[U-Boot] [PATCH 00/11] dm: Add more core features for livetree

This adds various minor features for livetree, mostly related to memory handling.
Michael Pratt (1): fdt: Add device tree memory bindings
Simon Glass (10): dm: core: Add ofnode function to read a 64-bit int dm: core: Fix a few ofnode function comments dm: core: Add comments to ofnode_read_resource() functoins dm: core: Add a way to find an ofnode by compatible string log: Add a way to log a return value with a message dm: core: Add a way to bind a device by ofnode dm: spi: Update sandbox SPI emulation driver to use ofnode dm: core: Update of_read_fmap_entry() for livetree dm: core: Add a function to decode a memory region dm: core: Add logging of some common errors
doc/device-tree-bindings/memory/memory.txt | 67 +++++++++++++ drivers/core/device.c | 8 ++ drivers/core/of_access.c | 19 ++++ drivers/core/of_extra.c | 89 ++++++++++++++++- drivers/core/ofnode.c | 44 +++++++++ drivers/core/uclass.c | 14 ++- drivers/misc/cros_ec.c | 4 +- drivers/mtd/spi/sandbox.c | 9 +- include/asm-generic/global_data.h | 1 + include/dm/device-internal.h | 4 + include/dm/of_access.h | 16 +++ include/dm/of_extra.h | 51 +++++++++- include/dm/ofnode.h | 48 ++++++++- include/fdt_support.h | 10 ++ include/fdtdec.h | 38 ++++++- include/log.h | 8 ++ include/spi_flash.h | 2 +- lib/fdtdec.c | 109 +++++++++++++++++++++ test/dm/spi.c | 8 +- 19 files changed, 526 insertions(+), 23 deletions(-) create mode 100644 doc/device-tree-bindings/memory/memory.txt

From: Michael Pratt mpratt@chromium.org
Support a default memory bank, specified in reg, as well as board-specific memory banks in subtree board-id nodes.
This allows memory information to be provided in the device tree, rather than hard-coded in, which will make it simpler to handle similar devices with different memory banks, as the board-id values or masks can be used to match devices.
Signed-off-by: Michael Pratt mpratt@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Vadim Bendebury vbendeb@chromium.org ---
doc/device-tree-bindings/memory/memory.txt | 67 +++++++++++++ include/asm-generic/global_data.h | 1 + include/fdt_support.h | 10 ++ include/fdtdec.h | 38 ++++++- lib/fdtdec.c | 109 +++++++++++++++++++++ 5 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/memory/memory.txt
diff --git a/doc/device-tree-bindings/memory/memory.txt b/doc/device-tree-bindings/memory/memory.txt new file mode 100644 index 0000000000..321894e01d --- /dev/null +++ b/doc/device-tree-bindings/memory/memory.txt @@ -0,0 +1,67 @@ +* Memory binding + +The memory binding for U-Boot is as in the ePAPR with the following additions: + +Optional subnodes can be used defining the memory layout for different board +ID masks. To match a set of board ids, a board-id node may define match-mask +and match-value ints to define a mask to apply to the board id, and the value +that the result should have for the match to be considered valid. The mask +defaults to -1, meaning that the value must fully match the board id. + +If subnodes are present, then the /memory node must define these properties: + +- #address-cells: should be 1. +- #size-cells: should be 0. + +Each subnode must define + + reg - board ID or mask for this subnode + memory-banks - list of memory banks in the same format as normal + +Each subnode may optionally define: + + match-mask - A mask to apply to the board id. This must be accompanied by + match-value. + match-value - The required resulting value of the board id mask for the given + node to be considered a match. + auto-size - Indicates that the value given for a bank is the maximum size, + each bank is probed to determine its actual size, which may be + smaller + + +The board id determination is up to the vendor and is not defined by this +binding. + +Example: + +memory { + #address-cells = <1>; + #size-cells = <1>; + reg = <0x20000000 0x20000000 + 0x40000000 0x20000000 + 0x60000000 0x20000000 + 0x80000000 0x20000000>; + auto-size; + board-id@0 { + match-value = <17>; + reg = <0x20000000 0x20000000 + 0x40000000 0x20000000>; + }; + board-id@1 { + match-mask = <2>; + match-value = <2>; + reg = <0x20000000 0x20000000 + 0x40000000 0x20000000 + 0x60000000 0x20000000 + 0x80000000 0x20000000 + 0xa0000000 0x20000000 + 0xc0000000 0x20000000 + 0xe0000000 0x20000000>; + }; +}; + + +This shows a system with the following properties: +* Default of 2GB of memory, auto-sized, so could be smaller +* 3.5GB of memory (with no auto-size) if (board id & 2) is 2 +* 1GB of memory (with no auto-size) if board id is 17. diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 2d451f8a1b..0fd4900392 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -52,6 +52,7 @@ typedef struct global_data { unsigned long env_has_init; /* Bitmask of boolean of struct env_location offsets */ int env_load_location;
+ unsigned long ram_base; /* Base address of RAM used by U-Boot */ unsigned long ram_top; /* Top address of RAM used by U-Boot */ unsigned long relocaddr; /* Start address of U-Boot in RAM */ phys_size_t ram_size; /* RAM size */ diff --git a/include/fdt_support.h b/include/fdt_support.h index e6c43ea983..a9a0078af6 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -283,6 +283,16 @@ int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
int fdt_overlay_apply_verbose(void *fdt, void *fdto);
+/** + * fdt_get_cells_len() - Get the length of a type of cell in top-level nodes + * + * Returns the length of the cell type in bytes (4 or 8). + * + * @blob: Pointer to device tree blob + * @nr_cells_name: Name to lookup, e.g. "#address-cells" + */ +int fdt_get_cells_len(const void *blob, char *nr_cells_name); + #endif /* ifdef CONFIG_OF_LIBFDT */
#ifdef USE_HOSTCC diff --git a/include/fdtdec.h b/include/fdtdec.h index c15b2a04a7..332105504b 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -41,6 +41,8 @@ struct fdt_memory { fdt_addr_t end; };
+struct bd_info; + #ifdef CONFIG_SPL_BUILD #define SPL_BUILD 1 #else @@ -993,6 +995,40 @@ int fdtdec_setup(void); * Called when CONFIG_OF_BOARD is defined, or if CONFIG_OF_SEPARATE is defined * and the board implements it. */ -void *board_fdt_blob_setup(void); + +/* + * Decode the size of memory + * + * RAM size is normally set in a /memory node and consists of a list of + * (base, size) cells in the 'reg' property. This information is used to + * determine the total available memory as well as the address and size + * of each bank. + * + * Optionally the memory configuration can vary depending on a board id, + * typically read from strapping resistors or an EEPROM on the board. + * + * Finally, memory size can be detected (within certain limits) by probing + * the available memory. It is safe to do so within the limits provides by + * the board's device tree information. This makes it possible to produce + * boards with different memory sizes, where the device tree specifies the + * maximum memory configuration, and the smaller memory configuration is + * probed. + * + * This function decodes that information, returning the memory base address, + * size and bank information. See the memory.txt binding for full + * documentation. + * + * @param blob Device tree blob + * @param area Name of node to check (NULL means "/memory") + * @param board_id Board ID to look up + * @param basep Returns base address of first memory bank (NULL to + * ignore) + * @param sizep Returns total memory size (NULL to ignore) + * @param bd Updated with the memory bank information (NULL to skip) + * @return 0 if OK, -ve on error + */ +int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id, + phys_addr_t *basep, phys_size_t *sizep, + struct bd_info *bd);
#endif diff --git a/lib/fdtdec.c b/lib/fdtdec.c index f4e8dbf699..fc92082b0b 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -11,6 +11,7 @@ #include <errno.h> #include <fdtdec.h> #include <fdt_support.h> +#include <inttypes.h> #include <linux/libfdt.h> #include <serial.h> #include <asm/sections.h> @@ -1350,4 +1351,112 @@ int fdtdec_setup(void) return fdtdec_prepare_fdt(); }
+#ifdef CONFIG_NR_DRAM_BANKS +int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id, + phys_addr_t *basep, phys_size_t *sizep, bd_t *bd) +{ + int addr_cells, size_cells; + const u32 *cell, *end; + u64 total_size, size, addr; + int node, child; + bool auto_size; + int bank; + int len; + + debug("%s: board_id=%d\n", __func__, board_id); + if (!area) + area = "/memory"; + node = fdt_path_offset(blob, area); + if (node < 0) { + debug("No %s node found\n", area); + return -ENOENT; + } + + cell = fdt_getprop(blob, node, "reg", &len); + if (!cell) { + debug("No reg property found\n"); + return -ENOENT; + } + + addr_cells = fdt_address_cells(blob, node); + size_cells = fdt_size_cells(blob, node); + + /* Check the board id and mask */ + for (child = fdt_first_subnode(blob, node); + child >= 0; + child = fdt_next_subnode(blob, child)) { + int match_mask, match_value; + + match_mask = fdtdec_get_int(blob, child, "match-mask", -1); + match_value = fdtdec_get_int(blob, child, "match-value", -1); + + if (match_value >= 0 && + ((board_id & match_mask) == match_value)) { + /* Found matching mask */ + debug("Found matching mask %d\n", match_mask); + node = child; + cell = fdt_getprop(blob, node, "reg", &len); + if (!cell) { + debug("No memory-banks property found\n"); + return -EINVAL; + } + break; + } + } + /* Note: if no matching subnode was found we use the parent node */ + + if (bd) { + memset(bd->bi_dram, '\0', sizeof(bd->bi_dram[0]) * + CONFIG_NR_DRAM_BANKS); + } + + auto_size = fdtdec_get_bool(blob, node, "auto-size"); + + total_size = 0; + end = cell + len / 4 - addr_cells - size_cells; + debug("cell at %p, end %p\n", cell, end); + for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { + if (cell > end) + break; + addr = 0; + if (addr_cells == 2) + addr += (u64)fdt32_to_cpu(*cell++) << 32UL; + addr += fdt32_to_cpu(*cell++); + if (bd) + bd->bi_dram[bank].start = addr; + if (basep && !bank) + *basep = (phys_addr_t)addr; + + size = 0; + if (size_cells == 2) + size += (u64)fdt32_to_cpu(*cell++) << 32UL; + size += fdt32_to_cpu(*cell++); + + if (auto_size) { + u64 new_size; + + debug("Auto-sizing %" PRIx64 ", size %" PRIx64 ": ", + addr, size); + new_size = get_ram_size((long *)(uintptr_t)addr, size); + if (new_size == size) { + debug("OK\n"); + } else { + debug("sized to %" PRIx64 "\n", new_size); + size = new_size; + } + } + + if (bd) + bd->bi_dram[bank].size = size; + total_size += size; + } + + debug("Memory size %" PRIu64 "\n", total_size); + if (sizep) + *sizep = (phys_size_t)total_size; + + return 0; +} +#endif /* CONFIG_NR_DRAM_BANKS */ + #endif /* !USE_HOSTCC */

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
From: Michael Pratt mpratt@chromium.org
Support a default memory bank, specified in reg, as well as board-specific memory banks in subtree board-id nodes.
This allows memory information to be provided in the device tree, rather than hard-coded in, which will make it simpler to handle similar devices with different memory banks, as the board-id values or masks can be used to match devices.
Signed-off-by: Michael Pratt mpratt@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Vadim Bendebury vbendeb@chromium.org
doc/device-tree-bindings/memory/memory.txt | 67 +++++++++++++ include/asm-generic/global_data.h | 1 + include/fdt_support.h | 10 ++ include/fdtdec.h | 38 ++++++- lib/fdtdec.c | 109 +++++++++++++++++++++ 5 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/memory/memory.txt
Applied to u-boot-dm

Hi Simon,
On 9.7.2018 21:50, Simon Glass wrote:
On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
From: Michael Pratt mpratt@chromium.org
Support a default memory bank, specified in reg, as well as board-specific memory banks in subtree board-id nodes.
This allows memory information to be provided in the device tree, rather than hard-coded in, which will make it simpler to handle similar devices with different memory banks, as the board-id values or masks can be used to match devices.
Signed-off-by: Michael Pratt mpratt@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Vadim Bendebury vbendeb@chromium.org
doc/device-tree-bindings/memory/memory.txt | 67 +++++++++++++ include/asm-generic/global_data.h | 1 + include/fdt_support.h | 10 ++ include/fdtdec.h | 38 ++++++- lib/fdtdec.c | 109 +++++++++++++++++++++ 5 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/memory/memory.txt
Applied to u-boot-dm
Just FYI: That ram_base in global_data.h is not used in this patch and in v2 in 2014 this wasn't the part of this patch. Anyway Siva will use this ram_base in his patch he sent recently.
Thanks, Michal

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 sjg@chromium.org ---
drivers/core/of_access.c | 19 +++++++++++++++++++ drivers/core/ofnode.c | 32 ++++++++++++++++++++++++++++++++ include/dm/of_access.h | 16 ++++++++++++++++ include/dm/ofnode.h | 10 ++++++++++ 4 files changed, 77 insertions(+)
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index 9a50f559de..ccc88ae4f0 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -457,6 +457,25 @@ 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("%#x (%d)\n", *outp, *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 3cf3205a2f..b2b02e4abf 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; diff --git a/include/dm/of_access.h b/include/dm/of_access.h index 74f0606e07..dd1abb8e97 100644 --- a/include/dm/of_access.h +++ b/include/dm/of_access.h @@ -218,6 +218,22 @@ struct device_node *of_find_node_by_phandle(phandle handle); */ int of_read_u32(const struct device_node *np, const char *propname, u32 *outp);
+/** + * of_read_u64() - Find and read a 64-bit integer from a property + * + * Search for a property in a device node and read a 64-bit value from + * it. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @outp: pointer to return value, modified only if return value is 0. + * + * @return 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + */ +int of_read_u64(const struct device_node *np, const char *propname, u64 *outp); + /** * of_read_u32_array() - Find and read an array of 32 bit integers * diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 5af6b7e616..dbb4273db6 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -236,6 +236,16 @@ int ofnode_read_u32_default(ofnode ref, const char *propname, u32 def); */ int ofnode_read_s32_default(ofnode node, const char *propname, s32 def);
+/** + * ofnode_read_u64_default() - Read a 64-bit integer from a property + * + * @ref: valid node reference to read property from + * @propname: name of the property to read from + * @def: default value to return if the property has no value + * @return property value, or @def if not found + */ +int ofnode_read_u64_default(ofnode node, const char *propname, u64 def); + /** * ofnode_read_string() - Read a string from a property *

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
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 sjg@chromium.org
drivers/core/of_access.c | 19 +++++++++++++++++++ drivers/core/ofnode.c | 32 ++++++++++++++++++++++++++++++++ include/dm/of_access.h | 16 ++++++++++++++++ include/dm/ofnode.h | 10 ++++++++++ 4 files changed, 77 insertions(+)
Applied to u-boot-dm

Tidy up three return-value errors.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/dm/ofnode.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index dbb4273db6..85cb87b83f 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -262,6 +262,7 @@ const char *ofnode_read_string(ofnode node, const char *propname); * @propname: name of the property to read * @out_values: pointer to return value, modified only if return value is 0 * @sz: number of array elements to read + * @return 0 if OK, -ve on error * * Search for a property in a device node and read 32-bit value(s) from * it. Returns 0 on success, -EINVAL if the property does not exist, @@ -490,6 +491,7 @@ ofnode ofnode_path(const char *path); * This looks for a property within the /chosen node and returns its value * * @propname: Property name to look for + * @return property value if found, else NULL */ const char *ofnode_get_chosen_prop(const char *propname);
@@ -645,7 +647,7 @@ int ofnode_read_simple_size_cells(ofnode node); * new platforms. * * @node: node to check - * @eturns true if node is needed in SPL/TL, false otherwise + * @return true if node is needed in SPL/TL, false otherwise */ bool ofnode_pre_reloc(ofnode node);

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
Tidy up three return-value errors.
Signed-off-by: Simon Glass sjg@chromium.org
include/dm/ofnode.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
Applied to u-boot-dm

These functions are missing comments. Add some.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/dm/ofnode.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 85cb87b83f..61c42311f8 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -651,7 +651,30 @@ int ofnode_read_simple_size_cells(ofnode node); */ bool ofnode_pre_reloc(ofnode node);
+/** + * ofnode_read_resource() - Read a resource from a node + * + * Read resource information from a node at the given index + * + * @node: Node to read from + * @index: Index of resource to read (0 = first) + * @res: Returns resource that was read, on success + * @return 0 if OK, -ve on error + */ int ofnode_read_resource(ofnode node, uint index, struct resource *res); + +/** + * ofnode_read_resource_byname() - Read a resource from a node by name + * + * Read resource information from a node matching the given name. This uses a + * 'reg-names' string list property with the names matching the associated + * 'reg' property list. + * + * @node: Node to read from + * @name: Name of resource to read + * @res: Returns resource that was read, on success + * @return 0 if OK, -ve on error + */ int ofnode_read_resource_byname(ofnode node, const char *name, struct resource *res);

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
These functions are missing comments. Add some.
Signed-off-by: Simon Glass sjg@chromium.org
include/dm/ofnode.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
Applied to u-boot-dm

Add an ofnode_by_compatible() to allow iterating through ofnodes with a given compatible string.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/ofnode.c | 12 ++++++++++++ include/dm/ofnode.h | 11 +++++++++++ 2 files changed, 23 insertions(+)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index b2b02e4abf..29375397e0 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 61c42311f8..cd08a7e4d0 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 *

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
Add an ofnode_by_compatible() to allow iterating through ofnodes with a given compatible string.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/ofnode.c | 12 ++++++++++++ include/dm/ofnode.h | 11 +++++++++++ 2 files changed, 23 insertions(+)
Applied to u-boot-dm

It is sometimes useful to show a message when logging an error return value, perhaps to add a few details about the problem. Add a function to support this.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/log.h | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/include/log.h b/include/log.h index a3edd25546..a01b728ec0 100644 --- a/include/log.h +++ b/include/log.h @@ -166,8 +166,16 @@ void __assert_fail(const char *assertion, const char *file, unsigned int line, log(LOG_CATEGORY, LOGL_ERR, "returning err=%d\n", __ret); \ __ret; \ }) +#define log_msg_ret(_msg, _ret) ({ \ + int __ret = (_ret); \ + if (__ret < 0) \ + log(LOG_CATEGORY, LOGL_ERR, "%s: returning err=%d\n", _msg, \ + __ret); \ + __ret; \ + }) #else #define log_ret(_ret) (_ret) +#define log_msg_ret(_ret) (_ret) #endif
/**

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
It is sometimes useful to show a message when logging an error return value, perhaps to add a few details about the problem. Add a function to support this.
Signed-off-by: Simon Glass sjg@chromium.org
include/log.h | 8 ++++++++ 1 file changed, 8 insertions(+)
Applied to u-boot-dm

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 sjg@chromium.org ---
drivers/core/device.c | 8 ++++++++ include/dm/device-internal.h | 4 ++++ 2 files changed, 12 insertions(+)
diff --git a/drivers/core/device.c b/drivers/core/device.c index e048e1a659..d5f5fc31b0 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 5a4d50cbbe..f4af15448f 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 *

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
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 sjg@chromium.org
drivers/core/device.c | 8 ++++++++ include/dm/device-internal.h | 4 ++++ 2 files changed, 12 insertions(+)
Applied to u-boot-dm

Update the parameters sandbox_sf_bind_emul to support livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mtd/spi/sandbox.c | 9 +++++---- include/spi_flash.h | 2 +- test/dm/spi.c | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 7893efee12..6dc2030281 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -556,7 +556,7 @@ static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state, SANDBOX_CMDLINE_OPT(spi_sf, 1, "connect a SPI flash: <bus>:<cs>:<id>:<file>");
int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs, - struct udevice *bus, int of_offset, const char *spec) + struct udevice *bus, ofnode node, const char *spec) { struct udevice *emul; char name[20], *str; @@ -575,7 +575,7 @@ int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs, puts("Cannot find sandbox_sf_emul driver\n"); return -ENOENT; } - ret = device_bind(bus, drv, str, NULL, of_offset, &emul); + ret = device_bind_ofnode(bus, drv, str, NULL, node, &emul); if (ret) { printf("Cannot create emul device for spec '%s' (err=%d)\n", spec, ret); @@ -619,7 +619,8 @@ static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum, if (ret) return ret;
- return sandbox_sf_bind_emul(state, busnum, cs, bus, -1, spec); + return sandbox_sf_bind_emul(state, busnum, cs, bus, ofnode_null(), + spec); }
int sandbox_spi_get_emul(struct sandbox_state *state, @@ -637,7 +638,7 @@ int sandbox_spi_get_emul(struct sandbox_state *state, debug("%s: busnum=%u, cs=%u: binding SPI flash emulation: ", __func__, busnum, cs); ret = sandbox_sf_bind_emul(state, busnum, cs, bus, - dev_of_offset(slave), slave->name); + dev_ofnode(slave), slave->name); if (ret) { debug("failed (err=%d)\n", ret); return ret; diff --git a/include/spi_flash.h b/include/spi_flash.h index 22533311c5..0ec98fb55d 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -185,7 +185,7 @@ static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, struct sandbox_state;
int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs, - struct udevice *bus, int of_offset, const char *spec); + struct udevice *bus, ofnode node, const char *spec);
void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs);
diff --git a/test/dm/spi.c b/test/dm/spi.c index 252b87431f..ffd789cd7f 100644 --- a/test/dm/spi.c +++ b/test/dm/spi.c @@ -23,7 +23,7 @@ static int dm_test_spi_find(struct unit_test_state *uts) struct udevice *bus, *dev; const int busnum = 0, cs = 0, mode = 0, speed = 1000000, cs_b = 1; struct spi_cs_info info; - int of_offset; + ofnode node;
ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_SPI, busnum, false, &bus)); @@ -34,7 +34,7 @@ static int dm_test_spi_find(struct unit_test_state *uts) */ ut_asserteq(0, uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus)); ut_assertok(spi_cs_info(bus, cs, &info)); - of_offset = dev_of_offset(info.dev); + node = dev_ofnode(info.dev); device_remove(info.dev, DM_REMOVE_NORMAL); device_unbind(info.dev);
@@ -65,7 +65,7 @@ static int dm_test_spi_find(struct unit_test_state *uts) ut_asserteq_ptr(NULL, info.dev);
/* Add the emulation and try again */ - ut_assertok(sandbox_sf_bind_emul(state, busnum, cs, bus, of_offset, + ut_assertok(sandbox_sf_bind_emul(state, busnum, cs, bus, node, "name")); ut_assertok(spi_find_bus_and_cs(busnum, cs, &bus, &dev)); ut_assertok(spi_get_bus_and_cs(busnum, cs, speed, mode, @@ -75,7 +75,7 @@ static int dm_test_spi_find(struct unit_test_state *uts) ut_asserteq_ptr(info.dev, slave->dev);
/* We should be able to add something to another chip select */ - ut_assertok(sandbox_sf_bind_emul(state, busnum, cs_b, bus, of_offset, + ut_assertok(sandbox_sf_bind_emul(state, busnum, cs_b, bus, node, "name")); ut_assertok(spi_get_bus_and_cs(busnum, cs_b, speed, mode, "spi_flash_std", "name", &bus, &slave));

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
Update the parameters sandbox_sf_bind_emul to support livetree.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/mtd/spi/sandbox.c | 9 +++++---- include/spi_flash.h | 2 +- test/dm/spi.c | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-)
Applied to u-boot-dm

Update this function to take an ofnode so that it can work with livetree.
Signed-off-by: Simon Glass sjg@chromium.org ---
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(-)
diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c index c76177c529..3243caa5d1 100644 --- a/drivers/core/of_extra.c +++ b/drivers/core/of_extra.c @@ -10,15 +10,15 @@ #include <dm/of_extra.h> #include <dm/ofnode.h>
-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 5fd2cd9973..6f299d407a 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 6f1529689f..e1540c1fbd 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

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
Update this function to take an ofnode so that it can work with livetree.
Signed-off-by: Simon Glass sjg@chromium.org
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(-)
Applied to u-boot-dm

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 sjg@chromium.org ---
drivers/core/of_extra.c | 81 +++++++++++++++++++++++++++++++++++++++++ include/dm/of_extra.h | 45 +++++++++++++++++++++++ 2 files changed, 126 insertions(+)
diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c index 3243caa5d1..aa48917ddd 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 e1540c1fbd..97988b6663 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: + * + * <mem_type>-memory<suffix> for the name of the memory bank + * <mem_type>-offset<suffix> 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

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
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 sjg@chromium.org
drivers/core/of_extra.c | 81 +++++++++++++++++++++++++++++++++++++++++ include/dm/of_extra.h | 45 +++++++++++++++++++++++ 2 files changed, 126 insertions(+)
Applied to u-boot-dm

Add additional logging so that common errors when finding a device by ofnode are easier to debug.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/uclass.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 0085d3fb24..d609b170e1 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); }

On 11 June 2018 at 13:07, Simon Glass sjg@chromium.org wrote:
Add additional logging so that common errors when finding a device by ofnode are easier to debug.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/uclass.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
Applied to u-boot-dm
participants (2)
-
Michal Simek
-
Simon Glass