summaryrefslogtreecommitdiff
path: root/drivers/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/core')
-rw-r--r--drivers/core/Kconfig18
-rw-r--r--drivers/core/Makefile2
-rw-r--r--drivers/core/device.c23
-rw-r--r--drivers/core/lists.c70
-rw-r--r--drivers/core/root.c56
-rw-r--r--drivers/core/util.c2
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;