From 7e5196c409f17091f2aeca144c6d76750df81cc4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Jun 2018 13:07:10 -0600 Subject: dm: core: Add ofnode function to read a 64-bit int We have a 32-bit version of this function. Add a 64-bit version as well so we can easily read 64-bit ints from the device tree. Signed-off-by: Simon Glass --- drivers/core/of_access.c | 20 ++++++++++++++++++++ drivers/core/ofnode.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index 9a50f559de2..0729dfcdb3b 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -457,6 +457,26 @@ int of_read_u32_array(const struct device_node *np, const char *propname, return 0; } +int of_read_u64(const struct device_node *np, const char *propname, u64 *outp) +{ + const __be64 *val; + + debug("%s: %s: ", __func__, propname); + if (!np) + return -EINVAL; + val = of_find_property_value_of_size(np, propname, sizeof(*outp)); + if (IS_ERR(val)) { + debug("(not found)\n"); + return PTR_ERR(val); + } + + *outp = be64_to_cpup(val); + debug("%#llx (%lld)\n", (unsigned long long)*outp, + (unsigned long long)*outp); + + return 0; +} + int of_property_match_string(const struct device_node *np, const char *propname, const char *string) { diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 3cf3205a2f1..b2b02e4abfb 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -55,6 +55,38 @@ int ofnode_read_s32_default(ofnode node, const char *propname, s32 def) return def; } +int ofnode_read_u64(ofnode node, const char *propname, u64 *outp) +{ + const fdt64_t *cell; + int len; + + assert(ofnode_valid(node)); + debug("%s: %s: ", __func__, propname); + + if (ofnode_is_np(node)) + return of_read_u64(ofnode_to_np(node), propname, outp); + + cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname, + &len); + if (!cell || len < sizeof(*cell)) { + debug("(not found)\n"); + return -EINVAL; + } + *outp = fdt64_to_cpu(cell[0]); + debug("%#llx (%lld)\n", (unsigned long long)*outp, + (unsigned long long)*outp); + + return 0; +} + +int ofnode_read_u64_default(ofnode node, const char *propname, u64 def) +{ + assert(ofnode_valid(node)); + ofnode_read_u64(node, propname, &def); + + return def; +} + bool ofnode_read_bool(ofnode node, const char *propname) { const void *prop; -- cgit v1.3.1 From c60f671b65a8b336c3533fcf0f0ee45dff287ff7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Jun 2018 13:07:13 -0600 Subject: dm: core: Add a way to find an ofnode by compatible string Add an ofnode_by_compatible() to allow iterating through ofnodes with a given compatible string. Signed-off-by: Simon Glass --- drivers/core/ofnode.c | 12 ++++++++++++ include/dm/ofnode.h | 11 +++++++++++ 2 files changed, 23 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index b2b02e4abfb..29375397e04 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -729,3 +729,15 @@ int ofnode_device_is_compatible(ofnode node, const char *compat) ofnode_to_offset(node), compat); } + +ofnode ofnode_by_compatible(ofnode from, const char *compat) +{ + if (of_live_active()) { + return np_to_ofnode(of_find_compatible_node( + (struct device_node *)ofnode_to_np(from), NULL, + compat)); + } else { + return offset_to_ofnode(fdt_node_offset_by_compatible( + gd->fdt_blob, ofnode_to_offset(from), compat)); + } +} diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 61c42311f8e..cd08a7e4d02 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -678,6 +678,17 @@ int ofnode_read_resource(ofnode node, uint index, struct resource *res); int ofnode_read_resource_byname(ofnode node, const char *name, struct resource *res); +/** + * ofnode_by_compatible() - Find the next compatible node + * + * Find the next node after @from that is compatible with @compat + * + * @from: ofnode to start from (use ofnode_null() to start at the beginning) + * @compat: Compatible string to match + * @return ofnode found, or ofnode_null() if none + */ +ofnode ofnode_by_compatible(ofnode from, const char *compat); + /** * ofnode_for_each_subnode() - iterate over all subnodes of a parent * -- cgit v1.3.1 From d677b00cb62a4cf4d4a24468f218581b4f57c2fe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Jun 2018 13:07:15 -0600 Subject: dm: core: Add a way to bind a device by ofnode Add a new device_bind_ofnode() function which can bind a device given its ofnode. This allows binding devices more easily with livetree nodes. Signed-off-by: Simon Glass --- drivers/core/device.c | 8 ++++++++ include/dm/device-internal.h | 4 ++++ 2 files changed, 12 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/device.c b/drivers/core/device.c index e048e1a6595..d5f5fc31b03 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -230,6 +230,14 @@ int device_bind(struct udevice *parent, const struct driver *drv, offset_to_ofnode(of_offset), 0, devp); } +int device_bind_ofnode(struct udevice *parent, const struct driver *drv, + const char *name, void *platdata, ofnode node, + struct udevice **devp) +{ + return device_bind_common(parent, drv, name, platdata, 0, node, 0, + devp); +} + int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, const struct driver_info *info, struct udevice **devp) { diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 5a4d50cbbea..f4af15448fa 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -40,6 +40,10 @@ int device_bind(struct udevice *parent, const struct driver *drv, const char *name, void *platdata, int of_offset, struct udevice **devp); +int device_bind_ofnode(struct udevice *parent, const struct driver *drv, + const char *name, void *platdata, ofnode node, + struct udevice **devp); + /** * device_bind_with_driver_data() - Create a device and bind it to a driver * -- cgit v1.3.1 From 5e0a7341cdda182f310624d5c336fb48be04a703 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Jun 2018 13:07:17 -0600 Subject: dm: core: Update of_read_fmap_entry() for livetree Update this function to take an ofnode so that it can work with livetree. Signed-off-by: Simon Glass --- drivers/core/of_extra.c | 8 ++++---- drivers/misc/cros_ec.c | 4 ++-- include/dm/of_extra.h | 6 ++---- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/core') diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c index c76177c5292..3243caa5d12 100644 --- a/drivers/core/of_extra.c +++ b/drivers/core/of_extra.c @@ -10,15 +10,15 @@ #include #include -int of_read_fmap_entry(ofnode node, const char *name, - struct fmap_entry *entry) +int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry) { const char *prop; u32 reg[2]; if (ofnode_read_u32_array(node, "reg", reg, 2)) { - debug("Node '%s' has bad/missing 'reg' property\n", name); - return -FDT_ERR_NOTFOUND; + debug("Node '%s' has bad/missing 'reg' property\n", + ofnode_get_name(node)); + return -log_ret(ENOENT); } entry->offset = reg[0]; entry->length = reg[1]; diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 5fd2cd99739..6f299d407a4 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1028,7 +1028,7 @@ int cros_ec_decode_ec_flash(struct udevice *dev, struct fdt_cros_ec *config) return -1; } - if (of_read_fmap_entry(flash_node, "flash", &config->flash)) { + if (ofnode_read_fmap_entry(flash_node, &config->flash)) { debug("Failed to decode flash node in chrome-ec\n"); return -1; } @@ -1050,7 +1050,7 @@ int cros_ec_decode_ec_flash(struct udevice *dev, struct fdt_cros_ec *config) return -1; } - if (of_read_fmap_entry(node, "reg", &config->region[region])) { + if (ofnode_read_fmap_entry(node, &config->region[region])) { debug("Failed to decode flash region in chrome-ec'\n"); return -1; } diff --git a/include/dm/of_extra.h b/include/dm/of_extra.h index 6f1529689f8..e1540c1fbdc 100644 --- a/include/dm/of_extra.h +++ b/include/dm/of_extra.h @@ -34,12 +34,10 @@ struct fmap_entry { /** * Read a flash entry from the fdt * - * @param node Reference to node to read - * @param name Name of node being read + * @param node Reference to node to read * @param entry Place to put offset and size of this node * @return 0 if ok, -ve on error */ -int of_read_fmap_entry(ofnode node, const char *name, - struct fmap_entry *entry); +int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry); #endif -- cgit v1.3.1 From 964cadc445f1437e63f1d2b4fffd233ac053c6e6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Jun 2018 13:07:18 -0600 Subject: dm: core: Add a function to decode a memory region Add a way to decode a memory region, including the memory type (sram or sdram) and its start address and size. Signed-off-by: Simon Glass --- drivers/core/of_extra.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++ include/dm/of_extra.h | 45 +++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c index 3243caa5d12..aa48917dddf 100644 --- a/drivers/core/of_extra.c +++ b/drivers/core/of_extra.c @@ -34,3 +34,84 @@ int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry) return 0; } + +int ofnode_decode_region(ofnode node, const char *prop_name, fdt_addr_t *basep, + fdt_size_t *sizep) +{ + const fdt_addr_t *cell; + int len; + + debug("%s: %s: %s\n", __func__, ofnode_get_name(node), prop_name); + cell = ofnode_get_property(node, prop_name, &len); + if (!cell || (len < sizeof(fdt_addr_t) * 2)) { + debug("cell=%p, len=%d\n", cell, len); + return -1; + } + + *basep = fdt_addr_to_cpu(*cell); + *sizep = fdt_size_to_cpu(cell[1]); + debug("%s: base=%08lx, size=%lx\n", __func__, (ulong)*basep, + (ulong)*sizep); + + return 0; +} + +int ofnode_decode_memory_region(ofnode config_node, const char *mem_type, + const char *suffix, fdt_addr_t *basep, + fdt_size_t *sizep) +{ + char prop_name[50]; + const char *mem; + fdt_size_t size, offset_size; + fdt_addr_t base, offset; + ofnode node; + + if (!ofnode_valid(config_node)) { + config_node = ofnode_path("/config"); + if (!ofnode_valid(config_node)) { + debug("%s: Cannot find /config node\n", __func__); + return -ENOENT; + } + } + if (!suffix) + suffix = ""; + + snprintf(prop_name, sizeof(prop_name), "%s-memory%s", mem_type, + suffix); + mem = ofnode_read_string(config_node, prop_name); + if (!mem) { + debug("%s: No memory type for '%s', using /memory\n", __func__, + prop_name); + mem = "/memory"; + } + + node = ofnode_path(mem); + if (!ofnode_valid(node)) { + debug("%s: Failed to find node '%s'\n", __func__, mem); + return -ENOENT; + } + + /* + * Not strictly correct - the memory may have multiple banks. We just + * use the first + */ + if (ofnode_decode_region(node, "reg", &base, &size)) { + debug("%s: Failed to decode memory region %s\n", __func__, + mem); + return -EINVAL; + } + + snprintf(prop_name, sizeof(prop_name), "%s-offset%s", mem_type, + suffix); + if (ofnode_decode_region(config_node, prop_name, &offset, + &offset_size)) { + debug("%s: Failed to decode memory region '%s'\n", __func__, + prop_name); + return -EINVAL; + } + + *basep = base + offset; + *sizep = offset_size; + + return 0; +} diff --git a/include/dm/of_extra.h b/include/dm/of_extra.h index e1540c1fbdc..97988b66632 100644 --- a/include/dm/of_extra.h +++ b/include/dm/of_extra.h @@ -40,4 +40,49 @@ struct fmap_entry { */ int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry); +/** + * ofnode_decode_region() - Decode a memory region from a node + * + * 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 node ofnode to examine + * @param prop_name name of property to find + * @param basep Returns base address of region + * @param size Returns size of region + * @return 0 if ok, -1 on error (property not found) + */ +int ofnode_decode_region(ofnode node, const char *prop_name, fdt_addr_t *basep, + fdt_size_t *sizep); + +/** + * ofnode_decode_memory_region()- Decode a named region within a memory bank + * + * This function handles selection of a memory region. The region is + * specified as an offset/size within a particular type of memory. + * + * The properties used are: + * + * -memory for the name of the memory bank + * -offset for the offset in that bank + * + * The property value must have an offset and a size. The function checks + * that the region is entirely within the memory bank.5 + * + * @param node ofnode containing the properties (-1 for /config) + * @param mem_type Type of memory to use, which is a name, such as + * "u-boot" or "kernel". + * @param suffix String to append to the memory/offset + * property names + * @param basep Returns base of region + * @param sizep Returns size of region + * @return 0 if OK, -ive on error + */ +int ofnode_decode_memory_region(ofnode config_node, const char *mem_type, + const char *suffix, fdt_addr_t *basep, + fdt_size_t *sizep); + #endif -- cgit v1.3.1 From 31e60ffa05b0952be3df8f584155567afdee50bd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Jun 2018 13:07:19 -0600 Subject: dm: core: Add logging of some common errors Add additional logging so that common errors when finding a device by ofnode are easier to debug. Signed-off-by: Simon Glass --- drivers/core/uclass.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/core') diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 0085d3fb24b..d609b170e1a 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -308,6 +308,7 @@ int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node, struct udevice *dev; int ret; + log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node)); *devp = NULL; if (!ofnode_valid(node)) return -ENODEV; @@ -316,13 +317,19 @@ int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node, return ret; list_for_each_entry(dev, &uc->dev_head, uclass_node) { + log(LOGC_DM, LOGL_DEBUG_CONTENT, " - checking %s\n", + dev->name); if (ofnode_equal(dev_ofnode(dev), node)) { *devp = dev; - return 0; + goto done; } } + ret = -ENODEV; - return -ENODEV; +done: + log(LOGC_DM, LOGL_DEBUG, " - result for %s: %s (ret=%d)\n", + ofnode_get_name(node), *devp ? (*devp)->name : "(none)", ret); + return ret; } #if CONFIG_IS_ENABLED(OF_CONTROL) @@ -449,8 +456,11 @@ int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node, struct udevice *dev; int ret; + log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node)); *devp = NULL; ret = uclass_find_device_by_ofnode(id, node, &dev); + log(LOGC_DM, LOGL_DEBUG, " - result for %s: %s (ret=%d)\n", + ofnode_get_name(node), dev ? dev->name : "(none)", ret); return uclass_get_device_tail(dev, ret, devp); } -- cgit v1.3.1