[PATCH 13/20] dm: Support parent devices with of-platdata

Simon Glass sjg at chromium.org
Sat Oct 3 19:31:35 CEST 2020


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 <sjg at chromium.org>
---

 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 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 046a54a1736..616f8484280 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,6 +385,15 @@ 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
 
 config MKIMAGE_DTC_PATH
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 at 0/pmic at 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)
-- 
2.28.0.806.g8561365e88-goog



More information about the U-Boot mailing list