omap4/5: Add support for booting with CH.

Configuration header(CH) is 512 byte header attached to an OMAP
boot image that will help ROM code to initialize clocks, SDRAM
etc and copy U-Boot directly into SDRAM. CH can help us in
by-passing SPL and directly boot U-boot, hence it's an alternative
for SPL. However, we intend to support both CH and SPL for OMAP4/5.

Initialization done through CH is limited and is not equivalent
to that done by SPL. So U-Boot has to distinguish between the
two cases and handle them accordingly. This patch takes care
of doing this.

Signed-off-by: sricharan <r.sricharan@ti.com>
Signed-off-by: Sandeep Paulraj <s-paulraj@ti.com>
diff --git a/arch/arm/cpu/armv7/omap-common/clocks-common.c b/arch/arm/cpu/armv7/omap-common/clocks-common.c
index c726093..f64a10b 100644
--- a/arch/arm/cpu/armv7/omap-common/clocks-common.c
+++ b/arch/arm/cpu/armv7/omap-common/clocks-common.c
@@ -115,17 +115,46 @@
 	}
 }
 
-static void do_setup_dpll(u32 *const base, const struct dpll_params *params,
-				u8 lock)
+inline u32 check_for_lock(u32 *const base)
 {
-	u32 temp;
 	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base;
+	u32 lock = readl(&dpll_regs->cm_idlest_dpll) & ST_DPLL_CLK_MASK;
+
+	return lock;
+}
+
+static void do_setup_dpll(u32 *const base, const struct dpll_params *params,
+				u8 lock, char *dpll)
+{
+	u32 temp, M, N;
+	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base;
+
+	temp = readl(&dpll_regs->cm_clksel_dpll);
+
+	if (check_for_lock(base)) {
+		/*
+		 * The Dpll has already been locked by rom code using CH.
+		 * Check if M,N are matching with Ideal nominal opp values.
+		 * If matches, skip the rest otherwise relock.
+		 */
+		M = (temp & CM_CLKSEL_DPLL_M_MASK) >> CM_CLKSEL_DPLL_M_SHIFT;
+		N = (temp & CM_CLKSEL_DPLL_N_MASK) >> CM_CLKSEL_DPLL_N_SHIFT;
+		if ((M != (params->m)) || (N != (params->n))) {
+			debug("\n %s Dpll locked, but not for ideal M = %d,"
+				"N = %d values, current values are M = %d,"
+				"N= %d" , dpll, params->m, params->n,
+				M, N);
+		} else {
+			/* Dpll locked with ideal values for nominal opps. */
+			debug("\n %s Dpll already locked with ideal"
+						"nominal opp values", dpll);
+			goto setup_post_dividers;
+		}
+	}
 
 	bypass_dpll(base);
 
 	/* Set M & N */
-	temp = readl(&dpll_regs->cm_clksel_dpll);
-
 	temp &= ~CM_CLKSEL_DPLL_M_MASK;
 	temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK;
 
@@ -138,6 +167,7 @@
 	if (lock)
 		do_lock_dpll(base);
 
+setup_post_dividers:
 	setup_post_dividers(base, params);
 
 	/* Wait till the DPLL locks */
@@ -216,7 +246,8 @@
 	}
 
 	params = get_mpu_dpll_params();
-	do_setup_dpll(&prcm->cm_clkmode_dpll_mpu, params, DPLL_LOCK);
+
+	do_setup_dpll(&prcm->cm_clkmode_dpll_mpu, params, DPLL_LOCK, "mpu");
 	debug("MPU DPLL locked\n");
 }
 
@@ -235,7 +266,8 @@
 	 * Core DPLL will be locked after setting up EMIF
 	 * using the FREQ_UPDATE method(freq_update_core())
 	 */
-	do_setup_dpll(&prcm->cm_clkmode_dpll_core, params, DPLL_NO_LOCK);
+	do_setup_dpll(&prcm->cm_clkmode_dpll_core, params, DPLL_NO_LOCK,
+								"core");
 	/* Set the ratios for CORE_CLK, L3_CLK, L4_CLK */
 	temp = (CLKSEL_CORE_X2_DIV_1 << CLKSEL_CORE_SHIFT) |
 	    (CLKSEL_L3_CORE_DIV_2 << CLKSEL_L3_SHIFT) |
@@ -246,13 +278,14 @@
 	/* lock PER dpll */
 	params = get_per_dpll_params();
 	do_setup_dpll(&prcm->cm_clkmode_dpll_per,
-			params, DPLL_LOCK);
+			params, DPLL_LOCK, "per");
 	debug("PER DPLL locked\n");
 
 	/* MPU dpll */
 	configure_mpu_dpll();
 }
 
+#ifdef CONFIG_SYS_CLOCKS_ENABLE_ALL
 static void setup_non_essential_dplls(void)
 {
 	u32 sys_clk_khz, abe_ref_clk;
@@ -267,7 +300,7 @@
 		CM_BYPCLK_DPLL_IVA_CLKSEL_MASK, DPLL_IVA_CLKSEL_CORE_X2_DIV_2);
 
 	params = get_iva_dpll_params();
-	do_setup_dpll(&prcm->cm_clkmode_dpll_iva, params, DPLL_LOCK);
+	do_setup_dpll(&prcm->cm_clkmode_dpll_iva, params, DPLL_LOCK, "iva");
 
 	/*
 	 * USB:
@@ -287,7 +320,7 @@
 			sd_div << CM_CLKSEL_DPLL_DPLL_SD_DIV_SHIFT);
 
 	/* Now setup the dpll with the regular function */
-	do_setup_dpll(&prcm->cm_clkmode_dpll_usb, params, DPLL_LOCK);
+	do_setup_dpll(&prcm->cm_clkmode_dpll_usb, params, DPLL_LOCK, "usb");
 
 	/* Configure ABE dpll */
 	params = get_abe_dpll_params();
@@ -315,8 +348,9 @@
 			CM_ABE_PLL_REF_CLKSEL_CLKSEL_MASK,
 			abe_ref_clk << CM_ABE_PLL_REF_CLKSEL_CLKSEL_SHIFT);
 	/* Lock the dpll */
-	do_setup_dpll(&prcm->cm_clkmode_dpll_abe, params, DPLL_LOCK);
+	do_setup_dpll(&prcm->cm_clkmode_dpll_abe, params, DPLL_LOCK, "abe");
 }
+#endif
 
 void do_scale_tps62361(u32 reg, u32 volt_mv)
 {
@@ -561,10 +595,15 @@
 		enable_basic_clocks();
 		scale_vcores();
 		setup_dplls();
+#ifdef CONFIG_SYS_CLOCKS_ENABLE_ALL
 		setup_non_essential_dplls();
 		enable_non_essential_clocks();
+#endif
 		break;
 	default:
 		break;
 	}
+
+	if (OMAP_INIT_CONTEXT_SPL != omap_hw_init_context())
+		enable_basic_uboot_clocks();
 }
diff --git a/arch/arm/cpu/armv7/omap-common/hwinit-common.c b/arch/arm/cpu/armv7/omap-common/hwinit-common.c
index 5cf4e2b..f65705d 100644
--- a/arch/arm/cpu/armv7/omap-common/hwinit-common.c
+++ b/arch/arm/cpu/armv7/omap-common/hwinit-common.c
@@ -31,9 +31,18 @@
 #include <asm/arch/sys_proto.h>
 #include <asm/sizes.h>
 #include <asm/emif.h>
+#include <asm/omap_common.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/*
+ * This is used to verify if the configuration header
+ * was executed by rom code prior to control of transfer
+ * to the bootloader. SPL is responsible for saving and
+ * passing the boot_params pointer to the u-boot.
+ */
+struct omap_boot_parameters boot_params __attribute__ ((section(".data")));
+
 #ifdef CONFIG_SPL_BUILD
 /*
  * We use static variables because global data is not ready yet.
@@ -41,12 +50,11 @@
  * We would not typically need to save these parameters in regular
  * U-Boot. This is needed only in SPL at the moment.
  */
-u32 omap_bootdevice = BOOT_DEVICE_MMC1;
 u32 omap_bootmode = MMCSD_MODE_FAT;
 
 u32 omap_boot_device(void)
 {
-	return omap_bootdevice;
+	return (u32) (boot_params.omap_bootdevice);
 }
 
 u32 omap_boot_mode(void)
@@ -71,12 +79,16 @@
 		set_muxconf_regs_essential();
 		break;
 	case OMAP_INIT_CONTEXT_UBOOT_AFTER_SPL:
+#ifdef CONFIG_SYS_ENABLE_PADS_ALL
 		set_muxconf_regs_non_essential();
+#endif
 		break;
 	case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR:
 	case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH:
 		set_muxconf_regs_essential();
+#ifdef CONFIG_SYS_ENABLE_PADS_ALL
 		set_muxconf_regs_non_essential();
+#endif
 		break;
 	}
 }
@@ -103,6 +115,13 @@
 		minor_rev);
 }
 
+#ifdef CONFIG_SPL_BUILD
+static void init_boot_params(void)
+{
+	boot_params_ptr = (u32 *) &boot_params;
+}
+#endif
+
 /*
  * Routine: s_init
  * Description: Does early system init of watchdog, muxing,  andclocks
@@ -131,6 +150,7 @@
 #ifdef CONFIG_SPL_BUILD
 	/* For regular u-boot sdram_init() is called from dram_init() */
 	sdram_init();
+	init_boot_params();
 #endif
 }
 
diff --git a/arch/arm/cpu/armv7/omap-common/lowlevel_init.S b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
index 6873298..35f38ac 100644
--- a/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
+++ b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
@@ -27,7 +27,7 @@
  */
 
 #include <asm/arch/omap.h>
-#ifdef CONFIG_SPL_BUILD
+
 .global save_boot_params
 save_boot_params:
 	/*
@@ -43,21 +43,40 @@
 	cmp	r2, r0
 	blt	1f
 
+	/*
+	 * store the boot params passed from rom code or saved
+	 * and passed by SPL
+	 */
+	cmp	r0, #0
+	beq	1f
+	ldr	r1, =boot_params
+	str	r0, [r1]
+#ifdef CONFIG_SPL_BUILD
 	/* Store the boot device in omap_boot_device */
-	ldr     r2, [r0, #BOOT_DEVICE_OFFSET]	@ r1 <- value of boot device
+	ldrb	r2, [r0, #BOOT_DEVICE_OFFSET]	@ r1 <- value of boot device
 	and	r2, #BOOT_DEVICE_MASK
-	ldr	r3, =omap_bootdevice
-	str     r2, [r3]			@ omap_boot_device <- r1
+	ldr	r3, =boot_params
+	strb	r2, [r3, #BOOT_DEVICE_OFFSET]	@ omap_boot_device <- r1
 
+	/* boot mode is passed only for devices that can raw/fat mode */
+	cmp	r2, #2
+	blt	2f
+	cmp	r2, #7
+	bgt	2f
 	/* Store the boot mode (raw/FAT) in omap_boot_mode */
 	ldr	r2, [r0, #DEV_DESC_PTR_OFFSET]	@ get the device descriptor ptr
 	ldr	r2, [r2, #DEV_DATA_PTR_OFFSET]	@ get the pDeviceData ptr
 	ldr	r2, [r2, #BOOT_MODE_OFFSET]	@ get the boot mode
 	ldr	r3, =omap_bootmode
 	str	r2, [r3]
+#endif
+2:
+	ldrb	r2, [r0, #CH_FLAGS_OFFSET]
+	ldr	r3, =boot_params
+	strb	r2, [r3, #CH_FLAGS_OFFSET]
 1:
 	bx	lr
-#endif
+
 
 .globl lowlevel_init
 lowlevel_init:
diff --git a/arch/arm/cpu/armv7/omap-common/spl.c b/arch/arm/cpu/armv7/omap-common/spl.c
index 2c59d2b..d6d7d65 100644
--- a/arch/arm/cpu/armv7/omap-common/spl.c
+++ b/arch/arm/cpu/armv7/omap-common/spl.c
@@ -38,6 +38,7 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+u32* boot_params_ptr = NULL;
 struct spl_image_info spl_image;
 
 /* Define global data structure pointer to it*/
@@ -92,12 +93,16 @@
 
 static void jump_to_image_no_args(void)
 {
-	typedef void (*image_entry_noargs_t)(void)__attribute__ ((noreturn));
+	typedef void (*image_entry_noargs_t)(u32 *)__attribute__ ((noreturn));
 	image_entry_noargs_t image_entry =
 			(image_entry_noargs_t) spl_image.entry_point;
 
 	debug("image entry point: 0x%X\n", spl_image.entry_point);
-	image_entry();
+	/* Pass the saved boot_params from rom code */
+#if defined(CONFIG_VIRTIO) || defined(CONFIG_ZEBU)
+	image_entry = 0x80100000;
+#endif
+	image_entry((u32 *)&boot_params_ptr);
 }
 
 void jump_to_image_no_args(void) __attribute__ ((noreturn));
diff --git a/arch/arm/cpu/armv7/omap4/clocks.c b/arch/arm/cpu/armv7/omap4/clocks.c
index a1098d4..0886f92 100644
--- a/arch/arm/cpu/armv7/omap4/clocks.c
+++ b/arch/arm/cpu/armv7/omap4/clocks.c
@@ -333,30 +333,23 @@
 	};
 
 	u32 *const clk_modules_hw_auto_essential[] = {
+		&prcm->cm_memif_emif_1_clkctrl,
+		&prcm->cm_memif_emif_2_clkctrl,
+		&prcm->cm_l4cfg_l4_cfg_clkctrl,
 		&prcm->cm_wkup_gpio1_clkctrl,
 		&prcm->cm_l4per_gpio2_clkctrl,
 		&prcm->cm_l4per_gpio3_clkctrl,
 		&prcm->cm_l4per_gpio4_clkctrl,
 		&prcm->cm_l4per_gpio5_clkctrl,
 		&prcm->cm_l4per_gpio6_clkctrl,
-		&prcm->cm_memif_emif_1_clkctrl,
-		&prcm->cm_memif_emif_2_clkctrl,
-		&prcm->cm_l3init_hsusbotg_clkctrl,
-		&prcm->cm_l3init_usbphy_clkctrl,
-		&prcm->cm_l4cfg_l4_cfg_clkctrl,
 		0
 	};
 
 	u32 *const clk_modules_explicit_en_essential[] = {
-		&prcm->cm_l4per_gptimer2_clkctrl,
+		&prcm->cm_wkup_gptimer1_clkctrl,
 		&prcm->cm_l3init_hsmmc1_clkctrl,
 		&prcm->cm_l3init_hsmmc2_clkctrl,
-		&prcm->cm_l4per_mcspi1_clkctrl,
-		&prcm->cm_wkup_gptimer1_clkctrl,
-		&prcm->cm_l4per_i2c1_clkctrl,
-		&prcm->cm_l4per_i2c2_clkctrl,
-		&prcm->cm_l4per_i2c3_clkctrl,
-		&prcm->cm_l4per_i2c4_clkctrl,
+		&prcm->cm_l4per_gptimer2_clkctrl,
 		&prcm->cm_wkup_wdtimer2_clkctrl,
 		&prcm->cm_l4per_uart3_clkctrl,
 		0
@@ -386,6 +379,33 @@
 			 1);
 }
 
+void enable_basic_uboot_clocks(void)
+{
+	u32 *const clk_domains_essential[] = {
+		0
+	};
+
+	u32 *const clk_modules_hw_auto_essential[] = {
+		&prcm->cm_l3init_hsusbotg_clkctrl,
+		&prcm->cm_l3init_usbphy_clkctrl,
+		0
+	};
+
+	u32 *const clk_modules_explicit_en_essential[] = {
+		&prcm->cm_l4per_mcspi1_clkctrl,
+		&prcm->cm_l4per_i2c1_clkctrl,
+		&prcm->cm_l4per_i2c2_clkctrl,
+		&prcm->cm_l4per_i2c3_clkctrl,
+		&prcm->cm_l4per_i2c4_clkctrl,
+		0
+	};
+
+	do_enable_clocks(clk_domains_essential,
+			 clk_modules_hw_auto_essential,
+			 clk_modules_explicit_en_essential,
+			 1);
+}
+
 /*
  * Enable non-essential clock domains, modules and
  * do some additional special settings needed
diff --git a/arch/arm/cpu/armv7/omap5/clocks.c b/arch/arm/cpu/armv7/omap5/clocks.c
index 28d3bcd..dd882a2 100644
--- a/arch/arm/cpu/armv7/omap5/clocks.c
+++ b/arch/arm/cpu/armv7/omap5/clocks.c
@@ -273,30 +273,26 @@
 	};
 
 	u32 *const clk_modules_hw_auto_essential[] = {
+		&prcm->cm_memif_emif_1_clkctrl,
+		&prcm->cm_memif_emif_2_clkctrl,
+		&prcm->cm_l4cfg_l4_cfg_clkctrl,
 		&prcm->cm_wkup_gpio1_clkctrl,
 		&prcm->cm_l4per_gpio2_clkctrl,
 		&prcm->cm_l4per_gpio3_clkctrl,
 		&prcm->cm_l4per_gpio4_clkctrl,
 		&prcm->cm_l4per_gpio5_clkctrl,
 		&prcm->cm_l4per_gpio6_clkctrl,
-		&prcm->cm_memif_emif_1_clkctrl,
-		&prcm->cm_memif_emif_2_clkctrl,
-		&prcm->cm_l4cfg_l4_cfg_clkctrl,
 		0
 	};
 
 	u32 *const clk_modules_explicit_en_essential[] = {
-		&prcm->cm_l4per_gptimer2_clkctrl,
+		&prcm->cm_wkup_gptimer1_clkctrl,
 		&prcm->cm_l3init_hsmmc1_clkctrl,
 		&prcm->cm_l3init_hsmmc2_clkctrl,
-		&prcm->cm_l4per_mcspi1_clkctrl,
-		&prcm->cm_wkup_gptimer1_clkctrl,
-		&prcm->cm_l4per_i2c1_clkctrl,
-		&prcm->cm_l4per_i2c2_clkctrl,
-		&prcm->cm_l4per_i2c3_clkctrl,
-		&prcm->cm_l4per_i2c4_clkctrl,
+		&prcm->cm_l4per_gptimer2_clkctrl,
 		&prcm->cm_wkup_wdtimer2_clkctrl,
 		&prcm->cm_l4per_uart3_clkctrl,
+		&prcm->cm_l4per_i2c1_clkctrl,
 		0
 	};
 
@@ -320,6 +316,30 @@
 			 1);
 }
 
+void enable_basic_uboot_clocks(void)
+{
+	u32 *const clk_domains_essential[] = {
+		0
+	};
+
+	u32 *const clk_modules_hw_auto_essential[] = {
+		0
+	};
+
+	u32 *const clk_modules_explicit_en_essential[] = {
+		&prcm->cm_l4per_mcspi1_clkctrl,
+		&prcm->cm_l4per_i2c2_clkctrl,
+		&prcm->cm_l4per_i2c3_clkctrl,
+		&prcm->cm_l4per_i2c4_clkctrl,
+		0
+	};
+
+	do_enable_clocks(clk_domains_essential,
+			 clk_modules_hw_auto_essential,
+			 clk_modules_explicit_en_essential,
+			 1);
+}
+
 /*
  * Enable non-essential clock domains, modules and
  * do some additional special settings needed