diff options
Diffstat (limited to 'drivers/core')
-rw-r--r-- | drivers/core/Kconfig | 50 | ||||
-rw-r--r-- | drivers/core/device.c | 12 | ||||
-rw-r--r-- | drivers/core/root.c | 64 |
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; |