summaryrefslogtreecommitdiff
path: root/drivers/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/core')
-rw-r--r--drivers/core/Kconfig50
-rw-r--r--drivers/core/device.c12
-rw-r--r--drivers/core/root.c64
3 files changed, 124 insertions, 2 deletions
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index d2799dc..f0d6110 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -2,5 +2,51 @@ config DM
bool "Enable Driver Model"
depends on !SPL_BUILD
help
- This config option enables Driver Model.
- To use legacy drivers, say N.
+ This config option enables Driver Model. This brings in the core
+ support, including scanning of platform data on start-up. If
+ CONFIG_OF_CONTROL is enabled, the device tree will be scanned also
+ when available.
+
+config SPL_DM
+ bool "Enable Driver Model for SPL"
+ depends on DM && SPL
+ help
+ Enable driver model in SPL. You will need to provide a
+ suitable malloc() implementation. If you are not using the
+ full malloc() enabled by CONFIG_SYS_SPL_MALLOC_START,
+ consider using CONFIG_SYS_MALLOC_SIMPLE. In that case you
+ must provide CONFIG_SYS_MALLOC_F_LEN to set the size.
+ In most cases driver model will only allocate a few uclasses
+ and devices in SPL, so 1KB should be enable. See
+ CONFIG_SYS_MALLOC_F_LEN for more details on how to enable it.
+
+config DM_WARN
+ bool "Enable warnings in driver model"
+ help
+ 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.
+ depends on DM
+ default y if !SPL_BUILD
+ default n if SPL_BUILD
+
+config DM_DEVICE_REMOVE
+ bool "Support device removal"
+ help
+ We can save some code space by dropping support for removing a
+ device. This is not normally required in SPL, so by default this
+ option is disabled for SPL.
+ depends on DM
+ default y if !SPL_BUILD
+ default n if SPL_BUILD
+
+config DM_STDIO
+ bool "Support stdio registration"
+ help
+ Normally serial drivers register with stdio so that they can be used
+ as normal output devices. In SPL we don't normally use stdio, so
+ we can omit this feature.
+ depends on DM
+ default y if !SPL_BUILD
+ default n if SPL_BUILD
diff --git a/drivers/core/device.c b/drivers/core/device.c
index b73d3b8..73c3e07 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -449,3 +449,15 @@ enum uclass_id device_get_uclass_id(struct udevice *dev)
{
return dev->uclass->uc_drv->id;
}
+
+#ifdef CONFIG_OF_CONTROL
+fdt_addr_t dev_get_addr(struct udevice *dev)
+{
+ return fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+}
+#else
+fdt_addr_t dev_get_addr(struct udevice *dev)
+{
+ return FDT_ADDR_T_NONE;
+}
+#endif
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 73e3c72..9b5c6bb 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -37,6 +37,65 @@ struct udevice *dm_root(void)
return gd->dm_root;
}
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+void fix_drivers(void)
+{
+ struct driver *drv =
+ ll_entry_start(struct driver, driver);
+ const int n_ents = ll_entry_count(struct driver, driver);
+ struct driver *entry;
+
+ 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);
+ if (entry->bind)
+ entry->bind += gd->reloc_off;
+ if (entry->probe)
+ entry->probe += gd->reloc_off;
+ if (entry->remove)
+ entry->remove += gd->reloc_off;
+ if (entry->unbind)
+ entry->unbind += gd->reloc_off;
+ if (entry->ofdata_to_platdata)
+ entry->ofdata_to_platdata += gd->reloc_off;
+ if (entry->child_pre_probe)
+ entry->child_pre_probe += gd->reloc_off;
+ if (entry->child_post_remove)
+ entry->child_post_remove += gd->reloc_off;
+ /* OPS are fixed in every uclass post_probe function */
+ if (entry->ops)
+ entry->ops += gd->reloc_off;
+ }
+}
+
+void fix_uclass(void)
+{
+ struct uclass_driver *uclass =
+ ll_entry_start(struct uclass_driver, uclass);
+ const int n_ents = ll_entry_count(struct uclass_driver, uclass);
+ struct uclass_driver *entry;
+
+ for (entry = uclass; entry != uclass + n_ents; entry++) {
+ if (entry->post_bind)
+ entry->post_bind += gd->reloc_off;
+ if (entry->pre_unbind)
+ entry->pre_unbind += gd->reloc_off;
+ if (entry->post_probe)
+ entry->post_probe += gd->reloc_off;
+ if (entry->pre_remove)
+ entry->pre_remove += gd->reloc_off;
+ if (entry->init)
+ entry->init += gd->reloc_off;
+ if (entry->destroy)
+ entry->destroy += gd->reloc_off;
+ /* FIXME maybe also need to fix these ops */
+ if (entry->ops)
+ entry->ops += gd->reloc_off;
+ }
+}
+#endif
+
int dm_init(void)
{
int ret;
@@ -47,6 +106,11 @@ int dm_init(void)
}
INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ fix_drivers();
+ fix_uclass();
+#endif
+
ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
if (ret)
return ret;