From ab7cd62790c4f7831b91eab8a2ec81742d01bb54 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Wed, 23 Jul 2014 06:55:04 -0600
Subject: [PATCH] dm: Support driver model prior to relocation

Initialise devices marked 'pre-reloc' and make them available prior to
relocation. Note that this requires pre-reloc malloc() to be available.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 common/board_f.c                  | 16 ++++++++++++++++
 common/board_r.c                  | 25 ++++---------------------
 drivers/core/root.c               | 25 +++++++++++++++++++++++++
 include/asm-generic/global_data.h |  3 ++-
 include/dm/root.h                 | 13 +++++++++++++
 5 files changed, 60 insertions(+), 22 deletions(-)

diff --git a/common/board_f.c b/common/board_f.c
index 6b2e277bd7..6203d85619 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -14,6 +14,7 @@
 #include <linux/compiler.h>
 #include <version.h>
 #include <environment.h>
+#include <dm.h>
 #include <fdtdec.h>
 #include <fs.h>
 #if defined(CONFIG_CMD_IDE)
@@ -53,6 +54,7 @@
 #ifdef CONFIG_SANDBOX
 #include <asm/state.h>
 #endif
+#include <dm/root.h>
 #include <linux/compiler.h>
 
 /*
@@ -778,6 +780,19 @@ static int initf_malloc(void)
 	return 0;
 }
 
+static int initf_dm(void)
+{
+#if defined(CONFIG_DM) && defined(CONFIG_SYS_MALLOC_F_LEN)
+	int ret;
+
+	ret = dm_init_and_scan(true);
+	if (ret)
+		return ret;
+#endif
+
+	return 0;
+}
+
 static init_fnc_t init_sequence_f[] = {
 #ifdef CONFIG_SANDBOX
 	setup_ram_buf,
@@ -836,6 +851,7 @@ static init_fnc_t init_sequence_f[] = {
 	init_timebase,
 #endif
 	initf_malloc,
+	initf_dm,
 	init_baud_rate,		/* initialze baudrate settings */
 	serial_init,		/* serial communications setup */
 	console_init_f,		/* stage 1 init of console */
diff --git a/common/board_r.c b/common/board_r.c
index fbabc898d8..8e7a3ac74c 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -273,27 +273,10 @@ static int initr_malloc(void)
 #ifdef CONFIG_DM
 static int initr_dm(void)
 {
-	int ret;
-
-	ret = dm_init();
-	if (ret) {
-		debug("dm_init() failed: %d\n", ret);
-		return ret;
-	}
-	ret = dm_scan_platdata(false);
-	if (ret) {
-		debug("dm_scan_platdata() failed: %d\n", ret);
-		return ret;
-	}
-#ifdef CONFIG_OF_CONTROL
-	ret = dm_scan_fdt(gd->fdt_blob, false);
-	if (ret) {
-		debug("dm_scan_fdt() failed: %d\n", ret);
-		return ret;
-	}
-#endif
-
-	return 0;
+	/* Save the pre-reloc driver model and start a new one */
+	gd->dm_root_f = gd->dm_root;
+	gd->dm_root = NULL;
+	return dm_init_and_scan(false);
 }
 #endif
 
diff --git a/drivers/core/root.c b/drivers/core/root.c
index ce4eef3054..60597563d6 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -105,6 +105,31 @@ int dm_scan_fdt(const void *blob, bool pre_reloc_only)
 }
 #endif
 
+int dm_init_and_scan(bool pre_reloc_only)
+{
+	int ret;
+
+	ret = dm_init();
+	if (ret) {
+		debug("dm_init() failed: %d\n", ret);
+		return ret;
+	}
+	ret = dm_scan_platdata(pre_reloc_only);
+	if (ret) {
+		debug("dm_scan_platdata() failed: %d\n", ret);
+		return ret;
+	}
+#ifdef CONFIG_OF_CONTROL
+	ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
+	if (ret) {
+		debug("dm_scan_fdt() failed: %d\n", ret);
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
 /* This is the root driver - all drivers are children of this */
 U_BOOT_DRIVER(root_driver) = {
 	.name	= "root_driver",
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index f6a2a2068a..edde9d7dd0 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -65,7 +65,8 @@ typedef struct global_data {
 	struct global_data *new_gd;	/* relocated global data */
 
 #ifdef CONFIG_DM
-	struct udevice	*dm_root;/* Root instance for Driver Model */
+	struct udevice	*dm_root;	/* Root instance for Driver Model */
+	struct udevice	*dm_root_f;	/* Pre-relocation root instance */
 	struct list_head uclass_root;	/* Head of core tree */
 #endif
 
diff --git a/include/dm/root.h b/include/dm/root.h
index d37b452eef..09f9303774 100644
--- a/include/dm/root.h
+++ b/include/dm/root.h
@@ -44,6 +44,19 @@ int dm_scan_platdata(bool pre_reloc_only);
  */
 int dm_scan_fdt(const void *blob, bool pre_reloc_only);
 
+/**
+ * dm_init_and_scan() - Initialise Driver Model structures and scan for devices
+ *
+ * This function initialises the roots of the driver tree and uclass trees,
+ * then scans and binds available devices from platform data and the FDT.
+ * This calls dm_init() to set up Driver Model structures.
+ *
+ * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
+ * flag. If false bind all drivers.
+ * @return 0 if OK, -ve on error
+ */
+int dm_init_and_scan(bool pre_reloc_only);
+
 /**
  * dm_init() - Initialise Driver Model structures
  *
-- 
2.39.5