From f4f4123708cd3699aa3981afca9511beb760c7fb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 27 Sep 2020 18:46:19 -0600 Subject: binman: Add a way to read the ROM offset Provide a function to read the ROM offset so that we can store the value in one place and clients don't need to store it themselves after calling binman_set_rom_offset(). Signed-off-by: Simon Glass --- include/binman.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/binman.h b/include/binman.h index e0b92075e27..8b89a9666d5 100644 --- a/include/binman.h +++ b/include/binman.h @@ -42,6 +42,13 @@ int binman_entry_map(ofnode parent, const char *name, void **bufp, int *sizep); */ void binman_set_rom_offset(int rom_offset); +/** + * binman_get_rom_offset() - Get the ROM memory-map offset + * + * @returns offset from an image_pos to the memory-mapped address + */ +int binman_get_rom_offset(void); + /** * binman_entry_find() - Find a binman symbol * -- cgit v1.3.1 From 3c14083f20679c526f3a133b2f71f0aad996fdc8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 3 Oct 2020 09:25:20 -0600 Subject: dm: core: Expand the comment for DM_GET_DEVICE() The current documentation for this is not particularly enlightening. Add a little more detail. Signed-off-by: Simon Glass --- include/dm/platdata.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/dm/platdata.h b/include/dm/platdata.h index cab93b071ba..25479b03d22 100644 --- a/include/dm/platdata.h +++ b/include/dm/platdata.h @@ -45,7 +45,22 @@ struct driver_info { #define U_BOOT_DEVICES(__name) \ ll_entry_declare_list(struct driver_info, __name, driver_info) -/* Get a pointer to a given driver */ +/** + * Get a pointer to a given device info given its name + * + * With the declaration U_BOOT_DEVICE(name), DM_GET_DEVICE(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. + * + * TODO(sjg@chromium.org): U_BOOT_DEVICE() tells U-Boot to create a device, so + * the naming seems sensible, but DM_GET_DEVICE() is a bit of misnomer, since it + * finds the driver_info record, not the device. + * + * @__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_GET_DEVICE(__name) \ ll_entry_get(struct driver_info, __name, driver_info) -- cgit v1.3.1 From 08c3b88dd145d3f7f06e7ad8458905bde7a286ef Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 3 Oct 2020 09:25:21 -0600 Subject: dm: core: Avoid void * in the of-platdata structs These pointers point to drivers. Update the definition to make this clear. Signed-off-by: Simon Glass --- include/dt-structs.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/dt-structs.h b/include/dt-structs.h index 924d51fc522..eed8273d18e 100644 --- a/include/dt-structs.h +++ b/include/dt-structs.h @@ -8,18 +8,20 @@ /* These structures may only be used in SPL */ #if CONFIG_IS_ENABLED(OF_PLATDATA) +struct driver_info; + struct phandle_0_arg { - const void *node; + const struct driver_info *node; int arg[0]; }; struct phandle_1_arg { - const void *node; + const struct driver_info *node; int arg[1]; }; struct phandle_2_arg { - const void *node; + const struct driver_info *node; int arg[2]; }; #include -- cgit v1.3.1 From a652d9c73a6eea1fdfb901c66178a4d804fac95d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 3 Oct 2020 09:25:22 -0600 Subject: dm: Avoid using #ifdef for CONFIG_OF_LIVE At present this option results in a number of #ifdefs due to the presence or absence of the global_data of_root member. Add a few macros to global_data.h to work around this. Update the code accordingly. Signed-off-by: Simon Glass --- common/board_r.c | 19 +++++++++---------- drivers/core/Makefile | 2 +- drivers/core/root.c | 27 +++++++++------------------ include/asm-generic/global_data.h | 13 ++++++++++++- include/dm/of.h | 9 +-------- test/dm/test-main.c | 16 +++++----------- 6 files changed, 37 insertions(+), 49 deletions(-) (limited to 'include') diff --git a/common/board_r.c b/common/board_r.c index b9217b2e27f..0829622d0d8 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -296,20 +296,21 @@ static int initr_noncached(void) } #endif -#ifdef CONFIG_OF_LIVE static int initr_of_live(void) { - int ret; + if (CONFIG_IS_ENABLED(OF_LIVE)) { + int ret; - bootstage_start(BOOTSTAGE_ID_ACCUM_OF_LIVE, "of_live"); - ret = of_live_build(gd->fdt_blob, (struct device_node **)&gd->of_root); - bootstage_accum(BOOTSTAGE_ID_ACCUM_OF_LIVE); - if (ret) - return ret; + bootstage_start(BOOTSTAGE_ID_ACCUM_OF_LIVE, "of_live"); + ret = of_live_build(gd->fdt_blob, + (struct device_node **)gd_of_root_ptr()); + bootstage_accum(BOOTSTAGE_ID_ACCUM_OF_LIVE); + if (ret) + return ret; + } return 0; } -#endif #ifdef CONFIG_DM static int initr_dm(void) @@ -713,9 +714,7 @@ static init_fnc_t init_sequence_r[] = { #ifdef CONFIG_SYS_NONCACHED_MEMORY initr_noncached, #endif -#ifdef CONFIG_OF_LIVE initr_of_live, -#endif #ifdef CONFIG_DM initr_dm, #endif diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 10f4bece335..5edd4e41357 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_DM) += dump.o obj-$(CONFIG_$(SPL_TPL_)REGMAP) += regmap.o obj-$(CONFIG_$(SPL_TPL_)SYSCON) += syscon-uclass.o -obj-$(CONFIG_OF_LIVE) += of_access.o of_addr.o +obj-$(CONFIG_$(SPL_)OF_LIVE) += of_access.o of_addr.o ifndef CONFIG_DM_DEV_READ_INLINE obj-$(CONFIG_OF_CONTROL) += read.o endif diff --git a/drivers/core/root.c b/drivers/core/root.c index 0726be6b795..de23161cff8 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -61,7 +61,7 @@ void fix_drivers(void) for (entry = drv; entry != drv + n_ents; entry++) { if (entry->of_match) entry->of_match = (const struct udevice_id *) - ((u32)entry->of_match + gd->reloc_off); + ((ulong)entry->of_match + gd->reloc_off); if (entry->bind) entry->bind += gd->reloc_off; if (entry->probe) @@ -151,11 +151,9 @@ int dm_init(bool of_live) if (ret) return ret; #if CONFIG_IS_ENABLED(OF_CONTROL) -# if CONFIG_IS_ENABLED(OF_LIVE) - if (of_live) - DM_ROOT_NON_CONST->node = np_to_ofnode(gd->of_root); + if (CONFIG_IS_ENABLED(OF_LIVE) && of_live) + DM_ROOT_NON_CONST->node = np_to_ofnode(gd_of_root()); else -#endif DM_ROOT_NON_CONST->node = offset_to_ofnode(0); #endif ret = device_probe(DM_ROOT_NON_CONST); @@ -196,7 +194,7 @@ int dm_scan_platdata(bool pre_reloc_only) return ret; } -#if CONFIG_IS_ENABLED(OF_LIVE) +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) static int dm_scan_fdt_live(struct udevice *parent, const struct device_node *node_parent, bool pre_reloc_only) @@ -223,9 +221,7 @@ static int dm_scan_fdt_live(struct udevice *parent, return ret; } -#endif /* CONFIG_IS_ENABLED(OF_LIVE) */ -#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) /** * dm_scan_fdt_node() - Scan the device tree and bind drivers for a node * @@ -272,24 +268,20 @@ int dm_scan_fdt_dev(struct udevice *dev) if (!dev_of_valid(dev)) return 0; -#if CONFIG_IS_ENABLED(OF_LIVE) if (of_live_active()) return dm_scan_fdt_live(dev, dev_np(dev), gd->flags & GD_FLG_RELOC ? false : true); - else -#endif + return dm_scan_fdt_node(dev, gd->fdt_blob, dev_of_offset(dev), gd->flags & GD_FLG_RELOC ? false : true); } int dm_scan_fdt(const void *blob, bool pre_reloc_only) { -#if CONFIG_IS_ENABLED(OF_LIVE) if (of_live_active()) - return dm_scan_fdt_live(gd->dm_root, gd->of_root, + return dm_scan_fdt_live(gd->dm_root, gd_of_root(), pre_reloc_only); - else -#endif + return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only); } @@ -302,10 +294,9 @@ static int dm_scan_fdt_ofnode_path(const void *blob, const char *path, if (!ofnode_valid(node)) return 0; -#if CONFIG_IS_ENABLED(OF_LIVE) if (of_live_active()) return dm_scan_fdt_live(gd->dm_root, node.np, pre_reloc_only); -#endif + return dm_scan_fdt_node(gd->dm_root, blob, node.of_offset, pre_reloc_only); } @@ -352,7 +343,7 @@ int dm_init_and_scan(bool pre_reloc_only) dm_populate_phandle_data(); #endif - ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE)); + ret = dm_init(CONFIG_IS_ENABLED(OF_LIVE)); if (ret) { debug("dm_init() failed: %d\n", ret); return ret; diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 0157af1aa4a..cadfc05dd75 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -211,7 +211,7 @@ struct global_data { * @fdt_size: space reserved for relocated device space */ unsigned long fdt_size; -#ifdef CONFIG_OF_LIVE +#if CONFIG_IS_ENABLED(OF_LIVE) /** * @of_root: root node of the live tree */ @@ -427,6 +427,17 @@ struct global_data { #define gd_board_type() 0 #endif +/* These macros help avoid #ifdefs in the code */ +#if CONFIG_IS_ENABLED(OF_LIVE) +#define gd_of_root() gd->of_root +#define gd_of_root_ptr() &gd->of_root +#define gd_set_of_root(_root) gd->of_root = (_root) +#else +#define gd_of_root() NULL +#define gd_of_root_ptr() NULL +#define gd_set_of_root(_root) +#endif + /** * enum gd_flags - global data flags * diff --git a/include/dm/of.h b/include/dm/of.h index 6bef73b441c..5cb6f44a6c6 100644 --- a/include/dm/of.h +++ b/include/dm/of.h @@ -90,17 +90,10 @@ DECLARE_GLOBAL_DATA_PTR; * * @returns true if livetree is active, false it not */ -#ifdef CONFIG_OF_LIVE static inline bool of_live_active(void) { - return gd->of_root != NULL; + return gd_of_root() != NULL; } -#else -static inline bool of_live_active(void) -{ - return false; -} -#endif #define OF_BAD_ADDR ((u64)-1) diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 38b7b1481a7..995988723ae 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -33,10 +33,8 @@ static int dm_test_init(struct unit_test_state *uts, bool of_live) memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); state_reset_for_test(state_get_current()); -#ifdef CONFIG_OF_LIVE /* Determine whether to make the live tree available */ - gd->of_root = of_live ? uts->of_root : NULL; -#endif + gd_set_of_root(of_live ? uts->of_root : NULL); ut_assertok(dm_init(of_live)); dms->root = dm_root(); @@ -152,9 +150,7 @@ static int dm_test_main(const char *test_name) printf("Running %d driver model tests\n", n_ents); found = 0; -#ifdef CONFIG_OF_LIVE - uts->of_root = gd->of_root; -#endif + uts->of_root = gd_of_root(); for (test = tests; test < tests + n_ents; test++) { const char *name = test->name; int runs; @@ -167,7 +163,7 @@ static int dm_test_main(const char *test_name) /* Run with the live tree if possible */ runs = 0; - if (IS_ENABLED(CONFIG_OF_LIVE)) { + if (CONFIG_IS_ENABLED(OF_LIVE)) { if (!(test->flags & UT_TESTF_FLAT_TREE)) { ut_assertok(dm_do_test(uts, test, true)); runs++; @@ -192,11 +188,9 @@ static int dm_test_main(const char *test_name) printf("Failures: %d\n", uts->fail_count); /* Put everything back to normal so that sandbox works as expected */ -#ifdef CONFIG_OF_LIVE - gd->of_root = uts->of_root; -#endif + gd_set_of_root(uts->of_root); gd->dm_root = NULL; - ut_assertok(dm_init(IS_ENABLED(CONFIG_OF_LIVE))); + ut_assertok(dm_init(CONFIG_IS_ENABLED(OF_LIVE))); dm_scan_platdata(false); dm_scan_fdt(gd->fdt_blob, false); -- cgit v1.3.1 From abb9cd30b23858125ce015c1dffdae4d7895bae8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 3 Oct 2020 11:31:26 -0600 Subject: dm: core: Allow dm_warn() to be used in SPL At present this option is disabled in SPL, meaning that warnings are not displayed. It is sometimes useful to see warnings in SPL for debugging purposes. Add a new Kconfig option to permit this. Signed-off-by: Simon Glass --- drivers/core/Kconfig | 18 ++++++++++++++++-- drivers/core/util.c | 2 +- include/config_uncmd_spl.h | 1 - include/dm/util.h | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 07d3a6a7a43..ffae6f9795f 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -40,10 +40,24 @@ config DM_WARN depends on DM default y help + Enable this to see warnings related to driver model. + + Warnings may help with debugging, such as when expected devices do + not bind correctly. If the option is disabled, dm_warn() is compiled + out - it will do nothing when called. + +config SPL_DM_WARN + bool "Enable warnings in driver model wuth SPL" + depends on SPL_DM + help + Enable this to see warnings related to driver model in SPL + The dm_warn() function can use up quite a bit of space for its strings. By default this is disabled for SPL builds to save space. - This will cause dm_warn() to be compiled out - it will do nothing - when called. + + Warnings may help with debugging, such as when expected devices do + not bind correctly. If the option is disabled, dm_warn() is compiled + out - it will do nothing when called. config DM_DEBUG bool "Enable debug messages in driver model core" diff --git a/drivers/core/util.c b/drivers/core/util.c index 25b0d76f430..91e93b0cf14 100644 --- a/drivers/core/util.c +++ b/drivers/core/util.c @@ -11,7 +11,7 @@ #include #include -#ifdef CONFIG_DM_WARN +#if CONFIG_IS_ENABLED(DM_WARN) void dm_warn(const char *fmt, ...) { va_list args; diff --git a/include/config_uncmd_spl.h b/include/config_uncmd_spl.h index 31da6215b3a..af7e3e49fdd 100644 --- a/include/config_uncmd_spl.h +++ b/include/config_uncmd_spl.h @@ -16,7 +16,6 @@ #undef CONFIG_DM_SPI #endif -#undef CONFIG_DM_WARN #undef CONFIG_DM_STDIO #endif /* CONFIG_SPL_BUILD */ diff --git a/include/dm/util.h b/include/dm/util.h index 9773db6de17..01a044992f2 100644 --- a/include/dm/util.h +++ b/include/dm/util.h @@ -6,7 +6,7 @@ #ifndef __DM_UTIL_H #define __DM_UTIL_H -#ifdef CONFIG_DM_WARN +#if CONFIG_IS_ENABLED(DM_WARN) void dm_warn(const char *fmt, ...); #else static inline void dm_warn(const char *fmt, ...) -- cgit v1.3.1 From 970cd91e8c4d9c812857601475dc2972ad1cd1b4 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sun, 11 Oct 2020 14:27:07 +0200 Subject: dm: core: fix typo in device.h Replace 'a the' with 'the' in include/dm/device.h. Signed-off-by: Dario Binacchi Reviewed-by: Simon Glass --- include/dm/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/dm/device.h b/include/dm/device.h index ac3b6c1b8a0..993c9e6c5ab 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -823,7 +823,7 @@ static inline bool device_is_on_pci_bus(const struct udevice *dev) _ret = device_next_child_err(&dev)) /** - * dm_scan_fdt_dev() - Bind child device in a the device tree + * dm_scan_fdt_dev() - Bind child device in the device tree * * This handles device which have sub-nodes in the device tree. It scans all * sub-nodes and binds drivers for each node where a driver can be found. -- cgit v1.3.1 From b25ff5cbaaaa7f144eb6e087b4bdd7362c58029d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Oct 2020 20:38:28 -0600 Subject: dm: test: Add a way to run SPL tests Add a -u flag for U-Boot SPL which requests that unit tests be run. To make this work, export dm_test_main() and update it to skip test features that are not used with of-platdata. To run the tests: $ spl/u-boot-spl -u U-Boot SPL 2020.10-rc5 (Oct 01 2020 - 07:35:39 -0600) Running 0 driver model tests Failures: 0 At present there are no SPL unit tests. Note that there is one wrinkle with these tests. SPL has limited memory available for allocation. Also malloc_simple does not free memory (free() is a nop) and running tests repeatedly causes driver-model to reinit multiple times and allocate memory. Therefore it is not possible to run more than a few tests at a time. One solution is to increase the amount of malloc space in sandbox_spl. This is not a problem for pytest, since it runs each test individually, so for now this is left as is. Signed-off-by: Simon Glass --- arch/sandbox/cpu/spl.c | 8 ++++++++ arch/sandbox/cpu/start.c | 9 +++++++++ arch/sandbox/include/asm/state.h | 1 + include/test/test.h | 11 +++++++++++ test/dm/test-main.c | 2 +- 5 files changed, 30 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index 7ab8919eb90..48fd1265afe 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -12,6 +12,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -67,6 +68,13 @@ void spl_board_init(void) uclass_next_device(&dev)) ; } + + if (state->run_unittests) { + int ret; + + ret = dm_test_main(NULL); + /* continue execution into U-Boot */ + } } void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index c6a2bbe4689..f5e104b127b 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -374,6 +374,15 @@ static int sandbox_cmdline_cb_show_of_platdata(struct sandbox_state *state, } SANDBOX_CMDLINE_OPT(show_of_platdata, 0, "Show of-platdata in SPL"); +static int sandbox_cmdline_cb_unittests(struct sandbox_state *state, + const char *arg) +{ + state->run_unittests = true; + + return 0; +} +SANDBOX_CMDLINE_OPT_SHORT(unittests, 'u', 0, "Run unit tests"); + static void setup_ram_buf(struct sandbox_state *state) { /* Zero the RAM buffer if we didn't read it, to keep valgrind happy */ diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 1bfad305f1a..f828d9d2447 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -92,6 +92,7 @@ struct sandbox_state { int default_log_level; /* Default log level for sandbox */ bool show_of_platdata; /* Show of-platdata in SPL */ bool ram_buf_read; /* true if we read the RAM buffer */ + bool run_unittests; /* Run unit tests */ /* Pointer to information for each SPI bus/cs */ struct sandbox_spi_info spi[CONFIG_SANDBOX_SPI_MAX_BUS] diff --git a/include/test/test.h b/include/test/test.h index 67c7d69d488..03e29290bf4 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -94,4 +94,15 @@ enum { TEST_DEVRES_SIZE3 = 37, }; +/** + * dm_test_main() - 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_main(const char *test_name); + #endif /* __TEST_TEST_H */ diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 5560572c7c6..9d22df8c4dc 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -127,7 +127,7 @@ static bool dm_test_run_on_flattree(struct unit_test *test) return !strstr(fname, "video") || strstr(test->name, "video_base"); } -static int dm_test_main(const char *test_name) +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); -- cgit v1.3.1 From a294ead8d2531a641f87bf182fee257029973ac0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 3 Oct 2020 11:31:33 -0600 Subject: dm: Use an allocated array for run-time device info At present we update the driver_info struct with a pointer to the device that it created (i.e. caused to be bound). This works fine when U-Boot SPL is stored in read-write memory. But on some platforms, such as Intel Apollo Lake, it is not possible to update the data memory. In any case, it is bad form to put this information in a structure that is in the data region, since it expands the size of the binary. Create a new driver_rt structure which holds runtime information about drivers. Update the code to store the device pointer in this instead. Also update the test check that this works. Signed-off-by: Simon Glass --- drivers/core/device.c | 11 ++++++----- drivers/core/lists.c | 16 +++++++++++----- drivers/core/root.c | 11 +++++++++++ include/asm-generic/global_data.h | 14 ++++++++++++++ include/dm/device-internal.h | 2 +- include/dm/platdata.h | 14 ++++++++++++-- test/dm/of_platdata.c | 19 ++++++++++--------- 7 files changed, 65 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/core/device.c b/drivers/core/device.c index 746c619cd96..2e5767ed99b 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -249,7 +249,7 @@ int device_bind_ofnode(struct udevice *parent, const struct driver *drv, } int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, - struct driver_info *info, struct udevice **devp) + const struct driver_info *info, struct udevice **devp) { struct driver *drv; uint platdata_size = 0; @@ -269,9 +269,6 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, platdata_size, devp); if (ret) return ret; -#if CONFIG_IS_ENABLED(OF_PLATDATA) - info->dev = *devp; -#endif return ret; } @@ -764,9 +761,13 @@ int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp) 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 = info->dev; + dev = drt->dev; *devp = NULL; return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp); diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 5beba9181cc..2e6bd5006ce 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -56,14 +56,20 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) struct driver_info *info = ll_entry_start(struct driver_info, driver_info); const int n_ents = ll_entry_count(struct driver_info, driver_info); - struct driver_info *entry; - struct udevice *dev; int result = 0; - int ret; + uint idx; + + for (idx = 0; idx < n_ents; idx++) { + const struct driver_info *entry = info + idx; + struct driver_rt *drt = gd_dm_driver_rt() + idx; + struct udevice *dev; + int ret; - for (entry = info; entry != info + n_ents; entry++) { ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev); - if (ret && ret != -EPERM) { + if (!ret) { + if (CONFIG_IS_ENABLED(OF_PLATDATA)) + drt->dev = dev; + } else if (ret != -EPERM) { dm_warn("No match for driver '%s'\n", entry->name); if (!result || ret != -ENOENT) result = ret; diff --git a/drivers/core/root.c b/drivers/core/root.c index de23161cff8..e8df5aebe84 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -185,6 +185,17 @@ int dm_scan_platdata(bool pre_reloc_only) { int ret; + if (CONFIG_IS_ENABLED(OF_PLATDATA)) { + struct driver_rt *dyn; + int n_ents; + + n_ents = ll_entry_count(struct driver_info, driver_info); + dyn = calloc(n_ents, sizeof(struct driver_rt)); + if (!dyn) + return -ENOMEM; + gd_set_dm_driver_rt(dyn); + } + ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only); if (ret == -ENOENT) { dm_warn("Some drivers were not found\n"); diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index cadfc05dd75..0aa11441848 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -24,6 +24,8 @@ #include #include +struct driver_rt; + typedef struct global_data gd_t; /** @@ -192,6 +194,10 @@ struct global_data { * @uclass_root: head of core tree */ struct list_head uclass_root; +# if CONFIG_IS_ENABLED(OF_PLATDATA) + /** Dynamic info about the driver */ + struct driver_rt *dm_driver_rt; +# endif #endif #ifdef CONFIG_TIMER /** @@ -438,6 +444,14 @@ struct global_data { #define gd_set_of_root(_root) #endif +#if CONFIG_IS_ENABLED(OF_PLATDATA) +#define gd_set_dm_driver_rt(dyn) gd->dm_driver_rt = dyn +#define gd_dm_driver_rt() gd->dm_driver_rt +#else +#define gd_set_dm_driver_rt(dyn) +#define gd_dm_driver_rt() NULL +#endif + /** * enum gd_flags - global data flags * diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 1dcc22f6891..c5d7ec0650f 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -81,7 +81,7 @@ int device_bind_with_driver_data(struct udevice *parent, * @return 0 if OK, -ve on error */ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, - struct driver_info *info, struct udevice **devp); + const struct driver_info *info, struct udevice **devp); /** * device_reparent: reparent the device to a new parent diff --git a/include/dm/platdata.h b/include/dm/platdata.h index 25479b03d22..2c3cc90c291 100644 --- a/include/dm/platdata.h +++ b/include/dm/platdata.h @@ -22,17 +22,27 @@ * @name: Driver name * @platdata: Driver-specific platform data * @platdata_size: Size of platform data structure - * @dev: Device created from this structure data */ struct driver_info { const char *name; const void *platdata; #if CONFIG_IS_ENABLED(OF_PLATDATA) uint platdata_size; - struct udevice *dev; #endif }; +/** + * driver_rt - runtime information set up by U-Boot + * + * There is one of these for every driver_info in the linker list, indexed by + * the driver_info idx value. + * + * @dev: Device created from this idx + */ +struct driver_rt { + struct udevice *dev; +}; + /** * NOTE: Avoid using these except in extreme circumstances, where device tree * is not feasible (e.g. serial driver in SPL where <8KB of SRAM is diff --git a/test/dm/of_platdata.c b/test/dm/of_platdata.c index 57f903611a6..e827d45ffb7 100644 --- a/test/dm/of_platdata.c +++ b/test/dm/of_platdata.c @@ -109,16 +109,16 @@ static int find_driver_info(struct unit_test_state *uts, struct udevice *parent, /* If not the root device, find the entry that caused it to be bound */ if (parent->parent) { - 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); - const struct driver_info *entry; int idx = -1; + int i; - for (entry = info; entry != info + n_ents; entry++) { - if (entry->dev == parent) { - idx = entry - info; + for (i = 0; i < n_ents; i++) { + const struct driver_rt *drt = gd_dm_driver_rt() + i; + + if (drt->dev == parent) { + idx = i; found[idx] = true; break; } @@ -153,16 +153,17 @@ static int dm_test_of_platdata_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(entry->dev); + ut_assertnonnull(drt->dev); ut_assertok(device_get_by_driver_info(entry, &dev)); - ut_asserteq_ptr(dev, entry->dev); + ut_asserteq_ptr(dev, drt->dev); } else { - ut_assertnull(entry->dev); + ut_assertnull(drt->dev); ut_asserteq(-ENOENT, device_get_by_driver_info(entry, &dev)); } -- cgit v1.3.1 From e41651fffda7da55f6d74afdf4b784088184c543 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 3 Oct 2020 11:31:35 -0600 Subject: dm: Support parent devices with of-platdata At present of-platdata does not provide parent information. But this is useful for I2C devices, for example, since it allows them to determine which bus they are on. Add support for setting the parent correctly, by storing the parent driver_info index in dtoc and reading this in lists_bind_drivers(). This needs multiple passes since we must process children after their parents already have been bound. Signed-off-by: Simon Glass --- drivers/core/lists.c | 54 ++++++++++++++++++++++++++++++++++++++++++++-- dts/Kconfig | 18 ++++++++++++++++ include/dm/platdata.h | 10 ++++++++- tools/dtoc/dtb_platdata.py | 4 ++++ tools/dtoc/test_dtoc.py | 33 ++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 2e6bd5006ce..b23ee3030e5 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -51,21 +51,48 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id) return NULL; } -int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) +static int bind_drivers_pass(struct udevice *parent, bool pre_reloc_only) { 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 missing_parent = false; int result = 0; uint idx; + /* + * Do one iteration through the driver_info records. For of-platdata, + * bind only devices whose parent is already bound. If we find any + * device we can't bind, set missing_parent to true, which will cause + * this function to be called again. + */ for (idx = 0; idx < n_ents; idx++) { + struct udevice *par = parent; const struct driver_info *entry = info + idx; struct driver_rt *drt = gd_dm_driver_rt() + idx; struct udevice *dev; int ret; - ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev); + if (CONFIG_IS_ENABLED(OF_PLATDATA)) { + int parent_idx = driver_info_parent_id(entry); + + if (drt->dev) + continue; + + if (CONFIG_IS_ENABLED(OF_PLATDATA_PARENT) && + parent_idx != -1) { + struct driver_rt *parent_drt; + + parent_drt = gd_dm_driver_rt() + parent_idx; + if (!parent_drt->dev) { + missing_parent = true; + continue; + } + + par = parent_drt->dev; + } + } + ret = device_bind_by_name(par, pre_reloc_only, entry, &dev); if (!ret) { if (CONFIG_IS_ENABLED(OF_PLATDATA)) drt->dev = dev; @@ -76,6 +103,29 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) } } + return result ? result : missing_parent ? -EAGAIN : 0; +} + +int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) +{ + int result = 0; + int pass; + + /* + * 10 passes is 10 levels deep in the devicetree, which is plenty. If + * OF_PLATDATA_PARENT is not enabled, then bind_drivers_pass() will + * always succeed on the first pass. + */ + for (pass = 0; pass < 10; pass++) { + int ret; + + ret = bind_drivers_pass(parent, pre_reloc_only); + if (!ret) + break; + if (ret != -EAGAIN && !result) + result = ret; + } + return result; } diff --git a/dts/Kconfig b/dts/Kconfig index 86ea8ce8875..aeda542f985 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -355,6 +355,15 @@ config SPL_OF_PLATDATA compatible string, then adding platform data and U_BOOT_DEVICE declarations for each node. See of-plat.txt for more information. +config SPL_OF_PLATDATA_PARENT + bool "Support parent information in devices" + depends on SPL_OF_PLATDATA + default y + help + Generally it is useful to be able to access the parent of a device + with of-platdata. To save space this can be disabled, but in that + case dev_get_parent() will always return NULL; + config TPL_OF_PLATDATA bool "Generate platform data for use in TPL" depends on TPL_OF_CONTROL @@ -376,4 +385,13 @@ config TPL_OF_PLATDATA compatible string, then adding platform data and U_BOOT_DEVICE declarations for each node. See of-plat.txt for more information. +config TPL_OF_PLATDATA_PARENT + bool "Support parent information in devices" + depends on TPL_OF_PLATDATA + default y + help + Generally it is useful to be able to access the parent of a device + with of-platdata. To save space this can be disabled, but in that + case dev_get_parent() will always return NULL; + endmenu diff --git a/include/dm/platdata.h b/include/dm/platdata.h index 2c3cc90c291..f800a866dda 100644 --- a/include/dm/platdata.h +++ b/include/dm/platdata.h @@ -22,15 +22,23 @@ * @name: Driver name * @platdata: Driver-specific platform data * @platdata_size: Size of platform data structure + * @parent_idx: Index of the parent driver_info structure */ struct driver_info { const char *name; const void *platdata; #if CONFIG_IS_ENABLED(OF_PLATDATA) - uint platdata_size; + unsigned short platdata_size; + short parent_idx; #endif }; +#if CONFIG_IS_ENABLED(OF_PLATDATA) +#define driver_info_parent_id(driver_info) driver_info->parent_idx +#else +#define driver_info_parent_id(driver_info) (-1) +#endif + /** * driver_rt - runtime information set up by U-Boot * diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index 31a9b3877ea..8832e6ebecb 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -662,6 +662,10 @@ class DtbPlatdata(object): self.buf('\t.name\t\t= "%s",\n' % struct_name) self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name)) + idx = -1 + if node.parent and node.parent in self._valid_nodes: + idx = node.parent.idx + self.buf('\t.parent_idx\t= %d,\n' % idx) self.buf('};\n') self.buf('\n') diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py index 8dcac91ee70..fee9853d034 100755 --- a/tools/dtoc/test_dtoc.py +++ b/tools/dtoc/test_dtoc.py @@ -216,6 +216,7 @@ U_BOOT_DEVICE(i2c_at_0) = { \t.name\t\t= "sandbox_i2c_test", \t.platdata\t= &dtv_i2c_at_0, \t.platdata_size\t= sizeof(dtv_i2c_at_0), +\t.parent_idx\t= -1, }; /* Node /i2c@0/pmic@9 index 1 */ @@ -227,6 +228,7 @@ U_BOOT_DEVICE(pmic_at_9) = { \t.name\t\t= "sandbox_pmic_test", \t.platdata\t= &dtv_pmic_at_9, \t.platdata_size\t= sizeof(dtv_pmic_at_9), +\t.parent_idx\t= 0, }; /* Node /spl-test index 2 */ @@ -246,6 +248,7 @@ U_BOOT_DEVICE(spl_test) = { \t.name\t\t= "sandbox_spl_test", \t.platdata\t= &dtv_spl_test, \t.platdata_size\t= sizeof(dtv_spl_test), +\t.parent_idx\t= -1, }; /* Node /spl-test2 index 3 */ @@ -264,6 +267,7 @@ U_BOOT_DEVICE(spl_test2) = { \t.name\t\t= "sandbox_spl_test", \t.platdata\t= &dtv_spl_test2, \t.platdata_size\t= sizeof(dtv_spl_test2), +\t.parent_idx\t= -1, }; /* Node /spl-test3 index 4 */ @@ -276,6 +280,7 @@ U_BOOT_DEVICE(spl_test3) = { \t.name\t\t= "sandbox_spl_test", \t.platdata\t= &dtv_spl_test3, \t.platdata_size\t= sizeof(dtv_spl_test3), +\t.parent_idx\t= -1, }; /* Node /spl-test4 index 5 */ @@ -285,6 +290,7 @@ U_BOOT_DEVICE(spl_test4) = { \t.name\t\t= "sandbox_spl_test_2", \t.platdata\t= &dtv_spl_test4, \t.platdata_size\t= sizeof(dtv_spl_test4), +\t.parent_idx\t= -1, }; ''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) @@ -318,6 +324,7 @@ U_BOOT_DEVICE(gpios_at_0) = { \t.name\t\t= "sandbox_gpio", \t.platdata\t= &dtv_gpios_at_0, \t.platdata_size\t= sizeof(dtv_gpios_at_0), +\t.parent_idx\t= -1, }; void dm_populate_phandle_data(void) { @@ -349,6 +356,7 @@ U_BOOT_DEVICE(spl_test) = { \t.name\t\t= "invalid", \t.platdata\t= &dtv_spl_test, \t.platdata_size\t= sizeof(dtv_spl_test), +\t.parent_idx\t= -1, }; void dm_populate_phandle_data(void) { @@ -383,6 +391,7 @@ U_BOOT_DEVICE(phandle2_target) = { \t.name\t\t= "target", \t.platdata\t= &dtv_phandle2_target, \t.platdata_size\t= sizeof(dtv_phandle2_target), +\t.parent_idx\t= -1, }; /* Node /phandle3-target index 1 */ @@ -393,6 +402,7 @@ U_BOOT_DEVICE(phandle3_target) = { \t.name\t\t= "target", \t.platdata\t= &dtv_phandle3_target, \t.platdata_size\t= sizeof(dtv_phandle3_target), +\t.parent_idx\t= -1, }; /* Node /phandle-target index 4 */ @@ -403,6 +413,7 @@ U_BOOT_DEVICE(phandle_target) = { \t.name\t\t= "target", \t.platdata\t= &dtv_phandle_target, \t.platdata_size\t= sizeof(dtv_phandle_target), +\t.parent_idx\t= -1, }; /* Node /phandle-source index 2 */ @@ -417,6 +428,7 @@ U_BOOT_DEVICE(phandle_source) = { \t.name\t\t= "source", \t.platdata\t= &dtv_phandle_source, \t.platdata_size\t= sizeof(dtv_phandle_source), +\t.parent_idx\t= -1, }; /* Node /phandle-source2 index 3 */ @@ -428,6 +440,7 @@ U_BOOT_DEVICE(phandle_source2) = { \t.name\t\t= "source", \t.platdata\t= &dtv_phandle_source2, \t.platdata_size\t= sizeof(dtv_phandle_source2), +\t.parent_idx\t= -1, }; void dm_populate_phandle_data(void) { @@ -470,6 +483,7 @@ U_BOOT_DEVICE(phandle_target) = { \t.name\t\t= "target", \t.platdata\t= &dtv_phandle_target, \t.platdata_size\t= sizeof(dtv_phandle_target), +\t.parent_idx\t= -1, }; /* Node /phandle-source2 index 0 */ @@ -481,6 +495,7 @@ U_BOOT_DEVICE(phandle_source2) = { \t.name\t\t= "source", \t.platdata\t= &dtv_phandle_source2, \t.platdata_size\t= sizeof(dtv_phandle_source2), +\t.parent_idx\t= -1, }; void dm_populate_phandle_data(void) { @@ -504,6 +519,7 @@ U_BOOT_DEVICE(phandle2_target) = { \t.name\t\t= "target", \t.platdata\t= &dtv_phandle2_target, \t.platdata_size\t= sizeof(dtv_phandle2_target), +\t.parent_idx\t= -1, }; /* Node /phandle3-target index 1 */ @@ -514,6 +530,7 @@ U_BOOT_DEVICE(phandle3_target) = { \t.name\t\t= "target", \t.platdata\t= &dtv_phandle3_target, \t.platdata_size\t= sizeof(dtv_phandle3_target), +\t.parent_idx\t= -1, }; /* Node /phandle-target index 4 */ @@ -524,6 +541,7 @@ U_BOOT_DEVICE(phandle_target) = { \t.name\t\t= "target", \t.platdata\t= &dtv_phandle_target, \t.platdata_size\t= sizeof(dtv_phandle_target), +\t.parent_idx\t= -1, }; /* Node /phandle-source index 2 */ @@ -538,6 +556,7 @@ U_BOOT_DEVICE(phandle_source) = { \t.name\t\t= "source", \t.platdata\t= &dtv_phandle_source, \t.platdata_size\t= sizeof(dtv_phandle_source), +\t.parent_idx\t= -1, }; /* Node /phandle-source2 index 3 */ @@ -549,6 +568,7 @@ U_BOOT_DEVICE(phandle_source2) = { \t.name\t\t= "source", \t.platdata\t= &dtv_phandle_source2, \t.platdata_size\t= sizeof(dtv_phandle_source2), +\t.parent_idx\t= -1, }; void dm_populate_phandle_data(void) { @@ -611,6 +631,7 @@ U_BOOT_DEVICE(test1) = { \t.name\t\t= "test1", \t.platdata\t= &dtv_test1, \t.platdata_size\t= sizeof(dtv_test1), +\t.parent_idx\t= -1, }; /* Node /test2 index 1 */ @@ -621,6 +642,7 @@ U_BOOT_DEVICE(test2) = { \t.name\t\t= "test2", \t.platdata\t= &dtv_test2, \t.platdata_size\t= sizeof(dtv_test2), +\t.parent_idx\t= -1, }; /* Node /test3 index 2 */ @@ -631,6 +653,7 @@ U_BOOT_DEVICE(test3) = { \t.name\t\t= "test3", \t.platdata\t= &dtv_test3, \t.platdata_size\t= sizeof(dtv_test3), +\t.parent_idx\t= -1, }; ''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) @@ -663,6 +686,7 @@ U_BOOT_DEVICE(test1) = { \t.name\t\t= "test1", \t.platdata\t= &dtv_test1, \t.platdata_size\t= sizeof(dtv_test1), +\t.parent_idx\t= -1, }; /* Node /test2 index 1 */ @@ -673,6 +697,7 @@ U_BOOT_DEVICE(test2) = { \t.name\t\t= "test2", \t.platdata\t= &dtv_test2, \t.platdata_size\t= sizeof(dtv_test2), +\t.parent_idx\t= -1, }; ''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) @@ -708,6 +733,7 @@ U_BOOT_DEVICE(test1) = { \t.name\t\t= "test1", \t.platdata\t= &dtv_test1, \t.platdata_size\t= sizeof(dtv_test1), +\t.parent_idx\t= -1, }; /* Node /test2 index 1 */ @@ -718,6 +744,7 @@ U_BOOT_DEVICE(test2) = { \t.name\t\t= "test2", \t.platdata\t= &dtv_test2, \t.platdata_size\t= sizeof(dtv_test2), +\t.parent_idx\t= -1, }; /* Node /test3 index 2 */ @@ -728,6 +755,7 @@ U_BOOT_DEVICE(test3) = { \t.name\t\t= "test3", \t.platdata\t= &dtv_test3, \t.platdata_size\t= sizeof(dtv_test3), +\t.parent_idx\t= -1, }; ''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) @@ -763,6 +791,7 @@ U_BOOT_DEVICE(test1) = { \t.name\t\t= "test1", \t.platdata\t= &dtv_test1, \t.platdata_size\t= sizeof(dtv_test1), +\t.parent_idx\t= -1, }; /* Node /test2 index 1 */ @@ -773,6 +802,7 @@ U_BOOT_DEVICE(test2) = { \t.name\t\t= "test2", \t.platdata\t= &dtv_test2, \t.platdata_size\t= sizeof(dtv_test2), +\t.parent_idx\t= -1, }; /* Node /test3 index 2 */ @@ -783,6 +813,7 @@ U_BOOT_DEVICE(test3) = { \t.name\t\t= "test3", \t.platdata\t= &dtv_test3, \t.platdata_size\t= sizeof(dtv_test3), +\t.parent_idx\t= -1, }; ''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) @@ -833,6 +864,7 @@ U_BOOT_DEVICE(spl_test) = { \t.name\t\t= "sandbox_spl_test", \t.platdata\t= &dtv_spl_test, \t.platdata_size\t= sizeof(dtv_spl_test), +\t.parent_idx\t= -1, }; /* Node /spl-test2 index 1 */ @@ -843,6 +875,7 @@ U_BOOT_DEVICE(spl_test2) = { \t.name\t\t= "sandbox_spl_test", \t.platdata\t= &dtv_spl_test2, \t.platdata_size\t= sizeof(dtv_spl_test2), +\t.parent_idx\t= -1, }; ''' + C_EMPTY_POPULATE_PHANDLE_DATA, data) -- cgit v1.3.1 From 8a38abfc43f94a92b63e428738714111710bda53 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 3 Oct 2020 11:31:40 -0600 Subject: dm: Use driver_info index instead of pointer At present we use a 'node' pointer in the of-platadata phandle_n_arg structs. This is a pointer to the struct driver_info for a particular device, and we can use it to obtain the struct udevice pointer itself. Since we don't know the struct udevice pointer until it is allocated in memory, we have to fix up the phandle_n_arg.node at runtime. This is annoying since it requires that SPL's data is writable and adds a small amount of extra (generated) code in the dm_populate_phandle_data() function. Now that we can find a driver_info by its index, it is easier to put the index in the phandle_n_arg structures. Update dtoc to do this, add a new device_get_by_driver_info_idx() to look up a device by drive_info index and update the tests to match. Signed-off-by: Simon Glass --- drivers/clk/clk-uclass.c | 3 +-- drivers/core/device.c | 11 +++++++++++ drivers/misc/irq-uclass.c | 2 +- drivers/mmc/fsl_esdhc_imx.c | 7 ++----- include/dm/device.h | 14 ++++++++++++++ include/dt-structs.h | 6 +++--- test/dm/of_platdata.c | 10 +++++----- test/dm/test-main.c | 24 ++++++++++++++++++++---- tools/dtoc/dtb_platdata.py | 20 ++++---------------- tools/dtoc/test_dtoc.py | 33 +++++++++++---------------------- 10 files changed, 72 insertions(+), 58 deletions(-) (limited to 'include') diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 31c5997aead..ac954a34d27 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -38,8 +38,7 @@ int clk_get_by_driver_info(struct udevice *dev, struct phandle_1_arg *cells, { int ret; - ret = device_get_by_driver_info((struct driver_info *)cells->node, - &clk->dev); + ret = device_get_by_driver_info_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 2e5767ed99b..4b3dcb3b379 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -772,6 +772,17 @@ int device_get_by_driver_info(const struct driver_info *info, 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; + struct udevice *dev; + + dev = drt->dev; + *devp = NULL; + + return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp); +} #endif int device_find_first_child(const struct udevice *parent, struct udevice **devp) diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c index 94fa233f193..24b27962a7d 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(cells->node, &irq->dev); + ret = device_get_by_driver_info_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 1c015ab7646..22040c67a84 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -1504,12 +1504,9 @@ static int fsl_esdhc_probe(struct udevice *dev) if (CONFIG_IS_ENABLED(DM_GPIO) && !priv->non_removable) { struct udevice *gpiodev; - struct driver_info *info; - - info = (struct driver_info *)dtplat->cd_gpios->node; - - ret = device_get_by_driver_info(info, &gpiodev); + ret = device_get_by_driver_info_idx(dtplat->cd_gpios->idx, + &gpiodev); if (ret) return ret; diff --git a/include/dm/device.h b/include/dm/device.h index 993c9e6c5ab..5bef4842470 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -553,6 +553,20 @@ int device_get_global_by_ofnode(ofnode node, struct udevice **devp); 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 + * + * 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. + * + * The device is probed to activate it ready for use. + * + * @idx: Index number of the driver_info 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); + /** * device_find_first_child() - Find the first child of a device * diff --git a/include/dt-structs.h b/include/dt-structs.h index eed8273d18e..f0e1c9cb901 100644 --- a/include/dt-structs.h +++ b/include/dt-structs.h @@ -11,17 +11,17 @@ struct driver_info; struct phandle_0_arg { - const struct driver_info *node; + uint idx; int arg[0]; }; struct phandle_1_arg { - const struct driver_info *node; + uint idx; int arg[1]; }; struct phandle_2_arg { - const struct driver_info *node; + uint idx; int arg[2]; }; #include diff --git a/test/dm/of_platdata.c b/test/dm/of_platdata.c index bad733fbee0..4f3cc159d03 100644 --- a/test/dm/of_platdata.c +++ b/test/dm/of_platdata.c @@ -183,22 +183,22 @@ static int dm_test_of_platdata_phandle(struct unit_test_state *uts) ut_asserteq_str("sandbox_clk_test", dev->name); plat = dev_get_platdata(dev); - ut_assertok(device_get_by_driver_info(plat->clocks[0].node, &clk)); + ut_assertok(device_get_by_driver_info_idx(plat->clocks[0].idx, &clk)); ut_asserteq_str("fixed_clock", clk->name); - ut_assertok(device_get_by_driver_info(plat->clocks[1].node, &clk)); + ut_assertok(device_get_by_driver_info_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(plat->clocks[2].node, &clk)); + ut_assertok(device_get_by_driver_info_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(plat->clocks[3].node, &clk)); + ut_assertok(device_get_by_driver_info_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(plat->clocks[4].node, &clk)); + ut_assertok(device_get_by_driver_info_idx(plat->clocks[4].idx, &clk)); ut_asserteq_str("sandbox_clk", clk->name); ut_asserteq(2, plat->clocks[4].arg[0]); diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 9d22df8c4dc..fd24635006c 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -127,6 +127,24 @@ static bool dm_test_run_on_flattree(struct unit_test *test) 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); @@ -152,6 +170,7 @@ int dm_test_main(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(); @@ -159,10 +178,7 @@ int dm_test_main(const char *test_name) const char *name = test->name; int runs; - /* All tests have this prefix */ - if (!strncmp(name, "dm_test_", 8)) - name += 8; - if (test_name && strcmp(test_name, name)) + if (!test_matches(name, test_name)) continue; /* Run with the live tree if possible */ diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index 8832e6ebecb..2be11fff6c2 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -154,8 +154,6 @@ class DtbPlatdata(object): key: Driver alias declared with U_BOOT_DRIVER_ALIAS(driver_alias, driver_name) value: Driver name declared with U_BOOT_DRIVER(driver_name) - _links: List of links to be included in dm_populate_phandle_data(), - each a PhandleLink _drivers_additional: List of additional drivers to use during scanning """ def __init__(self, dtb_fname, include_disabled, warning_disabled, @@ -169,7 +167,6 @@ class DtbPlatdata(object): self._lines = [] self._drivers = [] self._driver_aliases = {} - self._links = [] self._drivers_additional = drivers_additional def get_normalized_compat_name(self, node): @@ -612,17 +609,11 @@ class DtbPlatdata(object): name = conv_name_to_c(target_node.name) arg_values = [] for i in range(args): - arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i]))) + arg_values.append( + str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i]))) pos += 1 + args - # node member is filled with NULL as the real value - # will be update at run-time during dm_init_and_scan() - # by dm_populate_phandle_data() - vals.append('\t{NULL, {%s}}' % (', '.join(arg_values))) - var_node = '%s%s.%s[%d].node' % \ - (VAL_PREFIX, var_name, member_name, item) - # Save the the link information to be use to define - # dm_populate_phandle_data() - self._links.append(PhandleLink(var_node, name)) + vals.append('\t{%d, {%s}}' % (target_node.idx, + ', '.join(arg_values))) item += 1 for val in vals: self.buf('\n\t\t%s,' % val) @@ -703,9 +694,6 @@ class DtbPlatdata(object): # nodes using DM_GET_DEVICE # dtv_dmc_at_xxx.clocks[0].node = DM_GET_DEVICE(clock_controller_at_xxx) self.buf('void dm_populate_phandle_data(void) {\n') - for link in self._links: - self.buf('\t%s = DM_GET_DEVICE(%s);\n' % - (link.var_node, link.dev_name)) self.buf('}\n') self.out(''.join(self.get_buf())) diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py index fee9853d034..8e16dc0f0fa 100755 --- a/tools/dtoc/test_dtoc.py +++ b/tools/dtoc/test_dtoc.py @@ -419,10 +419,10 @@ U_BOOT_DEVICE(phandle_target) = { /* Node /phandle-source index 2 */ static struct dtd_source dtv_phandle_source = { \t.clocks\t\t\t= { -\t\t\t{NULL, {}}, -\t\t\t{NULL, {11}}, -\t\t\t{NULL, {12, 13}}, -\t\t\t{NULL, {}},}, +\t\t\t{4, {}}, +\t\t\t{0, {11}}, +\t\t\t{1, {12, 13}}, +\t\t\t{4, {}},}, }; U_BOOT_DEVICE(phandle_source) = { \t.name\t\t= "source", @@ -434,7 +434,7 @@ U_BOOT_DEVICE(phandle_source) = { /* Node /phandle-source2 index 3 */ static struct dtd_source dtv_phandle_source2 = { \t.clocks\t\t\t= { -\t\t\t{NULL, {}},}, +\t\t\t{4, {}},}, }; U_BOOT_DEVICE(phandle_source2) = { \t.name\t\t= "source", @@ -444,11 +444,6 @@ U_BOOT_DEVICE(phandle_source2) = { }; void dm_populate_phandle_data(void) { -\tdtv_phandle_source.clocks[0].node = DM_GET_DEVICE(phandle_target); -\tdtv_phandle_source.clocks[1].node = DM_GET_DEVICE(phandle2_target); -\tdtv_phandle_source.clocks[2].node = DM_GET_DEVICE(phandle3_target); -\tdtv_phandle_source.clocks[3].node = DM_GET_DEVICE(phandle_target); -\tdtv_phandle_source2.clocks[0].node = DM_GET_DEVICE(phandle_target); } ''', data) @@ -489,7 +484,7 @@ U_BOOT_DEVICE(phandle_target) = { /* Node /phandle-source2 index 0 */ static struct dtd_source dtv_phandle_source2 = { \t.clocks\t\t\t= { -\t\t\t{NULL, {}},}, +\t\t\t{1, {}},}, }; U_BOOT_DEVICE(phandle_source2) = { \t.name\t\t= "source", @@ -499,7 +494,6 @@ U_BOOT_DEVICE(phandle_source2) = { }; void dm_populate_phandle_data(void) { -\tdtv_phandle_source2.clocks[0].node = DM_GET_DEVICE(phandle_target); } ''', data) @@ -547,10 +541,10 @@ U_BOOT_DEVICE(phandle_target) = { /* Node /phandle-source index 2 */ static struct dtd_source dtv_phandle_source = { \t.cd_gpios\t\t= { -\t\t\t{NULL, {}}, -\t\t\t{NULL, {11}}, -\t\t\t{NULL, {12, 13}}, -\t\t\t{NULL, {}},}, +\t\t\t{4, {}}, +\t\t\t{0, {11}}, +\t\t\t{1, {12, 13}}, +\t\t\t{4, {}},}, }; U_BOOT_DEVICE(phandle_source) = { \t.name\t\t= "source", @@ -562,7 +556,7 @@ U_BOOT_DEVICE(phandle_source) = { /* Node /phandle-source2 index 3 */ static struct dtd_source dtv_phandle_source2 = { \t.cd_gpios\t\t= { -\t\t\t{NULL, {}},}, +\t\t\t{4, {}},}, }; U_BOOT_DEVICE(phandle_source2) = { \t.name\t\t= "source", @@ -572,11 +566,6 @@ U_BOOT_DEVICE(phandle_source2) = { }; void dm_populate_phandle_data(void) { -\tdtv_phandle_source.cd_gpios[0].node = DM_GET_DEVICE(phandle_target); -\tdtv_phandle_source.cd_gpios[1].node = DM_GET_DEVICE(phandle2_target); -\tdtv_phandle_source.cd_gpios[2].node = DM_GET_DEVICE(phandle3_target); -\tdtv_phandle_source.cd_gpios[3].node = DM_GET_DEVICE(phandle_target); -\tdtv_phandle_source2.cd_gpios[0].node = DM_GET_DEVICE(phandle_target); } ''', data) -- cgit v1.3.1 From cb43ac184f71f0ba696d0effcd39a746a6f3a456 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 3 Oct 2020 11:31:41 -0600 Subject: dm: Don't allow U_BOOT_DEVICE() when of-platdata is used With of-platdata, the devicetree is supposed to specify all the devices in the system. So far this hasn't really mattered since of-platdata still works correctly. However, new of-platdata features rely on numbering the devices in a particular order so that they can be referenced by a single integer. It is tricky to implement this efficiently when other devices are present in the build. To address this, disable use of U_BOOT_DEVICE() when of-platdata is enabled. This seems acceptable as it is not supposed to be used at all, except in SPL/TPL, where of-platdata is the recommended approach. This breaks one non-compliant boards at present: mx6cuboxi Signed-off-by: Simon Glass (disable CONFIG_IMX_THERMAL for mx6cuboxi to avoid a build error) --- include/dm/platdata.h | 8 ++++++++ tools/dtoc/dtb_platdata.py | 3 +++ tools/dtoc/test_dtoc.py | 3 +++ 3 files changed, 14 insertions(+) (limited to 'include') diff --git a/include/dm/platdata.h b/include/dm/platdata.h index f800a866dda..216efa8ef77 100644 --- a/include/dm/platdata.h +++ b/include/dm/platdata.h @@ -55,9 +55,17 @@ struct driver_rt { * NOTE: Avoid using these except in extreme circumstances, where device tree * is not feasible (e.g. serial driver in SPL where <8KB of SRAM is * available). U-Boot's driver model uses device tree for configuration. + * + * When of-platdata is in use, U_BOOT_DEVICE() cannot be used outside of the + * dt-platdata.c file created by dtoc */ +#if CONFIG_IS_ENABLED(OF_PLATDATA) && !defined(DT_PLATDATA_C) +#define U_BOOT_DEVICE(__name) _Static_assert(false, \ + "Cannot use U_BOOT_DEVICE with of-platdata. Please use devicetree instead") +#else #define U_BOOT_DEVICE(__name) \ ll_entry_declare(struct driver_info, __name, driver_info) +#endif /* Declare a list of devices. The argument is a driver_info[] array */ #define U_BOOT_DEVICES(__name) \ diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index 2be11fff6c2..9b27aecc140 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -673,6 +673,9 @@ class DtbPlatdata(object): information. """ self.out_header() + self.out('/* Allow use of U_BOOT_DEVICE() in this file */\n') + self.out('#define DT_PLATDATA_C\n') + self.out('\n') self.out('#include \n') self.out('#include \n') self.out('#include \n') diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py index 8e16dc0f0fa..a5836e04b7a 100755 --- a/tools/dtoc/test_dtoc.py +++ b/tools/dtoc/test_dtoc.py @@ -44,6 +44,9 @@ C_HEADER = '''/* * This file was generated by dtoc from a .dtb (device tree binary) file. */ +/* Allow use of U_BOOT_DEVICE() in this file */ +#define DT_PLATDATA_C + #include #include #include -- cgit v1.3.1