]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
dm: Support parent devices with of-platdata
authorSimon Glass <sjg@chromium.org>
Sat, 3 Oct 2020 17:31:35 +0000 (11:31 -0600)
committerSimon Glass <sjg@chromium.org>
Thu, 29 Oct 2020 20:42:18 +0000 (14:42 -0600)
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@chromium.org>
drivers/core/lists.c
dts/Kconfig
include/dm/platdata.h
tools/dtoc/dtb_platdata.py
tools/dtoc/test_dtoc.py

index 2e6bd5006ce585355cd75d7a29dfb3a5a8c658c1..b23ee3030e5861e90e88008eae96c68374cd4d90 100644 (file)
@@ -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;
 }
 
index 86ea8ce887514bf9a2e8e4b18d9a4f4dc508f152..aeda542f985707a0cfef7fbfa29f2f738122e92f 100644 (file)
@@ -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
index 2c3cc90c29137a4ff28ff8c0f2380056f918792d..f800a866ddab8ac6baf4d69a134141f1edb0d94e 100644 (file)
  * @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
  *
index 31a9b3877ea1f119c119cebb097a7e24f9f3d5a6..8832e6ebecbf1b7618846f3a6e0b02aed8fe96a1 100644 (file)
@@ -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')
 
index 8dcac91ee703ad7ef632cbecf60f3a3e49bbbfc0..fee9853d03429e04d5433d2d269c5a821244f20e 100755 (executable)
@@ -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)