rockchip: spl: Support full-speed CPU in SPL

Add a feature which speeds up the CPU to full speed in SPL to minimise
boot time. This is only supported for certain boards (at present only
jerry).

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/arm/dts/rk3288-veyron.dtsi b/arch/arm/dts/rk3288-veyron.dtsi
index c201e85..421d212 100644
--- a/arch/arm/dts/rk3288-veyron.dtsi
+++ b/arch/arm/dts/rk3288-veyron.dtsi
@@ -332,6 +332,7 @@
 	clock-frequency = <400000>;
 	i2c-scl-falling-time-ns = <50>;		/* 2.5ns measured */
 	i2c-scl-rising-time-ns = <100>;		/* 45ns measured */
+	u-boot,dm-pre-reloc;
 
 	rk808: pmic@1b {
 		compatible = "rockchip,rk808";
@@ -344,6 +345,7 @@
 		rockchip,system-power-controller;
 		wakeup-source;
 		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
 
 		vcc1-supply = <&vcc33_sys>;
 		vcc2-supply = <&vcc33_sys>;
diff --git a/arch/arm/include/asm/arch-rockchip/clock.h b/arch/arm/include/asm/arch-rockchip/clock.h
index a9ea268..d66b26f 100644
--- a/arch/arm/include/asm/arch-rockchip/clock.h
+++ b/arch/arm/include/asm/arch-rockchip/clock.h
@@ -74,4 +74,9 @@
  */
 int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp);
 
+struct rk3288_cru;
+struct rk3288_grf;
+
+void rkclk_configure_cpu(struct rk3288_cru *cru, struct rk3288_grf *grf);
+
 #endif
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3288.h b/arch/arm/include/asm/arch-rockchip/cru_rk3288.h
index b0dea70..d2690c7 100644
--- a/arch/arm/include/asm/arch-rockchip/cru_rk3288.h
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk3288.h
@@ -109,6 +109,18 @@
 	SPI0_DIV_MASK		= 0x7f,
 };
 
+/* CRU_CLKSEL37_CON */
+enum {
+	PCLK_CORE_DBG_DIV_SHIFT	= 9,
+	PCLK_CORE_DBG_DIV_MASK	= 0x1f,
+
+	ATCLK_CORE_DIV_CON_SHIFT = 4,
+	ATCLK_CORE_DIV_CON_MASK	= 0x1f,
+
+	CLK_L2RAM_DIV_SHIFT	= 0,
+	CLK_L2RAM_DIV_MASK	= 7,
+};
+
 /* CRU_CLKSEL39_CON */
 enum {
 	ACLK_HEVC_PLL_SHIFT	= 0xe,
diff --git a/arch/arm/mach-rockchip/rk3288/Kconfig b/arch/arm/mach-rockchip/rk3288/Kconfig
index d0a7276..ed89c3e 100644
--- a/arch/arm/mach-rockchip/rk3288/Kconfig
+++ b/arch/arm/mach-rockchip/rk3288/Kconfig
@@ -16,6 +16,15 @@
 	  WiFi. It includes a Chrome OS EC (Cortex-M3) to provide access to
 	  the keyboard and battery functions.
 
+config ROCKCHIP_FAST_SPL
+	bool "Change the CPU to full speed in SPL"
+	depends on TARGET_CHROMEBOOK_JERRY
+	help
+	  Some boards want to boot as fast as possible. We can increase the
+	  CPU frequency in SPL if the power supply is configured to the correct
+	  voltage. This option is only available on boards which support it
+	  and have the required PMIC code.
+
 config SYS_SOC
 	default "rockchip"
 
diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
index 074cf518..e9e2211 100644
--- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
+++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
@@ -22,6 +22,8 @@
 #include <asm/arch/pmu_rk3288.h>
 #include <asm/arch/sdram.h>
 #include <linux/err.h>
+#include <power/regulator.h>
+#include <power/rk808_pmic.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -748,6 +750,32 @@
 }
 
 #ifdef CONFIG_SPL_BUILD
+# ifdef CONFIG_ROCKCHIP_FAST_SPL
+static int veyron_init(struct dram_info *priv)
+{
+	struct udevice *pmic;
+	int ret;
+
+	ret = uclass_first_device(UCLASS_PMIC, &pmic);
+	if (ret)
+		return ret;
+
+	/* Slowly raise to max CPU voltage to prevent overshoot */
+	ret = rk808_spl_configure_buck(pmic, 1, 1200000);
+	if (ret)
+		return ret;
+	udelay(175);/* Must wait for voltage to stabilize, 2mV/us */
+	ret = rk808_spl_configure_buck(pmic, 1, 1400000);
+	if (ret)
+		return ret;
+	udelay(100);/* Must wait for voltage to stabilize, 2mV/us */
+
+	rkclk_configure_cpu(priv->cru, priv->grf);
+
+	return 0;
+}
+# endif
+
 static int setup_sdram(struct udevice *dev)
 {
 	struct dram_info *priv = dev_get_priv(dev);
@@ -790,6 +818,14 @@
 		debug("%s: Cannot read rockchip,sdram-params\n", __func__);
 		return -EINVAL;
 	}
+
+# ifdef CONFIG_ROCKCHIP_FAST_SPL
+	if (!fdt_node_check_compatible(blob, 0, "google,veyron")) {
+		ret = veyron_init(priv);
+		if (ret)
+			return ret;
+	}
+# endif
 
 	return sdram_init(priv, &params);
 }
diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig
index b2672b8..526306f 100644
--- a/configs/chromebook_jerry_defconfig
+++ b/configs/chromebook_jerry_defconfig
@@ -3,6 +3,7 @@
 CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_ROCKCHIP_RK3288=y
 CONFIG_TARGET_CHROMEBOOK_JERRY=y
+CONFIG_ROCKCHIP_FAST_SPL=y
 CONFIG_SPL_STACK_R_ADDR=0x80000
 CONFIG_DM_KEYBOARD=y
 CONFIG_DEFAULT_DEVICE_TREE="rk3288-jerry"
diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c
index 8ef68fe..2a85e93 100644
--- a/drivers/clk/clk_rk3288.c
+++ b/drivers/clk/clk_rk3288.c
@@ -59,6 +59,16 @@
 	/* PLL CON3 */
 	PLL_RESET_SHIFT		= 5,
 
+	/* CLKSEL0 */
+	CORE_SEL_PLL_MASK	= 1,
+	CORE_SEL_PLL_SHIFT	= 15,
+	A17_DIV_MASK		= 0x1f,
+	A17_DIV_SHIFT		= 8,
+	MP_DIV_MASK		= 0xf,
+	MP_DIV_SHIFT		= 4,
+	M0_DIV_MASK		= 0xf,
+	M0_DIV_SHIFT		= 0,
+
 	/* CLKSEL1: pd bus clk pll sel: codec or general */
 	PD_BUS_SEL_PLL_MASK	= 15,
 	PD_BUS_SEL_CPLL		= 0,
@@ -438,6 +448,52 @@
 }
 #endif
 
+void rkclk_configure_cpu(struct rk3288_cru *cru, struct rk3288_grf *grf)
+{
+	/* pll enter slow-mode */
+	rk_clrsetreg(&cru->cru_mode_con,
+		     APLL_MODE_MASK << APLL_MODE_SHIFT,
+		     APLL_MODE_SLOW << APLL_MODE_SHIFT);
+
+	rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg);
+
+	/* waiting for pll lock */
+	while (!(readl(&grf->soc_status[1]) & SOCSTS_APLL_LOCK))
+		udelay(1);
+
+	/*
+	 * core clock pll source selection and
+	 * set up dependent divisors for MPAXI/M0AXI and ARM clocks.
+	 * core clock select apll, apll clk = 1800MHz
+	 * arm clk = 1800MHz, mpclk = 450MHz, m0clk = 900MHz
+	 */
+	rk_clrsetreg(&cru->cru_clksel_con[0],
+		     CORE_SEL_PLL_MASK << CORE_SEL_PLL_SHIFT |
+		     A17_DIV_MASK << A17_DIV_SHIFT |
+		     MP_DIV_MASK << MP_DIV_SHIFT |
+		     M0_DIV_MASK << M0_DIV_SHIFT,
+		     0 << A17_DIV_SHIFT |
+		     3 << MP_DIV_SHIFT |
+		     1 << M0_DIV_SHIFT);
+
+	/*
+	 * set up dependent divisors for L2RAM/ATCLK and PCLK clocks.
+	 * l2ramclk = 900MHz, atclk = 450MHz, pclk_dbg = 450MHz
+	 */
+	rk_clrsetreg(&cru->cru_clksel_con[37],
+		     CLK_L2RAM_DIV_MASK << CLK_L2RAM_DIV_SHIFT |
+		     ATCLK_CORE_DIV_CON_MASK << ATCLK_CORE_DIV_CON_SHIFT |
+		     PCLK_CORE_DBG_DIV_MASK >> PCLK_CORE_DBG_DIV_SHIFT,
+		     1 << CLK_L2RAM_DIV_SHIFT |
+		     3 << ATCLK_CORE_DIV_CON_SHIFT |
+		     3 << PCLK_CORE_DBG_DIV_SHIFT);
+
+	/* PLL enter normal-mode */
+	rk_clrsetreg(&cru->cru_mode_con,
+		     APLL_MODE_MASK << APLL_MODE_SHIFT,
+		     APLL_MODE_NORMAL << APLL_MODE_SHIFT);
+}
+
 /* Get pll rate by id */
 static uint32_t rkclk_pll_get_rate(struct rk3288_cru *cru,
 				   enum rk_clk_id clk_id)
diff --git a/include/configs/chromebook_jerry.h b/include/configs/chromebook_jerry.h
index 6e32f2c..e07d057 100644
--- a/include/configs/chromebook_jerry.h
+++ b/include/configs/chromebook_jerry.h
@@ -24,4 +24,7 @@
 
 #define CONFIG_KEYBOARD
 
+#define CONFIG_SPL_POWER_SUPPORT
+#define CONFIG_SPL_I2C_SUPPORT
+
 #endif