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 <sjg@chromium.org>
This commit is contained in:
Simon Glass 2020-10-03 11:31:35 -06:00
parent 67507e4aab
commit e41651fffd
5 changed files with 116 additions and 3 deletions

View 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;
}

View 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

View file

@ -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
*

View 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')

View file

@ -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)