summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Simek <michal.simek@xilinx.com>2015-02-02 16:31:59 +0100
committerSimon Glass <sjg@chromium.org>2015-02-12 15:17:29 -0700
commit484fdf5ba058b07be5ca82763aa2b72063540ef3 (patch)
tree65f5743792dddb46f25e0d8440661197fcabdbc2
parent99c0ae16d8b2ebfb7381ba77d4e37e7bda734402 (diff)
downloadu-boot-imx-484fdf5ba058b07be5ca82763aa2b72063540ef3.zip
u-boot-imx-484fdf5ba058b07be5ca82763aa2b72063540ef3.tar.gz
u-boot-imx-484fdf5ba058b07be5ca82763aa2b72063540ef3.tar.bz2
dm: Add support for all targets which requires MANUAL_RELOC
Targets with CONFIG_NEEDS_MANUAL_RELOC do not use REL/RELA relocation (mostly only GOT) where functions aray are not updated. This patch is fixing function pointers for DM core and serial-uclass to ensure that relocated functions are called. Signed-off-by: Michal Simek <michal.simek@xilinx.com> Acked-by: Simon Glass <sjg@chromium.org>
-rw-r--r--drivers/core/root.c64
-rw-r--r--drivers/serial/serial-uclass.c16
2 files changed, 80 insertions, 0 deletions
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;
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 9131a8f..3fc7104 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -258,6 +258,22 @@ static int serial_post_probe(struct udevice *dev)
#endif
int ret;
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ if (ops->setbrg)
+ ops->setbrg += gd->reloc_off;
+ if (ops->getc)
+ ops->getc += gd->reloc_off;
+ if (ops->putc)
+ ops->putc += gd->reloc_off;
+ if (ops->pending)
+ ops->pending += gd->reloc_off;
+ if (ops->clear)
+ ops->clear += gd->reloc_off;
+#if CONFIG_POST & CONFIG_SYS_POST_UART
+ if (ops->loop)
+ ops->loop += gd->reloc_off
+#endif
+#endif
/* Set the baud rate */
if (ops->setbrg) {
ret = ops->setbrg(dev, gd->baudrate);