From 09258f1e8b12acc4a2a02b60d942660798038fba Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Thu, 25 Oct 2012 16:30:58 +0000 Subject: fdt: Add function to get config int from device tree Add a function to look up a configuration item such as machine id and return its value. Note: The code has been taken as is from the Chromium u-boot development tree and needs Simon Glass' sign-off. Signed-off-by: Abhilash Kesavan Signed-off-by: Simon Glass diff --git a/include/fdtdec.h b/include/fdtdec.h index 0b14075..d880fe8 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -354,6 +354,19 @@ int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name, */ int fdtdec_setup_gpio(struct fdt_gpio_state *gpio); +/** + * Look in the FDT for a config item with the given name and return its value + * as a 32-bit integer. The property must have at least 4 bytes of data. The + * value of the first cell is returned. + * + * @param blob FDT blob to use + * @param prop_name Node property name + * @param default_val default value to return if the property is not found + * @return integer value, if found, or default_val if not + */ +int fdtdec_get_config_int(const void *blob, const char *prop_name, + int default_val); + /* * Look up a property in a node and return its contents in a byte * array of given length. The property must have at least enough data for diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 4c23f45..1f50022 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -512,3 +512,25 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node, return NULL; return cell; } + +/** + * Look in the FDT for a config item with the given name and return its value + * as a 32-bit integer. The property must have at least 4 bytes of data. The + * value of the first cell is returned. + * + * @param blob FDT blob to use + * @param prop_name Node property name + * @param default_val default value to return if the property is not found + * @return integer value, if found, or default_val if not + */ +int fdtdec_get_config_int(const void *blob, const char *prop_name, + int default_val) +{ + int config_node; + + debug("%s: %s\n", __func__, prop_name); + config_node = fdt_path_offset(blob, "/config"); + if (config_node < 0) + return default_val; + return fdtdec_get_int(blob, config_node, prop_name, default_val); +} -- cgit v0.10.2 From 332ab0d54aaa5b8b27096996d10c8c6183c6972c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Oct 2012 16:30:59 +0000 Subject: fdt: Add function to get a config string from device tree Add a function to look up a configuration string such as board name and returns its value. We look in the "/config" node for this. Signed-off-by: Simon Glass diff --git a/include/fdtdec.h b/include/fdtdec.h index d880fe8..e828662 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -367,6 +367,16 @@ int fdtdec_setup_gpio(struct fdt_gpio_state *gpio); int fdtdec_get_config_int(const void *blob, const char *prop_name, int default_val); +/** + * Look in the FDT for a config item with the given name and return its value + * as a string. + * + * @param blob FDT blob + * @param prop_name property name to look up + * @returns property string, NULL on error. + */ +char *fdtdec_get_config_string(const void *blob, const char *prop_name); + /* * Look up a property in a node and return its contents in a byte * array of given length. The property must have at least enough data for diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 1f50022..2d60c8a 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -513,16 +513,6 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node, return cell; } -/** - * Look in the FDT for a config item with the given name and return its value - * as a 32-bit integer. The property must have at least 4 bytes of data. The - * value of the first cell is returned. - * - * @param blob FDT blob to use - * @param prop_name Node property name - * @param default_val default value to return if the property is not found - * @return integer value, if found, or default_val if not - */ int fdtdec_get_config_int(const void *blob, const char *prop_name, int default_val) { @@ -534,3 +524,21 @@ int fdtdec_get_config_int(const void *blob, const char *prop_name, return default_val; return fdtdec_get_int(blob, config_node, prop_name, default_val); } + +char *fdtdec_get_config_string(const void *blob, const char *prop_name) +{ + const char *nodep; + int nodeoffset; + int len; + + debug("%s: %s\n", __func__, prop_name); + nodeoffset = fdt_path_offset(blob, "/config"); + if (nodeoffset < 0) + return NULL; + + nodep = fdt_getprop(blob, nodeoffset, prop_name, &len); + if (!nodep) + return NULL; + + return (char *)nodep; +} -- cgit v0.10.2 From f20c461984c3d986fde037d4c5bf600aa0497676 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Oct 2012 16:31:00 +0000 Subject: fdt: Add fdtdec_decode_region() to decode memory region A memory region has a start and a size and is often specified in a node by a 'reg' property. Add a function to decode this information from the fdt. Signed-off-by: Simon Glass diff --git a/include/fdtdec.h b/include/fdtdec.h index e828662..341e6a1 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -40,10 +40,12 @@ typedef u64 fdt_addr_t; #define FDT_ADDR_T_NONE (-1ULL) #define fdt_addr_to_cpu(reg) be64_to_cpu(reg) +#define fdt_size_to_cpu(reg) be64_to_cpu(reg) #else typedef u32 fdt_addr_t; #define FDT_ADDR_T_NONE (-1U) #define fdt_addr_to_cpu(reg) be32_to_cpu(reg) +#define fdt_size_to_cpu(reg) be32_to_cpu(reg) #endif /* Information obtained about memory from the FDT */ @@ -408,4 +410,21 @@ int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, */ const u8 *fdtdec_locate_byte_array(const void *blob, int node, const char *prop_name, int count); + +/** + * Look up a property in a node which contains a memory region address and + * size. Then return a pointer to this address. + * + * The property must hold one address with a length. This is only tested on + * 32-bit machines. + * + * @param blob FDT blob + * @param node node to examine + * @param prop_name name of property to find + * @param ptrp returns pointer to region, or NULL if no address + * @param size returns size of region + * @return 0 if ok, -1 on error (propery not found) + */ +int fdtdec_decode_region(const void *blob, int node, + const char *prop_name, void **ptrp, size_t *size); #endif diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 2d60c8a..5570972 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -542,3 +542,20 @@ char *fdtdec_get_config_string(const void *blob, const char *prop_name) return (char *)nodep; } + +int fdtdec_decode_region(const void *blob, int node, + const char *prop_name, void **ptrp, size_t *size) +{ + const fdt_addr_t *cell; + int len; + + debug("%s: %s\n", __func__, prop_name); + cell = fdt_getprop(blob, node, prop_name, &len); + if (!cell || (len != sizeof(fdt_addr_t) * 2)) + return -1; + + *ptrp = (void *)fdt_addr_to_cpu(*cell); + *size = fdt_size_to_cpu(cell[1]); + debug("%s: size=%zx\n", __func__, *size); + return 0; +} -- cgit v0.10.2 From 5921f6a2924827548caf55b28a6827b9d856e37f Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Thu, 25 Oct 2012 16:31:01 +0000 Subject: fdt: Add function for decoding multiple gpios globally available Samsung's SDHCI bindings require multiple gpios to be parsed and configured at a time. Export the already available fdtdec_decode_gpios for this purpose. Signed-off-by: Abhilash Kesavan Commit-Ready: Che-Liang Chiou Signed-off-by: Simon Glass diff --git a/include/fdtdec.h b/include/fdtdec.h index 341e6a1..e70714b 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -345,6 +345,22 @@ int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name, struct fdt_gpio_state *gpio); /** + * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no + * terminating item. + * + * @param blob FDT blob to use + * @param node Node to look at + * @param prop_name Node property name + * @param gpio Array of gpio elements to fill from FDT. This will be + * untouched if either 0 or an error is returned + * @param max_count Maximum number of elements allowed + * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would + * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing. + */ +int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name, + struct fdt_gpio_state *gpio, int max_count); + +/** * Set up a GPIO pin according to the provided gpio information. At present this * just requests the GPIO. * diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 5570972..32f03cc 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -426,9 +426,8 @@ int fdtdec_get_bool(const void *blob, int node, const char *prop_name) * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing. */ -static int fdtdec_decode_gpios(const void *blob, int node, - const char *prop_name, struct fdt_gpio_state *gpio, - int max_count) +int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name, + struct fdt_gpio_state *gpio, int max_count) { const struct fdt_property *prop; const u32 *cell; -- cgit v0.10.2 From 7cde397b21a347134a39c40e24355a0e438adae3 Mon Sep 17 00:00:00 2001 From: Gerald Van Baren Date: Mon, 12 Nov 2012 23:13:54 -0500 Subject: fdt: Export fdtdec_lookup() and fix the name The name of this function is not consistent, so fix it, and export the function for external use. Signed-off-by: Simon Glass diff --git a/include/fdtdec.h b/include/fdtdec.h index e70714b..f8a4e94 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -110,6 +110,19 @@ int fdtdec_next_alias(const void *blob, const char *name, enum fdt_compat_id id, int *upto); /** + * Find the compatible ID for a given node. + * + * Generally each node has at least one compatible string attached to it. + * This function looks through our list of known compatible strings and + * returns the corresponding ID which matches the compatible string. + * + * @param blob FDT blob to use + * @param node Node containing compatible string to find + * @return compatible ID, or COMPAT_UNKNOWN if we cannot find a match + */ +enum fdt_compat_id fdtdec_lookup(const void *blob, int node); + +/** * Find the next compatible node for a peripheral. * * Do the first call with node = 0. This function will return a pointer to diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 32f03cc..96f3e7b 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -128,7 +128,7 @@ int fdtdec_get_is_enabled(const void *blob, int node) return 1; } -enum fdt_compat_id fd_dec_lookup(const void *blob, int node) +enum fdt_compat_id fdtdec_lookup(const void *blob, int node) { enum fdt_compat_id id; -- cgit v0.10.2 From 79289c0b5ff4a8c7869d7ca629cddc660dd06095 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 25 Oct 2012 16:31:04 +0000 Subject: fdt: Add function to read boolean property Signed-off-by: Vincent Palatin Commit-Ready: Vincent Palatin Commit-Ready: Gabe Black Signed-off-by: Simon Glass diff --git a/include/fdtdec.h b/include/fdtdec.h index f8a4e94..a37cf54 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -399,6 +399,16 @@ int fdtdec_get_config_int(const void *blob, const char *prop_name, int default_val); /** + * Look in the FDT for a config item with the given name + * and return whether it exists. + * + * @param blob FDT blob + * @param prop_name property name to look up + * @return 1, if it exists, or 0 if not + */ +int fdtdec_get_config_bool(const void *blob, const char *prop_name); + +/** * Look in the FDT for a config item with the given name and return its value * as a string. * diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 96f3e7b..da12df2 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -524,6 +524,20 @@ int fdtdec_get_config_int(const void *blob, const char *prop_name, return fdtdec_get_int(blob, config_node, prop_name, default_val); } +int fdtdec_get_config_bool(const void *blob, const char *prop_name) +{ + int config_node; + const void *prop; + + debug("%s: %s\n", __func__, prop_name); + config_node = fdt_path_offset(blob, "/config"); + if (config_node < 0) + return 0; + prop = fdt_get_property(blob, config_node, prop_name, NULL); + + return prop != NULL; +} + char *fdtdec_get_config_string(const void *blob, const char *prop_name) { const char *nodep; -- cgit v0.10.2 From aadef0a1bc3db81708471c9d18eb6c756659196f Mon Sep 17 00:00:00 2001 From: Che-Liang Chiou Date: Thu, 25 Oct 2012 16:31:05 +0000 Subject: fdt: Add fdtdec_get_uint64 to decode a 64-bit value from a property It decodes a 64-bit value from a property that is at least 8 bytes long. Signed-off-by: Che-Liang Chiou Signed-off-by: Simon Glass diff --git a/include/fdtdec.h b/include/fdtdec.h index a37cf54..b5d7d2f 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -182,6 +182,21 @@ s32 fdtdec_get_int(const void *blob, int node, const char *prop_name, s32 default_val); /** + * Look up a 64-bit integer property in a node and return it. The property + * must have at least 8 bytes of data (2 cells). The first two cells are + * concatenated to form a 8 bytes value, where the first cell is top half and + * the second cell is bottom half. + * + * @param blob FDT blob + * @param node node to examine + * @param prop_name name of property to find + * @param default_val default value to return if the property is not found + * @return integer value, if found, or default_val if not + */ +uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, + uint64_t default_val); + +/** * Checks whether a node is enabled. * This looks for a 'status' property. If this exists, then returns 1 if * the status is 'ok' and 0 otherwise. If there is no status property, diff --git a/lib/fdtdec.c b/lib/fdtdec.c index da12df2..150512e 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -111,6 +111,19 @@ s32 fdtdec_get_int(const void *blob, int node, const char *prop_name, return default_val; } +uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, + uint64_t default_val) +{ + const uint64_t *cell64; + int length; + + cell64 = fdt_getprop(blob, node, prop_name, &length); + if (!cell64 || length < sizeof(*cell64)) + return default_val; + + return fdt64_to_cpu(*cell64); +} + int fdtdec_get_is_enabled(const void *blob, int node) { const char *cell; -- cgit v0.10.2 From 202ff7537558edfd759b400cfe9e56c56fc7868c Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Thu, 25 Oct 2012 16:31:06 +0000 Subject: fdt: Add polarity-aware gpio functions to fdtdec Add get and set gpio functions to fdtdec that take into account the polarity field in fdtdec_gpio_state.flags. Signed-off-by: Sean Paul Signed-off-by: Simon Glass diff --git a/include/fdtdec.h b/include/fdtdec.h index b5d7d2f..5164ce2 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -90,6 +90,22 @@ struct fdt_gpio_state { #define fdt_gpio_isvalid(x) ((x)->gpio != FDT_GPIO_NONE) /** + * Read the GPIO taking into account the polarity of the pin. + * + * @param gpio pointer to the decoded gpio + * @return value of the gpio if successful, < 0 if unsuccessful + */ +int fdtdec_get_gpio(struct fdt_gpio_state *gpio); + +/** + * Write the GPIO taking into account the polarity of the pin. + * + * @param gpio pointer to the decoded gpio + * @return 0 if successful + */ +int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val); + +/** * Find the next numbered alias for a peripheral. This is used to enumerate * all the peripherals of a certain type. * diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 150512e..e1b17a5 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -487,6 +487,26 @@ int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name, return err == 1 ? 0 : err; } +int fdtdec_get_gpio(struct fdt_gpio_state *gpio) +{ + int val; + + if (!fdt_gpio_isvalid(gpio)) + return -1; + + val = gpio_get_value(gpio->gpio); + return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val; +} + +int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val) +{ + if (!fdt_gpio_isvalid(gpio)) + return -1; + + val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val; + return gpio_set_value(gpio->gpio, val); +} + int fdtdec_setup_gpio(struct fdt_gpio_state *gpio) { /* -- cgit v0.10.2 From 224b72e639e87040a1845cf9795b45417e064bba Mon Sep 17 00:00:00 2001 From: Che-Liang Chiou Date: Thu, 25 Oct 2012 16:31:07 +0000 Subject: fdt: Load boot command from device tree Load boot command from /config/bootcmd of device tree if present. Signed-off-by: Tom Wai-Hong Tam Signed-off-by: Che-Liang Chiou Signed-off-by: Simon Glass diff --git a/common/main.c b/common/main.c index 592ce07..48bed95 100644 --- a/common/main.c +++ b/common/main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_MODEM_SUPPORT @@ -40,6 +41,10 @@ #include #endif +#ifdef CONFIG_OF_CONTROL +#include +#endif + #include #include #include @@ -284,7 +289,10 @@ void main_loop (void) int rc = 1; int flag; #endif - +#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) && \ + defined(CONFIG_OF_CONTROL) + char *env; +#endif #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) char *s; int bootdelay; @@ -380,6 +388,12 @@ void main_loop (void) else #endif /* CONFIG_BOOTCOUNT_LIMIT */ s = getenv ("bootcmd"); +#ifdef CONFIG_OF_CONTROL + /* Allow the fdt to override the boot command */ + env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd"); + if (env) + s = env; +#endif /* CONFIG_OF_CONTROL */ debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : ""); -- cgit v0.10.2 From 3b73459ea3421e9f8c6c8c62e1d3fe458ca5bc56 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 25 Oct 2012 16:31:08 +0000 Subject: fdt: Tell the FDT library where the device tree is This change adds a call to set_working_fdt_addr near the end of u-boot initialization which tells the fdt command/library where the device tree is. This makes it possible to use the fdt command to look at the active device tree since otherwise there would be no way to know what address it was at to set things up manually. Signed-off-by: Gabe Black Signed-off-by: Simon Glass diff --git a/common/main.c b/common/main.c index 48bed95..fd70928 100644 --- a/common/main.c +++ b/common/main.c @@ -45,6 +45,10 @@ #include #endif +#ifdef CONFIG_OF_LIBFDT +#include +#endif /* CONFIG_OF_LIBFDT */ + #include #include #include @@ -418,6 +422,10 @@ void main_loop (void) #endif /* CONFIG_MENUKEY */ #endif /* CONFIG_BOOTDELAY */ +#if defined CONFIG_OF_CONTROL + set_working_fdt_addr((void *)gd->fdt_blob); +#endif /* CONFIG_OF_CONTROL */ + /* * Main Loop for Monitor Command Processing */ -- cgit v0.10.2 From 67e1ea26e89e19a550d86d6408f39d815eedaa7f Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Thu, 25 Oct 2012 16:31:09 +0000 Subject: fdt: Allow device tree to specify secure booting When secure booting is chosen: * The u-boot shell is never invoked during boot--we just do a simple table lookup to find the command. This means we could even remove the shell parsing from u-boot and still be able to boot. * The boot command can't be interruped. * Failure doesn't cause us to fall back to the shell. Signed-off-by: Gabe Black Signed-off-by: Doug Anderson Signed-off-by: Simon Glass diff --git a/common/main.c b/common/main.c index fd70928..61c6cac 100644 --- a/common/main.c +++ b/common/main.c @@ -283,6 +283,59 @@ int abortboot(int bootdelay) # endif /* CONFIG_AUTOBOOT_KEYED */ #endif /* CONFIG_BOOTDELAY >= 0 */ +/* + * Runs the given boot command securely. Specifically: + * - Doesn't run the command with the shell (run_command or parse_string_outer), + * since that's a lot of code surface that an attacker might exploit. + * Because of this, we don't do any argument parsing--the secure boot command + * has to be a full-fledged u-boot command. + * - Doesn't check for keypresses before booting, since that could be a + * security hole; also disables Ctrl-C. + * - Doesn't allow the command to return. + * + * Upon any failures, this function will drop into an infinite loop after + * printing the error message to console. + */ + +#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) && \ + defined(CONFIG_OF_CONTROL) +static void secure_boot_cmd(char *cmd) +{ + cmd_tbl_t *cmdtp; + int rc; + + if (!cmd) { + printf("## Error: Secure boot command not specified\n"); + goto err; + } + + /* Disable Ctrl-C just in case some command is used that checks it. */ + disable_ctrlc(1); + + /* Find the command directly. */ + cmdtp = find_cmd(cmd); + if (!cmdtp) { + printf("## Error: \"%s\" not defined\n", cmd); + goto err; + } + + /* Run the command, forcing no flags and faking argc and argv. */ + rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd); + + /* Shouldn't ever return from boot command. */ + printf("## Error: \"%s\" returned (code %d)\n", cmd, rc); + +err: + /* + * Not a whole lot to do here. Rebooting won't help much, since we'll + * just end up right back here. Just loop. + */ + hang(); +} + +#endif /* CONFIG_OF_CONTROL */ + + /****************************************************************************/ void main_loop (void) @@ -397,6 +450,15 @@ void main_loop (void) env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd"); if (env) s = env; + + /* + * If the bootsecure option was chosen, use secure_boot_cmd(). + * Always use 'env' in this case, since bootsecure requres that the + * bootcmd was specified in the FDT too. + */ + if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0)) + secure_boot_cmd(env); + #endif /* CONFIG_OF_CONTROL */ debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : ""); -- cgit v0.10.2 From d95f6ec7334076a1e4b13f3748ebfd1b58ac90f6 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 25 Oct 2012 16:31:10 +0000 Subject: fdt: Add option to default to most compatible conf in a fit image When booting a fit image with multiple configurations, the user either has to specify which configuration to use explicitly, or there has to be a default defined which is chosen automatically. This change adds an option to change that behavior so that a configuration can be selected explicitly, or the configuration which has the device tree that claims to be compatible with the earliest item in U-Boot's device tree. In other words, if U-Boot claimed to be compatible with A, B, and then C, and the configurations claimed to be compatible with A, D and B, D and D, E, the first configuration, A, D, would be chosen. Both the first and second configurations match, but the first one matches a more specific entry in U-Boot's device tree. The order in the kernel's device tree is ignored. Signed-off-by: Gabe Black Commit-Ready: Gabe Black Signed-off-by: Simon Glass diff --git a/README b/README index afdf591..6c77842 100644 --- a/README +++ b/README @@ -2597,6 +2597,17 @@ FIT uImage format: -150 common/cmd_nand.c Incorrect FIT image format 151 common/cmd_nand.c FIT image format OK +- FIT image support: + CONFIG_FIT + Enable support for the FIT uImage format. + + CONFIG_FIT_BEST_MATCH + When no configuration is explicitly selected, default to the + one whose fdt's compatibility field best matches that of + U-Boot itself. A match is considered "best" if it matches the + most specific compatibility entry of U-Boot's fdt's root node. + The order of entries in the configuration's fdt is ignored. + - Standalone program support: CONFIG_STANDALONE_LOAD_ADDR diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index d256ddf..4dbe952 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -949,8 +949,19 @@ static void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, * node */ bootstage_mark(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); +#ifdef CONFIG_FIT_BEST_MATCH + if (fit_uname_config) + cfg_noffset = + fit_conf_get_node(fit_hdr, + fit_uname_config); + else + cfg_noffset = + fit_conf_find_compat(fit_hdr, + gd->fdt_blob); +#else cfg_noffset = fit_conf_get_node(fit_hdr, fit_uname_config); +#endif if (cfg_noffset < 0) { bootstage_error(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); return NULL; diff --git a/common/image.c b/common/image.c index df642e6..e93b6e8 100644 --- a/common/image.c +++ b/common/image.c @@ -3049,6 +3049,133 @@ int fit_check_format(const void *fit) return 1; } + +/** + * fit_conf_find_compat + * @fit: pointer to the FIT format image header + * @fdt: pointer to the device tree to compare against + * + * fit_conf_find_compat() attempts to find the configuration whose fdt is the + * most compatible with the passed in device tree. + * + * Example: + * + * / o image-tree + * |-o images + * | |-o fdt@1 + * | |-o fdt@2 + * | + * |-o configurations + * |-o config@1 + * | |-fdt = fdt@1 + * | + * |-o config@2 + * |-fdt = fdt@2 + * + * / o U-Boot fdt + * |-compatible = "foo,bar", "bim,bam" + * + * / o kernel fdt1 + * |-compatible = "foo,bar", + * + * / o kernel fdt2 + * |-compatible = "bim,bam", "baz,biz" + * + * Configuration 1 would be picked because the first string in U-Boot's + * compatible list, "foo,bar", matches a compatible string in the root of fdt1. + * "bim,bam" in fdt2 matches the second string which isn't as good as fdt1. + * + * returns: + * offset to the configuration to use if one was found + * -1 otherwise + */ +int fit_conf_find_compat(const void *fit, const void *fdt) +{ + int ndepth = 0; + int noffset, confs_noffset, images_noffset; + const void *fdt_compat; + int fdt_compat_len; + int best_match_offset = 0; + int best_match_pos = 0; + + confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); + images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (confs_noffset < 0 || images_noffset < 0) { + debug("Can't find configurations or images nodes.\n"); + return -1; + } + + fdt_compat = fdt_getprop(fdt, 0, "compatible", &fdt_compat_len); + if (!fdt_compat) { + debug("Fdt for comparison has no \"compatible\" property.\n"); + return -1; + } + + /* + * Loop over the configurations in the FIT image. + */ + for (noffset = fdt_next_node(fit, confs_noffset, &ndepth); + (noffset >= 0) && (ndepth > 0); + noffset = fdt_next_node(fit, noffset, &ndepth)) { + const void *kfdt; + const char *kfdt_name; + int kfdt_noffset; + const char *cur_fdt_compat; + int len; + size_t size; + int i; + + if (ndepth > 1) + continue; + + kfdt_name = fdt_getprop(fit, noffset, "fdt", &len); + if (!kfdt_name) { + debug("No fdt property found.\n"); + continue; + } + kfdt_noffset = fdt_subnode_offset(fit, images_noffset, + kfdt_name); + if (kfdt_noffset < 0) { + debug("No image node named \"%s\" found.\n", + kfdt_name); + continue; + } + /* + * Get a pointer to this configuration's fdt. + */ + if (fit_image_get_data(fit, kfdt_noffset, &kfdt, &size)) { + debug("Failed to get fdt \"%s\".\n", kfdt_name); + continue; + } + + len = fdt_compat_len; + cur_fdt_compat = fdt_compat; + /* + * Look for a match for each U-Boot compatibility string in + * turn in this configuration's fdt. + */ + for (i = 0; len > 0 && + (!best_match_offset || best_match_pos > i); i++) { + int cur_len = strlen(cur_fdt_compat) + 1; + + if (!fdt_node_check_compatible(kfdt, 0, + cur_fdt_compat)) { + best_match_offset = noffset; + best_match_pos = i; + break; + } + len -= cur_len; + cur_fdt_compat += cur_len; + } + } + if (!best_match_offset) { + debug("No match found.\n"); + return -1; + } + + return best_match_offset; +} + /** * fit_conf_get_node - get node offset for configuration of a given unit name * @fit: pointer to the FIT format image header diff --git a/include/image.h b/include/image.h index 0a895f2..f54d983 100644 --- a/include/image.h +++ b/include/image.h @@ -615,6 +615,7 @@ int fit_image_check_type(const void *fit, int noffset, uint8_t type); int fit_image_check_comp(const void *fit, int noffset, uint8_t comp); int fit_check_format(const void *fit); +int fit_conf_find_compat(const void *fit, const void *fdt); int fit_conf_get_node(const void *fit, const char *conf_uname); int fit_conf_get_kernel_node(const void *fit, int noffset); int fit_conf_get_ramdisk_node(const void *fit, int noffset); -- cgit v0.10.2 From fcabc24f4fd2fd581036c7a20eee47a204f04f39 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Oct 2012 16:31:11 +0000 Subject: fdt: Set kernaddr if fdt indicates a kernel is present If kernel-offset is specified in the fdt, set an environment variable so that scripts can access the attached kernel. This can be used by a packaging program to tell U-Boot about a kernel that has been downloaded alongside U-Boot. The value in the fdt is the offset of the kernel from the start of the U-Boot image, so we can find it just by adding CONFIG_SYS_TEXT_BASE. It is then fairly easy to put something like this in the environment variables in the board header file: "if test ${kernaddr} != \"\"; then "\ "echo \"Using bundled kernel\"; "\ "bootm ${kernaddr};" \ "fi; "\ /* rest of boot sequence follows here */ Signed-off-by: Simon Glass diff --git a/common/main.c b/common/main.c index 61c6cac..8052d42 100644 --- a/common/main.c +++ b/common/main.c @@ -333,6 +333,20 @@ err: hang(); } +static void process_fdt_options(const void *blob) +{ + ulong addr; + + /* Add an env variable to point to a kernel payload, if available */ + addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0); + if (addr) + setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); + + /* Add an env variable to point to a root disk, if available */ + addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0); + if (addr) + setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); +} #endif /* CONFIG_OF_CONTROL */ @@ -451,6 +465,8 @@ void main_loop (void) if (env) s = env; + process_fdt_options(gd->fdt_blob); + /* * If the bootsecure option was chosen, use secure_boot_cmd(). * Always use 'env' in this case, since bootsecure requres that the -- cgit v0.10.2 From 008784765ab7f37fb355d5f7fb180661b94c42ab Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 31 Oct 2012 14:02:42 +0000 Subject: fdt: Remove fdtdec_find_alias_node() function This function is not needed, since fdt_path_offset() performs the same service. Remove it. Signed-off-by: Simon Glass diff --git a/lib/fdtdec.c b/lib/fdtdec.c index e1b17a5..348144a 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -52,28 +52,6 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id) return compat_names[id]; } -/** - * Look in the FDT for an alias with the given name and return its node. - * - * @param blob FDT blob - * @param name alias name to look up - * @return node offset if found, or an error code < 0 otherwise - */ -static int find_alias_node(const void *blob, const char *name) -{ - const char *path; - int alias_node; - - debug("find_alias_node: %s\n", name); - alias_node = fdt_path_offset(blob, "/aliases"); - if (alias_node < 0) - return alias_node; - path = fdt_getprop(blob, alias_node, name, NULL); - if (!path) - return -FDT_ERR_NOTFOUND; - return fdt_path_offset(blob, path); -} - fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name) { @@ -184,7 +162,7 @@ int fdtdec_next_alias(const void *blob, const char *name, /* snprintf() is not available */ assert(strlen(name) < MAX_STR_LEN); sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto); - node = find_alias_node(blob, str); + node = fdt_path_offset(blob, str); if (node < 0) return node; err = fdt_node_check_compatible(blob, node, compat_names[id]); -- cgit v0.10.2