From e41651fffda7da55f6d74afdf4b784088184c543 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 3 Oct 2020 11:31:35 -0600 Subject: [PATCH] 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(-) diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 2e6bd5006c..b23ee3030e 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 86ea8ce887..aeda542f98 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 2c3cc90c29..f800a866dd 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 31a9b3877e..8832e6ebec 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 8dcac91ee7..fee9853d03 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)