summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/core/lists.c54
-rw-r--r--dts/Kconfig18
-rw-r--r--include/dm/platdata.h10
-rw-r--r--tools/dtoc/dtb_platdata.py4
-rwxr-xr-xtools/dtoc/test_dtoc.py33
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)