From 35b65dd8ef3d37a088ee9169763a4d891aed618d Mon Sep 17 00:00:00 2001 From: Harald Seiler Date: Tue, 15 Dec 2020 16:47:52 +0100 Subject: reset: Remove addr parameter from reset_cpu() Historically, the reset_cpu() function had an `addr` parameter which was meant to pass in an address of the reset vector location, where the CPU should reset to. This feature is no longer used anywhere in U-Boot as all reset_cpu() implementations now ignore the passed value. Generic code has been added which always calls reset_cpu() with `0` which means this feature can no longer be used easily anyway. Over time, many implementations seem to have "misunderstood" the existence of this parameter as a way to customize/parameterize the reset (e.g. COLD vs WARM resets). As this is not properly supported, the code will almost always not do what it is intended to (because all call-sites just call reset_cpu() with 0). To avoid confusion and to clean up the codebase from unused left-overs of the past, remove the `addr` parameter entirely. Code which intends to support different kinds of resets should be rewritten as a sysreset driver instead. This transformation was done with the following coccinelle patch: @@ expression argvalue; @@ - reset_cpu(argvalue) + reset_cpu() @@ identifier argname; type argtype; @@ - reset_cpu(argtype argname) + reset_cpu(void) { ... } Signed-off-by: Harald Seiler Reviewed-by: Simon Glass --- include/cpu_func.h | 4 ++-- include/sysreset.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/cpu_func.h b/include/cpu_func.h index 8aa825daa47..c3a66f04059 100644 --- a/include/cpu_func.h +++ b/include/cpu_func.h @@ -84,6 +84,6 @@ enum { */ int cleanup_before_linux_select(int flags); -void reset_cpu(ulong addr); -; +void reset_cpu(void); + #endif diff --git a/include/sysreset.h b/include/sysreset.h index 8bb094d463b..701e4f5c86e 100644 --- a/include/sysreset.h +++ b/include/sysreset.h @@ -116,6 +116,6 @@ void sysreset_walk_halt(enum sysreset_t type); /** * reset_cpu() - calls sysreset_walk(SYSRESET_WARM) */ -void reset_cpu(ulong addr); +void reset_cpu(void); #endif -- cgit v1.3.1 From 14e46dfb176b4505e4bafa545d3facb9228d40a9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 6 Feb 2021 09:57:32 -0700 Subject: sandbox: Add os_realloc() We provide os_malloc() and os_free() but not os_realloc(). Add this, following the usual semantics. Also update os_malloc() to behave correctly when passed a zero size. Signed-off-by: Simon Glass Reviewed-by: Heinrich Schuchardt --- arch/sandbox/cpu/os.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ include/os.h | 12 +++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 3d8af0a52bb..d23aad318be 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -267,11 +267,18 @@ void os_tty_raw(int fd, bool allow_sigs) signal(SIGINT, os_sigint_handler); } +/* + * Provide our own malloc so we don't use space in the sandbox ram_buf for + * allocations that are internal to sandbox, or need to be done before U-Boot's + * malloc() is ready. + */ void *os_malloc(size_t length) { int page_size = getpagesize(); struct os_mem_hdr *hdr; + if (!length) + return NULL; /* * Use an address that is hopefully available to us so that pointers * to this memory are fairly obvious. If we end up with a different @@ -298,6 +305,47 @@ void os_free(void *ptr) } } +/* These macros are from kernel.h but not accessible in this file */ +#define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a) - 1) +#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) + +/* + * Provide our own malloc so we don't use space in the sandbox ram_buf for + * allocations that are internal to sandbox, or need to be done before U-Boot's + * malloc() is ready. + */ +void *os_realloc(void *ptr, size_t length) +{ + int page_size = getpagesize(); + struct os_mem_hdr *hdr; + void *new_ptr; + + /* Reallocating a NULL pointer is just an alloc */ + if (!ptr) + return os_malloc(length); + + /* Changing a length to 0 is just a free */ + if (length) { + os_free(ptr); + return NULL; + } + + /* + * If the new size is the same number of pages as the old, nothing to + * do. There isn't much point in shrinking things + */ + hdr = ptr - page_size; + if (ALIGN(length, page_size) <= ALIGN(hdr->length, page_size)) + return ptr; + + /* We have to grow it, so allocate something new */ + new_ptr = os_malloc(length); + memcpy(new_ptr, ptr, hdr->length); + os_free(ptr); + + return new_ptr; +} + void os_usleep(unsigned long usec) { usleep(usec); diff --git a/include/os.h b/include/os.h index 65bcb232cab..fd010cfee83 100644 --- a/include/os.h +++ b/include/os.h @@ -114,7 +114,7 @@ void os_fd_restore(void); * os_malloc() - aquires some memory from the underlying os. * * @length: Number of bytes to be allocated - * Return: Pointer to length bytes or NULL on error + * Return: Pointer to length bytes or NULL if @length is 0 or on error */ void *os_malloc(size_t length); @@ -127,6 +127,16 @@ void *os_malloc(size_t length); */ void os_free(void *ptr); +/** + * os_realloc() - reallocate memory + * + * This follows the semantics of realloc(), so can perform an os_malloc() or + * os_free() depending on @ptr and @length. + * + * Return: Pointer to reallocated memory or NULL if @length is 0 + */ +void *os_realloc(void *ptr, size_t length); + /** * os_usleep() - access to the usleep function of the os * -- cgit v1.3.1 From b308d9fd18fa4b9beed880a6ad169e7ab003a62f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 6 Feb 2021 09:57:33 -0700 Subject: sandbox: Avoid using malloc() for system state This state is not accessible to the running U-Boot but at present it is allocated in the emulated SDRAM. This doesn't seem very useful. Adjust it to allocate from the OS instead. The RAM buffer is currently not freed, but should be, so add that into state_uninit(). Update the comment for os_free() to indicate that NULL is a valid parameter value. Note that the strdup() in spl_board_load_image() is changed as well, since strdup() allocates memory in the RAM buffer. Signed-off-by: Simon Glass --- arch/sandbox/cpu/os.c | 24 ++++++++++++------------ arch/sandbox/cpu/spl.c | 10 +++++++--- arch/sandbox/cpu/start.c | 12 +++++++----- arch/sandbox/cpu/state.c | 18 +++++++++--------- include/os.h | 3 ++- 5 files changed, 37 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index d23aad318be..f5000e64966 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -153,7 +153,7 @@ int os_read_file(const char *fname, void **bufp, int *sizep) printf("Cannot seek to start of file '%s'\n", fname); goto err; } - *bufp = malloc(size); + *bufp = os_malloc(size); if (!*bufp) { printf("Not enough memory to read file '%s'\n", fname); ret = -ENOMEM; @@ -391,8 +391,8 @@ int os_parse_args(struct sandbox_state *state, int argc, char *argv[]) state->argv = argv; /* dynamically construct the arguments to the system getopt_long */ - short_opts = malloc(sizeof(*short_opts) * num_options * 2 + 1); - long_opts = malloc(sizeof(*long_opts) * (num_options + 1)); + short_opts = os_malloc(sizeof(*short_opts) * num_options * 2 + 1); + long_opts = os_malloc(sizeof(*long_opts) * (num_options + 1)); if (!short_opts || !long_opts) return 1; @@ -471,7 +471,7 @@ void os_dirent_free(struct os_dirent_node *node) while (node) { next = node->next; - free(node); + os_free(node); node = next; } } @@ -496,7 +496,7 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) /* Create a buffer upfront, with typically sufficient size */ dirlen = strlen(dirname) + 2; len = dirlen + 256; - fname = malloc(len); + fname = os_malloc(len); if (!fname) { ret = -ENOMEM; goto done; @@ -509,7 +509,7 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) ret = errno; break; } - next = malloc(sizeof(*node) + strlen(entry->d_name) + 1); + next = os_malloc(sizeof(*node) + strlen(entry->d_name) + 1); if (!next) { os_dirent_free(head); ret = -ENOMEM; @@ -518,10 +518,10 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) if (dirlen + strlen(entry->d_name) > len) { len = dirlen + strlen(entry->d_name); old_fname = fname; - fname = realloc(fname, len); + fname = os_realloc(fname, len); if (!fname) { - free(old_fname); - free(next); + os_free(old_fname); + os_free(next); os_dirent_free(head); ret = -ENOMEM; goto done; @@ -555,7 +555,7 @@ int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) done: closedir(dir); - free(fname); + os_free(fname); return ret; } @@ -672,7 +672,7 @@ static int add_args(char ***argvp, char *add_args[], int count) for (argc = 0; (*argvp)[argc]; argc++) ; - argv = malloc((argc + count + 1) * sizeof(char *)); + argv = os_malloc((argc + count + 1) * sizeof(char *)); if (!argv) { printf("Out of memory for %d argv\n", count); return -ENOMEM; @@ -755,7 +755,7 @@ static int os_jump_to_file(const char *fname) os_exit(2); err = execv(fname, argv); - free(argv); + os_free(argv); if (err) { perror("Unable to run image"); printf("Image filename '%s'\n", fname); diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index e7b4b50681a..6926e244ca2 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -43,10 +43,14 @@ static int spl_board_load_image(struct spl_image_info *spl_image, return ret; } - /* Set up spl_image to boot from jump_to_image_no_args() */ - spl_image->arg = strdup(fname); + /* + * Set up spl_image to boot from jump_to_image_no_args(). Allocate this + * outsdide the RAM buffer (i.e. don't use strdup()). + */ + spl_image->arg = os_malloc(strlen(fname) + 1); if (!spl_image->arg) - return log_msg_ret("Setup exec filename", -ENOMEM); + return log_msg_ret("exec", -ENOMEM); + strcpy(spl_image->arg, fname); return 0; } diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 483a2640404..c4c4128d465 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -88,7 +88,7 @@ int sandbox_early_getopt_check(void) /* Sort the options */ size = sizeof(*sorted_opt) * num_options; - sorted_opt = malloc(size); + sorted_opt = os_malloc(size); if (!sorted_opt) { printf("No memory to sort options\n"); os_exit(1); @@ -188,7 +188,7 @@ static int sandbox_cmdline_cb_default_fdt(struct sandbox_state *state, int len; len = strlen(state->argv[0]) + strlen(fmt) + 1; - fname = malloc(len); + fname = os_malloc(len); if (!fname) return -ENOMEM; snprintf(fname, len, fmt, state->argv[0]); @@ -208,7 +208,7 @@ static int sandbox_cmdline_cb_test_fdt(struct sandbox_state *state, int len; len = strlen(state->argv[0]) + strlen(fmt) + 1; - fname = malloc(len); + fname = os_malloc(len); if (!fname) return -ENOMEM; strcpy(fname, state->argv[0]); @@ -436,16 +436,18 @@ int main(int argc, char *argv[]) { struct sandbox_state *state; gd_t data; + int size; int ret; /* * Copy argv[] so that we can pass the arguments in the original * sequence when resetting the sandbox. */ - os_argv = calloc(argc + 1, sizeof(char *)); + size = sizeof(char *) * (argc + 1); + os_argv = os_malloc(size); if (!os_argv) os_exit(1); - memcpy(os_argv, argv, sizeof(char *) * (argc + 1)); + memcpy(os_argv, argv, size); memset(&data, '\0', sizeof(data)); gd = &data; diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c index b2901b7a8ca..4ffaf163789 100644 --- a/arch/sandbox/cpu/state.c +++ b/arch/sandbox/cpu/state.c @@ -29,17 +29,17 @@ static int state_ensure_space(int extra_size) return 0; size = used + extra_size; - buf = malloc(size); + buf = os_malloc(size); if (!buf) return -ENOMEM; ret = fdt_open_into(blob, buf, size); if (ret) { - free(buf); + os_free(buf); return -EIO; } - free(blob); + os_free(blob); state->state_fdt = buf; return 0; } @@ -55,7 +55,7 @@ static int state_read_file(struct sandbox_state *state, const char *fname) printf("Cannot find sandbox state file '%s'\n", fname); return -ENOENT; } - state->state_fdt = malloc(size); + state->state_fdt = os_malloc(size); if (!state->state_fdt) { puts("No memory to read sandbox state\n"); return -ENOMEM; @@ -77,7 +77,7 @@ static int state_read_file(struct sandbox_state *state, const char *fname) err_read: os_close(fd); err_open: - free(state->state_fdt); + os_free(state->state_fdt); state->state_fdt = NULL; return ret; @@ -244,7 +244,7 @@ int sandbox_write_state(struct sandbox_state *state, const char *fname) /* Create a state FDT if we don't have one */ if (!state->state_fdt) { size = 0x4000; - state->state_fdt = malloc(size); + state->state_fdt = os_malloc(size); if (!state->state_fdt) { puts("No memory to create FDT\n"); return -ENOMEM; @@ -302,7 +302,7 @@ int sandbox_write_state(struct sandbox_state *state, const char *fname) err_write: os_close(fd); err_create: - free(state->state_fdt); + os_free(state->state_fdt); return ret; } @@ -419,8 +419,8 @@ int state_uninit(void) if (state->jumped_fname) os_unlink(state->jumped_fname); - if (state->state_fdt) - free(state->state_fdt); + os_free(state->state_fdt); + os_free(state->ram_buf); memset(state, '\0', sizeof(*state)); return 0; diff --git a/include/os.h b/include/os.h index fd010cfee83..d2a4afeca0f 100644 --- a/include/os.h +++ b/include/os.h @@ -123,7 +123,8 @@ void *os_malloc(size_t length); * * This returns the memory to the OS. * - * @ptr: Pointer to memory block to free + * @ptr: Pointer to memory block to free. If this is NULL then this + * function does nothing */ void os_free(void *ptr); -- cgit v1.3.1 From bfe8fa262c788b817a8de66f78b3b2d9c22fa0d1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 6 Feb 2021 14:23:35 -0700 Subject: tpm: Add an API that can support v1.2 and v2 There are two different TPM standards. U-Boot supports both but each has its own set of functions. We really need a single TPM API that can call one or the other. This is not always possible as there are some differences between the two standards, but it is mostly possible. Add an API to handle this. So far it is not plumbed into the build and only supports TPMv1. Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- include/tpm_api.h | 322 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/tpm_api.c | 215 ++++++++++++++++++++++++++++++++++++ 2 files changed, 537 insertions(+) create mode 100644 include/tpm_api.h create mode 100644 lib/tpm_api.c (limited to 'include') diff --git a/include/tpm_api.h b/include/tpm_api.h new file mode 100644 index 00000000000..f13d98cae47 --- /dev/null +++ b/include/tpm_api.h @@ -0,0 +1,322 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#ifndef __TPM_API_H +#define __TPM_API_H + +#include +#include +#include + +/** + * Issue a TPM_Startup command. + * + * @param dev TPM device + * @param mode TPM startup mode + * @return return code of the operation + */ +u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode); + +/** + * Issue a TPM_SelfTestFull command. + * + * @param dev TPM device + * @return return code of the operation + */ +u32 tpm_self_test_full(struct udevice *dev); + +/** + * Issue a TPM_ContinueSelfTest command. + * + * @param dev TPM device + * @return return code of the operation + */ +u32 tpm_continue_self_test(struct udevice *dev); + +/** + * Issue a TPM_NV_DefineSpace command. The implementation is limited + * to specify TPM_NV_ATTRIBUTES and size of the area. The area index + * could be one of the special value listed in enum tpm_nv_index. + * + * @param dev TPM device + * @param index index of the area + * @param perm TPM_NV_ATTRIBUTES of the area + * @param size size of the area + * @return return code of the operation + */ +u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size); + +/** + * Issue a TPM_NV_ReadValue command. This implementation is limited + * to read the area from offset 0. The area index could be one of + * the special value listed in enum tpm_nv_index. + * + * @param dev TPM device + * @param index index of the area + * @param data output buffer of the area contents + * @param count size of output buffer + * @return return code of the operation + */ +u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count); + +/** + * Issue a TPM_NV_WriteValue command. This implementation is limited + * to write the area from offset 0. The area index could be one of + * the special value listed in enum tpm_nv_index. + * + * @param dev TPM device + * @param index index of the area + * @param data input buffer to be wrote to the area + * @param length length of data bytes of input buffer + * @return return code of the operation + */ +u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data, + u32 length); + +/** + * Issue a TPM_Extend command. + * + * @param dev TPM device + * @param index index of the PCR + * @param in_digest 160-bit value representing the event to be + * recorded + * @param out_digest 160-bit PCR value after execution of the + * command + * @return return code of the operation + */ +u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest, + void *out_digest); + +/** + * Issue a TPM_PCRRead command. + * + * @param dev TPM device + * @param index index of the PCR + * @param data output buffer for contents of the named PCR + * @param count size of output buffer + * @return return code of the operation + */ +u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count); + +/** + * Issue a TSC_PhysicalPresence command. TPM physical presence flag + * is bit-wise OR'ed of flags listed in enum tpm_physical_presence. + * + * @param dev TPM device + * @param presence TPM physical presence flag + * @return return code of the operation + */ +u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence); + +/** + * Issue a TPM_ReadPubek command. + * + * @param dev TPM device + * @param data output buffer for the public endorsement key + * @param count size of output buffer + * @return return code of the operation + */ +u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count); + +/** + * Issue a TPM_ForceClear command. + * + * @param dev TPM device + * @return return code of the operation + */ +u32 tpm_force_clear(struct udevice *dev); + +/** + * Issue a TPM_PhysicalEnable command. + * + * @param dev TPM device + * @return return code of the operation + */ +u32 tpm_physical_enable(struct udevice *dev); + +/** + * Issue a TPM_PhysicalDisable command. + * + * @param dev TPM device + * @return return code of the operation + */ +u32 tpm_physical_disable(struct udevice *dev); + +/** + * Issue a TPM_PhysicalSetDeactivated command. + * + * @param dev TPM device + * @param state boolean state of the deactivated flag + * @return return code of the operation + */ +u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state); + +/** + * Issue a TPM_GetCapability command. This implementation is limited + * to query sub_cap index that is 4-byte wide. + * + * @param dev TPM device + * @param cap_area partition of capabilities + * @param sub_cap further definition of capability, which is + * limited to be 4-byte wide + * @param cap output buffer for capability information + * @param count size of output buffer + * @return return code of the operation + */ +u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap, + void *cap, size_t count); + +/** + * Issue a TPM_FlushSpecific command for a AUTH resource. + * + * @param dev TPM device + * @param auth_handle handle of the auth session + * @return return code of the operation + */ +u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle); + +/** + * Issue a TPM_OIAP command to setup an object independent authorization + * session. + * Information about the session is stored internally. + * If there was already an OIAP session active it is terminated and a new + * session is set up. + * + * @param dev TPM device + * @param auth_handle pointer to the (new) auth handle or NULL. + * @return return code of the operation + */ +u32 tpm_oiap(struct udevice *dev, u32 *auth_handle); + +/** + * Ends an active OIAP session. + * + * @param dev TPM device + * @return return code of the operation + */ +u32 tpm_end_oiap(struct udevice *dev); + +/** + * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating + * the usage of the parent key. + * + * @param dev TPM device + * @param parent_handle handle of the parent key. + * @param key pointer to the key structure (TPM_KEY or TPM_KEY12). + * @param key_length size of the key structure + * @param parent_key_usage_auth usage auth for the parent key + * @param key_handle pointer to the key handle + * @return return code of the operation + */ +u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key, + size_t key_length, const void *parent_key_usage_auth, + u32 *key_handle); + +/** + * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for + * authenticating the usage of the key. + * + * @param dev TPM device + * @param key_handle handle of the key + * @param usage_auth usage auth for the key + * @param pubkey pointer to the pub key buffer; may be NULL if the pubkey + * should not be stored. + * @param pubkey_len pointer to the pub key buffer len. On entry: the size of + * the provided pubkey buffer. On successful exit: the size + * of the stored TPM_PUBKEY structure (iff pubkey != NULL). + * @return return code of the operation + */ +u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle, + const void *usage_auth, void *pubkey, + size_t *pubkey_len); + +/** + * Get the TPM permissions + * + * @param dev TPM device + * @param perm Returns permissions value + * @return return code of the operation + */ +u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm); + +/** + * Flush a resource with a given handle and type from the TPM + * + * @param dev TPM device + * @param key_handle handle of the resource + * @param resource_type type of the resource + * @return return code of the operation + */ +u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type); + +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 +/** + * Search for a key by usage AuthData and the hash of the parent's pub key. + * + * @param dev TPM device + * @param auth Usage auth of the key to search for + * @param pubkey_digest SHA1 hash of the pub key structure of the key + * @param[out] handle The handle of the key (Non-null iff found) + * @return 0 if key was found in TPM; != 0 if not. + */ +u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20], + const u8 pubkey_digest[20], u32 *handle); +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ + +/** + * Read random bytes from the TPM RNG. The implementation deals with the fact + * that the TPM may legally return fewer bytes than requested by retrying + * until @p count bytes have been received. + * + * @param dev TPM device + * @param data output buffer for the random bytes + * @param count size of output buffer + * @return return code of the operation + */ +u32 tpm_get_random(struct udevice *dev, void *data, u32 count); + +/** + * tpm_finalise_physical_presence() - Finalise physical presence + * + * @param dev TPM device + * @return return code of the operation (0 = success) + */ +u32 tpm_finalise_physical_presence(struct udevice *dev); + +/** + * tpm_nv_enable_locking() - lock the non-volatile space + * + * @param dev TPM device + * @return return code of the operation (0 = success) + */ +u32 tpm_nv_enable_locking(struct udevice *dev); + +/** + * tpm_set_global_lock() - set the global lock + * + * @param dev TPM device + * @return return code of the operation (0 = success) + */ +u32 tpm_set_global_lock(struct udevice *dev); + +/** + * tpm_write_lock() - lock the non-volatile space + * + * @param dev TPM device + * @param index Index of space to lock + * @return return code of the operation (0 = success) + */ +u32 tpm_write_lock(struct udevice *dev, u32 index); + +/** + * tpm_resume() - start up the TPM from resume (after suspend) + * + * @param dev TPM device + * @return return code of the operation (0 = success) + */ +u32 tpm_resume(struct udevice *dev); + +#endif /* __TPM_API_H */ diff --git a/lib/tpm_api.c b/lib/tpm_api.c new file mode 100644 index 00000000000..758350bd18d --- /dev/null +++ b/lib/tpm_api.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include + +static bool is_tpm1(struct udevice *dev) +{ + return IS_ENABLED(CONFIG_TPM_V1) && tpm_get_version(dev) == TPM_V1; +} + +u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode) +{ + if (is_tpm1(dev)) + return tpm1_startup(dev, mode); + else + return -ENOSYS; +} + +u32 tpm_resume(struct udevice *dev) +{ + if (is_tpm1(dev)) + return tpm1_startup(dev, TPM_ST_STATE); + else + return -ENOSYS; +} + +u32 tpm_self_test_full(struct udevice *dev) +{ + if (is_tpm1(dev)) + return tpm1_self_test_full(dev); + else + return -ENOSYS; +} + +u32 tpm_continue_self_test(struct udevice *dev) +{ + if (is_tpm1(dev)) + return tpm1_continue_self_test(dev); + else + return -ENOSYS; +} + +u32 tpm_clear_and_reenable(struct udevice *dev) +{ + u32 ret; + + log_info("TPM: Clear and re-enable\n"); + ret = tpm_force_clear(dev); + if (ret != TPM_SUCCESS) { + log_err("Can't initiate a force clear\n"); + return ret; + } + + if (is_tpm1(dev)) { + ret = tpm1_physical_enable(dev); + if (ret != TPM_SUCCESS) { + log_err("TPM: Can't set enabled state\n"); + return ret; + } + + ret = tpm1_physical_set_deactivated(dev, 0); + if (ret != TPM_SUCCESS) { + log_err("TPM: Can't set deactivated state\n"); + return ret; + } + } else { + return -ENOSYS; + } + + return TPM_SUCCESS; +} + +u32 tpm_nv_enable_locking(struct udevice *dev) +{ + if (is_tpm1(dev)) + return tpm1_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0); + else + return -ENOSYS; +} + +u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count) +{ + if (is_tpm1(dev)) + return tpm1_nv_read_value(dev, index, data, count); + else + return -ENOSYS; +} + +u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data, + u32 count) +{ + if (is_tpm1(dev)) + return tpm1_nv_write_value(dev, index, data, count); + else + return -ENOSYS; +} + +u32 tpm_set_global_lock(struct udevice *dev) +{ + return tpm_nv_write_value(dev, TPM_NV_INDEX_0, NULL, 0); +} + +u32 tpm_write_lock(struct udevice *dev, u32 index) +{ + if (is_tpm1(dev)) + return -ENOSYS; + else + return -ENOSYS; +} + +u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest, + void *out_digest) +{ + if (is_tpm1(dev)) + return tpm1_extend(dev, index, in_digest, out_digest); + else + return -ENOSYS; +} + +u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count) +{ + if (is_tpm1(dev)) + return tpm1_pcr_read(dev, index, data, count); + else + return -ENOSYS; +} + +u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence) +{ + if (is_tpm1(dev)) + return tpm1_tsc_physical_presence(dev, presence); + else + return -ENOSYS; +} + +u32 tpm_finalise_physical_presence(struct udevice *dev) +{ + if (is_tpm1(dev)) + return tpm1_finalise_physical_presence(dev); + else + return -ENOSYS; +} + +u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count) +{ + if (is_tpm1(dev)) + return tpm1_read_pubek(dev, data, count); + else + return -ENOSYS; /* not implemented yet */ +} + +u32 tpm_force_clear(struct udevice *dev) +{ + if (is_tpm1(dev)) + return tpm1_force_clear(dev); + else + return -ENOSYS; +} + +u32 tpm_physical_enable(struct udevice *dev) +{ + if (is_tpm1(dev)) + return tpm1_physical_enable(dev); + else + return -ENOSYS; +} + +u32 tpm_physical_disable(struct udevice *dev) +{ + if (is_tpm1(dev)) + return tpm1_physical_disable(dev); + else + return -ENOSYS; +} + +u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state) +{ + if (is_tpm1(dev)) + return tpm1_physical_set_deactivated(dev, state); + else + return -ENOSYS; +} + +u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap, + void *cap, size_t count) +{ + if (is_tpm1(dev)) + return tpm1_get_capability(dev, cap_area, sub_cap, cap, count); + else + return -ENOSYS; +} + +u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm) +{ + if (is_tpm1(dev)) + return tpm1_get_permissions(dev, index, perm); + else + return -ENOSYS; /* not implemented yet */ +} + +u32 tpm_get_random(struct udevice *dev, void *data, u32 count) +{ + if (is_tpm1(dev)) + return tpm1_get_random(dev, data, count); + else + return -ENOSYS; /* not implemented yet */ +} -- cgit v1.3.1 From d6a885f0878043d572bfd85a423e4a6bb6073178 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 6 Feb 2021 14:23:36 -0700 Subject: tpm: Switch TPMv1 over to use the new API Take over the plain 'tpm_...' functions for use by the new TPM API. Rename all the TPMv1 functions so they are called from the API. Update the TPMv1 functions so that they are called from the API. Change existing users to use the tpm1_ prefix so they don't need to go through the API, which might introduce uncertainty. Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- board/gdsys/a38x/controlcenterdc.c | 4 +- board/gdsys/a38x/hre.c | 28 ++++----- board/gdsys/a38x/keyprogram.c | 8 +-- board/gdsys/mpc8308/gazerbeam.c | 4 +- board/gdsys/p1022/controlcenterd-id.c | 36 +++++------ cmd/tpm-v1.c | 25 ++++---- cmd/tpm_test.c | 40 ++++++------ include/tpm-v1.h | 76 +++++++++++----------- lib/Makefile | 1 + lib/tpm-v1.c | 115 ++++++++++++++++------------------ 10 files changed, 168 insertions(+), 169 deletions(-) (limited to 'include') diff --git a/board/gdsys/a38x/controlcenterdc.c b/board/gdsys/a38x/controlcenterdc.c index 4f1dc3b4316..dc424f271c5 100644 --- a/board/gdsys/a38x/controlcenterdc.c +++ b/board/gdsys/a38x/controlcenterdc.c @@ -288,8 +288,8 @@ int last_stage_init(void) ccdc_eth_init(); #endif ret = get_tpm(&tpm); - if (ret || tpm_init(tpm) || tpm_startup(tpm, TPM_ST_CLEAR) || - tpm_continue_self_test(tpm)) { + if (ret || tpm_init(tpm) || tpm1_startup(tpm, TPM_ST_CLEAR) || + tpm1_continue_self_test(tpm)) { return 1; } diff --git a/board/gdsys/a38x/hre.c b/board/gdsys/a38x/hre.c index 699241b3e62..de5411a6b93 100644 --- a/board/gdsys/a38x/hre.c +++ b/board/gdsys/a38x/hre.c @@ -107,8 +107,8 @@ static int get_tpm_nv_size(struct udevice *tpm, uint32_t index, uint32_t *size) uint8_t *ptr; uint16_t v16; - err = tpm_get_capability(tpm, TPM_CAP_NV_INDEX, index, - info, sizeof(info)); + err = tpm1_get_capability(tpm, TPM_CAP_NV_INDEX, index, info, + sizeof(info)); if (err) { printf("tpm_get_capability(CAP_NV_INDEX, %08x) failed: %u\n", index, err); @@ -150,8 +150,8 @@ static int find_key(struct udevice *tpm, const uint8_t auth[20], unsigned int i; /* fetch list of already loaded keys in the TPM */ - err = tpm_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf, - sizeof(buf)); + err = tpm1_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf, + sizeof(buf)); if (err) return -1; key_count = get_unaligned_be16(buf); @@ -162,8 +162,8 @@ static int find_key(struct udevice *tpm, const uint8_t auth[20], /* now search a(/ the) key which we can access with the given auth */ for (i = 0; i < key_count; ++i) { buf_len = sizeof(buf); - err = tpm_get_pub_key_oiap(tpm, key_handles[i], auth, buf, - &buf_len); + err = tpm1_get_pub_key_oiap(tpm, key_handles[i], auth, buf, + &buf_len); if (err && err != TPM_AUTHFAIL) return -1; if (err) @@ -192,8 +192,8 @@ static int read_common_data(struct udevice *tpm) if (get_tpm_nv_size(tpm, NV_COMMON_DATA_INDEX, &size) || size < NV_COMMON_DATA_MIN_SIZE) return 1; - err = tpm_nv_read_value(tpm, NV_COMMON_DATA_INDEX, - buf, min(sizeof(buf), size)); + err = tpm1_nv_read_value(tpm, NV_COMMON_DATA_INDEX, buf, + min(sizeof(buf), size)); if (err) { printf("tpm_nv_read_value() failed: %u\n", err); return 1; @@ -270,8 +270,8 @@ static struct h_reg *access_hreg(struct udevice *tpm, uint8_t spec, if (mode & HREG_RD) { if (!result->valid) { if (IS_PCR_HREG(spec)) { - hre_tpm_err = tpm_pcr_read(tpm, HREG_IDX(spec), - result->digest, 20); + hre_tpm_err = tpm1_pcr_read(tpm, HREG_IDX(spec), + result->digest, 20); result->valid = (hre_tpm_err == TPM_SUCCESS); } else if (IS_FIX_HREG(spec)) { switch (HREG_IDX(spec)) { @@ -357,8 +357,8 @@ static int hre_op_loadkey(struct udevice *tpm, struct h_reg *src_reg, return -1; if (find_key(tpm, src_reg->digest, dst_reg->digest, &parent_handle)) return -1; - hre_tpm_err = tpm_load_key2_oiap(tpm, parent_handle, key, key_size, - src_reg->digest, &key_handle); + hre_tpm_err = tpm1_load_key2_oiap(tpm, parent_handle, key, key_size, + src_reg->digest, &key_handle); if (hre_tpm_err) { hre_err = HRE_E_TPM_FAILURE; return -1; @@ -474,8 +474,8 @@ do_bin_func: } if (dst_reg && dst_modified && IS_PCR_HREG(dst_spec)) { - hre_tpm_err = tpm_extend(tpm, HREG_IDX(dst_spec), - dst_reg->digest, dst_reg->digest); + hre_tpm_err = tpm1_extend(tpm, HREG_IDX(dst_spec), + dst_reg->digest, dst_reg->digest); if (hre_tpm_err) { hre_err = HRE_E_TPM_FAILURE; return NULL; diff --git a/board/gdsys/a38x/keyprogram.c b/board/gdsys/a38x/keyprogram.c index 853981aadbb..7020fae1894 100644 --- a/board/gdsys/a38x/keyprogram.c +++ b/board/gdsys/a38x/keyprogram.c @@ -23,15 +23,15 @@ int flush_keys(struct udevice *tpm) uint i; /* fetch list of already loaded keys in the TPM */ - err = tpm_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf, - sizeof(buf)); + err = tpm1_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf, + sizeof(buf)); if (err) return -1; key_count = get_unaligned_be16(buf); ptr = buf + 2; for (i = 0; i < key_count; ++i, ptr += 4) { - err = tpm_flush_specific(tpm, get_unaligned_be32(ptr), - TPM_RT_KEY); + err = tpm1_flush_specific(tpm, get_unaligned_be32(ptr), + TPM_RT_KEY); if (err && err != TPM_KEY_OWNER_CONTROL) return err; } diff --git a/board/gdsys/mpc8308/gazerbeam.c b/board/gdsys/mpc8308/gazerbeam.c index 4e974c56d2c..3d4a7e57fee 100644 --- a/board/gdsys/mpc8308/gazerbeam.c +++ b/board/gdsys/mpc8308/gazerbeam.c @@ -145,8 +145,8 @@ int last_stage_init(void) env_set_ulong("fpga_hw_rev", fpga_hw_rev); ret = get_tpm(&tpm); - if (ret || tpm_init(tpm) || tpm_startup(tpm, TPM_ST_CLEAR) || - tpm_continue_self_test(tpm)) { + if (ret || tpm_init(tpm) || tpm1_startup(tpm, TPM_ST_CLEAR) || + tpm1_continue_self_test(tpm)) { printf("TPM init failed\n"); } diff --git a/board/gdsys/p1022/controlcenterd-id.c b/board/gdsys/p1022/controlcenterd-id.c index 1b5aa9042f5..87b346aa9cf 100644 --- a/board/gdsys/p1022/controlcenterd-id.c +++ b/board/gdsys/p1022/controlcenterd-id.c @@ -273,8 +273,8 @@ static int get_tpm_nv_size(struct udevice *tpm, uint32_t index, uint32_t *size) uint8_t *ptr; uint16_t v16; - err = tpm_get_capability(tpm, TPM_CAP_NV_INDEX, index, - info, sizeof(info)); + err = tpm1_get_capability(tpm, TPM_CAP_NV_INDEX, index, info, + sizeof(info)); if (err) { printf("tpm_get_capability(CAP_NV_INDEX, %08x) failed: %u\n", index, err); @@ -315,8 +315,8 @@ static int find_key(struct udevice *tpm, const uint8_t auth[20], unsigned int i; /* fetch list of already loaded keys in the TPM */ - err = tpm_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf, - sizeof(buf)); + err = tpm1_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf, + sizeof(buf)); if (err) return -1; key_count = get_unaligned_be16(buf); @@ -327,8 +327,8 @@ static int find_key(struct udevice *tpm, const uint8_t auth[20], /* now search a(/ the) key which we can access with the given auth */ for (i = 0; i < key_count; ++i) { buf_len = sizeof(buf); - err = tpm_get_pub_key_oiap(tpm, key_handles[i], auth, buf, - &buf_len); + err = tpm1_get_pub_key_oiap(tpm, key_handles[i], auth, buf, + &buf_len); if (err && err != TPM_AUTHFAIL) return -1; if (err) @@ -356,8 +356,8 @@ static int read_common_data(struct udevice *tpm) if (get_tpm_nv_size(tpm, NV_COMMON_DATA_INDEX, &size) || size < NV_COMMON_DATA_MIN_SIZE) return 1; - err = tpm_nv_read_value(tpm, NV_COMMON_DATA_INDEX, - buf, min(sizeof(buf), size)); + err = tpm1_nv_read_value(tpm, NV_COMMON_DATA_INDEX, buf, + min(sizeof(buf), size)); if (err) { printf("tpm_nv_read_value() failed: %u\n", err); return 1; @@ -508,8 +508,8 @@ static struct h_reg *access_hreg(struct udevice *tpm, uint8_t spec, if (mode & HREG_RD) { if (!result->valid) { if (IS_PCR_HREG(spec)) { - hre_tpm_err = tpm_pcr_read(tpm, HREG_IDX(spec), - result->digest, 20); + hre_tpm_err = tpm1_pcr_read(tpm, HREG_IDX(spec), + result->digest, 20); result->valid = (hre_tpm_err == TPM_SUCCESS); } else if (IS_FIX_HREG(spec)) { switch (HREG_IDX(spec)) { @@ -601,8 +601,8 @@ static int hre_op_loadkey(struct udevice *tpm, struct h_reg *src_reg, return -1; if (find_key(tpm, src_reg->digest, dst_reg->digest, &parent_handle)) return -1; - hre_tpm_err = tpm_load_key2_oiap(tpm, parent_handle, key, key_size, - src_reg->digest, &key_handle); + hre_tpm_err = tpm1_load_key2_oiap(tpm, parent_handle, key, key_size, + src_reg->digest, &key_handle); if (hre_tpm_err) { hre_err = HRE_E_TPM_FAILURE; return -1; @@ -718,8 +718,8 @@ do_bin_func: } if (dst_reg && dst_modified && IS_PCR_HREG(dst_spec)) { - hre_tpm_err = tpm_extend(tpm, HREG_IDX(dst_spec), - dst_reg->digest, dst_reg->digest); + hre_tpm_err = tpm1_extend(tpm, HREG_IDX(dst_spec), + dst_reg->digest, dst_reg->digest); if (hre_tpm_err) { hre_err = HRE_E_TPM_FAILURE; return NULL; @@ -964,10 +964,10 @@ static int first_stage_actions(struct udevice *tpm) puts("CCDM S1: start actions\n"); #ifndef CCDM_SECOND_STAGE - if (tpm_continue_self_test(tpm)) + if (tpm1_continue_self_test(tpm)) goto failure; #else - tpm_continue_self_test(tpm); + tpm1_continue_self_test(tpm); #endif mdelay(37); @@ -1003,7 +1003,7 @@ static int first_stage_init(void) puts("CCDM S1\n"); ret = get_tpm(&tpm); - if (ret || tpm_init(tpm) || tpm_startup(tpm, TPM_ST_CLEAR)) + if (ret || tpm_init(tpm) || tpm1_startup(tpm, TPM_ST_CLEAR)) return 1; ret = first_stage_actions(tpm); #ifndef CCDM_SECOND_STAGE @@ -1061,7 +1061,7 @@ static int second_stage_init(void) ret = get_tpm(&tpm); if (ret || tpm_init(tpm)) return 1; - err = tpm_startup(tpm, TPM_ST_CLEAR); + err = tpm1_startup(tpm, TPM_ST_CLEAR); if (err != TPM_INVALID_POSTINIT) did_first_stage_run = false; diff --git a/cmd/tpm-v1.c b/cmd/tpm-v1.c index 0e2168aea67..3a7e35d5255 100644 --- a/cmd/tpm-v1.c +++ b/cmd/tpm-v1.c @@ -11,6 +11,7 @@ #include #include #include "tpm-user-utils.h" +#include static int do_tpm_startup(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) @@ -55,7 +56,7 @@ static int do_tpm_nv_define_space(struct cmd_tbl *cmdtp, int flag, int argc, perm = simple_strtoul(argv[2], NULL, 0); size = simple_strtoul(argv[3], NULL, 0); - return report_return_code(tpm_nv_define_space(dev, index, perm, size)); + return report_return_code(tpm1_nv_define_space(dev, index, perm, size)); } static int do_tpm_nv_read_value(struct cmd_tbl *cmdtp, int flag, int argc, @@ -130,7 +131,7 @@ static int do_tpm_extend(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_FAILURE; } - rc = tpm_extend(dev, index, in_digest, out_digest); + rc = tpm_pcr_extend(dev, index, in_digest, out_digest); if (!rc) { puts("PCR value after execution of the command:\n"); print_byte_string(out_digest, sizeof(out_digest)); @@ -304,7 +305,7 @@ static int do_tpm_nv_define(struct cmd_tbl *cmdtp, int flag, int argc, index = simple_strtoul(argv[2], NULL, 0); perm = simple_strtoul(argv[3], NULL, 0); - return report_return_code(tpm_nv_define_space(dev, index, perm, size)); + return report_return_code(tpm1_nv_define_space(dev, index, perm, size)); } static int do_tpm_nv_read(struct cmd_tbl *cmdtp, int flag, int argc, @@ -389,7 +390,7 @@ static int do_tpm_oiap(struct cmd_tbl *cmdtp, int flag, int argc, if (rc) return rc; - err = tpm_oiap(dev, &auth_handle); + err = tpm1_oiap(dev, &auth_handle); return report_return_code(err); } @@ -461,8 +462,8 @@ static int do_tpm_load_key2_oiap(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_FAILURE; parse_byte_string(argv[4], usage_auth, NULL); - err = tpm_load_key2_oiap(dev, parent_handle, key, key_len, usage_auth, - &key_handle); + err = tpm1_load_key2_oiap(dev, parent_handle, key, key_len, usage_auth, + &key_handle); if (!err) printf("Key handle is 0x%x\n", key_handle); @@ -491,8 +492,8 @@ static int do_tpm_get_pub_key_oiap(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_FAILURE; parse_byte_string(argv[2], usage_auth, NULL); - err = tpm_get_pub_key_oiap(dev, key_handle, usage_auth, pub_key_buffer, - &pub_key_len); + err = tpm1_get_pub_key_oiap(dev, key_handle, usage_auth, pub_key_buffer, + &pub_key_len); if (!err) { printf("dump of received pub key structure:\n"); print_byte_string(pub_key_buffer, pub_key_len); @@ -500,7 +501,7 @@ static int do_tpm_get_pub_key_oiap(struct cmd_tbl *cmdtp, int flag, int argc, return report_return_code(err); } -TPM_COMMAND_NO_ARG(tpm_end_oiap) +TPM_COMMAND_NO_ARG(tpm1_end_oiap) #endif /* CONFIG_TPM_AUTH_SESSIONS */ @@ -562,7 +563,7 @@ static int do_tpm_flush(struct cmd_tbl *cmdtp, int flag, int argc, res_count = get_unaligned_be16(buf); ptr = buf + 2; for (i = 0; i < res_count; ++i, ptr += 4) - tpm_flush_specific(dev, get_unaligned_be32(ptr), type); + tpm1_flush_specific(dev, get_unaligned_be32(ptr), type); } else { u32 handle = simple_strtoul(argv[2], NULL, 0); @@ -570,7 +571,7 @@ static int do_tpm_flush(struct cmd_tbl *cmdtp, int flag, int argc, printf("Illegal resource handle %s\n", argv[2]); return -1; } - tpm_flush_specific(dev, cpu_to_be32(handle), type); + tpm1_flush_specific(dev, cpu_to_be32(handle), type); } return 0; @@ -691,7 +692,7 @@ static struct cmd_tbl tpm1_commands[] = { U_BOOT_CMD_MKENT(oiap, 0, 1, do_tpm_oiap, "", ""), U_BOOT_CMD_MKENT(end_oiap, 0, 1, - do_tpm_end_oiap, "", ""), + do_tpm1_end_oiap, "", ""), U_BOOT_CMD_MKENT(load_key2_oiap, 0, 1, do_tpm_load_key2_oiap, "", ""), #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 diff --git a/cmd/tpm_test.c b/cmd/tpm_test.c index 3fb964c3719..a3ccb12f53a 100644 --- a/cmd/tpm_test.c +++ b/cmd/tpm_test.c @@ -9,6 +9,7 @@ #include #include #include "tpm-user-utils.h" +#include /* Prints error and returns on failure */ #define TPM_CHECK(tpm_command) do { \ @@ -49,7 +50,7 @@ static uint32_t tpm_get_flags(struct udevice *dev, uint8_t *disable, struct tpm_permanent_flags pflags; uint32_t result; - result = tpm_get_permanent_flags(dev, &pflags); + result = tpm1_get_permanent_flags(dev, &pflags); if (result) return result; if (disable) @@ -90,7 +91,7 @@ static int test_early_extend(struct udevice *dev) tpm_init(dev); TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR)); TPM_CHECK(tpm_continue_self_test(dev)); - TPM_CHECK(tpm_extend(dev, 1, value_in, value_out)); + TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, value_out)); printf("done\n"); return 0; } @@ -238,18 +239,18 @@ static void initialise_spaces(struct udevice *dev) uint32_t perm = TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE; printf("\tInitialising spaces\n"); - tpm_nv_set_locked(dev); /* useful only the first time */ - tpm_nv_define_space(dev, INDEX0, perm, 4); + tpm1_nv_set_locked(dev); /* useful only the first time */ + tpm1_nv_define_space(dev, INDEX0, perm, 4); tpm_nv_write_value(dev, INDEX0, (uint8_t *)&zero, 4); - tpm_nv_define_space(dev, INDEX1, perm, 4); + tpm1_nv_define_space(dev, INDEX1, perm, 4); tpm_nv_write_value(dev, INDEX1, (uint8_t *)&zero, 4); - tpm_nv_define_space(dev, INDEX2, perm, 4); + tpm1_nv_define_space(dev, INDEX2, perm, 4); tpm_nv_write_value(dev, INDEX2, (uint8_t *)&zero, 4); - tpm_nv_define_space(dev, INDEX3, perm, 4); + tpm1_nv_define_space(dev, INDEX3, perm, 4); tpm_nv_write_value(dev, INDEX3, (uint8_t *)&zero, 4); perm = TPM_NV_PER_READ_STCLEAR | TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE; - tpm_nv_define_space(dev, INDEX_INITIALISED, perm, 1); + tpm1_nv_define_space(dev, INDEX_INITIALISED, perm, 1); } static int test_readonly(struct udevice *dev) @@ -325,30 +326,33 @@ static int test_redefine_unowned(struct udevice *dev) /* Redefines spaces a couple of times. */ perm = TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK; - TPM_CHECK(tpm_nv_define_space(dev, INDEX0, perm, 2 * sizeof(uint32_t))); - TPM_CHECK(tpm_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t))); + TPM_CHECK(tpm1_nv_define_space(dev, INDEX0, perm, + 2 * sizeof(uint32_t))); + TPM_CHECK(tpm1_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t))); perm = TPM_NV_PER_PPWRITE; - TPM_CHECK(tpm_nv_define_space(dev, INDEX1, perm, 2 * sizeof(uint32_t))); - TPM_CHECK(tpm_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t))); + TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm, + 2 * sizeof(uint32_t))); + TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t))); /* Sets the global lock */ tpm_set_global_lock(dev); /* Verifies that index0 cannot be redefined */ - result = tpm_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t)); + result = tpm1_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t)); assert(result == TPM_AREA_LOCKED); /* Checks that index1 can */ - TPM_CHECK(tpm_nv_define_space(dev, INDEX1, perm, 2 * sizeof(uint32_t))); - TPM_CHECK(tpm_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t))); + TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm, + 2 * sizeof(uint32_t))); + TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t))); /* Turns off PP */ tpm_tsc_physical_presence(dev, PHYS_PRESENCE); /* Verifies that neither index0 nor index1 can be redefined */ - result = tpm_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t)); + result = tpm1_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t)); assert(result == TPM_BAD_PRESENCE); - result = tpm_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t)); + result = tpm1_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t)); assert(result == TPM_BAD_PRESENCE); printf("done\n"); @@ -434,7 +438,7 @@ static int test_timing(struct udevice *dev) 100); TTPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)), 100); - TTPM_CHECK(tpm_extend(dev, 0, in, out), 200); + TTPM_CHECK(tpm_pcr_extend(dev, 0, in, out), 200); TTPM_CHECK(tpm_set_global_lock(dev), 50); TTPM_CHECK(tpm_tsc_physical_presence(dev, PHYS_PRESENCE), 100); printf("done\n"); diff --git a/include/tpm-v1.h b/include/tpm-v1.h index 8f6cc28a9ea..fcfe1f054f6 100644 --- a/include/tpm-v1.h +++ b/include/tpm-v1.h @@ -289,7 +289,7 @@ struct __packed tpm_nv_data_public { * @param mode TPM startup mode * @return return code of the operation */ -u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode); +u32 tpm1_startup(struct udevice *dev, enum tpm_startup_type mode); /** * Issue a TPM_SelfTestFull command. @@ -297,7 +297,7 @@ u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode); * @param dev TPM device * @return return code of the operation */ -u32 tpm_self_test_full(struct udevice *dev); +u32 tpm1_self_test_full(struct udevice *dev); /** * Issue a TPM_ContinueSelfTest command. @@ -305,7 +305,7 @@ u32 tpm_self_test_full(struct udevice *dev); * @param dev TPM device * @return return code of the operation */ -u32 tpm_continue_self_test(struct udevice *dev); +u32 tpm1_continue_self_test(struct udevice *dev); /** * Issue a TPM_NV_DefineSpace command. The implementation is limited @@ -318,7 +318,7 @@ u32 tpm_continue_self_test(struct udevice *dev); * @param size size of the area * @return return code of the operation */ -u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size); +u32 tpm1_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size); /** * Issue a TPM_NV_ReadValue command. This implementation is limited @@ -331,7 +331,7 @@ u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size); * @param count size of output buffer * @return return code of the operation */ -u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count); +u32 tpm1_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count); /** * Issue a TPM_NV_WriteValue command. This implementation is limited @@ -344,8 +344,8 @@ u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count); * @param length length of data bytes of input buffer * @return return code of the operation */ -u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data, - u32 length); +u32 tpm1_nv_write_value(struct udevice *dev, u32 index, const void *data, + u32 length); /** * Issue a TPM_Extend command. @@ -358,8 +358,8 @@ u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data, * command * @return return code of the operation */ -u32 tpm_extend(struct udevice *dev, u32 index, const void *in_digest, - void *out_digest); +u32 tpm1_extend(struct udevice *dev, u32 index, const void *in_digest, + void *out_digest); /** * Issue a TPM_PCRRead command. @@ -370,7 +370,7 @@ u32 tpm_extend(struct udevice *dev, u32 index, const void *in_digest, * @param count size of output buffer * @return return code of the operation */ -u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count); +u32 tpm1_pcr_read(struct udevice *dev, u32 index, void *data, size_t count); /** * Issue a TSC_PhysicalPresence command. TPM physical presence flag @@ -380,7 +380,7 @@ u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count); * @param presence TPM physical presence flag * @return return code of the operation */ -u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence); +u32 tpm1_tsc_physical_presence(struct udevice *dev, u16 presence); /** * Issue a TPM_ReadPubek command. @@ -390,7 +390,7 @@ u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence); * @param count size of output buffer * @return return code of the operation */ -u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count); +u32 tpm1_read_pubek(struct udevice *dev, void *data, size_t count); /** * Issue a TPM_ForceClear command. @@ -398,7 +398,7 @@ u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count); * @param dev TPM device * @return return code of the operation */ -u32 tpm_force_clear(struct udevice *dev); +u32 tpm1_force_clear(struct udevice *dev); /** * Issue a TPM_PhysicalEnable command. @@ -406,7 +406,7 @@ u32 tpm_force_clear(struct udevice *dev); * @param dev TPM device * @return return code of the operation */ -u32 tpm_physical_enable(struct udevice *dev); +u32 tpm1_physical_enable(struct udevice *dev); /** * Issue a TPM_PhysicalDisable command. @@ -414,7 +414,7 @@ u32 tpm_physical_enable(struct udevice *dev); * @param dev TPM device * @return return code of the operation */ -u32 tpm_physical_disable(struct udevice *dev); +u32 tpm1_physical_disable(struct udevice *dev); /** * Issue a TPM_PhysicalSetDeactivated command. @@ -423,7 +423,7 @@ u32 tpm_physical_disable(struct udevice *dev); * @param state boolean state of the deactivated flag * @return return code of the operation */ -u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state); +u32 tpm1_physical_set_deactivated(struct udevice *dev, u8 state); /** * Issue a TPM_GetCapability command. This implementation is limited @@ -437,8 +437,8 @@ u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state); * @param count size of output buffer * @return return code of the operation */ -u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap, - void *cap, size_t count); +u32 tpm1_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap, + void *cap, size_t count); /** * Issue a TPM_FlushSpecific command for a AUTH resource. @@ -447,7 +447,7 @@ u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap, * @param auth_handle handle of the auth session * @return return code of the operation */ -u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle); +u32 tpm1_terminate_auth_session(struct udevice *dev, u32 auth_handle); /** * Issue a TPM_OIAP command to setup an object independent authorization @@ -460,7 +460,7 @@ u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle); * @param auth_handle pointer to the (new) auth handle or NULL. * @return return code of the operation */ -u32 tpm_oiap(struct udevice *dev, u32 *auth_handle); +u32 tpm1_oiap(struct udevice *dev, u32 *auth_handle); /** * Ends an active OIAP session. @@ -468,7 +468,7 @@ u32 tpm_oiap(struct udevice *dev, u32 *auth_handle); * @param dev TPM device * @return return code of the operation */ -u32 tpm_end_oiap(struct udevice *dev); +u32 tpm1_end_oiap(struct udevice *dev); /** * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating @@ -482,9 +482,9 @@ u32 tpm_end_oiap(struct udevice *dev); * @param key_handle pointer to the key handle * @return return code of the operation */ -u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key, - size_t key_length, const void *parent_key_usage_auth, - u32 *key_handle); +u32 tpm1_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key, + size_t key_length, const void *parent_key_usage_auth, + u32 *key_handle); /** * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for @@ -500,9 +500,9 @@ u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key, * of the stored TPM_PUBKEY structure (iff pubkey != NULL). * @return return code of the operation */ -u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle, - const void *usage_auth, void *pubkey, - size_t *pubkey_len); +u32 tpm1_get_pub_key_oiap(struct udevice *dev, u32 key_handle, + const void *usage_auth, void *pubkey, + size_t *pubkey_len); /** * Get the TPM permanent flags value @@ -511,8 +511,8 @@ u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle, * @param pflags Place to put permanent flags * @return return code of the operation */ -u32 tpm_get_permanent_flags(struct udevice *dev, - struct tpm_permanent_flags *pflags); +u32 tpm1_get_permanent_flags(struct udevice *dev, + struct tpm_permanent_flags *pflags); /** * Get the TPM permissions @@ -521,7 +521,7 @@ u32 tpm_get_permanent_flags(struct udevice *dev, * @param perm Returns permissions value * @return return code of the operation */ -u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm); +u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm); /** * Flush a resource with a given handle and type from the TPM @@ -531,7 +531,7 @@ u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm); * @param resource_type type of the resource * @return return code of the operation */ -u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type); +u32 tpm1_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type); #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 /** @@ -543,8 +543,8 @@ u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type); * @param[out] handle The handle of the key (Non-null iff found) * @return 0 if key was found in TPM; != 0 if not. */ -u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20], - const u8 pubkey_digest[20], u32 *handle); +u32 tpm1_find_key_sha1(struct udevice *dev, const u8 auth[20], + const u8 pubkey_digest[20], u32 *handle); #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ /** @@ -557,7 +557,7 @@ u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20], * @param count size of output buffer * @return return code of the operation */ -u32 tpm_get_random(struct udevice *dev, void *data, u32 count); +u32 tpm1_get_random(struct udevice *dev, void *data, u32 count); /** * tpm_finalise_physical_presence() - Finalise physical presence @@ -565,15 +565,15 @@ u32 tpm_get_random(struct udevice *dev, void *data, u32 count); * @param dev TPM device * @return return code of the operation (0 = success) */ -u32 tpm_finalise_physical_presence(struct udevice *dev); +u32 tpm1_finalise_physical_presence(struct udevice *dev); /** - * tpm_nv_set_locked() - lock the non-volatile space + * tpm_nv_enable_locking() - lock the non-volatile space * * @param dev TPM device * @return return code of the operation (0 = success) */ -u32 tpm_nv_set_locked(struct udevice *dev); +u32 tpm1_nv_set_locked(struct udevice *dev); /** * tpm_set_global_lock() - set the global lock @@ -589,6 +589,6 @@ u32 tpm_set_global_lock(struct udevice *dev); * @param dev TPM device * @return return code of the operation (0 = success) */ -u32 tpm_resume(struct udevice *dev); +u32 tpm1_resume(struct udevice *dev); #endif /* __TPM_V1_H */ diff --git a/lib/Makefile b/lib/Makefile index edc1c3dd4f9..c42d4e12335 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -53,6 +53,7 @@ endif obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-common.o ifeq ($(CONFIG_$(SPL_TPL_)TPM),y) obj-y += crc8.o +obj-$(CONFIG_TPM) += tpm_api.o obj-$(CONFIG_TPM_V1) += tpm-v1.o obj-$(CONFIG_TPM_V2) += tpm-v2.o endif diff --git a/lib/tpm-v1.c b/lib/tpm-v1.c index a846fe00dd3..8dc144080ca 100644 --- a/lib/tpm-v1.c +++ b/lib/tpm-v1.c @@ -32,7 +32,7 @@ static struct session_data oiap_session = {0, }; #endif /* CONFIG_TPM_AUTH_SESSIONS */ -u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode) +u32 tpm1_startup(struct udevice *dev, enum tpm_startup_type mode) { const u8 command[12] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0, @@ -48,12 +48,12 @@ u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode) return tpm_sendrecv_command(dev, buf, NULL, NULL); } -u32 tpm_resume(struct udevice *dev) +u32 tpm1_resume(struct udevice *dev) { - return tpm_startup(dev, TPM_ST_STATE); + return tpm1_startup(dev, TPM_ST_STATE); } -u32 tpm_self_test_full(struct udevice *dev) +u32 tpm1_self_test_full(struct udevice *dev) { const u8 command[10] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, @@ -61,7 +61,7 @@ u32 tpm_self_test_full(struct udevice *dev) return tpm_sendrecv_command(dev, command, NULL, NULL); } -u32 tpm_continue_self_test(struct udevice *dev) +u32 tpm1_continue_self_test(struct udevice *dev) { const u8 command[10] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53, @@ -69,35 +69,33 @@ u32 tpm_continue_self_test(struct udevice *dev) return tpm_sendrecv_command(dev, command, NULL, NULL); } -u32 tpm_clear_and_reenable(struct udevice *dev) +u32 tpm1_clear_and_reenable(struct udevice *dev) { u32 ret; log_info("TPM: Clear and re-enable\n"); - ret = tpm_force_clear(dev); + ret = tpm1_force_clear(dev); if (ret != TPM_SUCCESS) { log_err("Can't initiate a force clear\n"); return ret; } - if (tpm_get_version(dev) == TPM_V1) { - ret = tpm_physical_enable(dev); - if (ret != TPM_SUCCESS) { - log_err("TPM: Can't set enabled state\n"); - return ret; - } + ret = tpm1_physical_enable(dev); + if (ret != TPM_SUCCESS) { + log_err("TPM: Can't set enabled state\n"); + return ret; + } - ret = tpm_physical_set_deactivated(dev, 0); - if (ret != TPM_SUCCESS) { - log_err("TPM: Can't set deactivated state\n"); - return ret; - } + ret = tpm1_physical_set_deactivated(dev, 0); + if (ret != TPM_SUCCESS) { + log_err("TPM: Can't set deactivated state\n"); + return ret; } return TPM_SUCCESS; } -u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size) +u32 tpm1_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size) { const u8 command[101] = { 0x0, 0xc1, /* TPM_TAG */ @@ -140,12 +138,12 @@ u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size) return tpm_sendrecv_command(dev, buf, NULL, NULL); } -u32 tpm_nv_set_locked(struct udevice *dev) +u32 tpm1_nv_set_locked(struct udevice *dev) { - return tpm_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0); + return tpm1_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0); } -u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count) +u32 tpm1_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count) { const u8 command[22] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, @@ -179,8 +177,8 @@ u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count) return 0; } -u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data, - u32 length) +u32 tpm1_nv_write_value(struct udevice *dev, u32 index, const void *data, + u32 length) { const u8 command[256] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, @@ -210,13 +208,8 @@ u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data, return 0; } -uint32_t tpm_set_global_lock(struct udevice *dev) -{ - return tpm_nv_write_value(dev, TPM_NV_INDEX_0, NULL, 0); -} - -u32 tpm_extend(struct udevice *dev, u32 index, const void *in_digest, - void *out_digest) +u32 tpm1_extend(struct udevice *dev, u32 index, const void *in_digest, + void *out_digest) { const u8 command[34] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14, @@ -247,7 +240,7 @@ u32 tpm_extend(struct udevice *dev, u32 index, const void *in_digest, return 0; } -u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count) +u32 tpm1_pcr_read(struct udevice *dev, u32 index, void *data, size_t count) { const u8 command[14] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15, @@ -275,7 +268,7 @@ u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count) return 0; } -u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence) +u32 tpm1_tsc_physical_presence(struct udevice *dev, u16 presence) { const u8 command[12] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0, @@ -291,7 +284,7 @@ u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence) return tpm_sendrecv_command(dev, buf, NULL, NULL); } -u32 tpm_finalise_physical_presence(struct udevice *dev) +u32 tpm1_finalise_physical_presence(struct udevice *dev) { const u8 command[12] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0, @@ -300,7 +293,7 @@ u32 tpm_finalise_physical_presence(struct udevice *dev) return tpm_sendrecv_command(dev, command, NULL, NULL); } -u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count) +u32 tpm1_read_pubek(struct udevice *dev, void *data, size_t count) { const u8 command[30] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c, @@ -331,7 +324,7 @@ u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count) return 0; } -u32 tpm_force_clear(struct udevice *dev) +u32 tpm1_force_clear(struct udevice *dev) { const u8 command[10] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d, @@ -340,7 +333,7 @@ u32 tpm_force_clear(struct udevice *dev) return tpm_sendrecv_command(dev, command, NULL, NULL); } -u32 tpm_physical_enable(struct udevice *dev) +u32 tpm1_physical_enable(struct udevice *dev) { const u8 command[10] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f, @@ -349,7 +342,7 @@ u32 tpm_physical_enable(struct udevice *dev) return tpm_sendrecv_command(dev, command, NULL, NULL); } -u32 tpm_physical_disable(struct udevice *dev) +u32 tpm1_physical_disable(struct udevice *dev) { const u8 command[10] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70, @@ -358,7 +351,7 @@ u32 tpm_physical_disable(struct udevice *dev) return tpm_sendrecv_command(dev, command, NULL, NULL); } -u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state) +u32 tpm1_physical_set_deactivated(struct udevice *dev, u8 state) { const u8 command[11] = { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72, @@ -374,8 +367,8 @@ u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state) return tpm_sendrecv_command(dev, buf, NULL, NULL); } -u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap, - void *cap, size_t count) +u32 tpm1_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap, + void *cap, size_t count) { const u8 command[22] = { 0x0, 0xc1, /* TPM_TAG */ @@ -414,8 +407,8 @@ u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap, return 0; } -u32 tpm_get_permanent_flags(struct udevice *dev, - struct tpm_permanent_flags *pflags) +u32 tpm1_get_permanent_flags(struct udevice *dev, + struct tpm_permanent_flags *pflags) { const u8 command[22] = { 0x0, 0xc1, /* TPM_TAG */ @@ -453,7 +446,7 @@ u32 tpm_get_permanent_flags(struct udevice *dev, return 0; } -u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm) +u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm) { const u8 command[22] = { 0x0, 0xc1, /* TPM_TAG */ @@ -482,7 +475,7 @@ u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm) } #ifdef CONFIG_TPM_FLUSH_RESOURCES -u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type) +u32 tpm1_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type) { const u8 command[18] = { 0x00, 0xc1, /* TPM_TAG */ @@ -641,7 +634,7 @@ static u32 verify_response_auth(u32 command_code, const void *response, return TPM_SUCCESS; } -u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle) +u32 tpm1_terminate_auth_session(struct udevice *dev, u32 auth_handle) { const u8 command[18] = { 0x00, 0xc1, /* TPM_TAG */ @@ -663,16 +656,16 @@ u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle) return tpm_sendrecv_command(dev, request, NULL, NULL); } -u32 tpm_end_oiap(struct udevice *dev) +u32 tpm1_end_oiap(struct udevice *dev) { u32 err = TPM_SUCCESS; if (oiap_session.valid) - err = tpm_terminate_auth_session(dev, oiap_session.handle); + err = tpm1_terminate_auth_session(dev, oiap_session.handle); return err; } -u32 tpm_oiap(struct udevice *dev, u32 *auth_handle) +u32 tpm1_oiap(struct udevice *dev, u32 *auth_handle) { const u8 command[10] = { 0x00, 0xc1, /* TPM_TAG */ @@ -686,7 +679,7 @@ u32 tpm_oiap(struct udevice *dev, u32 *auth_handle) u32 err; if (oiap_session.valid) - tpm_terminate_auth_session(dev, oiap_session.handle); + tpm1_terminate_auth_session(dev, oiap_session.handle); err = tpm_sendrecv_command(dev, command, response, &response_length); if (err) @@ -702,9 +695,9 @@ u32 tpm_oiap(struct udevice *dev, u32 *auth_handle) return 0; } -u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key, - size_t key_length, const void *parent_key_usage_auth, - u32 *key_handle) +u32 tpm1_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key, + size_t key_length, const void *parent_key_usage_auth, + u32 *key_handle) { const u8 command[14] = { 0x00, 0xc2, /* TPM_TAG */ @@ -723,7 +716,7 @@ u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key, u32 err; if (!oiap_session.valid) { - err = tpm_oiap(dev, NULL); + err = tpm1_oiap(dev, NULL); if (err) return err; } @@ -768,9 +761,9 @@ u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key, return 0; } -u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle, - const void *usage_auth, void *pubkey, - size_t *pubkey_len) +u32 tpm1_get_pub_key_oiap(struct udevice *dev, u32 key_handle, + const void *usage_auth, void *pubkey, + size_t *pubkey_len) { const u8 command[14] = { 0x00, 0xc2, /* TPM_TAG */ @@ -788,7 +781,7 @@ u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle, u32 err; if (!oiap_session.valid) { - err = tpm_oiap(dev, NULL); + err = tpm1_oiap(dev, NULL); if (err) return err; } @@ -834,8 +827,8 @@ u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle, } #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 -u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20], - const u8 pubkey_digest[20], u32 *handle) +u32 tpm1_find_key_sha1(struct udevice *dev, const u8 auth[20], + const u8 pubkey_digest[20], u32 *handle) { u16 key_count; u32 key_handles[10]; @@ -876,7 +869,7 @@ u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20], #endif /* CONFIG_TPM_AUTH_SESSIONS */ -u32 tpm_get_random(struct udevice *dev, void *data, u32 count) +u32 tpm1_get_random(struct udevice *dev, void *data, u32 count) { const u8 command[14] = { 0x0, 0xc1, /* TPM_TAG */ -- cgit v1.3.1 From eadcbc7896e8d3eefafc8a34dee125a7d7eecead Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 6 Feb 2021 14:23:39 -0700 Subject: tpm: Add an implementation of define_space Add support for this so that the TPM can be set up for use with Chromium OS verified boot. Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- include/tpm-v2.h | 18 ++++++++++++++++++ lib/tpm-v2.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) (limited to 'include') diff --git a/include/tpm-v2.h b/include/tpm-v2.h index 56eaa65815f..aa8b6512b2b 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -240,6 +240,7 @@ enum tpm2_command_codes { TPM2_CC_CLEAR = 0x0126, TPM2_CC_CLEARCONTROL = 0x0127, TPM2_CC_HIERCHANGEAUTH = 0x0129, + TPM2_CC_NV_DEFINE_SPACE = 0x012a, TPM2_CC_PCR_SETAUTHPOL = 0x012C, TPM2_CC_DAM_RESET = 0x0139, TPM2_CC_DAM_PARAMETERS = 0x013A, @@ -388,6 +389,23 @@ u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test); u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw, const ssize_t pw_sz); +/** + * Issue a TPM_NV_DefineSpace command + * + * This allows a space to be defined with given attributes and policy + * + * @dev TPM device + * @space_index index of the area + * @space_size size of area in bytes + * @nv_attributes TPM_NV_ATTRIBUTES of the area + * @nv_policy policy to use + * @nv_policy_size size of the policy + * @return return code of the operation + */ +u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index, + size_t space_size, u32 nv_attributes, + const u8 *nv_policy, size_t nv_policy_size); + /** * Issue a TPM2_PCR_Extend command. * diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index c4e869ec5b5..e9bf4018fed 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -81,6 +81,53 @@ u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw, return tpm_sendrecv_command(dev, command_v2, NULL, NULL); } +u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index, + size_t space_size, u32 nv_attributes, + const u8 *nv_policy, size_t nv_policy_size) +{ + /* + * Calculate the offset of the nv_policy piece by adding each of the + * chunks below. + */ + uint offset = 10 + 8 + 13 + 14; + u8 command_v2[COMMAND_BUFFER_SIZE] = { + /* header 10 bytes */ + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(offset + nv_policy_size),/* Length */ + tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */ + + /* handles 8 bytes */ + tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ + + /* session header 13 bytes */ + tpm_u32(9), /* Header size */ + tpm_u32(TPM2_RS_PW), /* Password authorisation */ + tpm_u16(0), /* nonce_size */ + 0, /* session_attrs */ + tpm_u16(0), /* auth_size */ + + /* message 14 bytes + policy */ + tpm_u16(12 + nv_policy_size), /* size */ + tpm_u32(space_index), + tpm_u16(TPM2_ALG_SHA256), + tpm_u32(nv_attributes), + tpm_u16(nv_policy_size), + /* nv_policy */ + }; + int ret; + + /* + * Fill the command structure starting from the first buffer: + * - the password (if any) + */ + ret = pack_byte_string(command_v2, sizeof(command_v2), "s", + offset, nv_policy, nv_policy_size); + if (ret) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(dev, command_v2, NULL, NULL); +} + u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm, const u8 *digest, u32 digest_len) { -- cgit v1.3.1 From 6719cbe31afef2cba4bc10b33350b38c4a51c3ac Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 6 Feb 2021 14:23:40 -0700 Subject: tpm: Add TPM2 support for read/write values Implement this API function for TPM2. Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- include/tpm-common.h | 3 ++ include/tpm-v2.h | 38 ++++++++++++++++++++++++ lib/tpm-v2.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/tpm_api.c | 4 +-- 4 files changed, 127 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/tpm-common.h b/include/tpm-common.h index c1309a2735d..998b4fbb415 100644 --- a/include/tpm-common.h +++ b/include/tpm-common.h @@ -55,6 +55,8 @@ enum tpm_version { * @buf: Buffer used during the exchanges with the chip * @pcr_count: Number of PCR per bank * @pcr_select_min: Minimum size in bytes of the pcrSelect array + * @plat_hier_disabled: Platform hierarchy has been disabled (TPM is locked + * down until next reboot) */ struct tpm_chip_priv { enum tpm_version version; @@ -66,6 +68,7 @@ struct tpm_chip_priv { /* TPM v2 specific data */ uint pcr_count; uint pcr_select_min; + bool plat_hier_disabled; }; /** diff --git a/include/tpm-v2.h b/include/tpm-v2.h index aa8b6512b2b..b73a2d278e7 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -242,6 +242,7 @@ enum tpm2_command_codes { TPM2_CC_HIERCHANGEAUTH = 0x0129, TPM2_CC_NV_DEFINE_SPACE = 0x012a, TPM2_CC_PCR_SETAUTHPOL = 0x012C, + TPM2_CC_NV_WRITE = 0x0137, TPM2_CC_DAM_RESET = 0x0139, TPM2_CC_DAM_PARAMETERS = 0x013A, TPM2_CC_NV_READ = 0x014E, @@ -356,6 +357,20 @@ enum { TPM_MAX_BUF_SIZE = 1260, }; +enum { + /* Secure storage for firmware settings */ + TPM_HT_PCR = 0, + TPM_HT_NV_INDEX, + TPM_HT_HMAC_SESSION, + TPM_HT_POLICY_SESSION, + + HR_SHIFT = 24, + HR_PCR = TPM_HT_PCR << HR_SHIFT, + HR_HMAC_SESSION = TPM_HT_HMAC_SESSION << HR_SHIFT, + HR_POLICY_SESSION = TPM_HT_POLICY_SESSION << HR_SHIFT, + HR_NV_INDEX = TPM_HT_NV_INDEX << HR_SHIFT, +}; + /** * Issue a TPM2_Startup command. * @@ -420,6 +435,29 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index, u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm, const u8 *digest, u32 digest_len); +/** + * Read data from the secure storage + * + * @dev TPM device + * @index Index of data to read + * @data Place to put data + * @count Number of bytes of data + * @return code of the operation + */ +u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count); + +/** + * Write data to the secure storage + * + * @dev TPM device + * @index Index of data to write + * @data Data to write + * @count Number of bytes of data + * @return code of the operation + */ +u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data, + u32 count); + /** * Issue a TPM2_PCR_Read command. * diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index e9bf4018fed..9f1699131e1 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -169,6 +169,90 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm, return tpm_sendrecv_command(dev, command_v2, NULL, NULL); } +u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count) +{ + u8 command_v2[COMMAND_BUFFER_SIZE] = { + /* header 10 bytes */ + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(10 + 8 + 4 + 9 + 4), /* Length */ + tpm_u32(TPM2_CC_NV_READ), /* Command code */ + + /* handles 8 bytes */ + tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ + tpm_u32(HR_NV_INDEX + index), /* Password authorisation */ + + /* AUTH_SESSION */ + tpm_u32(9), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* Session handle */ + tpm_u16(0), /* Size of */ + /* (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(0), /* Size of */ + /* (if any) */ + + tpm_u16(count), /* Number of bytes */ + tpm_u16(0), /* Offset */ + }; + size_t response_len = COMMAND_BUFFER_SIZE; + u8 response[COMMAND_BUFFER_SIZE]; + int ret; + u16 tag; + u32 size, code; + + ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); + if (ret) + return log_msg_ret("read", ret); + if (unpack_byte_string(response, response_len, "wdds", + 0, &tag, 2, &size, 6, &code, + 16, data, count)) + return TPM_LIB_ERROR; + + return 0; +} + +u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data, + u32 count) +{ + struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); + uint offset = 10 + 8 + 4 + 9 + 2; + uint len = offset + count + 2; + /* Use empty password auth if platform hierarchy is disabled */ + u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index : + TPM2_RH_PLATFORM; + u8 command_v2[COMMAND_BUFFER_SIZE] = { + /* header 10 bytes */ + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(len), /* Length */ + tpm_u32(TPM2_CC_NV_WRITE), /* Command code */ + + /* handles 8 bytes */ + tpm_u32(auth), /* Primary platform seed */ + tpm_u32(HR_NV_INDEX + index), /* Password authorisation */ + + /* AUTH_SESSION */ + tpm_u32(9), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* Session handle */ + tpm_u16(0), /* Size of */ + /* (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(0), /* Size of */ + /* (if any) */ + + tpm_u16(count), + }; + size_t response_len = COMMAND_BUFFER_SIZE; + u8 response[COMMAND_BUFFER_SIZE]; + int ret; + + ret = pack_byte_string(command_v2, sizeof(command_v2), "sw", + offset, data, count, + offset + count, 0); + if (ret) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(dev, command_v2, response, &response_len); +} + u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz, void *data, unsigned int *updates) { diff --git a/lib/tpm_api.c b/lib/tpm_api.c index f1553512cc5..687fc8bc7ee 100644 --- a/lib/tpm_api.c +++ b/lib/tpm_api.c @@ -118,7 +118,7 @@ u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count) if (is_tpm1(dev)) return tpm1_nv_read_value(dev, index, data, count); else if (is_tpm2(dev)) - return -ENOSYS; + return tpm2_nv_read_value(dev, index, data, count); else return -ENOSYS; } @@ -129,7 +129,7 @@ u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data, if (is_tpm1(dev)) return tpm1_nv_write_value(dev, index, data, count); else if (is_tpm2(dev)) - return -ENOSYS; + return tpm2_nv_write_value(dev, index, data, count); else return -ENOSYS; } -- cgit v1.3.1 From 7785bc1d5f94d28497bef6935ecbaa1b0ddd3e26 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 6 Feb 2021 14:23:41 -0700 Subject: tpm: Add TPM2 support for write_lock Implement this API function for TPM2. Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- include/tpm-v2.h | 12 ++++++++++++ lib/tpm-v2.c | 23 +++++++++++++++++++++++ lib/tpm_api.c | 2 +- 3 files changed, 36 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/tpm-v2.h b/include/tpm-v2.h index b73a2d278e7..fa3296a7b0e 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -243,6 +243,7 @@ enum tpm2_command_codes { TPM2_CC_NV_DEFINE_SPACE = 0x012a, TPM2_CC_PCR_SETAUTHPOL = 0x012C, TPM2_CC_NV_WRITE = 0x0137, + TPM2_CC_NV_WRITELOCK = 0x0138, TPM2_CC_DAM_RESET = 0x0139, TPM2_CC_DAM_PARAMETERS = 0x013A, TPM2_CC_NV_READ = 0x014E, @@ -572,4 +573,15 @@ u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw, */ u32 tpm2_get_random(struct udevice *dev, void *data, u32 count); +/** + * Lock data in the TPM + * + * Once locked the data cannot be written until after a reboot + * + * @dev TPM device + * @index Index of data to lock + * @return code of the operation + */ +u32 tpm2_write_lock(struct udevice *dev, u32 index); + #endif /* __TPM_V2_H */ diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 9f1699131e1..b796004930e 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -601,3 +601,26 @@ u32 tpm2_get_random(struct udevice *dev, void *data, u32 count) return 0; } + +u32 tpm2_write_lock(struct udevice *dev, u32 index) +{ + u8 command_v2[COMMAND_BUFFER_SIZE] = { + /* header 10 bytes */ + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(10 + 8 + 13), /* Length */ + tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */ + + /* handles 8 bytes */ + tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ + tpm_u32(HR_NV_INDEX + index), /* Password authorisation */ + + /* session header 9 bytes */ + tpm_u32(9), /* Header size */ + tpm_u32(TPM2_RS_PW), /* Password authorisation */ + tpm_u16(0), /* nonce_size */ + 0, /* session_attrs */ + tpm_u16(0), /* auth_size */ + }; + + return tpm_sendrecv_command(dev, command_v2, NULL, NULL); +} diff --git a/lib/tpm_api.c b/lib/tpm_api.c index 687fc8bc7ee..4c662640a92 100644 --- a/lib/tpm_api.c +++ b/lib/tpm_api.c @@ -144,7 +144,7 @@ u32 tpm_write_lock(struct udevice *dev, u32 index) if (is_tpm1(dev)) return -ENOSYS; else if (is_tpm2(dev)) - return -ENOSYS; + return tpm2_write_lock(dev, index); else return -ENOSYS; } -- cgit v1.3.1 From 63af92e837f3d7c21ab5fc4a96ffcbf202efaf90 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 6 Feb 2021 14:23:42 -0700 Subject: tpm: Allow disabling platform hierarchy with TPM2 With TPM2 we don't actually lock the TPM once verified boot is finished. Instead we disable the platform hierarchy which serves the same purpose. Add an implementation of this so we can safely boot into the kernel. Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- include/tpm-v2.h | 13 +++++++++++++ lib/tpm-v2.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) (limited to 'include') diff --git a/include/tpm-v2.h b/include/tpm-v2.h index fa3296a7b0e..df67a196cf3 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -237,6 +237,7 @@ enum tpm2_handles { enum tpm2_command_codes { TPM2_CC_STARTUP = 0x0144, TPM2_CC_SELF_TEST = 0x0143, + TPM2_CC_HIER_CONTROL = 0x0121, TPM2_CC_CLEAR = 0x0126, TPM2_CC_CLEARCONTROL = 0x0127, TPM2_CC_HIERCHANGEAUTH = 0x0129, @@ -274,6 +275,7 @@ enum tpm2_return_codes { TPM2_RC_COMMAND_CODE = TPM2_RC_VER1 + 0x0043, TPM2_RC_AUTHSIZE = TPM2_RC_VER1 + 0x0044, TPM2_RC_AUTH_CONTEXT = TPM2_RC_VER1 + 0x0045, + TPM2_RC_NV_DEFINED = TPM2_RC_VER1 + 0x004c, TPM2_RC_NEEDS_TEST = TPM2_RC_VER1 + 0x0053, TPM2_RC_WARN = 0x0900, TPM2_RC_TESTING = TPM2_RC_WARN + 0x000A, @@ -584,4 +586,15 @@ u32 tpm2_get_random(struct udevice *dev, void *data, u32 count); */ u32 tpm2_write_lock(struct udevice *dev, u32 index); +/** + * Disable access to any platform data + * + * This can be called to close off access to the firmware data in the data, + * before calling the kernel. + * + * @dev TPM device + * @return code of the operation + */ +u32 tpm2_disable_platform_hierarchy(struct udevice *dev); + #endif /* __TPM_V2_H */ diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index b796004930e..235f8c20d43 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -624,3 +624,38 @@ u32 tpm2_write_lock(struct udevice *dev, u32 index) return tpm_sendrecv_command(dev, command_v2, NULL, NULL); } + +u32 tpm2_disable_platform_hierarchy(struct udevice *dev) +{ + struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); + u8 command_v2[COMMAND_BUFFER_SIZE] = { + /* header 10 bytes */ + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(10 + 4 + 13 + 5), /* Length */ + tpm_u32(TPM2_CC_HIER_CONTROL), /* Command code */ + + /* 4 bytes */ + tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ + + /* session header 9 bytes */ + tpm_u32(9), /* Header size */ + tpm_u32(TPM2_RS_PW), /* Password authorisation */ + tpm_u16(0), /* nonce_size */ + 0, /* session_attrs */ + tpm_u16(0), /* auth_size */ + + /* payload 5 bytes */ + tpm_u32(TPM2_RH_PLATFORM), /* Hierarchy to disable */ + 0, /* 0=disable */ + }; + int ret; + + ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL); + log_info("ret=%s, %x\n", dev->name, ret); + if (ret) + return ret; + + priv->plat_hier_disabled = true; + + return 0; +} -- cgit v1.3.1 From 5d235324ae7a5b04b37c63a3445020fbd89ac7b2 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 22 Feb 2021 00:12:34 +0000 Subject: video: sunxi_display: Convert to DM_VIDEO DM_VIDEO migration deadline is already expired, but around 80 Allwinner boards are still using video in a legacy way: ===================== WARNING ====================== This board does not use CONFIG_DM_VIDEO Please update the board to use CONFIG_DM_VIDEO before the v2019.07 release. Failure to update by the deadline may result in board removal. See doc/driver-model/migration.rst for more info. ==================================================== Convert the legacy video driver over to the DM_VIDEO framework. This is a minimal conversion: it doesn't use the DT for finding its resources, nor does it use DM clocks or DM devices for the outputs (LCD, HDMI, CVBS). Tested in Bananapi M1+ Plus 1920x1200 HDMI out. (Jagan) Signed-off-by: Jagan Teki [Andre: rebase and smaller fixes] Signed-off-by: Andre Przywara Acked-by: Maxime Ripard Reviewed-by: Jernej Skrabec Reviewed-by: Simon Glass --- arch/arm/mach-sunxi/Kconfig | 9 +- drivers/video/sunxi/sunxi_display.c | 268 ++++++++++++++++++++---------------- include/configs/sunxi-common.h | 23 +--- scripts/config_whitelist.txt | 1 - 4 files changed, 159 insertions(+), 142 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 0135575ca1e..a29d11505aa 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -816,13 +816,14 @@ config VIDEO_SUNXI depends on !MACH_SUN9I depends on !MACH_SUN50I depends on !SUN50I_GEN_H6 - select VIDEO + select DM_VIDEO + select DISPLAY imply VIDEO_DT_SIMPLEFB default y ---help--- - Say Y here to add support for using a cfb console on the HDMI, LCD - or VGA output found on most sunxi devices. See doc/README.video for - info on how to select the video output and mode. + Say Y here to add support for using a graphical console on the HDMI, + LCD or VGA output found on older sunxi devices. This will also provide + a simple_framebuffer device for Linux. config VIDEO_HDMI bool "HDMI output support" diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c index f52aba4d21c..4361a58cd7e 100644 --- a/drivers/video/sunxi/sunxi_display.c +++ b/drivers/video/sunxi/sunxi_display.c @@ -7,6 +7,8 @@ */ #include +#include +#include #include #include #include @@ -28,7 +30,9 @@ #include #include #include +#include #include +#include #include "../videomodes.h" #include "../anx9804.h" #include "../hitachi_tx18d42vm_lcd.h" @@ -45,6 +49,11 @@ DECLARE_GLOBAL_DATA_PTR; +/* Maximum LCD size we support */ +#define LCD_MAX_WIDTH 3840 +#define LCD_MAX_HEIGHT 2160 +#define LCD_MAX_LOG2_BPP VIDEO_BPP32 + enum sunxi_monitor { sunxi_monitor_none, sunxi_monitor_dvi, @@ -58,13 +67,12 @@ enum sunxi_monitor { }; #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc -struct sunxi_display { - GraphicDevice graphic_device; +struct sunxi_display_priv { enum sunxi_monitor monitor; unsigned int depth; unsigned int fb_addr; unsigned int fb_size; -} sunxi_display; +}; const struct ctfb_res_modes composite_video_modes[2] = { /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */ @@ -214,7 +222,8 @@ static int sunxi_hdmi_edid_get_block(int block, u8 *buf) return r; } -static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode, +static int sunxi_hdmi_edid_get_mode(struct sunxi_display_priv *sunxi_display, + struct ctfb_res_modes *mode, bool verbose_mode) { struct edid1_info edid1; @@ -291,14 +300,14 @@ static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode, } /* Check for basic audio support, if found enable hdmi output */ - sunxi_display.monitor = sunxi_monitor_dvi; + sunxi_display->monitor = sunxi_monitor_dvi; for (i = 0; i < ext_blocks; i++) { if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG || cea681[i].revision < 2) continue; if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i])) - sunxi_display.monitor = sunxi_monitor_hdmi; + sunxi_display->monitor = sunxi_monitor_hdmi; } return 0; @@ -414,9 +423,9 @@ static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode, static void sunxi_frontend_enable(void) {} #endif -static bool sunxi_is_composite(void) +static bool sunxi_is_composite(enum sunxi_monitor monitor) { - switch (sunxi_display.monitor) { + switch (monitor) { case sunxi_monitor_none: case sunxi_monitor_dvi: case sunxi_monitor_hdmi: @@ -473,7 +482,8 @@ static const u32 sunxi_rgb2yuv_coef[12] = { }; static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode, - unsigned int address) + unsigned int address, + enum sunxi_monitor monitor) { struct sunxi_de_be_reg * const de_be = (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE; @@ -502,7 +512,7 @@ static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode, #endif SUNXI_DE_BE_MODE_INTERLACE_ENABLE); - if (sunxi_is_composite()) { + if (sunxi_is_composite(monitor)) { writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE, &de_be->output_color_ctrl); for (i = 0; i < 12; i++) @@ -616,7 +626,8 @@ static void sunxi_lcdc_backlight_enable(void) gpio_direction_output(pin, PWM_ON); } -static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode, +static void sunxi_lcdc_tcon0_mode_set(struct sunxi_display_priv *sunxi_display, + const struct ctfb_res_modes *mode, bool for_ext_vga_dac) { struct sunxi_lcdc_reg * const lcdc = @@ -643,17 +654,18 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode, } lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double, - sunxi_is_composite()); + sunxi_is_composite(sunxi_display->monitor)); video_ctfb_mode_to_display_timing(mode, &timing); lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac, - sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE); + sunxi_display->depth, CONFIG_VIDEO_LCD_DCLK_PHASE); } #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode, int *clk_div, int *clk_double, - bool use_portd_hvsync) + bool use_portd_hvsync, + enum sunxi_monitor monitor) { struct sunxi_lcdc_reg * const lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; @@ -663,7 +675,7 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode, video_ctfb_mode_to_display_timing(mode, &timing); lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync, - sunxi_is_composite()); + sunxi_is_composite(monitor)); if (use_portd_hvsync) { sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0); @@ -671,7 +683,7 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode, } lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double, - sunxi_is_composite()); + sunxi_is_composite(monitor)); } #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */ @@ -725,7 +737,8 @@ static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode) } static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode, - int clk_div, int clk_double) + int clk_div, int clk_double, + enum sunxi_monitor monitor) { struct sunxi_hdmi_reg * const hdmi = (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; @@ -734,7 +747,7 @@ static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode, /* Write clear interrupt status bits */ writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq); - if (sunxi_display.monitor == sunxi_monitor_hdmi) + if (monitor == sunxi_monitor_hdmi) sunxi_hdmi_setup_info_frames(mode); /* Set input sync enable */ @@ -789,7 +802,7 @@ static void sunxi_hdmi_enable(void) #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE -static void sunxi_tvencoder_mode_set(void) +static void sunxi_tvencoder_mode_set(enum sunxi_monitor monitor) { struct sunxi_ccm_reg * const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; @@ -801,7 +814,7 @@ static void sunxi_tvencoder_mode_set(void) /* Clock on */ setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0); - switch (sunxi_display.monitor) { + switch (monitor) { case sunxi_monitor_vga: tvencoder_mode_set(tve, tve_mode_vga); break; @@ -896,26 +909,28 @@ static void sunxi_engines_init(void) sunxi_drc_init(); } -static void sunxi_mode_set(const struct ctfb_res_modes *mode, +static void sunxi_mode_set(struct sunxi_display_priv *sunxi_display, + const struct ctfb_res_modes *mode, unsigned int address) { + enum sunxi_monitor monitor = sunxi_display->monitor; int __maybe_unused clk_div, clk_double; struct sunxi_lcdc_reg * const lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; struct sunxi_tve_reg * __maybe_unused const tve = (struct sunxi_tve_reg *)SUNXI_TVE0_BASE; - switch (sunxi_display.monitor) { + switch (sunxi_display->monitor) { case sunxi_monitor_none: break; case sunxi_monitor_dvi: case sunxi_monitor_hdmi: #ifdef CONFIG_VIDEO_HDMI - sunxi_composer_mode_set(mode, address); - sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0); - sunxi_hdmi_mode_set(mode, clk_div, clk_double); + sunxi_composer_mode_set(mode, address, monitor); + sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor); + sunxi_hdmi_mode_set(mode, clk_div, clk_double, monitor); sunxi_composer_enable(); - lcdc_enable(lcdc, sunxi_display.depth); + lcdc_enable(lcdc, sunxi_display->depth); sunxi_hdmi_enable(); #endif break; @@ -930,7 +945,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, axp_set_eldo(3, 1800); anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4, ANX9804_DATA_RATE_1620M, - sunxi_display.depth); + sunxi_display->depth); } if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) { mdelay(50); /* Wait for lcd controller power on */ @@ -942,10 +957,10 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */ i2c_set_bus_num(orig_i2c_bus); } - sunxi_composer_mode_set(mode, address); - sunxi_lcdc_tcon0_mode_set(mode, false); + sunxi_composer_mode_set(mode, address, monitor); + sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false); sunxi_composer_enable(); - lcdc_enable(lcdc, sunxi_display.depth); + lcdc_enable(lcdc, sunxi_display->depth); #ifdef CONFIG_VIDEO_LCD_SSD2828 sunxi_ssd2828_init(mode); #endif @@ -953,17 +968,17 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, break; case sunxi_monitor_vga: #ifdef CONFIG_VIDEO_VGA - sunxi_composer_mode_set(mode, address); - sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1); - sunxi_tvencoder_mode_set(); + sunxi_composer_mode_set(mode, address, monitor); + sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1, monitor); + sunxi_tvencoder_mode_set(monitor); sunxi_composer_enable(); - lcdc_enable(lcdc, sunxi_display.depth); + lcdc_enable(lcdc, sunxi_display->depth); tvencoder_enable(tve); #elif defined CONFIG_VIDEO_VGA_VIA_LCD - sunxi_composer_mode_set(mode, address); - sunxi_lcdc_tcon0_mode_set(mode, true); + sunxi_composer_mode_set(mode, address, monitor); + sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, true); sunxi_composer_enable(); - lcdc_enable(lcdc, sunxi_display.depth); + lcdc_enable(lcdc, sunxi_display->depth); sunxi_vga_external_dac_enable(); #endif break; @@ -972,11 +987,11 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, case sunxi_monitor_composite_pal_m: case sunxi_monitor_composite_pal_nc: #ifdef CONFIG_VIDEO_COMPOSITE - sunxi_composer_mode_set(mode, address); - sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0); - sunxi_tvencoder_mode_set(); + sunxi_composer_mode_set(mode, address, monitor); + sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor); + sunxi_tvencoder_mode_set(monitor); sunxi_composer_enable(); - lcdc_enable(lcdc, sunxi_display.depth); + lcdc_enable(lcdc, sunxi_display->depth); tvencoder_enable(tve); #endif break; @@ -999,11 +1014,6 @@ static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor) } } -ulong board_get_usable_ram_top(ulong total_size) -{ - return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE; -} - static bool sunxi_has_hdmi(void) { #ifdef CONFIG_VIDEO_HDMI @@ -1052,9 +1062,11 @@ static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi) return sunxi_monitor_none; } -void *video_hw_init(void) +static int sunxi_de_probe(struct udevice *dev) { - static GraphicDevice *graphic_device = &sunxi_display.graphic_device; + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct video_uc_plat *plat = dev_get_uclass_plat(dev); + struct sunxi_display_priv *sunxi_display = dev_get_priv(dev); const struct ctfb_res_modes *mode; struct ctfb_res_modes custom; const char *options; @@ -1067,10 +1079,8 @@ void *video_hw_init(void) char mon[16]; char *lcd_mode = CONFIG_VIDEO_LCD_MODE; - memset(&sunxi_display, 0, sizeof(struct sunxi_display)); - video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode, - &sunxi_display.depth, &options); + &sunxi_display->depth, &options); #ifdef CONFIG_VIDEO_HDMI hpd = video_get_option_int(options, "hpd", 1); hpd_delay = video_get_option_int(options, "hpd_delay", 500); @@ -1078,35 +1088,35 @@ void *video_hw_init(void) #endif overscan_x = video_get_option_int(options, "overscan_x", -1); overscan_y = video_get_option_int(options, "overscan_y", -1); - sunxi_display.monitor = sunxi_get_default_mon(true); + sunxi_display->monitor = sunxi_get_default_mon(true); video_get_option_string(options, "monitor", mon, sizeof(mon), - sunxi_get_mon_desc(sunxi_display.monitor)); + sunxi_get_mon_desc(sunxi_display->monitor)); for (i = 0; i <= SUNXI_MONITOR_LAST; i++) { if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) { - sunxi_display.monitor = i; + sunxi_display->monitor = i; break; } } if (i > SUNXI_MONITOR_LAST) printf("Unknown monitor: '%s', falling back to '%s'\n", - mon, sunxi_get_mon_desc(sunxi_display.monitor)); + mon, sunxi_get_mon_desc(sunxi_display->monitor)); #ifdef CONFIG_VIDEO_HDMI /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */ - if (sunxi_display.monitor == sunxi_monitor_dvi || - sunxi_display.monitor == sunxi_monitor_hdmi) { + if (sunxi_display->monitor == sunxi_monitor_dvi || + sunxi_display->monitor == sunxi_monitor_hdmi) { /* Always call hdp_detect, as it also enables clocks, etc. */ hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1); if (hdmi_present && edid) { printf("HDMI connected: "); - if (sunxi_hdmi_edid_get_mode(&custom, true) == 0) + if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, true) == 0) mode = &custom; else hdmi_present = false; } /* Fall back to EDID in case HPD failed */ if (edid && !hdmi_present) { - if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) { + if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, false) == 0) { mode = &custom; hdmi_present = true; } @@ -1114,38 +1124,39 @@ void *video_hw_init(void) /* Shut down when display was not found */ if ((hpd || edid) && !hdmi_present) { sunxi_hdmi_shutdown(); - sunxi_display.monitor = sunxi_get_default_mon(false); + sunxi_display->monitor = sunxi_get_default_mon(false); } /* else continue with hdmi/dvi without a cable connected */ } #endif - switch (sunxi_display.monitor) { + switch (sunxi_display->monitor) { case sunxi_monitor_none: - return NULL; + printf("Unknown monitor\n"); + return -EINVAL; case sunxi_monitor_dvi: case sunxi_monitor_hdmi: if (!sunxi_has_hdmi()) { printf("HDMI/DVI not supported on this board\n"); - sunxi_display.monitor = sunxi_monitor_none; - return NULL; + sunxi_display->monitor = sunxi_monitor_none; + return -EINVAL; } break; case sunxi_monitor_lcd: if (!sunxi_has_lcd()) { printf("LCD not supported on this board\n"); - sunxi_display.monitor = sunxi_monitor_none; - return NULL; + sunxi_display->monitor = sunxi_monitor_none; + return -EINVAL; } - sunxi_display.depth = video_get_params(&custom, lcd_mode); + sunxi_display->depth = video_get_params(&custom, lcd_mode); mode = &custom; break; case sunxi_monitor_vga: if (!sunxi_has_vga()) { printf("VGA not supported on this board\n"); - sunxi_display.monitor = sunxi_monitor_none; - return NULL; + sunxi_display->monitor = sunxi_monitor_none; + return -EINVAL; } - sunxi_display.depth = 18; + sunxi_display->depth = 18; break; case sunxi_monitor_composite_pal: case sunxi_monitor_composite_ntsc: @@ -1153,85 +1164,99 @@ void *video_hw_init(void) case sunxi_monitor_composite_pal_nc: if (!sunxi_has_composite()) { printf("Composite video not supported on this board\n"); - sunxi_display.monitor = sunxi_monitor_none; - return NULL; + sunxi_display->monitor = sunxi_monitor_none; + return -EINVAL; } - if (sunxi_display.monitor == sunxi_monitor_composite_pal || - sunxi_display.monitor == sunxi_monitor_composite_pal_nc) + if (sunxi_display->monitor == sunxi_monitor_composite_pal || + sunxi_display->monitor == sunxi_monitor_composite_pal_nc) mode = &composite_video_modes[0]; else mode = &composite_video_modes[1]; - sunxi_display.depth = 24; + sunxi_display->depth = 24; break; } /* Yes these defaults are quite high, overscan on composite sucks... */ if (overscan_x == -1) - overscan_x = sunxi_is_composite() ? 32 : 0; + overscan_x = sunxi_is_composite(sunxi_display->monitor) ? 32 : 0; if (overscan_y == -1) - overscan_y = sunxi_is_composite() ? 20 : 0; + overscan_y = sunxi_is_composite(sunxi_display->monitor) ? 20 : 0; - sunxi_display.fb_size = - (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff; + sunxi_display->fb_size = plat->size; overscan_offset = (overscan_y * mode->xres + overscan_x) * 4; /* We want to keep the fb_base for simplefb page aligned, where as * the sunxi dma engines will happily accept an unaligned address. */ if (overscan_offset) - sunxi_display.fb_size += 0x1000; - - if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) { - printf("Error need %dkB for fb, but only %dkB is reserved\n", - sunxi_display.fb_size >> 10, - CONFIG_SUNXI_MAX_FB_SIZE >> 10); - return NULL; - } + sunxi_display->fb_size += 0x1000; printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n", mode->xres, mode->yres, (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "", - sunxi_get_mon_desc(sunxi_display.monitor), + sunxi_get_mon_desc(sunxi_display->monitor), overscan_x, overscan_y); - gd->fb_base = gd->bd->bi_dram[0].start + - gd->bd->bi_dram[0].size - sunxi_display.fb_size; + sunxi_display->fb_addr = plat->base; sunxi_engines_init(); #ifdef CONFIG_EFI_LOADER - efi_add_memory_map(gd->fb_base, sunxi_display.fb_size, + efi_add_memory_map(sunxi_display->fb_addr, sunxi_display->fb_size, EFI_RESERVED_MEMORY_TYPE); #endif - fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE; - sunxi_display.fb_addr = gd->fb_base; + fb_dma_addr = sunxi_display->fb_addr - CONFIG_SYS_SDRAM_BASE; if (overscan_offset) { fb_dma_addr += 0x1000 - (overscan_offset & 0xfff); - sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff; - memset((void *)gd->fb_base, 0, sunxi_display.fb_size); - flush_cache(gd->fb_base, sunxi_display.fb_size); + sunxi_display->fb_addr += ALIGN(overscan_offset, 0x1000); + memset((void *)sunxi_display->fb_addr, 0, sunxi_display->fb_size); + flush_cache(sunxi_display->fb_addr, sunxi_display->fb_size); } - sunxi_mode_set(mode, fb_dma_addr); + sunxi_mode_set(sunxi_display, mode, fb_dma_addr); - /* - * These are the only members of this structure that are used. All the - * others are driver specific. The pitch is stored in plnSizeX. - */ - graphic_device->frameAdrs = sunxi_display.fb_addr; - graphic_device->gdfIndex = GDF_32BIT_X888RGB; - graphic_device->gdfBytesPP = 4; - graphic_device->winSizeX = mode->xres - 2 * overscan_x; - graphic_device->winSizeY = mode->yres - 2 * overscan_y; - graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP; - - return graphic_device; + /* The members of struct video_priv to be set by the driver. */ + uc_priv->bpix = VIDEO_BPP32; + uc_priv->xsize = mode->xres; + uc_priv->ysize = mode->yres; + + video_set_flush_dcache(dev, true); + + return 0; } +static int sunxi_de_bind(struct udevice *dev) +{ + struct video_uc_plat *plat = dev_get_uclass_plat(dev); + + plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * VNBYTES(LCD_MAX_LOG2_BPP); + + return 0; +} + +static const struct video_ops sunxi_de_ops = { +}; + +U_BOOT_DRIVER(sunxi_de) = { + .name = "sunxi_de", + .id = UCLASS_VIDEO, + .ops = &sunxi_de_ops, + .bind = sunxi_de_bind, + .probe = sunxi_de_probe, + .priv_auto = sizeof(struct sunxi_display_priv), + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRVINFO(sunxi_de) = { + .name = "sunxi_de" +}; + /* * Simplefb support. */ #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB) int sunxi_simplefb_setup(void *blob) { - static GraphicDevice *graphic_device = &sunxi_display.graphic_device; + struct sunxi_display_priv *sunxi_display; + struct video_priv *uc_priv; + struct udevice *de; int offset, ret; u64 start, size; const char *pipeline = NULL; @@ -1242,7 +1267,19 @@ int sunxi_simplefb_setup(void *blob) #define PIPELINE_PREFIX #endif - switch (sunxi_display.monitor) { + ret = uclass_find_device_by_name(UCLASS_VIDEO, "sunxi_de", &de); + if (ret) { + printf("DE not present\n"); + return 0; + } else if (!device_active(de)) { + printf("DE is present but not probed\n"); + return 0; + } + + uc_priv = dev_get_uclass_priv(de); + sunxi_display = dev_get_priv(de); + + switch (sunxi_display->monitor) { case sunxi_monitor_none: return 0; case sunxi_monitor_dvi: @@ -1280,16 +1317,17 @@ int sunxi_simplefb_setup(void *blob) * linux/arch/arm/mm/ioremap.c around line 301. */ start = gd->bd->bi_dram[0].start; - size = gd->bd->bi_dram[0].size - sunxi_display.fb_size; + size = sunxi_display->fb_addr - start; ret = fdt_fixup_memory_banks(blob, &start, &size, 1); if (ret) { eprintf("Cannot setup simplefb: Error reserving memory\n"); return ret; } - ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr, - graphic_device->winSizeX, graphic_device->winSizeY, - graphic_device->plnSizeX, "x8r8g8b8"); + ret = fdt_setup_simplefb_node(blob, offset, sunxi_display->fb_addr, + uc_priv->xsize, uc_priv->ysize, + VNBYTES(uc_priv->bpix) * uc_priv->xsize, + "x8r8g8b8"); if (ret) eprintf("Cannot setup simplefb: Error setting properties\n"); diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 7b602dd9ea4..33a4d7b6373 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -223,23 +223,6 @@ extern int soft_i2c_gpio_scl; #define CONFIG_VIDEO_LCD_I2C_BUS -1 /* NA, but necessary to compile */ #endif -#ifdef CONFIG_VIDEO_SUNXI -/* - * The amount of RAM to keep free at the top of RAM when relocating u-boot, - * to use as framebuffer. This must be a multiple of 4096. - */ -#define CONFIG_SUNXI_MAX_FB_SIZE (16 << 20) - -#define CONFIG_VIDEO_LOGO -#define CONFIG_VIDEO_STD_TIMINGS -#define CONFIG_I2C_EDID -#define VIDEO_LINE_LEN (pGD->plnSizeX) - -/* allow both serial and cfb console. */ -/* stop x86 thinking in cfbconsole from trying to init a pc keyboard */ - -#endif /* CONFIG_VIDEO_SUNXI */ - /* Ethernet support */ #ifdef CONFIG_USB_EHCI_HCD @@ -401,11 +384,7 @@ extern int soft_i2c_gpio_scl; "stdin=serial\0" #endif -#ifdef CONFIG_VIDEO -#define CONSOLE_STDOUT_SETTINGS \ - "stdout=serial,vga\0" \ - "stderr=serial,vga\0" -#elif CONFIG_DM_VIDEO +#ifdef CONFIG_DM_VIDEO #define CONSOLE_STDOUT_SETTINGS \ "stdout=serial,vidconsole\0" \ "stderr=serial,vidconsole\0" diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index c8c87900ce8..7340e95bd4e 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -1636,7 +1636,6 @@ CONFIG_STV0991 CONFIG_STV0991_HZ CONFIG_STV0991_HZ_CLOCK CONFIG_ST_SMI -CONFIG_SUNXI_MAX_FB_SIZE CONFIG_SXNI855T CONFIG_SYSFLAGS_ADDR CONFIG_SYSFS -- cgit v1.3.1 From 13979fc44667cbc577f3c4d07b6692de104a3174 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:21:55 -0700 Subject: dm: gpio: Rename set_dir_flags() method to update_flags() The current method is a misnomer since it is also used (e.g. by stm32) to update pull settings and open source/open drain. Rename it and expand the documentation to cover a few more details. Signed-off-by: Simon Glass Reviewed-by: Pratyush Yadav Reviewed-by: Patrick Delaunay --- drivers/gpio/gpio-uclass.c | 16 ++++++++-------- drivers/gpio/sandbox.c | 6 +++--- drivers/gpio/stm32_gpio.c | 6 +++--- drivers/pinctrl/pinctrl-stmfx.c | 6 +++--- include/asm-generic/gpio.h | 28 ++++++++++++++++++++++------ test/dm/gpio.c | 8 ++++---- 6 files changed, 43 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 1db5ef001e2..d42e778ed88 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -620,7 +620,7 @@ static int check_dir_flags(ulong flags) return 0; } -static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) +static int _dm_gpio_set_flags(struct gpio_desc *desc, ulong flags) { struct udevice *dev = desc->dev; struct dm_gpio_ops *ops = gpio_get_ops(dev); @@ -638,9 +638,9 @@ static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) return ret; } - /* GPIOD_ are directly managed by driver in set_dir_flags*/ - if (ops->set_dir_flags) { - ret = ops->set_dir_flags(dev, desc->offset, flags); + /* GPIOD_ are directly managed by driver in set_flags */ + if (ops->set_flags) { + ret = ops->set_flags(dev, desc->offset, flags); } else { if (flags & GPIOD_IS_OUT) { ret = ops->direction_output(dev, desc->offset, @@ -667,7 +667,7 @@ int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) /* combine the requested flags (for IN/OUT) and the descriptor flags */ flags |= desc->flags; - ret = _dm_gpio_set_dir_flags(desc, flags); + ret = _dm_gpio_set_flags(desc, flags); return ret; } @@ -680,7 +680,7 @@ int dm_gpio_set_dir(struct gpio_desc *desc) if (ret) return ret; - return _dm_gpio_set_dir_flags(desc, desc->flags); + return _dm_gpio_set_flags(desc, desc->flags); } int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags) @@ -1308,8 +1308,8 @@ static int gpio_post_bind(struct udevice *dev) ops->get_function += gd->reloc_off; if (ops->xlate) ops->xlate += gd->reloc_off; - if (ops->set_dir_flags) - ops->set_dir_flags += gd->reloc_off; + if (ops->set_flags) + ops->set_flags += gd->reloc_off; if (ops->get_dir_flags) ops->get_dir_flags += gd->reloc_off; diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index dc8d506e8d4..05f17928f0a 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -177,8 +177,8 @@ static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, return 0; } -static int sb_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, - ulong flags) +static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset, + ulong flags) { ulong *dir_flags; @@ -272,7 +272,7 @@ static const struct dm_gpio_ops gpio_sandbox_ops = { .set_value = sb_gpio_set_value, .get_function = sb_gpio_get_function, .xlate = sb_gpio_xlate, - .set_dir_flags = sb_gpio_set_dir_flags, + .set_flags = sb_gpio_set_flags, .get_dir_flags = sb_gpio_get_dir_flags, #if CONFIG_IS_ENABLED(ACPIGEN) .get_acpi = sb_gpio_get_acpi, diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index 7184db3c527..6d1bef63c36 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -191,8 +191,8 @@ static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset) return GPIOF_FUNC; } -static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, - ulong flags) +static int stm32_gpio_set_flags(struct udevice *dev, unsigned int offset, + ulong flags) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; @@ -270,7 +270,7 @@ static const struct dm_gpio_ops gpio_stm32_ops = { .get_value = stm32_gpio_get_value, .set_value = stm32_gpio_set_value, .get_function = stm32_gpio_get_function, - .set_dir_flags = stm32_gpio_set_dir_flags, + .set_flags = stm32_gpio_set_flags, .get_dir_flags = stm32_gpio_get_dir_flags, }; diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 1a8d0a3a35e..6147e867dcc 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -163,8 +163,8 @@ static int stmfx_gpio_direction_output(struct udevice *dev, return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 1); } -static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, - ulong flags) +static int stmfx_gpio_set_flags(struct udevice *dev, unsigned int offset, + ulong flags) { int ret = -ENOTSUPP; @@ -266,7 +266,7 @@ static const struct dm_gpio_ops stmfx_gpio_ops = { .get_function = stmfx_gpio_get_function, .direction_input = stmfx_gpio_direction_input, .direction_output = stmfx_gpio_direction_output, - .set_dir_flags = stmfx_gpio_set_dir_flags, + .set_flags = stmfx_gpio_set_flags, .get_dir_flags = stmfx_gpio_get_dir_flags, }; diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 82294cbdc57..de16cabcbf9 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -301,20 +301,36 @@ struct dm_gpio_ops { struct ofnode_phandle_args *args); /** - * set_dir_flags() - Set GPIO dir flags + * set_flags() - Adjust GPIO flags * * This function should set up the GPIO configuration according to the - * information provide by the direction flags bitfield. + * information provided by @flags. + * + * If any flags cannot be set (e.g. the driver or hardware does not + * support them or this particular GPIO does not have the requested + * feature), the driver should return -EINVAL. + * + * The uclass checks that flags do not obviously conflict (e.g. input + * and output). If the driver finds other conflicts it should return + * -ERECALLCONFLICT + * + * Note that GPIOD_ACTIVE_LOW should be ignored, since the uclass + * adjusts for it automatically. For example, for an output GPIO, + * GPIOD_ACTIVE_LOW causes GPIOD_IS_OUT_ACTIVE to be inverted by the + * uclass, so the driver always sees the value that should be set at the + * pin (1=high, 0=low). * * This method is optional. * * @dev: GPIO device * @offset: GPIO offset within that device - * @flags: GPIO configuration to use - * @return 0 if OK, -ve on error + * @flags: New flags value (GPIOD_...) + * + * @return 0 if OK, -EINVAL if unsupported, -ERECALLCONFLICT if flags + * conflict in some * non-obvious way and were not applied, + * other -ve on error */ - int (*set_dir_flags)(struct udevice *dev, unsigned int offset, - ulong flags); + int (*set_flags)(struct udevice *dev, unsigned int offset, ulong flags); /** * get_dir_flags() - Get GPIO dir flags diff --git a/test/dm/gpio.c b/test/dm/gpio.c index d7b85e74ce5..36bbaedb01c 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -81,12 +81,12 @@ static int dm_test_gpio(struct unit_test_state *uts) /* Make it an open drain output, and reset it */ ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, sandbox_gpio_get_dir_flags(dev, offset)); - ut_assertok(ops->set_dir_flags(dev, offset, - GPIOD_IS_OUT | GPIOD_OPEN_DRAIN)); + ut_assertok(ops->set_flags(dev, offset, + GPIOD_IS_OUT | GPIOD_OPEN_DRAIN)); ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, sandbox_gpio_get_dir_flags(dev, offset)); - ut_assertok(ops->set_dir_flags(dev, offset, - GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE)); + ut_assertok(ops->set_flags(dev, offset, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE)); ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, sandbox_gpio_get_dir_flags(dev, offset)); -- cgit v1.3.1 From 9648789e2634e30fc58ad7180a7c7815e6227061 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:21:56 -0700 Subject: dm: gpio: Rename get_dir_flags() method to get_flags() It is more useful to be able to read all the flags, not just the direction ones. In fact this is what the STM32 driver does. Update the method name to reflect this. Tweak the docs a little and use 'flagsp' as the return argument, as is common in driver model, to indicate it returns a value. Signed-off-by: Simon Glass Reviewed-by: Patrick Delaunay Reviewed-by: Pratyush Yadav --- drivers/gpio/gpio-uclass.c | 30 +++++++++++++++--------------- drivers/gpio/sandbox.c | 8 ++++---- drivers/gpio/stm32_gpio.c | 8 ++++---- drivers/pinctrl/pinctrl-stmfx.c | 8 ++++---- include/asm-generic/gpio.h | 11 ++++++----- 5 files changed, 33 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index d42e778ed88..4d15162bc4d 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -683,39 +683,39 @@ int dm_gpio_set_dir(struct gpio_desc *desc) return _dm_gpio_set_flags(desc, desc->flags); } -int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags) +int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flagsp) { struct udevice *dev = desc->dev; int ret, value; struct dm_gpio_ops *ops = gpio_get_ops(dev); - ulong dir_flags; + ulong flags; - ret = check_reserved(desc, "get_dir_flags"); + ret = check_reserved(desc, "get_flags"); if (ret) return ret; /* GPIOD_ are directly provided by driver except GPIOD_ACTIVE_LOW */ - if (ops->get_dir_flags) { - ret = ops->get_dir_flags(dev, desc->offset, &dir_flags); + if (ops->get_flags) { + ret = ops->get_flags(dev, desc->offset, &flags); if (ret) return ret; /* GPIOD_ACTIVE_LOW is saved in desc->flags */ - value = dir_flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0; + value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0; if (desc->flags & GPIOD_ACTIVE_LOW) value = !value; - dir_flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE); - dir_flags |= (desc->flags & GPIOD_ACTIVE_LOW); + flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE); + flags |= (desc->flags & GPIOD_ACTIVE_LOW); if (value) - dir_flags |= GPIOD_IS_OUT_ACTIVE; + flags |= GPIOD_IS_OUT_ACTIVE; } else { - dir_flags = desc->flags; + flags = desc->flags; /* only GPIOD_IS_OUT_ACTIVE is provided by uclass */ - dir_flags &= ~GPIOD_IS_OUT_ACTIVE; + flags &= ~GPIOD_IS_OUT_ACTIVE; if ((desc->flags & GPIOD_IS_OUT) && _gpio_get_value(desc)) - dir_flags |= GPIOD_IS_OUT_ACTIVE; + flags |= GPIOD_IS_OUT_ACTIVE; } - *flags = dir_flags; + *flagsp = flags; return 0; } @@ -1310,8 +1310,8 @@ static int gpio_post_bind(struct udevice *dev) ops->xlate += gd->reloc_off; if (ops->set_flags) ops->set_flags += gd->reloc_off; - if (ops->get_dir_flags) - ops->get_dir_flags += gd->reloc_off; + if (ops->get_flags) + ops->get_flags += gd->reloc_off; reloc_done++; } diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index 05f17928f0a..38dc34ee910 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -199,11 +199,11 @@ static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset, return 0; } -static int sb_gpio_get_dir_flags(struct udevice *dev, unsigned int offset, - ulong *flags) +static int sb_gpio_get_flags(struct udevice *dev, unsigned int offset, + ulong *flagsp) { debug("%s: offset:%u\n", __func__, offset); - *flags = *get_gpio_dir_flags(dev, offset); + *flagsp = *get_gpio_dir_flags(dev, offset); return 0; } @@ -273,7 +273,7 @@ static const struct dm_gpio_ops gpio_sandbox_ops = { .get_function = sb_gpio_get_function, .xlate = sb_gpio_xlate, .set_flags = sb_gpio_set_flags, - .get_dir_flags = sb_gpio_get_dir_flags, + .get_flags = sb_gpio_get_flags, #if CONFIG_IS_ENABLED(ACPIGEN) .get_acpi = sb_gpio_get_acpi, #endif diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index 6d1bef63c36..c2d7046c0dd 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -223,8 +223,8 @@ static int stm32_gpio_set_flags(struct udevice *dev, unsigned int offset, return 0; } -static int stm32_gpio_get_dir_flags(struct udevice *dev, unsigned int offset, - ulong *flags) +static int stm32_gpio_get_flags(struct udevice *dev, unsigned int offset, + ulong *flagsp) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; @@ -259,7 +259,7 @@ static int stm32_gpio_get_dir_flags(struct udevice *dev, unsigned int offset, default: break; } - *flags = dir_flags; + *flagsp = dir_flags; return 0; } @@ -271,7 +271,7 @@ static const struct dm_gpio_ops gpio_stm32_ops = { .set_value = stm32_gpio_set_value, .get_function = stm32_gpio_get_function, .set_flags = stm32_gpio_set_flags, - .get_dir_flags = stm32_gpio_get_dir_flags, + .get_flags = stm32_gpio_get_flags, }; static int gpio_stm32_probe(struct udevice *dev) diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 6147e867dcc..6ba56a16a3a 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -199,8 +199,8 @@ static int stmfx_gpio_set_flags(struct udevice *dev, unsigned int offset, return ret; } -static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset, - ulong *flags) +static int stmfx_gpio_get_flags(struct udevice *dev, unsigned int offset, + ulong *flagsp) { ulong dir_flags = 0; int ret; @@ -233,7 +233,7 @@ static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset, dir_flags |= GPIOD_PULL_DOWN; } } - *flags = dir_flags; + *flagsp = dir_flags; return 0; } @@ -267,7 +267,7 @@ static const struct dm_gpio_ops stmfx_gpio_ops = { .direction_input = stmfx_gpio_direction_input, .direction_output = stmfx_gpio_direction_output, .set_flags = stmfx_gpio_set_flags, - .get_dir_flags = stmfx_gpio_get_dir_flags, + .get_flags = stmfx_gpio_get_flags, }; U_BOOT_DRIVER(stmfx_gpio) = { diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index de16cabcbf9..153312d8af4 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -333,19 +333,20 @@ struct dm_gpio_ops { int (*set_flags)(struct udevice *dev, unsigned int offset, ulong flags); /** - * get_dir_flags() - Get GPIO dir flags + * get_flags() - Get GPIO flags * - * This function return the GPIO direction flags used. + * This function return the GPIO flags used. It should read this from + * the hardware directly. * * This method is optional. * * @dev: GPIO device * @offset: GPIO offset within that device - * @flags: place to put the used direction flags by GPIO + * @flagsp: place to put the current flags value * @return 0 if OK, -ve on error */ - int (*get_dir_flags)(struct udevice *dev, unsigned int offset, - ulong *flags); + int (*get_flags)(struct udevice *dev, unsigned int offset, + ulong *flagsp); #if CONFIG_IS_ENABLED(ACPIGEN) /** -- cgit v1.3.1 From c0c1e62c6e47ffccca953c57df4624d685493584 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:21:57 -0700 Subject: gpio: Rename dm_gpio_get_dir_flags() to dm_gpio_get_flags() This function can be used to get any flags, not just direction flags. Rename it to avoid confusion. Signed-off-by: Simon Glass Reviewed-by: Patrick Delaunay Reviewed-by: Pratyush Yadav --- drivers/gpio/gpio-uclass.c | 2 +- include/asm-generic/gpio.h | 6 +++--- test/dm/gpio.c | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 4d15162bc4d..42479dba4da 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -683,7 +683,7 @@ int dm_gpio_set_dir(struct gpio_desc *desc) return _dm_gpio_set_flags(desc, desc->flags); } -int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flagsp) +int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flagsp) { struct udevice *dev = desc->dev; int ret, value; diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 153312d8af4..4f8d1938da9 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -683,16 +683,16 @@ int dm_gpio_set_dir(struct gpio_desc *desc); int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags); /** - * dm_gpio_get_dir_flags() - Get direction flags + * dm_gpio_get_flags() - Get flags * - * read the current direction flags + * Read the current flags * * @desc: GPIO description containing device, offset and flags, * previously returned by gpio_request_by_name() * @flags: place to put the used flags * @return 0 if OK, -ve on error, in which case desc->flags is not updated */ -int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags); +int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flags); /** * gpio_get_number() - Get the global GPIO number of a GPIO diff --git a/test/dm/gpio.c b/test/dm/gpio.c index 36bbaedb01c..c583d2b3447 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -397,22 +397,22 @@ static int dm_test_gpio_get_dir_flags(struct unit_test_state *uts) ut_asserteq(6, gpio_request_list_by_name(dev, "test3-gpios", desc_list, ARRAY_SIZE(desc_list), 0)); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[0], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[0], &flags)); ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, flags); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[1], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[1], &flags)); ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, flags); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[2], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[2], &flags)); ut_asserteq(GPIOD_IS_OUT, flags); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[3], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[3], &flags)); ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, flags); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[4], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[4], &flags)); ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_DOWN, flags); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[5], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[5], &flags)); ut_asserteq(GPIOD_IS_IN, flags); ut_assertok(gpio_free_list(dev, desc_list, 6)); -- cgit v1.3.1 From 7e0a96d559da493812220731535f5ba6351bcea1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:22:03 -0700 Subject: dm: gpio: Add a way to update flags It is convenient to be able to adjust some of the flags for a GPIO while leaving others alone. Add a function for this. Update dm_gpio_set_dir_flags() to make use of this. Also update dm_gpio_set_value() to use this also, since this allows the open-drain / open-source features to be implemented directly in the driver, rather than using the uclass workaround. Update the sandbox tests accordingly. This involves a lot of changes to dm_test_gpio_opendrain_opensource() since we no-longer have the direciion being reported differently depending on the open drain/open source flags. Also update the STM32 drivers to let the uclass handle the active low/high logic. Drop the GPIOD_FLAGS_OUTPUT() macro which is no-longer used. Signed-off-by: Simon Glass Tested-by: Kory Maincent Reviewed-by: Patrick Delaunay Tested-by: Patrick Delaunay Reviewed-by: Patrick Delaunay Tested-by: Patrick Delaunay --- drivers/gpio/gpio-uclass.c | 75 +++++++++++++++++------ drivers/gpio/stm32_gpio.c | 3 +- drivers/pinctrl/pinctrl-stmfx.c | 5 +- include/asm-generic/gpio.h | 31 ++++++++-- test/dm/gpio.c | 132 ++++++++++++++++++++++++++++++++++------ 5 files changed, 203 insertions(+), 43 deletions(-) (limited to 'include') diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 42479dba4da..eb8850dfe5c 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -569,6 +569,7 @@ int dm_gpio_get_value(const struct gpio_desc *desc) int dm_gpio_set_value(const struct gpio_desc *desc, int value) { + const struct dm_gpio_ops *ops; int ret; ret = check_reserved(desc, "set_value"); @@ -578,21 +579,33 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value) if (desc->flags & GPIOD_ACTIVE_LOW) value = !value; + /* GPIOD_ are directly managed by driver in set_flags */ + ops = gpio_get_ops(desc->dev); + if (ops->set_flags) { + ulong flags = desc->flags; + + if (value) + flags |= GPIOD_IS_OUT_ACTIVE; + else + flags &= ~GPIOD_IS_OUT_ACTIVE; + return ops->set_flags(desc->dev, desc->offset, flags); + } + /* * Emulate open drain by not actively driving the line high or * Emulate open source by not actively driving the line low */ if ((desc->flags & GPIOD_OPEN_DRAIN && value) || (desc->flags & GPIOD_OPEN_SOURCE && !value)) - return gpio_get_ops(desc->dev)->direction_input(desc->dev, - desc->offset); + return ops->direction_input(desc->dev, desc->offset); else if (desc->flags & GPIOD_OPEN_DRAIN || desc->flags & GPIOD_OPEN_SOURCE) - return gpio_get_ops(desc->dev)->direction_output(desc->dev, - desc->offset, - value); + return ops->direction_output(desc->dev, desc->offset, value); + + ret = ops->set_value(desc->dev, desc->offset, value); + if (ret) + return ret; - gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value); return 0; } @@ -620,6 +633,17 @@ static int check_dir_flags(ulong flags) return 0; } +/** + * _dm_gpio_set_flags() - Send flags to the driver + * + * This uses the best available method to send the given flags to the driver. + * Note that if flags & GPIOD_ACTIVE_LOW, the driver sees the opposite value + * of GPIOD_IS_OUT_ACTIVE. + * + * @desc: GPIO description + * @flags: flags value to set + * @return 0 if OK, -ve on error + */ static int _dm_gpio_set_flags(struct gpio_desc *desc, ulong flags) { struct udevice *dev = desc->dev; @@ -638,38 +662,52 @@ static int _dm_gpio_set_flags(struct gpio_desc *desc, ulong flags) return ret; } + /* If active low, invert the output state */ + if ((flags & (GPIOD_IS_OUT | GPIOD_ACTIVE_LOW)) == + (GPIOD_IS_OUT | GPIOD_ACTIVE_LOW)) + flags ^= GPIOD_IS_OUT_ACTIVE; + /* GPIOD_ are directly managed by driver in set_flags */ if (ops->set_flags) { ret = ops->set_flags(dev, desc->offset, flags); } else { if (flags & GPIOD_IS_OUT) { - ret = ops->direction_output(dev, desc->offset, - GPIOD_FLAGS_OUTPUT(flags)); + bool value = flags & GPIOD_IS_OUT_ACTIVE; + + ret = ops->direction_output(dev, desc->offset, value); } else if (flags & GPIOD_IS_IN) { ret = ops->direction_input(dev, desc->offset); } } - /* save the flags also in descriptor */ - if (!ret) - desc->flags = flags; - return ret; } -int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) +int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set) { + ulong flags; int ret; ret = check_reserved(desc, "set_dir_flags"); if (ret) return ret; - /* combine the requested flags (for IN/OUT) and the descriptor flags */ - flags |= desc->flags; + flags = (desc->flags & ~clr) | set; + ret = _dm_gpio_set_flags(desc, flags); + if (ret) + return ret; - return ret; + /* save the flags also in descriptor */ + desc->flags = flags; + + return 0; +} + +int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) +{ + /* combine the requested flags (for IN/OUT) and the descriptor flags */ + return dm_gpio_clrset_flags(desc, GPIOD_MASK_DIR, flags); } int dm_gpio_set_dir(struct gpio_desc *desc) @@ -1011,7 +1049,10 @@ static int gpio_request_tail(int ret, const char *nodename, debug("%s: dm_gpio_requestf failed\n", __func__); goto err; } - ret = dm_gpio_set_dir_flags(desc, flags); + + /* Keep any direction flags provided by the devicetree */ + ret = dm_gpio_set_dir_flags(desc, + flags | (desc->flags & GPIOD_MASK_DIR)); if (ret) { debug("%s: dm_gpio_set_dir failed\n", __func__); goto err; diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index c2d7046c0dd..125c237551c 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -203,12 +203,13 @@ static int stm32_gpio_set_flags(struct udevice *dev, unsigned int offset, return idx; if (flags & GPIOD_IS_OUT) { - int value = GPIOD_FLAGS_OUTPUT(flags); + bool value = flags & GPIOD_IS_OUT_ACTIVE; if (flags & GPIOD_OPEN_DRAIN) stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_OD); else stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_PP); + stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT); writel(BSRR_BIT(idx, value), ®s->bsrr); diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 6ba56a16a3a..fe7a59d4313 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -169,6 +169,8 @@ static int stmfx_gpio_set_flags(struct udevice *dev, unsigned int offset, int ret = -ENOTSUPP; if (flags & GPIOD_IS_OUT) { + bool value = flags & GPIOD_IS_OUT_ACTIVE; + if (flags & GPIOD_OPEN_SOURCE) return -ENOTSUPP; if (flags & GPIOD_OPEN_DRAIN) @@ -177,8 +179,7 @@ static int stmfx_gpio_set_flags(struct udevice *dev, unsigned int offset, ret = stmfx_conf_set_type(dev, offset, 1); if (ret) return ret; - ret = stmfx_gpio_direction_output(dev, offset, - GPIOD_FLAGS_OUTPUT(flags)); + ret = stmfx_gpio_direction_output(dev, offset, value); } else if (flags & GPIOD_IS_IN) { ret = stmfx_gpio_direction_input(dev, offset); if (ret) diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 4f8d1938da9..7d1e19ad531 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -128,6 +128,12 @@ struct gpio_desc { #define GPIOD_PULL_UP BIT(7) /* GPIO has pull-up enabled */ #define GPIOD_PULL_DOWN BIT(8) /* GPIO has pull-down enabled */ +/* Flags for updating the above */ +#define GPIOD_MASK_DIR (GPIOD_IS_OUT | GPIOD_IS_IN | \ + GPIOD_IS_OUT_ACTIVE) +#define GPIOD_MASK_DSTYPE (GPIOD_OPEN_DRAIN | GPIOD_OPEN_SOURCE) +#define GPIOD_MASK_PULL (GPIOD_PULL_UP | GPIOD_PULL_DOWN) + uint offset; /* GPIO offset within the device */ /* * We could consider adding the GPIO label in here. Possibly we could @@ -135,12 +141,6 @@ struct gpio_desc { */ }; -/* helper to compute the value of the gpio output */ -#define GPIOD_FLAGS_OUTPUT_MASK (GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE) -#define GPIOD_FLAGS_OUTPUT(flags) \ - (((((flags) & GPIOD_FLAGS_OUTPUT_MASK) == GPIOD_IS_OUT_ACTIVE) || \ - (((flags) & GPIOD_FLAGS_OUTPUT_MASK) == GPIOD_ACTIVE_LOW))) - /** * dm_gpio_is_valid() - Check if a GPIO is valid * @@ -668,6 +668,25 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value); */ int dm_gpio_set_dir(struct gpio_desc *desc); +/** + * dm_gpio_clrset_flags() - Update flags + * + * This updates the flags as directled. Note that desc->flags is updated by this + * function on success. If any changes cannot be made, best efforts are made. + * + * By use of @clr and @set any of flags can be individually updated, or left + * alone + * + * @desc: GPIO description containing device, offset and flags, + * previously returned by gpio_request_by_name() + * @clr: Flags to clear (GPIOD_...) + * @set: Flags to set (GPIOD_...) + * @return 0 if OK, -EINVAL if the flags had obvious conflicts, + * -ERECALLCONFLICT if there was a non-obvious hardware conflict when attempting + * to set the flags + */ +int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set); + /** * dm_gpio_set_dir_flags() - Set direction using description and added flags * diff --git a/test/dm/gpio.c b/test/dm/gpio.c index dfbb634bf71..be5da953045 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -178,15 +178,15 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, sandbox_gpio_get_flags(gpio_c, 0)); - /* Set it as output high, should become an input */ + /* Set it as output high */ ut_assertok(dm_gpio_set_value(&desc_list[0], 1)); - ut_assertok(gpio_get_status(gpio_c, 0, buf, sizeof(buf))); - ut_asserteq_str("c0: input: 0 [x] a-test.test3-gpios0", buf); + ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN | GPIOD_IS_OUT_ACTIVE, + sandbox_gpio_get_flags(gpio_c, 0)); - /* Set it as output low, should become output low */ + /* Set it as output low */ ut_assertok(dm_gpio_set_value(&desc_list[0], 0)); - ut_assertok(gpio_get_status(gpio_c, 0, buf, sizeof(buf))); - ut_asserteq_str("c0: output: 0 [x] a-test.test3-gpios0", buf); + ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, + sandbox_gpio_get_flags(gpio_c, 0)); /* GPIO 1 is (GPIO_OUT|GPIO_OPEN_SOURCE) */ ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, @@ -197,13 +197,21 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf))); ut_asserteq_str("c1: output: 1 [x] a-test.test3-gpios1", buf); - /* Set it as output low, should become an input */ + /* Set it as output low */ ut_assertok(dm_gpio_set_value(&desc_list[1], 0)); + ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, + sandbox_gpio_get_flags(gpio_c, 1)); + ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf))); - ut_asserteq_str("c1: input: 1 [x] a-test.test3-gpios1", buf); + ut_asserteq_str("c1: output: 0 [x] a-test.test3-gpios1", buf); - /* GPIO 6 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN) */ - ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, + /* + * GPIO 6 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN). Looking at it + * directlt from the driver, we get GPIOD_IS_OUT_ACTIVE also, since it + * is active low + */ + ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN | + GPIOD_IS_OUT_ACTIVE, sandbox_gpio_get_flags(gpio_c, 6)); /* Set it as output high, should become output low */ @@ -211,19 +219,21 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) ut_assertok(gpio_get_status(gpio_c, 6, buf, sizeof(buf))); ut_asserteq_str("c6: output: 0 [x] a-test.test3-gpios6", buf); - /* Set it as output low, should become an input */ + /* Set it as output low */ ut_assertok(dm_gpio_set_value(&desc_list[6], 0)); - ut_assertok(gpio_get_status(gpio_c, 6, buf, sizeof(buf))); - ut_asserteq_str("c6: input: 0 [x] a-test.test3-gpios6", buf); + ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN | + GPIOD_IS_OUT_ACTIVE, + sandbox_gpio_get_flags(gpio_c, 6)); /* GPIO 7 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_SOURCE) */ - ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, + ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE | + GPIOD_IS_OUT_ACTIVE, sandbox_gpio_get_flags(gpio_c, 7)); - /* Set it as output high, should become an input */ + /* Set it as output high */ ut_assertok(dm_gpio_set_value(&desc_list[7], 1)); - ut_assertok(gpio_get_status(gpio_c, 7, buf, sizeof(buf))); - ut_asserteq_str("c7: input: 0 [x] a-test.test3-gpios7", buf); + ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, + sandbox_gpio_get_flags(gpio_c, 7)); /* Set it as output low, should become output high */ ut_assertok(dm_gpio_set_value(&desc_list[7], 0)); @@ -582,3 +592,91 @@ static int dm_test_gpio_devm(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_gpio_devm, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_clrset_flags(struct unit_test_state *uts) +{ + struct gpio_desc desc; + struct udevice *dev; + ulong flags; + + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); + ut_asserteq_str("a-test", dev->name); + ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc, 0)); + + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_OUT)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_OUT, flags); + ut_asserteq(GPIOD_IS_OUT, desc.flags); + ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset)); + + ut_assertok(dm_gpio_clrset_flags(&desc, 0, GPIOD_IS_OUT_ACTIVE)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, flags); + ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, desc.flags); + ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset)); + ut_asserteq(1, dm_gpio_get_value(&desc)); + + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_IN)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_IN, flags & GPIOD_MASK_DIR); + ut_asserteq(GPIOD_IS_IN, desc.flags & GPIOD_MASK_DIR); + + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_PULL, + GPIOD_PULL_UP)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, flags); + ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, desc.flags); + + /* Check we cannot set both PULL_UP and PULL_DOWN */ + ut_asserteq(-EINVAL, dm_gpio_clrset_flags(&desc, 0, GPIOD_PULL_DOWN)); + + return 0; +} +DM_TEST(dm_test_clrset_flags, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* Check that an active-low GPIO works as expected */ +static int dm_test_clrset_flags_invert(struct unit_test_state *uts) +{ + struct gpio_desc desc; + struct udevice *dev; + ulong flags; + + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); + ut_asserteq_str("a-test", dev->name); + ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc, + GPIOD_IS_OUT | GPIOD_ACTIVE_LOW)); + + /* + * From this size we see it as 0 (active low), but the sandbox driver + * sees the pin value high + */ + ut_asserteq(0, dm_gpio_get_value(&desc)); + ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset)); + + ut_assertok(dm_gpio_set_value(&desc, 1)); + ut_asserteq(1, dm_gpio_get_value(&desc)); + ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset)); + + /* Do the same with dm_gpio_clrset_flags() */ + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_IS_OUT_ACTIVE, 0)); + ut_asserteq(0, dm_gpio_get_value(&desc)); + ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset)); + + ut_assertok(dm_gpio_clrset_flags(&desc, 0, GPIOD_IS_OUT_ACTIVE)); + ut_asserteq(1, dm_gpio_get_value(&desc)); + ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset)); + + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE, + flags); + ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE, + desc.flags); + + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_IS_OUT_ACTIVE, 0)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW, flags); + ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW, desc.flags); + + return 0; +} +DM_TEST(dm_test_clrset_flags_invert, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); -- cgit v1.3.1 From ca1e1f57beb29fbaf48f9488ada1b008dace8314 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:22:04 -0700 Subject: gpio: Replace direction_input() and direction_output() The new update_flags() method is more flexible since it allows the driver to see the full flags all at once. Use that in preference to these two functions. Add comments to that effect. Signed-off-by: Simon Glass Reviewed-by: Patrick Delaunay --- drivers/gpio/gpio-uclass.c | 15 ++++++--------- include/asm-generic/gpio.h | 26 +++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index eb8850dfe5c..f90962a0075 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -513,13 +513,10 @@ int gpio_direction_input(unsigned gpio) int ret; ret = gpio_to_device(gpio, &desc); - if (ret) - return ret; - ret = check_reserved(&desc, "dir_input"); if (ret) return ret; - return gpio_get_ops(desc.dev)->direction_input(desc.dev, desc.offset); + return dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_IN); } /** @@ -534,17 +531,17 @@ int gpio_direction_input(unsigned gpio) int gpio_direction_output(unsigned gpio, int value) { struct gpio_desc desc; + ulong flags; int ret; ret = gpio_to_device(gpio, &desc); - if (ret) - return ret; - ret = check_reserved(&desc, "dir_output"); if (ret) return ret; - return gpio_get_ops(desc.dev)->direction_output(desc.dev, - desc.offset, value); + flags = GPIOD_IS_OUT; + if (value) + flags |= GPIOD_IS_OUT_ACTIVE; + return dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, flags); } static int _gpio_get_value(const struct gpio_desc *desc) diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 7d1e19ad531..f0c835e60bf 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -260,10 +260,32 @@ int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc, struct dm_gpio_ops { int (*request)(struct udevice *dev, unsigned offset, const char *label); int (*rfree)(struct udevice *dev, unsigned int offset); + + /** + * direction_input() - deprecated + * + * Equivalent to set_flags(...GPIOD_IS_IN) + */ int (*direction_input)(struct udevice *dev, unsigned offset); + + /** + * direction_output() - deprecated + * + * Equivalent to set_flags(...GPIOD_IS_OUT) with GPIOD_IS_OUT_ACTIVE + * also set if @value + */ int (*direction_output)(struct udevice *dev, unsigned offset, int value); + int (*get_value)(struct udevice *dev, unsigned offset); + + /** + * set_value() - Sets the GPIO value of an output + * + * If the driver provides an @set_flags() method then that is used + * in preference to this, with GPIOD_IS_OUT_ACTIVE set according to + * @value. + */ int (*set_value)(struct udevice *dev, unsigned offset, int value); /** * get_function() Get the GPIO function @@ -320,7 +342,9 @@ struct dm_gpio_ops { * uclass, so the driver always sees the value that should be set at the * pin (1=high, 0=low). * - * This method is optional. + * This method is required and should be implemented by new drivers. At + * some point, it will supersede direction_input() and + * direction_output(), which wil be removed. * * @dev: GPIO device * @offset: GPIO offset within that device -- cgit v1.3.1 From 8a45b2205749252f61d26508d5de9dcce020b2ef Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:22:09 -0700 Subject: gpio: Add a way to read 3-way strapping pins Using the internal vs. external pull resistors it is possible to get 27 different combinations from 3 strapping pins. Add an implementation of this. This involves updating the sandbox GPIO driver to model external and (weaker) internal pull resistors. The get_value() method now takes account of what is driving a pin: sandbox: GPIOD_EXT_DRIVEN - in which case GPIO_EXT_HIGH provides the value outside source - in which case GPIO_EXT_PULL_UP/DOWN indicates the external state and we work the final state using those flags and the internal GPIOD_PULL_UP/DOWN flags Of course the outside source does not really exist in sandbox. We are just modelling it for test purpose. Signed-off-by: Simon Glass --- arch/sandbox/include/asm/gpio.h | 5 ++- drivers/gpio/gpio-uclass.c | 81 ++++++++++++++++++++++++++++++++++ drivers/gpio/sandbox.c | 13 ++++-- include/asm-generic/gpio.h | 40 +++++++++++++++++ test/dm/gpio.c | 98 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 232 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/arch/sandbox/include/asm/gpio.h b/arch/sandbox/include/asm/gpio.h index 33b83ea4cc3..9e10052667d 100644 --- a/arch/sandbox/include/asm/gpio.h +++ b/arch/sandbox/include/asm/gpio.h @@ -26,8 +26,11 @@ /* Our own private GPIO flags, which musn't conflict with GPIOD_... */ #define GPIOD_EXT_HIGH BIT(31) /* external source is high (else low) */ #define GPIOD_EXT_DRIVEN BIT(30) /* external source is driven */ +#define GPIOD_EXT_PULL_UP BIT(29) /* GPIO has external pull-up */ +#define GPIOD_EXT_PULL_DOWN BIT(28) /* GPIO has external pull-down */ -#define GPIOD_SANDBOX_MASK GENMASK(31, 30) +#define GPIOD_EXT_PULL (BIT(28) | BIT(29)) +#define GPIOD_SANDBOX_MASK GENMASK(31, 28) /** * Return the simulated value of a GPIO (used only in sandbox test code) diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 729e41033bb..f24db87ef06 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -23,6 +23,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -723,6 +724,21 @@ int dm_gpio_set_dir(struct gpio_desc *desc) return _dm_gpio_set_flags(desc, desc->flags); } +int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr, + ulong set) +{ + int ret; + int i; + + for (i = 0; i < count; i++) { + ret = dm_gpio_clrset_flags(&desc[i], clr, set); + if (ret) + return log_ret(ret); + } + + return 0; +} + int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flagsp) { struct udevice *dev = desc->dev; @@ -989,6 +1005,71 @@ int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count) return vector; } +int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list, + int count) +{ + static const char tristate[] = "01z"; + enum { + PULLUP, + PULLDOWN, + + NUM_OPTIONS, + }; + int vals[NUM_OPTIONS]; + uint mask; + uint vector = 0; + int ret, i; + + /* + * Limit to 19 digits which should be plenty. This avoids overflow of a + * 32-bit int + */ + assert(count < 20); + + for (i = 0; i < NUM_OPTIONS; i++) { + uint flags = GPIOD_IS_IN; + + flags |= (i == PULLDOWN) ? GPIOD_PULL_DOWN : GPIOD_PULL_UP; + ret = dm_gpios_clrset_flags(desc_list, count, GPIOD_MASK_PULL, + flags); + if (ret) + return log_msg_ret("pu", ret); + + /* Give the lines time to settle */ + udelay(10); + + ret = dm_gpio_get_values_as_int(desc_list, count); + if (ret < 0) + return log_msg_ret("get1", ret); + vals[i] = ret; + } + + log_debug("values: %x %x, count = %d\n", vals[0], vals[1], count); + for (i = count - 1, mask = 1 << i; i >= 0; i--, mask >>= 1) { + uint pd = vals[PULLDOWN] & mask ? 1 : 0; + uint pu = vals[PULLUP] & mask ? 1 : 0; + uint digit; + + /* + * Get value with internal pulldown active. If this is 1 then + * there is a stronger external pullup, which we call 1. If not + * then call it 0. + * + * If the values differ then the pin is floating so we call + * this a 2. + */ + if (pu == pd) + digit = pd; + else + digit = 2; + log_debug("%c ", tristate[digit]); + vector = 3 * vector + digit; + } + log_debug("vector=%d\n", vector); + + return vector; +} + /** * gpio_request_tail: common work for requesting a gpio. * diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index 700098446b5..d008fdd2224 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -19,7 +19,6 @@ #include #include - struct gpio_state { const char *label; /* label given by requester */ ulong flags; /* flags (GPIOD_...) */ @@ -81,10 +80,16 @@ int sandbox_gpio_get_value(struct udevice *dev, unsigned offset) if (get_gpio_flag(dev, offset, GPIOD_IS_OUT)) debug("sandbox_gpio: get_value on output gpio %u\n", offset); - if (state->flags & GPIOD_EXT_DRIVEN) + if (state->flags & GPIOD_EXT_DRIVEN) { val = state->flags & GPIOD_EXT_HIGH; - else - val = false; + } else { + if (state->flags & GPIOD_EXT_PULL_UP) + val = true; + else if (state->flags & GPIOD_EXT_PULL_DOWN) + val = false; + else + val = state->flags & GPIOD_PULL_UP; + } return val; } diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index f0c835e60bf..2cb0500aec5 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -497,6 +497,31 @@ int gpio_get_values_as_int(const int *gpio_list); */ int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count); +/** + * dm_gpio_get_values_as_int_base3() - Create a base-3 int from a list of GPIOs + * + * This uses pull-ups/pull-downs to figure out whether a GPIO line is externally + * pulled down, pulled up or floating. This allows three different strap values + * for each pin: + * 0 : external pull-down + * 1 : external pull-up + * 2 : floating + * + * With this it is possible to obtain more combinations from the same number of + * strapping pins, when compared to dm_gpio_get_values_as_int(). The external + * pull resistors should be made stronger that the internal SoC pull resistors, + * for this to work. + * + * With 2 pins, 6 combinations are possible, compared with 4 + * With 3 pins, 27 are possible, compared with 8 + * + * @desc_list: List of GPIOs to collect + * @count: Number of GPIOs + * @return resulting integer value, or -ve on error + */ +int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list, + int count); + /** * gpio_claim_vector() - claim a number of GPIOs for input * @@ -725,6 +750,21 @@ int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set); */ int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags); +/** + * dm_gpios_clrset_flags() - Sets flags for a set of GPIOs + * + * This clears and sets flags individually for each GPIO. + * + * @desc: List of GPIOs to update + * @count: Number of GPIOs in the list + * @clr: Flags to clear (GPIOD_...), e.g. GPIOD_MASK_DIR if you are + * changing the direction + * @set: Flags to set (GPIOD_...) + * @return 0 if OK, -ve on error + */ +int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr, + ulong set); + /** * dm_gpio_get_flags() - Get flags * diff --git a/test/dm/gpio.c b/test/dm/gpio.c index be5da953045..33ae98701f4 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -680,3 +680,101 @@ static int dm_test_clrset_flags_invert(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_clrset_flags_invert, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int set_gpios(struct unit_test_state *uts, struct gpio_desc *desc, + int count, uint value) +{ + int i; + + for (i = 0; i < count; i++) { + const uint mask = 1 << i; + + ut_assertok(sandbox_gpio_set_value(desc[i].dev, desc[i].offset, + value & mask)); + } + + return 0; +} + +/* Check that an active-low GPIO works as expected */ +static int dm_test_gpio_get_values_as_int(struct unit_test_state *uts) +{ + const int gpio_count = 3; + struct gpio_desc desc[gpio_count]; + struct udevice *dev; + + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); + ut_asserteq_str("a-test", dev->name); + + ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc, + gpio_count, GPIOD_IS_IN)); + ut_assertok(set_gpios(uts, desc, gpio_count, 0)); + ut_asserteq(0, dm_gpio_get_values_as_int(desc, gpio_count)); + + ut_assertok(set_gpios(uts, desc, gpio_count, 5)); + ut_asserteq(5, dm_gpio_get_values_as_int(desc, gpio_count)); + + ut_assertok(set_gpios(uts, desc, gpio_count, 7)); + ut_asserteq(7, dm_gpio_get_values_as_int(desc, gpio_count)); + + return 0; +} +DM_TEST(dm_test_gpio_get_values_as_int, + UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* Check that an active-low GPIO works as expected */ +static int dm_test_gpio_get_values_as_int_base3(struct unit_test_state *uts) +{ + const int gpio_count = 3; + struct gpio_desc desc[gpio_count]; + struct udevice *dev; + + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); + ut_asserteq_str("a-test", dev->name); + + ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc, + gpio_count, GPIOD_IS_IN)); + + /* + * First test the sandbox GPIO driver works as expected. The external + * pull resistor should be stronger than the internal one. + */ + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, + GPIOD_IS_IN | GPIOD_EXT_PULL_UP | GPIOD_PULL_UP); + ut_asserteq(1, dm_gpio_get_value(desc)); + + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_IS_IN | + GPIOD_EXT_PULL_DOWN | GPIOD_PULL_UP); + ut_asserteq(0, dm_gpio_get_value(desc)); + + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, + GPIOD_IS_IN | GPIOD_PULL_UP); + ut_asserteq(1, dm_gpio_get_value(desc)); + + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_PULL_DOWN); + ut_asserteq(0, dm_gpio_get_value(desc)); + + /* + * Set up pins: pull-up (1), pull-down (0) and floating (2). This should + * result in digits 2 0 1, i.e. 2 * 9 + 1 * 3 = 19 + */ + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_EXT_PULL_UP); + sandbox_gpio_set_flags(desc[1].dev, desc[1].offset, + GPIOD_EXT_PULL_DOWN); + sandbox_gpio_set_flags(desc[2].dev, desc[2].offset, 0); + ut_asserteq(19, dm_gpio_get_values_as_int_base3(desc, gpio_count)); + + /* + * Set up pins: floating (2), pull-up (1) and pull-down (0). This should + * result in digits 0 1 2, i.e. 1 * 3 + 2 = 5 + */ + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, 0); + sandbox_gpio_set_flags(desc[1].dev, desc[1].offset, GPIOD_EXT_PULL_UP); + sandbox_gpio_set_flags(desc[2].dev, desc[2].offset, + GPIOD_EXT_PULL_DOWN); + ut_asserteq(5, dm_gpio_get_values_as_int_base3(desc, gpio_count)); + + return 0; +} +DM_TEST(dm_test_gpio_get_values_as_int_base3, + UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); -- cgit v1.3.1 From 4bc639ee1181dc25df733da5de76ce4ea4b3f406 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:34:45 -0700 Subject: test: Mark all driver model tests with a flag Add a flag for driver model tests, so we can do special processing for them. Signed-off-by: Simon Glass --- include/dm/test.h | 3 ++- include/test/test.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/dm/test.h b/include/dm/test.h index 6ac6672cd6f..dfbc82c756d 100644 --- a/include/dm/test.h +++ b/include/dm/test.h @@ -143,7 +143,8 @@ struct dm_test_state { }; /* Declare a new driver model test */ -#define DM_TEST(_name, _flags) UNIT_TEST(_name, _flags, dm_test) +#define DM_TEST(_name, _flags) \ + UNIT_TEST(_name, UT_TESTF_DM | (_flags), dm_test) /* * struct sandbox_sdl_plat - Platform data for the SDL video driver diff --git a/include/test/test.h b/include/test/test.h index 3fdaa2b5e51..27585507d8c 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -36,6 +36,8 @@ enum { UT_TESTF_FLAT_TREE = BIT(3), /* test needs flat DT */ UT_TESTF_LIVE_TREE = BIT(4), /* needs live device tree */ UT_TESTF_CONSOLE_REC = BIT(5), /* needs console recording */ + /* do extra driver model init and uninit */ + UT_TESTF_DM = BIT(6), }; /** -- cgit v1.3.1 From 409f4a2a7280abc6fe22447f7c1933fc5f669539 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:34:46 -0700 Subject: test: Rename test-main.c to test-dm.c This is the main test function for driver model but not for other tests. Rename the file and the function so this is clear. Signed-off-by: Simon Glass --- arch/sandbox/cpu/spl.c | 2 +- include/test/test.h | 4 +- test/dm/Makefile | 2 +- test/dm/test-dm.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++ test/dm/test-main.c | 230 ------------------------------------------------- 5 files changed, 234 insertions(+), 234 deletions(-) create mode 100644 test/dm/test-dm.c delete mode 100644 test/dm/test-main.c (limited to 'include') diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index 6926e244ca2..3779d58c3fe 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -65,7 +65,7 @@ void spl_board_init(void) if (state->run_unittests) { int ret; - ret = dm_test_main(state->select_unittests); + ret = dm_test_run(state->select_unittests); /* continue execution into U-Boot */ } } diff --git a/include/test/test.h b/include/test/test.h index 27585507d8c..d282cb2362d 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -106,7 +106,7 @@ enum { struct udevice *testbus_get_clear_removed(void); /** - * dm_test_main() - Run driver model tests + * dm_test_run() - Run driver model tests * * Run all the available driver model tests, or a selection * @@ -114,6 +114,6 @@ struct udevice *testbus_get_clear_removed(void); * "fdt_pre_reloc"), or NULL to run all * @return 0 if all tests passed, 1 if not */ -int dm_test_main(const char *test_name); +int dm_test_run(const char *test_name); #endif /* __TEST_TEST_H */ diff --git a/test/dm/Makefile b/test/dm/Makefile index fd1455109d4..f5cc5540e8a 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -2,7 +2,7 @@ # # Copyright (c) 2013 Google, Inc -obj-$(CONFIG_UT_DM) += test-main.o +obj-$(CONFIG_UT_DM) += test-dm.o # Tests for particular subsystems - when enabling driver model for a new # subsystem you must add sandbox tests here. diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c new file mode 100644 index 00000000000..71e9cf6e5da --- /dev/null +++ b/test/dm/test-dm.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2013 Google, Inc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct unit_test_state global_dm_test_state; +static struct dm_test_state _global_priv_dm_test_state; + +/* Get ready for testing */ +static int dm_test_init(struct unit_test_state *uts, bool of_live) +{ + struct dm_test_state *dms = uts->priv; + + memset(dms, '\0', sizeof(*dms)); + gd->dm_root = NULL; + if (!CONFIG_IS_ENABLED(OF_PLATDATA)) + memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); + state_reset_for_test(state_get_current()); + + /* Determine whether to make the live tree available */ + gd_set_of_root(of_live ? uts->of_root : NULL); + ut_assertok(dm_init(of_live)); + dms->root = dm_root(); + + return 0; +} + +/* Ensure all the test devices are probed */ +static int do_autoprobe(struct unit_test_state *uts) +{ + struct udevice *dev; + int ret; + + /* Scanning the uclass is enough to probe all the devices */ + for (ret = uclass_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_next_device(&dev)) + ; + + return ret; +} + +static int dm_test_destroy(struct unit_test_state *uts) +{ + int id; + + for (id = 0; id < UCLASS_COUNT; id++) { + struct uclass *uc; + + /* + * If the uclass doesn't exist we don't want to create it. So + * check that here before we call uclass_find_device(). + */ + uc = uclass_find(id); + if (!uc) + continue; + ut_assertok(uclass_destroy(uc)); + } + + return 0; +} + +static int dm_do_test(struct unit_test_state *uts, struct unit_test *test, + bool of_live) +{ + struct sandbox_state *state = state_get_current(); + const char *fname = strrchr(test->file, '/') + 1; + + printf("Test: %s: %s%s\n", test->name, fname, + !of_live ? " (flat tree)" : ""); + ut_assertok(dm_test_init(uts, of_live)); + + uts->start = mallinfo(); + if (test->flags & UT_TESTF_SCAN_PDATA) + ut_assertok(dm_scan_plat(false)); + if (test->flags & UT_TESTF_PROBE_TEST) + ut_assertok(do_autoprobe(uts)); + if (!CONFIG_IS_ENABLED(OF_PLATDATA) && + (test->flags & UT_TESTF_SCAN_FDT)) + ut_assertok(dm_extended_scan(false)); + + /* + * Silence the console and rely on console recording to get + * our output. + */ + console_record_reset_enable(); + if (!state->show_test_output) + gd->flags |= GD_FLG_SILENT; + test->func(uts); + gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD); + state_set_skip_delays(false); + + ut_assertok(dm_test_destroy(uts)); + + return 0; +} + +/** + * dm_test_run_on_flattree() - Check if we should run a test with flat DT + * + * This skips long/slow tests where there is not much value in running a flat + * DT test in addition to a live DT test. + * + * @return true to run the given test on the flat device tree + */ +static bool dm_test_run_on_flattree(struct unit_test *test) +{ + const char *fname = strrchr(test->file, '/') + 1; + + return !strstr(fname, "video") || strstr(test->name, "video_base"); +} + +static bool test_matches(const char *test_name, const char *find_name) +{ + if (!find_name) + return true; + + if (!strcmp(test_name, find_name)) + return true; + + /* All tests have this prefix */ + if (!strncmp(test_name, "dm_test_", 8)) + test_name += 8; + + if (!strcmp(test_name, find_name)) + return true; + + return false; +} + +int dm_test_run(const char *test_name) +{ + struct unit_test *tests = ll_entry_start(struct unit_test, dm_test); + const int n_ents = ll_entry_count(struct unit_test, dm_test); + struct unit_test_state *uts = &global_dm_test_state; + struct unit_test *test; + int found; + + uts->priv = &_global_priv_dm_test_state; + uts->fail_count = 0; + + if (!CONFIG_IS_ENABLED(OF_PLATDATA)) { + /* + * If we have no device tree, or it only has a root node, then + * these * tests clearly aren't going to work... + */ + if (!gd->fdt_blob || fdt_next_node(gd->fdt_blob, 0, NULL) < 0) { + puts("Please run with test device tree:\n" + " ./u-boot -d arch/sandbox/dts/test.dtb\n"); + ut_assert(gd->fdt_blob); + } + } + + if (!test_name) + printf("Running %d driver model tests\n", n_ents); + else + + found = 0; + uts->of_root = gd_of_root(); + for (test = tests; test < tests + n_ents; test++) { + const char *name = test->name; + int runs; + + if (!test_matches(name, test_name)) + continue; + + /* Run with the live tree if possible */ + runs = 0; + if (CONFIG_IS_ENABLED(OF_LIVE)) { + if (!(test->flags & UT_TESTF_FLAT_TREE)) { + ut_assertok(dm_do_test(uts, test, true)); + runs++; + } + } + + /* + * Run with the flat tree if we couldn't run it with live tree, + * or it is a core test. + */ + if (!(test->flags & UT_TESTF_LIVE_TREE) && + (!runs || dm_test_run_on_flattree(test))) { + ut_assertok(dm_do_test(uts, test, false)); + runs++; + } + found++; + } + + if (test_name && !found) + printf("Test '%s' not found\n", test_name); + else + printf("Failures: %d\n", uts->fail_count); + + /* Put everything back to normal so that sandbox works as expected */ + gd_set_of_root(uts->of_root); + gd->dm_root = NULL; + ut_assertok(dm_init(CONFIG_IS_ENABLED(OF_LIVE))); + dm_scan_plat(false); + if (!CONFIG_IS_ENABLED(OF_PLATDATA)) + dm_scan_fdt(false); + + return uts->fail_count ? CMD_RET_FAILURE : 0; +} + +int do_ut_dm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + const char *test_name = NULL; + + if (argc > 1) + test_name = argv[1]; + + return dm_test_run(test_name); +} diff --git a/test/dm/test-main.c b/test/dm/test-main.c deleted file mode 100644 index 560f8d63ec6..00000000000 --- a/test/dm/test-main.c +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2013 Google, Inc - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -struct unit_test_state global_dm_test_state; -static struct dm_test_state _global_priv_dm_test_state; - -/* Get ready for testing */ -static int dm_test_init(struct unit_test_state *uts, bool of_live) -{ - struct dm_test_state *dms = uts->priv; - - memset(dms, '\0', sizeof(*dms)); - gd->dm_root = NULL; - if (!CONFIG_IS_ENABLED(OF_PLATDATA)) - memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); - state_reset_for_test(state_get_current()); - - /* Determine whether to make the live tree available */ - gd_set_of_root(of_live ? uts->of_root : NULL); - ut_assertok(dm_init(of_live)); - dms->root = dm_root(); - - return 0; -} - -/* Ensure all the test devices are probed */ -static int do_autoprobe(struct unit_test_state *uts) -{ - struct udevice *dev; - int ret; - - /* Scanning the uclass is enough to probe all the devices */ - for (ret = uclass_first_device(UCLASS_TEST, &dev); - dev; - ret = uclass_next_device(&dev)) - ; - - return ret; -} - -static int dm_test_destroy(struct unit_test_state *uts) -{ - int id; - - for (id = 0; id < UCLASS_COUNT; id++) { - struct uclass *uc; - - /* - * If the uclass doesn't exist we don't want to create it. So - * check that here before we call uclass_find_device(). - */ - uc = uclass_find(id); - if (!uc) - continue; - ut_assertok(uclass_destroy(uc)); - } - - return 0; -} - -static int dm_do_test(struct unit_test_state *uts, struct unit_test *test, - bool of_live) -{ - struct sandbox_state *state = state_get_current(); - const char *fname = strrchr(test->file, '/') + 1; - - printf("Test: %s: %s%s\n", test->name, fname, - !of_live ? " (flat tree)" : ""); - ut_assertok(dm_test_init(uts, of_live)); - - uts->start = mallinfo(); - if (test->flags & UT_TESTF_SCAN_PDATA) - ut_assertok(dm_scan_plat(false)); - if (test->flags & UT_TESTF_PROBE_TEST) - ut_assertok(do_autoprobe(uts)); - if (!CONFIG_IS_ENABLED(OF_PLATDATA) && - (test->flags & UT_TESTF_SCAN_FDT)) - ut_assertok(dm_extended_scan(false)); - - /* - * Silence the console and rely on console recording to get - * our output. - */ - console_record_reset_enable(); - if (!state->show_test_output) - gd->flags |= GD_FLG_SILENT; - test->func(uts); - gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD); - state_set_skip_delays(false); - - ut_assertok(dm_test_destroy(uts)); - - return 0; -} - -/** - * dm_test_run_on_flattree() - Check if we should run a test with flat DT - * - * This skips long/slow tests where there is not much value in running a flat - * DT test in addition to a live DT test. - * - * @return true to run the given test on the flat device tree - */ -static bool dm_test_run_on_flattree(struct unit_test *test) -{ - const char *fname = strrchr(test->file, '/') + 1; - - return !strstr(fname, "video") || strstr(test->name, "video_base"); -} - -static bool test_matches(const char *test_name, const char *find_name) -{ - if (!find_name) - return true; - - if (!strcmp(test_name, find_name)) - return true; - - /* All tests have this prefix */ - if (!strncmp(test_name, "dm_test_", 8)) - test_name += 8; - - if (!strcmp(test_name, find_name)) - return true; - - return false; -} - -int dm_test_main(const char *test_name) -{ - struct unit_test *tests = ll_entry_start(struct unit_test, dm_test); - const int n_ents = ll_entry_count(struct unit_test, dm_test); - struct unit_test_state *uts = &global_dm_test_state; - struct unit_test *test; - int found; - - uts->priv = &_global_priv_dm_test_state; - uts->fail_count = 0; - - if (!CONFIG_IS_ENABLED(OF_PLATDATA)) { - /* - * If we have no device tree, or it only has a root node, then - * these * tests clearly aren't going to work... - */ - if (!gd->fdt_blob || fdt_next_node(gd->fdt_blob, 0, NULL) < 0) { - puts("Please run with test device tree:\n" - " ./u-boot -d arch/sandbox/dts/test.dtb\n"); - ut_assert(gd->fdt_blob); - } - } - - if (!test_name) - printf("Running %d driver model tests\n", n_ents); - else - - found = 0; - uts->of_root = gd_of_root(); - for (test = tests; test < tests + n_ents; test++) { - const char *name = test->name; - int runs; - - if (!test_matches(name, test_name)) - continue; - - /* Run with the live tree if possible */ - runs = 0; - if (CONFIG_IS_ENABLED(OF_LIVE)) { - if (!(test->flags & UT_TESTF_FLAT_TREE)) { - ut_assertok(dm_do_test(uts, test, true)); - runs++; - } - } - - /* - * Run with the flat tree if we couldn't run it with live tree, - * or it is a core test. - */ - if (!(test->flags & UT_TESTF_LIVE_TREE) && - (!runs || dm_test_run_on_flattree(test))) { - ut_assertok(dm_do_test(uts, test, false)); - runs++; - } - found++; - } - - if (test_name && !found) - printf("Test '%s' not found\n", test_name); - else - printf("Failures: %d\n", uts->fail_count); - - /* Put everything back to normal so that sandbox works as expected */ - gd_set_of_root(uts->of_root); - gd->dm_root = NULL; - ut_assertok(dm_init(CONFIG_IS_ENABLED(OF_LIVE))); - dm_scan_plat(false); - if (!CONFIG_IS_ENABLED(OF_PLATDATA)) - dm_scan_fdt(false); - - return uts->fail_count ? CMD_RET_FAILURE : 0; -} - -int do_ut_dm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{ - const char *test_name = NULL; - - if (argc > 1) - test_name = argv[1]; - - return dm_test_main(test_name); -} -- cgit v1.3.1 From 1c7217511cd9a050183402b56c0371e4f9720bea Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:34:47 -0700 Subject: test: Add an overall test runner Add a new test runner that will eventually be able to run any test. For now, have it run the 'command' unit tests, so that the functionality in cmd_ut_category() moves into it. Signed-off-by: Simon Glass --- include/test/ut.h | 42 +++++++++++++++++++++++++++++++++++ test/Makefile | 2 ++ test/cmd_ut.c | 38 +++++--------------------------- test/test-main.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 33 deletions(-) create mode 100644 test/test-main.c (limited to 'include') diff --git a/include/test/ut.h b/include/test/ut.h index 17400c73ea9..88e75ab791c 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -356,4 +356,46 @@ void ut_silence_console(struct unit_test_state *uts); */ void ut_unsilence_console(struct unit_test_state *uts); +/** + * ut_run_tests() - Run a set of tests + * + * This runs the tests, handling any preparation and clean-up needed. It prints + * the name of each test before running it. + * + * @uts: Test state to update. The caller should ensure that this is zeroed for + * the first call to this function. On exit, @uts->fail_count is + * incremented by the number of failures (0, one hopes) + * @prefix: String prefix for the tests. Any tests that have this prefix will be + * printed without the prefix, so that it is easier to see the unique part + * of the test name. If NULL, no prefix processing is done + * @tests: List of tests to run + * @count: Number of tests to run + * @select_name: Name of a single test to run (from the list provided). If NULL + * then all tests are run + * @return 0 if all tests passed, -ENOENT if test @select_name was not found, + * -EBADF if any failed + */ +int ut_run_tests(struct unit_test_state *uts, const char *prefix, + struct unit_test *tests, int count, const char *select_name); + +/** + * ut_run_tests() - Run a set of tests + * + * This runs the test, handling any preparation and clean-up needed. It prints + * the name of each test before running it. + * + * @category: Category of these tests. This is a string printed at the start to + * announce the the number of tests + * @prefix: String prefix for the tests. Any tests that have this prefix will be + * printed without the prefix, so that it is easier to see the unique part + * of the test name. If NULL, no prefix processing is done + * @tests: List of tests to run + * @count: Number of tests to run + * @select_name: Name of a single test to run (from the list provided). If NULL + * then all tests are run + * @return 0 if all tests passed, -1 if any failed + */ +int ut_run_list(const char *name, const char *prefix, struct unit_test *tests, + int count, const char *select_name); + #endif diff --git a/test/Makefile b/test/Makefile index 932e5173831..5cd284e322e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,6 +2,8 @@ # # (C) Copyright 2012 The Chromium Authors +obj-y += test-main.o + ifneq ($(CONFIG_$(SPL_)BLOBLIST),) obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o obj-$(CONFIG_$(SPL_)CMDLINE) += bootm.o diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 8f3089890ea..157f6aa9767 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -9,6 +9,7 @@ #include #include #include +#include static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); @@ -17,41 +18,12 @@ int cmd_ut_category(const char *name, const char *prefix, struct unit_test *tests, int n_ents, int argc, char *const argv[]) { - struct unit_test_state uts = { .fail_count = 0 }; - struct unit_test *test; - int prefix_len = prefix ? strlen(prefix) : 0; + int ret; - if (argc == 1) - printf("Running %d %s tests\n", n_ents, name); + ret = ut_run_list(name, prefix, tests, n_ents, + argc > 1 ? argv[1] : NULL); - for (test = tests; test < tests + n_ents; test++) { - const char *test_name = test->name; - - /* Remove the prefix */ - if (prefix && !strncmp(test_name, prefix, prefix_len)) - test_name += prefix_len; - - if (argc > 1 && strcmp(argv[1], test_name)) - continue; - printf("Test: %s\n", test->name); - - if (test->flags & UT_TESTF_CONSOLE_REC) { - int ret = console_record_reset_enable(); - - if (ret) { - printf("Skipping: Console recording disabled\n"); - continue; - } - } - - uts.start = mallinfo(); - - test->func(&uts); - } - - printf("Failures: %d\n", uts.fail_count); - - return uts.fail_count ? CMD_RET_FAILURE : 0; + return ret ? CMD_RET_FAILURE : 0; } static struct cmd_tbl cmd_ut_sub[] = { diff --git a/test/test-main.c b/test/test-main.c new file mode 100644 index 00000000000..376e7ebd3d2 --- /dev/null +++ b/test/test-main.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include + +int ut_run_tests(struct unit_test_state *uts, const char *prefix, + struct unit_test *tests, int count, const char *select_name) +{ + struct unit_test *test; + int prefix_len = prefix ? strlen(prefix) : 0; + int found = 0; + + for (test = tests; test < tests + count; test++) { + const char *test_name = test->name; + + /* Remove the prefix */ + if (prefix && !strncmp(test_name, prefix, prefix_len)) + test_name += prefix_len; + + if (select_name && strcmp(select_name, test_name)) + continue; + printf("Test: %s\n", test_name); + found++; + + if (test->flags & UT_TESTF_CONSOLE_REC) { + int ret = console_record_reset_enable(); + + if (ret) { + printf("Skipping: Console recording disabled\n"); + continue; + } + } + + uts->start = mallinfo(); + + test->func(uts); + } + if (select_name && !found) + return -ENOENT; + + return uts->fail_count ? -EBADF : 0; +} + +int ut_run_list(const char *category, const char *prefix, + struct unit_test *tests, int count, const char *select_name) +{ + struct unit_test_state uts = { .fail_count = 0 }; + int ret; + + if (!select_name) + printf("Running %d %s tests\n", count, category); + + ret = ut_run_tests(&uts, prefix, tests, count, select_name); + + if (ret == -ENOENT) + printf("Test '%s' not found\n", select_name); + else + printf("Failures: %d\n", uts.fail_count); + + return ret; +} -- cgit v1.3.1 From d002a2764418fa8f054d94789e7814f60294318f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:34:48 -0700 Subject: test: Create pre/post-run functions Split out the test preparation into a separation function before expanding it. Add a post-run function as well, currently empty. Signed-off-by: Simon Glass --- include/test/ut.h | 20 ++++++++++++++++++++ test/test-main.c | 41 +++++++++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/test/ut.h b/include/test/ut.h index 88e75ab791c..7cb5e10f3af 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -356,6 +356,26 @@ void ut_silence_console(struct unit_test_state *uts); */ void ut_unsilence_console(struct unit_test_state *uts); +/** + * test_pre_run() - Handle any preparation needed to run a test + * + * @uts: Test state + * @test: Test to prepare for + * @return 0 if OK, -EAGAIN to skip this test since some required feature is not + * available, other -ve on error (meaning that testing cannot likely + * continue) + */ +int test_pre_run(struct unit_test_state *uts, struct unit_test *test); + +/** + * test_post_run() - Handle cleaning up after a test + * + * @uts: Test state + * @test: Test to clean up after + * @return 0 if OK, -ve on error (meaning that testing cannot likely continue) + */ +int test_post_run(struct unit_test_state *uts, struct unit_test *test); + /** * ut_run_tests() - Run a set of tests * diff --git a/test/test-main.c b/test/test-main.c index 376e7ebd3d2..7961fd8aa3e 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -8,6 +8,27 @@ #include #include +int test_pre_run(struct unit_test_state *uts, struct unit_test *test) +{ + uts->start = mallinfo(); + + if (test->flags & UT_TESTF_CONSOLE_REC) { + int ret = console_record_reset_enable(); + + if (ret) { + printf("Skipping: Console recording disabled\n"); + return -EAGAIN; + } + } + + return 0; +} + +int test_post_run(struct unit_test_state *uts, struct unit_test *test) +{ + return 0; +} + int ut_run_tests(struct unit_test_state *uts, const char *prefix, struct unit_test *tests, int count, const char *select_name) { @@ -17,6 +38,7 @@ int ut_run_tests(struct unit_test_state *uts, const char *prefix, for (test = tests; test < tests + count; test++) { const char *test_name = test->name; + int ret; /* Remove the prefix */ if (prefix && !strncmp(test_name, prefix, prefix_len)) @@ -27,18 +49,17 @@ int ut_run_tests(struct unit_test_state *uts, const char *prefix, printf("Test: %s\n", test_name); found++; - if (test->flags & UT_TESTF_CONSOLE_REC) { - int ret = console_record_reset_enable(); - - if (ret) { - printf("Skipping: Console recording disabled\n"); - continue; - } - } - - uts->start = mallinfo(); + ret = test_pre_run(uts, test); + if (ret == -EAGAIN) + continue; + if (ret) + return ret; test->func(uts); + + ret = test_post_run(uts, test); + if (ret) + return ret; } if (select_name && !found) return -ENOENT; -- cgit v1.3.1 From 30a0d2064d593bf357282071a938816de876c64b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:34:49 -0700 Subject: test: Call test_pre/post_run() from driver model tests Ultimately we want to get rid of the special driver model test init and use test_pre_run() and test_post_run() for all tests. As a first step, use those function to handle console recording. For now we need a special case for setting uts->start, but that wil go away once all init is in one place. Signed-off-by: Simon Glass --- include/dm/test.h | 2 +- test/dm/test-dm.c | 10 +++++----- test/test-main.c | 8 +++++++- 3 files changed, 13 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/dm/test.h b/include/dm/test.h index dfbc82c756d..c0b463cc0f1 100644 --- a/include/dm/test.h +++ b/include/dm/test.h @@ -144,7 +144,7 @@ struct dm_test_state { /* Declare a new driver model test */ #define DM_TEST(_name, _flags) \ - UNIT_TEST(_name, UT_TESTF_DM | (_flags), dm_test) + UNIT_TEST(_name, UT_TESTF_DM | UT_TESTF_CONSOLE_REC | (_flags), dm_test) /* * struct sandbox_sdl_plat - Platform data for the SDL video driver diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index 71e9cf6e5da..69a0349d04c 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -97,14 +97,14 @@ static int dm_do_test(struct unit_test_state *uts, struct unit_test *test, (test->flags & UT_TESTF_SCAN_FDT)) ut_assertok(dm_extended_scan(false)); - /* - * Silence the console and rely on console recording to get - * our output. - */ - console_record_reset_enable(); + ut_assertok(test_pre_run(uts, test)); + if (!state->show_test_output) gd->flags |= GD_FLG_SILENT; test->func(uts); + + ut_assertok(test_post_run(uts, test)); + gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD); state_set_skip_delays(false); diff --git a/test/test-main.c b/test/test-main.c index 7961fd8aa3e..9c600094740 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -8,9 +8,13 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + int test_pre_run(struct unit_test_state *uts, struct unit_test *test) { - uts->start = mallinfo(); + /* DM tests have already done this */ + if (!(test->flags & UT_TESTF_DM)) + uts->start = mallinfo(); if (test->flags & UT_TESTF_CONSOLE_REC) { int ret = console_record_reset_enable(); @@ -26,6 +30,8 @@ int test_pre_run(struct unit_test_state *uts, struct unit_test *test) int test_post_run(struct unit_test_state *uts, struct unit_test *test) { + gd->flags &= ~GD_FLG_RECORD; + return 0; } -- cgit v1.3.1 From 47ec3ede4efe214b4debdaf845d6eb622154f405 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:34:55 -0700 Subject: test: Move delay skipping to test_pre_run() This allows delays to be skipped in sandbox tests. Move it to the common pre-init function. Signed-off-by: Simon Glass --- include/test/ut.h | 11 +++++++++++ test/dm/test-dm.c | 2 -- test/test-main.c | 2 ++ test/ut.c | 7 +++++++ 4 files changed, 20 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/test/ut.h b/include/test/ut.h index 7cb5e10f3af..e5ec18e60b0 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -356,6 +356,17 @@ void ut_silence_console(struct unit_test_state *uts); */ void ut_unsilence_console(struct unit_test_state *uts); +/** + * ut_set_skip_delays() - Sets whether delays should be skipped + * + * Normally functions like mdelay() cause U-Boot to wait for a while. This + * allows all such delays to be skipped on sandbox, to speed up tests + * + * @uts: Test state (in case in future we want to keep state here) + * @skip_delays: true to skip delays, false to process them normally + */ +void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays); + /** * test_pre_run() - Handle any preparation needed to run a test * diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index fdd35f663e4..569ffbbad93 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -78,8 +78,6 @@ static int dm_do_test(struct unit_test_state *uts, struct unit_test *test, ut_assertok(test_post_run(uts, test)); - state_set_skip_delays(false); - ut_assertok(dm_test_destroy(uts)); return 0; diff --git a/test/test-main.c b/test/test-main.c index e273777b6e2..6f0d32f7e27 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -30,6 +30,8 @@ static int do_autoprobe(struct unit_test_state *uts) int test_pre_run(struct unit_test_state *uts, struct unit_test *test) { + ut_set_skip_delays(uts, false); + uts->start = mallinfo(); if (test->flags & UT_TESTF_SCAN_PDATA) diff --git a/test/ut.c b/test/ut.c index 7328338731c..ea0af153e4a 100644 --- a/test/ut.c +++ b/test/ut.c @@ -133,3 +133,10 @@ void ut_unsilence_console(struct unit_test_state *uts) { gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD); } + +void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays) +{ +#ifdef CONFIG_SANDBOX + state_set_skip_delays(skip_delays); +#endif +} -- cgit v1.3.1 From 72b524cf426697e764c9c63611d0f6743f50f0f5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:34:56 -0700 Subject: test: Handle driver model reinit in test_pre_run() For driver model tests we want to reinit the data structures so that everything is in a known state before the test runs. This avoids one test changing something that breaks a subsequent tests. Move the call for this into test_pre_run(). Signed-off-by: Simon Glass --- include/test/test.h | 2 ++ include/test/ut.h | 10 ++++++++++ test/dm/test-dm.c | 6 +++--- test/test-main.c | 3 +++ 4 files changed, 18 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/test/test.h b/include/test/test.h index d282cb2362d..6997568cc07 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -15,6 +15,7 @@ * @fail_count: Number of tests that failed * @start: Store the starting mallinfo when doing leak test * @priv: A pointer to some other info some suites want to track + * @of_live: true to use livetree if available, false to use flattree * @of_root: Record of the livetree root node (used for setting up tests) * @expect_str: Temporary string used to hold expected string value * @actual_str: Temporary string used to hold actual string value @@ -24,6 +25,7 @@ struct unit_test_state { struct mallinfo start; void *priv; struct device_node *of_root; + bool of_live; char expect_str[256]; char actual_str[256]; }; diff --git a/include/test/ut.h b/include/test/ut.h index e5ec18e60b0..6e56ca99c31 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -387,6 +387,16 @@ int test_pre_run(struct unit_test_state *uts, struct unit_test *test); */ int test_post_run(struct unit_test_state *uts, struct unit_test *test); +/** + * dm_test_init() - Get ready to run a driver model test + * + * This clears out the driver model data structures. For sandbox it resets the + * state structure. + * + * @uts: Test state + */ +int dm_test_init(struct unit_test_state *uts); + /** * ut_run_tests() - Run a set of tests * diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index 569ffbbad93..ceeac3fd361 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -24,10 +24,10 @@ DECLARE_GLOBAL_DATA_PTR; struct unit_test_state global_dm_test_state; static struct dm_test_state _global_priv_dm_test_state; -/* Get ready for testing */ -static int dm_test_init(struct unit_test_state *uts, bool of_live) +int dm_test_init(struct unit_test_state *uts) { struct dm_test_state *dms = uts->priv; + bool of_live = uts->of_live; memset(dms, '\0', sizeof(*dms)); gd->dm_root = NULL; @@ -70,7 +70,7 @@ static int dm_do_test(struct unit_test_state *uts, struct unit_test *test, printf("Test: %s: %s%s\n", test->name, fname, !of_live ? " (flat tree)" : ""); - ut_assertok(dm_test_init(uts, of_live)); + uts->of_live = of_live; ut_assertok(test_pre_run(uts, test)); diff --git a/test/test-main.c b/test/test-main.c index 6f0d32f7e27..f14b7b09f79 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -30,6 +30,9 @@ static int do_autoprobe(struct unit_test_state *uts) int test_pre_run(struct unit_test_state *uts, struct unit_test *test) { + if (test->flags & UT_TESTF_DM) + ut_assertok(dm_test_init(uts)); + ut_set_skip_delays(uts, false); uts->start = mallinfo(); -- cgit v1.3.1 From 4a467c6de6765a9685d1e3ced95ce141a14dfcf3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:34:57 -0700 Subject: test: Drop struct dm_test_state Driver model is a core part of U-Boot. We don't really need to have a separate test structure for the driver model tests and it makes it harder to write a test if you have to think about which type of test it is. Subsume the fields from struct dm_test_state into struct unit_test_state and delete the former. Signed-off-by: Simon Glass --- include/dm/test.h | 17 --------------- include/test/test.h | 10 +++++++-- test/dm/core.c | 58 +++++++++++++++++++++------------------------------ test/dm/test-dm.c | 10 ++++----- test/dm/test-driver.c | 4 +--- test/dm/test-uclass.c | 3 +-- 6 files changed, 39 insertions(+), 63 deletions(-) (limited to 'include') diff --git a/include/dm/test.h b/include/dm/test.h index c0b463cc0f1..fe1cc2e278c 100644 --- a/include/dm/test.h +++ b/include/dm/test.h @@ -125,23 +125,6 @@ extern int dm_testdrv_op_count[DM_TEST_OP_COUNT]; extern struct unit_test_state global_dm_test_state; -/* - * struct dm_test_state - Entire state of dm test system - * - * This is often abreviated to dms. - * - * @root: Root device - * @testdev: Test device - * @force_fail_alloc: Force all memory allocs to fail - * @skip_post_probe: Skip uclass post-probe processing - */ -struct dm_test_state { - struct udevice *root; - struct udevice *testdev; - int force_fail_alloc; - int skip_post_probe; -}; - /* Declare a new driver model test */ #define DM_TEST(_name, _flags) \ UNIT_TEST(_name, UT_TESTF_DM | UT_TESTF_CONSOLE_REC | (_flags), dm_test) diff --git a/include/test/test.h b/include/test/test.h index 6997568cc07..5eeec35f525 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -14,18 +14,24 @@ * * @fail_count: Number of tests that failed * @start: Store the starting mallinfo when doing leak test - * @priv: A pointer to some other info some suites want to track * @of_live: true to use livetree if available, false to use flattree * @of_root: Record of the livetree root node (used for setting up tests) + * @root: Root device + * @testdev: Test device + * @force_fail_alloc: Force all memory allocs to fail + * @skip_post_probe: Skip uclass post-probe processing * @expect_str: Temporary string used to hold expected string value * @actual_str: Temporary string used to hold actual string value */ struct unit_test_state { int fail_count; struct mallinfo start; - void *priv; struct device_node *of_root; bool of_live; + struct udevice *root; + struct udevice *testdev; + int force_fail_alloc; + int skip_post_probe; char expect_str[256]; char actual_str[256]; }; diff --git a/test/dm/core.c b/test/dm/core.c index 35ca689d646..2210345dd14 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -117,14 +117,13 @@ int dm_leak_check_end(struct unit_test_state *uts) /* Test that binding with plat occurs correctly */ static int dm_test_autobind(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; struct udevice *dev; /* * We should have a single class (UCLASS_ROOT) and a single root * device with no children. */ - ut_assert(dms->root); + ut_assert(uts->root); ut_asserteq(1, list_count_items(gd->uclass_root)); ut_asserteq(0, list_count_items(&gd->dm_root->child_head)); ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]); @@ -207,7 +206,6 @@ DM_TEST(dm_test_autobind_uclass_pdata_valid, UT_TESTF_SCAN_PDATA); /* Test that autoprobe finds all the expected devices */ static int dm_test_autoprobe(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; int expected_base_add; struct udevice *dev; struct uclass *uc; @@ -221,7 +219,7 @@ static int dm_test_autoprobe(struct unit_test_state *uts) ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]); /* The root device should not be activated until needed */ - ut_assert(dev_get_flags(dms->root) & DM_FLAG_ACTIVATED); + ut_assert(dev_get_flags(uts->root) & DM_FLAG_ACTIVATED); /* * We should be able to find the three test devices, and they should @@ -241,7 +239,7 @@ static int dm_test_autoprobe(struct unit_test_state *uts) /* Activating a device should activate the root device */ if (!i) - ut_assert(dev_get_flags(dms->root) & DM_FLAG_ACTIVATED); + ut_assert(dev_get_flags(uts->root) & DM_FLAG_ACTIVATED); } /* @@ -293,7 +291,6 @@ DM_TEST(dm_test_plat, UT_TESTF_SCAN_PDATA); /* Test that we can bind, probe, remove, unbind a driver */ static int dm_test_lifecycle(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; int op_count[DM_TEST_OP_COUNT]; struct udevice *dev, *test_dev; int pingret; @@ -301,7 +298,7 @@ static int dm_test_lifecycle(struct unit_test_state *uts) memcpy(op_count, dm_testdrv_op_count, sizeof(op_count)); - ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual, &dev)); ut_assert(dev); ut_assert(dm_testdrv_op_count[DM_TEST_OP_BIND] @@ -309,7 +306,7 @@ static int dm_test_lifecycle(struct unit_test_state *uts) ut_assert(!dev_get_priv(dev)); /* Probe the device - it should fail allocating private data */ - dms->force_fail_alloc = 1; + uts->force_fail_alloc = 1; ret = device_probe(dev); ut_assert(ret == -ENOMEM); ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE] @@ -317,7 +314,7 @@ static int dm_test_lifecycle(struct unit_test_state *uts) ut_assert(!dev_get_priv(dev)); /* Try again without the alloc failure */ - dms->force_fail_alloc = 0; + uts->force_fail_alloc = 0; ut_assertok(device_probe(dev)); ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE] == op_count[DM_TEST_OP_PROBE] + 2); @@ -349,19 +346,18 @@ DM_TEST(dm_test_lifecycle, UT_TESTF_SCAN_PDATA | UT_TESTF_PROBE_TEST); /* Test that we can bind/unbind and the lists update correctly */ static int dm_test_ordering(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; struct udevice *dev, *dev_penultimate, *dev_last, *test_dev; int pingret; - ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual, &dev)); ut_assert(dev); /* Bind two new devices (numbers 4 and 5) */ - ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual, &dev_penultimate)); ut_assert(dev_penultimate); - ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual, &dev_last)); ut_assert(dev_last); @@ -376,7 +372,7 @@ static int dm_test_ordering(struct unit_test_state *uts) ut_assert(dev_last == test_dev); /* Add back the original device 3, now in position 5 */ - ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual, &dev)); ut_assert(dev); @@ -568,7 +564,6 @@ static int create_children(struct unit_test_state *uts, struct udevice *parent, static int dm_test_children(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; struct udevice *top[NODE_COUNT]; struct udevice *child[NODE_COUNT]; struct udevice *grandchild[NODE_COUNT]; @@ -578,12 +573,12 @@ static int dm_test_children(struct unit_test_state *uts) int i; /* We don't care about the numbering for this test */ - dms->skip_post_probe = 1; + uts->skip_post_probe = 1; ut_assert(NODE_COUNT > 5); /* First create 10 top-level children */ - ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top)); + ut_assertok(create_children(uts, uts->root, NODE_COUNT, 0, top)); /* Now a few have their own children */ ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL)); @@ -654,7 +649,6 @@ DM_TEST(dm_test_children, 0); static int dm_test_device_reparent(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; struct udevice *top[NODE_COUNT]; struct udevice *child[NODE_COUNT]; struct udevice *grandchild[NODE_COUNT]; @@ -664,12 +658,12 @@ static int dm_test_device_reparent(struct unit_test_state *uts) int i; /* We don't care about the numbering for this test */ - dms->skip_post_probe = 1; + uts->skip_post_probe = 1; ut_assert(NODE_COUNT > 5); /* First create 10 top-level children */ - ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top)); + ut_assertok(create_children(uts, uts->root, NODE_COUNT, 0, top)); /* Now a few have their own children */ ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL)); @@ -815,15 +809,14 @@ DM_TEST(dm_test_device_reparent, 0); /* Test that pre-relocation devices work as expected */ static int dm_test_pre_reloc(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; struct udevice *dev; /* The normal driver should refuse to bind before relocation */ - ut_asserteq(-EPERM, device_bind_by_name(dms->root, true, + ut_asserteq(-EPERM, device_bind_by_name(uts->root, true, &driver_info_manual, &dev)); /* But this one is marked pre-reloc */ - ut_assertok(device_bind_by_name(dms->root, true, + ut_assertok(device_bind_by_name(uts->root, true, &driver_info_pre_reloc, &dev)); return 0; @@ -836,10 +829,9 @@ DM_TEST(dm_test_pre_reloc, 0); */ static int dm_test_remove_active_dma(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; struct udevice *dev; - ut_assertok(device_bind_by_name(dms->root, false, &driver_info_act_dma, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_act_dma, &dev)); ut_assert(dev); @@ -872,7 +864,7 @@ static int dm_test_remove_active_dma(struct unit_test_state *uts) * the active DMA remove call */ ut_assertok(device_unbind(dev)); - ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual, &dev)); ut_assert(dev); @@ -895,25 +887,24 @@ DM_TEST(dm_test_remove_active_dma, 0); /* Test removal of 'vital' devices */ static int dm_test_remove_vital(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; struct udevice *normal, *dma, *vital, *dma_vital; /* Skip the behaviour in test_post_probe() */ - dms->skip_post_probe = 1; + uts->skip_post_probe = 1; - ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual, &normal)); ut_assertnonnull(normal); - ut_assertok(device_bind_by_name(dms->root, false, &driver_info_act_dma, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_act_dma, &dma)); ut_assertnonnull(dma); - ut_assertok(device_bind_by_name(dms->root, false, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_vital_clk, &vital)); ut_assertnonnull(vital); - ut_assertok(device_bind_by_name(dms->root, false, + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_act_dma_vital_clk, &dma_vital)); ut_assertnonnull(dma_vital); @@ -1133,11 +1124,10 @@ DM_TEST(dm_test_uclass_names, UT_TESTF_SCAN_PDATA); static int dm_test_inactive_child(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; struct udevice *parent, *dev1, *dev2; /* Skip the behaviour in test_post_probe() */ - dms->skip_post_probe = 1; + uts->skip_post_probe = 1; ut_assertok(uclass_first_device_err(UCLASS_TEST, &parent)); diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index ceeac3fd361..15adc53f533 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -22,14 +22,15 @@ DECLARE_GLOBAL_DATA_PTR; struct unit_test_state global_dm_test_state; -static struct dm_test_state _global_priv_dm_test_state; int dm_test_init(struct unit_test_state *uts) { - struct dm_test_state *dms = uts->priv; bool of_live = uts->of_live; - memset(dms, '\0', sizeof(*dms)); + uts->root = NULL; + uts->testdev = NULL; + uts->force_fail_alloc = false; + uts->skip_post_probe = false; gd->dm_root = NULL; if (!CONFIG_IS_ENABLED(OF_PLATDATA)) memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); @@ -38,7 +39,7 @@ int dm_test_init(struct unit_test_state *uts) /* Determine whether to make the live tree available */ gd_set_of_root(of_live ? uts->of_root : NULL); ut_assertok(dm_init(of_live)); - dms->root = dm_root(); + uts->root = dm_root(); return 0; } @@ -124,7 +125,6 @@ int dm_test_run(const char *test_name) struct unit_test *test; int found; - uts->priv = &_global_priv_dm_test_state; uts->fail_count = 0; if (!CONFIG_IS_ENABLED(OF_PLATDATA)) { diff --git a/test/dm/test-driver.c b/test/dm/test-driver.c index ca7626a0668..63dc9d335ae 100644 --- a/test/dm/test-driver.c +++ b/test/dm/test-driver.c @@ -116,10 +116,8 @@ static int test_manual_bind(struct udevice *dev) static int test_manual_probe(struct udevice *dev) { - struct dm_test_state *dms = uts->priv; - dm_testdrv_op_count[DM_TEST_OP_PROBE]++; - if (!dms->force_fail_alloc) + if (!uts->force_fail_alloc) dev_set_priv(dev, calloc(1, sizeof(struct dm_test_priv))); if (!dev_get_priv(dev)) return -ENOMEM; diff --git a/test/dm/test-uclass.c b/test/dm/test-uclass.c index f1b7aaa727f..f4b540c9278 100644 --- a/test/dm/test-uclass.c +++ b/test/dm/test-uclass.c @@ -71,13 +71,12 @@ static int test_post_probe(struct udevice *dev) struct dm_test_uclass_perdev_priv *priv = dev_get_uclass_priv(dev); struct uclass *uc = dev->uclass; - struct dm_test_state *dms = uts->priv; dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]++; ut_assert(priv); ut_assert(device_active(dev)); priv->base_add = 0; - if (dms->skip_post_probe) + if (uts->skip_post_probe) return 0; if (&prev->uclass_node != &uc->dev_head) { struct dm_test_uclass_perdev_priv *prev_uc_priv -- cgit v1.3.1 From c79705ea938e40e204ad90e083a0654f0598a772 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:34:58 -0700 Subject: test: Move dm_test_init() into test-main.c Move this function into test-main so that all the init is in one place. Rename it so that its purpose is clearer. Signed-off-by: Simon Glass --- include/test/ut.h | 9 --------- test/dm/test-dm.c | 22 ---------------------- test/test-main.c | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/include/test/ut.h b/include/test/ut.h index 6e56ca99c31..4e0aba9f700 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -387,15 +387,6 @@ int test_pre_run(struct unit_test_state *uts, struct unit_test *test); */ int test_post_run(struct unit_test_state *uts, struct unit_test *test); -/** - * dm_test_init() - Get ready to run a driver model test - * - * This clears out the driver model data structures. For sandbox it resets the - * state structure. - * - * @uts: Test state - */ -int dm_test_init(struct unit_test_state *uts); /** * ut_run_tests() - Run a set of tests diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index 15adc53f533..d601e497522 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -23,27 +22,6 @@ DECLARE_GLOBAL_DATA_PTR; struct unit_test_state global_dm_test_state; -int dm_test_init(struct unit_test_state *uts) -{ - bool of_live = uts->of_live; - - uts->root = NULL; - uts->testdev = NULL; - uts->force_fail_alloc = false; - uts->skip_post_probe = false; - gd->dm_root = NULL; - if (!CONFIG_IS_ENABLED(OF_PLATDATA)) - memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); - state_reset_for_test(state_get_current()); - - /* Determine whether to make the live tree available */ - gd_set_of_root(of_live ? uts->of_root : NULL); - ut_assertok(dm_init(of_live)); - uts->root = dm_root(); - - return 0; -} - static int dm_test_destroy(struct unit_test_state *uts) { int id; diff --git a/test/test-main.c b/test/test-main.c index f14b7b09f79..8b0121bdcec 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -7,12 +7,43 @@ #include #include #include +#include #include +#include #include #include DECLARE_GLOBAL_DATA_PTR; +/** + * dm_test_pre_run() - Get ready to run a driver model test + * + * This clears out the driver model data structures. For sandbox it resets the + * state structure + * + * @uts: Test state + */ +static int dm_test_pre_run(struct unit_test_state *uts) +{ + bool of_live = uts->of_live; + + uts->root = NULL; + uts->testdev = NULL; + uts->force_fail_alloc = false; + uts->skip_post_probe = false; + gd->dm_root = NULL; + if (!CONFIG_IS_ENABLED(OF_PLATDATA)) + memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); + state_reset_for_test(state_get_current()); + + /* Determine whether to make the live tree available */ + gd_set_of_root(of_live ? uts->of_root : NULL); + ut_assertok(dm_init(of_live)); + uts->root = dm_root(); + + return 0; +} + /* Ensure all the test devices are probed */ static int do_autoprobe(struct unit_test_state *uts) { @@ -31,7 +62,7 @@ static int do_autoprobe(struct unit_test_state *uts) int test_pre_run(struct unit_test_state *uts, struct unit_test *test) { if (test->flags & UT_TESTF_DM) - ut_assertok(dm_test_init(uts)); + ut_assertok(dm_test_pre_run(uts)); ut_set_skip_delays(uts, false); -- cgit v1.3.1 From 99a88fe1bd98ad800ec0460e3174c2a846a991fe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:35:00 -0700 Subject: test: Move test running into a separate function Add a function to handle the preparation for running a test and the post-test clean-up. Signed-off-by: Simon Glass --- include/test/ut.h | 16 ++++++++++++++++ test/test-main.c | 32 +++++++++++++++++++++++--------- 2 files changed, 39 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/test/ut.h b/include/test/ut.h index 4e0aba9f700..98f699cbba2 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -387,6 +387,22 @@ int test_pre_run(struct unit_test_state *uts, struct unit_test *test); */ int test_post_run(struct unit_test_state *uts, struct unit_test *test); +/** + * ut_run_test() - Run a single test + * + * This runs the test, handling any preparation and clean-up needed. It prints + * the name of each test before running it. + * + * @uts: Test state to update. The caller should ensure that this is zeroed for + * the first call to this function. On exit, @uts->fail_count is + * incremented by the number of failures (0, one hopes) + * @test: Test to run + * @name: Name of test, possibly skipping a prefix that should not be displayed + * @return 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if + * any failed + */ +int ut_run_test(struct unit_test_state *uts, struct unit_test *test, + const char *name); /** * ut_run_tests() - Run a set of tests diff --git a/test/test-main.c b/test/test-main.c index 3806c2ad89c..dee28d35d82 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -121,6 +121,28 @@ int test_post_run(struct unit_test_state *uts, struct unit_test *test) return 0; } +int ut_run_test(struct unit_test_state *uts, struct unit_test *test, + const char *test_name) +{ + int ret; + + printf("Test: %s\n", test_name); + + ret = test_pre_run(uts, test); + if (ret == -EAGAIN) + return -EAGAIN; + if (ret) + return ret; + + test->func(uts); + + ret = test_post_run(uts, test); + if (ret) + return ret; + + return 0; +} + int ut_run_tests(struct unit_test_state *uts, const char *prefix, struct unit_test *tests, int count, const char *select_name) { @@ -138,20 +160,12 @@ int ut_run_tests(struct unit_test_state *uts, const char *prefix, if (select_name && strcmp(select_name, test_name)) continue; - printf("Test: %s\n", test_name); + ret = ut_run_test(uts, test, test_name); found++; - - ret = test_pre_run(uts, test); if (ret == -EAGAIN) continue; if (ret) return ret; - - test->func(uts); - - ret = test_post_run(uts, test); - if (ret) - return ret; } if (select_name && !found) return -ENOENT; -- cgit v1.3.1 From ca44ca0556a29934de6356cd70a1b10f9a13c15c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:35:01 -0700 Subject: test: Use ut_run_test() to run driver model tests Instead of having a separate function for running driver model tests, use the common one. Make the pre/post-run functions private since we don't need these outside of test-main.c Signed-off-by: Simon Glass --- include/test/ut.h | 20 -------------------- test/dm/test-dm.c | 11 +---------- test/test-main.c | 26 +++++++++++++++++++++++--- 3 files changed, 24 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/include/test/ut.h b/include/test/ut.h index 98f699cbba2..adef0b7e1cf 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -367,26 +367,6 @@ void ut_unsilence_console(struct unit_test_state *uts); */ void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays); -/** - * test_pre_run() - Handle any preparation needed to run a test - * - * @uts: Test state - * @test: Test to prepare for - * @return 0 if OK, -EAGAIN to skip this test since some required feature is not - * available, other -ve on error (meaning that testing cannot likely - * continue) - */ -int test_pre_run(struct unit_test_state *uts, struct unit_test *test); - -/** - * test_post_run() - Handle cleaning up after a test - * - * @uts: Test state - * @test: Test to clean up after - * @return 0 if OK, -ve on error (meaning that testing cannot likely continue) - */ -int test_post_run(struct unit_test_state *uts, struct unit_test *test); - /** * ut_run_test() - Run a single test * diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index df938395bb6..b01123c7409 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -25,17 +25,8 @@ struct unit_test_state global_dm_test_state; static int dm_do_test(struct unit_test_state *uts, struct unit_test *test, bool of_live) { - const char *fname = strrchr(test->file, '/') + 1; - - printf("Test: %s: %s%s\n", test->name, fname, - !of_live ? " (flat tree)" : ""); uts->of_live = of_live; - - ut_assertok(test_pre_run(uts, test)); - - test->func(uts); - - ut_assertok(test_post_run(uts, test)); + ut_assertok(ut_run_test(uts, test, test->name)); return 0; } diff --git a/test/test-main.c b/test/test-main.c index dee28d35d82..32c4d4b1996 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -80,7 +80,16 @@ static int do_autoprobe(struct unit_test_state *uts) return ret; } -int test_pre_run(struct unit_test_state *uts, struct unit_test *test) +/** + * test_pre_run() - Handle any preparation needed to run a test + * + * @uts: Test state + * @test: Test to prepare for + * @return 0 if OK, -EAGAIN to skip this test since some required feature is not + * available, other -ve on error (meaning that testing cannot likely + * continue) + */ +static int test_pre_run(struct unit_test_state *uts, struct unit_test *test) { if (test->flags & UT_TESTF_DM) ut_assertok(dm_test_pre_run(uts)); @@ -112,7 +121,14 @@ int test_pre_run(struct unit_test_state *uts, struct unit_test *test) return 0; } -int test_post_run(struct unit_test_state *uts, struct unit_test *test) +/** + * test_post_run() - Handle cleaning up after a test + * + * @uts: Test state + * @test: Test to clean up after + * @return 0 if OK, -ve on error (meaning that testing cannot likely continue) + */ +static int test_post_run(struct unit_test_state *uts, struct unit_test *test) { ut_unsilence_console(uts); if (test->flags & UT_TESTF_DM) @@ -124,9 +140,13 @@ int test_post_run(struct unit_test_state *uts, struct unit_test *test) int ut_run_test(struct unit_test_state *uts, struct unit_test *test, const char *test_name) { + const char *fname = strrchr(test->file, '/') + 1; + const char *note = ""; int ret; - printf("Test: %s\n", test_name); + if ((test->flags & UT_TESTF_DM) && !uts->of_live) + note = " (flat tree)"; + printf("Test: %s: %s%s\n", test_name, fname, note); ret = test_pre_run(uts, test); if (ret == -EAGAIN) -- cgit v1.3.1 From d2281bb09b0ebf580f8efe23c84c240a2f3ea9bb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:35:03 -0700 Subject: test: Add ut_run_test_live_flat() to run tests twice Driver model tests are generally run twice, once with livetree enable and again with it disabled. Add a function to handle this and call it from the driver model test runner. Make ut_run_test() private since it is not used outside test-main.c now. Signed-off-by: Simon Glass --- include/test/ut.h | 13 ++++++----- test/dm/test-dm.c | 37 +----------------------------- test/test-main.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 73 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/include/test/ut.h b/include/test/ut.h index adef0b7e1cf..d06bc5089be 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -368,10 +368,13 @@ void ut_unsilence_console(struct unit_test_state *uts); void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays); /** - * ut_run_test() - Run a single test + * ut_run_test_live_flat() - Run a test with both live and flat tree * - * This runs the test, handling any preparation and clean-up needed. It prints - * the name of each test before running it. + * This calls ut_run_test() with livetree enabled, which is the standard setup + * for runnig tests. Then, for driver model test, it calls it again with + * livetree disabled. This allows checking of flattree being used when OF_LIVE + * is enabled, as is the case in U-Boot proper before relocation, as well as in + * SPL. * * @uts: Test state to update. The caller should ensure that this is zeroed for * the first call to this function. On exit, @uts->fail_count is @@ -381,8 +384,8 @@ void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays); * @return 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if * any failed */ -int ut_run_test(struct unit_test_state *uts, struct unit_test *test, - const char *name); +int ut_run_test_live_flat(struct unit_test_state *uts, struct unit_test *test, + const char *name); /** * ut_run_tests() - Run a set of tests diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index de41fc09db0..826b64565e8 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -22,21 +22,6 @@ DECLARE_GLOBAL_DATA_PTR; struct unit_test_state global_dm_test_state; -/** - * dm_test_run_on_flattree() - Check if we should run a test with flat DT - * - * This skips long/slow tests where there is not much value in running a flat - * DT test in addition to a live DT test. - * - * @return true to run the given test on the flat device tree - */ -static bool dm_test_run_on_flattree(struct unit_test *test) -{ - const char *fname = strrchr(test->file, '/') + 1; - - return !strstr(fname, "video") || strstr(test->name, "video_base"); -} - static bool test_matches(const char *test_name, const char *find_name) { if (!find_name) @@ -85,31 +70,11 @@ int dm_test_run(const char *test_name) uts->of_root = gd_of_root(); for (test = tests; test < tests + n_ents; test++) { const char *name = test->name; - int runs; if (!test_matches(name, test_name)) continue; - /* Run with the live tree if possible */ - runs = 0; - if (CONFIG_IS_ENABLED(OF_LIVE)) { - if (!(test->flags & UT_TESTF_FLAT_TREE)) { - uts->of_live = true; - ut_assertok(ut_run_test(uts, test, test->name)); - runs++; - } - } - - /* - * Run with the flat tree if we couldn't run it with live tree, - * or it is a core test. - */ - if (!(test->flags & UT_TESTF_LIVE_TREE) && - (!runs || dm_test_run_on_flattree(test))) { - uts->of_live = false; - ut_assertok(ut_run_test(uts, test, test->name)); - runs++; - } + ut_assertok(ut_run_test_live_flat(uts, test, test->name)); found++; } diff --git a/test/test-main.c b/test/test-main.c index 32c4d4b1996..4e17c9edb28 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -80,6 +80,24 @@ static int do_autoprobe(struct unit_test_state *uts) return ret; } +/* + * ut_test_run_on_flattree() - Check if we should run a test with flat DT + * + * This skips long/slow tests where there is not much value in running a flat + * DT test in addition to a live DT test. + * + * @return true to run the given test on the flat device tree + */ +static bool ut_test_run_on_flattree(struct unit_test *test) +{ + const char *fname = strrchr(test->file, '/') + 1; + + if (!(test->flags & UT_TESTF_DM)) + return false; + + return !strstr(fname, "video") || strstr(test->name, "video_base"); +} + /** * test_pre_run() - Handle any preparation needed to run a test * @@ -137,8 +155,22 @@ static int test_post_run(struct unit_test_state *uts, struct unit_test *test) return 0; } -int ut_run_test(struct unit_test_state *uts, struct unit_test *test, - const char *test_name) +/** + * ut_run_test() - Run a single test + * + * This runs the test, handling any preparation and clean-up needed. It prints + * the name of each test before running it. + * + * @uts: Test state to update. The caller should ensure that this is zeroed for + * the first call to this function. On exit, @uts->fail_count is + * incremented by the number of failures (0, one hopes) + * @test_name: Test to run + * @name: Name of test, possibly skipping a prefix that should not be displayed + * @return 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if + * any failed + */ +static int ut_run_test(struct unit_test_state *uts, struct unit_test *test, + const char *test_name) { const char *fname = strrchr(test->file, '/') + 1; const char *note = ""; @@ -163,6 +195,35 @@ int ut_run_test(struct unit_test_state *uts, struct unit_test *test, return 0; } +int ut_run_test_live_flat(struct unit_test_state *uts, struct unit_test *test, + const char *name) +{ + int runs; + + /* Run with the live tree if possible */ + runs = 0; + if (CONFIG_IS_ENABLED(OF_LIVE)) { + if (!(test->flags & UT_TESTF_FLAT_TREE)) { + uts->of_live = true; + ut_assertok(ut_run_test(uts, test, test->name)); + runs++; + } + } + + /* + * Run with the flat tree if we couldn't run it with live tree, + * or it is a core test. + */ + if (!(test->flags & UT_TESTF_LIVE_TREE) && + (!runs || ut_test_run_on_flattree(test))) { + uts->of_live = false; + ut_assertok(ut_run_test(uts, test, test->name)); + runs++; + } + + return 0; +} + int ut_run_tests(struct unit_test_state *uts, const char *prefix, struct unit_test *tests, int count, const char *select_name) { @@ -180,7 +241,7 @@ int ut_run_tests(struct unit_test_state *uts, const char *prefix, if (select_name && strcmp(select_name, test_name)) continue; - ret = ut_run_test(uts, test, test_name); + ret = ut_run_test_live_flat(uts, test, test_name); found++; if (ret == -EAGAIN) continue; -- cgit v1.3.1 From fe806861a98b4ad524d070c6d7b9d20fd475ec6f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:35:04 -0700 Subject: test: Use a local variable for test state At present we use a global test state for all driver-model tests. Make use of a local struct like we do with the other tests. To make this work, add functions to get and set this state. When a test starts, the state is set (so it can be used in the test). When a test finishes, the state is unset, so it cannot be used by mistake. Signed-off-by: Simon Glass --- include/test/ut.h | 14 ++++++++++++++ test/dm/test-dm.c | 4 +--- test/dm/test-driver.c | 10 +++++++++- test/dm/test-uclass.c | 7 +++++-- test/test-main.c | 18 ++++++++++++++++++ 5 files changed, 47 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/test/ut.h b/include/test/ut.h index d06bc5089be..bed0e6eb5f6 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -367,6 +367,20 @@ void ut_unsilence_console(struct unit_test_state *uts); */ void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays); +/** + * test_get_state() - Get the active test state + * + * @return the currently active test state, or NULL if none + */ +struct unit_test_state *test_get_state(void); + +/** + * test_set_state() - Set the active test state + * + * @uts: Test state to use as currently active test state, or NULL if none + */ +void test_set_state(struct unit_test_state *uts); + /** * ut_run_test_live_flat() - Run a test with both live and flat tree * diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index 826b64565e8..cdaf27bf987 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -20,8 +20,6 @@ DECLARE_GLOBAL_DATA_PTR; -struct unit_test_state global_dm_test_state; - static bool test_matches(const char *test_name, const char *find_name) { if (!find_name) @@ -44,7 +42,7 @@ int dm_test_run(const char *test_name) { struct unit_test *tests = ll_entry_start(struct unit_test, dm_test); const int n_ents = ll_entry_count(struct unit_test, dm_test); - struct unit_test_state *uts = &global_dm_test_state; + struct unit_test_state uts_s = { .fail_count = 0 }, *uts = &uts_s; struct unit_test *test; int found; diff --git a/test/dm/test-driver.c b/test/dm/test-driver.c index 63dc9d335ae..02cb974b0f7 100644 --- a/test/dm/test-driver.c +++ b/test/dm/test-driver.c @@ -18,7 +18,6 @@ #include int dm_testdrv_op_count[DM_TEST_OP_COUNT]; -static struct unit_test_state *uts = &global_dm_test_state; static int testdrv_ping(struct udevice *dev, int pingval, int *pingret) { @@ -37,6 +36,8 @@ static const struct test_ops test_ops = { static int test_bind(struct udevice *dev) { + struct unit_test_state *uts = test_get_state(); + /* Private data should not be allocated */ ut_assert(!dev_get_priv(dev)); @@ -46,6 +47,7 @@ static int test_bind(struct udevice *dev) static int test_probe(struct udevice *dev) { + struct unit_test_state *uts = test_get_state(); struct dm_test_priv *priv = dev_get_priv(dev); /* Private data should be allocated */ @@ -58,6 +60,8 @@ static int test_probe(struct udevice *dev) static int test_remove(struct udevice *dev) { + struct unit_test_state *uts = test_get_state(); + /* Private data should still be allocated */ ut_assert(dev_get_priv(dev)); @@ -67,6 +71,8 @@ static int test_remove(struct udevice *dev) static int test_unbind(struct udevice *dev) { + struct unit_test_state *uts = test_get_state(); + /* Private data should not be allocated */ ut_assert(!dev_get_priv(dev)); @@ -116,6 +122,8 @@ static int test_manual_bind(struct udevice *dev) static int test_manual_probe(struct udevice *dev) { + struct unit_test_state *uts = test_get_state(); + dm_testdrv_op_count[DM_TEST_OP_PROBE]++; if (!uts->force_fail_alloc) dev_set_priv(dev, calloc(1, sizeof(struct dm_test_priv))); diff --git a/test/dm/test-uclass.c b/test/dm/test-uclass.c index f4b540c9278..067701734a0 100644 --- a/test/dm/test-uclass.c +++ b/test/dm/test-uclass.c @@ -17,8 +17,6 @@ #include #include -static struct unit_test_state *uts = &global_dm_test_state; - int test_ping(struct udevice *dev, int pingval, int *pingret) { const struct test_ops *ops = device_get_ops(dev); @@ -31,6 +29,7 @@ int test_ping(struct udevice *dev, int pingval, int *pingret) static int test_post_bind(struct udevice *dev) { + struct unit_test_state *uts = test_get_state(); struct dm_test_perdev_uc_pdata *uc_pdata; dm_testdrv_op_count[DM_TEST_OP_POST_BIND]++; @@ -56,6 +55,7 @@ static int test_pre_unbind(struct udevice *dev) static int test_pre_probe(struct udevice *dev) { struct dm_test_uclass_perdev_priv *priv = dev_get_uclass_priv(dev); + struct unit_test_state *uts = test_get_state(); dm_testdrv_op_count[DM_TEST_OP_PRE_PROBE]++; ut_assert(priv); @@ -66,6 +66,7 @@ static int test_pre_probe(struct udevice *dev) static int test_post_probe(struct udevice *dev) { + struct unit_test_state *uts = test_get_state(); struct udevice *prev = list_entry(dev->uclass_node.prev, struct udevice, uclass_node); @@ -100,6 +101,8 @@ static int test_pre_remove(struct udevice *dev) static int test_init(struct uclass *uc) { + struct unit_test_state *uts = test_get_state(); + dm_testdrv_op_count[DM_TEST_OP_INIT]++; ut_assert(uclass_get_priv(uc)); diff --git a/test/test-main.c b/test/test-main.c index 4e17c9edb28..139fc1f6f18 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -16,6 +16,19 @@ DECLARE_GLOBAL_DATA_PTR; +/* This is valid when a test is running, NULL otherwise */ +static struct unit_test_state *cur_test_state; + +struct unit_test_state *test_get_state(void) +{ + return cur_test_state; +} + +void test_set_state(struct unit_test_state *uts) +{ + cur_test_state = uts; +} + /** * dm_test_pre_run() - Get ready to run a driver model test * @@ -180,6 +193,9 @@ static int ut_run_test(struct unit_test_state *uts, struct unit_test *test, note = " (flat tree)"; printf("Test: %s: %s%s\n", test_name, fname, note); + /* Allow access to test state from drivers */ + test_set_state(uts); + ret = test_pre_run(uts, test); if (ret == -EAGAIN) return -EAGAIN; @@ -192,6 +208,8 @@ static int ut_run_test(struct unit_test_state *uts, struct unit_test *test, if (ret) return ret; + test_set_state( NULL); + return 0; } -- cgit v1.3.1 From f97f85e6618667c877b90e938d6bf36d56e69270 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:35:05 -0700 Subject: test: Run driver-model tests using ut_run_list() Use this function instead of implementing it separately for driver model. Make ut_run_tests() private since it is only used in test-main.c Signed-off-by: Simon Glass --- include/test/ut.h | 42 --------------------------- test/dm/test-dm.c | 45 ++++------------------------ test/test-main.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 81 insertions(+), 93 deletions(-) (limited to 'include') diff --git a/include/test/ut.h b/include/test/ut.h index bed0e6eb5f6..fbbba286ee0 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -381,48 +381,6 @@ struct unit_test_state *test_get_state(void); */ void test_set_state(struct unit_test_state *uts); -/** - * ut_run_test_live_flat() - Run a test with both live and flat tree - * - * This calls ut_run_test() with livetree enabled, which is the standard setup - * for runnig tests. Then, for driver model test, it calls it again with - * livetree disabled. This allows checking of flattree being used when OF_LIVE - * is enabled, as is the case in U-Boot proper before relocation, as well as in - * SPL. - * - * @uts: Test state to update. The caller should ensure that this is zeroed for - * the first call to this function. On exit, @uts->fail_count is - * incremented by the number of failures (0, one hopes) - * @test: Test to run - * @name: Name of test, possibly skipping a prefix that should not be displayed - * @return 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if - * any failed - */ -int ut_run_test_live_flat(struct unit_test_state *uts, struct unit_test *test, - const char *name); - -/** - * ut_run_tests() - Run a set of tests - * - * This runs the tests, handling any preparation and clean-up needed. It prints - * the name of each test before running it. - * - * @uts: Test state to update. The caller should ensure that this is zeroed for - * the first call to this function. On exit, @uts->fail_count is - * incremented by the number of failures (0, one hopes) - * @prefix: String prefix for the tests. Any tests that have this prefix will be - * printed without the prefix, so that it is easier to see the unique part - * of the test name. If NULL, no prefix processing is done - * @tests: List of tests to run - * @count: Number of tests to run - * @select_name: Name of a single test to run (from the list provided). If NULL - * then all tests are run - * @return 0 if all tests passed, -ENOENT if test @select_name was not found, - * -EBADF if any failed - */ -int ut_run_tests(struct unit_test_state *uts, const char *prefix, - struct unit_test *tests, int count, const char *select_name); - /** * ut_run_tests() - Run a set of tests * diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index cdaf27bf987..20af1c13b3c 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -20,31 +20,14 @@ DECLARE_GLOBAL_DATA_PTR; -static bool test_matches(const char *test_name, const char *find_name) -{ - if (!find_name) - return true; - - if (!strcmp(test_name, find_name)) - return true; - - /* All tests have this prefix */ - if (!strncmp(test_name, "dm_test_", 8)) - test_name += 8; - - if (!strcmp(test_name, find_name)) - return true; - - return false; -} +struct unit_test_state global_dm_test_state; int dm_test_run(const char *test_name) { struct unit_test *tests = ll_entry_start(struct unit_test, dm_test); const int n_ents = ll_entry_count(struct unit_test, dm_test); struct unit_test_state uts_s = { .fail_count = 0 }, *uts = &uts_s; - struct unit_test *test; - int found; + struct device_node *of_root; uts->fail_count = 0; @@ -60,29 +43,11 @@ int dm_test_run(const char *test_name) } } - if (!test_name) - printf("Running %d driver model tests\n", n_ents); - else - - found = 0; - uts->of_root = gd_of_root(); - for (test = tests; test < tests + n_ents; test++) { - const char *name = test->name; - - if (!test_matches(name, test_name)) - continue; - - ut_assertok(ut_run_test_live_flat(uts, test, test->name)); - found++; - } - - if (test_name && !found) - printf("Test '%s' not found\n", test_name); - else - printf("Failures: %d\n", uts->fail_count); + of_root = gd_of_root(); + ut_run_list("driver model", "dm_test_", tests, n_ents, test_name); /* Put everything back to normal so that sandbox works as expected */ - gd_set_of_root(uts->of_root); + gd_set_of_root(of_root); gd->dm_root = NULL; ut_assertok(dm_init(CONFIG_IS_ENABLED(OF_LIVE))); dm_scan_plat(false); diff --git a/test/test-main.c b/test/test-main.c index 139fc1f6f18..16c0d13ea55 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -111,6 +111,38 @@ static bool ut_test_run_on_flattree(struct unit_test *test) return !strstr(fname, "video") || strstr(test->name, "video_base"); } +/** + * test_matches() - Check if a test should be run + * + * This checks if the a test should be run. In the normal case of running all + * tests, @select_name is NULL. + * + * @prefix: String prefix for the tests. Any tests that have this prefix will be + * printed without the prefix, so that it is easier to see the unique part + * of the test name. If NULL, no prefix processing is done + * @test_name: Name of current test + * @select_name: Name of test to run (or NULL for all) + * @return true to run this test, false to skip it + */ +static bool test_matches(const char *prefix, const char *test_name, + const char *select_name) +{ + if (!select_name) + return true; + + if (!strcmp(test_name, select_name)) + return true; + + /* All tests have this prefix */ + if (prefix && !strncmp(test_name, prefix, strlen(prefix))) + test_name += strlen(prefix); + + if (!strcmp(test_name, select_name)) + return true; + + return false; +} + /** * test_pre_run() - Handle any preparation needed to run a test * @@ -213,8 +245,25 @@ static int ut_run_test(struct unit_test_state *uts, struct unit_test *test, return 0; } -int ut_run_test_live_flat(struct unit_test_state *uts, struct unit_test *test, - const char *name) +/** + * ut_run_test_live_flat() - Run a test with both live and flat tree + * + * This calls ut_run_test() with livetree enabled, which is the standard setup + * for runnig tests. Then, for driver model test, it calls it again with + * livetree disabled. This allows checking of flattree being used when OF_LIVE + * is enabled, as is the case in U-Boot proper before relocation, as well as in + * SPL. + * + * @uts: Test state to update. The caller should ensure that this is zeroed for + * the first call to this function. On exit, @uts->fail_count is + * incremented by the number of failures (0, one hopes) + * @test: Test to run + * @name: Name of test, possibly skipping a prefix that should not be displayed + * @return 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if + * any failed + */ +static int ut_run_test_live_flat(struct unit_test_state *uts, + struct unit_test *test, const char *name) { int runs; @@ -242,24 +291,39 @@ int ut_run_test_live_flat(struct unit_test_state *uts, struct unit_test *test, return 0; } -int ut_run_tests(struct unit_test_state *uts, const char *prefix, - struct unit_test *tests, int count, const char *select_name) +/** + * ut_run_tests() - Run a set of tests + * + * This runs the tests, handling any preparation and clean-up needed. It prints + * the name of each test before running it. + * + * @uts: Test state to update. The caller should ensure that this is zeroed for + * the first call to this function. On exit, @uts->fail_count is + * incremented by the number of failures (0, one hopes) + * @prefix: String prefix for the tests. Any tests that have this prefix will be + * printed without the prefix, so that it is easier to see the unique part + * of the test name. If NULL, no prefix processing is done + * @tests: List of tests to run + * @count: Number of tests to run + * @select_name: Name of a single test to run (from the list provided). If NULL + * then all tests are run + * @return 0 if all tests passed, -ENOENT if test @select_name was not found, + * -EBADF if any failed + */ +static int ut_run_tests(struct unit_test_state *uts, const char *prefix, + struct unit_test *tests, int count, + const char *select_name) { struct unit_test *test; - int prefix_len = prefix ? strlen(prefix) : 0; int found = 0; for (test = tests; test < tests + count; test++) { const char *test_name = test->name; int ret; - /* Remove the prefix */ - if (prefix && !strncmp(test_name, prefix, prefix_len)) - test_name += prefix_len; - - if (select_name && strcmp(select_name, test_name)) + if (!test_matches(prefix, test_name, select_name)) continue; - ret = ut_run_test_live_flat(uts, test, test_name); + ret = ut_run_test_live_flat(uts, test, select_name); found++; if (ret == -EAGAIN) continue; @@ -281,6 +345,7 @@ int ut_run_list(const char *category, const char *prefix, if (!select_name) printf("Running %d %s tests\n", count, category); + uts.of_root = gd_of_root(); ret = ut_run_tests(&uts, prefix, tests, count, select_name); if (ret == -ENOENT) -- cgit v1.3.1 From a7a98755b888254cbc1857c567ce898a8e105e0f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:35:10 -0700 Subject: test: Add a macros for finding tests in linker_lists At present we use the linker list directly. This is not very friendly, so add a helpful macro instead. This will also allow us to change the naming later without updating this code. Signed-off-by: Simon Glass --- include/test/test.h | 6 ++++++ test/bloblist.c | 5 ++--- test/bootm.c | 4 ++-- test/cmd/mem.c | 4 ++-- test/cmd/setexpr.c | 5 ++--- test/compression.c | 5 ++--- test/dm/test-dm.c | 4 ++-- test/env/cmd_ut_env.c | 4 ++-- test/lib/cmd_ut_lib.c | 4 ++-- test/log/log_ut.c | 4 ++-- test/optee/cmd_ut_optee.c | 5 ++--- test/overlay/cmd_ut_overlay.c | 5 ++--- test/str_ut.c | 5 ++--- test/unicode_ut.c | 4 ++-- 14 files changed, 32 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/include/test/test.h b/include/test/test.h index 5eeec35f525..b16c9135f2c 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -93,6 +93,12 @@ struct unit_test { .func = _name, \ } +/* Get the start of a list of unit tests for a particular category */ +#define UNIT_TEST_SUITE_START(_suite) \ + ll_entry_start(struct unit_test, _suite) +#define UNIT_TEST_SUITE_COUNT(_suite) \ + ll_entry_count(struct unit_test, _suite) + /* Sizes for devres tests */ enum { TEST_DEVRES_SIZE = 100, diff --git a/test/bloblist.c b/test/bloblist.c index 6953d3010a6..d876b639184 100644 --- a/test/bloblist.c +++ b/test/bloblist.c @@ -387,9 +387,8 @@ BLOBLIST_TEST(bloblist_test_reloc, 0); int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, - bloblist_test); - const int n_ents = ll_entry_count(struct unit_test, bloblist_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(bloblist_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(bloblist_test); return cmd_ut_category("bloblist", "bloblist_test_", tests, n_ents, argc, argv); diff --git a/test/bootm.c b/test/bootm.c index 563d6ebaa5a..8528982ae11 100644 --- a/test/bootm.c +++ b/test/bootm.c @@ -240,8 +240,8 @@ BOOTM_TEST(bootm_test_subst_both, 0); int do_ut_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, bootm_test); - const int n_ents = ll_entry_count(struct unit_test, bootm_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(bootm_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(bootm_test); return cmd_ut_category("bootm", "bootm_test_", tests, n_ents, argc, argv); diff --git a/test/cmd/mem.c b/test/cmd/mem.c index fbaa8a4b3cf..d76f47cf311 100644 --- a/test/cmd/mem.c +++ b/test/cmd/mem.c @@ -12,8 +12,8 @@ int do_ut_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, mem_test); - const int n_ents = ll_entry_count(struct unit_test, mem_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(mem_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(mem_test); return cmd_ut_category("cmd_mem", "mem_test_", tests, n_ents, argc, argv); diff --git a/test/cmd/setexpr.c b/test/cmd/setexpr.c index b483069ff0f..27113c083c5 100644 --- a/test/cmd/setexpr.c +++ b/test/cmd/setexpr.c @@ -390,9 +390,8 @@ SETEXPR_TEST(setexpr_test_str_long, UT_TESTF_CONSOLE_REC); int do_ut_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, - setexpr_test); - const int n_ents = ll_entry_count(struct unit_test, setexpr_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(setexpr_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(setexpr_test); return cmd_ut_category("cmd_setexpr", "setexpr_test_", tests, n_ents, argc, argv); diff --git a/test/compression.c b/test/compression.c index a2a4b9ff9e8..4cd1be564f3 100644 --- a/test/compression.c +++ b/test/compression.c @@ -539,9 +539,8 @@ COMPRESSION_TEST(compression_test_bootm_none, 0); int do_ut_compression(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, - compression_test); - const int n_ents = ll_entry_count(struct unit_test, compression_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(compression_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(compression_test); return cmd_ut_category("compression", "compression_test_", tests, n_ents, argc, argv); diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index cb4f99537df..729becf57b2 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -22,8 +22,8 @@ DECLARE_GLOBAL_DATA_PTR; int dm_test_run(const char *test_name) { - struct unit_test *tests = ll_entry_start(struct unit_test, dm_test); - const int n_ents = ll_entry_count(struct unit_test, dm_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(dm_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(dm_test); int ret; ret = ut_run_list("driver model", "dm_test_", tests, n_ents, test_name); diff --git a/test/env/cmd_ut_env.c b/test/env/cmd_ut_env.c index a440b1bfb0e..d65a32179ce 100644 --- a/test/env/cmd_ut_env.c +++ b/test/env/cmd_ut_env.c @@ -12,8 +12,8 @@ int do_ut_env(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, env_test); - const int n_ents = ll_entry_count(struct unit_test, env_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(env_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(env_test); return cmd_ut_category("environment", "env_test_", tests, n_ents, argc, argv); diff --git a/test/lib/cmd_ut_lib.c b/test/lib/cmd_ut_lib.c index f5c7bf3d3b0..f1ac015b2c8 100644 --- a/test/lib/cmd_ut_lib.c +++ b/test/lib/cmd_ut_lib.c @@ -13,8 +13,8 @@ int do_ut_lib(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, lib_test); - const int n_ents = ll_entry_count(struct unit_test, lib_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(lib_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(lib_test); return cmd_ut_category("lib", "lib_test_", tests, n_ents, argc, argv); } diff --git a/test/log/log_ut.c b/test/log/log_ut.c index c534add493e..5aa3a184004 100644 --- a/test/log/log_ut.c +++ b/test/log/log_ut.c @@ -13,8 +13,8 @@ int do_ut_log(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, log_test); - const int n_ents = ll_entry_count(struct unit_test, log_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(log_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(log_test); return cmd_ut_category("log", "log_test_", tests, n_ents, argc, argv); diff --git a/test/optee/cmd_ut_optee.c b/test/optee/cmd_ut_optee.c index 9fa4c91e0dd..c3887ab11d9 100644 --- a/test/optee/cmd_ut_optee.c +++ b/test/optee/cmd_ut_optee.c @@ -94,9 +94,8 @@ OPTEE_TEST(optee_fdt_protected_memory, 0); int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, - optee_test); - const int n_ents = ll_entry_count(struct unit_test, optee_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(optee_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(optee_test); struct unit_test_state *uts; void *fdt_optee = &__dtb_test_optee_optee_begin; void *fdt_no_optee = &__dtb_test_optee_no_optee_begin; diff --git a/test/overlay/cmd_ut_overlay.c b/test/overlay/cmd_ut_overlay.c index c001fb183fe..56a3df17138 100644 --- a/test/overlay/cmd_ut_overlay.c +++ b/test/overlay/cmd_ut_overlay.c @@ -213,9 +213,8 @@ OVERLAY_TEST(fdt_overlay_stacked, 0); int do_ut_overlay(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, - overlay_test); - const int n_ents = ll_entry_count(struct unit_test, overlay_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(overlay_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(overlay_test); struct unit_test_state *uts; void *fdt_base = &__dtb_test_fdt_base_begin; void *fdt_overlay = &__dtb_test_fdt_overlay_begin; diff --git a/test/str_ut.c b/test/str_ut.c index cd5045516d1..359d7d4ea1f 100644 --- a/test/str_ut.c +++ b/test/str_ut.c @@ -107,9 +107,8 @@ STR_TEST(str_simple_strtoul, 0); int do_ut_str(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, - str_test); - const int n_ents = ll_entry_count(struct unit_test, str_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(str_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(str_test); return cmd_ut_category("str", "str_", tests, n_ents, argc, argv); } diff --git a/test/unicode_ut.c b/test/unicode_ut.c index 6130ef0b549..7b9c020eff9 100644 --- a/test/unicode_ut.c +++ b/test/unicode_ut.c @@ -615,8 +615,8 @@ UNICODE_TEST(unicode_test_efi_create_indexed_name); int do_ut_unicode(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct unit_test *tests = ll_entry_start(struct unit_test, unicode_test); - const int n_ents = ll_entry_count(struct unit_test, unicode_test); + struct unit_test *tests = UNIT_TEST_SUITE_START(unicode_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(unicode_test); return cmd_ut_category("Unicode", "unicode_test_", tests, n_ents, argc, argv); -- cgit v1.3.1 From 2a2814d5f2714a7b0aef9ea7f9d8d67a34875d55 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:35:11 -0700 Subject: test: Rename all linker lists to have a ut_ prefix At present each test suite has its own portion of the linker_list section of the image, but other lists are interspersed. This makes it hard to enumerate all the available tests without knowing the suites that each one is in. Place all tests together in a single contiguous list by giving them common prefix not used elsewhere in U-Boot. This makes it possible to find the start and end of all tests. Signed-off-by: Simon Glass --- include/test/test.h | 8 ++++---- test/py/conftest.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/test/test.h b/include/test/test.h index b16c9135f2c..3330dcc72d3 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -86,18 +86,18 @@ struct unit_test { * @_suite: name of the test suite concatenated with "_test" */ #define UNIT_TEST(_name, _flags, _suite) \ - ll_entry_declare(struct unit_test, _name, _suite) = { \ + ll_entry_declare(struct unit_test, _name, ut_ ## _suite) = { \ .file = __FILE__, \ .name = #_name, \ .flags = _flags, \ .func = _name, \ } -/* Get the start of a list of unit tests for a particular category */ +/* Get the start of a list of unit tests for a particular suite */ #define UNIT_TEST_SUITE_START(_suite) \ - ll_entry_start(struct unit_test, _suite) + ll_entry_start(struct unit_test, ut_ ## _suite) #define UNIT_TEST_SUITE_COUNT(_suite) \ - ll_entry_count(struct unit_test, _suite) + ll_entry_count(struct unit_test, ut_ ## _suite) /* Sizes for devres tests */ enum { diff --git a/test/py/conftest.py b/test/py/conftest.py index 9bfd9263455..1b909cde9d3 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -226,7 +226,7 @@ def pytest_configure(config): import u_boot_console_exec_attach console = u_boot_console_exec_attach.ConsoleExecAttach(log, ubconfig) -re_ut_test_list = re.compile(r'_u_boot_list_2_(.*)_test_2_\1_test_(.*)\s*$') +re_ut_test_list = re.compile(r'_u_boot_list_2_ut_(.*)_test_2_\1_test_(.*)\s*$') def generate_ut_subtest(metafunc, fixture_name, sym_path): """Provide parametrization for a ut_subtest fixture. -- cgit v1.3.1 From 8482356f48c96eb49f1bd9efd53c887d09a1cf64 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:35:12 -0700 Subject: test: Allow SPL to run any available test At present SPL only runs driver model tests. Update it to run all available tests, i.e. in any test suite. Signed-off-by: Simon Glass --- arch/sandbox/cpu/spl.c | 7 +++++-- include/test/test.h | 16 +++++----------- test/dm/test-dm.c | 11 ++++++++++- test/test-main.c | 17 +++++++++++++---- 4 files changed, 33 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index 3779d58c3fe..ce5aae87fb6 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include DECLARE_GLOBAL_DATA_PTR; @@ -63,9 +63,12 @@ void spl_board_init(void) preloader_console_init(); if (state->run_unittests) { + struct unit_test *tests = UNIT_TEST_ALL_START(); + const int count = UNIT_TEST_ALL_COUNT(); int ret; - ret = dm_test_run(state->select_unittests); + ret = ut_run_list("spl", NULL, tests, count, + state->select_unittests); /* continue execution into U-Boot */ } } diff --git a/include/test/test.h b/include/test/test.h index 3330dcc72d3..0b124edd601 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -99,6 +99,11 @@ struct unit_test { #define UNIT_TEST_SUITE_COUNT(_suite) \ ll_entry_count(struct unit_test, ut_ ## _suite) +/* Use ! and ~ so that all tests will be sorted between these two values */ +#define UNIT_TEST_ALL_START() ll_entry_start(struct unit_test, ut_!) +#define UNIT_TEST_ALL_END() ll_entry_start(struct unit_test, ut_~) +#define UNIT_TEST_ALL_COUNT() (UNIT_TEST_ALL_END() - UNIT_TEST_ALL_START()) + /* Sizes for devres tests */ enum { TEST_DEVRES_SIZE = 100, @@ -119,15 +124,4 @@ enum { */ struct udevice *testbus_get_clear_removed(void); -/** - * dm_test_run() - Run driver model tests - * - * Run all the available driver model tests, or a selection - * - * @test_name: Name of single test to run (e.g. "dm_test_fdt_pre_reloc" or just - * "fdt_pre_reloc"), or NULL to run all - * @return 0 if all tests passed, 1 if not - */ -int dm_test_run(const char *test_name); - #endif /* __TEST_TEST_H */ diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index 729becf57b2..9ba2ba23d5d 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -20,7 +20,16 @@ DECLARE_GLOBAL_DATA_PTR; -int dm_test_run(const char *test_name) +/** + * dm_test_run() - Run driver model tests + * + * Run all the available driver model tests, or a selection + * + * @test_name: Name of single test to run (e.g. "dm_test_fdt_pre_reloc" or just + * "fdt_pre_reloc"), or NULL to run all + * @return 0 if all tests passed, 1 if not + */ +static int dm_test_run(const char *test_name) { struct unit_test *tests = UNIT_TEST_SUITE_START(dm_test); const int n_ents = UNIT_TEST_SUITE_COUNT(dm_test); diff --git a/test/test-main.c b/test/test-main.c index 6edd49f0b61..e1b49e091ab 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -119,7 +119,8 @@ static bool ut_test_run_on_flattree(struct unit_test *test) * * @prefix: String prefix for the tests. Any tests that have this prefix will be * printed without the prefix, so that it is easier to see the unique part - * of the test name. If NULL, no prefix processing is done + * of the test name. If NULL, any suite name (xxx_test) is considered to be + * a prefix. * @test_name: Name of current test * @select_name: Name of test to run (or NULL for all) * @return true to run this test, false to skip it @@ -133,9 +134,17 @@ static bool test_matches(const char *prefix, const char *test_name, if (!strcmp(test_name, select_name)) return true; - /* All tests have this prefix */ - if (prefix && !strncmp(test_name, prefix, strlen(prefix))) - test_name += strlen(prefix); + if (!prefix) { + const char *p = strstr(test_name, "_test_"); + + /* convert xxx_test_yyy to yyy, i.e. remove the suite name */ + if (p) + test_name = p + 6; + } else { + /* All tests have this prefix */ + if (!strncmp(test_name, prefix, strlen(prefix))) + test_name += strlen(prefix); + } if (!strcmp(test_name, select_name)) return true; -- cgit v1.3.1 From 01ad9f75c5ccbf2dbb30f8c630fad7e648026449 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:35:13 -0700 Subject: sandbox: Update os_find_u_boot() to find the .img file At present this function can only locate the u-boot ELF file. For SPL it is handy to be able to locate u-boot.img since this is what would normally be loaded by SPL. Add another argument to allow this to be selected. While we are here, update the function to load SPL when running in TPL, since that is the next stage. Signed-off-by: Simon Glass --- arch/sandbox/cpu/os.c | 8 +++++--- arch/sandbox/cpu/spl.c | 2 +- include/os.h | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index f5000e64966..2d9583c17ca 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -777,7 +777,7 @@ int os_jump_to_image(const void *dest, int size) return os_jump_to_file(fname); } -int os_find_u_boot(char *fname, int maxlen) +int os_find_u_boot(char *fname, int maxlen, bool use_img) { struct sandbox_state *state = state_get_current(); const char *progname = state->argv[0]; @@ -801,8 +801,8 @@ int os_find_u_boot(char *fname, int maxlen) return 0; } - /* Look for 'u-boot-tpl' in the tpl/ directory */ - p = strstr(fname, "/tpl/"); + /* Look for 'u-boot-spl' in the spl/ directory */ + p = strstr(fname, "/spl/"); if (p) { p[1] = 's'; fd = os_open(fname, O_RDONLY); @@ -829,6 +829,8 @@ int os_find_u_boot(char *fname, int maxlen) if (p) { /* Remove the "spl" characters */ memmove(p, p + 4, strlen(p + 4) + 1); + if (use_img) + strcat(p, ".img"); fd = os_open(fname, O_RDONLY); if (fd >= 0) { close(fd); diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index ce5aae87fb6..f82b0d3de16 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -37,7 +37,7 @@ static int spl_board_load_image(struct spl_image_info *spl_image, char fname[256]; int ret; - ret = os_find_u_boot(fname, sizeof(fname)); + ret = os_find_u_boot(fname, sizeof(fname), false); if (ret) { printf("(%s not found, error %d)\n", fname, ret); return ret; diff --git a/include/os.h b/include/os.h index d2a4afeca0f..77d8bd89d0f 100644 --- a/include/os.h +++ b/include/os.h @@ -324,9 +324,10 @@ int os_jump_to_image(const void *dest, int size); * * @fname: place to put full path to U-Boot * @maxlen: maximum size of @fname + * @use_img: select the 'u-boot.img' file instead of the 'u-boot' ELF file * Return: 0 if OK, -NOSPC if the filename is too large, -ENOENT if not found */ -int os_find_u_boot(char *fname, int maxlen); +int os_find_u_boot(char *fname, int maxlen, bool use_img); /** * os_spl_to_uboot() - Run U-Boot proper -- cgit v1.3.1 From 2e059e4a6ea075431942c51a48c682119b76bed2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Mar 2021 17:35:15 -0700 Subject: spl: test: Add a test for spl_load_simple_fit() As an example of an SPL test, add a new test for loading a FIT within SPL. This runs on sandbox_spl. For this to work, the text base is adjusted so that there is plenty of space available. While we are here, document struct spl_load_info properly, since this is currently ambiguous. This test only verifies the logic path. It does not actually check that the image is loaded correctly. It is not possible for sandbox's SPL to actually run u-boot.img since it currently includes u-boot.bin rather than u-boot. Further work could expand the test in that direction. The need for this was noted at: http://patchwork.ozlabs.org/project/uboot/patch/20201216000944.2832585-3-mr.nuke.me@gmail.com/ Signed-off-by: Simon Glass --- configs/sandbox_spl_defconfig | 2 +- doc/arch/sandbox.rst | 4 +- include/spl.h | 9 +++++ test/Makefile | 1 + test/image/Makefile | 5 +++ test/image/spl_load.c | 91 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 test/image/Makefile create mode 100644 test/image/spl_load.c (limited to 'include') diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index c0118702a81..2696d0b6cdd 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -1,4 +1,4 @@ -CONFIG_SYS_TEXT_BASE=0 +CONFIG_SYS_TEXT_BASE=0x200000 CONFIG_SPL_LIBCOMMON_SUPPORT=y CONFIG_SPL_LIBGENERIC_SUPPORT=y CONFIG_NR_DRAM_BANKS=1 diff --git a/doc/arch/sandbox.rst b/doc/arch/sandbox.rst index 60ee1e0741a..1ccb5344ac6 100644 --- a/doc/arch/sandbox.rst +++ b/doc/arch/sandbox.rst @@ -537,5 +537,7 @@ Addr Config Usage e000 CONFIG_BLOBLIST_ADDR Blob list 10000 CONFIG_MALLOC_F_ADDR Early memory allocation f0000 CONFIG_PRE_CON_BUF_ADDR Pre-console buffer - 100000 CONFIG_TRACE_EARLY_ADDR Early trace buffer (if enabled) + 100000 CONFIG_TRACE_EARLY_ADDR Early trace buffer (if enabled). Also used + as the SPL load buffer in spl_test_load(). + 200000 CONFIG_SYS_TEXT_BASE Load buffer for U-Boot (sandbox_spl only) ======= ======================== =============================== diff --git a/include/spl.h b/include/spl.h index 0d134587de2..4f6e0e53f5d 100644 --- a/include/spl.h +++ b/include/spl.h @@ -222,6 +222,15 @@ struct spl_load_info { void *priv; int bl_len; const char *filename; + /** + * read() - Read from device + * + * @load: Information about the load state + * @sector: Sector number to read from (each @load->bl_len bytes) + * @count: Number of sectors to read + * @buf: Buffer to read into + * @return number of sectors read, 0 on error + */ ulong (*read)(struct spl_load_info *load, ulong sector, ulong count, void *buf); }; diff --git a/test/Makefile b/test/Makefile index 5cd284e322e..a26e915e050 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,6 +3,7 @@ # (C) Copyright 2012 The Chromium Authors obj-y += test-main.o +obj-$(CONFIG_SANDBOX) += image/ ifneq ($(CONFIG_$(SPL_)BLOBLIST),) obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o diff --git a/test/image/Makefile b/test/image/Makefile new file mode 100644 index 00000000000..c4039df707f --- /dev/null +++ b/test/image/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2021 Google LLC + +obj-$(CONFIG_SPL_BUILD) += spl_load.o diff --git a/test/image/spl_load.c b/test/image/spl_load.c new file mode 100644 index 00000000000..851603ddd75 --- /dev/null +++ b/test/image/spl_load.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include + +/* Declare a new SPL test */ +#define SPL_TEST(_name, _flags) UNIT_TEST(_name, _flags, spl_test) + +/* Context used for this test */ +struct text_ctx { + int fd; +}; + +static ulong read_fit_image(struct spl_load_info *load, ulong sector, + ulong count, void *buf) +{ + struct text_ctx *text_ctx = load->priv; + off_t offset, ret; + ssize_t res; + + offset = sector * load->bl_len; + ret = os_lseek(text_ctx->fd, offset, OS_SEEK_SET); + if (ret != offset) { + printf("Failed to seek to %zx, got %zx (errno=%d)\n", offset, + ret, errno); + return 0; + } + + res = os_read(text_ctx->fd, buf, count * load->bl_len); + if (res == -1) { + printf("Failed to read %lx bytes, got %ld (errno=%d)\n", + count * load->bl_len, res, errno); + return 0; + } + + return count; +} + +int board_fit_config_name_match(const char *name) +{ + return 0; +} + +struct image_header *spl_get_load_buffer(ssize_t offset, size_t size) +{ + return map_sysmem(0x100000, 0); +} + +static int spl_test_load(struct unit_test_state *uts) +{ + struct spl_image_info image; + struct image_header *header; + struct text_ctx text_ctx; + struct spl_load_info load; + char fname[256]; + int ret; + int fd; + + memset(&load, '\0', sizeof(load)); + load.bl_len = 512; + load.read = read_fit_image; + + ret = os_find_u_boot(fname, sizeof(fname), true); + if (ret) { + printf("(%s not found, error %d)\n", fname, ret); + return ret; + } + load.filename = fname; + + header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); + + fd = os_open(fname, OS_O_RDONLY); + ut_assert(fd >= 0); + ut_asserteq(512, os_read(fd, header, 512)); + text_ctx.fd = fd; + + load.priv = &text_ctx; + + ut_assertok(spl_load_simple_fit(&image, &load, 0, header)); + + return 0; +} +SPL_TEST(spl_test_load, 0); -- cgit v1.3.1 From 79d5983b61e41d5c586489b03e75a75961d31041 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 20 Jan 2021 20:10:52 -0700 Subject: log: Set up a flag byte for log records At present only a single flag (force_debug) is used in log records. Before adding more, convert this into a bitfield, so more can be added without using more space. To avoid expanding the log_record struct itself (which some drivers may wish to store in memory) reduce the line-number field to 16 bits. This provides for up to 64K lines which should be enough for anyone. Signed-off-by: Simon Glass --- common/log.c | 9 ++++++--- include/log.h | 14 ++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/common/log.c b/common/log.c index 6b0034c3ba2..f87e33a9ca1 100644 --- a/common/log.c +++ b/common/log.c @@ -153,7 +153,7 @@ static bool log_passes_filters(struct log_device *ldev, struct log_rec *rec) { struct log_filter *filt; - if (rec->force_debug) + if (rec->flags & LOGRECF_FORCE_DEBUG) return true; /* If there are no filters, filter on the default log level */ @@ -245,7 +245,9 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, rec.cat = cat; rec.level = level & LOGL_LEVEL_MASK; - rec.force_debug = level & LOGL_FORCE_DEBUG; + rec.flags = 0; + if (level & LOGL_FORCE_DEBUG) + rec.flags |= LOGRECF_FORCE_DEBUG; rec.file = file; rec.line = line; rec.func = func; @@ -255,7 +257,8 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, gd->log_drop_count++; /* display dropped traces with console puts and DEBUG_UART */ - if (rec.level <= CONFIG_LOG_DEFAULT_LEVEL || rec.force_debug) { + if (rec.level <= CONFIG_LOG_DEFAULT_LEVEL || + rec.flags & LOGRECF_FORCE_DEBUG) { char buf[CONFIG_SYS_CBSIZE]; va_start(args, fmt); diff --git a/include/log.h b/include/log.h index 2d27f9f657e..da053b0a6e8 100644 --- a/include/log.h +++ b/include/log.h @@ -322,6 +322,12 @@ void __assert_fail(const char *assertion, const char *file, unsigned int line, #define log_msg_ret(_msg, _ret) ((void)(_msg), _ret) #endif +/** * enum log_rec_flags - Flags for a log record */ +enum log_rec_flags { + /** @LOGRECF_FORCE_DEBUG: Force output of debug record */ + LOGRECF_FORCE_DEBUG = BIT(0), +}; + /** * struct log_rec - a single log record * @@ -337,18 +343,18 @@ void __assert_fail(const char *assertion, const char *file, unsigned int line, * * @cat: Category, representing a uclass or part of U-Boot * @level: Severity level, less severe is higher - * @force_debug: Force output of debug - * @file: Name of file where the log record was generated (not allocated) * @line: Line number where the log record was generated + * @flags: Flags for log record (enum log_rec_flags) + * @file: Name of file where the log record was generated (not allocated) * @func: Function where the log record was generated (not allocated) * @msg: Log message (allocated) */ struct log_rec { enum log_category_t cat; enum log_level_t level; - bool force_debug; + u16 line; + u8 flags; const char *file; - int line; const char *func; const char *msg; }; -- cgit v1.3.1 From 9ad7a6c25c7142a46fe4b811c13bc3280c4bb27f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 20 Jan 2021 20:10:53 -0700 Subject: log: Handle line continuation When multiple log() calls are used which don't end in newline, the log prefix is prepended multiple times in the same line. This makes the output look strange. Fix this by detecting when the previous log record did not end in newline. In that case, setting a flag. Drop the unused BUFFSIZE in the test while we are here. As an example implementation, update log_console to check the flag and produce the expected output. Signed-off-by: Simon Glass --- common/log.c | 7 ++++++- common/log_console.c | 26 +++++++++++++++----------- doc/develop/logging.rst | 16 ++++++++++++++++ include/asm-generic/global_data.h | 6 ++++++ include/log.h | 2 ++ test/log/cont_test.c | 19 +++++++++++++++---- 6 files changed, 60 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/common/log.c b/common/log.c index f87e33a9ca1..ea407c6db9e 100644 --- a/common/log.c +++ b/common/log.c @@ -218,8 +218,11 @@ static int log_dispatch(struct log_rec *rec, const char *fmt, va_list args) if ((ldev->flags & LOGDF_ENABLE) && log_passes_filters(ldev, rec)) { if (!rec->msg) { - vsnprintf(buf, sizeof(buf), fmt, args); + int len; + + len = vsnprintf(buf, sizeof(buf), fmt, args); rec->msg = buf; + gd->log_cont = len && buf[len - 1] != '\n'; } ldev->drv->emit(ldev, rec); } @@ -248,6 +251,8 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, rec.flags = 0; if (level & LOGL_FORCE_DEBUG) rec.flags |= LOGRECF_FORCE_DEBUG; + if (gd->log_cont) + rec.flags |= LOGRECF_CONT; rec.file = file; rec.line = line; rec.func = func; diff --git a/common/log_console.c b/common/log_console.c index 6abb13c93b8..3f6177499ef 100644 --- a/common/log_console.c +++ b/common/log_console.c @@ -15,6 +15,7 @@ DECLARE_GLOBAL_DATA_PTR; static int log_console_emit(struct log_device *ldev, struct log_rec *rec) { int fmt = gd->log_fmt; + bool add_space = false; /* * The output format is designed to give someone a fighting chance of @@ -26,18 +27,21 @@ static int log_console_emit(struct log_device *ldev, struct log_rec *rec) * - function is an identifier and ends with () * - message has a space before it unless it is on its own */ - if (fmt & BIT(LOGF_LEVEL)) - printf("%s.", log_get_level_name(rec->level)); - if (fmt & BIT(LOGF_CAT)) - printf("%s,", log_get_cat_name(rec->cat)); - if (fmt & BIT(LOGF_FILE)) - printf("%s:", rec->file); - if (fmt & BIT(LOGF_LINE)) - printf("%d-", rec->line); - if (fmt & BIT(LOGF_FUNC)) - printf("%s()", rec->func); + if (!(rec->flags & LOGRECF_CONT) && fmt != BIT(LOGF_MSG)) { + add_space = true; + if (fmt & BIT(LOGF_LEVEL)) + printf("%s.", log_get_level_name(rec->level)); + if (fmt & BIT(LOGF_CAT)) + printf("%s,", log_get_cat_name(rec->cat)); + if (fmt & BIT(LOGF_FILE)) + printf("%s:", rec->file); + if (fmt & BIT(LOGF_LINE)) + printf("%d-", rec->line); + if (fmt & BIT(LOGF_FUNC)) + printf("%s()", rec->func); + } if (fmt & BIT(LOGF_MSG)) - printf("%s%s", fmt != BIT(LOGF_MSG) ? " " : "", rec->msg); + printf("%s%s", add_space ? " " : "", rec->msg); return 0; } diff --git a/doc/develop/logging.rst b/doc/develop/logging.rst index 60c18c5b3a8..622ad6ad1af 100644 --- a/doc/develop/logging.rst +++ b/doc/develop/logging.rst @@ -96,6 +96,22 @@ Also debug() and error() will generate log records - these use LOG_CATEGORY as the category, so you should #define this right at the top of the source file to ensure the category is correct. +Generally each log format_string ends with a newline. If it does not, then the +next log statement will have the LOGRECF_CONT flag set. This can be used to +continue the statement on the same line as the previous one without emitting +new header information (such as category/level). This behaviour is implemented +with log_console. Here is an example that prints a list all on one line with +the tags at the start: + +.. code-block:: c + + log_debug("Here is a list:"); + for (i = 0; i < count; i++) + log_debug(" item %d", i); + log_debug("\n"); + +Also see the special category LOGL_CONT and level LOGC_CONT. + You can also define CONFIG_LOG_ERROR_RETURN to enable the log_ret() macro. This can be used whenever your function returns an error value: diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index b6a9991fc9a..c24f5e0e973 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -410,6 +410,12 @@ struct global_data { * This value is used as logging level for continuation messages. */ int logl_prev; + /** + * @log_cont: Previous log line did not finished wtih \n + * + * This allows for chained log messages on the same line + */ + bool log_cont; #endif #if CONFIG_IS_ENABLED(BLOBLIST) /** diff --git a/include/log.h b/include/log.h index da053b0a6e8..c0453d2f97c 100644 --- a/include/log.h +++ b/include/log.h @@ -326,6 +326,8 @@ void __assert_fail(const char *assertion, const char *file, unsigned int line, enum log_rec_flags { /** @LOGRECF_FORCE_DEBUG: Force output of debug record */ LOGRECF_FORCE_DEBUG = BIT(0), + /** @LOGRECF_CONT: Continuation of previous log record */ + LOGRECF_CONT = BIT(1), }; /** diff --git a/test/log/cont_test.c b/test/log/cont_test.c index 16379a74be6..de7b7f064cd 100644 --- a/test/log/cont_test.c +++ b/test/log/cont_test.c @@ -15,8 +15,6 @@ DECLARE_GLOBAL_DATA_PTR; -#define BUFFSIZE 64 - static int log_test_cont(struct unit_test_state *uts) { int log_fmt; @@ -29,12 +27,13 @@ static int log_test_cont(struct unit_test_state *uts) gd->log_fmt = (1 << LOGF_CAT) | (1 << LOGF_LEVEL) | (1 << LOGF_MSG); gd->default_log_level = LOGL_INFO; console_record_reset_enable(); - log(LOGC_ARCH, LOGL_ERR, "ea%d ", 1); + log(LOGC_ARCH, LOGL_ERR, "ea%d\n", 1); log(LOGC_CONT, LOGL_CONT, "cc%d\n", 2); gd->default_log_level = log_level; gd->log_fmt = log_fmt; gd->flags &= ~GD_FLG_RECORD; - ut_assertok(ut_check_console_line(uts, "ERR.arch, ea1 ERR.arch, cc2")); + ut_assertok(ut_check_console_line(uts, "ERR.arch, ea1")); + ut_assertok(ut_check_console_line(uts, "ERR.arch, cc2")); ut_assertok(ut_check_console_end(uts)); /* Write a third message which is not a continuation */ @@ -48,6 +47,18 @@ static int log_test_cont(struct unit_test_state *uts) ut_assertok(ut_check_console_line(uts, "INFO.efi, ie3")); ut_assertok(ut_check_console_end(uts)); + /* Write two messages without a newline between them */ + gd->log_fmt = (1 << LOGF_CAT) | (1 << LOGF_LEVEL) | (1 << LOGF_MSG); + gd->default_log_level = LOGL_INFO; + console_record_reset_enable(); + log(LOGC_ARCH, LOGL_ERR, "ea%d ", 1); + log(LOGC_CONT, LOGL_CONT, "cc%d\n", 2); + gd->default_log_level = log_level; + gd->log_fmt = log_fmt; + gd->flags &= ~GD_FLG_RECORD; + ut_assertok(ut_check_console_line(uts, "ERR.arch, ea1 cc2")); + ut_assertok(ut_check_console_end(uts)); + return 0; } LOG_TEST(log_test_cont); -- cgit v1.3.1 From 7bd06587decafabb56f68de3ae87adb4c49ca8db Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 20 Jan 2021 20:10:54 -0700 Subject: log: Add return-checking macros for 0 being success The existing log_ret() and log_msg_ret() macros consider an error to be less than zero. But some function may return a positive number to indicate a different kind of failure. Add macros to check for that also. Signed-off-by: Simon Glass --- doc/develop/logging.rst | 15 ++++++++++++++- include/log.h | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/doc/develop/logging.rst b/doc/develop/logging.rst index 622ad6ad1af..f4e925048e8 100644 --- a/doc/develop/logging.rst +++ b/doc/develop/logging.rst @@ -117,11 +117,24 @@ can be used whenever your function returns an error value: .. code-block:: c - return log_ret(uclass_first_device(UCLASS_MMC, &dev)); + return log_ret(uclass_first_device_err(UCLASS_MMC, &dev)); This will write a log record when an error code is detected (a value < 0). This can make it easier to trace errors that are generated deep in the call stack. +The log_msg_ret() variant will print a short string if CONFIG_LOG_ERROR_RETURN +is enabled. So long as the string is unique within the function you can normally +determine exactly which call failed: + +.. code-block:: c + + ret = gpio_request_by_name(dev, "cd-gpios", 0, &desc, GPIOD_IS_IN); + if (ret) + return log_msg_ret("gpio", ret); + +Some functions return 0 for success and any other value is an error. For these, +log_retz() and log_msg_retz() are available. + Convenience functions ~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/log.h b/include/log.h index c0453d2f97c..6ef891d4d2d 100644 --- a/include/log.h +++ b/include/log.h @@ -316,10 +316,30 @@ void __assert_fail(const char *assertion, const char *file, unsigned int line, __ret); \ __ret; \ }) + +/* + * Similar to the above, but any non-zero value is consider an error, not just + * values less than 0. + */ +#define log_retz(_ret) ({ \ + int __ret = (_ret); \ + if (__ret) \ + log(LOG_CATEGORY, LOGL_ERR, "returning err=%d\n", __ret); \ + __ret; \ + }) +#define log_msg_retz(_msg, _ret) ({ \ + int __ret = (_ret); \ + if (__ret) \ + log(LOG_CATEGORY, LOGL_ERR, "%s: returning err=%d\n", _msg, \ + __ret); \ + __ret; \ + }) #else /* Non-logging versions of the above which just return the error code */ #define log_ret(_ret) (_ret) #define log_msg_ret(_msg, _ret) ((void)(_msg), _ret) +#define log_retz(_ret) (_ret) +#define log_msg_retz(_msg, _ret) ((void)(_msg), _ret) #endif /** * enum log_rec_flags - Flags for a log record */ -- cgit v1.3.1 From 166363f2ed9e72ed3e2bf09d9317d6a5fdafcbea Mon Sep 17 00:00:00 2001 From: Jorge Ramirez-Ortiz Date: Sun, 14 Feb 2021 16:27:23 +0100 Subject: common: SCP03 control (enable and provision of keys) This Trusted Application allows enabling SCP03 as well as provisioning the keys on TEE controlled secure element (ie, NXP SE050). All the information flowing on buses (ie I2C) between the processor and the secure element must be encrypted. Secure elements are pre-provisioned with a set of keys known to the user so that the secure channel protocol (encryption) can be enforced on the first boot. This situation is however unsafe since the keys are publically available. For example, in the case of the NXP SE050, these keys would be available in the OP-TEE source tree [2] and of course in the documentation corresponding to the part. To address that, users are required to rotate/provision those keys (ie, generate new keys and write them in the secure element's persistent memory). For information on SCP03, check the Global Platform HomePage and google for that term [1] [1] globalplatform.org [2] https://github.com/OP-TEE/optee_os/ check: core/drivers/crypto/se050/adaptors/utils/scp_config.c Signed-off-by: Jorge Ramirez-Ortiz Reviewed-by: Simon Glass --- common/Kconfig | 8 +++++++ common/Makefile | 1 + common/scp03.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ include/scp03.h | 21 ++++++++++++++++++ include/tee/optee_ta_scp03.h | 21 ++++++++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 common/scp03.c create mode 100644 include/scp03.h create mode 100644 include/tee/optee_ta_scp03.h (limited to 'include') diff --git a/common/Kconfig b/common/Kconfig index 2bb3798f808..482f1235347 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -588,6 +588,14 @@ config AVB_BUF_SIZE endif # AVB_VERIFY +config SCP03 + bool "Build SCP03 - Secure Channel Protocol O3 - controls" + depends on OPTEE || SANDBOX + depends on TEE + help + This option allows U-Boot to enable and or provision SCP03 on an OPTEE + controlled Secured Element. + config SPL_HASH bool # "Support hashing API (SHA1, SHA256, etc.)" help diff --git a/common/Makefile b/common/Makefile index daeea67cf29..215b8b26fdc 100644 --- a/common/Makefile +++ b/common/Makefile @@ -137,3 +137,4 @@ obj-$(CONFIG_CMD_LOADB) += xyzModem.o obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += xyzModem.o obj-$(CONFIG_AVB_VERIFY) += avb_verify.o +obj-$(CONFIG_SCP03) += scp03.o diff --git a/common/scp03.c b/common/scp03.c new file mode 100644 index 00000000000..09ef7b5ba3d --- /dev/null +++ b/common/scp03.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2021, Foundries.IO + * + */ + +#include +#include +#include +#include + +static int scp03_enable(bool provision) +{ + const struct tee_optee_ta_uuid uuid = PTA_SCP03_UUID; + struct tee_open_session_arg session; + struct tee_invoke_arg invoke; + struct tee_param param; + struct udevice *tee = NULL; + + tee = tee_find_device(tee, NULL, NULL, NULL); + if (!tee) + return -ENODEV; + + memset(&session, 0, sizeof(session)); + tee_optee_ta_uuid_to_octets(session.uuid, &uuid); + if (tee_open_session(tee, &session, 0, NULL)) + return -ENXIO; + + memset(¶m, 0, sizeof(param)); + param.attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT; + param.u.value.a = provision; + + memset(&invoke, 0, sizeof(invoke)); + invoke.func = PTA_CMD_ENABLE_SCP03; + invoke.session = session.session; + + if (tee_invoke_func(tee, &invoke, 1, ¶m)) + return -EIO; + + tee_close_session(tee, session.session); + + return 0; +} + +int tee_enable_scp03(void) +{ + return scp03_enable(false); +} + +int tee_provision_scp03(void) +{ + return scp03_enable(true); +} diff --git a/include/scp03.h b/include/scp03.h new file mode 100644 index 00000000000..729667ccd1c --- /dev/null +++ b/include/scp03.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2021, Foundries.IO + * + */ + +#ifndef _SCP03_H +#define _SCP03_H + +/* + * Requests to OPTEE to enable or provision the Secure Channel Protocol on its + * Secure Element + * + * If key provisioning is requested, OPTEE shall generate new SCP03 keys and + * write them to the Secure Element. + * + * Both functions return < 0 on error else 0. + */ +int tee_enable_scp03(void); +int tee_provision_scp03(void); +#endif /* _SCP03_H */ diff --git a/include/tee/optee_ta_scp03.h b/include/tee/optee_ta_scp03.h new file mode 100644 index 00000000000..13f9956d983 --- /dev/null +++ b/include/tee/optee_ta_scp03.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * (C) Copyright 2021, Foundries.IO + * + */ +#ifndef __TA_SCP03_H +#define __TA_SCP03_H + +#define PTA_SCP03_UUID { 0xbe0e5821, 0xe718, 0x4f77, \ + { 0xab, 0x3e, 0x8e, 0x6c, 0x73, 0xa9, 0xc7, 0x35 } } + +/* + * Enable Secure Channel Protocol functionality (SCP03) on the Secure Element. + * Setting the operation value to something different than NULL will trigger + * the SCP03 provisioning request. + * + * in params[0].a = operation + */ +#define PTA_CMD_ENABLE_SCP03 0 + +#endif /*__TA_SCP03_H*/ -- cgit v1.3.1 From b650c838253f602cd28205b23d89caa454994790 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 1 Mar 2021 17:08:47 +0000 Subject: arm: rmobile: Add HopeRun HiHope RZ/G2M board support The HiHope RZ/G2M board from HopeRun consists of main board (HopeRun HiHope RZ/G2M main board) and sub board(HopeRun HiHope RZ/G2M sub board). The HiHope RZ/G2M sub board sits below the HiHope RZ/G2M main board. This patch adds the required board support to boot HopeRun HiHope RZ/G2M board. Signed-off-by: Biju Das Reviewed-by: Lad Prabhakar --- arch/arm/dts/Makefile | 1 + arch/arm/mach-rmobile/Kconfig.64 | 14 +++++ board/hoperun/hihope-rzg2/Kconfig | 15 +++++ board/hoperun/hihope-rzg2/MAINTAINERS | 6 ++ board/hoperun/hihope-rzg2/Makefile | 9 +++ board/hoperun/hihope-rzg2/hihope-rzg2.c | 105 ++++++++++++++++++++++++++++++++ configs/hihope_rzg2_defconfig | 82 +++++++++++++++++++++++++ include/configs/hihope-rzg2.h | 20 ++++++ 8 files changed, 252 insertions(+) create mode 100644 board/hoperun/hihope-rzg2/Kconfig create mode 100644 board/hoperun/hihope-rzg2/MAINTAINERS create mode 100644 board/hoperun/hihope-rzg2/Makefile create mode 100644 board/hoperun/hihope-rzg2/hihope-rzg2.c create mode 100644 configs/hihope_rzg2_defconfig create mode 100644 include/configs/hihope-rzg2.h (limited to 'include') diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index c6710826a0a..142e2ad6bfe 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -822,6 +822,7 @@ dtb-$(CONFIG_RCAR_GEN3) += \ r8a774a1-beacon-rzg2m-kit.dtb \ r8a774b1-beacon-rzg2n-kit.dtb \ r8a774e1-beacon-rzg2h-kit.dtb \ + r8a774a1-hihope-rzg2m-u-boot.dtb \ r8a77950-ulcb-u-boot.dtb \ r8a77950-salvator-x-u-boot.dtb \ r8a77960-ulcb-u-boot.dtb \ diff --git a/arch/arm/mach-rmobile/Kconfig.64 b/arch/arm/mach-rmobile/Kconfig.64 index b95c8e8d29e..2c2c60385d9 100644 --- a/arch/arm/mach-rmobile/Kconfig.64 +++ b/arch/arm/mach-rmobile/Kconfig.64 @@ -4,6 +4,8 @@ menu "Select Target SoC" config R8A774A1 bool "Renesas SoC R8A774A1" + imply CLK_R8A774A1 + imply PINCTRL_PFC_R8A774A1 config R8A774B1 bool "Renesas SoC R8A774B1" @@ -99,6 +101,15 @@ config TARGET_EBISU help Support for Renesas R-Car Gen3 Ebisu platform +config TARGET_HIHOPE_RZG2 + bool "HiHope RZ/G2 board" + imply R8A774A1 + imply SYS_MALLOC_F + imply MULTI_DTB_FIT + imply MULTI_DTB_FIT_USER_DEFINED_AREA + help + Support for RZG2 HiHope platform + config TARGET_SALVATOR_X bool "Salvator-X board" imply R8A7795 @@ -133,12 +144,15 @@ source "board/renesas/ebisu/Kconfig" source "board/renesas/salvator-x/Kconfig" source "board/renesas/ulcb/Kconfig" source "board/beacon/beacon-rzg2m/Kconfig" +source "board/hoperun/hihope-rzg2/Kconfig" config MULTI_DTB_FIT_UNCOMPRESS_SZ + default 0x80000 if TARGET_HIHOPE_RZG2 default 0x80000 if TARGET_SALVATOR_X default 0x80000 if TARGET_ULCB config MULTI_DTB_FIT_USER_DEF_ADDR + default 0x49000000 if TARGET_HIHOPE_RZG2 default 0x49000000 if TARGET_SALVATOR_X default 0x49000000 if TARGET_ULCB diff --git a/board/hoperun/hihope-rzg2/Kconfig b/board/hoperun/hihope-rzg2/Kconfig new file mode 100644 index 00000000000..ee422ba6c8f --- /dev/null +++ b/board/hoperun/hihope-rzg2/Kconfig @@ -0,0 +1,15 @@ +if TARGET_HIHOPE_RZG2 + +config SYS_SOC + default "rmobile" + +config SYS_BOARD + default "hihope-rzg2" + +config SYS_VENDOR + default "hoperun" + +config SYS_CONFIG_NAME + default "hihope-rzg2" + +endif diff --git a/board/hoperun/hihope-rzg2/MAINTAINERS b/board/hoperun/hihope-rzg2/MAINTAINERS new file mode 100644 index 00000000000..e3702fd12e7 --- /dev/null +++ b/board/hoperun/hihope-rzg2/MAINTAINERS @@ -0,0 +1,6 @@ +HIHOPE_RZG2 BOARD +M: Biju Das +S: Maintained +F: board/hoperun/hihope-rzg2/ +F: include/configs/hihope-rzg2.h +F: configs/hihope_rzg2_defconfig diff --git a/board/hoperun/hihope-rzg2/Makefile b/board/hoperun/hihope-rzg2/Makefile new file mode 100644 index 00000000000..e989e7aacc5 --- /dev/null +++ b/board/hoperun/hihope-rzg2/Makefile @@ -0,0 +1,9 @@ +# +# board/hoperun/hihope-rzg2/Makefile +# +# Copyright (C) 2021 Renesas Electronics Corporation +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := hihope-rzg2.o ../../renesas/rcar-common/common.o diff --git a/board/hoperun/hihope-rzg2/hihope-rzg2.c b/board/hoperun/hihope-rzg2/hihope-rzg2.c new file mode 100644 index 00000000000..a60529f7805 --- /dev/null +++ b/board/hoperun/hihope-rzg2/hihope-rzg2.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * board/hoperun/hihope-rzg2/hihope-rzg2.c + * This file is HiHope RZ/G2M board support. + * + * Copyright (C) 2021 Renesas Electronics Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RST_BASE 0xE6160000 +#define RST_CA57RESCNT (RST_BASE + 0x40) +#define RST_CA53RESCNT (RST_BASE + 0x44) +#define RST_CA57_CODE 0xA5A5000F +#define RST_CA53_CODE 0x5A5A000F + +DECLARE_GLOBAL_DATA_PTR; +#define HSUSB_MSTP704 BIT(4) /* HSUSB */ + +/* HSUSB block registers */ +#define HSUSB_REG_LPSTS 0xE6590102 +#define HSUSB_REG_LPSTS_SUSPM_NORMAL BIT(14) +#define HSUSB_REG_UGCTRL2 0xE6590184 +#define HSUSB_REG_UGCTRL2_USB0SEL_EHCI 0x10 +#define HSUSB_REG_UGCTRL2_RESERVED_3 0x1 /* bit[3:0] should be B'0001 */ + +#define PRR_REGISTER (0xFFF00044) + +int board_init(void) +{ + u32 i; + + /* address of boot parameters */ + gd->bd->bi_boot_params = CONFIG_SYS_TEXT_BASE + 0x50000; + + /* Configure the HSUSB block */ + mstp_clrbits_le32(SMSTPCR7, SMSTPCR7, HSUSB_MSTP704); + /* + * We need to add a barrier instruction after HSUSB module stop release. + * This barrier instruction can be either reading back the same MSTP + * register or any other register in the same IP block. So like linux + * adding check for MSTPSR register, which indicates the clock has been + * started. + */ + for (i = 1000; i > 0; --i) { + if (!(readl(MSTPSR7) & HSUSB_MSTP704)) + break; + cpu_relax(); + } + + /* Select EHCI/OHCI host module for USB2.0 ch0 */ + writel(HSUSB_REG_UGCTRL2_USB0SEL_EHCI | HSUSB_REG_UGCTRL2_RESERVED_3, + HSUSB_REG_UGCTRL2); + /* low power status */ + setbits_le16(HSUSB_REG_LPSTS, HSUSB_REG_LPSTS_SUSPM_NORMAL); + + return 0; +} + +void reset_cpu(ulong addr) +{ + unsigned long midr, cputype; + + asm volatile("mrs %0, midr_el1" : "=r" (midr)); + cputype = (midr >> 4) & 0xfff; + + if (cputype == 0xd03) + writel(RST_CA53_CODE, RST_CA53RESCNT); + else + writel(RST_CA57_CODE, RST_CA57RESCNT); +} + +#if defined(CONFIG_MULTI_DTB_FIT) +/* If the firmware passed a device tree, use it for board identification. */ +extern u64 rcar_atf_boot_args[]; + +static bool is_hoperun_hihope_rzg2_board(const char *board_name) +{ + void *atf_fdt_blob = (void *)(rcar_atf_boot_args[1]); + bool ret = false; + + if ((fdt_magic(atf_fdt_blob) == FDT_MAGIC) && + (fdt_node_check_compatible(atf_fdt_blob, 0, board_name) == 0)) + ret = true; + + return ret; +} + +int board_fit_config_name_match(const char *name) +{ + if (is_hoperun_hihope_rzg2_board("hoperun,hihope-rzg2m") && + !strcmp(name, "r8a774a1-hihope-rzg2m-u-boot")) + return 0; + + return -1; +} +#endif diff --git a/configs/hihope_rzg2_defconfig b/configs/hihope_rzg2_defconfig new file mode 100644 index 00000000000..bc40445b5e9 --- /dev/null +++ b/configs/hihope_rzg2_defconfig @@ -0,0 +1,82 @@ +CONFIG_ARM=y +CONFIG_ARCH_CPU_INIT=y +CONFIG_ARCH_RMOBILE=y +CONFIG_SYS_TEXT_BASE=0x50000000 +CONFIG_ENV_SIZE=0x20000 +CONFIG_ENV_OFFSET=0xFFFE0000 +CONFIG_DM_GPIO=y +CONFIG_RCAR_GEN3=y +CONFIG_TARGET_HIHOPE_RZG2=y +# CONFIG_SPL is not set +CONFIG_DEFAULT_DEVICE_TREE="r8a774a1-hihope-rzg2m-u-boot" +CONFIG_FIT=y +CONFIG_SUPPORT_RAW_INITRD=y +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="root=/dev/nfs rw nfsroot=192.168.0.1:/export/rfs ip=192.168.0.20" +CONFIG_DEFAULT_FDT_FILE="r8a774a1-hihope-rzg2m.dtb" +# CONFIG_BOARD_EARLY_INIT_F is not set +CONFIG_HUSH_PARSER=y +CONFIG_CMD_BOOTZ=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_MMC=y +CONFIG_CMD_PART=y +CONFIG_CMD_SPI=y +CONFIG_CMD_USB=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y +CONFIG_CMD_PING=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_OF_CONTROL=y +CONFIG_OF_LIST="r8a774a1-hihope-rzg2m-u-boot" +CONFIG_MULTI_DTB_FIT_LZO=y +CONFIG_MULTI_DTB_FIT_USER_DEFINED_AREA=y +CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_MMC=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_SYS_MMC_ENV_DEV=1 +CONFIG_SYS_MMC_ENV_PART=2 +CONFIG_VERSION_VARIABLE=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y +CONFIG_CLK=y +CONFIG_CLK_RENESAS=y +CONFIG_GPIO_HOG=y +CONFIG_RCAR_GPIO=y +CONFIG_DM_PCA953X=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_RCAR_I2C=y +CONFIG_SYS_I2C_RCAR_IIC=y +CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_MMC_HS400_SUPPORT=y +CONFIG_RENESAS_SDHI=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH_BAR=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_SPI_FLASH_USE_4K_SECTORS=y +CONFIG_BITBANGMII=y +CONFIG_PHY_REALTEK=y +CONFIG_DM_ETH=y +CONFIG_RENESAS_RAVB=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_REGULATOR_GPIO=y +CONFIG_SCIF_CONSOLE=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_RENESAS_RPC_SPI=y +CONFIG_TEE=y +CONFIG_OPTEE=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_GENERIC=y +CONFIG_USB_STORAGE=y +CONFIG_OF_LIBFDT_OVERLAY=y diff --git a/include/configs/hihope-rzg2.h b/include/configs/hihope-rzg2.h new file mode 100644 index 00000000000..68a51176e38 --- /dev/null +++ b/include/configs/hihope-rzg2.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * include/configs/hihope-rzg2.h + * This file is HOPERUN HiHope RZ/G2 board configuration. + * + * Copyright (C) 2020 Renesas Electronics Corporation + */ + +#ifndef __HIHOPE_RZG2_H +#define __HIHOPE_RZG2_H + +#include "rcar-gen3-common.h" + +/* Ethernet RAVB */ +#define CONFIG_BITBANGMII_MULTI + +/* Generic Timer Definitions (use in assembler source) */ +#define COUNTER_FREQUENCY 0xFE502A /* 16.66MHz from CPclk */ + +#endif /* __HIHOPE_RZG2_H */ -- cgit v1.3.1 From 07148c18994517610a21cfe9dd370296df349712 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 15 Mar 2021 22:24:05 +0000 Subject: arm: rmobile: Add Silicon Linux EK874 board support The EK874 development kit from Silicon Linux is made of CAT874 (the main board) and CAT875 (the sub board that goes on top of CAT874). This patch adds the required board support to boot Si-Linux EK874 board based on R8A774C0 SoC. DTS files apart from r8a774c0-ek874-u-boot.dts and r8a774c0-u-boot.dtsi have been imported from Linux kernel 5.11 commit f40ddce88593 ("Linux 5.11"). Signed-off-by: Lad Prabhakar Reviewed-by: Biju Das --- arch/arm/dts/Makefile | 1 + arch/arm/dts/cat875.dtsi | 64 +++++ arch/arm/dts/r8a774c0-cat874.dts | 453 +++++++++++++++++++++++++++++++++ arch/arm/dts/r8a774c0-ek874-u-boot.dts | 33 +++ arch/arm/dts/r8a774c0-ek874.dts | 14 + arch/arm/dts/r8a774c0-u-boot.dtsi | 53 ++++ arch/arm/mach-rmobile/Kconfig.64 | 7 + board/silinux/ek874/Kconfig | 15 ++ board/silinux/ek874/MAINTAINERS | 6 + board/silinux/ek874/Makefile | 9 + board/silinux/ek874/ek874.c | 30 +++ configs/silinux_ek874_defconfig | 83 ++++++ include/configs/silinux-ek874.h | 20 ++ include/dt-bindings/display/tda998x.h | 8 + 14 files changed, 796 insertions(+) create mode 100644 arch/arm/dts/cat875.dtsi create mode 100644 arch/arm/dts/r8a774c0-cat874.dts create mode 100644 arch/arm/dts/r8a774c0-ek874-u-boot.dts create mode 100644 arch/arm/dts/r8a774c0-ek874.dts create mode 100644 arch/arm/dts/r8a774c0-u-boot.dtsi create mode 100644 board/silinux/ek874/Kconfig create mode 100644 board/silinux/ek874/MAINTAINERS create mode 100644 board/silinux/ek874/Makefile create mode 100644 board/silinux/ek874/ek874.c create mode 100644 configs/silinux_ek874_defconfig create mode 100644 include/configs/silinux-ek874.h create mode 100644 include/dt-bindings/display/tda998x.h (limited to 'include') diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index d2f2212f867..f5fe327b6c3 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -824,6 +824,7 @@ dtb-$(CONFIG_RCAR_GEN3) += \ r8a774e1-beacon-rzg2h-kit.dtb \ r8a774a1-hihope-rzg2m-u-boot.dtb \ r8a774b1-hihope-rzg2n-u-boot.dtb \ + r8a774c0-ek874-u-boot.dtb \ r8a774e1-hihope-rzg2h-u-boot.dtb \ r8a77950-ulcb-u-boot.dtb \ r8a77950-salvator-x-u-boot.dtb \ diff --git a/arch/arm/dts/cat875.dtsi b/arch/arm/dts/cat875.dtsi new file mode 100644 index 00000000000..4a2f6fa9553 --- /dev/null +++ b/arch/arm/dts/cat875.dtsi @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for the Silicon Linux sub board for CAT874 (CAT875) + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +/ { + model = "Silicon Linux sub board for CAT874 (CAT875)"; + + aliases { + ethernet0 = &avb; + }; +}; + +&avb { + pinctrl-0 = <&avb_pins>; + pinctrl-names = "default"; + renesas,no-ether-link; + phy-handle = <&phy0>; + status = "okay"; + + phy0: ethernet-phy@0 { + reg = <0>; + interrupt-parent = <&gpio2>; + interrupts = <21 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; + }; +}; + +&can0 { + pinctrl-0 = <&can0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&can1 { + pinctrl-0 = <&can1_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pciec0 { + status = "okay"; +}; + +&pfc { + avb_pins: avb { + mux { + groups = "avb_mii"; + function = "avb"; + }; + }; + + can0_pins: can0 { + groups = "can0_data"; + function = "can0"; + }; + + can1_pins: can1 { + groups = "can1_data"; + function = "can1"; + }; +}; diff --git a/arch/arm/dts/r8a774c0-cat874.dts b/arch/arm/dts/r8a774c0-cat874.dts new file mode 100644 index 00000000000..676fdef9e08 --- /dev/null +++ b/arch/arm/dts/r8a774c0-cat874.dts @@ -0,0 +1,453 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for the Silicon Linux RZ/G2E 96board platform (CAT874) + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +/dts-v1/; +#include "r8a774c0.dtsi" +#include +#include + +/ { + model = "Silicon Linux RZ/G2E 96board platform (CAT874)"; + compatible = "si-linux,cat874", "renesas,r8a774c0"; + + aliases { + serial0 = &scif2; + serial1 = &hscif2; + }; + + chosen { + bootargs = "ignore_loglevel rw root=/dev/nfs ip=on"; + stdout-path = "serial0:115200n8"; + }; + + hdmi-out { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_out: endpoint { + remote-endpoint = <&tda19988_out>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + led0 { + gpios = <&gpio5 19 GPIO_ACTIVE_HIGH>; + label = "LED0"; + }; + + led1 { + gpios = <&gpio3 14 GPIO_ACTIVE_HIGH>; + label = "LED1"; + }; + + led2 { + gpios = <&gpio4 10 GPIO_ACTIVE_HIGH>; + label = "LED2"; + }; + + led3 { + gpios = <&gpio6 4 GPIO_ACTIVE_HIGH>; + label = "LED3"; + }; + }; + + memory@48000000 { + device_type = "memory"; + /* first 128MB is reserved for secure area. */ + reg = <0x0 0x48000000 0x0 0x78000000>; + }; + + reg_12p0v: regulator-12p0v { + compatible = "regulator-fixed"; + regulator-name = "D12.0V"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-boot-on; + regulator-always-on; + }; + + sound: sound { + compatible = "simple-audio-card"; + + simple-audio-card,name = "CAT874 HDMI sound"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&sndcpu>; + simple-audio-card,frame-master = <&sndcpu>; + + sndcodec: simple-audio-card,codec { + sound-dai = <&tda19988>; + }; + + sndcpu: simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + }; + }; + + vcc_sdhi0: regulator-vcc-sdhi0 { + compatible = "regulator-fixed"; + + regulator-name = "SDHI0 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + vccq_sdhi0: regulator-vccq-sdhi0 { + compatible = "regulator-gpio"; + + regulator-name = "SDHI0 VccQ"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + + gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>; + gpios-states = <1>; + states = <3300000 1>, <1800000 0>; + }; + + wlan_en_reg: fixedregulator { + compatible = "regulator-fixed"; + regulator-name = "wlan-en-regulator"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + startup-delay-us = <70000>; + + gpio = <&gpio2 25 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + x13_clk: x13 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <74250000>; + }; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + hs_ep: endpoint { + remote-endpoint = <&usb3_hs_ep>; + }; + }; + port@1 { + reg = <1>; + ss_ep: endpoint { + remote-endpoint = <&hd3ss3220_in_ep>; + }; + }; + }; + }; +}; + +&audio_clk_a { + clock-frequency = <22579200>; +}; + +&du { + pinctrl-0 = <&du_pins>; + pinctrl-names = "default"; + status = "okay"; + + clocks = <&cpg CPG_MOD 724>, + <&cpg CPG_MOD 723>, + <&x13_clk>; + clock-names = "du.0", "du.1", "dclkin.0"; + + ports { + port@0 { + endpoint { + remote-endpoint = <&tda19988_in>; + }; + }; + }; +}; + +&ehci0 { + dr_mode = "host"; + status = "okay"; +}; + +&extal_clk { + clock-frequency = <48000000>; +}; + +&hscif2 { + pinctrl-0 = <&hscif2_pins>; + pinctrl-names = "default"; + + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "ti,wl1837-st"; + enable-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>; + }; +}; + +&i2c0 { + status = "okay"; + clock-frequency = <100000>; + + hd3ss3220@47 { + compatible = "ti,hd3ss3220"; + reg = <0x47>; + interrupt-parent = <&gpio6>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + hd3ss3220_in_ep: endpoint { + remote-endpoint = <&ss_ep>; + }; + }; + port@1 { + reg = <1>; + hd3ss3220_out_ep: endpoint { + remote-endpoint = <&usb3_role_switch>; + }; + }; + }; + }; + + tda19988: tda19988@70 { + compatible = "nxp,tda998x"; + reg = <0x70>; + interrupt-parent = <&gpio1>; + interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + + video-ports = <0x234501>; + + #sound-dai-cells = <0>; + audio-ports = ; + clocks = <&rcar_sound 1>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tda19988_in: endpoint { + remote-endpoint = <&du_out_rgb>; + }; + }; + + port@1 { + reg = <1>; + tda19988_out: endpoint { + remote-endpoint = <&hdmi_con_out>; + }; + }; + }; + }; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + + status = "okay"; + clock-frequency = <400000>; + + rtc@32 { + compatible = "epson,rx8571"; + reg = <0x32>; + }; +}; + +&lvds0 { + status = "okay"; + + clocks = <&cpg CPG_MOD 727>, <&x13_clk>, <&extal_clk>; + clock-names = "fck", "dclkin.0", "extal"; +}; + +&ohci0 { + dr_mode = "host"; + status = "okay"; +}; + +&pcie_bus_clk { + clock-frequency = <100000000>; +}; + +&pciec0 { + /* Map all possible DDR as inbound ranges */ + dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000>; +}; + +&pfc { + du_pins: du { + groups = "du_rgb888", "du_clk_out_0", "du_sync", "du_disp", + "du_clk_in_0"; + function = "du"; + }; + + hscif2_pins: hscif2 { + groups = "hscif2_data_a", "hscif2_ctrl_a"; + function = "hscif2"; + }; + + i2c1_pins: i2c1 { + groups = "i2c1_b"; + function = "i2c1"; + }; + + scif2_pins: scif2 { + groups = "scif2_data_a"; + function = "scif2"; + }; + + sdhi0_pins: sd0 { + groups = "sdhi0_data4", "sdhi0_ctrl"; + function = "sdhi0"; + power-source = <3300>; + }; + + sdhi0_pins_uhs: sd0_uhs { + groups = "sdhi0_data4", "sdhi0_ctrl"; + function = "sdhi0"; + power-source = <1800>; + }; + + sdhi3_pins: sd3 { + groups = "sdhi3_data4", "sdhi3_ctrl"; + function = "sdhi3"; + power-source = <1800>; + }; + + sound_clk_pins: sound_clk { + groups = "audio_clkout1_a"; + function = "audio_clk"; + }; + + sound_pins: sound { + groups = "ssi01239_ctrl", "ssi0_data"; + function = "ssi"; + }; + + usb30_pins: usb30 { + groups = "usb30", "usb30_id"; + function = "usb30"; + }; +}; + +&rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; + + /* Single DAI */ + #sound-dai-cells = <0>; + + /* audio_clkout0/1/2/3 */ + #clock-cells = <1>; + clock-frequency = <11289600>; + + status = "okay"; + + rcar_sound,dai { + dai0 { + playback = <&ssi0 &src0 &dvc0>; + }; + }; +}; + +&rwdt { + timeout-sec = <60>; + status = "okay"; +}; + +&scif2 { + pinctrl-0 = <&scif2_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&sdhi0 { + pinctrl-0 = <&sdhi0_pins>; + pinctrl-1 = <&sdhi0_pins_uhs>; + pinctrl-names = "default", "state_uhs"; + + vmmc-supply = <&vcc_sdhi0>; + vqmmc-supply = <&vccq_sdhi0>; + cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>; + bus-width = <4>; + sd-uhs-sdr50; + sd-uhs-sdr104; + status = "okay"; +}; + +&sdhi3 { + status = "okay"; + pinctrl-0 = <&sdhi3_pins>; + pinctrl-names = "default"; + + vmmc-supply = <&wlan_en_reg>; + bus-width = <4>; + non-removable; + cap-power-off-card; + keep-power-in-suspend; + + #address-cells = <1>; + #size-cells = <0>; + wlcore: wlcore@2 { + compatible = "ti,wl1837"; + reg = <2>; + interrupt-parent = <&gpio1>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; +}; + +&usb2_phy0 { + renesas,no-otg-pins; + status = "okay"; +}; + +&usb3_peri0 { + companion = <&xhci0>; + status = "okay"; + usb-role-switch; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + usb3_hs_ep: endpoint { + remote-endpoint = <&hs_ep>; + }; + }; + port@1 { + reg = <1>; + usb3_role_switch: endpoint { + remote-endpoint = <&hd3ss3220_out_ep>; + }; + }; + }; +}; + +&xhci0 { + pinctrl-0 = <&usb30_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; diff --git a/arch/arm/dts/r8a774c0-ek874-u-boot.dts b/arch/arm/dts/r8a774c0-ek874-u-boot.dts new file mode 100644 index 00000000000..8fa6d8074b3 --- /dev/null +++ b/arch/arm/dts/r8a774c0-ek874-u-boot.dts @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source extras for U-Boot for the Hihope board + * + * Copyright (C) 2021 Renesas Electronisc Corporation + */ + +#include "r8a774c0-ek874.dts" +#include "r8a774c0-u-boot.dtsi" + +/ { + aliases { + spi0 = &rpc; + }; +}; + +&rpc { + num-cs = <1>; + status = "okay"; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <0>; + + flash0: spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "w25m512jv", "spi-flash", "jedec,spi-nor"; + spi-max-frequency = <50000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + reg = <0>; + }; +}; diff --git a/arch/arm/dts/r8a774c0-ek874.dts b/arch/arm/dts/r8a774c0-ek874.dts new file mode 100644 index 00000000000..d3ab28ba31e --- /dev/null +++ b/arch/arm/dts/r8a774c0-ek874.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for the Silicon Linux RZ/G2E evaluation kit (EK874) + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +#include "r8a774c0-cat874.dts" +#include "cat875.dtsi" + +/ { + model = "Silicon Linux RZ/G2E evaluation kit EK874 (CAT874 + CAT875)"; + compatible = "si-linux,cat875", "si-linux,cat874", "renesas,r8a774c0"; +}; diff --git a/arch/arm/dts/r8a774c0-u-boot.dtsi b/arch/arm/dts/r8a774c0-u-boot.dtsi new file mode 100644 index 00000000000..af1c86171b6 --- /dev/null +++ b/arch/arm/dts/r8a774c0-u-boot.dtsi @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source extras for U-Boot on R8A774C0 SoC + * + * Copyright (C) 2021 Renesas Electronics Corp. + * + */ + +#include "r8a779x-u-boot.dtsi" + +/ { + soc { + rpc: rpc@ee200000 { + compatible = "renesas,rcar-gen3-rpc", "renesas,rpc-r8a774c0"; + reg = <0 0xee200000 0 0x100>, <0 0x08000000 0 0x04000000>; + clocks = <&cpg CPG_MOD 917>; + bank-width = <2>; + status = "disabled"; + }; + }; +}; + +/delete-node/ &can0; +/delete-node/ &can1; +/delete-node/ &canfd; +/delete-node/ &pwm0; +/delete-node/ &pwm1; +/delete-node/ &pwm2; +/delete-node/ &pwm3; +/delete-node/ &pwm4; +/delete-node/ &pwm5; +/delete-node/ &pwm6; +/delete-node/ &vin4; +/delete-node/ &vin5; +/delete-node/ &rcar_sound; +/delete-node/ &audma0; +/delete-node/ &sdhi1; +/delete-node/ &sdhi3; +/delete-node/ &vspb0; +/delete-node/ &vspd0; +/delete-node/ &vspd1; +/delete-node/ &vspi0; +/delete-node/ &fcpvb0; +/delete-node/ &fcpvd0; +/delete-node/ &fcpvd1; +/delete-node/ &fcpvi0; +/delete-node/ &csi40; +/delete-node/ &du; +/delete-node/ &lvds0; +/delete-node/ &lvds1; +/delete-node/ &hdmi_con_out; +/delete-node/ &sound; +/delete-node/ &tda19988; diff --git a/arch/arm/mach-rmobile/Kconfig.64 b/arch/arm/mach-rmobile/Kconfig.64 index 28c2628a3cb..8127d33f2d6 100644 --- a/arch/arm/mach-rmobile/Kconfig.64 +++ b/arch/arm/mach-rmobile/Kconfig.64 @@ -113,6 +113,12 @@ config TARGET_HIHOPE_RZG2 help Support for RZG2 HiHope platform +config TARGET_SILINUX_EK874 + bool "Silicon Linux EK874 board" + imply R8A774C0 + help + Support for Silicon Linux EK874 platform + config TARGET_SALVATOR_X bool "Salvator-X board" imply R8A7795 @@ -148,6 +154,7 @@ source "board/renesas/salvator-x/Kconfig" source "board/renesas/ulcb/Kconfig" source "board/beacon/beacon-rzg2m/Kconfig" source "board/hoperun/hihope-rzg2/Kconfig" +source "board/silinux/ek874/Kconfig" config MULTI_DTB_FIT_UNCOMPRESS_SZ default 0x80000 if TARGET_HIHOPE_RZG2 diff --git a/board/silinux/ek874/Kconfig b/board/silinux/ek874/Kconfig new file mode 100644 index 00000000000..60b390a121e --- /dev/null +++ b/board/silinux/ek874/Kconfig @@ -0,0 +1,15 @@ +if TARGET_SILINUX_EK874 + +config SYS_SOC + default "rmobile" + +config SYS_BOARD + default "ek874" + +config SYS_VENDOR + default "silinux" + +config SYS_CONFIG_NAME + default "silinux-ek874" + +endif diff --git a/board/silinux/ek874/MAINTAINERS b/board/silinux/ek874/MAINTAINERS new file mode 100644 index 00000000000..57a71b83b20 --- /dev/null +++ b/board/silinux/ek874/MAINTAINERS @@ -0,0 +1,6 @@ +SILINUX_EK874 BOARD +M: Lad Prabhakar +S: Maintained +F: board/silinux/ek874/ +F: include/configs/silinux-ek874.h +F: configs/silinux_ek874_defconfig diff --git a/board/silinux/ek874/Makefile b/board/silinux/ek874/Makefile new file mode 100644 index 00000000000..32a3a009900 --- /dev/null +++ b/board/silinux/ek874/Makefile @@ -0,0 +1,9 @@ +# +# board/silinux/ek874/Makefile +# +# Copyright (C) 2021 Renesas Electronics Corporation +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := ek874.o ../../renesas/rcar-common/common.o diff --git a/board/silinux/ek874/ek874.c b/board/silinux/ek874/ek874.c new file mode 100644 index 00000000000..5a219cd98d7 --- /dev/null +++ b/board/silinux/ek874/ek874.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * board/silinux/ek874/ek874.c + * This file is ek874 board support. + * + * Copyright (C) 2021 Renesas Electronics Corporation + */ + +#include +#include +#include + +#define RST_BASE 0xE6160000 +#define RST_CA53RESCNT (RST_BASE + 0x44) +#define RST_CA53_CODE 0x5A5A000F + +DECLARE_GLOBAL_DATA_PTR; + +int board_init(void) +{ + /* address of boot parameters */ + gd->bd->bi_boot_params = CONFIG_SYS_TEXT_BASE + 0x50000; + + return 0; +} + +void reset_cpu(ulong addr) +{ + writel(RST_CA53_CODE, RST_CA53RESCNT); +} diff --git a/configs/silinux_ek874_defconfig b/configs/silinux_ek874_defconfig new file mode 100644 index 00000000000..442e24a3d74 --- /dev/null +++ b/configs/silinux_ek874_defconfig @@ -0,0 +1,83 @@ +CONFIG_ARM=y +CONFIG_ARCH_CPU_INIT=y +CONFIG_ARCH_RMOBILE=y +CONFIG_SYS_TEXT_BASE=0x50000000 +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_ENV_SIZE=0x10000 +CONFIG_ENV_OFFSET=0x3F0000 +CONFIG_ENV_SECT_SIZE=0x10000 +CONFIG_RCAR_GEN3=y +CONFIG_TARGET_SILINUX_EK874=y +# CONFIG_BOARD_EARLY_INIT_F is not set +# CONFIG_SPL is not set +CONFIG_SOC_DEVICE=y +CONFIG_SOC_DEVICE_RENESAS=y +CONFIG_DEFAULT_DEVICE_TREE="r8a774c0-ek874-u-boot" +CONFIG_SMBIOS_PRODUCT_NAME="" +CONFIG_FIT=y +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="root=/dev/nfs rw nfsroot=192.168.0.1:/export/rfs ip=192.168.0.20" +CONFIG_SUPPORT_RAW_INITRD=y +CONFIG_DEFAULT_FDT_FILE="r8a774c0-ek874.dtb" +CONFIG_VERSION_VARIABLE=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_BOOTZ=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +CONFIG_CMD_MMC=y +CONFIG_CMD_PART=y +CONFIG_CMD_USB=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y +CONFIG_CMD_PING=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_OF_CONTROL=y +CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y +CONFIG_BLK=y +CONFIG_CLK=y +CONFIG_CLK_RENESAS=y +CONFIG_DM_GPIO=y +CONFIG_RCAR_GPIO=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_RCAR_I2C=y +CONFIG_SYS_I2C_RCAR_IIC=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_BAR=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_SPI_FLASH_USE_4K_SECTORS=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_RENESAS_RPC_SPI=y +CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_RENESAS_SDHI=y +CONFIG_BITBANGMII=y +CONFIG_PHY_REALTEK=y +CONFIG_DM_ETH=y +CONFIG_RENESAS_RAVB=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_REGULATOR_GPIO=y +CONFIG_SCIF_CONSOLE=y +CONFIG_TEE=y +CONFIG_OPTEE=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_GENERIC=y +CONFIG_USB_STORAGE=y +CONFIG_OF_LIBFDT_OVERLAY=y +CONFIG_SMBIOS_MANUFACTURER="" diff --git a/include/configs/silinux-ek874.h b/include/configs/silinux-ek874.h new file mode 100644 index 00000000000..25c0cd2335c --- /dev/null +++ b/include/configs/silinux-ek874.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * include/configs/silinux-ek874.h + * This file is Silicon Linux EK874 board configuration. + * + * Copyright (C) 2021 Renesas Electronics Corporation + */ + +#ifndef __SILINUX_EK874_H +#define __SILINUX_EK874_H + +#include "rcar-gen3-common.h" + +/* Ethernet RAVB */ +#define CONFIG_BITBANGMII_MULTI + +/* Generic Timer Definitions (use in assembler source) */ +#define COUNTER_FREQUENCY 0xFE502A /* 16.66MHz from CPclk */ + +#endif /* __SILINUX_EK874_H */ diff --git a/include/dt-bindings/display/tda998x.h b/include/dt-bindings/display/tda998x.h new file mode 100644 index 00000000000..746831ff396 --- /dev/null +++ b/include/dt-bindings/display/tda998x.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _DT_BINDINGS_TDA998X_H +#define _DT_BINDINGS_TDA998X_H + +#define TDA998x_SPDIF 1 +#define TDA998x_I2S 2 + +#endif /*_DT_BINDINGS_TDA998X_H */ -- cgit v1.3.1 From 86e07d59ee53cdd209c114bdabef599d3b3d2036 Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Mon, 15 Feb 2021 19:07:44 +0100 Subject: board: mediatek: rename pumpkin board into mt8516 More than one pumpkin board has been made with different MediaTek SoCs. Rename the pumpkin board to follow the naming convention of all other MediaTek boards and also to not be confusing when other pumpkin boards will be added in follow-up commits. Signed-off-by: Fabien Parent --- arch/arm/mach-mediatek/Kconfig | 2 +- board/mediatek/mt8516/Kconfig | 13 ++++++ board/mediatek/mt8516/MAINTAINERS | 6 +++ board/mediatek/mt8516/Makefile | 3 ++ board/mediatek/mt8516/mt8516_pumpkin.c | 28 ++++++++++++ board/mediatek/pumpkin/Kconfig | 13 ------ board/mediatek/pumpkin/MAINTAINERS | 6 --- board/mediatek/pumpkin/Makefile | 3 -- board/mediatek/pumpkin/pumpkin.c | 28 ------------ configs/mt8516_pumpkin_defconfig | 78 ++++++++++++++++++++++++++++++++++ configs/pumpkin_defconfig | 78 ---------------------------------- include/configs/mt8516.h | 53 +++++++++++++++++++++++ include/configs/pumpkin.h | 53 ----------------------- 13 files changed, 182 insertions(+), 182 deletions(-) create mode 100644 board/mediatek/mt8516/Kconfig create mode 100644 board/mediatek/mt8516/MAINTAINERS create mode 100644 board/mediatek/mt8516/Makefile create mode 100644 board/mediatek/mt8516/mt8516_pumpkin.c delete mode 100644 board/mediatek/pumpkin/Kconfig delete mode 100644 board/mediatek/pumpkin/MAINTAINERS delete mode 100644 board/mediatek/pumpkin/Makefile delete mode 100644 board/mediatek/pumpkin/pumpkin.c create mode 100644 configs/mt8516_pumpkin_defconfig delete mode 100644 configs/pumpkin_defconfig create mode 100644 include/configs/mt8516.h delete mode 100644 include/configs/pumpkin.h (limited to 'include') diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig index 7f40ba93190..2791b3dbda2 100644 --- a/arch/arm/mach-mediatek/Kconfig +++ b/arch/arm/mach-mediatek/Kconfig @@ -76,7 +76,7 @@ source "board/mediatek/mt7622/Kconfig" source "board/mediatek/mt7623/Kconfig" source "board/mediatek/mt7629/Kconfig" source "board/mediatek/mt8512/Kconfig" +source "board/mediatek/mt8516/Kconfig" source "board/mediatek/mt8518/Kconfig" -source "board/mediatek/pumpkin/Kconfig" endif diff --git a/board/mediatek/mt8516/Kconfig b/board/mediatek/mt8516/Kconfig new file mode 100644 index 00000000000..a87d3872fe6 --- /dev/null +++ b/board/mediatek/mt8516/Kconfig @@ -0,0 +1,13 @@ +if TARGET_MT8516 + +config SYS_BOARD + default "mt8516" + +config SYS_CONFIG_NAME + default "mt8516" + +config MTK_BROM_HEADER_INFO + string + default "media=emmc" + +endif diff --git a/board/mediatek/mt8516/MAINTAINERS b/board/mediatek/mt8516/MAINTAINERS new file mode 100644 index 00000000000..2f0d8f64649 --- /dev/null +++ b/board/mediatek/mt8516/MAINTAINERS @@ -0,0 +1,6 @@ +MT8516 Pumpkin +M: Fabien Parent +S: Maintained +F: board/mediatek/mt8516 +F: include/configs/mt8516.h +F: configs/mt8516_pumpkin_defconfig diff --git a/board/mediatek/mt8516/Makefile b/board/mediatek/mt8516/Makefile new file mode 100644 index 00000000000..1d4815d1370 --- /dev/null +++ b/board/mediatek/mt8516/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += mt8516_pumpkin.o diff --git a/board/mediatek/mt8516/mt8516_pumpkin.c b/board/mediatek/mt8516/mt8516_pumpkin.c new file mode 100644 index 00000000000..37daf1c51b9 --- /dev/null +++ b/board/mediatek/mt8516/mt8516_pumpkin.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 BayLibre SAS + */ + +#include +#include + +int board_init(void) +{ + return 0; +} + +int board_late_init(void) +{ + struct udevice *dev; + int ret; + + if (CONFIG_IS_ENABLED(USB_GADGET)) { + ret = uclass_get_device(UCLASS_USB_GADGET_GENERIC, 0, &dev); + if (ret) { + pr_err("%s: Cannot find USB device\n", __func__); + return ret; + } + } + + return 0; +} diff --git a/board/mediatek/pumpkin/Kconfig b/board/mediatek/pumpkin/Kconfig deleted file mode 100644 index 34b1c0b09d4..00000000000 --- a/board/mediatek/pumpkin/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -if TARGET_MT8516 - -config SYS_BOARD - default "pumpkin" - -config SYS_CONFIG_NAME - default "pumpkin" - -config MTK_BROM_HEADER_INFO - string - default "media=emmc" - -endif diff --git a/board/mediatek/pumpkin/MAINTAINERS b/board/mediatek/pumpkin/MAINTAINERS deleted file mode 100644 index 16beadc027a..00000000000 --- a/board/mediatek/pumpkin/MAINTAINERS +++ /dev/null @@ -1,6 +0,0 @@ -Pumpkin -M: Fabien Parent -S: Maintained -F: board/mediatek/pumpkin -F: include/configs/pumpkin.h -F: configs/pumpkin_defconfig diff --git a/board/mediatek/pumpkin/Makefile b/board/mediatek/pumpkin/Makefile deleted file mode 100644 index 75fce4a393a..00000000000 --- a/board/mediatek/pumpkin/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -obj-y += pumpkin.o diff --git a/board/mediatek/pumpkin/pumpkin.c b/board/mediatek/pumpkin/pumpkin.c deleted file mode 100644 index 37daf1c51b9..00000000000 --- a/board/mediatek/pumpkin/pumpkin.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2019 BayLibre SAS - */ - -#include -#include - -int board_init(void) -{ - return 0; -} - -int board_late_init(void) -{ - struct udevice *dev; - int ret; - - if (CONFIG_IS_ENABLED(USB_GADGET)) { - ret = uclass_get_device(UCLASS_USB_GADGET_GENERIC, 0, &dev); - if (ret) { - pr_err("%s: Cannot find USB device\n", __func__); - return ret; - } - } - - return 0; -} diff --git a/configs/mt8516_pumpkin_defconfig b/configs/mt8516_pumpkin_defconfig new file mode 100644 index 00000000000..5270ec28cbd --- /dev/null +++ b/configs/mt8516_pumpkin_defconfig @@ -0,0 +1,78 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_ARCH_MEDIATEK=y +CONFIG_SYS_TEXT_BASE=0x4C000000 +CONFIG_SYS_MALLOC_F_LEN=0x4000 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_ENV_SIZE=0x1000 +CONFIG_DM_GPIO=y +CONFIG_TARGET_MT8516=y +CONFIG_DEBUG_UART_BASE=0x11005000 +CONFIG_DEBUG_UART_CLOCK=26000000 +# CONFIG_PSCI_RESET is not set +CONFIG_DEFAULT_DEVICE_TREE="mt8516-pumpkin" +CONFIG_DEBUG_UART=y +CONFIG_FIT=y +# CONFIG_FIT_ENABLE_SHA256_SUPPORT is not set +# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set +CONFIG_DEFAULT_FDT_FILE="mt8516-pumpkin" +# CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_BOARD_LATE_INIT=y +CONFIG_HUSH_PARSER=y +# CONFIG_CMD_BDI is not set +# CONFIG_CMD_CONSOLE is not set +# CONFIG_CMD_BOOTD is not set +# CONFIG_CMD_BOOTI is not set +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_GO is not set +# CONFIG_CMD_IMI is not set +# CONFIG_CMD_XIMG is not set +# CONFIG_CMD_EXPORTENV is not set +# CONFIG_CMD_IMPORTENV is not set +# CONFIG_CMD_EDITENV is not set +# CONFIG_CMD_ENV_EXISTS is not set +# CONFIG_CMD_CRC32 is not set +# CONFIG_CMD_MEMORY is not set +CONFIG_CMD_GPT=y +# CONFIG_RANDOM_UUID is not set +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_PART=y +# CONFIG_CMD_ITEST is not set +# CONFIG_CMD_SOURCE is not set +# CONFIG_CMD_SETEXPR is not set +# CONFIG_CMD_BLOCK_CACHE is not set +# CONFIG_CMD_SLEEP is not set +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y +CONFIG_CLK=y +CONFIG_USB_FUNCTION_FASTBOOT=y +CONFIG_FASTBOOT_BUF_ADDR=0x4d000000 +CONFIG_FASTBOOT_BUF_SIZE=0x4000000 +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_FLASH_MMC_DEV=0 +CONFIG_FASTBOOT_MMC_BOOT_SUPPORT=y +CONFIG_FASTBOOT_MMC_USER_SUPPORT=y +# CONFIG_INPUT is not set +CONFIG_DM_MMC=y +# CONFIG_MMC_QUIRKS is not set +CONFIG_MMC_MTK=y +CONFIG_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_MT8516=y +CONFIG_RAM=y +CONFIG_BAUDRATE=921600 +CONFIG_DM_SERIAL=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_MTK_SERIAL=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_MUSB_GADGET=y +CONFIG_USB_MUSB_MT85XX=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VENDOR_NUM=0x0e8d +CONFIG_USB_GADGET_PRODUCT_NUM=0x201c +CONFIG_WDT=y +CONFIG_WDT_MTK=y +# CONFIG_EFI_LOADER is not set diff --git a/configs/pumpkin_defconfig b/configs/pumpkin_defconfig deleted file mode 100644 index 5270ec28cbd..00000000000 --- a/configs/pumpkin_defconfig +++ /dev/null @@ -1,78 +0,0 @@ -CONFIG_ARM=y -CONFIG_POSITION_INDEPENDENT=y -CONFIG_ARCH_MEDIATEK=y -CONFIG_SYS_TEXT_BASE=0x4C000000 -CONFIG_SYS_MALLOC_F_LEN=0x4000 -CONFIG_NR_DRAM_BANKS=1 -CONFIG_ENV_SIZE=0x1000 -CONFIG_DM_GPIO=y -CONFIG_TARGET_MT8516=y -CONFIG_DEBUG_UART_BASE=0x11005000 -CONFIG_DEBUG_UART_CLOCK=26000000 -# CONFIG_PSCI_RESET is not set -CONFIG_DEFAULT_DEVICE_TREE="mt8516-pumpkin" -CONFIG_DEBUG_UART=y -CONFIG_FIT=y -# CONFIG_FIT_ENABLE_SHA256_SUPPORT is not set -# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set -CONFIG_DEFAULT_FDT_FILE="mt8516-pumpkin" -# CONFIG_DISPLAY_BOARDINFO is not set -CONFIG_BOARD_LATE_INIT=y -CONFIG_HUSH_PARSER=y -# CONFIG_CMD_BDI is not set -# CONFIG_CMD_CONSOLE is not set -# CONFIG_CMD_BOOTD is not set -# CONFIG_CMD_BOOTI is not set -# CONFIG_CMD_ELF is not set -# CONFIG_CMD_GO is not set -# CONFIG_CMD_IMI is not set -# CONFIG_CMD_XIMG is not set -# CONFIG_CMD_EXPORTENV is not set -# CONFIG_CMD_IMPORTENV is not set -# CONFIG_CMD_EDITENV is not set -# CONFIG_CMD_ENV_EXISTS is not set -# CONFIG_CMD_CRC32 is not set -# CONFIG_CMD_MEMORY is not set -CONFIG_CMD_GPT=y -# CONFIG_RANDOM_UUID is not set -# CONFIG_CMD_LOADB is not set -# CONFIG_CMD_LOADS is not set -CONFIG_CMD_MMC=y -CONFIG_CMD_PART=y -# CONFIG_CMD_ITEST is not set -# CONFIG_CMD_SOURCE is not set -# CONFIG_CMD_SETEXPR is not set -# CONFIG_CMD_BLOCK_CACHE is not set -# CONFIG_CMD_SLEEP is not set -CONFIG_SYS_RELOC_GD_ENV_ADDR=y -CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y -CONFIG_CLK=y -CONFIG_USB_FUNCTION_FASTBOOT=y -CONFIG_FASTBOOT_BUF_ADDR=0x4d000000 -CONFIG_FASTBOOT_BUF_SIZE=0x4000000 -CONFIG_FASTBOOT_FLASH=y -CONFIG_FASTBOOT_FLASH_MMC_DEV=0 -CONFIG_FASTBOOT_MMC_BOOT_SUPPORT=y -CONFIG_FASTBOOT_MMC_USER_SUPPORT=y -# CONFIG_INPUT is not set -CONFIG_DM_MMC=y -# CONFIG_MMC_QUIRKS is not set -CONFIG_MMC_MTK=y -CONFIG_PINCTRL=y -CONFIG_PINCONF=y -CONFIG_PINCTRL_MT8516=y -CONFIG_RAM=y -CONFIG_BAUDRATE=921600 -CONFIG_DM_SERIAL=y -CONFIG_DEBUG_UART_ANNOUNCE=y -CONFIG_MTK_SERIAL=y -CONFIG_USB=y -CONFIG_DM_USB=y -CONFIG_USB_MUSB_GADGET=y -CONFIG_USB_MUSB_MT85XX=y -CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_VENDOR_NUM=0x0e8d -CONFIG_USB_GADGET_PRODUCT_NUM=0x201c -CONFIG_WDT=y -CONFIG_WDT_MTK=y -# CONFIG_EFI_LOADER is not set diff --git a/include/configs/mt8516.h b/include/configs/mt8516.h new file mode 100644 index 00000000000..e809a9c7e30 --- /dev/null +++ b/include/configs/mt8516.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Configuration for Pumpkin board + * + * Copyright (C) 2019 BayLibre, SAS + * Author: Fabien Parent + +#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_MALLOC_LEN SZ_4M + +#define CONFIG_CPU_ARMV8 +#define COUNTER_FREQUENCY 13000000 + +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_REG_SIZE -4 +#define CONFIG_SYS_NS16550_MEM32 +#define CONFIG_SYS_NS16550_COM1 0x11005000 +#define CONFIG_SYS_NS16550_CLK 26000000 + +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_TEXT_BASE + SZ_2M - \ + GENERATED_GBL_DATA_SIZE) + +#define CONFIG_SYS_BOOTM_LEN SZ_64M + +/* Environment settings */ +#include + +#define MMCBOOT \ + "mmcdev=0\0" \ + "kernel_partition=2\0" \ + "rootfs_partition=3\0" \ + "mmc_discover_partition=" \ + "part start mmc ${mmcdev} ${kernel_partition} kernel_part_addr;" \ + "part size mmc ${mmcdev} ${kernel_partition} kernel_part_size;\0" \ + "mmcboot=" \ + "mmc dev ${mmcdev};" \ + "run mmc_discover_partition;" \ + "mmc read ${kerneladdr} ${kernel_part_addr} ${kernel_part_size};" \ + "setenv bootargs ${bootargs} root=/dev/mmcblk${mmcdev}p${rootfs_partition} rootwait; " \ + "bootm ${kerneladdr}; \0" + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "kerneladdr=0x4A000000\0" \ + MMCBOOT \ + "bootcmd=run mmcboot;\0" + +#endif diff --git a/include/configs/pumpkin.h b/include/configs/pumpkin.h deleted file mode 100644 index 9c52cae41d7..00000000000 --- a/include/configs/pumpkin.h +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Configuration for Pumpkin board - * - * Copyright (C) 2019 BayLibre, SAS - * Author: Fabien Parent - -#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_TEXT_BASE -#define CONFIG_SYS_MALLOC_LEN SZ_4M - -#define CONFIG_CPU_ARMV8 -#define COUNTER_FREQUENCY 13000000 - -#define CONFIG_SYS_NS16550_SERIAL -#define CONFIG_SYS_NS16550_REG_SIZE -4 -#define CONFIG_SYS_NS16550_MEM32 -#define CONFIG_SYS_NS16550_COM1 0x11005000 -#define CONFIG_SYS_NS16550_CLK 26000000 - -#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_TEXT_BASE + SZ_2M - \ - GENERATED_GBL_DATA_SIZE) - -#define CONFIG_SYS_BOOTM_LEN SZ_64M - -/* Environment settings */ -#include - -#define MMCBOOT \ - "mmcdev=0\0" \ - "kernel_partition=2\0" \ - "rootfs_partition=3\0" \ - "mmc_discover_partition=" \ - "part start mmc ${mmcdev} ${kernel_partition} kernel_part_addr;" \ - "part size mmc ${mmcdev} ${kernel_partition} kernel_part_size;\0" \ - "mmcboot=" \ - "mmc dev ${mmcdev};" \ - "run mmc_discover_partition;" \ - "mmc read ${kerneladdr} ${kernel_part_addr} ${kernel_part_size};" \ - "setenv bootargs ${bootargs} root=/dev/mmcblk${mmcdev}p${rootfs_partition} rootwait; " \ - "bootm ${kerneladdr}; \0" - -#define CONFIG_EXTRA_ENV_SETTINGS \ - "kerneladdr=0x4A000000\0" \ - MMCBOOT \ - "bootcmd=run mmcboot;\0" - -#endif -- cgit v1.3.1 From 21f593214ba2db5fe58c110766ea209e11dbf12d Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Mon, 15 Feb 2021 19:07:46 +0100 Subject: configs: mt8516: use bootcmd from config_distro_bootcmd.h Instead of redefining our own way to boot, let's just use config_distro_bootcmd.h. Signed-off-by: Fabien Parent --- include/configs/mt8516.h | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/configs/mt8516.h b/include/configs/mt8516.h index e809a9c7e30..a1c5d8174be 100644 --- a/include/configs/mt8516.h +++ b/include/configs/mt8516.h @@ -31,23 +31,11 @@ /* Environment settings */ #include -#define MMCBOOT \ - "mmcdev=0\0" \ - "kernel_partition=2\0" \ - "rootfs_partition=3\0" \ - "mmc_discover_partition=" \ - "part start mmc ${mmcdev} ${kernel_partition} kernel_part_addr;" \ - "part size mmc ${mmcdev} ${kernel_partition} kernel_part_size;\0" \ - "mmcboot=" \ - "mmc dev ${mmcdev};" \ - "run mmc_discover_partition;" \ - "mmc read ${kerneladdr} ${kernel_part_addr} ${kernel_part_size};" \ - "setenv bootargs ${bootargs} root=/dev/mmcblk${mmcdev}p${rootfs_partition} rootwait; " \ - "bootm ${kerneladdr}; \0" +#define BOOT_TARGET_DEVICES(func) \ + func(MMC, mmc, 0) #define CONFIG_EXTRA_ENV_SETTINGS \ - "kerneladdr=0x4A000000\0" \ - MMCBOOT \ - "bootcmd=run mmcboot;\0" + "scriptaddr=0x40000000\0" \ + BOOTENV #endif -- cgit v1.3.1 From e96bedf146bdb5ae980ab228165f5f06ef5a168d Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Mon, 15 Feb 2021 19:21:12 +0100 Subject: board: Add MT8183 pumpkin board support Add the MT8183 pumpkin board support. Signed-off-by: Fabien Parent --- arch/arm/dts/Makefile | 1 + arch/arm/dts/mt8183-pumpkin.dts | 99 ++++++++++++++++++++++++++++++++++ arch/arm/mach-mediatek/Kconfig | 1 + board/mediatek/mt8183/Kconfig | 13 +++++ board/mediatek/mt8183/MAINTAINERS | 6 +++ board/mediatek/mt8183/Makefile | 3 ++ board/mediatek/mt8183/mt8183_pumpkin.c | 28 ++++++++++ configs/mt8183_pumpkin_defconfig | 81 ++++++++++++++++++++++++++++ include/configs/mt8183.h | 41 ++++++++++++++ 9 files changed, 273 insertions(+) create mode 100644 arch/arm/dts/mt8183-pumpkin.dts create mode 100644 board/mediatek/mt8183/Kconfig create mode 100644 board/mediatek/mt8183/MAINTAINERS create mode 100644 board/mediatek/mt8183/Makefile create mode 100644 board/mediatek/mt8183/mt8183_pumpkin.c create mode 100644 configs/mt8183_pumpkin_defconfig create mode 100644 include/configs/mt8183.h (limited to 'include') diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index f5fe327b6c3..9a8de46272a 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -1013,6 +1013,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ mt7622-bananapi-bpi-r64.dtb \ mt7623n-bananapi-bpi-r2.dtb \ mt7629-rfb.dtb \ + mt8183-pumpkin.dtb \ mt8512-bm1-emmc.dtb \ mt8516-pumpkin.dtb \ mt8518-ap1-emmc.dtb diff --git a/arch/arm/dts/mt8183-pumpkin.dts b/arch/arm/dts/mt8183-pumpkin.dts new file mode 100644 index 00000000000..470a7693997 --- /dev/null +++ b/arch/arm/dts/mt8183-pumpkin.dts @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Copyright (C) 2021 BayLibre SAS. + * Author: Fabien Parent + */ + +/dts-v1/; + +#include +#include "mt8183.dtsi" + +/ { + model = "MediaTek MT8183 pumpkin board"; + compatible = "mediatek,mt8183-pumpkin", "mediatek,mt8183"; + + memory@40000000 { + device_type = "memory"; + reg = <0 0x40000000 0 0x80000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ + bl31_secmon_reserved: secmon@54600000 { + no-map; + reg = <0 0x54600000 0x0 0x30000>; + }; + + /* 12 MiB reserved for OP-TEE (BL32) + * +-----------------------+ 0x43e0_0000 + * | SHMEM 2MiB | + * +-----------------------+ 0x43c0_0000 + * | | TA_RAM 8MiB | + * + TZDRAM +--------------+ 0x4340_0000 + * | | TEE_RAM 2MiB | + * +-----------------------+ 0x4320_0000 + */ + optee_reserved: optee@43200000 { + no-map; + reg = <0 0x43200000 0 0x00c00000>; + }; + }; + + chosen { + stdout-path = &uart0; + }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; +}; + +&watchdog { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&mmc0 { + bus-width = <4>; + max-frequency = <200000000>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + cap-mmc-hw-reset; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_1p8v>; + non-removable; + status = "okay"; +}; + +&usb { + status = "okay"; +}; + +&ssusb { + mediatek,force-vbus; + maximum-speed = "high-speed"; + dr_mode = "peripheral"; + status = "okay"; +}; diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig index a035471374b..18b7756bdf5 100644 --- a/arch/arm/mach-mediatek/Kconfig +++ b/arch/arm/mach-mediatek/Kconfig @@ -84,6 +84,7 @@ endchoice source "board/mediatek/mt7622/Kconfig" source "board/mediatek/mt7623/Kconfig" source "board/mediatek/mt7629/Kconfig" +source "board/mediatek/mt8183/Kconfig" source "board/mediatek/mt8512/Kconfig" source "board/mediatek/mt8516/Kconfig" source "board/mediatek/mt8518/Kconfig" diff --git a/board/mediatek/mt8183/Kconfig b/board/mediatek/mt8183/Kconfig new file mode 100644 index 00000000000..b75c3b8d806 --- /dev/null +++ b/board/mediatek/mt8183/Kconfig @@ -0,0 +1,13 @@ +if TARGET_MT8183 + +config SYS_BOARD + default "mt8183" + +config SYS_CONFIG_NAME + default "mt8183" + +config MTK_BROM_HEADER_INFO + string + default "media=emmc" + +endif diff --git a/board/mediatek/mt8183/MAINTAINERS b/board/mediatek/mt8183/MAINTAINERS new file mode 100644 index 00000000000..a49995e1bfe --- /dev/null +++ b/board/mediatek/mt8183/MAINTAINERS @@ -0,0 +1,6 @@ +MT8183 Pumpkin +M: Fabien Parent +S: Maintained +F: board/mediatek/mt8183 +F: include/configs/mt8183.h +F: configs/mt8183_pumpkin_defconfig diff --git a/board/mediatek/mt8183/Makefile b/board/mediatek/mt8183/Makefile new file mode 100644 index 00000000000..90b5b72323c --- /dev/null +++ b/board/mediatek/mt8183/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += mt8183_pumpkin.o diff --git a/board/mediatek/mt8183/mt8183_pumpkin.c b/board/mediatek/mt8183/mt8183_pumpkin.c new file mode 100644 index 00000000000..db613ebdc4f --- /dev/null +++ b/board/mediatek/mt8183/mt8183_pumpkin.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 BayLibre SAS + * Author: Fabien Parent + */ + +#include +#include +#include + +int board_init(void) +{ + struct udevice *dev; + int ret; + + if (CONFIG_IS_ENABLED(USB_GADGET)) { + ret = uclass_get_device(UCLASS_USB_GADGET_GENERIC, 0, &dev); + if (ret) { + pr_err("%s: Cannot find USB device\n", __func__); + return ret; + } + } + + if (CONFIG_IS_ENABLED(USB_ETHER)) + usb_ether_init(); + + return 0; +} diff --git a/configs/mt8183_pumpkin_defconfig b/configs/mt8183_pumpkin_defconfig new file mode 100644 index 00000000000..b0bdcb39388 --- /dev/null +++ b/configs/mt8183_pumpkin_defconfig @@ -0,0 +1,81 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_ARCH_MEDIATEK=y +CONFIG_SYS_TEXT_BASE=0x4c000000 +CONFIG_SYS_MALLOC_F_LEN=0x4000 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_ENV_SIZE=0x1000 +CONFIG_ENV_OFFSET=0x0 +CONFIG_DM_GPIO=y +CONFIG_TARGET_MT8183=y +CONFIG_DEBUG_UART_BASE=0x11002000 +CONFIG_DEBUG_UART_CLOCK=26000000 +# CONFIG_PSCI_RESET is not set +CONFIG_DEFAULT_DEVICE_TREE="mt8183-pumpkin" +CONFIG_DEBUG_UART=y +# CONFIG_ANDROID_BOOT_IMAGE is not set +CONFIG_FIT=y +# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set +CONFIG_DEFAULT_FDT_FILE="mt8183-pumpkin" +# CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_HUSH_PARSER=y +# CONFIG_CMD_BDI is not set +# CONFIG_CMD_CONSOLE is not set +# CONFIG_CMD_BOOTD is not set +# CONFIG_CMD_BOOTI is not set +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_GO is not set +# CONFIG_CMD_IMI is not set +# CONFIG_CMD_XIMG is not set +# CONFIG_CMD_EXPORTENV is not set +# CONFIG_CMD_IMPORTENV is not set +# CONFIG_CMD_EDITENV is not set +# CONFIG_CMD_CRC32 is not set +# CONFIG_CMD_MEMORY is not set +CONFIG_CMD_CLK=y +CONFIG_CMD_GPT=y +# CONFIG_RANDOM_UUID is not set +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_PART=y +# CONFIG_CMD_ITEST is not set +# CONFIG_CMD_SETEXPR is not set +# CONFIG_CMD_BLOCK_CACHE is not set +CONFIG_CMD_EXT4=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_ENV_IS_IN_MMC=y +CONFIG_SYS_MMC_ENV_PART=2 +CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y +CONFIG_DEVRES=y +CONFIG_CLK=y +CONFIG_USB_FUNCTION_FASTBOOT=y +CONFIG_FASTBOOT_BUF_ADDR=0x4d000000 +CONFIG_FASTBOOT_BUF_SIZE=0x8000000 +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_FLASH_MMC_DEV=0 +CONFIG_FASTBOOT_MMC_BOOT1_SUPPORT=y +# CONFIG_INPUT is not set +CONFIG_DM_MMC=y +# CONFIG_MMC_QUIRKS is not set +CONFIG_MMC_MTK=y +CONFIG_DM_ETH=y +CONFIG_PHY=y +CONFIG_PHY_MTK_TPHY=y +CONFIG_BAUDRATE=921600 +CONFIG_DM_SERIAL=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_MTK_SERIAL=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_DM_USB_GADGET=y +CONFIG_USB_MTU3=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VENDOR_NUM=0x0e8d +CONFIG_USB_GADGET_PRODUCT_NUM=0x201c +CONFIG_USB_ETHER=y +CONFIG_WDT=y +CONFIG_WDT_MTK=y +# CONFIG_REGEX is not set +CONFIG_OF_LIBFDT_OVERLAY=y +# CONFIG_EFI_LOADER is not set diff --git a/include/configs/mt8183.h b/include/configs/mt8183.h new file mode 100644 index 00000000000..8e7afbb48a7 --- /dev/null +++ b/include/configs/mt8183.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Configuration for MT8183 based boards + * + * Copyright (C) 2021 BayLibre, SAS + * Author: Fabien Parent + +#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_MALLOC_LEN SZ_4M + +#define CONFIG_CPU_ARMV8 +#define COUNTER_FREQUENCY 13000000 + +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_REG_SIZE -4 +#define CONFIG_SYS_NS16550_MEM32 +#define CONFIG_SYS_NS16550_COM1 0x11005200 +#define CONFIG_SYS_NS16550_CLK 26000000 + +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_TEXT_BASE + SZ_2M - \ + GENERATED_GBL_DATA_SIZE) + +#define CONFIG_SYS_BOOTM_LEN SZ_64M + +/* Environment settings */ +#include + +#define BOOT_TARGET_DEVICES(func) \ + func(MMC, mmc, 0) + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "scriptaddr=0x40000000\0" \ + BOOTENV + +#endif -- cgit v1.3.1 From b00f0066e52413e0f8fd4a84681e6e27c4270c26 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 3 Feb 2021 06:01:02 -0700 Subject: dtoc: Support tracking the phase of U-Boot U-Boot operates in several phases, typically TPL, SPL and U-Boot proper. The latter does not use dtoc. In some rare cases different drivers are used for two phases. For example, in TPL it may not be necessary to use the full PCI subsystem, so a simple driver can be used instead. This works in the build system simply by compiling in one driver or the other (e.g. PCI driver + uclass for SPL; simple_bus for TPL). But dtoc has no way of knowing which code is compiled in for which phase, since it does not inspect Makefiles or dependency graphs. So to make this work for dtoc, we need to be able to explicitly mark drivers with their phase. This is done by adding an empty macro to the driver. Add support for this in dtoc. Signed-off-by: Simon Glass --- include/dm/device.h | 16 ++++++++++++++++ tools/dtoc/dtb_platdata.py | 7 +++++-- tools/dtoc/main.py | 5 ++++- tools/dtoc/src_scan.py | 12 +++++++++++- tools/dtoc/test_dtoc.py | 16 ++++++++-------- tools/dtoc/test_src_scan.py | 3 +++ 6 files changed, 47 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/dm/device.h b/include/dm/device.h index bb9faa0ed93..84df5b9e95a 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -369,6 +369,22 @@ struct driver { */ #define DM_DRIVER_ALIAS(__name, __alias) +/** + * Declare a macro to indicate which phase of U-Boot this driver is fore. + * + * + * This macro produces no code but its information will be parsed by dtoc. The + * macro can be only be used once in a driver. Put it within the U_BOOT_DRIVER() + * declaration, e.g.: + * + * U_BOOT_DRIVER(cpu) = { + * .name = ... + * ... + * DM_PHASE(tpl) + * }; + */ +#define DM_PHASE(_phase) + /** * dev_get_plat() - Get the platform data for a device * diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index 28669f31217..ef0454c8904 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -733,7 +733,7 @@ OUTPUT_FILES = { } -def run_steps(args, dtb_file, include_disabled, output, output_dirs, +def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase, warning_disabled=False, drivers_additional=None, basedir=None, scan=None): """Run all the steps of the dtoc tool @@ -746,6 +746,8 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, output_dirs (tuple of str): Directory to put C output files Directory to put H output files + phase: The phase of U-Boot that we are generating data for, e.g. 'spl' + or 'tpl'. None if not known warning_disabled (bool): True to avoid showing warnings about missing drivers drivers_additional (list): List of additional drivers to use during @@ -764,7 +766,8 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, raise ValueError('Must specify either output or output_dirs, not both') if not scan: - scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional) + scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional, + phase) scan.scan_drivers() do_process = True else: diff --git a/tools/dtoc/main.py b/tools/dtoc/main.py index 355b1e62773..15a8ff167a9 100755 --- a/tools/dtoc/main.py +++ b/tools/dtoc/main.py @@ -85,6 +85,8 @@ parser.add_option('--include-disabled', action='store_true', help='Include disabled nodes') parser.add_option('-o', '--output', action='store', help='Select output filename') +parser.add_option('-p', '--phase', type=str, + help='set phase of U-Boot this invocation is for (spl/tpl)') parser.add_option('-P', '--processes', type=int, help='set number of processes to use for running tests') parser.add_option('-t', '--test', action='store_true', dest='test', @@ -104,4 +106,5 @@ elif options.test_coverage: else: dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled, options.output, - [options.c_output_dir, options.h_output_dir]) + [options.c_output_dir, options.h_output_dir], + phase=options.phase) diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py index 1a02d41063f..2699153016c 100644 --- a/tools/dtoc/src_scan.py +++ b/tools/dtoc/src_scan.py @@ -67,6 +67,7 @@ class Driver: child_plat (str): struct name of the per_child_plat_auto member, e.g. 'pci_child_plat' used (bool): True if the driver is used by the structs being output + phase (str): Which phase of U-Boot to use this driver """ def __init__(self, name, fname): self.name = name @@ -78,6 +79,7 @@ class Driver: self.child_priv = '' self.child_plat = '' self.used = False + self.phase = '' def __eq__(self, other): return (self.name == other.name and @@ -173,8 +175,10 @@ class Scanner: _structs: Dict of all structs found in U-Boot: key: Name of struct value: Struct object + _phase: The phase of U-Boot that we are generating data for, e.g. 'spl' + or 'tpl'. None if not known """ - def __init__(self, basedir, warning_disabled, drivers_additional): + def __init__(self, basedir, warning_disabled, drivers_additional, phase=''): """Set up a new Scanner """ if not basedir: @@ -190,6 +194,7 @@ class Scanner: self._compat_to_driver = {} self._uclass = {} self._structs = {} + self._phase = phase def get_driver(self, name): """Get a driver given its name @@ -428,6 +433,8 @@ class Scanner: re_of_match = re.compile( r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)(\))?,') + re_phase = re.compile('^\s*DM_PHASE\((.*)\).*$') + # Matches the struct name for priv, plat re_priv = self._get_re_for_member('priv_auto') re_plat = self._get_re_for_member('plat_auto') @@ -454,6 +461,7 @@ class Scanner: m_plat = re_plat.match(line) m_cplat = re_child_plat.match(line) m_cpriv = re_child_priv.match(line) + m_phase = re_phase.match(line) if m_priv: driver.priv = m_priv.group(1) elif m_plat: @@ -466,6 +474,8 @@ class Scanner: driver.uclass_id = m_id.group(1) elif m_of_match: compat = m_of_match.group(2) + elif m_phase: + driver.phase = m_phase.group(1) elif '};' in line: if driver.uclass_id and compat: if compat not in of_match: diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py index d90ece205d7..c1fafb656fb 100755 --- a/tools/dtoc/test_dtoc.py +++ b/tools/dtoc/test_dtoc.py @@ -138,8 +138,8 @@ class TestDtoc(unittest.TestCase): dtb_file (str): Filename of .dtb file output (str): Filename of output file """ - dtb_platdata.run_steps(args, dtb_file, False, output, [], True, - None, None, scan=copy_scan()) + dtb_platdata.run_steps(args, dtb_file, False, output, [], None, + warning_disabled=True, scan=copy_scan()) def test_name(self): """Test conversion of device tree names to C identifiers""" @@ -365,7 +365,7 @@ U_BOOT_DRVINFO(gpios_at_0) = { output = tools.GetOutputFilename('output') with test_util.capture_sys_output() as _: dtb_platdata.run_steps(['struct'], dtb_file, False, output, [], - scan=copy_scan()) + None, scan=copy_scan()) with open(output) as infile: data = infile.read() self._check_strings(HEADER + ''' @@ -375,7 +375,7 @@ struct dtd_invalid { with test_util.capture_sys_output() as _: dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [], - scan=copy_scan()) + None, scan=copy_scan()) with open(output) as infile: data = infile.read() self._check_strings(C_HEADER + ''' @@ -927,8 +927,8 @@ U_BOOT_DRVINFO(spl_test2) = { def test_output_conflict(self): """Test a conflict between and output dirs and output file""" with self.assertRaises(ValueError) as exc: - dtb_platdata.run_steps(['all'], None, False, 'out', ['cdir'], True, - scan=copy_scan()) + dtb_platdata.run_steps(['all'], None, False, 'out', ['cdir'], None, + warning_disabled=True, scan=copy_scan()) self.assertIn("Must specify either output or output_dirs, not both", str(exc.exception)) @@ -944,8 +944,8 @@ U_BOOT_DRVINFO(spl_test2) = { fnames = glob.glob(outdir + '/*') self.assertEqual(2, len(fnames)) - dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], True, - scan=copy_scan()) + dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], None, + warning_disabled=True, scan=copy_scan()) fnames = glob.glob(outdir + '/*') self.assertEqual(4, len(fnames)) diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py index ebdc12abc87..8d35b33c28a 100644 --- a/tools/dtoc/test_src_scan.py +++ b/tools/dtoc/test_src_scan.py @@ -233,6 +233,7 @@ U_BOOT_DRIVER(i2c_tegra) = { self.assertIn('i2c_tegra', scan._drivers) drv = scan._drivers['i2c_tegra'] self.assertEqual('i2c_tegra', drv.name) + self.assertEqual('', drv.phase) def test_priv(self): """Test collection of struct info from drivers""" @@ -250,6 +251,7 @@ U_BOOT_DRIVER(testing) = { .plat_auto = sizeof(struct some_plat), .per_child_auto = sizeof(struct some_cpriv), .per_child_plat_auto = sizeof(struct some_cplat), + DM_PHASE(tpl) }; ''' scan = src_scan.Scanner(None, False, None) @@ -264,6 +266,7 @@ U_BOOT_DRIVER(testing) = { self.assertEqual('some_plat', drv.plat) self.assertEqual('some_cpriv', drv.child_priv) self.assertEqual('some_cplat', drv.child_plat) + self.assertEqual('tpl', drv.phase) self.assertEqual(1, len(scan._drivers)) def test_uclass_scan(self): -- cgit v1.3.1 From 735ddfc638bf3ffdf6888f5502bddbbfa6b3636e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 3 Feb 2021 06:01:04 -0700 Subject: dtoc: Support headers needed for drivers Typically dtoc can detect the header file needed for a driver by looking for the structs that it uses. For example, if a driver as a .priv_auto that uses 'struct serial_priv', then dtoc can search header files for the definition of that struct and use the file. In some cases, enums are used in drivers, typically with the .data field of struct udevice_id. Since dtoc does not support searching for these, add a way to tell dtoc which header to use. This works as a macro included in the driver definition. Signed-off-by: Simon Glass --- include/dm/device.h | 18 ++++++++++++++++++ tools/dtoc/src_scan.py | 7 +++++++ tools/dtoc/test_src_scan.py | 4 ++++ 3 files changed, 29 insertions(+) (limited to 'include') diff --git a/include/dm/device.h b/include/dm/device.h index 84df5b9e95a..45010b4df92 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -385,6 +385,24 @@ struct driver { */ #define DM_PHASE(_phase) +/** + * Declare a macro to declare a header needed for a driver. Often the correct + * header can be found automatically, but only for struct declarations. For + * enums and #defines used in the driver declaration and declared in a different + * header from the structs, this macro must be used. + * + * This macro produces no code but its information will be parsed by dtoc. The + * macro can be used multiple times with different headers, for the same driver. + * Put it within the U_BOOT_DRIVER() declaration, e.g.: + * + * U_BOOT_DRIVER(cpu) = { + * .name = ... + * ... + * DM_HEADER() + * }; + */ +#define DM_HEADER(_hdr) + /** * dev_get_plat() - Get the platform data for a device * diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py index 2699153016c..206b2b37583 100644 --- a/tools/dtoc/src_scan.py +++ b/tools/dtoc/src_scan.py @@ -68,6 +68,8 @@ class Driver: e.g. 'pci_child_plat' used (bool): True if the driver is used by the structs being output phase (str): Which phase of U-Boot to use this driver + headers (list): List of header files needed for this driver (each a str) + e.g. [''] """ def __init__(self, name, fname): self.name = name @@ -80,6 +82,7 @@ class Driver: self.child_plat = '' self.used = False self.phase = '' + self.headers = [] def __eq__(self, other): return (self.name == other.name and @@ -434,6 +437,7 @@ class Scanner: r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)(\))?,') re_phase = re.compile('^\s*DM_PHASE\((.*)\).*$') + re_hdr = re.compile('^\s*DM_HEADER\((.*)\).*$') # Matches the struct name for priv, plat re_priv = self._get_re_for_member('priv_auto') @@ -462,6 +466,7 @@ class Scanner: m_cplat = re_child_plat.match(line) m_cpriv = re_child_priv.match(line) m_phase = re_phase.match(line) + m_hdr = re_hdr.match(line) if m_priv: driver.priv = m_priv.group(1) elif m_plat: @@ -476,6 +481,8 @@ class Scanner: compat = m_of_match.group(2) elif m_phase: driver.phase = m_phase.group(1) + elif m_hdr: + driver.headers.append(m_hdr.group(1)) elif '};' in line: if driver.uclass_id and compat: if compat not in of_match: diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py index 8d35b33c28a..245b7302fd6 100644 --- a/tools/dtoc/test_src_scan.py +++ b/tools/dtoc/test_src_scan.py @@ -234,6 +234,7 @@ U_BOOT_DRIVER(i2c_tegra) = { drv = scan._drivers['i2c_tegra'] self.assertEqual('i2c_tegra', drv.name) self.assertEqual('', drv.phase) + self.assertEqual([], drv.headers) def test_priv(self): """Test collection of struct info from drivers""" @@ -252,6 +253,8 @@ U_BOOT_DRIVER(testing) = { .per_child_auto = sizeof(struct some_cpriv), .per_child_plat_auto = sizeof(struct some_cplat), DM_PHASE(tpl) + DM_HEADER() + DM_HEADER() }; ''' scan = src_scan.Scanner(None, False, None) @@ -267,6 +270,7 @@ U_BOOT_DRIVER(testing) = { self.assertEqual('some_cpriv', drv.child_priv) self.assertEqual('some_cplat', drv.child_plat) self.assertEqual('tpl', drv.phase) + self.assertEqual(['', ''], drv.headers) self.assertEqual(1, len(scan._drivers)) def test_uclass_scan(self): -- cgit v1.3.1 From ea74c95103c66282b8c43e7893bdcd533cab220f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 3 Feb 2021 06:01:20 -0700 Subject: dtoc: Generate uclass devices Add support for generating a file containing uclass instances. This avoids the need to create these at run time. Update a test uclass to include a 'priv_auto' member, to increase test coverage. Signed-off-by: Simon Glass --- drivers/misc/test_drv.c | 1 + include/dm/test.h | 5 ++ tools/dtoc/dtb_platdata.py | 93 +++++++++++++++++++++++++ tools/dtoc/test_dtoc.py | 164 +++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 250 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/misc/test_drv.c b/drivers/misc/test_drv.c index a2a77d36bbf..f431a576f19 100644 --- a/drivers/misc/test_drv.c +++ b/drivers/misc/test_drv.c @@ -205,6 +205,7 @@ UCLASS_DRIVER(testfdt) = { .name = "testfdt", .id = UCLASS_TEST_FDT, .flags = DM_UC_FLAG_SEQ_ALIAS, + .priv_auto = sizeof(struct dm_test_uc_priv), }; static const struct udevice_id testfdtm_ids[] = { diff --git a/include/dm/test.h b/include/dm/test.h index fe1cc2e278c..30f71edbd96 100644 --- a/include/dm/test.h +++ b/include/dm/test.h @@ -71,6 +71,11 @@ struct dm_test_priv { int uclass_postp; }; +/* struct dm_test_uc_priv - private data for the testdrv uclass */ +struct dm_test_uc_priv { + int dummy; +}; + /** * struct dm_test_perdev_class_priv - private per-device data for test uclass */ diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index ab26c4adca5..6dadf37582f 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -246,6 +246,7 @@ class DtbPlatdata(): """ if self._outfile != sys.stdout: self._outfile.close() + self._outfile = None def out(self, line): """Output a string to the output file @@ -649,6 +650,27 @@ class DtbPlatdata(): self.buf('};\n') self.buf('\n') + def prep_priv(self, struc, name, suffix, section='.priv_data'): + if not struc: + return None + var_name = '_%s%s' % (name, suffix) + hdr = self._scan._structs.get(struc) + if hdr: + self.buf('#include <%s>\n' % hdr.fname) + else: + print('Warning: Cannot find header file for struct %s' % struc) + attr = '__attribute__ ((section ("%s")))' % section + return var_name, struc, attr + + def alloc_priv(self, info, name, extra, suffix='_priv'): + result = self.prep_priv(info, name, suffix) + if not result: + return None + var_name, struc, section = result + self.buf('u8 %s_%s[sizeof(struct %s)]\n\t%s;\n' % + (var_name, extra, struc.strip(), section)) + return '%s_%s' % (var_name, extra) + def _output_prop(self, node, prop): """Output a line containing the value of a struct member @@ -680,6 +702,74 @@ class DtbPlatdata(): self._output_prop(node, node.props[pname]) self.buf('};\n') + def list_head(self, head_member, node_member, node_refs, var_name): + self.buf('\t.%s\t= {\n' % head_member) + if node_refs: + last = node_refs[-1].dev_ref + first = node_refs[0].dev_ref + member = node_member + else: + last = 'DM_DEVICE_REF(%s)' % var_name + first = last + member = head_member + self.buf('\t\t.prev = &%s->%s,\n' % (last, member)) + self.buf('\t\t.next = &%s->%s,\n' % (first, member)) + self.buf('\t},\n') + + def list_node(self, member, node_refs, seq): + self.buf('\t.%s\t= {\n' % member) + self.buf('\t\t.prev = %s,\n' % node_refs[seq - 1]) + self.buf('\t\t.next = %s,\n' % node_refs[seq + 1]) + self.buf('\t},\n') + + def generate_uclasses(self): + if not self.check_instantiate(True): + return + self.out('\n') + self.out('#include \n') + self.out('#include \n') + self.out('#include \n') + self.out('\n') + self.buf('/*\n') + self.buf(' * uclass declarations\n') + self.buf(' *\n') + self.buf(' * Sequence numbers:\n') + uclass_list = self._valid_uclasses + for uclass in uclass_list: + if uclass.alias_num_to_node: + self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id)) + for seq, node in uclass.alias_num_to_node.items(): + self.buf(' * %d: %s\n' % (seq, node.path)) + self.buf(' */\n') + + uclass_node = {} + for seq, uclass in enumerate(uclass_list): + uclass_node[seq] = ('&DM_UCLASS_REF(%s)->sibling_node' % + uclass.name) + uclass_node[-1] = '&uclass_head' + uclass_node[len(uclass_list)] = '&uclass_head' + self.buf('\n') + self.buf('struct list_head %s = {\n' % 'uclass_head') + self.buf('\t.prev = %s,\n' % uclass_node[len(uclass_list) -1]) + self.buf('\t.next = %s,\n' % uclass_node[0]) + self.buf('};\n') + self.buf('\n') + + for seq, uclass in enumerate(uclass_list): + uc_drv = self._scan._uclass.get(uclass.uclass_id) + + priv_name = self.alloc_priv(uc_drv.priv, uc_drv.name, '') + + self.buf('DM_UCLASS_INST(%s) = {\n' % uclass.name) + if priv_name: + self.buf('\t.priv_\t\t= %s,\n' % priv_name) + self.buf('\t.uc_drv\t\t= DM_UCLASS_DRIVER_REF(%s),\n' % uclass.name) + self.list_node('sibling_node', uclass_node, seq) + self.list_head('dev_head', 'uclass_node', uc_drv.devs, None) + self.buf('};\n') + self.buf('\n') + self.out(''.join(self.get_buf())) + def read_aliases(self): """Read the aliases and attach the information to self._alias @@ -894,6 +984,9 @@ OUTPUT_FILES = { 'platdata': OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat, 'Declares the U_BOOT_DRIVER() records and platform data'), + 'uclass': + OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses, + 'Declares the uclass instances (struct uclass)'), } diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py index 56d5c8d6b38..053d140664e 100755 --- a/tools/dtoc/test_dtoc.py +++ b/tools/dtoc/test_dtoc.py @@ -16,6 +16,7 @@ import os import struct import unittest +from dtb_platdata import Ftype from dtb_platdata import get_value from dtb_platdata import tab_to from dtoc import dtb_platdata @@ -65,6 +66,18 @@ C_HEADER = C_HEADER_PRE + ''' #include ''' +UCLASS_HEADER_COMMON = '''/* + * DO NOT MODIFY + * + * Declares the uclass instances (struct uclass). + * This was generated by dtoc from a .dtb (device tree binary) file. + */ +''' + +UCLASS_HEADER = UCLASS_HEADER_COMMON + ''' +/* This file is not used: --instantiate was not enabled */ +''' + # Scanner saved from a previous run of the tests (to speed things up) saved_scan = None @@ -245,31 +258,35 @@ DM_UCLASS_DRIVER_DECL(pmic); /* driver declarations - these allow DM_DRIVER_GET() to be used */ DM_DRIVER_DECL(sandbox_i2c); -DM_DRIVER_DECL(sandbox_pmic); DM_DRIVER_DECL(root_driver); +DM_DRIVER_DECL(denx_u_boot_test_bus); DM_DRIVER_DECL(sandbox_spl_test); DM_DRIVER_DECL(sandbox_spl_test); -DM_DRIVER_DECL(sandbox_spl_test); +DM_DRIVER_DECL(denx_u_boot_fdt_test); +DM_DRIVER_DECL(denx_u_boot_fdt_test); /* device declarations - these allow DM_DEVICE_REF() to be used */ -DM_DEVICE_DECL(i2c_at_0); -DM_DEVICE_DECL(pmic_at_9); +DM_DEVICE_DECL(i2c); DM_DEVICE_DECL(root); +DM_DEVICE_DECL(some_bus); DM_DEVICE_DECL(spl_test); -DM_DEVICE_DECL(spl_test2); DM_DEVICE_DECL(spl_test3); +DM_DEVICE_DECL(test); +DM_DEVICE_DECL(test0); /* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */ DM_UCLASS_DRIVER_DECL(i2c); DM_UCLASS_DRIVER_DECL(misc); -DM_UCLASS_DRIVER_DECL(pmic); DM_UCLASS_DRIVER_DECL(root); +DM_UCLASS_DRIVER_DECL(testbus); +DM_UCLASS_DRIVER_DECL(testfdt); /* uclass declarations - needed for DM_UCLASS_REF() */ DM_UCLASS_DECL(i2c); DM_UCLASS_DECL(misc); -DM_UCLASS_DECL(pmic); DM_UCLASS_DECL(root); +DM_UCLASS_DECL(testbus); +DM_UCLASS_DECL(testfdt); ''' struct_text = HEADER + ''' struct dtd_sandbox_i2c { @@ -394,6 +411,101 @@ U_BOOT_DRVINFO(spl_test3) = { \t.parent_idx\t= -1, }; +''' + uclass_text = UCLASS_HEADER + uclass_text_inst = ''' + +#include +#include +#include + +/* + * uclass declarations + * + * Sequence numbers: + * i2c: UCLASS_I2C + * 4: /i2c + * misc: UCLASS_MISC + * 0: /spl-test + * 1: /spl-test3 + * root: UCLASS_ROOT + * 0: / + * testbus: UCLASS_TEST_BUS + * 2: /some-bus + * testfdt: UCLASS_TEST_FDT + * 1: /some-bus/test + * 2: /some-bus/test0 + */ + +struct list_head uclass_head = { + .prev = &DM_UCLASS_REF(testfdt)->sibling_node, + .next = &DM_UCLASS_REF(i2c)->sibling_node, +}; + +DM_UCLASS_INST(i2c) = { + .uc_drv = DM_UCLASS_DRIVER_REF(i2c), + .sibling_node = { + .prev = &uclass_head, + .next = &DM_UCLASS_REF(misc)->sibling_node, + }, + .dev_head = { + .prev = &DM_DEVICE_REF(i2c)->uclass_node, + .next = &DM_DEVICE_REF(i2c)->uclass_node, + }, +}; + +DM_UCLASS_INST(misc) = { + .uc_drv = DM_UCLASS_DRIVER_REF(misc), + .sibling_node = { + .prev = &DM_UCLASS_REF(i2c)->sibling_node, + .next = &DM_UCLASS_REF(root)->sibling_node, + }, + .dev_head = { + .prev = &DM_DEVICE_REF(spl_test3)->uclass_node, + .next = &DM_DEVICE_REF(spl_test)->uclass_node, + }, +}; + +DM_UCLASS_INST(root) = { + .uc_drv = DM_UCLASS_DRIVER_REF(root), + .sibling_node = { + .prev = &DM_UCLASS_REF(misc)->sibling_node, + .next = &DM_UCLASS_REF(testbus)->sibling_node, + }, + .dev_head = { + .prev = &DM_DEVICE_REF(root)->uclass_node, + .next = &DM_DEVICE_REF(root)->uclass_node, + }, +}; + +DM_UCLASS_INST(testbus) = { + .uc_drv = DM_UCLASS_DRIVER_REF(testbus), + .sibling_node = { + .prev = &DM_UCLASS_REF(root)->sibling_node, + .next = &DM_UCLASS_REF(testfdt)->sibling_node, + }, + .dev_head = { + .prev = &DM_DEVICE_REF(some_bus)->uclass_node, + .next = &DM_DEVICE_REF(some_bus)->uclass_node, + }, +}; + +#include +u8 _testfdt_priv_[sizeof(struct dm_test_uc_priv)] + __attribute__ ((section (".priv_data"))); +DM_UCLASS_INST(testfdt) = { + .priv_ = _testfdt_priv_, + .uc_drv = DM_UCLASS_DRIVER_REF(testfdt), + .sibling_node = { + .prev = &DM_UCLASS_REF(testbus)->sibling_node, + .next = &uclass_head, + }, + .dev_head = { + .prev = &DM_DEVICE_REF(test0)->uclass_node, + .next = &DM_DEVICE_REF(test)->uclass_node, + }, +}; + ''' def test_simple(self): @@ -422,7 +534,7 @@ U_BOOT_DRVINFO(spl_test3) = { self.run_test(['all'], dtb_file, output) data = tools.ReadFile(output, binary=False) self._check_strings(self.decl_text + self.platdata_text + - self.struct_text, data) + self.struct_text + self.uclass_text, data) def test_driver_alias(self): """Test output from a device tree file with a driver alias""" @@ -1125,7 +1237,7 @@ U_BOOT_DRVINFO(spl_test2) = { self.run_test(['all'], dtb_file, output) data = tools.ReadFile(output, binary=False) self._check_strings(self.decl_text + self.platdata_text + - self.struct_text, data) + self.struct_text + self.uclass_text, data) def test_no_command(self): """Test running dtoc without a command""" @@ -1141,7 +1253,7 @@ U_BOOT_DRVINFO(spl_test2) = { with self.assertRaises(ValueError) as exc: self.run_test(['invalid-cmd'], dtb_file, output) self.assertIn( - "Unknown command 'invalid-cmd': (use: decl, platdata, struct)", + "Unknown command 'invalid-cmd': (use: decl, platdata, struct, uclass)", str(exc.exception)) def test_output_conflict(self): @@ -1169,12 +1281,12 @@ U_BOOT_DRVINFO(spl_test2) = { ['all'], dtb_file, False, None, [outdir], None, False, warning_disabled=True, scan=copy_scan()) fnames = glob.glob(outdir + '/*') - self.assertEqual(5, len(fnames)) + self.assertEqual(6, len(fnames)) leafs = set(os.path.basename(fname) for fname in fnames) self.assertEqual( {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb', - 'dt-decl.h'}, + 'dt-uclass.c', 'dt-decl.h'}, leafs) def setup_process_test(self): @@ -1363,7 +1475,7 @@ U_BOOT_DRVINFO(spl_test2) = { def test_simple_inst(self): """Test output from some simple nodes with instantiate enabled""" - dtb_file = get_dtb_file('dtoc_test_simple.dts') + dtb_file = get_dtb_file('dtoc_test_inst.dts') output = tools.GetOutputFilename('output') self.run_test(['decl'], dtb_file, output, True) @@ -1379,3 +1491,29 @@ U_BOOT_DRVINFO(spl_test2) = { self._check_strings(C_HEADER_PRE + ''' /* This file is not used: --instantiate was enabled */ ''', data) + + self.run_test(['uclass'], dtb_file, output, True) + with open(output) as infile: + data = infile.read() + + self._check_strings(UCLASS_HEADER_COMMON + self.uclass_text_inst, data) + + def test_inst_no_hdr(self): + """Test dealing with a struct that has no header""" + dtb_file = get_dtb_file('dtoc_test_inst.dts') + output = tools.GetOutputFilename('output') + + # Run it once to set everything up + plat = self.run_test(['decl'], dtb_file, output, True) + scan = plat._scan + + # Restart the output file and delete any record of the uclass' struct + plat.setup_output(Ftype.SOURCE, output) + del scan._structs['dm_test_uc_priv'] + + # Now generate the uclasses, which should provide a warning + with test_util.capture_sys_output() as (stdout, _): + plat.generate_uclasses() + self.assertEqual( + 'Warning: Cannot find header file for struct dm_test_uc_priv', + stdout.getvalue().strip()) -- cgit v1.3.1 From 851144350b6ff1d4982b9af2f9b0fe48aed24b3c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:13 +1300 Subject: linker_lists: Allow use in data structures At present linker lists are designed for use in code. They make use of statements within expressions ({...}), for example. It is possible to generate a reference to a linker_list entry that can be used in data structures, where such features are not permitted. It requires that the reference first be declared as extern. In other words the existing macro needs to be split into two parts. Add new macros to support this. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- include/linker_lists.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include') diff --git a/include/linker_lists.h b/include/linker_lists.h index fd98ecd297c..0ca30da4172 100644 --- a/include/linker_lists.h +++ b/include/linker_lists.h @@ -211,6 +211,18 @@ _ll_result; \ }) +/** + * ll_entry_ref() - Get a reference to a linker-generated array entry + * + * Once ll_entry_decl() has been used to declare the reference, this macro + * allows the entry to be accessed. + * + * This is like ll_entry_get(), but without the extra code, so it is suitable + * for putting into data structures. + */ +#define ll_entry_ref(_type, _name, _list) \ + ((_type *)&_u_boot_list_2_##_list##_2_##_name) + /** * ll_start() - Point to first entry of first linker-generated array * @_type: Data type of the entry -- cgit v1.3.1 From 607f9bcb0d0af57c52bacf4d3aeb3a7d389ea206 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:14 +1300 Subject: dm: core: Add macros to access the new linker lists Add macros which work with instantiated devices and uclasses, as created at build time by dtoc. Include variants that can be used in data structures. These are mostly used by dtoc but it is worth documenting them fully for the occasional case where they might come up in user code. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- include/dm/device-internal.h | 75 ++++++++++++++++++++++++++++++++++++++++++++ include/dm/device.h | 22 +++++++++++++ include/dm/uclass-internal.h | 49 +++++++++++++++++++++++++++++ include/dm/uclass.h | 31 ++++++++++++++++++ include/linker_lists.h | 4 +-- 5 files changed, 179 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 39406c3f352..71e5c75028d 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -10,11 +10,86 @@ #ifndef _DM_DEVICE_INTERNAL_H #define _DM_DEVICE_INTERNAL_H +#include #include struct device_node; struct udevice; +/* + * These two macros DM_DEVICE_INST and DM_DEVICE_REF are only allowed in code + * generated by dtoc, because the ordering is important and if other instances + * creep in then they may mess up the ordering expected by dtoc. + * + * It is OK to use them with 'extern' though, since that does not actually + * add a new record to the linker_list. + */ + +/** + * DM_DEVICE_INST() - Declare a bound device ready for run-time use + * + * This adds an actual struct udevice to a list which is found by driver model + * on start-up. + * + * For example: + * + * extern U_BOOT_DRIVER(sandbox_fixed_clock); + * extern DM_UCLASS_INST(clk); + * + * DM_DEVICE_INST(clk_fixed) = { + * .driver = DM_DRIVER_REF(sandbox_fixed_clock), + * .name = "sandbox_fixed_clock", + * .plat_ = &_sandbox_fixed_clock_plat_clk_fixed, + * .uclass = DM_UCLASS_REF(clk), + * ... + * .seq_ = 0, + * }; + * + * @_name: Name of the udevice. This must be a valid C identifier, used by the + * linker_list. + */ +#define DM_DEVICE_INST(_name) \ + ll_entry_declare(struct udevice, _name, udevice) + +/** + * DM_DEVICE_REF() - Get a reference to a device + * + * This is useful in data structures and code for referencing a udevice at + * build time. Before this is used, an extern DM_DEVICE_INST() must have been + * declared. + * + * For example: + * + * extern DM_DEVICE_INST(clk_fixed); + * + * struct udevice *devs[] = { + * DM_DEVICE_REF(clk_fixed), + * }; + * + * @_name: Name of the udevice. This must be a valid C identifier, used by the + * linker_list + * @returns struct udevice * for the device + */ +#define DM_DEVICE_REF(_name) \ + ll_entry_ref(struct udevice, _name, udevice) + +/** + * DM_DEVICE_GET() - Get a pointer to a given device + * + * This is similar to DM_DEVICE_REF() except that it does not need the extern + * declaration before it. However it cannot be used in a data structures, only + * in code within a function. + * + * For example: + * + * void some_function() { + * struct udevice *dev = DM_DEVICE_GET(clk_fixed); + * ... + * } + */ +#define DM_DEVICE_GET(__name) \ + ll_entry_get(struct udevice, __name, udevice) + /** * device_bind() - Create a device and bind it to a driver * diff --git a/include/dm/device.h b/include/dm/device.h index 45010b4df92..5b8f27d455b 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -362,6 +362,28 @@ struct driver { #define DM_DRIVER_GET(__name) \ ll_entry_get(struct driver, __name, driver) +/** + * DM_DRIVER_REF() - Get a reference to a driver + * + * This is useful in data structures and code for referencing a driver at + * build time. Before this is used, an extern U_BOOT_DRIVER() must have been + * declared. + * + * For example: + * + * extern U_BOOT_DRIVER(sandbox_fixed_clock); + * + * struct driver *drvs[] = { + * DM_DRIVER_REF(sandbox_fixed_clock), + * }; + * + * @_name: Name of the driver. This must be a valid C identifier, used by the + * linker_list + * @returns struct driver * for the driver + */ +#define DM_DRIVER_REF(_name) \ + ll_entry_ref(struct driver, _name, driver) + /** * Declare a macro to state a alias for a driver name. This macro will * produce no code but its information will be parsed by tools like diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h index c5a464be7c4..f2a780682b4 100644 --- a/include/dm/uclass-internal.h +++ b/include/dm/uclass-internal.h @@ -11,6 +11,55 @@ #include +/* + * These next two macros DM_UCLASS_INST() and DM_UCLASS_REF() are only allowed + * in code generated by dtoc, because the ordering is important and if other + * instances creep in then they may mess up the ordering expected by dtoc. + * + * It is OK to use them with 'extern' though, since that does not actually + * add a new record to the linker_list. + */ + +/** + * DM_UCLASS_INST() - Declare a uclass ready for run-time use + * + * This adds an actual struct uclass to a list which is found by driver model + * on start-up. + * + * For example: + * + * DM_UCLASS_INST(clk) = { + * .uc_drv = DM_UCLASS_DRIVER_REF(clk), + * ... + * }; + * + * @_name: Name of the uclass. This must be a valid C identifier, used by the + * linker_list. + */ +#define DM_UCLASS_INST(_name) \ + ll_entry_declare(struct uclass, _name, uclass) + +/** + * DM_UCLASS_REF() - Get a reference to a uclass + * + * This is useful for referencing a uclass at build time. Before this is used, + * an extern DM_UCLASS_INST() must have been declared. + * + * For example: + * + * extern DM_UCLASS_INST(clk); + * + * struct uclass *ucs[] = { + * DM_UCLASS_REF(clk), + * } + * + * @_name: Name of the uclass. This must be a valid C identifier, used by the + * linker_list + * @returns struct uclass * for the device + */ +#define DM_UCLASS_REF(_name) \ + ll_entry_ref(struct uclass, _name, uclass) + /** * uclass_set_priv() - Set the private data for a uclass * diff --git a/include/dm/uclass.h b/include/dm/uclass.h index d95683740cb..6752d8ee0be 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -114,6 +114,37 @@ struct uclass_driver { #define UCLASS_DRIVER(__name) \ ll_entry_declare(struct uclass_driver, __name, uclass_driver) +/* + * These two macros DM_UCLASS_DRIVER_REF and DM_UCLASS_DRIVER_REF are only + * allowed in code generated by dtoc, because the ordering is important and if + * other instances creep in then they may mess up the ordering expected by dtoc. + * + * It is OK to use them with 'extern' though, since that does not actually + * add a new record to the linker_list. + */ + +/** + * DM_UCLASS_DRIVER_REF() - Get a reference to a uclass driver + * + * This is useful in data structures and code for referencing a uclass_driver at + * build time. Before this is used, an extern UCLASS_DRIVER() must have been + * declared. + * + * For example: + * + * extern UCLASS_DRIVER(clk); + * + * struct uclass_driver *drvs[] = { + * DM_UCLASS_DRIVER_REF(clk), + * }; + * + * @_name: Name of the uclass_driver. This must be a valid C identifier, used by + * the linker_list. + * @returns struct uclass_driver * for the uclass driver + */ +#define DM_UCLASS_DRIVER_REF(_name) \ + ll_entry_ref(struct uclass_driver, _name, uclass_driver) + /** * uclass_get_priv() - Get the private data for a uclass * diff --git a/include/linker_lists.h b/include/linker_lists.h index 0ca30da4172..81a280a8841 100644 --- a/include/linker_lists.h +++ b/include/linker_lists.h @@ -214,8 +214,8 @@ /** * ll_entry_ref() - Get a reference to a linker-generated array entry * - * Once ll_entry_decl() has been used to declare the reference, this macro - * allows the entry to be accessed. + * Once an extern ll_entry_declare() has been used to declare the reference, + * this macro allows the entry to be accessed. * * This is like ll_entry_get(), but without the extra code, so it is suitable * for putting into data structures. -- cgit v1.3.1 From 3fa9f553c0c0418b9abf93c2f33a44c98380beaf Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:16 +1300 Subject: dm: core: Adjust uclass setup with of-platdata When OF_PLATDATA_INST is enabled we don't need to create the uclass list. Instead we just need to point to the existing list. Update the code accordingly. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- drivers/core/root.c | 8 ++++++-- include/dm/root.h | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/core/root.c b/drivers/core/root.c index 9bc682cffea..3feadb77b56 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -140,8 +140,12 @@ int dm_init(bool of_live) dm_warn("Virtual root driver already exists!\n"); return -EINVAL; } - gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST; - INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST); + if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) { + gd->uclass_root = &uclass_head; + } else { + gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST; + INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST); + } if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) { fix_drivers(); diff --git a/include/dm/root.h b/include/dm/root.h index 89afbee6196..42510b106ab 100644 --- a/include/dm/root.h +++ b/include/dm/root.h @@ -11,6 +11,9 @@ struct udevice; +/* Head of the uclass list if CONFIG_OF_PLATDATA_INST is enabled */ +extern struct list_head uclass_head; + /** * dm_root() - Return pointer to the top of the driver tree * -- cgit v1.3.1 From f027222ad8c7488bab6f4e5b6ab77104081842c6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 19 Mar 2021 02:49:54 +0100 Subject: efi_loader: Uart device path When uploading an EFI binary via the UART we need to assign a device path. * Provide devicepath node to text conversion for Uart() node. * Provide function to create Uart() device path. * Add UART support to efi_dp_from_name(). Signed-off-by: Heinrich Schuchardt --- include/efi_api.h | 10 ++++++++ lib/efi_loader/efi_device_path.c | 41 +++++++++++++++++++++++++------- lib/efi_loader/efi_device_path_to_text.c | 13 ++++++++++ 3 files changed, 55 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 48e48a6263b..4ccde1d24da 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -523,6 +523,7 @@ struct efi_device_path_acpi_path { # define DEVICE_PATH_SUB_TYPE_MSG_SCSI 0x02 # define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05 # define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b +# define DEVICE_PATH_SUB_TYPE_MSG_UART 0x0e # define DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS 0x0f # define DEVICE_PATH_SUB_TYPE_MSG_SATA 0x12 # define DEVICE_PATH_SUB_TYPE_MSG_NVME 0x17 @@ -542,6 +543,15 @@ struct efi_device_path_scsi { u16 logical_unit_number; } __packed; +struct efi_device_path_uart { + struct efi_device_path dp; + u32 reserved; + u64 baud_rate; + u8 data_bits; + u8 parity; + u8 stop_bits; +} __packed; + struct efi_device_path_usb { struct efi_device_path dp; u8 parent_port_number; diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index c9315dd4585..398dbc699bb 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -960,6 +960,28 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part, return start; } +struct efi_device_path *efi_dp_from_uart(void) +{ + void *buf, *pos; + struct efi_device_path_uart *uart; + size_t dpsize = sizeof(ROOT) + sizeof(*uart) + sizeof(END); + + buf = dp_alloc(dpsize); + if (!buf) + return NULL; + pos = buf; + memcpy(pos, &ROOT, sizeof(ROOT)); + pos += sizeof(ROOT); + uart = pos; + uart->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; + uart->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_UART; + uart->dp.length = sizeof(*uart); + pos += sizeof(*uart); + memcpy(pos, &END, sizeof(END)); + + return buf; +} + #ifdef CONFIG_NET struct efi_device_path *efi_dp_from_eth(void) { @@ -1086,7 +1108,6 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, struct efi_device_path **device, struct efi_device_path **file) { - int is_net; struct blk_desc *desc = NULL; struct disk_partition fs_partition; int part = 0; @@ -1096,8 +1117,15 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, if (path && !file) return EFI_INVALID_PARAMETER; - is_net = !strcmp(dev, "Net"); - if (!is_net) { + if (!strcmp(dev, "Net")) { +#ifdef CONFIG_NET + if (device) + *device = efi_dp_from_eth(); +#endif + } else if (!strcmp(dev, "Uart")) { + if (device) + *device = efi_dp_from_uart(); + } else { part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition, 1); if (part < 0 || !desc) @@ -1105,11 +1133,6 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, if (device) *device = efi_dp_from_part(desc, part); - } else { -#ifdef CONFIG_NET - if (device) - *device = efi_dp_from_eth(); -#endif } if (!path) @@ -1120,7 +1143,7 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, s = filename; while ((s = strchr(s, '/'))) *s++ = '\\'; - *file = efi_dp_from_file(is_net ? NULL : desc, part, filename); + *file = efi_dp_from_file(desc, part, filename); if (!*file) return EFI_INVALID_PARAMETER; diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index edc9fdc3870..43554cd771b 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -118,6 +118,19 @@ static char *dp_msging(char *s, struct efi_device_path *dp) ide->logical_unit_number); break; } + case DEVICE_PATH_SUB_TYPE_MSG_UART: { + struct efi_device_path_uart *uart = + (struct efi_device_path_uart *)dp; + s += sprintf(s, "Uart(%lld,%d,%d,", uart->baud_rate, + uart->data_bits, uart->parity); + switch (uart->stop_bits) { + case 2: + s += sprintf(s, "1.5)"); + default: + s += sprintf(s, "%d)", uart->stop_bits); + } + break; + } case DEVICE_PATH_SUB_TYPE_MSG_USB: { struct efi_device_path_usb *udp = (struct efi_device_path_usb *)dp; -- cgit v1.3.1 From 76e8acce12fe6e914fdab422c8af44956c1dac04 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Wed, 17 Mar 2021 21:54:58 +0200 Subject: efi_loader: Add device path related functions for initrd via Boot#### On the following patches we allow for an initrd path to be stored in Boot#### variables. Specifically we encode in the FIlePathList[] of the EFI_LOAD_OPTIONS for each Boot#### variable. The FilePathList[] array looks like this: kernel - 0xff - VenMedia(initrd GUID) - initrd1 - 0x01 initrd2 - 0xff So let's add the relevant functions to concatenate and retrieve a device path based on a Vendor GUID. Signed-off-by: Ilias Apalodimas Reformat function descriptions. Reviewed-by: Heinrich Schuchardt --- include/efi_loader.h | 4 ++ lib/efi_loader/efi_device_path.c | 110 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 68daa1a4a9d..5d534e69bb5 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -744,6 +744,10 @@ struct efi_load_option { const u8 *optional_data; }; +struct efi_device_path *efi_dp_from_lo(struct efi_load_option *lo, + efi_uintn_t *size, efi_guid_t guid); +struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1, + const struct efi_device_path *dp2); efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data, efi_uintn_t *size); unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data); diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 398dbc699bb..4b20859b255 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -282,11 +282,31 @@ struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp) return ndp; } -struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1, - const struct efi_device_path *dp2) +/** + * efi_dp_append_or_concatenate() - Append or concatenate two device paths. + * Concatenated device path will be separated + * by a sub-type 0xff end node + * + * @dp1: First device path + * @dp2: Second device path + * @concat: If true the two device paths will be concatenated and separated + * by an end of entrire device path sub-type 0xff end node. + * If true the second device path will be appended to the first and + * terminated by an end node + * + * Return: + * concatenated device path or NULL. Caller must free the returned value + */ +static struct +efi_device_path *efi_dp_append_or_concatenate(const struct efi_device_path *dp1, + const struct efi_device_path *dp2, + bool concat) { struct efi_device_path *ret; + size_t end_size = sizeof(END); + if (concat) + end_size = 2 * sizeof(END); if (!dp1 && !dp2) { /* return an end node */ ret = efi_dp_dup(&END); @@ -298,18 +318,58 @@ struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1, /* both dp1 and dp2 are non-null */ unsigned sz1 = efi_dp_size(dp1); unsigned sz2 = efi_dp_size(dp2); - void *p = dp_alloc(sz1 + sz2 + sizeof(END)); + void *p = dp_alloc(sz1 + sz2 + end_size); if (!p) return NULL; + ret = p; memcpy(p, dp1, sz1); + p += sz1; + + if (concat) { + memcpy(p, &END, sizeof(END)); + p += sizeof(END); + } + /* the end node of the second device path has to be retained */ - memcpy(p + sz1, dp2, sz2 + sizeof(END)); - ret = p; + memcpy(p, dp2, sz2); + p += sz2; + memcpy(p, &END, sizeof(END)); } return ret; } +/** + * efi_dp_append() - Append a device to an existing device path. + * + * @dp1: First device path + * @dp2: Second device path + * + * Return: + * concatenated device path or NULL. Caller must free the returned value + */ +struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1, + const struct efi_device_path *dp2) +{ + return efi_dp_append_or_concatenate(dp1, dp2, false); +} + +/** + * efi_dp_concat() - Concatenate 2 device paths. The final device path will + * contain two device paths separated by and end node (0xff). + * + * @dp1: First device path + * @dp2: Second device path + * + * Return: + * concatenated device path or NULL. Caller must free the returned value + */ +struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1, + const struct efi_device_path *dp2) +{ + return efi_dp_append_or_concatenate(dp1, dp2, true); +} + struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp, const struct efi_device_path *node) { @@ -1183,3 +1243,43 @@ ssize_t efi_dp_check_length(const struct efi_device_path *dp, dp = (const struct efi_device_path *)((const u8 *)dp + len); } } + +/** + * efi_dp_from_lo() - Get the instance of a VenMedia node in a + * multi-instance device path that matches + * a specific GUID. This kind of device paths + * is found in Boot#### options describing an + * initrd location + * + * @lo: EFI_LOAD_OPTION containing a valid device path + * @size: size of the discovered device path + * @guid: guid to search for + * + * Return: + * device path including the VenMedia node or NULL. + * Caller must free the returned value. + */ +struct +efi_device_path *efi_dp_from_lo(struct efi_load_option *lo, + efi_uintn_t *size, efi_guid_t guid) +{ + struct efi_device_path *fp = lo->file_path; + struct efi_device_path_vendor *vendor; + int lo_len = lo->file_path_length; + + for (; lo_len >= sizeof(struct efi_device_path); + lo_len -= fp->length, fp = (void *)fp + fp->length) { + if (lo_len < 0 || efi_dp_check_length(fp, lo_len) < 0) + break; + if (fp->type != DEVICE_PATH_TYPE_MEDIA_DEVICE || + fp->sub_type != DEVICE_PATH_SUB_TYPE_VENDOR_PATH) + continue; + + vendor = (struct efi_device_path_vendor *)fp; + if (!guidcmp(&vendor->guid, &guid)) + return efi_dp_dup(fp); + } + log_debug("VenMedia(%pUl) not found in %ls\n", &guid, lo->label); + + return NULL; +} -- cgit v1.3.1 From 37c3ca5c0b1a449356279efdcaca346b3eae84fd Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Wed, 17 Mar 2021 21:54:59 +0200 Subject: efi_loader: Add helper functions for EFI A following patch introduces a different logic for loading initrd's based on the EFI_LOAD_FILE2_PROTOCOL. Since similar logic can be applied in the future for other system files (i.e DTBs), let's add some helper functions which will retrieve and parse file paths stored in EFI variables. Signed-off-by: Ilias Apalodimas --- include/efi_loader.h | 7 +++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_file.c | 39 ++++++++++++++++ lib/efi_loader/efi_helper.c | 98 +++++++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_var_common.c | 33 ++++++++++++++ 5 files changed, 178 insertions(+) create mode 100644 lib/efi_loader/efi_helper.c (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 5d534e69bb5..9c227005d13 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -558,6 +558,11 @@ struct efi_simple_file_system_protocol *efi_simple_file_system( /* open file from device-path: */ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp); +efi_status_t efi_file_size(struct efi_file_handle *fh, efi_uintn_t *size); + +/* get a device path from a Boot#### option */ +struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid); + /** * efi_size_in_pages() - convert size in bytes to size in pages * @@ -723,6 +728,8 @@ efi_status_t EFIAPI efi_query_variable_info( u64 *remaining_variable_storage_size, u64 *maximum_variable_size); +void *efi_get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size); + /* * See section 3.1.3 in the v2.7 UEFI spec for more details on * the layout of EFI_LOAD_OPTION. In short it is: diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 10b42e8847b..da2741adecf 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -23,6 +23,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o obj-y += efi_boottime.o +obj-y += efi_helper.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o obj-y += efi_console.o diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index 8ece8e71ee1..204105e25af 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -409,6 +409,45 @@ static efi_status_t efi_get_file_size(struct file_handle *fh, return EFI_SUCCESS; } +/** + * efi_file_size() - Get the size of a file using an EFI file handle + * + * @fh: EFI file handle + * @size: buffer to fill in the discovered size + * + * Return: size of the file + */ +efi_status_t efi_file_size(struct efi_file_handle *fh, efi_uintn_t *size) +{ + struct efi_file_info *info = NULL; + efi_uintn_t bs = 0; + efi_status_t ret; + + *size = 0; + ret = EFI_CALL(fh->getinfo(fh, (efi_guid_t *)&efi_file_info_guid, &bs, + info)); + if (ret != EFI_BUFFER_TOO_SMALL) { + ret = EFI_DEVICE_ERROR; + goto out; + } + + info = malloc(bs); + if (!info) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + ret = EFI_CALL(fh->getinfo(fh, (efi_guid_t *)&efi_file_info_guid, &bs, + info)); + if (ret != EFI_SUCCESS) + goto out; + + *size = info->file_size; + +out: + free(info); + return ret; +} + static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size, void *buffer) { diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c new file mode 100644 index 00000000000..d03a7364615 --- /dev/null +++ b/lib/efi_loader/efi_helper.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020, Linaro Limited + */ + +#define LOG_CATEGORY LOGC_EFI +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * efi_create_current_boot_var() - Return Boot#### name were #### is replaced by + * the value of BootCurrent + * + * @var_name: variable name + * @var_name_size: size of var_name + * + * Return: Status code + */ +static efi_status_t efi_create_current_boot_var(u16 var_name[], + size_t var_name_size) +{ + efi_uintn_t boot_current_size; + efi_status_t ret; + u16 boot_current; + u16 *pos; + + boot_current_size = sizeof(boot_current); + ret = efi_get_variable_int(L"BootCurrent", + &efi_global_variable_guid, NULL, + &boot_current_size, &boot_current, NULL); + if (ret != EFI_SUCCESS) + goto out; + + pos = efi_create_indexed_name(var_name, var_name_size, "Boot", + boot_current); + if (!pos) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + +out: + return ret; +} + +/** + * efi_get_dp_from_boot() - Retrieve and return a device path from an EFI + * Boot### variable. + * A boot option may contain an array of device paths. + * We use a VenMedia() with a specific GUID to identify + * the usage of the array members. This function is + * used to extract a specific device path + * + * @guid: vendor GUID of the VenMedia() device path node identifying the + * device path + * + * Return: device path or NULL. Caller must free the returned value + */ +struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid) +{ + struct efi_device_path *file_path = NULL; + struct efi_device_path *tmp = NULL; + struct efi_load_option lo; + void *var_value = NULL; + efi_uintn_t size; + efi_status_t ret; + u16 var_name[16]; + + ret = efi_create_current_boot_var(var_name, sizeof(var_name)); + if (ret != EFI_SUCCESS) + return NULL; + + var_value = efi_get_var(var_name, &efi_global_variable_guid, &size); + if (!var_value) + return NULL; + + ret = efi_deserialize_load_option(&lo, var_value, &size); + if (ret != EFI_SUCCESS) + goto out; + + tmp = efi_dp_from_lo(&lo, &size, guid); + if (!tmp) + goto out; + + /* efi_dp_dup will just return NULL if efi_dp_next is NULL */ + file_path = efi_dp_dup(efi_dp_next(tmp)); + +out: + efi_free_pool(tmp); + free(var_value); + + return file_path; +} diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c index 1c7459266a3..b11ed91a74a 100644 --- a/lib/efi_loader/efi_var_common.c +++ b/lib/efi_loader/efi_var_common.c @@ -9,6 +9,7 @@ #include #include #include +#include enum efi_secure_mode { EFI_MODE_SETUP, @@ -343,3 +344,35 @@ enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid) } return EFI_AUTH_VAR_NONE; } + +/** + * efi_get_var() - read value of an EFI variable + * + * @name: variable name + * @start: vendor GUID + * @size: size of allocated buffer + * + * Return: buffer with variable data or NULL + */ +void *efi_get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size) +{ + efi_status_t ret; + void *buf = NULL; + + *size = 0; + ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL); + if (ret == EFI_BUFFER_TOO_SMALL) { + buf = malloc(*size); + if (!buf) + return NULL; + ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL); + } + + if (ret != EFI_SUCCESS) { + free(buf); + *size = 0; + return NULL; + } + + return buf; +} -- cgit v1.3.1 From 53f6a5aa86267a59ea9d45c89405e42002410e37 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Wed, 17 Mar 2021 21:55:00 +0200 Subject: efi_loader: Replace config option for initrd loading Up to now we install EFI_LOAD_FILE2_PROTOCOL to load an initrd unconditionally. Although we correctly return various EFI exit codes depending on the file status (i.e EFI_NO_MEDIA, EFI_NOT_FOUND etc), the kernel loader, only falls back to the cmdline interpreted initrd if the protocol is not installed. This creates a problem for EFI installers, since they won't be able to load their own initrd and continue the installation. It also makes the feature hard to use, since we can either have a single initrd or we have to recompile u-boot if the filename changes. So let's introduce a different logic that will decouple the initrd path from the config option we currently have. When defining a UEFI BootXXXX we can use the filepathlist and store a file path pointing to our initrd. Specifically the EFI spec describes: "The first element of the array is a device path that describes the device and location of the Image for this load option. Other device paths may optionally exist in the FilePathList, but their usage is OSV specific" When the EFI application is launched through the bootmgr, we'll try to interpret the extra device path. If that points to a file that exists on our disk, we'll now install the load_file2 and the efi-stub will be able to use it. This opens up another path using U-Boot and defines a new boot flow. A user will be able to control the kernel/initrd pairs without explicit cmdline args or GRUB. Signed-off-by: Ilias Apalodimas Reviewed-by: Heinrich Schuchardt --- cmd/bootefi.c | 3 + include/efi_loader.h | 1 + lib/efi_loader/Kconfig | 17 ++-- lib/efi_loader/efi_bootmgr.c | 19 +++- lib/efi_loader/efi_load_initrd.c | 202 +++++++++++++++++++++++---------------- 5 files changed, 144 insertions(+), 98 deletions(-) (limited to 'include') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 271b385edea..cba81ffe75e 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -358,6 +358,9 @@ static efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options) free(load_options); + if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) + efi_initrd_deregister(); + return ret; } diff --git a/include/efi_loader.h b/include/efi_loader.h index 9c227005d13..903bf60bc0a 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -437,6 +437,7 @@ efi_status_t efi_net_register(void); /* Called by bootefi to make the watchdog available */ efi_status_t efi_watchdog_register(void); efi_status_t efi_initrd_register(void); +void efi_initrd_deregister(void); /* Called by bootefi to make SMBIOS tables available */ /** * efi_acpi_register() - write out ACPI tables diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 634d3b1ff4e..0a412441a71 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -315,18 +315,13 @@ config EFI_TCG2_PROTOCOL_EVENTLOG_SIZE config EFI_LOAD_FILE2_INITRD bool "EFI_FILE_LOAD2_PROTOCOL for Linux initial ramdisk" - default n - help - Expose a EFI_FILE_LOAD2_PROTOCOL that the Linux UEFI stub can - use to load the initial ramdisk. Once this is enabled using - initrd= will stop working. - -config EFI_INITRD_FILESPEC - string "initramfs path" - default "host 0:1 initrd" - depends on EFI_LOAD_FILE2_INITRD + default y help - Full path of the initramfs file, e.g. mmc 0:2 initramfs.cpio.gz. + Linux v5.7 and later can make use of this option. If the boot option + selected by the UEFI boot manager specifies an existing file to be used + as initial RAM disk, a Linux specific Load File2 protocol will be + installed and Linux 5.7+ will ignore any initrd= command line + argument. config EFI_SECURE_BOOT bool "Enable EFI secure boot support" diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 25f5cebfdb6..46c8011344b 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -118,11 +118,13 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle, ret = efi_set_variable_int(L"BootCurrent", &efi_global_variable_guid, attributes, sizeof(n), &n, false); - if (ret != EFI_SUCCESS) { - if (EFI_CALL(efi_unload_image(*handle)) - != EFI_SUCCESS) - log_err("Unloading image failed\n"); - goto error; + if (ret != EFI_SUCCESS) + goto unload; + /* try to register load file2 for initrd's */ + if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) { + ret = efi_initrd_register(); + if (ret != EFI_SUCCESS) + goto unload; } log_info("Booting: %ls\n", lo.label); @@ -146,6 +148,13 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle, error: free(load_option); + return ret; + +unload: + if (EFI_CALL(efi_unload_image(*handle)) != EFI_SUCCESS) + log_err("Unloading image failed\n"); + free(load_option); + return ret; } diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c index b9ee8839054..e2a80630230 100644 --- a/lib/efi_loader/efi_load_initrd.c +++ b/lib/efi_loader/efi_load_initrd.c @@ -3,9 +3,11 @@ * Copyright (c) 2020, Linaro Limited */ +#define LOG_CATEGORY LOGC_EFI #include #include #include +#include #include #include #include @@ -23,57 +25,56 @@ static const struct efi_load_file_protocol efi_lf2_protocol = { * Device path defined by Linux to identify the handle providing the * EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk. */ -static const struct efi_initrd_dp dp = { +static const struct efi_initrd_dp dp_lf2_handle = { .vendor = { { DEVICE_PATH_TYPE_MEDIA_DEVICE, DEVICE_PATH_SUB_TYPE_VENDOR_PATH, - sizeof(dp.vendor), + sizeof(dp_lf2_handle.vendor), }, EFI_INITRD_MEDIA_GUID, }, .end = { DEVICE_PATH_TYPE_END, DEVICE_PATH_SUB_TYPE_END, - sizeof(dp.end), + sizeof(dp_lf2_handle.end), } }; +static efi_handle_t efi_initrd_handle; + /** - * get_file_size() - retrieve the size of initramfs, set efi status on error + * get_initrd_fp() - Get initrd device path from a FilePathList device path * - * @dev: device to read from, e.g. "mmc" - * @part: device partition, e.g. "0:1" - * @file: name of file - * @status: EFI exit code in case of failure + * @initrd_fp: the final initrd filepath * - * Return: size of file + * Return: status code. Caller must free initrd_fp */ -static loff_t get_file_size(const char *dev, const char *part, const char *file, - efi_status_t *status) +static efi_status_t get_initrd_fp(struct efi_device_path **initrd_fp) { - loff_t sz = 0; - int ret; - - ret = fs_set_blk_dev(dev, part, FS_TYPE_ANY); - if (ret) { - *status = EFI_NO_MEDIA; - goto out; - } + const efi_guid_t lf2_initrd_guid = EFI_INITRD_MEDIA_GUID; + struct efi_device_path *dp = NULL; - ret = fs_size(file, &sz); - if (ret) { - sz = 0; - *status = EFI_NOT_FOUND; - goto out; - } + /* + * if bootmgr is setup with and initrd, the device path will be + * in the FilePathList[] of our load options in Boot####. + * The first device path of the multi instance device path will + * start with a VenMedia and the initrds will follow. + * + * If the device path is not found return EFI_INVALID_PARAMETER. + * We can then use this specific return value and not install the + * protocol, while allowing the boot to continue + */ + dp = efi_get_dp_from_boot(lf2_initrd_guid); + if (!dp) + return EFI_INVALID_PARAMETER; -out: - return sz; + *initrd_fp = dp; + return EFI_SUCCESS; } /** - * efi_load_file2initrd() - load initial RAM disk + * efi_load_file2_initrd() - load initial RAM disk * * This function implements the LoadFile service of the EFI_LOAD_FILE2_PROTOCOL * in order to load an initial RAM disk requested by the Linux kernel stub. @@ -93,102 +94,125 @@ efi_load_file2_initrd(struct efi_load_file_protocol *this, struct efi_device_path *file_path, bool boot_policy, efi_uintn_t *buffer_size, void *buffer) { - char *filespec; - efi_status_t status = EFI_NOT_FOUND; - loff_t file_sz = 0, read_sz = 0; - char *dev, *part, *file; - char *pos; - int ret; + struct efi_device_path *initrd_fp = NULL; + efi_status_t ret = EFI_NOT_FOUND; + struct efi_file_handle *f = NULL; + efi_uintn_t bs; EFI_ENTRY("%p, %p, %d, %p, %p", this, file_path, boot_policy, buffer_size, buffer); - filespec = strdup(CONFIG_EFI_INITRD_FILESPEC); - if (!filespec) - goto out; - pos = filespec; - if (!this || this != &efi_lf2_protocol || !buffer_size) { - status = EFI_INVALID_PARAMETER; + ret = EFI_INVALID_PARAMETER; goto out; } - if (file_path->type != dp.end.type || - file_path->sub_type != dp.end.sub_type) { - status = EFI_INVALID_PARAMETER; + if (file_path->type != dp_lf2_handle.end.type || + file_path->sub_type != dp_lf2_handle.end.sub_type) { + ret = EFI_INVALID_PARAMETER; goto out; } if (boot_policy) { - status = EFI_UNSUPPORTED; + ret = EFI_UNSUPPORTED; goto out; } - /* - * expect a string with three space separated parts: - * - * * a block device type, e.g. "mmc" - * * a device and partition identifier, e.g. "0:1" - * * a file path on the block device, e.g. "/boot/initrd.cpio.gz" - */ - dev = strsep(&pos, " "); - if (!dev) + ret = get_initrd_fp(&initrd_fp); + if (ret != EFI_SUCCESS) goto out; - part = strsep(&pos, " "); - if (!part) - goto out; - file = strsep(&pos, " "); - if (!file) + + /* Open file */ + f = efi_file_from_path(initrd_fp); + if (!f) { + log_err("Can't find initrd specified in Boot####\n"); + ret = EFI_NOT_FOUND; goto out; + } - file_sz = get_file_size(dev, part, file, &status); - if (!file_sz) + /* Get file size */ + ret = efi_file_size(f, &bs); + if (ret != EFI_SUCCESS) goto out; - if (!buffer || *buffer_size < file_sz) { - status = EFI_BUFFER_TOO_SMALL; - *buffer_size = file_sz; + if (!buffer || *buffer_size < bs) { + ret = EFI_BUFFER_TOO_SMALL; + *buffer_size = bs; } else { - ret = fs_set_blk_dev(dev, part, FS_TYPE_ANY); - if (ret) { - status = EFI_NO_MEDIA; - goto out; - } - - ret = fs_read(file, map_to_sysmem(buffer), 0, *buffer_size, - &read_sz); - if (ret || read_sz != file_sz) - goto out; - *buffer_size = read_sz; - - status = EFI_SUCCESS; + ret = EFI_CALL(f->read(f, &bs, (void *)(uintptr_t)buffer)); + *buffer_size = bs; + } + +out: + efi_free_pool(initrd_fp); + if (f) + EFI_CALL(f->close(f)); + return EFI_EXIT(ret); +} + +/** + * check_initrd() - Determine if the file defined as an initrd in Boot#### + * load_options device path is present + * + * Return: status code + */ +static efi_status_t check_initrd(void) +{ + struct efi_device_path *initrd_fp = NULL; + struct efi_file_handle *f; + efi_status_t ret; + + ret = get_initrd_fp(&initrd_fp); + if (ret != EFI_SUCCESS) + goto out; + + /* + * If the file is not found, but the file path is set, return an error + * and trigger the bootmgr fallback + */ + f = efi_file_from_path(initrd_fp); + if (!f) { + log_err("Can't find initrd specified in Boot####\n"); + ret = EFI_NOT_FOUND; + goto out; } + EFI_CALL(f->close(f)); + out: - free(filespec); - return EFI_EXIT(status); + efi_free_pool(initrd_fp); + return ret; } /** * efi_initrd_register() - create handle for loading initial RAM disk * * This function creates a new handle and installs a Linux specific vendor - * device path and an EFI_LOAD_FILE_2_PROTOCOL. Linux uses the device path + * device path and an EFI_LOAD_FILE2_PROTOCOL. Linux uses the device path * to identify the handle and then calls the LoadFile service of the - * EFI_LOAD_FILE_2_PROTOCOL to read the initial RAM disk. + * EFI_LOAD_FILE2_PROTOCOL to read the initial RAM disk. * * Return: status code */ efi_status_t efi_initrd_register(void) { - efi_handle_t efi_initrd_handle = NULL; efi_status_t ret; + /* + * Allow the user to continue if Boot#### file path is not set for + * an initrd + */ + ret = check_initrd(); + if (ret == EFI_INVALID_PARAMETER) + return EFI_SUCCESS; + if (ret != EFI_SUCCESS) + return ret; + ret = EFI_CALL(efi_install_multiple_protocol_interfaces (&efi_initrd_handle, /* initramfs */ - &efi_guid_device_path, &dp, + &efi_guid_device_path, &dp_lf2_handle, /* LOAD_FILE2 */ &efi_guid_load_file2_protocol, (void *)&efi_lf2_protocol, @@ -196,3 +220,17 @@ efi_status_t efi_initrd_register(void) return ret; } + +/** + * efi_initrd_deregister() - delete the handle for loading initial RAM disk + * + * This will delete the handle containing the Linux specific vendor device + * path and EFI_LOAD_FILE2_PROTOCOL for loading an initrd + * + * Return: status code + */ +void efi_initrd_deregister(void) +{ + efi_delete_handle(efi_initrd_handle); + efi_initrd_handle = NULL; +} -- cgit v1.3.1 From 64a8aae15ce9cccdb907219a9fce9f5b17ae791a Mon Sep 17 00:00:00 2001 From: Jose Marinho Date: Tue, 2 Mar 2021 17:26:38 +0000 Subject: efi: Add ESRT to the EFI system table The ESRT is initialised during efi_init_objlist after efi_initialize_system_table(). The ESRT is recreated from scratch at the following events: - successful UpdateCapsule; - FMP instance install. The code ensures that every ESRT entry has a unique fw_class value. Limitations: - The ESRT is not updated if an FMP instance is uninstalled; - the fields image_type and flags are in the current implementation left undefined. Setting these values will require a per-platform function that returns the image_type/flags as a function of the image fw_class. CC: Heinrich Schuchardt CC: Sughosh Ganu CC: AKASHI Takahiro CC: Ilias Apalodimas CC: Andre Przywara CC: Alexander Graf CC: nd@arm.com Signed-off-by: Jose Marinho Remove two EFI_CALL() indirections. Move ESRT GUID in efidebug's list of GUIDs. Reviewed-by: Heinrich Schuchardt --- cmd/efidebug.c | 4 + include/efi_api.h | 21 ++ include/efi_loader.h | 24 ++ lib/efi_loader/Kconfig | 7 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 7 +- lib/efi_loader/efi_capsule.c | 8 + lib/efi_loader/efi_esrt.c | 510 ++++++++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_setup.c | 6 + 9 files changed, 584 insertions(+), 4 deletions(-) create mode 100644 lib/efi_loader/efi_esrt.c (limited to 'include') diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 80ddd598e0a..392d2d58109 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -518,6 +518,10 @@ static const struct { "ACPI table", EFI_ACPI_TABLE_GUID, }, + { + "EFI System Resource Table", + EFI_SYSTEM_RESOURCE_TABLE_GUID, + }, { "device tree", EFI_FDT_GUID, diff --git a/include/efi_api.h b/include/efi_api.h index 4ccde1d24da..18a1adf0239 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1732,6 +1732,23 @@ struct efi_load_file_protocol { void *buffer); }; +struct efi_system_resource_entry { + efi_guid_t fw_class; + u32 fw_type; + u32 fw_version; + u32 lowest_supported_fw_version; + u32 capsule_flags; + u32 last_attempt_version; + u32 last_attempt_status; +} __packed; + +struct efi_system_resource_table { + u32 fw_resource_count; + u32 fw_resource_count_max; + u64 fw_resource_version; + struct efi_system_resource_entry entries[]; +} __packed; + /* Boot manager load options */ #define LOAD_OPTION_ACTIVE 0x00000001 #define LOAD_OPTION_FORCE_RECONNECT 0x00000002 @@ -1750,6 +1767,10 @@ struct efi_load_file_protocol { #define ESRT_FW_TYPE_DEVICEFIRMWARE 0x00000002 #define ESRT_FW_TYPE_UEFIDRIVER 0x00000003 +#define EFI_SYSTEM_RESOURCE_TABLE_GUID\ + EFI_GUID(0xb122a263, 0x3661, 0x4f68,\ + 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80) + /* Last Attempt Status Values */ #define LAST_ATTEMPT_STATUS_SUCCESS 0x00000000 #define LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL 0x00000001 diff --git a/include/efi_loader.h b/include/efi_loader.h index 903bf60bc0a..de1a496a972 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -214,6 +214,8 @@ extern const efi_guid_t efi_guid_rng_protocol; extern const efi_guid_t efi_guid_capsule_report; /* GUID of firmware management protocol */ extern const efi_guid_t efi_guid_firmware_management_protocol; +/* GUID for the ESRT */ +extern const efi_guid_t efi_esrt_guid; extern unsigned int __efi_runtime_start, __efi_runtime_stop; extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; @@ -559,6 +561,10 @@ struct efi_simple_file_system_protocol *efi_simple_file_system( /* open file from device-path: */ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp); +/* Registers a callback function for a notification event. */ +efi_status_t EFIAPI efi_register_protocol_notify(const efi_guid_t *protocol, + struct efi_event *event, + void **registration); efi_status_t efi_file_size(struct efi_file_handle *fh, efi_uintn_t *size); /* get a device path from a Boot#### option */ @@ -902,4 +908,22 @@ static inline efi_status_t efi_launch_capsules(void) #endif /* CONFIG_IS_ENABLED(EFI_LOADER) */ +/** + * Install the ESRT system table. + * + * @return status code + */ +efi_status_t efi_esrt_register(void); + +/** + * efi_esrt_populate() - Populates the ESRT entries from the FMP instances + * present in the system. + * If an ESRT already exists, the old ESRT is replaced in the system table. + * The memory of the old ESRT is deallocated. + * + * Return: + * - EFI_SUCCESS if the ESRT is correctly created + * - error code otherwise. + */ +efi_status_t efi_esrt_populate(void); #endif /* _EFI_LOADER_H */ diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 0a412441a71..e44f004f3f8 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -342,4 +342,11 @@ config EFI_SECURE_BOOT it is signed with a trusted key. To do that, you need to install, at least, PK, KEK and db. +config EFI_ESRT + bool "Enable the UEFI ESRT generation" + depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT + default y + help + Enabling this option creates the ESRT UEFI system table. + endif diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index da2741adecf..8bd343e258a 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -53,6 +53,7 @@ obj-y += efi_variable.o obj-$(CONFIG_EFI_VARIABLES_PRESEED) += efi_var_seed.o endif obj-y += efi_watchdog.o +obj-$(CONFIG_EFI_ESRT) += efi_esrt.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 41b8949b042..8e8b0a9bc6c 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1406,10 +1406,9 @@ out: * * Return: status code */ -static efi_status_t EFIAPI efi_register_protocol_notify( - const efi_guid_t *protocol, - struct efi_event *event, - void **registration) +efi_status_t EFIAPI efi_register_protocol_notify(const efi_guid_t *protocol, + struct efi_event *event, + void **registration) { struct efi_register_notify_event *item; efi_status_t ret = EFI_SUCCESS; diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index 7ba1ced0a08..9df9c35084c 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -482,6 +482,14 @@ efi_status_t EFIAPI efi_update_capsule( goto out; } out: + + if (IS_ENABLED(CONFIG_EFI_ESRT)) { + /* Rebuild the ESRT to reflect any updated FW images. */ + ret = efi_esrt_populate(); + if (ret != EFI_SUCCESS) + log_warning("EFI Capsule: failed to update ESRT\n"); + } + return EFI_EXIT(ret); } diff --git a/lib/efi_loader/efi_esrt.c b/lib/efi_loader/efi_esrt.c new file mode 100644 index 00000000000..947bdb5e95f --- /dev/null +++ b/lib/efi_loader/efi_esrt.c @@ -0,0 +1,510 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * EFI application ESRT tables support + * + * Copyright (C) 2021 Arm Ltd. + */ + +#include +#include +#include +#include +#include + +const efi_guid_t efi_esrt_guid = EFI_SYSTEM_RESOURCE_TABLE_GUID; + +static struct efi_system_resource_table *esrt; + +#define EFI_ESRT_VERSION 1 + +/** + * efi_esrt_image_info_to_entry() - copy the information present in a fw image + * descriptor to a ESRT entry. + * The function ensures the ESRT entry matches the image_type_id in @img_info. + * In case of a mismatch we leave the entry unchanged. + * + * @img_info: the source image info descriptor + * @entry: pointer to the ESRT entry to be filled + * @desc_version: the version of the elements in img_info + * @image_type: the image type value to be set in the ESRT entry + * @flags: the capsule flags value to be set in the ESRT entry + * + * Return: + * - EFI_SUCCESS if the entry is correctly updated + * - EFI_INVALID_PARAMETER if entry does not match image_type_id in @img_info. + */ +static efi_status_t +efi_esrt_image_info_to_entry(struct efi_firmware_image_descriptor *img_info, + struct efi_system_resource_entry *entry, + u32 desc_version, u32 image_type, u32 flags) +{ + if (guidcmp(&entry->fw_class, &img_info->image_type_id)) { + EFI_PRINT("ESRT entry %pUL mismatches img_type_id %pUL\n", + &entry->fw_class, &img_info->image_type_id); + return EFI_INVALID_PARAMETER; + } + + entry->fw_version = img_info->version; + + entry->fw_type = image_type; + entry->capsule_flags = flags; + + /* + * The field lowest_supported_image_version is only present + * on image info structure of version 2 or greater. + * See the EFI_FIRMWARE_IMAGE_DESCRIPTOR definition in UEFI. + */ + if (desc_version >= 2) + entry->lowest_supported_fw_version = + img_info->lowest_supported_image_version; + else + entry->lowest_supported_fw_version = 0; + + /* + * The fields last_attempt_version and last_attempt_status + * are only present on image info structure of version 3 or + * greater. + * See the EFI_FIRMWARE_IMAGE_DESCRIPTOR definition in UEFI. + */ + if (desc_version >= 3) { + entry->last_attempt_version = + img_info->last_attempt_version; + + entry->last_attempt_status = + img_info->last_attempt_status; + } else { + entry->last_attempt_version = 0; + entry->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS; + } + + return EFI_SUCCESS; +} + +/** + * efi_esrt_entries_to_size() - Obtain the bytes used by an ESRT + * datastructure with @num_entries. + * + * @num_entries: the number of entries in the ESRT. + * + * Return: the number of bytes an ESRT with @num_entries occupies in memory. + */ +static +inline u32 efi_esrt_entries_to_size(u32 num_entries) +{ + u32 esrt_size = sizeof(struct efi_system_resource_table) + + num_entries * sizeof(struct efi_system_resource_entry); + + return esrt_size; +} + +/** + * efi_esrt_allocate_install() - Allocates @num_entries for the ESRT and + * performs basic ESRT initialization. + * + * @num_entries: the number of entries that the ESRT will hold. + * + * Return: + * - pointer to the ESRT if successful. + * - NULL otherwise. + */ +static +efi_status_t efi_esrt_allocate_install(u32 num_entries) +{ + efi_status_t ret; + struct efi_system_resource_table *new_esrt; + u32 size = efi_esrt_entries_to_size(num_entries); + efi_guid_t esrt_guid = efi_esrt_guid; + + /* Reserve num_pages for ESRT */ + ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, size, + (void **)&new_esrt); + + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT cannot allocate memory for %d entries (%d bytes)\n", + num_entries, efi_esrt_entries_to_size(num_entries)); + + return ret; + } + + new_esrt->fw_resource_count_max = num_entries; + new_esrt->fw_resource_count = 0; + new_esrt->fw_resource_version = EFI_ESRT_VERSION; + + /* Install the ESRT in the system configuration table. */ + ret = efi_install_configuration_table(&esrt_guid, (void *)new_esrt); + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT failed to install the ESRT in the system table\n"); + return ret; + } + + /* If there was a previous ESRT, deallocate its memory now. */ + if (esrt) + ret = EFI_CALL(efi_free_pool(esrt)); + + esrt = new_esrt; + + return EFI_SUCCESS; +} + +/** + * esrt_find_entry() - Obtain the ESRT entry for the image with GUID + * @img_fw_class. + * + * If the img_fw_class is not yet present in the ESRT, this function + * reserves the tail element of the current ESRT as the entry for that fw_class. + * The number of elements in the ESRT is updated in that case. + * + * @img_fw_class: the GUID of the FW image which ESRT entry we want to obtain. + * + * Return: + * - A pointer to the ESRT entry for the image with GUID img_fw_class, + * - NULL if: + * - there is no more space in the ESRT, + * - ESRT is not initialized, + */ +static +struct efi_system_resource_entry *esrt_find_entry(efi_guid_t *img_fw_class) +{ + u32 filled_entries; + u32 max_entries; + struct efi_system_resource_entry *entry; + + if (!esrt) { + EFI_PRINT("ESRT access before initialized\n"); + return NULL; + } + + filled_entries = esrt->fw_resource_count; + entry = esrt->entries; + + /* Check if the image with img_fw_class is already in the ESRT. */ + for (u32 idx = 0; idx < filled_entries; idx++) { + if (!guidcmp(&entry[idx].fw_class, img_fw_class)) { + EFI_PRINT("ESRT found entry for image %pUl at index %d\n", + img_fw_class, idx); + return &entry[idx]; + } + } + + max_entries = esrt->fw_resource_count_max; + /* + * Since the image with img_fw_class is not present in the ESRT, check + * if ESRT is full before appending the new entry to it. + */ + if (filled_entries == max_entries) { + EFI_PRINT("ESRT full, this should not happen\n"); + return NULL; + } + + /* + * This is a new entry for a fw image, increment the element + * number in the table and set the fw_class field. + */ + esrt->fw_resource_count++; + entry[filled_entries].fw_class = *img_fw_class; + EFI_PRINT("ESRT allocated new entry for image %pUl at index %d\n", + img_fw_class, filled_entries); + + return &entry[filled_entries]; +} + +/** + * efi_esrt_add_from_fmp() - Populates a sequence of ESRT entries from the FW + * images in the FMP. + * + * @fmp: the FMP instance from which FW images are added to the ESRT + * + * Return: + * - EFI_SUCCESS if all the FW images in the FMP are added to the ESRT + * - Error status otherwise + */ +static +efi_status_t efi_esrt_add_from_fmp(struct efi_firmware_management_protocol *fmp) +{ + struct efi_system_resource_entry *entry = NULL; + size_t info_size = 0; + struct efi_firmware_image_descriptor *img_info = NULL; + u32 desc_version; + u8 desc_count; + size_t desc_size; + u32 package_version; + u16 *package_version_name; + efi_status_t ret = EFI_SUCCESS; + + /* + * TODO: set the field image_type depending on the FW image type + * defined in a platform basis. + */ + u32 image_type = ESRT_FW_TYPE_UNKNOWN; + + /* TODO: set the capsule flags as a function of the FW image type. */ + u32 flags = 0; + + ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info, + &desc_version, &desc_count, + &desc_size, NULL, NULL)); + + if (ret != EFI_BUFFER_TOO_SMALL) { + /* + * An input of info_size=0 should always lead + * fmp->get_image_info to return BUFFER_TO_SMALL. + */ + EFI_PRINT("Erroneous FMP implementation\n"); + return EFI_INVALID_PARAMETER; + } + + ret = EFI_CALL(efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size, + (void **)&img_info)); + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT failed to allocate memory for image info.\n"); + return ret; + } + + ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info, + &desc_version, &desc_count, + &desc_size, &package_version, + &package_version_name)); + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT failed to obtain the FMP image info\n"); + goto out; + } + + /* + * Iterate over all the FW images in the FMP. + */ + for (u32 desc_idx = 0; desc_idx < desc_count; desc_idx++) { + struct efi_firmware_image_descriptor *cur_img_info = + (struct efi_firmware_image_descriptor *) + ((uintptr_t)img_info + desc_idx * desc_size); + + /* + * Obtain the ESRT entry for the FW image with fw_class + * equal to cur_img_info->image_type_id. + */ + entry = esrt_find_entry(&cur_img_info->image_type_id); + + if (entry) { + ret = efi_esrt_image_info_to_entry(cur_img_info, entry, + desc_version, + image_type, flags); + if (ret != EFI_SUCCESS) + EFI_PRINT("ESRT entry mismatches image_type\n"); + + } else { + EFI_PRINT("ESRT failed to add entry for %pUl\n", + &cur_img_info->image_type_id); + continue; + } + } + +out: + EFI_CALL(efi_free_pool(img_info)); + return EFI_SUCCESS; +} + +/** + * efi_esrt_populate() - Populates the ESRT entries from the FMP instances + * present in the system. + * If an ESRT already exists, the old ESRT is replaced in the system table. + * The memory of the old ESRT is deallocated. + * + * Return: + * - EFI_SUCCESS if the ESRT is correctly created + * - error code otherwise. + */ +efi_status_t efi_esrt_populate(void) +{ + efi_handle_t *base_handle = NULL; + efi_handle_t *it_handle; + size_t no_handles = 0; + struct efi_firmware_management_protocol *fmp; + efi_status_t ret; + u32 num_entries = 0; + struct efi_handler *handler; + + /* + * Obtain the number of registered FMP handles. + */ + ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, + &efi_guid_firmware_management_protocol, + NULL, &no_handles, + (efi_handle_t **)&base_handle)); + + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT There are no FMP instances\n"); + + ret = efi_esrt_allocate_install(0); + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT failed to create table with 0 entries\n"); + return ret; + } + return EFI_SUCCESS; + } + + EFI_PRINT("ESRT populate esrt from (%ld) available FMP handles\n", + no_handles); + + /* + * Iterate over all FMPs to determine an upper bound on the number of + * ESRT entries. + */ + it_handle = base_handle; + for (u32 idx = 0; idx < no_handles; idx++, it_handle++) { + struct efi_firmware_image_descriptor *img_info = NULL; + size_t info_size = 0; + u32 desc_version = 0; + u8 desc_count = 0; + size_t desc_size = 0; + u32 package_version; + u16 *package_version_name; + + ret = efi_search_protocol(*it_handle, + &efi_guid_firmware_management_protocol, + &handler); + + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT Unable to find FMP handle (%d)\n", + idx); + goto out; + } + fmp = handler->protocol_interface; + + ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, NULL, + &desc_version, &desc_count, + &desc_size, &package_version, + &package_version_name)); + + if (ret != EFI_BUFFER_TOO_SMALL) { + /* + * An input of info_size=0 should always lead + * fmp->get_image_info to return BUFFER_TO_SMALL. + */ + EFI_PRINT("ESRT erroneous FMP implementation\n"); + ret = EFI_INVALID_PARAMETER; + goto out; + } + + ret = EFI_CALL(efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size, + (void **)&img_info)); + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT failed to allocate memory for image info\n"); + goto out; + } + + /* + * Calls to a FMP get_image_info method do not return the + * desc_count value if the return status differs from EFI_SUCCESS. + * We need to repeat the call to get_image_info with a properly + * sized buffer in order to obtain the real number of images + * handled by the FMP. + */ + ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info, + &desc_version, &desc_count, + &desc_size, &package_version, + &package_version_name)); + + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT failed to obtain image info from FMP\n"); + EFI_CALL(efi_free_pool(img_info)); + goto out; + } + + num_entries += desc_count; + + EFI_CALL(efi_free_pool(img_info)); + } + + EFI_PRINT("ESRT create table with %d entries\n", num_entries); + /* + * Allocate an ESRT with the sufficient number of entries to accommodate + * all the FMPs in the system. + */ + ret = efi_esrt_allocate_install(num_entries); + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT failed to initialize table\n"); + goto out; + } + + /* + * Populate the ESRT entries with all existing FMP. + */ + it_handle = base_handle; + for (u32 idx = 0; idx < no_handles; idx++, it_handle++) { + ret = EFI_CALL(efi_search_protocol(*it_handle, + &efi_guid_firmware_management_protocol, + &handler)); + + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT unable to find FMP handle (%d)\n", + idx); + break; + } + fmp = handler->protocol_interface; + + ret = efi_esrt_add_from_fmp(fmp); + if (ret != EFI_SUCCESS) + EFI_PRINT("ESRT failed to add FMP to the table\n"); + } + +out: + + EFI_CALL(efi_free_pool(base_handle)); + + return ret; +} + +/** + * efi_esrt_new_fmp_notify() - Callback for the EVT_NOTIFY_SIGNAL event raised + * when a new FMP protocol instance is registered in the system. + */ +static void EFIAPI efi_esrt_new_fmp_notify(struct efi_event *event, + void *context) +{ + efi_status_t ret; + + EFI_ENTRY(); + + ret = efi_esrt_populate(); + if (ret != EFI_SUCCESS) + EFI_PRINT("ESRT failed to populate ESRT entry\n"); + + EFI_EXIT(ret); +} + +/** + * efi_esrt_register() - Install the ESRT system table. + * + * Return: status code + */ +efi_status_t efi_esrt_register(void) +{ + struct efi_event *ev = NULL; + void *registration; + efi_status_t ret; + + EFI_PRINT("ESRT creation start\n"); + + ret = efi_esrt_populate(); + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT failed to initiate the table\n"); + return ret; + } + + ret = EFI_CALL(efi_create_event(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + efi_esrt_new_fmp_notify, NULL, NULL, &ev)); + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT failed to create event\n"); + return ret; + } + + ret = EFI_CALL(efi_register_protocol_notify(&efi_guid_firmware_management_protocol, + ev, ®istration)); + if (ret != EFI_SUCCESS) { + EFI_PRINT("ESRT failed to register FMP callback\n"); + return ret; + } + + EFI_PRINT("ESRT table created\n"); + + return ret; +} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index b1c5125032b..3c5cf9a4357 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -227,6 +227,12 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out; + if (IS_ENABLED(CONFIG_EFI_ESRT)) { + ret = efi_esrt_register(); + if (ret != EFI_SUCCESS) + goto out; + } + if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) { ret = efi_tcg2_register(); if (ret != EFI_SUCCESS) -- cgit v1.3.1 From 5e21958c02e20bbba444c8061f8b87405093a9b5 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 24 Mar 2021 17:48:01 +0100 Subject: efi_selfest: redefine enum efi_test_phase Setup will always occur before ExitBootServices(). So eliminate EFI_SETUP_AFTER_BOOTTIME_EXIT. Put the SetVirtualAddressMap() test into a separate class so that we can execute it last. Signed-off-by: Heinrich Schuchardt --- include/efi_selftest.h | 7 +++---- lib/efi_selftest/efi_selftest.c | 11 ++++++----- lib/efi_selftest/efi_selftest_set_virtual_address_map.c | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/efi_selftest.h b/include/efi_selftest.h index 1515fdaa02b..07b619901c0 100644 --- a/include/efi_selftest.h +++ b/include/efi_selftest.h @@ -66,11 +66,10 @@ enum efi_test_phase { */ EFI_SETUP_BEFORE_BOOTTIME_EXIT, /** - * @EFI_SETUP_AFTER_BOOTTIME_EXIT: - setup after ExitBootServices - * - * Setup, execute, and teardown are executed after ExitBootServices(). + * @EFI_SETTING_VIRTUAL_ADDRESS_MAP - calls SetVirtualAddressMap() + * Execute calls SetVirtualAddressMap(). */ - EFI_SETUP_AFTER_BOOTTIME_EXIT, + EFI_SETTING_VIRTUAL_ADDRESS_MAP, }; extern struct efi_simple_text_output_protocol *con_out; diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index b8eed048c23..39ee2edf5de 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -160,7 +160,7 @@ static bool need_reset(const u16 *testname) if (testname && efi_st_strcmp_16_8(testname, test->name)) continue; if (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT || - test->phase == EFI_SETUP_AFTER_BOOTTIME_EXIT) + test->phase == EFI_SETTING_VIRTUAL_ADDRESS_MAP) return true; } return false; @@ -327,15 +327,16 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, /* Execute mixed tests */ efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, EFI_ST_SETUP, &failures); + efi_st_do_tests(testname, EFI_SETTING_VIRTUAL_ADDRESS_MAP, + EFI_ST_SETUP, &failures); efi_st_exit_boot_services(); efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); - - /* Execute runtime tests */ - efi_st_do_tests(testname, EFI_SETUP_AFTER_BOOTTIME_EXIT, - EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, + /* Execute test setting the virtual address map */ + efi_st_do_tests(testname, EFI_SETTING_VIRTUAL_ADDRESS_MAP, + EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); /* Give feedback */ diff --git a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c index b097a811364..8e2e8ba1720 100644 --- a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c +++ b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c @@ -201,7 +201,7 @@ static int execute(void) EFI_UNIT_TEST(virtaddrmap) = { .name = "virtual address map", - .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, + .phase = EFI_SETTING_VIRTUAL_ADDRESS_MAP, .setup = setup, .execute = execute, }; -- cgit v1.3.1 From 910de1092f6e2febf5b9066f7ce437dc2303c1e0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:20 +1300 Subject: dm: core: Include dt-decl.h automatically When dt-structs.h is used, include the dt-decl.h header as well, so that these declarations are available. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- include/dt-structs.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/dt-structs.h b/include/dt-structs.h index f0e1c9cb901..f9ccaf56a46 100644 --- a/include/dt-structs.h +++ b/include/dt-structs.h @@ -24,7 +24,9 @@ struct phandle_2_arg { uint idx; int arg[2]; }; + #include +#include #endif #endif -- cgit v1.3.1 From 4ddc91b32f9fc2292686dffe0159e2679362f78b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:23 +1300 Subject: clk: fixed-rate: Export driver parts for OF_PLATDATA_INST We need to allow SoCs to create their own drivers for this so that they can use their own of-platdata structs. To minimise code duplication, export the driver operations and the ofdata_to_plat() setup function. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- drivers/clk/clk_fixed_rate.c | 14 ++++++++++---- include/linux/clk-provider.h | 5 +++++ 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index 3c5a83c523c..09f9ef26a42 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -25,18 +25,24 @@ const struct clk_ops clk_fixed_rate_ops = { .enable = dummy_enable, }; -static int clk_fixed_rate_of_to_plat(struct udevice *dev) +void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev, + struct clk_fixed_rate *plat) { - struct clk *clk = &to_clk_fixed_rate(dev)->clk; + struct clk *clk = &plat->clk; #if !CONFIG_IS_ENABLED(OF_PLATDATA) - to_clk_fixed_rate(dev)->fixed_rate = - dev_read_u32_default(dev, "clock-frequency", 0); + plat->fixed_rate = dev_read_u32_default(dev, "clock-frequency", 0); #endif /* Make fixed rate clock accessible from higher level struct clk */ /* FIXME: This is not allowed */ dev_set_uclass_priv(dev, clk); + clk->dev = dev; clk->enable_count = 0; +} + +static int clk_fixed_rate_of_to_plat(struct udevice *dev) +{ + clk_fixed_rate_ofdata_to_plat_(dev, to_clk_fixed_rate(dev)); return 0; } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index cc9c430512d..6fda14f5fe6 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -192,6 +192,8 @@ struct clk_fixed_factor { unsigned int div; }; +extern const struct clk_ops clk_fixed_rate_ops; + #define to_clk_fixed_factor(_clk) container_of(_clk, struct clk_fixed_factor,\ clk) @@ -202,6 +204,9 @@ struct clk_fixed_rate { #define to_clk_fixed_rate(dev) ((struct clk_fixed_rate *)dev_get_plat(dev)) +void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev, + struct clk_fixed_rate *plat); + struct clk_composite { struct clk clk; struct clk_ops ops; -- cgit v1.3.1 From 6ba46a0f21df1804e1c98334215ac57a495d9655 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:25 +1300 Subject: dm: core: Drop device_get_by_driver_info() This function is now only used in a test. Drop it. Also drop DM_DRVINFO_GET() which was the only purpose for having the function. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- drivers/core/device.c | 15 --------------- include/dm/device.h | 15 --------------- include/dm/platdata.h | 15 --------------- test/dm/of_platdata.c | 7 ++----- 4 files changed, 2 insertions(+), 50 deletions(-) (limited to 'include') diff --git a/drivers/core/device.c b/drivers/core/device.c index e915b3089de..2399f6f70ce 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -811,21 +811,6 @@ int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp) } #if CONFIG_IS_ENABLED(OF_PLATDATA) -int device_get_by_driver_info(const struct driver_info *info, - struct udevice **devp) -{ - struct driver_info *info_base = - ll_entry_start(struct driver_info, driver_info); - int idx = info - info_base; - struct driver_rt *drt = gd_dm_driver_rt() + idx; - struct udevice *dev; - - dev = drt->dev; - *devp = NULL; - - return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp); -} - int device_get_by_driver_info_idx(uint idx, struct udevice **devp) { struct driver_rt *drt = gd_dm_driver_rt() + idx; diff --git a/include/dm/device.h b/include/dm/device.h index 5b8f27d455b..ca796059e0c 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -666,21 +666,6 @@ int device_find_global_by_ofnode(ofnode node, struct udevice **devp); */ int device_get_global_by_ofnode(ofnode node, struct udevice **devp); -/** - * device_get_by_driver_info() - Get a device based on driver_info - * - * Locates a device by its struct driver_info, by using its reference which - * is updated during the bind process. - * - * The device is probed to activate it ready for use. - * - * @info: Struct driver_info - * @devp: Returns pointer to device if found, otherwise this is set to NULL - * @return 0 if OK, -ve on error - */ -int device_get_by_driver_info(const struct driver_info *info, - struct udevice **devp); - /** * device_get_by_driver_info_idx() - Get a device based on driver_info index * diff --git a/include/dm/platdata.h b/include/dm/platdata.h index 3821a56f2ca..4efb1dfe12d 100644 --- a/include/dm/platdata.h +++ b/include/dm/platdata.h @@ -71,19 +71,4 @@ struct driver_rt { #define U_BOOT_DRVINFOS(__name) \ ll_entry_declare_list(struct driver_info, __name, driver_info) -/** - * Get a pointer to a given device info given its name - * - * With the declaration U_BOOT_DRVINFO(name), DM_DRVINFO_GET(name) will return a - * pointer to the struct driver_info created by that declaration. - * - * if OF_PLATDATA is enabled, from this it is possible to use the @dev member of - * struct driver_info to find the device pointer itself. - * - * @__name: Driver name (C identifier, not a string. E.g. gpio7_at_ff7e0000) - * @return struct driver_info * to the driver that created the device - */ -#define DM_DRVINFO_GET(__name) \ - ll_entry_get(struct driver_info, __name, driver_info) - #endif diff --git a/test/dm/of_platdata.c b/test/dm/of_platdata.c index 93ad5727255..d68c5912828 100644 --- a/test/dm/of_platdata.c +++ b/test/dm/of_platdata.c @@ -142,8 +142,6 @@ static int find_driver_info(struct unit_test_state *uts, struct udevice *parent, /* Check that every device is recorded in its driver_info struct */ static int dm_test_of_plat_dev(struct unit_test_state *uts) { - const struct driver_info *info = - ll_entry_start(struct driver_info, driver_info); const int n_ents = ll_entry_count(struct driver_info, driver_info); bool found[n_ents]; uint i; @@ -155,18 +153,17 @@ static int dm_test_of_plat_dev(struct unit_test_state *uts) /* Make sure that the driver entries without devices have no ->dev */ for (i = 0; i < n_ents; i++) { const struct driver_rt *drt = gd_dm_driver_rt() + i; - const struct driver_info *entry = info + i; struct udevice *dev; if (found[i]) { /* Make sure we can find it */ ut_assertnonnull(drt->dev); - ut_assertok(device_get_by_driver_info(entry, &dev)); + ut_assertok(device_get_by_driver_info_idx(i, &dev)); ut_asserteq_ptr(dev, drt->dev); } else { ut_assertnull(drt->dev); ut_asserteq(-ENOENT, - device_get_by_driver_info(entry, &dev)); + device_get_by_driver_info_idx(i, &dev)); } } -- cgit v1.3.1 From cc469b708667d24fc2a2c285e52d0d8ef5b14909 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:28 +1300 Subject: dm: Rename device_get_by_driver_info_idx() This function finds a device by its driver_info index. With of-platdata-inst we do not use driver_info, but instead instantiate udevice records at build-time. However the semantics of using the function are the same in each case: the caller provides an index and gets back a device. So rename the function to device_get_by_ofplat_idx(), so that it can be used for both situations. The caller does not really need to worry about the details. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- drivers/clk/clk-uclass.c | 2 +- drivers/core/device.c | 13 ++++++++++--- drivers/misc/irq-uclass.c | 2 +- drivers/mmc/fsl_esdhc_imx.c | 3 +-- include/dm/device.h | 16 +++++++++++----- test/dm/of_platdata.c | 15 +++++++-------- 6 files changed, 31 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index b87288da7a2..4ab3c402ed8 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -39,7 +39,7 @@ int clk_get_by_driver_info(struct udevice *dev, struct phandle_1_arg *cells, { int ret; - ret = device_get_by_driver_info_idx(cells->idx, &clk->dev); + ret = device_get_by_ofplat_idx(cells->idx, &clk->dev); if (ret) return ret; clk->id = cells->arg[0]; diff --git a/drivers/core/device.c b/drivers/core/device.c index 2399f6f70ce..1990b6f69f8 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -811,12 +811,19 @@ int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp) } #if CONFIG_IS_ENABLED(OF_PLATDATA) -int device_get_by_driver_info_idx(uint idx, struct udevice **devp) +int device_get_by_ofplat_idx(uint idx, struct udevice **devp) { - struct driver_rt *drt = gd_dm_driver_rt() + idx; struct udevice *dev; - dev = drt->dev; + if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) { + struct udevice *base = ll_entry_start(struct udevice, udevice); + + dev = base + idx; + } else { + struct driver_rt *drt = gd_dm_driver_rt() + idx; + + dev = drt->dev; + } *devp = NULL; return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp); diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c index 24b27962a7d..3aa26f61d9e 100644 --- a/drivers/misc/irq-uclass.c +++ b/drivers/misc/irq-uclass.c @@ -69,7 +69,7 @@ int irq_get_by_driver_info(struct udevice *dev, { int ret; - ret = device_get_by_driver_info_idx(cells->idx, &irq->dev); + ret = device_get_by_ofplat_idx(cells->idx, &irq->dev); if (ret) return ret; irq->id = cells->arg[0]; diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 6a9403dc004..09a5cd61e3b 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -1530,8 +1530,7 @@ static int fsl_esdhc_probe(struct udevice *dev) if (CONFIG_IS_ENABLED(DM_GPIO) && !priv->non_removable) { struct udevice *gpiodev; - ret = device_get_by_driver_info_idx(dtplat->cd_gpios->idx, - &gpiodev); + ret = device_get_by_ofplat_idx(dtplat->cd_gpios->idx, &gpiodev); if (ret) return ret; diff --git a/include/dm/device.h b/include/dm/device.h index ca796059e0c..9183356468f 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -667,18 +667,24 @@ int device_find_global_by_ofnode(ofnode node, struct udevice **devp); int device_get_global_by_ofnode(ofnode node, struct udevice **devp); /** - * device_get_by_driver_info_idx() - Get a device based on driver_info index + * device_get_by_ofplat_idx() - Get a device based on of-platdata index * - * Locates a device by its struct driver_info, by using its index number which - * is written into the idx field of struct phandle_1_arg, etc. + * Locates a device by either its struct driver_info index, or its + * struct udevice index. The latter is used with OF_PLATDATA_INST, since we have + * a list of build-time instantiated struct udevice records, The former is used + * with !OF_PLATDATA_INST since in that case we have a list of + * struct driver_info records. + * + * The index number is written into the idx field of struct phandle_1_arg, etc. + * It is the position of this driver_info/udevice in its linker list. * * The device is probed to activate it ready for use. * - * @idx: Index number of the driver_info structure (0=first) + * @idx: Index number of the driver_info/udevice structure (0=first) * @devp: Returns pointer to device if found, otherwise this is set to NULL * @return 0 if OK, -ve on error */ -int device_get_by_driver_info_idx(uint idx, struct udevice **devp); +int device_get_by_ofplat_idx(uint idx, struct udevice **devp); /** * device_find_first_child() - Find the first child of a device diff --git a/test/dm/of_platdata.c b/test/dm/of_platdata.c index d68c5912828..e5f32a0f1c4 100644 --- a/test/dm/of_platdata.c +++ b/test/dm/of_platdata.c @@ -158,12 +158,11 @@ static int dm_test_of_plat_dev(struct unit_test_state *uts) if (found[i]) { /* Make sure we can find it */ ut_assertnonnull(drt->dev); - ut_assertok(device_get_by_driver_info_idx(i, &dev)); + ut_assertok(device_get_by_ofplat_idx(i, &dev)); ut_asserteq_ptr(dev, drt->dev); } else { ut_assertnull(drt->dev); - ut_asserteq(-ENOENT, - device_get_by_driver_info_idx(i, &dev)); + ut_asserteq(-ENOENT, device_get_by_ofplat_idx(i, &dev)); } } @@ -181,22 +180,22 @@ static int dm_test_of_plat_phandle(struct unit_test_state *uts) ut_asserteq_str("sandbox_clk_test", dev->name); plat = dev_get_plat(dev); - ut_assertok(device_get_by_driver_info_idx(plat->clocks[0].idx, &clk)); + ut_assertok(device_get_by_ofplat_idx(plat->clocks[0].idx, &clk)); ut_asserteq_str("sandbox_fixed_clock", clk->name); - ut_assertok(device_get_by_driver_info_idx(plat->clocks[1].idx, &clk)); + ut_assertok(device_get_by_ofplat_idx(plat->clocks[1].idx, &clk)); ut_asserteq_str("sandbox_clk", clk->name); ut_asserteq(1, plat->clocks[1].arg[0]); - ut_assertok(device_get_by_driver_info_idx(plat->clocks[2].idx, &clk)); + ut_assertok(device_get_by_ofplat_idx(plat->clocks[2].idx, &clk)); ut_asserteq_str("sandbox_clk", clk->name); ut_asserteq(0, plat->clocks[2].arg[0]); - ut_assertok(device_get_by_driver_info_idx(plat->clocks[3].idx, &clk)); + ut_assertok(device_get_by_ofplat_idx(plat->clocks[3].idx, &clk)); ut_asserteq_str("sandbox_clk", clk->name); ut_asserteq(3, plat->clocks[3].arg[0]); - ut_assertok(device_get_by_driver_info_idx(plat->clocks[4].idx, &clk)); + ut_assertok(device_get_by_ofplat_idx(plat->clocks[4].idx, &clk)); ut_asserteq_str("sandbox_clk", clk->name); ut_asserteq(2, plat->clocks[4].arg[0]); -- cgit v1.3.1 From 728d04cc72855e23f6a9116e68911dcac5be4693 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:30 +1300 Subject: sandbox: i2c: Support i2c emulation with of-platdata At present the i2c emulators require access to the devicetree, which is not possible (by design) with of-platdata. Add a way for drivers to record the of-platdata index of their emulator, so that we can still find the emulator. This allows i2c emulation to work with of-platdata. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- drivers/i2c/i2c-emul-uclass.c | 17 +++++++++++++++-- drivers/rtc/sandbox_rtc.c | 13 +++++++++++++ include/i2c.h | 15 +++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c index 9ef4651fa43..7917b63c55b 100644 --- a/drivers/i2c/i2c-emul-uclass.c +++ b/drivers/i2c/i2c-emul-uclass.c @@ -31,14 +31,27 @@ struct udevice *i2c_emul_get_device(struct udevice *emul) return uc_plat->dev; } +void i2c_emul_set_idx(struct udevice *dev, int emul_idx) +{ + struct dm_i2c_chip *plat = dev_get_parent_plat(dev); + + plat->emul_idx = emul_idx; +} + int i2c_emul_find(struct udevice *dev, struct udevice **emulp) { struct i2c_emul_uc_plat *uc_plat; struct udevice *emul; int ret; - ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev, - "sandbox,emul", &emul); + if (!CONFIG_IS_ENABLED(OF_PLATDATA)) { + ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev, + "sandbox,emul", &emul); + } else { + struct dm_i2c_chip *plat = dev_get_parent_plat(dev); + + ret = device_get_by_ofplat_idx(plat->emul_idx, &emul); + } if (ret) { log_err("No emulators for device '%s'\n", dev->name); return ret; diff --git a/drivers/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c index d0864b1df97..657e5c7be2c 100644 --- a/drivers/rtc/sandbox_rtc.c +++ b/drivers/rtc/sandbox_rtc.c @@ -79,6 +79,18 @@ struct acpi_ops sandbox_rtc_acpi_ops = { }; #endif +static int sandbox_rtc_bind(struct udevice *dev) +{ +#if CONFIG_IS_ENABLED(PLATDATA) + struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev); + + /* Set up the emul_idx for i2c_emul_find() */ + i2c_emul_set_idx(dev, plat->dtplat.sandbox_emul->idx); +#endif + + return 0; +} + static const struct rtc_ops sandbox_rtc_ops = { .get = sandbox_rtc_get, .set = sandbox_rtc_set, @@ -97,5 +109,6 @@ U_BOOT_DRIVER(sandbox_rtc) = { .id = UCLASS_RTC, .of_match = sandbox_rtc_ids, .ops = &sandbox_rtc_ops, + .bind = sandbox_rtc_bind, ACPI_OPS_PTR(&sandbox_rtc_acpi_ops) }; diff --git a/include/i2c.h b/include/i2c.h index 7ae0c42706e..c0fe94c1f33 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -93,6 +93,8 @@ struct udevice; * datasheet explains it's usage of this addressing * mode. * @emul: Emulator for this chip address (only used for emulation) + * @emul_idx: Emulator index, used for of-platdata and set by each i2c chip's + * bind() method. This allows i2c_emul_find() to work with of-platdata. */ struct dm_i2c_chip { uint chip_addr; @@ -102,6 +104,7 @@ struct dm_i2c_chip { #ifdef CONFIG_SANDBOX struct udevice *emul; bool test_mode; + int emul_idx; #endif }; @@ -554,6 +557,18 @@ void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs); */ int i2c_emul_find(struct udevice *dev, struct udevice **emulp); +/** + * i2c_emul_set_idx() - Set the emulator index for an i2c sandbox device + * + * With of-platdata we cannot find the emulator using the device tree, so rely + * on the bind() method of each i2c driver calling this function to tell us + * the of-platdata idx of the emulator + * + * @dev: i2c device to set the emulator for + * @emul_idx: of-platdata index for that emulator + */ +void i2c_emul_set_idx(struct udevice *dev, int emul_idx); + /** * i2c_emul_get_device() - Find the device being emulated * -- cgit v1.3.1 From ab933d802643ca51d276f0f449921a047126f8a1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:36 +1300 Subject: dm: core: Create a struct for device runtime info At present when driver model needs to change a device it simply updates the struct udevice structure. But with of-platdata-inst most of the fields are not modified at runtime. In fact, typically only the flags need to change. For systems running SPL from read-only memory it is convenient to separate out the runtime information, so that the devices don't need to be copied before being used. Create a new udevice_rt table, similar to the existing driver_rt. For now it just holds the flags, although they are not used in this patch. Add a new Kconfig for the driver_rt data, since this is not needed when of-platdata-inst is used. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- drivers/core/root.c | 14 +++++++++++++- dts/Kconfig | 20 ++++++++++++++++++++ include/asm-generic/global_data.h | 16 ++++++++++++++-- include/dm/device.h | 15 +++++++++++++++ test/dm/of_platdata.c | 2 +- 5 files changed, 63 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/core/root.c b/drivers/core/root.c index 3e52452cd85..446ac2ff774 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -133,6 +133,18 @@ static int dm_setup_inst(void) { DM_ROOT_NON_CONST = DM_DEVICE_GET(root); + if (CONFIG_IS_ENABLED(OF_PLATDATA_RT)) { + struct udevice_rt *urt; + int n_ents; + + /* Allocate the udevice_rt table */ + n_ents = ll_entry_count(struct udevice, udevice); + urt = calloc(n_ents, sizeof(struct udevice_rt)); + if (!urt) + return log_msg_ret("urt", -ENOMEM); + gd_set_dm_udevice_rt(urt); + } + return 0; } @@ -205,7 +217,7 @@ int dm_scan_plat(bool pre_reloc_only) { int ret; - if (CONFIG_IS_ENABLED(OF_PLATDATA)) { + if (CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)) { struct driver_rt *dyn; int n_ents; diff --git a/dts/Kconfig b/dts/Kconfig index e6bbdc596bd..99ce75e1a2a 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -338,6 +338,7 @@ config SPL_OF_PLATDATA bool "Generate platform data for use in SPL" depends on SPL_OF_CONTROL select DTOC + select SPL_OF_PLATDATA_DRIVER_RT if !SPL_OF_PLATDATA_INST help For very constrained SPL environments the overhead of decoding device tree nodes and converting their contents into platform data @@ -391,12 +392,22 @@ config SPL_OF_PLATDATA_RT struct udevice (at present just the flags) into a separate struct, which is allocated at runtime. +config SPL_OF_PLATDATA_DRIVER_RT + bool + help + Use a separate struct for driver runtime data. + + This enables the driver_rt information, used with of-platdata when + of-platdata-inst is not used. It allows finding devices by their + driver data. + endif config TPL_OF_PLATDATA bool "Generate platform data for use in TPL" depends on TPL_OF_CONTROL select DTOC + select TPL_OF_PLATDATA_DRIVER_RT if !TPL_OF_PLATDATA_INST help For very constrained SPL environments the overhead of decoding device tree nodes and converting their contents into platform data @@ -451,6 +462,15 @@ config TPL_OF_PLATDATA_RT struct udevice (at present just the flags) into a separate struct, which is allocated at runtime. +config TPL_OF_PLATDATA_DRIVER_RT + bool + help + Use a separate struct for driver runtime data. + + This enables the driver_rt information, used with of-platdata when + of-platdata-inst is not used. It allows finding devices by their + driver data. + endif endmenu diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index c24f5e0e973..f6189eff4eb 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -215,10 +215,14 @@ struct global_data { * @uclass_root_s. */ struct list_head *uclass_root; -# if CONFIG_IS_ENABLED(OF_PLATDATA) +# if CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT) /** @dm_driver_rt: Dynamic info about the driver */ struct driver_rt *dm_driver_rt; # endif +#if CONFIG_IS_ENABLED(OF_PLATDATA_RT) + /** @dm_udevice_rt: Dynamic info about the udevice */ + struct udevice_rt *dm_udevice_rt; +# endif #endif #ifdef CONFIG_TIMER /** @@ -483,7 +487,7 @@ struct global_data { #define gd_set_of_root(_root) #endif -#if CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT) #define gd_set_dm_driver_rt(dyn) gd->dm_driver_rt = dyn #define gd_dm_driver_rt() gd->dm_driver_rt #else @@ -491,6 +495,14 @@ struct global_data { #define gd_dm_driver_rt() NULL #endif +#if CONFIG_IS_ENABLED(OF_PLATDATA_RT) +#define gd_set_dm_udevice_rt(dyn) gd->dm_udevice_rt = dyn +#define gd_dm_udevice_rt() gd->dm_udevice_rt +#else +#define gd_set_dm_udevice_rt(dyn) +#define gd_dm_udevice_rt() NULL +#endif + #ifdef CONFIG_GENERATE_ACPI_TABLE #define gd_acpi_ctx() gd->acpi_ctx #else diff --git a/include/dm/device.h b/include/dm/device.h index 9183356468f..8e16f2ea497 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -190,6 +190,21 @@ struct udevice { #endif }; +/** + * udevice_rt - runtime information set up by U-Boot + * + * This is only used with OF_PLATDATA_RT + * + * There is one of these for every udevice in the linker list, indexed by + * the udevice_info idx value. + * + * @flags_: Flags for this device DM_FLAG_... (do not access outside driver + * model) + */ +struct udevice_rt { + u32 flags_; +}; + /* Maximum sequence number supported */ #define DM_MAX_SEQ 999 diff --git a/test/dm/of_platdata.c b/test/dm/of_platdata.c index f2b45b9a868..0f89c7a7da8 100644 --- a/test/dm/of_platdata.c +++ b/test/dm/of_platdata.c @@ -147,7 +147,7 @@ static int dm_test_of_plat_dev(struct unit_test_state *uts) uint i; /* Skip this test if there is no platform data */ - if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) + if (!CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)) return 0; /* Record the indexes that are found */ -- cgit v1.3.1 From 6f644efdd803e0718d39266f75c0535a534cc601 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:37 +1300 Subject: dm: core: Move flags to device-runtime info When of-platdata-inst is active, use the flags in the new udevice_rt table, dropping them from the main struct udevice. This ensures that the latter is not updated at runtime. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- drivers/core/device.c | 33 +++++++++++++++++++++++++++++++++ include/dm/device.h | 8 ++++++++ 2 files changed, 41 insertions(+) (limited to 'include') diff --git a/drivers/core/device.c b/drivers/core/device.c index 1990b6f69f8..06d2467825f 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -1136,3 +1136,36 @@ int dev_enable_by_path(const char *path) return lists_bind_fdt(parent, node, NULL, false); } #endif + +#if CONFIG_IS_ENABLED(OF_PLATDATA_RT) +static struct udevice_rt *dev_get_rt(const struct udevice *dev) +{ + struct udevice *base = ll_entry_start(struct udevice, udevice); + int idx = dev - base; + + struct udevice_rt *urt = gd_dm_udevice_rt() + idx; + + return urt; +} + +u32 dev_get_flags(const struct udevice *dev) +{ + const struct udevice_rt *urt = dev_get_rt(dev); + + return urt->flags_; +} + +void dev_or_flags(const struct udevice *dev, u32 or) +{ + struct udevice_rt *urt = dev_get_rt(dev); + + urt->flags_ |= or; +} + +void dev_bic_flags(const struct udevice *dev, u32 bic) +{ + struct udevice_rt *urt = dev_get_rt(dev); + + urt->flags_ &= ~bic; +} +#endif /* OF_PLATDATA_RT */ diff --git a/include/dm/device.h b/include/dm/device.h index 8e16f2ea497..0a9718a5b81 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -177,7 +177,9 @@ struct udevice { struct list_head uclass_node; struct list_head child_head; struct list_head sibling_node; +#if !CONFIG_IS_ENABLED(OF_PLATDATA_RT) u32 flags_; +#endif int seq_; #if !CONFIG_IS_ENABLED(OF_PLATDATA) ofnode node_; @@ -211,6 +213,11 @@ struct udevice_rt { /* Returns the operations for a device */ #define device_get_ops(dev) (dev->driver->ops) +#if CONFIG_IS_ENABLED(OF_PLATDATA_RT) +u32 dev_get_flags(const struct udevice *dev); +void dev_or_flags(const struct udevice *dev, u32 or); +void dev_bic_flags(const struct udevice *dev, u32 bic); +#else static inline u32 dev_get_flags(const struct udevice *dev) { return dev->flags_; @@ -225,6 +232,7 @@ static inline void dev_bic_flags(struct udevice *dev, u32 bic) { dev->flags_ &= ~bic; } +#endif /* OF_PLATDATA_RT */ /** * dev_ofnode() - get the DT node reference associated with a udevice -- cgit v1.3.1 From baf0371883b243fa793ba3f984704b027705d6a9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:38 +1300 Subject: dm: core: Allow storing priv/plat data separately At present the device priv/data data allocated by dtoc is stored in the data section along with other variables. On some platforms it is better to allocate space for it separately, e.g. if SPL is running from read-only memory. Create a new space with the same size as that allocated by dtoc, ready for use. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- drivers/core/root.c | 12 ++++++++++++ include/asm-generic/global_data.h | 10 ++++++++++ include/asm-generic/sections.h | 3 +++ 3 files changed, 25 insertions(+) (limited to 'include') diff --git a/drivers/core/root.c b/drivers/core/root.c index 446ac2ff774..82b3c7de715 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -135,7 +136,9 @@ static int dm_setup_inst(void) if (CONFIG_IS_ENABLED(OF_PLATDATA_RT)) { struct udevice_rt *urt; + void *base; int n_ents; + uint size; /* Allocate the udevice_rt table */ n_ents = ll_entry_count(struct udevice, udevice); @@ -143,6 +146,15 @@ static int dm_setup_inst(void) if (!urt) return log_msg_ret("urt", -ENOMEM); gd_set_dm_udevice_rt(urt); + + /* Now allocate space for the priv/plat data, and copy it in */ + size = __priv_data_end - __priv_data_start; + + base = calloc(1, size); + if (!base) + return log_msg_ret("priv", -ENOMEM); + memcpy(base, __priv_data_start, size); + gd_set_dm_priv_base(base); } return 0; diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index f6189eff4eb..e1a5f4b1d18 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -222,6 +222,12 @@ struct global_data { #if CONFIG_IS_ENABLED(OF_PLATDATA_RT) /** @dm_udevice_rt: Dynamic info about the udevice */ struct udevice_rt *dm_udevice_rt; + /** + * @dm_priv_base: Base address of the priv/plat region used when + * udevices and uclasses are in read-only memory. This is NULL if not + * used + */ + void *dm_priv_base; # endif #endif #ifdef CONFIG_TIMER @@ -498,9 +504,13 @@ struct global_data { #if CONFIG_IS_ENABLED(OF_PLATDATA_RT) #define gd_set_dm_udevice_rt(dyn) gd->dm_udevice_rt = dyn #define gd_dm_udevice_rt() gd->dm_udevice_rt +#define gd_set_dm_priv_base(dyn) gd->dm_priv_base = dyn +#define gd_dm_priv_base() gd->dm_priv_base #else #define gd_set_dm_udevice_rt(dyn) #define gd_dm_udevice_rt() NULL +#define gd_set_dm_priv_base(dyn) +#define gd_dm_priv_base() NULL #endif #ifdef CONFIG_GENERATE_ACPI_TABLE diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 0577238d60b..267f1db73f2 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -28,6 +28,9 @@ extern char __efi_helloworld_end[]; extern char __efi_var_file_begin[]; extern char __efi_var_file_end[]; +/* Private data used by of-platdata devices/uclasses */ +extern char __priv_data_start[], __priv_data_end[]; + /* Start and end of .ctors section - used for constructor calls. */ extern char __ctors_start[], __ctors_end[]; -- cgit v1.3.1 From cfb9c9b77c29f48ae2c71ff30ca294bdaf369d87 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:40 +1300 Subject: dm: core: Use separate priv/plat data region Make use of the new priv/plat data region if enabled. This is implemented as a simple offset from the position set up by dtoc to the new position. So long as all access goes through dm_priv_to_rw() this is safe. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- drivers/core/device.c | 12 ++++++------ drivers/core/root.c | 9 +++++++++ include/dm/util.h | 9 +++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/core/device.c b/drivers/core/device.c index 06d2467825f..cb960f8ec44 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -600,7 +600,7 @@ void *dev_get_plat(const struct udevice *dev) return NULL; } - return dev->plat_; + return dm_priv_to_rw(dev->plat_); } void *dev_get_parent_plat(const struct udevice *dev) @@ -610,7 +610,7 @@ void *dev_get_parent_plat(const struct udevice *dev) return NULL; } - return dev->parent_plat_; + return dm_priv_to_rw(dev->parent_plat_); } void *dev_get_uclass_plat(const struct udevice *dev) @@ -620,7 +620,7 @@ void *dev_get_uclass_plat(const struct udevice *dev) return NULL; } - return dev->uclass_plat_; + return dm_priv_to_rw(dev->uclass_plat_); } void *dev_get_priv(const struct udevice *dev) @@ -630,7 +630,7 @@ void *dev_get_priv(const struct udevice *dev) return NULL; } - return dev->priv_; + return dm_priv_to_rw(dev->priv_); } void *dev_get_uclass_priv(const struct udevice *dev) @@ -640,7 +640,7 @@ void *dev_get_uclass_priv(const struct udevice *dev) return NULL; } - return dev->uclass_priv_; + return dm_priv_to_rw(dev->uclass_priv_); } void *dev_get_parent_priv(const struct udevice *dev) @@ -650,7 +650,7 @@ void *dev_get_parent_priv(const struct udevice *dev) return NULL; } - return dev->parent_priv_; + return dm_priv_to_rw(dev->parent_priv_); } static int device_get_device_tail(struct udevice *dev, int ret, diff --git a/drivers/core/root.c b/drivers/core/root.c index 82b3c7de715..d9a19c5e6b6 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -347,6 +347,15 @@ __weak int dm_scan_other(bool pre_reloc_only) return 0; } +#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY) +void *dm_priv_to_rw(void *priv) +{ + long offset = priv - (void *)__priv_data_start; + + return gd_dm_priv_base() + offset; +} +#endif + /** * dm_scan() - Scan tables to bind devices * diff --git a/include/dm/util.h b/include/dm/util.h index 01a044992f2..138893c9354 100644 --- a/include/dm/util.h +++ b/include/dm/util.h @@ -49,3 +49,12 @@ void dm_dump_driver_compat(void); void dm_dump_static_driver_info(void); #endif + +#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY) +void *dm_priv_to_rw(void *priv); +#else +static inline void *dm_priv_to_rw(void *priv) +{ + return priv; +} +#endif -- cgit v1.3.1 From e81bf6d72fbd016027d856f6da6047d39903390b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 17:25:41 +1300 Subject: dm: core: Add warnings to private / platform setters Add a warning to each of these functions so that people do not attempt to use them outside driver model. Signed-off-by: Simon Glass Signed-off-by: Simon Glass --- include/dm/device-internal.h | 18 ++++++++++++++++++ include/dm/uclass-internal.h | 3 +++ 2 files changed, 21 insertions(+) (limited to 'include') diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 71e5c75028d..e6b71cbfd2b 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -284,6 +284,9 @@ static inline int device_chld_remove(struct udevice *dev, struct driver *drv, * Use this function to override normal operation for special situations, such * as needing to allocate a variable amount of data. * + * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver + * model code, since the pointer must be within the gd->dm_priv_base region. + * * @dev Device to check * @priv New private-data pointer */ @@ -298,6 +301,9 @@ void dev_set_priv(struct udevice *dev, void *priv); * Use this function to override normal operation for special situations, such * as needing to allocate a variable amount of data. * + * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver + * model code, since the pointer must be within the gd->dm_priv_base region. + * * @dev: Device to update * @parent_priv: New parent-private data */ @@ -312,6 +318,9 @@ void dev_set_parent_priv(struct udevice *dev, void *parent_priv); * Use this function to override normal operation for special situations, such * as needing to allocate a variable amount of data. * + * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver + * model code, since the pointer must be within the gd->dm_priv_base region. + * * @dev: Device to update * @uclass_priv: New uclass private data */ @@ -326,6 +335,9 @@ void dev_set_uclass_priv(struct udevice *dev, void *uclass_priv); * Use this function to override normal operation for special situations, such * as needing to allocate a variable amount of data. * + * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver + * model code, since the pointer must be within the gd->dm_priv_base region. + * * @dev Device to check * @plat New platform-data pointer */ @@ -340,6 +352,9 @@ void dev_set_plat(struct udevice *dev, void *priv); * Use this function to override normal operation for special situations, such * as needing to allocate a variable amount of data. * + * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver + * model code, since the pointer must be within the gd->dm_priv_base region. + * * @dev: Device to update * @parent_plat: New parent platform data */ @@ -354,6 +369,9 @@ void dev_set_parent_plat(struct udevice *dev, void *parent_plat); * Use this function to override normal operation for special situations, such * as needing to allocate a variable amount of data. * + * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver + * model code, since the pointer must be within the gd->dm_priv_base region. + * * @dev: Device to update * @uclass_plat: New uclass platform data */ diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h index f2a780682b4..57c664c6daa 100644 --- a/include/dm/uclass-internal.h +++ b/include/dm/uclass-internal.h @@ -69,6 +69,9 @@ * Use this function to override normal operation for special situations, such * as needing to allocate a variable amount of data. * + * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver + * model code, since the pointer must be within the gd->dm_priv_base region. + * * @uc Uclass to update * @priv New private-data pointer */ -- cgit v1.3.1 From b09c74f66d46fac7f25e53a0c06f832cf0638a5c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 10 Mar 2021 18:23:57 +0100 Subject: mtd: spi_flash_free() dfu_free_entities() invoking dfu_free_entity_sf() has let to segementation faults due to double freeing the same device. spi_flash_free() is not relevant for the driver model but exists only for compatibility with old drivers. We must not remove any device here: * The device may still be referenced. * We don't want to have to probe again. Signed-off-by: Heinrich Schuchardt --- drivers/mtd/spi/sf-uclass.c | 5 ----- include/spi_flash.h | 4 +++- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c index 12d132152d3..fd1bec80d64 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -46,11 +46,6 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, return dev_get_uclass_priv(dev); } -void spi_flash_free(struct spi_flash *flash) -{ - device_remove(flash->spi->dev, DM_REMOVE_NORMAL); -} - int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, unsigned int max_hz, unsigned int spi_mode, struct udevice **devp) diff --git a/include/spi_flash.h b/include/spi_flash.h index 85cae32cc73..478c543b06b 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -97,7 +97,9 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int spi_mode); /* Compatibility function - this is the old U-Boot API */ -void spi_flash_free(struct spi_flash *flash); +static inline void spi_flash_free(struct spi_flash *flash) +{ +} static inline int spi_flash_read(struct spi_flash *flash, u32 offset, size_t len, void *buf) -- cgit v1.3.1 From 041089fe930b6c7bdaadfb1e81a77dd8ca45e907 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:00:05 +1300 Subject: x86: coral: Put the eMMC first At present the eMMC device does not have an alias so it appears after the SD card which is device 1. There is no device 0 which is odd. Make the eMMC device be the first one. Update the boot script to use the new device. Signed-off-by: Simon Glass Reviewed-by: Jaehoon Chung --- arch/x86/dts/chromebook_coral.dts | 1 + include/configs/chromebook_coral.h | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/x86/dts/chromebook_coral.dts b/arch/x86/dts/chromebook_coral.dts index d109a387597..4cadfd198d0 100644 --- a/arch/x86/dts/chromebook_coral.dts +++ b/arch/x86/dts/chromebook_coral.dts @@ -47,6 +47,7 @@ i2c5 = &i2c_5; i2c6 = &i2c_6; i2c7 = &i2c_7; + mmc0 = &emmc; mmc1 = &sdmmc; }; diff --git a/include/configs/chromebook_coral.h b/include/configs/chromebook_coral.h index 6e8e8ec1709..00760b8a307 100644 --- a/include/configs/chromebook_coral.h +++ b/include/configs/chromebook_coral.h @@ -12,13 +12,13 @@ #define CONFIG_BOOTCOMMAND \ "tpm init; tpm startup TPM2_SU_CLEAR; " \ - "read mmc 2:2 100000 0 80; setexpr loader *001004f0; " \ + "read mmc 0:2 100000 0 80; setexpr loader *001004f0; " \ "setexpr size *00100518; setexpr blocks $size / 200; " \ - "read mmc 2:2 100000 80 $blocks; setexpr setup $loader - 1000; " \ + "read mmc 0:2 100000 80 $blocks; setexpr setup $loader - 1000; " \ "setexpr cmdline_ptr $loader - 2000; " \ "setexpr.s cmdline *$cmdline_ptr; " \ "setexpr cmdline gsub %U \\\\${uuid}; " \ - "if part uuid mmc 2:2 uuid; then " \ + "if part uuid mmc 0:2 uuid; then " \ "zboot start 100000 0 0 0 $setup cmdline; " \ "zboot load; zboot setup; zboot dump; zboot go;" \ "fi" -- cgit v1.3.1 From 72ca4859784227138a42d924678222d68fc20484 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:00:09 +1300 Subject: cbfs: Add support for attributes CBFS now supports attributes for things that cannot fit in the header as originally conceived. Add the structures for these. Also rename attributes_offset to something shorter, to ease code readability. Signed-off-by: Simon Glass --- fs/cbfs/cbfs.c | 2 +- include/cbfs.h | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/cbfs/cbfs.c b/fs/cbfs/cbfs.c index 9007aa7d159..abc43ad33f6 100644 --- a/fs/cbfs/cbfs.c +++ b/fs/cbfs/cbfs.c @@ -129,7 +129,7 @@ static int file_cbfs_next_file(struct cbfs_priv *priv, void *start, int size, new_node->name = (char *)file_header + sizeof(struct cbfs_fileheader); new_node->name_length = name_len; - new_node->attributes_offset = header.attributes_offset; + new_node->attr_offset = header.attributes_offset; step = header.len; if (step % align) diff --git a/include/cbfs.h b/include/cbfs.h index 5f296d6a371..d98afea6480 100644 --- a/include/cbfs.h +++ b/include/cbfs.h @@ -68,6 +68,43 @@ struct cbfs_fileheader { /* offset to struct cbfs_file_attribute or 0 */ u32 attributes_offset; u32 offset; + char filename[]; +} __packed; + +/* + * Depending on how the header was initialized, it may be backed with 0x00 or + * 0xff, so support both + */ +#define CBFS_FILE_ATTR_TAG_UNUSED 0 +#define CBFS_FILE_ATTR_TAG_UNUSED2 0xffffffff +#define CBFS_FILE_ATTR_TAG_COMPRESSION 0x42435a4c +#define CBFS_FILE_ATTR_TAG_HASH 0x68736148 + +/* + * The common fields of extended cbfs file attributes. Attributes are expected + * to start with tag/len, then append their specific fields + */ +struct cbfs_file_attribute { + u32 tag; + /* len covers the whole structure, incl. tag and len */ + u32 len; + u8 data[0]; +} __packed; + +struct cbfs_file_attr_compression { + u32 tag; + u32 len; + /* whole file compression format. 0 if no compression. */ + u32 compression; + u32 decompressed_size; +} __packed; + +struct cbfs_file_attr_hash { + u32 tag; + u32 len; + u32 hash_type; + /* hash_data is len - sizeof(struct) bytes */ + u8 hash_data[]; } __packed; struct cbfs_cachenode { @@ -77,7 +114,7 @@ struct cbfs_cachenode { u32 type; u32 data_length; u32 name_length; - u32 attributes_offset; + u32 attr_offset; }; /** -- cgit v1.3.1 From 272e62cb83f01acf7ae89449eaa9f020e76bff23 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:00:11 +1300 Subject: smbios: Allow writing to the coreboot version string When U-Boot is booted from coreboot the SMBIOS tables are written by coreboot, not U-Boot. The existing method of updating the BIOS version string does not work in that case, since gd->smbios_version is only set when U-Boot writes the tables. Add a new function which allows the version to be updated by parsing the tables and writing the string in the correct place. Since coreboot provides a pointer to the SMBIOS tables in its sysinfo structure, this makes it easy to do the update. Signed-off-by: Simon Glass --- include/smbios.h | 20 ++++++++++++++++++++ lib/smbios-parser.c | 38 ++++++++++++++++++++++++++++++++++++++ lib/smbios.c | 4 ---- 3 files changed, 58 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/smbios.h b/include/smbios.h index ecc4fd1de3b..ffeefb47372 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -14,6 +14,10 @@ #define SMBIOS_MAJOR_VER 3 #define SMBIOS_MINOR_VER 0 +enum { + SMBIOS_STR_MAX = 64, /* Maximum length allowed for a string */ +}; + /* SMBIOS structure types */ enum { SMBIOS_BIOS_INFORMATION = 0, @@ -269,4 +273,20 @@ const char *smbios_string(const struct smbios_header *header, int index); */ int smbios_update_version(const char *version); +/** + * smbios_update_version_full() - Update the version string + * + * This can be called after the SMBIOS tables are written (e.g. after the U-Boot + * main loop has started) to update the BIOS version string (SMBIOS table 0). + * It scans for the correct place to put the version, so does not need U-Boot + * to have actually written the tables itself (e.g. if a previous bootloader + * did it). + * + * @smbios_tab: Start of SMBIOS tables + * @version: New version string to use + * @return 0 if OK, -ENOENT if no version string was previously written, + * -ENOSPC if the new string is too large to fit + */ +int smbios_update_version_full(void *smbios_tab, const char *version); + #endif /* _SMBIOS_H_ */ diff --git a/lib/smbios-parser.c b/lib/smbios-parser.c index b89f988ef9f..34203f952c9 100644 --- a/lib/smbios-parser.c +++ b/lib/smbios-parser.c @@ -3,6 +3,8 @@ * Copyright (C) 2020, Bachmann electronic GmbH */ +#define LOG_CATEGORY LOGC_BOOT + #include #include @@ -94,3 +96,39 @@ const char *smbios_string(const struct smbios_header *header, int index) return string_from_smbios_table(header, index); } + +int smbios_update_version_full(void *smbios_tab, const char *version) +{ + const struct smbios_header *hdr; + struct smbios_type0 *bios; + uint old_len, len; + char *ptr; + + log_info("Updating SMBIOS table at %p\n", smbios_tab); + hdr = smbios_header(smbios_tab, SMBIOS_BIOS_INFORMATION); + if (!hdr) + return log_msg_ret("tab", -ENOENT); + bios = (struct smbios_type0 *)hdr; + ptr = (char *)smbios_string(hdr, bios->bios_ver); + if (!ptr) + return log_msg_ret("str", -ENOMEDIUM); + + /* + * This string is supposed to have at least enough bytes and is + * padded with spaces. Update it, taking care not to move the + * \0 terminator, so that other strings in the string table + * are not disturbed. See smbios_add_string() + */ + old_len = strnlen(ptr, SMBIOS_STR_MAX); + len = strnlen(version, SMBIOS_STR_MAX); + if (len > old_len) + return log_ret(-ENOSPC); + + log_debug("Replacing SMBIOS type 0 version string '%s'\n", ptr); + memcpy(ptr, version, len); +#ifdef LOG_DEBUG + print_buffer((ulong)ptr, ptr, 1, old_len + 1, 0); +#endif + + return 0; +} diff --git a/lib/smbios.c b/lib/smbios.c index 7d463c84a93..9eb226ec9fb 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -20,10 +20,6 @@ DECLARE_GLOBAL_DATA_PTR; -enum { - SMBIOS_STR_MAX = 64, /* Maximum length allowed for a string */ -}; - /** * struct smbios_ctx - context for writing SMBIOS tables * -- cgit v1.3.1 From 5536f1285fd2f9ec3e177d6e74b7eb73c6821c8b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:00:12 +1300 Subject: cbfs: Allow access to CBFS without a header In some cases CBFS does not start with a header but is just a collection of files. It is possible to support this so long as the size of the CBFS is provided. Update the cbfs_init_mem() function to support this. Signed-off-by: Simon Glass --- arch/x86/lib/fsp2/fsp_init.c | 3 ++- fs/cbfs/cbfs.c | 18 +++++++++++++----- include/cbfs.h | 8 ++++++-- 3 files changed, 21 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/arch/x86/lib/fsp2/fsp_init.c b/arch/x86/lib/fsp2/fsp_init.c index 85cae54a0ca..5afdce1e0d4 100644 --- a/arch/x86/lib/fsp2/fsp_init.c +++ b/arch/x86/lib/fsp2/fsp_init.c @@ -84,7 +84,8 @@ static int get_cbfs_fsp(enum fsp_type_t type, ulong map_base, struct cbfs_priv *cbfs; int ret; - ret = cbfs_init_mem(map_base + cbfs_base, &cbfs); + ret = cbfs_init_mem(map_base + cbfs_base, CBFS_SIZE_UNKNOWN, true, + &cbfs); if (ret) return ret; if (!ret) { diff --git a/fs/cbfs/cbfs.c b/fs/cbfs/cbfs.c index c9323a562c6..13a74e6ed43 100644 --- a/fs/cbfs/cbfs.c +++ b/fs/cbfs/cbfs.c @@ -276,18 +276,26 @@ int file_cbfs_init(ulong end_of_rom) return cbfs_init(&cbfs_s, end_of_rom); } -int cbfs_init_mem(ulong base, struct cbfs_priv **privp) +int cbfs_init_mem(ulong base, ulong size, bool require_hdr, + struct cbfs_priv **privp) { struct cbfs_priv priv_s, *priv = &priv_s; int ret; /* - * Use a local variable to start with until we know that the CBFS is - * valid. + * Use a local variable to start with until we know that the * CBFS is + * valid. Note that size is detected from the header, if present, + * meaning the parameter is ignored. */ ret = cbfs_load_header_ptr(priv, base); - if (ret) - return ret; + if (ret) { + if (require_hdr || size == CBFS_SIZE_UNKNOWN) + return ret; + memset(priv, '\0', sizeof(struct cbfs_priv)); + priv->header.rom_size = size; + priv->header.align = CBFS_ALIGN_SIZE; + priv->start = (void *)base; + } ret = file_cbfs_fill_cache(priv, priv->header.rom_size, priv->header.align); diff --git a/include/cbfs.h b/include/cbfs.h index d98afea6480..05770e2c7ec 100644 --- a/include/cbfs.h +++ b/include/cbfs.h @@ -42,6 +42,8 @@ enum cbfs_filetype { enum { CBFS_HEADER_MAGIC = 0x4f524243, + CBFS_SIZE_UNKNOWN = 0xffffffff, + CBFS_ALIGN_SIZE = 0x40, }; /** @@ -186,11 +188,13 @@ const struct cbfs_cachenode *cbfs_find_file(struct cbfs_priv *cbfs, * cbfs_init_mem() - Set up a new CBFS * * @base: Base address of CBFS + * @size: Size of CBFS if known, else CBFS_SIZE_UNKNOWN + * @require_header: true to read a header at the start, false to not require one * @cbfsp: Returns a pointer to CBFS on success * @return 0 if OK, -ve on error */ -int cbfs_init_mem(ulong base, struct cbfs_priv **privp); - +int cbfs_init_mem(ulong base, ulong size, bool require_hdr, + struct cbfs_priv **privp); /***************************************************************************/ /* All of the functions below can be used without first initializing CBFS. */ -- cgit v1.3.1 From c4f5b5dcc31b5aee37dabbadc998fcf695885157 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:00:13 +1300 Subject: cbfs: Allow file traversal with any CBFS The file traversal functions currently use a single global CBFS. In some cases we need to access multiple CBFSs to obtain different files. Add new functions to support this. Signed-off-by: Simon Glass --- fs/cbfs/cbfs.c | 11 +++++++++++ include/cbfs.h | 19 +++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/cbfs/cbfs.c b/fs/cbfs/cbfs.c index 13a74e6ed43..aed4026d653 100644 --- a/fs/cbfs/cbfs.c +++ b/fs/cbfs/cbfs.c @@ -325,6 +325,17 @@ const struct cbfs_header *file_cbfs_get_header(void) } } +const struct cbfs_cachenode *cbfs_get_first(const struct cbfs_priv *priv) +{ + return priv->file_cache; +} + +void cbfs_get_next(const struct cbfs_cachenode **filep) +{ + if (*filep) + *filep = (*filep)->next; +} + const struct cbfs_cachenode *file_cbfs_get_first(void) { struct cbfs_priv *priv = &cbfs_s; diff --git a/include/cbfs.h b/include/cbfs.h index 05770e2c7ec..055edbaac2e 100644 --- a/include/cbfs.h +++ b/include/cbfs.h @@ -9,6 +9,8 @@ #include #include +struct cbfs_priv; + enum cbfs_result { CBFS_SUCCESS = 0, CBFS_NOT_INITIALIZED, @@ -149,6 +151,21 @@ int file_cbfs_init(ulong end_of_rom); */ const struct cbfs_header *file_cbfs_get_header(void); +/** + * cbfs_get_first() - Get the first file in a CBFS + * + * @return pointer to first file, or NULL if it is empty + */ +const struct cbfs_cachenode *cbfs_get_first(const struct cbfs_priv *priv); + +/** + * cbfs_get_next() - Get the next file in a CBFS + * + * @filep: Pointer to current file; updated to point to the next file, if any, + * else NULL + */ +void cbfs_get_next(const struct cbfs_cachenode **filep); + /** * file_cbfs_get_first() - Get a handle for the first file in CBFS. * @@ -172,8 +189,6 @@ void file_cbfs_get_next(const struct cbfs_cachenode **file); */ const struct cbfs_cachenode *file_cbfs_find(const char *name); -struct cbfs_priv; - /** * cbfs_find_file() - Find a file in a given CBFS * -- cgit v1.3.1 From a202f17d7bc2a51af53352c6e21d6a70d167effe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:00:16 +1300 Subject: cbfs: Support reading compression information CBFS now supports compressed filed. Add support for reading this information so that the correct decompression can be applied. The decompression itself is not implemented in CBFS. Signed-off-by: Simon Glass --- fs/cbfs/cbfs.c | 22 ++++++++++++++++++++++ include/cbfs.h | 11 +++++++++++ 2 files changed, 33 insertions(+) (limited to 'include') diff --git a/fs/cbfs/cbfs.c b/fs/cbfs/cbfs.c index 9e534d15f28..443a148e3f1 100644 --- a/fs/cbfs/cbfs.c +++ b/fs/cbfs/cbfs.c @@ -91,6 +91,7 @@ static int fill_node(struct cbfs_cachenode *node, void *start, struct cbfs_fileheader *header) { uint name_len; + uint offset; /* Check the header is large enough */ if (header->offset < sizeof(struct cbfs_fileheader)) @@ -104,6 +105,27 @@ static int fill_node(struct cbfs_cachenode *node, void *start, node->name = start + sizeof(struct cbfs_fileheader); node->name_length = name_len; node->attr_offset = header->attributes_offset; + node->comp_algo = CBFS_COMPRESS_NONE; + node->decomp_size = 0; + + for (offset = node->attr_offset; offset < header->offset;) { + const struct cbfs_file_attribute *attr; + uint tag, len; + + attr = start + offset; + tag = be32_to_cpu(attr->tag); + len = be32_to_cpu(attr->len); + if (tag == CBFS_FILE_ATTR_TAG_COMPRESSION) { + struct cbfs_file_attr_compression *comp; + + comp = start + offset; + node->comp_algo = be32_to_cpu(comp->compression); + node->decomp_size = + be32_to_cpu(comp->decompressed_size); + } + + offset += len; + } return 0; } diff --git a/include/cbfs.h b/include/cbfs.h index 055edbaac2e..ae94f1dcdf5 100644 --- a/include/cbfs.h +++ b/include/cbfs.h @@ -75,6 +75,15 @@ struct cbfs_fileheader { char filename[]; } __packed; +/** + * These are standard values for the known compression alogrithms that coreboot + * knows about for stages and payloads. Of course, other CBFS users can use + * whatever values they want, as long as they understand them. + */ +#define CBFS_COMPRESS_NONE 0 +#define CBFS_COMPRESS_LZMA 1 +#define CBFS_COMPRESS_LZ4 2 + /* * Depending on how the header was initialized, it may be backed with 0x00 or * 0xff, so support both @@ -119,6 +128,8 @@ struct cbfs_cachenode { u32 data_length; u32 name_length; u32 attr_offset; + u32 comp_algo; + u32 decomp_size; }; /** -- cgit v1.3.1 From b8bcccedac91b8551bf00af724d6a5d45f47bd0f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:00:29 +1300 Subject: dm: core: Add CBFS support to flashmap Allow referencing a CBFS file in the flashmap, so that it is possible to boot from coreboot, where files are not available from binman. Signed-off-by: Simon Glass --- include/dm/of_extra.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include') diff --git a/include/dm/of_extra.h b/include/dm/of_extra.h index ca15df21b06..fc4f9743196 100644 --- a/include/dm/of_extra.h +++ b/include/dm/of_extra.h @@ -11,7 +11,11 @@ enum fmap_compress_t { FMAP_COMPRESS_NONE, + FMAP_COMPRESS_LZMA, FMAP_COMPRESS_LZ4, + + FMAP_COMPRESS_COUNT, + FMAP_COMPRESS_UNKNOWN, }; enum fmap_hash_t { @@ -30,6 +34,10 @@ struct fmap_entry { enum fmap_hash_t hash_algo; /* Hash algorithm */ const uint8_t *hash; /* Hash value */ int hash_size; /* Hash size */ + /* Node pointer if CBFS, else NULL */ + const struct cbfs_cachenode *cbfs_node; + /* Hash node pointer if CBFS, else NULL */ + const struct cbfs_cachenode *cbfs_hash_node; }; /** -- cgit v1.3.1 From 1758551ec9526d56303a2b5cf1f58147e66945ed Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:11:11 +1300 Subject: sandbox: Provide a way to bind fixed/removeable devices At present when a file is bound to a host device it is always marked as removeable. Arguably the device is removeable, since it can be unbound at will. However while it is bound, it is not considered removable by the user. Also it is useful to be able to model both fixed and removeable devices for code that distinguishes them. Add a -r flag to the 'host bind' command and plumb it through to provide this feature. Signed-off-by: Simon Glass --- cmd/host.c | 19 +++++++++++++++---- doc/arch/sandbox.rst | 2 ++ drivers/block/sandbox.c | 8 ++++---- include/sandboxblockdev.h | 9 ++++++++- 4 files changed, 29 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/cmd/host.c b/cmd/host.c index 847bb1d3b5f..6aa3d9167a4 100644 --- a/cmd/host.c +++ b/cmd/host.c @@ -41,6 +41,7 @@ static int do_host_save(struct cmd_tbl *cmdtp, int flag, int argc, static int do_host_bind(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { + bool removable = false; const char *dev_str; char *file; char *ep; @@ -49,7 +50,16 @@ static int do_host_bind(struct cmd_tbl *cmdtp, int flag, int argc, /* Skip 'bind' */ argc--; argv++; - if (argc < 1 || argv > 2) + if (argc < 2) + return CMD_RET_USAGE; + + if (!strcmp(argv[0], "-r")) { + removable = true; + argc--; + argv++; + } + + if (argc > 2) return CMD_RET_USAGE; dev_str = argv[0]; dev = simple_strtoul(dev_str, &ep, 16); @@ -59,7 +69,7 @@ static int do_host_bind(struct cmd_tbl *cmdtp, int flag, int argc, } file = argc > 1 ? argv[1] : NULL; - return !!host_dev_bind(dev, file); + return !!host_dev_bind(dev, file, removable); } static int do_host_info(struct cmd_tbl *cmdtp, int flag, int argc, @@ -154,7 +164,7 @@ static struct cmd_tbl cmd_host_sub[] = { U_BOOT_CMD_MKENT(ls, 3, 0, do_host_ls, "", ""), U_BOOT_CMD_MKENT(save, 6, 0, do_host_save, "", ""), U_BOOT_CMD_MKENT(size, 3, 0, do_host_size, "", ""), - U_BOOT_CMD_MKENT(bind, 3, 0, do_host_bind, "", ""), + U_BOOT_CMD_MKENT(bind, 4, 0, do_host_bind, "", ""), U_BOOT_CMD_MKENT(info, 3, 0, do_host_info, "", ""), U_BOOT_CMD_MKENT(dev, 0, 1, do_host_dev, "", ""), }; @@ -186,7 +196,8 @@ U_BOOT_CMD( "host save hostfs - [] - " "save a file to host\n" "host size hostfs - - determine size of file on host\n" - "host bind [] - bind \"host\" device to file\n" + "host bind [-r] [] - bind \"host\" device to file\n" + " -r = mark as removable\n" "host info [] - show device binding & info\n" "host dev [] - Set or retrieve the current host device\n" "host commands use the \"hostfs\" device. The \"host\" device is used\n" diff --git a/doc/arch/sandbox.rst b/doc/arch/sandbox.rst index 8b18a221172..e052b6bdb09 100644 --- a/doc/arch/sandbox.rst +++ b/doc/arch/sandbox.rst @@ -389,6 +389,8 @@ the contents of the root directory on the second partion of the image =>host bind 0 ./disk.raw =>ls host 0:2 +The device can be marked removeable with 'host bind -r'. + A disk image can be created using the following commands:: $> truncate -s 1200M ./disk.raw diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c index e2f229b15db..1c2c3b4f886 100644 --- a/drivers/block/sandbox.c +++ b/drivers/block/sandbox.c @@ -89,7 +89,7 @@ static unsigned long host_block_write(struct blk_desc *block_dev, } #ifdef CONFIG_BLK -int host_dev_bind(int devnum, char *filename) +int host_dev_bind(int devnum, char *filename, bool removable) { struct host_block_dev *host_dev; struct udevice *dev; @@ -146,7 +146,7 @@ int host_dev_bind(int devnum, char *filename) } desc = blk_get_devnum_by_type(IF_TYPE_HOST, devnum); - desc->removable = 1; + desc->removable = removable; snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot"); snprintf(desc->product, BLK_PRD_SIZE, "hostfile"); snprintf(desc->revision, BLK_REV_SIZE, "1.0"); @@ -160,7 +160,7 @@ err: return ret; } #else -int host_dev_bind(int dev, char *filename) +int host_dev_bind(int dev, char *filename, bool removable) { struct host_block_dev *host_dev = find_host_device(dev); @@ -195,7 +195,7 @@ int host_dev_bind(int dev, char *filename) blk_dev->block_write = host_block_write; blk_dev->devnum = dev; blk_dev->part_type = PART_TYPE_UNKNOWN; - blk_dev->removable = 1; + blk_dev->removable = removable; snprintf(blk_dev->vendor, BLK_VEN_SIZE, "U-Boot"); snprintf(blk_dev->product, BLK_PRD_SIZE, "hostfile"); snprintf(blk_dev->revision, BLK_REV_SIZE, "1.0"); diff --git a/include/sandboxblockdev.h b/include/sandboxblockdev.h index c1f0afb337d..4006e942a02 100644 --- a/include/sandboxblockdev.h +++ b/include/sandboxblockdev.h @@ -14,6 +14,13 @@ struct host_block_dev { int fd; }; -int host_dev_bind(int dev, char *filename); +/** + * host_dev_bind() - Bind or unbind a device + * + * @dev: Device number (0=first slot) + * @filename: Host filename to use, or NULL to unbind + * @removable: true if the block device should mark itself as removable + */ +int host_dev_bind(int dev, char *filename, bool removable); #endif -- cgit v1.3.1 From e2734d647e9c86f46083b29224fc7b41a46e1858 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:11:12 +1300 Subject: sandbox: image: Allow sandbox to load any image Sandbox is special in that it is used for testing and it does not match any particular target architecture. Allow it to load an image from any architecture, so that 'bootm' can be used as needed. Signed-off-by: Simon Glass --- common/image-fit.c | 4 ++++ include/image.h | 5 +++++ 2 files changed, 9 insertions(+) (limited to 'include') diff --git a/common/image-fit.c b/common/image-fit.c index 28b3d2b1911..2d0ece61815 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -1512,6 +1512,10 @@ int fit_image_check_arch(const void *fit, int noffset, uint8_t arch) uint8_t image_arch; int aarch32_support = 0; + /* Let's assume that sandbox can load any architecture */ + if (IS_ENABLED(CONFIG_SANDBOX)) + return true; + if (IS_ENABLED(CONFIG_ARM64_SUPPORT_AARCH32)) aarch32_support = 1; diff --git a/include/image.h b/include/image.h index 138c83dd28d..bcd126d262d 100644 --- a/include/image.h +++ b/include/image.h @@ -886,6 +886,11 @@ static inline int image_check_type(const image_header_t *hdr, uint8_t type) } static inline int image_check_arch(const image_header_t *hdr, uint8_t arch) { +#ifndef USE_HOSTCC + /* Let's assume that sandbox can load any architecture */ + if (IS_ENABLED(CONFIG_SANDBOX)) + return true; +#endif return (image_get_arch(hdr) == arch) || (image_get_arch(hdr) == IH_ARCH_ARM && arch == IH_ARCH_ARM64); } -- cgit v1.3.1 From b3b60f59124a1f4fdcee5b7eff3f057e33cfa4c7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:11:17 +1300 Subject: sf: Support querying write-protect This feature was dropped from U-Boot some time ago: f12f96cfaf5 (sf: Drop spl_flash_get_sw_write_prot") However, we do need a way to see if a flash device is write-protected, since if it is, it may not be possible to write to do (i.e. failing to write is expected). I am not sure of the correct layer to implement this, so this patch is a stab at it. If spi-flash makes sense then I will add to the 'sf' also. Re the points mentioned in the removal commit: 1) This kind of requirement can be achieved using existing flash operations and flash locking API calls instead of making a separate flash API. Which uclass is this? 2) Technically there is no real hardware user for this API to use in the source tree. I do want coral (at least) to support this. 3) Having a flash operations API for simple register read bits also make difficult to extend the flash operations. This new patch only mentions write-protect being on or off, rather than the actual mechanism. 4) Instead of touching generic code, it is possible to have this functionality inside spinor operations in the form of flash hooks or fixups for associated flash chips. That sounds to me like what drivers are for. But we still need some sort of API for it to be accessible. Signed-off-by: Simon Glass --- drivers/mtd/spi/sf-uclass.c | 9 +++++++++ drivers/mtd/spi/sf_internal.h | 4 ++++ drivers/mtd/spi/sf_probe.c | 8 ++++++++ drivers/mtd/spi/spi-nor-core.c | 11 +++++++++++ drivers/mtd/spi/spi-nor-tiny.c | 6 ++++++ include/spi_flash.h | 27 +++++++++++++++++++++++++++ test/dm/sf.c | 10 +++++++++- 7 files changed, 74 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c index fd1bec80d64..cfce00ef548 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -31,6 +31,15 @@ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len) return log_ret(sf_get_ops(dev)->erase(dev, offset, len)); } +int spl_flash_get_sw_write_prot(struct udevice *dev) +{ + struct dm_spi_flash_ops *ops = sf_get_ops(dev); + + if (!ops->get_sw_write_prot) + return -ENOSYS; + return log_ret(ops->get_sw_write_prot(dev)); +} + /* * TODO(sjg@chromium.org): This is an old-style function. We should remove * it when all SPI flash drivers use dm diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 9ceff0e7c12..786301ba4a9 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -75,6 +75,10 @@ extern const struct flash_info spi_nor_ids[]; #define JEDEC_MFR(info) ((info)->id[0]) #define JEDEC_ID(info) (((info)->id[1]) << 8 | ((info)->id[2])) +/* Get software write-protect value (BP bits) */ +int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash); + + #if CONFIG_IS_ENABLED(SPI_FLASH_MTD) int spi_flash_mtd_register(struct spi_flash *flash); void spi_flash_mtd_unregister(void); diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 6c874348676..3befbe91cac 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -130,6 +130,13 @@ static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) return mtd->_erase(mtd, &instr); } +static int spi_flash_std_get_sw_write_prot(struct udevice *dev) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + + return spi_flash_cmd_get_sw_write_prot(flash); +} + int spi_flash_std_probe(struct udevice *dev) { struct spi_slave *slave = dev_get_parent_priv(dev); @@ -153,6 +160,7 @@ static const struct dm_spi_flash_ops spi_flash_std_ops = { .read = spi_flash_std_read, .write = spi_flash_std_write, .erase = spi_flash_std_erase, + .get_sw_write_prot = spi_flash_std_get_sw_write_prot, }; static const struct udevice_id spi_flash_std_ids[] = { diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index e0efebc3555..a6625535a70 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -2647,3 +2647,14 @@ int spi_nor_scan(struct spi_nor *nor) return 0; } + +/* U-Boot specific functions, need to extend MTD to support these */ +int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor) +{ + int sr = read_sr(nor); + + if (sr < 0) + return sr; + + return (sr >> 2) & 7; +} diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index 07c8c7b82b1..1d5861d55cd 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -809,3 +809,9 @@ int spi_nor_scan(struct spi_nor *nor) return 0; } + +/* U-Boot specific functions, need to extend MTD to support these */ +int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor) +{ + return -ENOTSUPP; +} diff --git a/include/spi_flash.h b/include/spi_flash.h index 478c543b06b..3d747c925b9 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -35,6 +35,19 @@ struct dm_spi_flash_ops { int (*write)(struct udevice *dev, u32 offset, size_t len, const void *buf); int (*erase)(struct udevice *dev, u32 offset, size_t len); + /** + * get_sw_write_prot() - Check state of software write-protect feature + * + * SPI flash chips can lock a region of the flash defined by a + * 'protected area'. This function checks if this protected area is + * defined. + * + * @dev: SPI flash device + * @return 0 if no region is write-protected, 1 if a region is + * write-protected, -ENOSYS if the driver does not implement this, + * other -ve value on error + */ + int (*get_sw_write_prot)(struct udevice *dev); }; /* Access the serial operations for a device */ @@ -76,6 +89,20 @@ int spi_flash_write_dm(struct udevice *dev, u32 offset, size_t len, */ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len); +/** + * spl_flash_get_sw_write_prot() - Check state of software write-protect feature + * + * SPI flash chips can lock a region of the flash defined by a + * 'protected area'. This function checks if this protected area is + * defined. + * + * @dev: SPI flash device + * @return 0 if no region is write-protected, 1 if a region is + * write-protected, -ENOSYS if the driver does not implement this, + * other -ve value on error + */ +int spl_flash_get_sw_write_prot(struct udevice *dev); + /** * spi_flash_std_probe() - Probe a SPI flash device * diff --git a/test/dm/sf.c b/test/dm/sf.c index cc1fc4d69af..17d43fef3bc 100644 --- a/test/dm/sf.c +++ b/test/dm/sf.c @@ -21,7 +21,7 @@ /* Simple test of sandbox SPI flash */ static int dm_test_spi_flash(struct unit_test_state *uts) { - struct udevice *dev; + struct udevice *dev, *emul; int full_size = 0x200000; int size = 0x10000; u8 *src, *dst; @@ -51,6 +51,14 @@ static int dm_test_spi_flash(struct unit_test_state *uts) ut_assertok(spi_flash_read_dm(dev, 0, size, dst)); ut_asserteq_mem(src, dst, size); + /* Try the write-protect stuff */ + ut_assertok(uclass_first_device_err(UCLASS_SPI_EMUL, &emul)); + ut_asserteq(0, spl_flash_get_sw_write_prot(dev)); + sandbox_sf_set_block_protect(emul, 1); + ut_asserteq(1, spl_flash_get_sw_write_prot(dev)); + sandbox_sf_set_block_protect(emul, 0); + ut_asserteq(0, spl_flash_get_sw_write_prot(dev)); + /* Check mapping */ ut_assertok(dm_spi_get_mmap(dev, &map_base, &map_size, &offset)); ut_asserteq(0x1000, map_base); -- cgit v1.3.1 From c197f6e27923b4cff9d782cd9be7a058d5d65aa2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:11:19 +1300 Subject: malloc: Export malloc_simple_info() Export this function always so it can be used behind IS_ENABLED() instead of requiring an #ifdef. Signed-off-by: Simon Glass --- include/malloc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/malloc.h b/include/malloc.h index e15e528a2e3..024b18be00e 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -880,6 +880,8 @@ extern Void_t* sbrk(); #else +void malloc_simple_info(void); + #if CONFIG_IS_ENABLED(SYS_MALLOC_SIMPLE) #define malloc malloc_simple #define realloc realloc_simple @@ -887,7 +889,6 @@ extern Void_t* sbrk(); static inline void free(void *ptr) {} void *calloc(size_t nmemb, size_t size); void *realloc_simple(void *ptr, size_t size); -void malloc_simple_info(void); #else # ifdef USE_DL_PREFIX -- cgit v1.3.1 From 45cd2e55755b77b644401bb3887c11f7653327c0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 15 Mar 2021 18:11:21 +1300 Subject: command: Fix operation of !CONFIG_CMDLINE The U_BOOT_CMDREP_COMPLETE() macro produces a build error if CONFIG_CMDLINE is not enabled. Fix this by updating the macro to provide the 'repeatable' arugment in this case. Signed-off-by: Simon Glass --- include/command.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/command.h b/include/command.h index 747f8f80958..137cfbc3231 100644 --- a/include/command.h +++ b/include/command.h @@ -389,6 +389,14 @@ int run_command_list(const char *cmd, int len, int flag); return 0; \ } +#define _CMD_REMOVE_REP(_name, _cmd) \ + int __remove_ ## _name(void) \ + { \ + if (0) \ + _cmd(NULL, 0, 0, NULL, NULL); \ + return 0; \ + } + #define U_BOOT_CMDREP_MKENT_COMPLETE(_name, _maxargs, _cmd_rep, \ _usage, _help, _comp) \ { #_name, _maxargs, 0 ? _cmd_rep : NULL, NULL, _usage, \ @@ -405,7 +413,7 @@ int run_command_list(const char *cmd, int len, int flag); #define U_BOOT_CMDREP_COMPLETE(_name, _maxargs, _cmd_rep, _usage, \ _help, _comp) \ - _CMD_REMOVE(sub_ ## _name, _cmd_rep) + _CMD_REMOVE_REP(sub_ ## _name, _cmd_rep) #endif /* CONFIG_CMDLINE */ -- cgit v1.3.1 From 96dedb0da2e8b27165c755fab8d06b15a8b8097a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Mar 2021 16:50:06 +1300 Subject: sysinfo: Allow showing model info from sysinfo Some boards may want to show the SKU ID or other information obtained at runtime. Allow this to come from sysinfo. The board can then provide a sysinfo driver to provide it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- common/board_info.c | 37 +++++++++++++++++++++++++++++-------- include/sysinfo.h | 4 ++++ 2 files changed, 33 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/common/board_info.c b/common/board_info.c index b54aa30a944..1cfe34f7067 100644 --- a/common/board_info.c +++ b/common/board_info.c @@ -1,31 +1,52 @@ // SPDX-License-Identifier: GPL-2.0+ #include +#include #include +#include #include #include #include +DECLARE_GLOBAL_DATA_PTR; + int __weak checkboard(void) { return 0; } /* - * If the root node of the DTB has a "model" property, show it. + * Check sysinfo for board information. Failing that if the root node of the DTB + * has a "model" property, show it. + * * Then call checkboard(). */ int __weak show_board_info(void) { -#ifdef CONFIG_OF_CONTROL - DECLARE_GLOBAL_DATA_PTR; - const char *model; + if (IS_ENABLED(CONFIG_OF_CONTROL)) { + struct udevice *dev; + const char *model; + char str[80]; + int ret = -ENOSYS; + + if (IS_ENABLED(CONFIG_SYSINFO)) { + /* This might provide more detail */ + ret = uclass_first_device_err(UCLASS_SYSINFO, &dev); + if (!ret) + ret = sysinfo_get_str(dev, + SYSINFO_ID_BOARD_MODEL, + sizeof(str), str); + } - model = fdt_getprop(gd->fdt_blob, 0, "model", NULL); + /* Fail back to the main 'model' if available */ + if (ret) + model = fdt_getprop(gd->fdt_blob, 0, "model", NULL); + else + model = str; - if (model) - printf("Model: %s\n", model); -#endif + if (model) + printf("Model: %s\n", model); + } return checkboard(); } diff --git a/include/sysinfo.h b/include/sysinfo.h index 270ac1b377f..68fad25a065 100644 --- a/include/sysinfo.h +++ b/include/sysinfo.h @@ -37,9 +37,13 @@ struct udevice; enum sysinfo_id { SYSINFO_ID_NONE, + /* For SMBIOS tables */ SYSINFO_ID_SMBIOS_SYSTEM_VERSION, SYSINFO_ID_SMBIOS_BASEBOARD_VERSION, + /* For show_board_info() */ + SYSINFO_ID_BOARD_MODEL, + /* First value available for downstream/board used */ SYSINFO_ID_USER = 0x1000, }; -- cgit v1.3.1 From ce90654d1c150549312c2c58e2b30de099d2265e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 26 Nov 2020 14:25:02 +0100 Subject: xilinx: Sync DTs with Linux kernel There are several changes which happen in mainline kernel which should get also to U-Boot. Here is the list of patches from the kernel: - ARM: zynq: Fix leds subnode name for zc702/zybo-z7 - arm64: dts: zynqmp: Fix leds subnode name for zcu100/ultra96 v1 - arm64: dts: zynqmp: Fix u48 si5382 chip on zcu111 - arm64: dts: zynqmp: Wire up the DisplayPort subsystem - arm64: dts: zynqmp: Add DisplayPort subsystem - arm64: dts: zynqmp: Add DPDMA node - arm64: dts: zynqmp: Enable phy driver for Sata on zcu102/zcu104/zcu106 - arm64: dts: zynqmp: Enable si5341 driver for zcu102/106/111 - arm64: dts: zynqmp: Add DT description for si5328 for zcu102/zcu106 - arm64: dts: zynqmp-zcu100-revC: correct interrupt flags - arm64: dts: xilinx: align GPIO hog names with dtschema - arm64: zynqmp: Add Xilinx AES node - dt: bindings: dma: xilinx: dpdma: DT bindings for Xilinx DPDMA but also some other changes have been done. - Using only one compatible string for adxl345 on zturn - Remove Xilinx internal DP bindings - Remove USB3.0 serdes configurations - Remove SATA serdes configuration for zc1232 - Resort nvmem_firmware - Update nand compatible string - Aling power-domains property for sd0/1 Signed-off-by: Michal Simek --- arch/arm/dts/zynq-zc702.dts | 2 +- arch/arm/dts/zynq-zturn-common.dtsi | 2 +- arch/arm/dts/zynq-zybo-z7.dts | 2 +- arch/arm/dts/zynqmp-clk-ccf.dtsi | 16 ++- arch/arm/dts/zynqmp-g-a2197-00-revA.dts | 3 - arch/arm/dts/zynqmp-m-a2197-01-revA.dts | 3 - arch/arm/dts/zynqmp-zc1232-revA.dts | 2 - arch/arm/dts/zynqmp-zc1751-xm015-dc1.dts | 19 +--- arch/arm/dts/zynqmp-zc1751-xm018-dc4.dts | 2 +- arch/arm/dts/zynqmp-zcu100-revC.dts | 48 ++++++--- arch/arm/dts/zynqmp-zcu102-revA.dts | 106 +++++++++++++------ arch/arm/dts/zynqmp-zcu104-revA.dts | 44 ++++++-- arch/arm/dts/zynqmp-zcu104-revC.dts | 44 ++++++-- arch/arm/dts/zynqmp-zcu106-revA.dts | 96 +++++++++++++++-- arch/arm/dts/zynqmp-zcu111-revA.dts | 78 +++++++++++--- arch/arm/dts/zynqmp-zcu208-revA.dts | 58 +++++++++-- arch/arm/dts/zynqmp-zcu216-revA.dts | 58 +++++++++-- arch/arm/dts/zynqmp.dtsi | 154 +++++++--------------------- include/dt-bindings/dma/xlnx-zynqmp-dpdma.h | 16 +++ 19 files changed, 498 insertions(+), 255 deletions(-) create mode 100644 include/dt-bindings/dma/xlnx-zynqmp-dpdma.h (limited to 'include') diff --git a/arch/arm/dts/zynq-zc702.dts b/arch/arm/dts/zynq-zc702.dts index b043d341d68..e45eba3d90b 100644 --- a/arch/arm/dts/zynq-zc702.dts +++ b/arch/arm/dts/zynq-zc702.dts @@ -51,7 +51,7 @@ leds { compatible = "gpio-leds"; - ds23 { + led-ds23 { label = "ds23"; gpios = <&gpio0 10 0>; linux,default-trigger = "heartbeat"; diff --git a/arch/arm/dts/zynq-zturn-common.dtsi b/arch/arm/dts/zynq-zturn-common.dtsi index 1d7af02893d..486b6fa2e1b 100644 --- a/arch/arm/dts/zynq-zturn-common.dtsi +++ b/arch/arm/dts/zynq-zturn-common.dtsi @@ -112,7 +112,7 @@ }; accelerometer@53 { - compatible = "adi,adxl345", "adxl345", "adi,adxl34x", "adxl34x"; + compatible = "adi,adxl345"; reg = <0x53>; interrupt-parent = <&intc>; interrupts = <0x0 0x1e 0x4>; diff --git a/arch/arm/dts/zynq-zybo-z7.dts b/arch/arm/dts/zynq-zybo-z7.dts index 3f8a3bfa0ff..116958ec97a 100644 --- a/arch/arm/dts/zynq-zybo-z7.dts +++ b/arch/arm/dts/zynq-zybo-z7.dts @@ -31,7 +31,7 @@ gpio-leds { compatible = "gpio-leds"; - ld4 { + led-ld4 { label = "zynq-zybo-z7:green:ld4"; gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm/dts/zynqmp-clk-ccf.dtsi b/arch/arm/dts/zynqmp-clk-ccf.dtsi index b02ef22abd2..987792e5c51 100644 --- a/arch/arm/dts/zynqmp-clk-ccf.dtsi +++ b/arch/arm/dts/zynqmp-clk-ccf.dtsi @@ -284,18 +284,16 @@ clocks = <&zynqmp_clk AMS_REF>; }; -&zynqmp_dpsub { - clocks = <&dp_aclk>, <&zynqmp_clk DP_AUDIO_REF>, <&zynqmp_clk DP_VIDEO_REF>; +&zynqmp_pcap { + clocks = <&zynqmp_clk PCAP>; }; -&xlnx_dpdma { +&zynqmp_dpdma { clocks = <&zynqmp_clk DPDMA_REF>; }; -&zynqmp_dp_snd_codec0 { - clocks = <&zynqmp_clk DP_AUDIO_REF>; -}; - -&zynqmp_pcap { - clocks = <&zynqmp_clk PCAP>; +&zynqmp_dpsub { + clocks = <&zynqmp_clk TOPSW_LSBUS>, + <&zynqmp_clk DP_AUDIO_REF>, + <&zynqmp_clk DP_VIDEO_REF>; }; diff --git a/arch/arm/dts/zynqmp-g-a2197-00-revA.dts b/arch/arm/dts/zynqmp-g-a2197-00-revA.dts index 9468dc574fd..f94b797d1a2 100644 --- a/arch/arm/dts/zynqmp-g-a2197-00-revA.dts +++ b/arch/arm/dts/zynqmp-g-a2197-00-revA.dts @@ -88,9 +88,6 @@ reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>; /* xlnx,phy-type = ; */ }; -/* phy-names = "..."; - phys = <&lane0 PHY_TYPE_SGMII ... > - Note: lane0 sgmii/lane1 usb3 */ }; &gpio { diff --git a/arch/arm/dts/zynqmp-m-a2197-01-revA.dts b/arch/arm/dts/zynqmp-m-a2197-01-revA.dts index 66ea02e5be7..19e1ebdb1d6 100644 --- a/arch/arm/dts/zynqmp-m-a2197-01-revA.dts +++ b/arch/arm/dts/zynqmp-m-a2197-01-revA.dts @@ -118,9 +118,6 @@ reg = <0>; /* xlnx,phy-type = ; */ }; -/* phy-names = "..."; - phys = <&lane0 PHY_TYPE_SGMII ... > - Note: lane0 sgmii/lane1 usb3 */ }; &gpio { diff --git a/arch/arm/dts/zynqmp-zc1232-revA.dts b/arch/arm/dts/zynqmp-zc1232-revA.dts index afb3e96520b..ef7cf0a36b2 100644 --- a/arch/arm/dts/zynqmp-zc1232-revA.dts +++ b/arch/arm/dts/zynqmp-zc1232-revA.dts @@ -78,8 +78,6 @@ ceva,p1-comwake-params = /bits/ 8 <0x06 0x14 0x08 0x0E>; ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>; ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>; - phy-names = "sata-phy"; - phys = <&lane0 PHY_TYPE_SATA 0 0 125000000>, <&lane1 PHY_TYPE_SATA 1 1 125000000>; }; &uart0 { diff --git a/arch/arm/dts/zynqmp-zc1751-xm015-dc1.dts b/arch/arm/dts/zynqmp-zc1751-xm015-dc1.dts index e2428ec974a..b8c5efb6a91 100644 --- a/arch/arm/dts/zynqmp-zc1751-xm015-dc1.dts +++ b/arch/arm/dts/zynqmp-zc1751-xm015-dc1.dts @@ -175,26 +175,11 @@ dr_mode = "host"; }; -&zynqmp_dpsub { - status = "okay"; -}; - -&zynqmp_dp_snd_pcm0 { - status = "okay"; -}; - -&zynqmp_dp_snd_pcm1 { +&zynqmp_dpdma { status = "okay"; }; -&zynqmp_dp_snd_card0 { - status = "okay"; -}; - -&zynqmp_dp_snd_codec0 { +&zynqmp_dpsub { status = "okay"; }; -&xlnx_dpdma { - status = "okay"; -}; diff --git a/arch/arm/dts/zynqmp-zc1751-xm018-dc4.dts b/arch/arm/dts/zynqmp-zc1751-xm018-dc4.dts index 9b38b8b919e..aadda179c32 100644 --- a/arch/arm/dts/zynqmp-zc1751-xm018-dc4.dts +++ b/arch/arm/dts/zynqmp-zc1751-xm018-dc4.dts @@ -119,7 +119,7 @@ status = "okay"; }; -&xlnx_dpdma { +&zynqmp_dpdma { status = "okay"; }; diff --git a/arch/arm/dts/zynqmp-zcu100-revC.dts b/arch/arm/dts/zynqmp-zcu100-revC.dts index d6c914c917f..bbcc69c7967 100644 --- a/arch/arm/dts/zynqmp-zcu100-revC.dts +++ b/arch/arm/dts/zynqmp-zcu100-revC.dts @@ -69,27 +69,27 @@ leds { compatible = "gpio-leds"; - ds2 { + led-ds2 { label = "ds2"; gpios = <&gpio 20 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; - ds3 { + led-ds3 { label = "ds3"; gpios = <&gpio 19 GPIO_ACTIVE_HIGH>; linux,default-trigger = "phy0tx"; /* WLAN tx */ default-state = "off"; }; - ds4 { + led-ds4 { label = "ds4"; gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; linux,default-trigger = "phy0rx"; /* WLAN rx */ default-state = "off"; }; - ds5 { + led-ds5 { label = "ds5"; gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; linux,default-trigger = "bluetooth-power"; @@ -130,6 +130,18 @@ compatible = "iio-hwmon"; io-channels = <&u35 0>, <&u35 1>, <&u35 2>, <&u35 3>; }; + + si5335a_0: clk26 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; + + si5335a_1: clk27 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; &dcc { @@ -212,7 +224,7 @@ compatible = "ti,tps65086"; reg = <0x5e>; interrupt-parent = <&gpio>; - interrupts = <77 GPIO_ACTIVE_LOW>; + interrupts = <77 IRQ_TYPE_LEVEL_LOW>; #gpio-cells = <2>; gpio-controller; }; @@ -250,6 +262,13 @@ }; }; +&psgtr { + status = "okay"; + /* usb3, dps */ + clocks = <&si5335a_0>, <&si5335a_1>; + clock-names = "ref0", "ref1"; +}; + &rtc { status = "okay"; }; @@ -281,10 +300,6 @@ }; }; -&serdes { - status = "okay"; -}; - &spi0 { /* Low Speed connector */ status = "okay"; label = "LS-SPI0"; @@ -318,8 +333,6 @@ &dwc3_0 { status = "okay"; dr_mode = "peripheral"; - phy-names = "usb3-phy"; - phys = <&lane2 PHY_TYPE_USB3 0 0 26000000>; maximum-speed = "super-speed"; }; @@ -331,8 +344,6 @@ &dwc3_1 { status = "okay"; dr_mode = "host"; - phy-names = "usb3-phy"; - phys = <&lane3 PHY_TYPE_USB3 1 0 26000000>; maximum-speed = "super-speed"; }; @@ -347,3 +358,14 @@ &ams_ps { status = "okay"; }; + +&zynqmp_dpdma { + status = "okay"; +}; + +&zynqmp_dpsub { + status = "okay"; + phy-names = "dp-phy0", "dp-phy1"; + phys = <&psgtr 1 PHY_TYPE_DP 0 1>, + <&psgtr 0 PHY_TYPE_DP 1 1>; +}; diff --git a/arch/arm/dts/zynqmp-zcu102-revA.dts b/arch/arm/dts/zynqmp-zcu102-revA.dts index ed036e68f5e..9323b8d64d5 100644 --- a/arch/arm/dts/zynqmp-zcu102-revA.dts +++ b/arch/arm/dts/zynqmp-zcu102-revA.dts @@ -137,6 +137,19 @@ compatible = "iio-hwmon"; io-channels = <&u75 0>, <&u75 1>, <&u75 2>, <&u75 3>; }; + + /* 48MHz reference crystal */ + ref48: ref48M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + }; + + refhdmi: refhdmi { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <114285000>; + }; }; &can1 { @@ -213,25 +226,25 @@ gpio-line-names = "PS_GTR_LAN_SEL0", "PS_GTR_LAN_SEL1", "PS_GTR_LAN_SEL2", "PS_GTR_LAN_SEL3", "PCI_CLK_DIR_SEL", "IIC_MUX_RESET_B", "GEM3_EXP_RESET_B", "", "", "", "", "", "", "", "", ""; - gtr-sel0 { + gtr-sel0-hog { gpio-hog; gpios = <0 0>; output-low; /* PCIE = 0, DP = 1 */ line-name = "sel0"; }; - gtr-sel1 { + gtr-sel1-hog { gpio-hog; gpios = <1 0>; output-high; /* PCIE = 0, DP = 1 */ line-name = "sel1"; }; - gtr-sel2 { + gtr-sel2-hog { gpio-hog; gpios = <2 0>; output-high; /* PCIE = 0, USB0 = 1 */ line-name = "sel2"; }; - gtr-sel3 { + gtr-sel3-hog { gpio-hog; gpios = <3 0>; output-high; /* PCIE = 0, SATA = 1 */ @@ -494,8 +507,54 @@ si5341: clock-generator@36 { /* SI5341 - u69 */ compatible = "silabs,si5341"; reg = <0x36>; + #clock-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&ref48>; + clock-names = "xtal"; + clock-output-names = "si5341"; + + si5341_0: out@0 { + /* refclk0 for PS-GT, used for DP */ + reg = <0>; + always-on; + }; + si5341_2: out@2 { + /* refclk2 for PS-GT, used for USB3 */ + reg = <2>; + always-on; + }; + si5341_3: out@3 { + /* refclk3 for PS-GT, used for SATA */ + reg = <3>; + always-on; + }; + si5341_4: out@4 { + /* refclk4 for PS-GT, used for PCIE slot */ + reg = <4>; + always-on; + }; + si5341_5: out@5 { + /* refclk5 for PS-GT, used for PCIE */ + reg = <5>; + always-on; + }; + si5341_6: out@6 { + /* refclk6 PL CLK125 */ + reg = <6>; + always-on; + }; + si5341_7: out@7 { + /* refclk7 PL CLK74 */ + reg = <7>; + always-on; + }; + si5341_9: out@9 { + /* refclk9 used for PS_REF_CLK 33.3 MHz */ + reg = <9>; + always-on; + }; }; - }; i2c@2 { #address-cells = <1>; @@ -603,6 +662,13 @@ status = "okay"; }; +&psgtr { + status = "okay"; + /* pcie, sata, usb3, dp */ + clocks = <&si5341 0 5>, <&si5341 0 3>, <&si5341 0 2>, <&si5341 0 0>; + clock-names = "ref0", "ref1", "ref2", "ref3"; +}; + &qspi { status = "okay"; is-dual = <1>; @@ -649,7 +715,7 @@ ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>; ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>; phy-names = "sata-phy"; - phys = <&lane3 PHY_TYPE_SATA 1 1 125000000>; + phys = <&psgtr 3 PHY_TYPE_SATA 1 1>; }; /* SD1 with level shifter */ @@ -663,10 +729,6 @@ xlnx,mio-bank = <1>; }; -&serdes { - status = "okay"; -}; - &uart0 { status = "okay"; }; @@ -684,8 +746,6 @@ status = "okay"; dr_mode = "host"; snps,usb3_lpm_capable; - phy-names = "usb3-phy"; - phys = <&lane2 PHY_TYPE_USB3 0 2 26000000>; maximum-speed = "super-speed"; }; @@ -705,26 +765,12 @@ status = "okay"; }; -&zynqmp_dpsub { +&zynqmp_dpdma { status = "okay"; }; -&zynqmp_dp_snd_codec0 { - status = "okay"; -}; - -&zynqmp_dp_snd_pcm0 { - status = "okay"; -}; - -&zynqmp_dp_snd_pcm1 { - status = "okay"; -}; - -&zynqmp_dp_snd_card0 { - status = "okay"; -}; - -&xlnx_dpdma { +&zynqmp_dpsub { status = "okay"; + phy-names = "dp-phy0"; + phys = <&psgtr 1 PHY_TYPE_DP 0 3>; }; diff --git a/arch/arm/dts/zynqmp-zcu104-revA.dts b/arch/arm/dts/zynqmp-zcu104-revA.dts index cb8ffdff977..a95bd4922a6 100644 --- a/arch/arm/dts/zynqmp-zcu104-revA.dts +++ b/arch/arm/dts/zynqmp-zcu104-revA.dts @@ -40,6 +40,24 @@ device_type = "memory"; reg = <0x0 0x0 0x0 0x80000000>; }; + + clock_8t49n287_5: clk125 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + }; + + clock_8t49n287_2: clk26 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; + + clock_8t49n287_3: clk27 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; &can1 { @@ -226,6 +244,13 @@ }; }; +&psgtr { + status = "okay"; + /* nc, sata, usb3, dp */ + clocks = <&clock_8t49n287_5>, <&clock_8t49n287_2>, <&clock_8t49n287_3>; + clock-names = "ref1", "ref2", "ref3"; +}; + &rtc { status = "okay"; }; @@ -242,7 +267,7 @@ ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>; ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>; phy-names = "sata-phy"; - phys = <&lane3 PHY_TYPE_SATA 1 1 125000000>; + phys = <&psgtr 3 PHY_TYPE_SATA 1 1>; }; /* SD1 with level shifter */ @@ -253,10 +278,6 @@ disable-wp; }; -&serdes { - status = "okay"; -}; - &uart0 { status = "okay"; }; @@ -274,8 +295,6 @@ status = "okay"; dr_mode = "host"; snps,usb3_lpm_capable; - phy-names = "usb3-phy"; - phys = <&lane2 PHY_TYPE_USB3 0 2 26000000>; maximum-speed = "super-speed"; }; @@ -294,3 +313,14 @@ &ams_pl { status = "okay"; }; + +&zynqmp_dpdma { + status = "okay"; +}; + +&zynqmp_dpsub { + status = "okay"; + phy-names = "dp-phy0", "dp-phy1"; + phys = <&psgtr 1 PHY_TYPE_DP 0 3>, + <&psgtr 0 PHY_TYPE_DP 1 3>; +}; diff --git a/arch/arm/dts/zynqmp-zcu104-revC.dts b/arch/arm/dts/zynqmp-zcu104-revC.dts index e203280f0ec..8f30a2883e2 100644 --- a/arch/arm/dts/zynqmp-zcu104-revC.dts +++ b/arch/arm/dts/zynqmp-zcu104-revC.dts @@ -46,6 +46,24 @@ compatible = "iio-hwmon"; io-channels = <&u183 0>, <&u183 1>, <&u183 2>, <&u183 3>; }; + + clock_8t49n287_5: clk125 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + }; + + clock_8t49n287_2: clk26 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; + + clock_8t49n287_3: clk27 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; }; &can1 { @@ -243,6 +261,13 @@ status = "okay"; }; +&psgtr { + status = "okay"; + /* nc, sata, usb3, dp */ + clocks = <&clock_8t49n287_5>, <&clock_8t49n287_2>, <&clock_8t49n287_3>; + clock-names = "ref1", "ref2", "ref3"; +}; + &sata { status = "okay"; /* SATA OOB timing settings */ @@ -255,7 +280,7 @@ ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>; ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>; phy-names = "sata-phy"; - phys = <&lane3 PHY_TYPE_SATA 1 1 125000000>; + phys = <&psgtr 3 PHY_TYPE_SATA 1 1>; }; /* SD1 with level shifter */ @@ -266,10 +291,6 @@ disable-wp; }; -&serdes { - status = "okay"; -}; - &uart0 { status = "okay"; }; @@ -287,8 +308,6 @@ status = "okay"; dr_mode = "host"; snps,usb3_lpm_capable; - phy-names = "usb3-phy"; - phys = <&lane2 PHY_TYPE_USB3 0 2 26000000>; maximum-speed = "super-speed"; }; @@ -307,3 +326,14 @@ &ams_pl { status = "okay"; }; + +&zynqmp_dpdma { + status = "okay"; +}; + +&zynqmp_dpsub { + status = "okay"; + phy-names = "dp-phy0", "dp-phy1"; + phys = <&psgtr 1 PHY_TYPE_DP 0 3>, + <&psgtr 0 PHY_TYPE_DP 1 3>; +}; diff --git a/arch/arm/dts/zynqmp-zcu106-revA.dts b/arch/arm/dts/zynqmp-zcu106-revA.dts index 1dff845ceeb..971f76f1cab 100644 --- a/arch/arm/dts/zynqmp-zcu106-revA.dts +++ b/arch/arm/dts/zynqmp-zcu106-revA.dts @@ -137,6 +137,19 @@ compatible = "iio-hwmon"; io-channels = <&u75 0>, <&u75 1>, <&u75 2>, <&u75 3>; }; + + /* 48MHz reference crystal */ + ref48: ref48M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + }; + + refhdmi: refhdmi { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <114285000>; + }; }; &can1 { @@ -147,6 +160,18 @@ status = "okay"; }; +&zynqmp_dpdma { + status = "okay"; +}; + +&zynqmp_dpsub { + status = "okay"; + phy-names = "dp-phy0", "dp-phy1"; + phys = <&psgtr 1 PHY_TYPE_DP 0 3>, + <&psgtr 0 PHY_TYPE_DP 1 3>; +}; + +/* fpd_dma clk 667MHz, lpd_dma 500MHz */ &fpd_dma_chan1 { status = "okay"; }; @@ -490,8 +515,45 @@ #size-cells = <0>; reg = <1>; si5341: clock-generator@36 { /* SI5341 - u69 */ - compatible = "si5341"; + compatible = "silabs,si5341"; reg = <0x36>; + #clock-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&ref48>; + clock-names = "xtal"; + clock-output-names = "si5341"; + + si5341_0: out@0 { + /* refclk0 for PS-GT, used for DP */ + reg = <0>; + always-on; + }; + si5341_2: out@2 { + /* refclk2 for PS-GT, used for USB3 */ + reg = <2>; + always-on; + }; + si5341_3: out@3 { + /* refclk3 for PS-GT, used for SATA */ + reg = <3>; + always-on; + }; + si5341_6: out@6 { + /* refclk6 PL CLK125 */ + reg = <6>; + always-on; + }; + si5341_7: out@7 { + /* refclk7 PL CLK74 */ + reg = <7>; + always-on; + }; + si5341_9: out@9 { + /* refclk9 used for PS_REF_CLK 33.3 MHz */ + reg = <9>; + always-on; + }; }; }; @@ -528,8 +590,23 @@ #size-cells = <0>; reg = <4>; si5328: clock-generator@69 {/* SI5328 - u20 */ - compatible = "silabs,si5328"; reg = <0x69>; + /* + * Chip has interrupt present connected to PL + * interrupt-parent = <&>; + * interrupts = <>; + */ + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + clocks = <&refhdmi>; + clock-names = "xtal"; + clock-output-names = "si5328"; + + si5328_clk: clk0@0 { + reg = <0>; + clock-frequency = <27000000>; + }; }; }; i2c@5 { @@ -601,6 +678,13 @@ }; }; +&psgtr { + status = "okay"; + /* nc, sata, usb3, dp */ + clocks = <&si5341 0 3>, <&si5341 0 2>, <&si5341 0 0>; + clock-names = "ref1", "ref2", "ref3"; +}; + &qspi { status = "okay"; is-dual = <1>; @@ -647,7 +731,7 @@ ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>; ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>; phy-names = "sata-phy"; - phys = <&lane3 PHY_TYPE_SATA 1 1 125000000>; + phys = <&psgtr 3 PHY_TYPE_SATA 1 1>; }; /* SD1 with level shifter */ @@ -660,10 +744,6 @@ xlnx,mio-bank = <1>; }; -&serdes { - status = "okay"; -}; - &uart0 { status = "okay"; }; @@ -681,8 +761,6 @@ status = "okay"; dr_mode = "host"; snps,usb3_lpm_capable; - phy-names = "usb3-phy"; - phys = <&lane2 PHY_TYPE_USB3 0 2 26000000>; }; &watchdog0 { diff --git a/arch/arm/dts/zynqmp-zcu111-revA.dts b/arch/arm/dts/zynqmp-zcu111-revA.dts index 82e6c8d3cdf..9e47008542a 100644 --- a/arch/arm/dts/zynqmp-zcu111-revA.dts +++ b/arch/arm/dts/zynqmp-zcu111-revA.dts @@ -121,6 +121,13 @@ compatible = "iio-hwmon"; io-channels = <&u79 0>, <&u79 1>, <&u79 2>, <&u79 3>; }; + + /* 48MHz reference crystal */ + ref48: ref48M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + }; }; &dcc { @@ -386,10 +393,46 @@ #size-cells = <0>; reg = <1>; si5341: clock-generator@36 { /* SI5341 - u46 */ - compatible = "si5341"; + compatible = "silabs,si5341"; reg = <0x36>; + #clock-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&ref48>; + clock-names = "xtal"; + clock-output-names = "si5341"; + + si5341_0: out@0 { + /* refclk0 for PS-GT, used for DP */ + reg = <0>; + always-on; + }; + si5341_2: out@2 { + /* refclk2 for PS-GT, used for USB3 */ + reg = <2>; + always-on; + }; + si5341_3: out@3 { + /* refclk3 for PS-GT, used for SATA */ + reg = <3>; + always-on; + }; + si5341_5: out@5 { + /* refclk5 PL CLK100 */ + reg = <5>; + always-on; + }; + si5341_6: out@6 { + /* refclk6 PL CLK125 */ + reg = <6>; + always-on; + }; + si5341_9: out@9 { + /* refclk9 used for PS_REF_CLK 33.3 MHz */ + reg = <9>; + always-on; + }; }; - }; i2c@2 { #address-cells = <1>; @@ -423,8 +466,8 @@ #address-cells = <1>; #size-cells = <0>; reg = <4>; - si5328: clock-generator@69 { /* SI5328 - u48 */ - compatible = "silabs,si5328"; + si5382: clock-generator@69 { /* SI5382 - u48 */ + compatible = "silabs,si5382"; reg = <0x69>; }; }; @@ -511,6 +554,13 @@ }; }; +&psgtr { + status = "okay"; + /* nc, sata, usb3, dp */ + clocks = <&si5341 0 3>, <&si5341 0 2>, <&si5341 0 0>; + clock-names = "ref1", "ref2", "ref3"; +}; + &qspi { status = "okay"; is-dual = <1>; @@ -557,7 +607,7 @@ ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>; ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>; phy-names = "sata-phy"; - phys = <&lane3 PHY_TYPE_SATA 1 3 125000000>; + phys = <&psgtr 3 PHY_TYPE_SATA 1 1>; }; /* SD1 with level shifter */ @@ -571,10 +621,6 @@ xlnx,mio-bank = <1>; }; -&serdes { - status = "okay"; -}; - &uart0 { status = "okay"; }; @@ -582,12 +628,16 @@ /* ULPI SMSC USB3320 */ &usb0 { status = "okay"; + dr_mode = "host"; }; -&dwc3_0 { +&zynqmp_dpdma { status = "okay"; - dr_mode = "host"; - snps,usb3_lpm_capable; - phy-names = "usb3-phy"; - phys = <&lane2 PHY_TYPE_USB3 0 2 26000000>; +}; + +&zynqmp_dpsub { + status = "okay"; + phy-names = "dp-phy0", "dp-phy1"; + phys = <&psgtr 1 PHY_TYPE_DP 0 1>, + <&psgtr 0 PHY_TYPE_DP 1 1>; }; diff --git a/arch/arm/dts/zynqmp-zcu208-revA.dts b/arch/arm/dts/zynqmp-zcu208-revA.dts index 268e368b765..0e114cdacb1 100644 --- a/arch/arm/dts/zynqmp-zcu208-revA.dts +++ b/arch/arm/dts/zynqmp-zcu208-revA.dts @@ -120,6 +120,13 @@ compatible = "iio-hwmon"; io-channels = <&dac_avcc 0>, <&dac_avcc 1>, <&dac_avcc 2>, <&dac_avcc 3>; }; + + /* 48MHz reference crystal */ + ref48: ref48M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + }; }; &dcc { @@ -404,10 +411,41 @@ #size-cells = <0>; reg = <1>; si5341: clock-generator@36 { /* SI5341 - u43 */ - compatible = "si5341"; + compatible = "silabs,si5341"; reg = <0x36>; + #clock-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&ref48>; + clock-names = "xtal"; + clock-output-names = "si5341"; + + si5341_2: out@2 { + /* refclk2 for PS-GT, used for USB3 */ + reg = <2>; + always-on; /* assigned-clocks does not enable, so do it here */ + }; + si5341_3: out@3 { + /* refclk3 for PS-GT, used for SATA */ + reg = <3>; + always-on; /* assigned-clocks does not enable, so do it here */ + }; + si5341_5: out@5 { + /* refclk5 PL CLK100 */ + reg = <5>; + always-on; /* assigned-clocks does not enable, so do it here */ + }; + si5341_6: out@6 { + /* refclk6 PL CLK125 */ + reg = <6>; + always-on; /* assigned-clocks does not enable, so do it here */ + }; + si5341_9: out@9 { + /* refclk9 used for PS_REF_CLK 33.3 MHz */ + reg = <9>; + always-on; /* assigned-clocks does not enable, so do it here */ + }; }; - }; i2c_si570_user_c0: i2c@2 { #address-cells = <1>; @@ -541,6 +579,13 @@ }; }; +&psgtr { + status = "okay"; + /* pcie, sata, usb3, dp */ + clocks = <&si5341 0 5>, <&si5341 0 3>, <&si5341 0 2>, <&si5341 0 0>; + clock-names = "ref0", "ref1", "ref2", "ref3"; +}; + &rtc { status = "okay"; }; @@ -556,8 +601,7 @@ ceva,p1-comwake-params = /bits/ 8 <0x06 0x14 0x08 0x0E>; ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>; ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>; - phy-names = "sata-phy"; - phys = <&lane3 PHY_TYPE_SATA 1 3 125000000>; + phys = <&psgtr 3 PHY_TYPE_SATA 1 3>; }; /* SD1 with level shifter */ @@ -571,10 +615,6 @@ xlnx,mio-bank = <1>; }; -&serdes { - status = "okay"; -}; - &uart0 { status = "okay"; }; @@ -588,6 +628,4 @@ status = "okay"; dr_mode = "host"; snps,usb3_lpm_capable; - phy-names = "usb3-phy"; - phys = <&lane2 PHY_TYPE_USB3 0 2 26000000>; }; diff --git a/arch/arm/dts/zynqmp-zcu216-revA.dts b/arch/arm/dts/zynqmp-zcu216-revA.dts index 847e689c155..2302b07c482 100644 --- a/arch/arm/dts/zynqmp-zcu216-revA.dts +++ b/arch/arm/dts/zynqmp-zcu216-revA.dts @@ -120,6 +120,20 @@ compatible = "iio-hwmon"; io-channels = <&dac_avcc 0>, <&dac_avcc 1>, <&dac_avcc 2>, <&dac_avcc 3>; }; + + /* 48MHz reference crystal */ + ref48: ref48M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + }; +}; + +&psgtr { + status = "okay"; + /* pcie, sata, usb3, dp */ + clocks = <&si5341 0 5>, <&si5341 0 3>, <&si5341 0 2>, <&si5341 0 0>; + clock-names = "ref0", "ref1", "ref2", "ref3"; }; &dcc { @@ -408,10 +422,41 @@ #size-cells = <0>; reg = <1>; si5341: clock-generator@36 { /* SI5341 - u43 */ - compatible = "si5341"; + compatible = "silabs,si5341"; reg = <0x36>; + #clock-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&ref48>; + clock-names = "xtal"; + clock-output-names = "si5341"; + + si5341_2: out@2 { + /* refclk2 for PS-GT, used for USB3 */ + reg = <2>; + always-on; /* assigned-clocks does not enable, so do it here */ + }; + si5341_3: out@3 { + /* refclk3 for PS-GT, used for SATA */ + reg = <3>; + always-on; /* assigned-clocks does not enable, so do it here */ + }; + si5341_5: out@5 { + /* refclk5 PL CLK100 */ + reg = <5>; + always-on; /* assigned-clocks does not enable, so do it here */ + }; + si5341_6: out@6 { + /* refclk6 PL CLK125 */ + reg = <6>; + always-on; /* assigned-clocks does not enable, so do it here */ + }; + si5341_9: out@9 { + /* refclk9 used for PS_REF_CLK 33.3 MHz */ + reg = <9>; + always-on; /* assigned-clocks does not enable, so do it here */ + }; }; - }; i2c_si570_user_c0: i2c@2 { #address-cells = <1>; @@ -560,8 +605,7 @@ ceva,p1-comwake-params = /bits/ 8 <0x06 0x14 0x08 0x0E>; ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>; ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>; - phy-names = "sata-phy"; - phys = <&lane3 PHY_TYPE_SATA 1 3 125000000>; + phys = <&psgtr 3 PHY_TYPE_SATA 1 3>; }; /* SD1 with level shifter */ @@ -575,10 +619,6 @@ xlnx,mio-bank = <1>; }; -&serdes { - status = "okay"; -}; - &uart0 { status = "okay"; }; @@ -592,6 +632,4 @@ status = "okay"; dr_mode = "host"; snps,usb3_lpm_capable; - phy-names = "usb3-phy"; - phys = <&lane2 PHY_TYPE_USB3 0 2 26000000>; }; diff --git a/arch/arm/dts/zynqmp.dtsi b/arch/arm/dts/zynqmp.dtsi index 2917a956eb3..84d9770225a 100644 --- a/arch/arm/dts/zynqmp.dtsi +++ b/arch/arm/dts/zynqmp.dtsi @@ -12,6 +12,7 @@ * the License, or (at your option) any later version. */ +#include #include #include @@ -160,11 +161,25 @@ mbox-names = "tx", "rx"; }; + nvmem_firmware { + compatible = "xlnx,zynqmp-nvmem-fw"; + #address-cells = <1>; + #size-cells = <1>; + + soc_revision: soc_revision@0 { + reg = <0x0 0x4>; + }; + }; + zynqmp_pcap: pcap { compatible = "xlnx,zynqmp-pcap-fpga"; clock-names = "ref_clk"; }; + xlnx_aes: zynqmp-aes { + compatible = "xlnx,zynqmp-aes"; + }; + zynqmp_reset: reset-controller { compatible = "xlnx,zynqmp-reset"; #reset-cells = <1>; @@ -198,16 +213,6 @@ ranges; }; - nvmem_firmware { - compatible = "xlnx,zynqmp-nvmem-fw"; - #address-cells = <1>; - #size-cells = <1>; - - soc_revision: soc_revision@0 { - reg = <0x0 0x4>; - }; - }; - amba: axi { compatible = "simple-bus"; u-boot,dm-pre-reloc; @@ -501,8 +506,8 @@ interrupts = <0 112 4>; }; - nand0: nand@ff100000 { - compatible = "arasan,nfc-v3p10"; + nand0: nand-controller@ff100000 { + compatible = "xlnx,zynqmp-nand-controller", "arasan,nfc-v3p10"; status = "disabled"; reg = <0x0 0xff100000 0x0 0x1000>; clock-names = "controller", "bus"; @@ -667,6 +672,15 @@ power-domains = <&zynqmp_firmware PD_QSPI>; }; + psgtr: phy@fd400000 { + compatible = "xlnx,zynqmp-psgtr-v1.1"; + status = "disabled"; + reg = <0x0 0xfd400000 0x0 0x40000>, + <0x0 0xfd3d0000 0x0 0x1000>; + reg-names = "serdes", "siou"; + #phy-cells = <4>; + }; + rtc: rtc@ffa60000 { compatible = "xlnx,zynqmp-rtc"; status = "disabled"; @@ -677,45 +691,6 @@ calibration = <0x8000>; }; - serdes: zynqmp_phy@fd400000 { - compatible = "xlnx,zynqmp-psgtr"; - status = "disabled"; - reg = <0x0 0xfd400000 0x0 0x40000>, - <0x0 0xfd3d0000 0x0 0x1000>, - <0x0 0xff5e0000 0x0 0x1000>; - reg-names = "serdes", "siou", "lpd"; - nvmem-cells = <&soc_revision>; - nvmem-cell-names = "soc_revision"; - resets = <&zynqmp_reset ZYNQMP_RESET_SATA>, - <&zynqmp_reset ZYNQMP_RESET_USB0_CORERESET>, - <&zynqmp_reset ZYNQMP_RESET_USB1_CORERESET>, - <&zynqmp_reset ZYNQMP_RESET_USB0_HIBERRESET>, - <&zynqmp_reset ZYNQMP_RESET_USB1_HIBERRESET>, - <&zynqmp_reset ZYNQMP_RESET_USB0_APB>, - <&zynqmp_reset ZYNQMP_RESET_USB1_APB>, - <&zynqmp_reset ZYNQMP_RESET_DP>, - <&zynqmp_reset ZYNQMP_RESET_GEM0>, - <&zynqmp_reset ZYNQMP_RESET_GEM1>, - <&zynqmp_reset ZYNQMP_RESET_GEM2>, - <&zynqmp_reset ZYNQMP_RESET_GEM3>; - reset-names = "sata_rst", "usb0_crst", "usb1_crst", - "usb0_hibrst", "usb1_hibrst", "usb0_apbrst", - "usb1_apbrst", "dp_rst", "gem0_rst", - "gem1_rst", "gem2_rst", "gem3_rst"; - lane0: lane0 { - #phy-cells = <4>; - }; - lane1: lane1 { - #phy-cells = <4>; - }; - lane2: lane2 { - #phy-cells = <4>; - }; - lane3: lane3 { - #phy-cells = <4>; - }; - }; - sata: ahci@fd0c0000 { compatible = "ceva,ahci-1v84"; status = "disabled"; @@ -740,11 +715,11 @@ xlnx,device_id = <0>; #stream-id-cells = <1>; iommus = <&smmu 0x870>; - power-domains = <&zynqmp_firmware PD_SD_0>; nvmem-cells = <&soc_revision>; nvmem-cell-names = "soc_revision"; #clock-cells = <1>; clock-output-names = "clk_out_sd0", "clk_in_sd0"; + power-domains = <&zynqmp_firmware PD_SD_0>; }; sdhci1: mmc@ff170000 { @@ -758,11 +733,11 @@ xlnx,device_id = <1>; #stream-id-cells = <1>; iommus = <&smmu 0x871>; - power-domains = <&zynqmp_firmware PD_SD_1>; nvmem-cells = <&soc_revision>; nvmem-cell-names = "soc_revision"; #clock-cells = <1>; clock-output-names = "clk_out_sd1", "clk_in_sd1"; + power-domains = <&zynqmp_firmware PD_SD_1>; }; smmu: iommu@fd800000 { @@ -962,37 +937,18 @@ }; }; - xlnx_dpdma: dma@fd4c0000 { - compatible = "xlnx,dpdma"; + zynqmp_dpdma: dma-controller@fd4c0000 { + compatible = "xlnx,zynqmp-dpdma"; status = "disabled"; reg = <0x0 0xfd4c0000 0x0 0x1000>; interrupts = <0 122 4>; interrupt-parent = <&gic>; clock-names = "axi_clk"; power-domains = <&zynqmp_firmware PD_DP>; - dma-channels = <6>; #dma-cells = <1>; - dma-video0channel { - compatible = "xlnx,video0"; - }; - dma-video1channel { - compatible = "xlnx,video1"; - }; - dma-video2channel { - compatible = "xlnx,video2"; - }; - dma-graphicschannel { - compatible = "xlnx,graphics"; - }; - dma-audio0channel { - compatible = "xlnx,audio0"; - }; - dma-audio1channel { - compatible = "xlnx,audio1"; - }; }; - zynqmp_dpsub: zynqmp-display@fd4a0000 { + zynqmp_dpsub: display@fd4a0000 { compatible = "xlnx,zynqmp-dpsub-1.7"; status = "disabled"; reg = <0x0 0xfd4a0000 0x0 0x1000>, @@ -1002,51 +958,15 @@ reg-names = "dp", "blend", "av_buf", "aud"; interrupts = <0 119 4>; interrupt-parent = <&gic>; - clock-names = "dp_apb_clk", "dp_aud_clk", "dp_vtc_pixel_clk_in"; - power-domains = <&zynqmp_firmware PD_DP>; - - vid-layer { - dma-names = "vid0", "vid1", "vid2"; - dmas = <&xlnx_dpdma 0>, - <&xlnx_dpdma 1>, - <&xlnx_dpdma 2>; - }; - - gfx-layer { - dma-names = "gfx0"; - dmas = <&xlnx_dpdma 3>; - }; - - /* dummy node to indicate there's no child i2c device */ - i2c-bus { - }; - - zynqmp_dp_snd_codec0: zynqmp_dp_snd_codec0 { - compatible = "xlnx,dp-snd-codec"; - clock-names = "aud_clk"; - }; - - zynqmp_dp_snd_pcm0: zynqmp_dp_snd_pcm0 { - compatible = "xlnx,dp-snd-pcm"; - dmas = <&xlnx_dpdma 4>; - dma-names = "tx"; - }; - - zynqmp_dp_snd_pcm1: zynqmp_dp_snd_pcm1 { - compatible = "xlnx,dp-snd-pcm"; - dmas = <&xlnx_dpdma 5>; - dma-names = "tx"; - }; - - zynqmp_dp_snd_card0: zynqmp_dp_snd_card { - compatible = "xlnx,dp-snd-card"; - xlnx,dp-snd-pcm = <&zynqmp_dp_snd_pcm0>, - <&zynqmp_dp_snd_pcm1>; - xlnx,dp-snd-codec = <&zynqmp_dp_snd_codec0>; - }; + resets = <&zynqmp_reset ZYNQMP_RESET_DP>; + dma-names = "vid0", "vid1", "vid2", "gfx0"; + dmas = <&zynqmp_dpdma ZYNQMP_DPDMA_VIDEO0>, + <&zynqmp_dpdma ZYNQMP_DPDMA_VIDEO1>, + <&zynqmp_dpdma ZYNQMP_DPDMA_VIDEO2>, + <&zynqmp_dpdma ZYNQMP_DPDMA_GRAPHICS>; }; }; }; diff --git a/include/dt-bindings/dma/xlnx-zynqmp-dpdma.h b/include/dt-bindings/dma/xlnx-zynqmp-dpdma.h new file mode 100644 index 00000000000..3719cda5679 --- /dev/null +++ b/include/dt-bindings/dma/xlnx-zynqmp-dpdma.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright 2019 Laurent Pinchart + */ + +#ifndef __DT_BINDINGS_DMA_XLNX_ZYNQMP_DPDMA_H__ +#define __DT_BINDINGS_DMA_XLNX_ZYNQMP_DPDMA_H__ + +#define ZYNQMP_DPDMA_VIDEO0 0 +#define ZYNQMP_DPDMA_VIDEO1 1 +#define ZYNQMP_DPDMA_VIDEO2 2 +#define ZYNQMP_DPDMA_GRAPHICS 3 +#define ZYNQMP_DPDMA_AUDIO0 4 +#define ZYNQMP_DPDMA_AUDIO1 5 + +#endif /* __DT_BINDINGS_DMA_XLNX_ZYNQMP_DPDMA_H__ */ -- cgit v1.3.1