diff options
Diffstat (limited to 'drivers/core')
-rw-r--r-- | drivers/core/Kconfig | 18 | ||||
-rw-r--r-- | drivers/core/Makefile | 2 | ||||
-rw-r--r-- | drivers/core/device.c | 23 | ||||
-rw-r--r-- | drivers/core/lists.c | 70 | ||||
-rw-r--r-- | drivers/core/root.c | 56 | ||||
-rw-r--r-- | drivers/core/util.c | 2 |
6 files changed, 126 insertions, 45 deletions
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 07d3a6a7a4..ffae6f9795 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -40,10 +40,24 @@ config DM_WARN depends on DM default y help + Enable this to see warnings related to driver model. + + Warnings may help with debugging, such as when expected devices do + not bind correctly. If the option is disabled, dm_warn() is compiled + out - it will do nothing when called. + +config SPL_DM_WARN + bool "Enable warnings in driver model wuth SPL" + depends on SPL_DM + help + Enable this to see warnings related to driver model in SPL + The dm_warn() function can use up quite a bit of space for its strings. By default this is disabled for SPL builds to save space. - This will cause dm_warn() to be compiled out - it will do nothing - when called. + + Warnings may help with debugging, such as when expected devices do + not bind correctly. If the option is disabled, dm_warn() is compiled + out - it will do nothing when called. config DM_DEBUG bool "Enable debug messages in driver model core" diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 10f4bece33..5edd4e4135 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_DM) += dump.o obj-$(CONFIG_$(SPL_TPL_)REGMAP) += regmap.o obj-$(CONFIG_$(SPL_TPL_)SYSCON) += syscon-uclass.o -obj-$(CONFIG_OF_LIVE) += of_access.o of_addr.o +obj-$(CONFIG_$(SPL_)OF_LIVE) += of_access.o of_addr.o ifndef CONFIG_DM_DEV_READ_INLINE obj-$(CONFIG_OF_CONTROL) += read.o endif diff --git a/drivers/core/device.c b/drivers/core/device.c index e90d70101c..4b3dcb3b37 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -249,7 +249,7 @@ int device_bind_ofnode(struct udevice *parent, const struct driver *drv, } int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, - struct driver_info *info, struct udevice **devp) + const struct driver_info *info, struct udevice **devp) { struct driver *drv; uint platdata_size = 0; @@ -269,9 +269,6 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, platdata_size, devp); if (ret) return ret; -#if CONFIG_IS_ENABLED(OF_PLATDATA) - info->dev = *devp; -#endif return ret; } @@ -764,9 +761,25 @@ int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp) int device_get_by_driver_info(const struct driver_info *info, struct udevice **devp) { + struct driver_info *info_base = + ll_entry_start(struct driver_info, driver_info); + int idx = info - info_base; + struct driver_rt *drt = gd_dm_driver_rt() + idx; struct udevice *dev; - dev = info->dev; + dev = drt->dev; + *devp = NULL; + + return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp); +} + +int device_get_by_driver_info_idx(uint idx, struct udevice **devp) +{ + struct driver_rt *drt = gd_dm_driver_rt() + idx; + struct udevice *dev; + + dev = drt->dev; + *devp = NULL; return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp); } diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 5beba9181c..b23ee3030e 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -51,25 +51,81 @@ 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); - struct driver_info *entry; - struct udevice *dev; + bool missing_parent = false; int result = 0; - int ret; + 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; - for (entry = info; entry != info + n_ents; entry++) { - ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev); - if (ret && ret != -EPERM) { + 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; + } else if (ret != -EPERM) { dm_warn("No match for driver '%s'\n", entry->name); if (!result || ret != -ENOENT) result = ret; } } + 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/drivers/core/root.c b/drivers/core/root.c index 0726be6b79..5f10d7a39c 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -50,7 +50,6 @@ void dm_fixup_for_gd_move(struct global_data *new_gd) } } -#if defined(CONFIG_NEEDS_MANUAL_RELOC) void fix_drivers(void) { struct driver *drv = @@ -61,7 +60,7 @@ void fix_drivers(void) for (entry = drv; entry != drv + n_ents; entry++) { if (entry->of_match) entry->of_match = (const struct udevice_id *) - ((u32)entry->of_match + gd->reloc_off); + ((ulong)entry->of_match + gd->reloc_off); if (entry->bind) entry->bind += gd->reloc_off; if (entry->probe) @@ -129,8 +128,6 @@ void fix_devices(void) } } -#endif - int dm_init(bool of_live) { int ret; @@ -141,21 +138,19 @@ int dm_init(bool of_live) } INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST); -#if defined(CONFIG_NEEDS_MANUAL_RELOC) - fix_drivers(); - fix_uclass(); - fix_devices(); -#endif + if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) { + fix_drivers(); + fix_uclass(); + fix_devices(); + } ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST); if (ret) return ret; #if CONFIG_IS_ENABLED(OF_CONTROL) -# if CONFIG_IS_ENABLED(OF_LIVE) - if (of_live) - DM_ROOT_NON_CONST->node = np_to_ofnode(gd->of_root); + if (CONFIG_IS_ENABLED(OF_LIVE) && of_live) + DM_ROOT_NON_CONST->node = np_to_ofnode(gd_of_root()); else -#endif DM_ROOT_NON_CONST->node = offset_to_ofnode(0); #endif ret = device_probe(DM_ROOT_NON_CONST); @@ -187,6 +182,17 @@ int dm_scan_platdata(bool pre_reloc_only) { int ret; + if (CONFIG_IS_ENABLED(OF_PLATDATA)) { + struct driver_rt *dyn; + int n_ents; + + n_ents = ll_entry_count(struct driver_info, driver_info); + dyn = calloc(n_ents, sizeof(struct driver_rt)); + if (!dyn) + return -ENOMEM; + gd_set_dm_driver_rt(dyn); + } + ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only); if (ret == -ENOENT) { dm_warn("Some drivers were not found\n"); @@ -196,7 +202,7 @@ int dm_scan_platdata(bool pre_reloc_only) return ret; } -#if CONFIG_IS_ENABLED(OF_LIVE) +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) static int dm_scan_fdt_live(struct udevice *parent, const struct device_node *node_parent, bool pre_reloc_only) @@ -223,9 +229,7 @@ static int dm_scan_fdt_live(struct udevice *parent, return ret; } -#endif /* CONFIG_IS_ENABLED(OF_LIVE) */ -#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) /** * dm_scan_fdt_node() - Scan the device tree and bind drivers for a node * @@ -272,24 +276,20 @@ int dm_scan_fdt_dev(struct udevice *dev) if (!dev_of_valid(dev)) return 0; -#if CONFIG_IS_ENABLED(OF_LIVE) if (of_live_active()) return dm_scan_fdt_live(dev, dev_np(dev), gd->flags & GD_FLG_RELOC ? false : true); - else -#endif + return dm_scan_fdt_node(dev, gd->fdt_blob, dev_of_offset(dev), gd->flags & GD_FLG_RELOC ? false : true); } int dm_scan_fdt(const void *blob, bool pre_reloc_only) { -#if CONFIG_IS_ENABLED(OF_LIVE) if (of_live_active()) - return dm_scan_fdt_live(gd->dm_root, gd->of_root, + return dm_scan_fdt_live(gd->dm_root, gd_of_root(), pre_reloc_only); - else -#endif + return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only); } @@ -302,10 +302,9 @@ static int dm_scan_fdt_ofnode_path(const void *blob, const char *path, if (!ofnode_valid(node)) return 0; -#if CONFIG_IS_ENABLED(OF_LIVE) if (of_live_active()) return dm_scan_fdt_live(gd->dm_root, node.np, pre_reloc_only); -#endif + return dm_scan_fdt_node(gd->dm_root, blob, node.of_offset, pre_reloc_only); } @@ -348,11 +347,10 @@ int dm_init_and_scan(bool pre_reloc_only) { int ret; -#if CONFIG_IS_ENABLED(OF_PLATDATA) - dm_populate_phandle_data(); -#endif + if (CONFIG_IS_ENABLED(OF_PLATDATA)) + dm_populate_phandle_data(); - ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE)); + ret = dm_init(CONFIG_IS_ENABLED(OF_LIVE)); if (ret) { debug("dm_init() failed: %d\n", ret); return ret; diff --git a/drivers/core/util.c b/drivers/core/util.c index 25b0d76f43..91e93b0cf1 100644 --- a/drivers/core/util.c +++ b/drivers/core/util.c @@ -11,7 +11,7 @@ #include <linux/libfdt.h> #include <vsprintf.h> -#ifdef CONFIG_DM_WARN +#if CONFIG_IS_ENABLED(DM_WARN) void dm_warn(const char *fmt, ...) { va_list args; |