[U-Boot] [PATCH 11/22] ARM: sunxi: U-Boot SPL capable of booting directly from MMC

Henrik Nordström henrik at henriknordstrom.net
Sun Nov 25 12:44:17 CET 2012


Allwinner sunxi family of SoCs boots from MMC0/NAND/NOR/MMC2 loading
boot code into an embedded 32KB SRAM.

This patch adds support for booting u-boot SPL from MMC0

We first initializes the console UART, then DRAM controller with board
specific DRAM configuration details, configure CPU core voltage and
clocks before loading the full u-boot image into DRAM.

From: Henrik Nordstrom <henrik at henriknordstrom.net>
Signed-off-by: Tom Cubie <tangliang at allwinnertech.com>
Signed-off-by: Stefan Roese <sr at denx.de>
Signed-off-by: Henrik Nordstrom <henrik at henriknordstrom.net>
---
 Makefile                                |   11 +
 arch/arm/cpu/armv7/sunxi/board.c        |   38 +++
 arch/arm/cpu/armv7/sunxi/clock.c        |   99 +++++++
 arch/arm/cpu/armv7/sunxi/dram.c         |  445 +++++++++++++++++++++++++++++++
 arch/arm/cpu/armv7/sunxi/u-boot-spl.lds |   63 +++++
 arch/arm/include/asm/arch-sunxi/spl.h   |   34 +++
 board/sunxi/board.c                     |   46 ++++
 include/configs/sunxi-common.h          |   30 ++-
 spl/Makefile                            |   10 +
 9 files changed, 775 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/sunxi/dram.c
 create mode 100644 arch/arm/cpu/armv7/sunxi/u-boot-spl.lds
 create mode 100644 arch/arm/include/asm/arch-sunxi/spl.h

diff --git a/Makefile b/Makefile
index 81fe532..d1b7f97 100644
--- a/Makefile
+++ b/Makefile
@@ -517,6 +517,16 @@ $(obj)u-boot.spr:	$(obj)u-boot.img $(obj)spl/u-boot-spl.bin
 			conv=notrunc 2>/dev/null
 		cat $(obj)spl/u-boot-spl-pad.img $(obj)u-boot.img > $@
 
+# sunxi: Combined object with SPL U-Boot with sunxi header (sunxi-spl.bin)
+# and the full-blown U-Boot attached to it
+$(obj)u-boot-sunxi-with-spl.bin: $(obj)spl/sunxi-spl.bin $(obj)u-boot.bin
+		tr "\000" "\377" < /dev/zero | dd ibs=1 count=$(CONFIG_SPL_PAD_TO) \
+			of=$(obj)spl/sunxi-spl-pad.bin 2>/dev/null
+		dd if=$(obj)spl/sunxi-spl.bin of=$(obj)spl/sunxi-spl-pad.bin \
+			conv=notrunc 2>/dev/null
+		cat $(obj)spl/sunxi-spl-pad.bin $(obj)u-boot.bin > $@
+		rm $(obj)spl/sunxi-spl-pad.bin
+
 ifeq ($(SOC),tegra20)
 ifeq ($(CONFIG_OF_SEPARATE),y)
 nodtb=dtb
@@ -854,6 +864,7 @@ clobber:	tidy
 	@[ ! -d $(obj)nand_spl ] || find $(obj)nand_spl -name "*" -type l -print | xargs rm -f
 	@rm -f $(obj)dts/*.tmp
 	@rm -f $(obj)spl/u-boot-spl{,-pad}.ais
+	@rm -f $(obj)spl/sun?i-spl.bin
 
 mrproper \
 distclean:	clobber unconfig
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c
index 29cc4bd..6dc2bd0 100644
--- a/arch/arm/cpu/armv7/sunxi/board.c
+++ b/arch/arm/cpu/armv7/sunxi/board.c
@@ -27,12 +27,37 @@
 #include <common.h>
 #include <asm/io.h>
 #include <serial.h>
+#include <i2c.h>
 #include <asm/gpio.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/timer.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/sys_proto.h>
 #include <netdev.h>
+#ifdef CONFIG_SPL_BUILD
+#include <spl.h>
+#endif
+
+#ifdef CONFIG_SPL_BUILD
+/* Pointer to the global data structure for SPL */
+DECLARE_GLOBAL_DATA_PTR;
+
+/* The sunxi internal brom will try to loader external bootloader
+ * from mmc0, nannd flash, mmc2.
+ * Unfortunately we can't check how SPL was loaded so assume
+ * it's always the first SD/MMC controller
+ */
+u32 spl_boot_device(void)
+{
+	return BOOT_DEVICE_MMC1;
+}
+
+/* No confiration data available in SPL yet. Hardcode bootmode */
+u32 spl_boot_mode(void)
+{
+	return MMCSD_MODE_RAW;
+}
+#endif
 
 int gpio_init(void)
 {
@@ -65,6 +90,19 @@ void s_init(void)
 #endif
 	clock_init();
 	gpio_init();
+
+#ifdef CONFIG_SPL_BUILD
+	gd = &gdata;
+	preloader_console_init();
+
+#ifdef CONFIG_SPL_I2C_SUPPORT
+	/* Needed early by sunxi_board_init if PMU is enabled */
+	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+
+	sunxi_board_init();
+#endif
+
 }
 
 void reset_cpu(ulong addr)
diff --git a/arch/arm/cpu/armv7/sunxi/clock.c b/arch/arm/cpu/armv7/sunxi/clock.c
index b9bbb7d..91cfae3 100644
--- a/arch/arm/cpu/armv7/sunxi/clock.c
+++ b/arch/arm/cpu/armv7/sunxi/clock.c
@@ -24,13 +24,34 @@
 #include <common.h>
 #include <asm/io.h>
 #include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
 #include <asm/arch/sys_proto.h>
 
+#ifdef CONFIG_SPL_BUILD
+static void clock_init_safe(void)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* Set safe defaults until PMU is configured */
+	writel(AXI_DIV_1 << 0 | AHB_DIV_2 << 4 | APB0_DIV_1 << 8 |
+	       CPU_CLK_SRC_OSC24M << 16, &ccm->cpu_ahb_apb0_cfg);
+	writel(0xa1005000, &ccm->pll1_cfg);
+	sdelay(200);
+	writel(AXI_DIV_1 << 0 | AHB_DIV_2 << 4 | APB0_DIV_1 << 8 |
+	       CPU_CLK_SRC_PLL1 << 16, &ccm->cpu_ahb_apb0_cfg);
+}
+#endif
+
 int clock_init(void)
 {
 	struct sunxi_ccm_reg *const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 
+#ifdef CONFIG_SPL_BUILD
+	clock_init_safe();
+#endif
+
 	/* uart clock source is apb1 */
 	sr32(&ccm->apb1_clk_div_cfg, 24, 2, APB1_CLK_SRC_OSC24M);
 	sr32(&ccm->apb1_clk_div_cfg, 16, 2, APB1_FACTOR_N);
@@ -70,3 +91,81 @@ int clock_twi_onoff(int port, int state)
 
 	return 0;
 }
+
+#ifdef CONFIG_SPL_BUILD
+#define PLL1_CFG(N, K, M, P)	(1 << 31 | 0 << 30 | 8 << 26 | 0 << 25 | \
+				 16 << 20 | (P) << 16 | 2 << 13 | (N) << 8 | \
+				 (K) << 4 | 0 << 3 | 0 << 2 | (M) << 0)
+#define RDIV(a, b)		((a + (b) - 1) / (b))
+
+struct {
+	u32 pll1_cfg;
+	unsigned int freq;
+} pll1_para[] = {
+	{ PLL1_CFG(16, 0, 0, 0), 384000000 },
+	{ PLL1_CFG(16, 1, 0, 0), 768000000 },
+	{ PLL1_CFG(20, 1, 0, 0), 960000000 },
+	{ PLL1_CFG(21, 1, 0, 0), 1008000000},
+	{ PLL1_CFG(22, 1, 0, 0), 1056000000},
+	{ PLL1_CFG(23, 1, 0, 0), 1104000000},
+	{ PLL1_CFG(24, 1, 0, 0), 1152000000},
+	{ PLL1_CFG(25, 1, 0, 0), 1200000000},
+	{ PLL1_CFG(26, 1, 0, 0), 1248000000},
+	{ PLL1_CFG(27, 1, 0, 0), 1296000000},
+	{ PLL1_CFG(28, 1, 0, 0), 1344000000},
+	{ PLL1_CFG(29, 1, 0, 0), 1392000000},
+	{ PLL1_CFG(30, 1, 0, 0), 1440000000},
+	{ PLL1_CFG(31, 1, 0, 0), 1488000000},
+	{ PLL1_CFG(31, 1, 0, 0), ~0},
+};
+
+void clock_set_pll1(int hz)
+{
+	int i = 0;
+	int axi, ahb, apb0;
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* Find target frequency */
+	while (pll1_para[i].freq < hz)
+		i++;
+
+	hz = pll1_para[i].freq;
+
+	/* Calculate system clock divisors */
+	axi = RDIV(hz, 432000000);		/* Max 450MHz */
+	ahb = RDIV(hz/axi, 204000000);		/* Max 250MHz */
+	apb0 = 2;				/* Max 150MHz */
+
+	/* Map divisors to register values */
+	axi = axi - 1;
+	if (ahb > 4)
+		ahb = 3;
+	else if (ahb > 2)
+		ahb = 2;
+	else if (ahb > 1)
+		ahb = 1;
+	else
+		ahb = 0;
+
+	apb0 = apb0 - 1;
+
+	/* Switch to 24MHz clock while changing PLL1 */
+	writel(AXI_DIV_1 << 0 | AHB_DIV_2 << 4 | APB0_DIV_1 << 8 |
+	       CPU_CLK_SRC_OSC24M << 16, &ccm->cpu_ahb_apb0_cfg);
+	sdelay(20);
+
+	/* Configure sys clock divisors */
+	writel(axi << 0 | ahb << 4 | apb0 << 8 | CPU_CLK_SRC_OSC24M << 16,
+	       &ccm->cpu_ahb_apb0_cfg);
+
+	/* Configure PLL1 at the desired frequency */
+	writel(pll1_para[i].pll1_cfg, &ccm->pll1_cfg);
+	sdelay(200);
+
+	/* Switch CPU to PLL1 */
+	writel(axi << 0 | ahb << 4 | apb0 << 8 | CPU_CLK_SRC_PLL1 << 16,
+	       &ccm->cpu_ahb_apb0_cfg);
+	sdelay(20);
+}
+#endif
diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c
new file mode 100644
index 0000000..f169b7b
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/dram.c
@@ -0,0 +1,445 @@
+/*
+ * sunxi DRAM controller initialization
+ * (C) Copyright 2012 Henrik Nordstrom <henrik at henriknordstrom.net>
+ *
+ * Based on sun4i Linux kernel sources mach-sunxi/pm/standby/dram*.c
+ * and earlier U-Boot Allwiner A10 SPL work
+ *
+ * (C) Copyright 2007-2012
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Berg Xing <bergxing at allwinnertech.com>
+ * Tom Cubie <tangliang at allwinnertech.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/timer.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sys_proto.h>
+
+static void mctl_ddr3_reset(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+#ifdef CONFIG_SUN4I
+	struct sunxi_timer_reg *timer = (struct sunxi_timer_reg *)SUNXI_TIMER_BASE;
+	u32 reg_val;
+
+	writel(0, &timer->cpu_cfg);
+	reg_val = readl(&timer->cpu_cfg);
+	reg_val >>= 6;
+	reg_val &= 0x3;
+
+	if (reg_val != 0) {
+		setbits_le32(&dram->mcr, 0x1 << 12);
+		sdelay(0x100);
+		clrbits_le32(&dram->mcr, 0x1 << 12);
+	} else
+#endif
+	{
+		clrbits_le32(&dram->mcr, 0x1 << 12);
+		sdelay(0x100);
+		setbits_le32(&dram->mcr, 0x1 << 12);
+	}
+}
+
+static void mctl_set_drive(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	clrsetbits_le32(&dram->mcr, 0x3, (0x6 << 12) | 0xFFC);
+}
+
+static void mctl_itm_disable(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	setbits_le32(&dram->ccr, 0x1 << 28);
+}
+
+static void mctl_itm_enable(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	clrbits_le32(&dram->ccr, 0x1 << 28);
+}
+
+static void mctl_enable_dll0(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	clrsetbits_le32(&dram->dllcr[0], 0x40000000, 0x80000000);
+	sdelay(0x100);
+
+	clrbits_le32(&dram->dllcr[0], 0xC0000000);
+	sdelay(0x1000);
+
+	clrsetbits_le32(&dram->dllcr[0], 0x80000000, 0x40000000);
+	sdelay(0x1000);
+}
+
+/*
+ * Note: This differs from pm/standby in that it checks the bus width
+ */
+static void mctl_enable_dllx(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 i, n, bus_width;
+
+	bus_width = readl(&dram->dcr);
+	bus_width >>= 6;
+	bus_width &= 7;
+
+	if (bus_width == 3)
+		n = 5;
+	else
+		n = 3;
+
+	for (i = 1; i < n; i++)
+		clrsetbits_le32(&dram->dllcr[i], 0x40000000, 0x80000000);
+	sdelay(0x100);
+
+	for (i = 1; i < n; i++)
+		clrbits_le32(&dram->dllcr[i], 0xC0000000);
+	sdelay(0x1000);
+
+	for (i = 1; i < n; i++)
+		clrsetbits_le32(&dram->dllcr[i], 0x80000000, 0x40000000);
+	sdelay(0x1000);
+}
+
+static u32 hpcr_value[32] = {
+#ifdef CONFIG_SUN5I
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0x1031, 0x1031, 0x0735, 0x1035,
+	0x1035, 0x0731, 0x1031, 0,
+	0x0301, 0x0301, 0x0301, 0x0301,
+	0x0301, 0x0301, 0x0301, 0
+#endif
+#ifdef CONFIG_SUN4I
+	0x0301, 0x0301, 0x0301, 0x0301,
+	0x0301, 0x0301, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0x1031, 0x1031, 0x0735, 0x1035,
+	0x1035, 0x0731, 0x1031, 0x0735,
+	0x1035, 0x1031, 0x0731, 0x1035,
+	0x1031, 0x0301, 0x0301, 0x0731
+#endif
+};
+
+static void mctl_configure_hostport(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 i;
+
+	for (i = 0; i < 32; i++)
+		writel(hpcr_value[i], &dram->hpcr[i]);
+}
+
+static void mctl_setup_dram_clock(u32 clk)
+{
+	u32 reg_val;
+	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* setup DRAM PLL */
+	reg_val = readl(&ccm->pll5_cfg);
+	reg_val &= ~0x3;
+	reg_val |= 0x1;			/* m factor */
+	reg_val &= ~(0x3 << 4);
+	reg_val |= 0x1 << 4;		/* k factor */
+	reg_val &= ~(0x1f << 8);
+	reg_val |= ((clk / 24) & 0x1f) << 8;	/* n factor */
+	reg_val &= ~(0x3 << 16);
+	reg_val |= 0x1 << 16;		/* p factor */
+	reg_val &= ~(0x1 << 29);	/* PLL on */
+	reg_val |= (u32) 0x1 << 31;	/* PLL En */
+	writel(reg_val, &ccm->pll5_cfg);
+	sdelay(0x100000);
+
+	setbits_le32(&ccm->pll5_cfg, 0x1 << 29);
+
+#ifdef CONFIG_SUN4I
+	/* reset GPS */
+	clrbits_le32(&ccm->gps_clk_cfg, 0x3);
+	setbits_le32(&ccm->ahb_gate0, 0x1 << 26);
+	sdelay(0x20);
+	clrbits_le32(&ccm->ahb_gate0, 0x1 << 26);
+#endif
+
+	/* setup MBUS clock */
+	reg_val = (0x1 << 31) | (0x2 << 24) | (0x1);
+	writel(reg_val, &ccm->mbus_clk_cfg);
+
+	/*
+	 * open DRAMC AHB & DLL register clock
+	 * close it first
+	 */
+#ifdef CONFIG_SUN5I
+	clrbits_le32(&ccm->ahb_gate0, 0x3 << 14);
+#else
+	clrbits_le32(&ccm->ahb_gate0, 0x1 << 14);
+#endif
+	sdelay(0x1000);
+
+	/* then open it */
+#ifdef CONFIG_SUN5I
+	setbits_le32(&ccm->ahb_gate0, 0x3 << 14);
+#else
+	setbits_le32(&ccm->ahb_gate0, 0x1 << 14);
+#endif
+	sdelay(0x1000);
+}
+
+static int dramc_scan_readpipe(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 reg_val;
+
+	/* data training trigger */
+	setbits_le32(&dram->ccr, 0x1 << 30);
+
+	/* check whether data training process is end */
+	while (readl(&dram->ccr) & (0x1 << 30))
+		;
+
+	/* check data training result */
+	reg_val = readl(&dram->csr);
+	if (reg_val & (0x1 << 20))
+		return -1;
+
+	return 0;
+}
+
+static void dramc_clock_output_en(u32 on)
+{
+#ifdef CONFIG_SUN5I
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	if (on)
+		setbits_le32(&dram->mcr, 0x1 << SUN5I_DRAM_MCR_DCLK_OUT_OFFSET);
+	else
+		clrbits_le32(&dram->mcr, 0x1 << SUN5I_DRAM_MCR_DCLK_OUT_OFFSET);
+#endif
+#ifdef CONFIG_SUN4I
+	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	if (on)
+		setbits_le32(&ccm->dram_clk_cfg, 0x1 << SUN4I_CCM_SDRAM_DCLK_OUT_OFFSET);
+	else
+		clrbits_le32(&ccm->dram_clk_cfg, 0x1 << SUN4I_CCM_SDRAM_DCLK_OUT_OFFSET);
+#endif
+}
+
+#ifdef CONFIG_SUN4I
+static void dramc_set_autorefresh_cycle(u32 clk)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 reg_val;
+	u32 tmp_val;
+	u32 dram_size;
+
+	if (clk < 600) {
+		dram_size = readl(&dram->dcr);
+		dram_size >>= 3;
+		dram_size &= 0x7;
+		if (dram_size <= 0x2)
+			reg_val = (131 * clk) >> 10;
+		else
+			reg_val = (336 * clk) >> 10;
+
+		tmp_val = (7987 * clk) >> 10;
+		tmp_val = tmp_val * 9 - 200;
+		reg_val |= tmp_val << 8;
+		reg_val |= 0x8 << 24;
+		writel(reg_val, &dram->drr);
+	} else {
+		writel(0x0, &dram->drr);
+	}
+}
+#endif /* SUN4I */
+
+#ifdef CONFIG_SUN5I
+static void dramc_set_autorefresh_cycle(u32 clk)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 reg_val;
+	u32 tmp_val;
+	reg_val = 131;
+
+	tmp_val = (7987 * clk) >> 10;
+	tmp_val = tmp_val * 9 - 200;
+	reg_val |= tmp_val << 8;
+	reg_val |= 0x8 << 24;
+	writel(reg_val, &dram->drr);
+}
+#endif /* SUN5I */
+
+int dramc_init(struct dram_para *para)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 reg_val;
+	int ret_val;
+
+	/* check input dram parameter structure */
+	if (!para)
+		return -1;
+
+	/* setup DRAM relative clock */
+	mctl_setup_dram_clock(para->clock);
+
+#ifdef CONFIG_SUN5I
+	/* Disable any pad power save control */
+	writel(0, &dram->ppwrsctl);
+#endif
+
+	/* reset external DRAM */
+	mctl_ddr3_reset();
+	mctl_set_drive();
+
+	/* dram clock off */
+	dramc_clock_output_en(0);
+
+#ifdef CONFIG_SUN4I
+	/* select dram controller 1 */
+	writel(0x16237495, &dram->csel);
+#endif
+
+	mctl_itm_disable();
+	mctl_enable_dll0();
+
+	/* configure external DRAM */
+	reg_val = 0;
+	if (para->type == 3)
+		reg_val |= 0x1;
+	reg_val |= (para->io_width >> 3) << 1;
+
+	if (para->density == 256)
+		reg_val |= 0x0 << 3;
+	else if (para->density == 512)
+		reg_val |= 0x1 << 3;
+	else if (para->density == 1024)
+		reg_val |= 0x2 << 3;
+	else if (para->density == 2048)
+		reg_val |= 0x3 << 3;
+	else if (para->density == 4096)
+		reg_val |= 0x4 << 3;
+	else if (para->density == 8192)
+		reg_val |= 0x5 << 3;
+	else
+		reg_val |= 0x0 << 3;
+
+	reg_val |= ((para->bus_width >> 3) - 1) << 6;
+
+	reg_val |= (para->rank_num - 1) << 10;
+
+	reg_val |= 0x1 << 12;
+	reg_val |= ((0x1) & 0x3) << 13;
+
+	writel(reg_val, &dram->dcr);
+
+#ifdef CONFIG_SUN5I
+	/* set odt impendance divide ratio */
+	reg_val = ((para->zq) >> 8) & 0xfffff;
+	reg_val |= ((para->zq) & 0xff) << 20;
+	reg_val |= (para->zq) & 0xf0000000;
+	writel(reg_val, &dram->zqcr0);
+#endif
+
+	/* dram clock on */
+	dramc_clock_output_en(1);
+
+	sdelay(0x10);
+
+	while (readl(&dram->ccr) & (0x1U << 31))
+		;
+
+	mctl_enable_dllx();
+
+#ifdef CONFIG_SUN4I
+	/* set odt impendance divide ratio */
+	reg_val = ((para->zq) >> 8) & 0xfffff;
+	reg_val |= ((para->zq) & 0xff) << 20;
+	reg_val |= (para->zq) & 0xf0000000;
+	writel(reg_val, &dram->zqcr0);
+#endif
+
+#ifdef CONFIG_SUN4I
+	/* set I/O configure register */
+	reg_val = 0x00cc0000;
+	reg_val |= (para->odt_en) & 0x3;
+	reg_val |= ((para->odt_en) & 0x3) << 30;
+	writel(reg_val, &dram->iocr);
+#endif
+
+	/* set refresh period */
+	dramc_set_autorefresh_cycle(para->clock);
+
+	/* set timing parameters */
+	writel(para->tpr0, &dram->tpr0);
+	writel(para->tpr1, &dram->tpr1);
+	writel(para->tpr2, &dram->tpr2);
+
+	/* set mode register */
+	if (para->type == 3) {
+		/* ddr3 */
+		reg_val = 0x0;
+#ifdef CONFIG_SUN5I
+		reg_val |= 0x1000;
+#endif
+		reg_val |= (para->cas - 4) << 4;
+		reg_val |= 0x5 << 9;
+	} else if (para->type == 2) {
+		/* ddr2 */
+		reg_val = 0x2;
+		reg_val |= para->cas << 4;
+		reg_val |= 0x5 << 9;
+	}
+	writel(reg_val, &dram->mr);
+
+	writel(para->emr1, &dram->emr);
+	writel(para->emr2, &dram->emr2);
+	writel(para->emr3, &dram->emr3);
+
+	/* set DQS window mode */
+	clrsetbits_le32(&dram->ccr, 0x1U << 17, 0x1U << 14);
+
+	/* initial external DRAM */
+	setbits_le32(&dram->ccr, 0x1U << 31);
+
+	while (readl(&dram->ccr) & (0x1U << 31))
+		;
+
+	/* scan read pipe value */
+	mctl_itm_enable();
+	ret_val = dramc_scan_readpipe();
+
+	if (ret_val < 0)
+		return 0;
+
+	/* configure all host port */
+	mctl_configure_hostport();
+
+	return get_ram_size((long *)PHYS_SDRAM_1, 1 << 30);
+}
diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds
new file mode 100644
index 0000000..cb418e1
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds
@@ -0,0 +1,63 @@
+/*
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj at denx.de>
+ *
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *	Aneesh V <aneesh at ti.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
+		LENGTH = CONFIG_SPL_MAX_SIZE }
+MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
+		LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+	.text      :
+	{
+		__start = .;
+		arch/arm/cpu/armv7/start.o	(.text)
+		*(.text*)
+	} > .sram
+
+	. = ALIGN(4);
+	.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
+
+	. = ALIGN(4);
+	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
+
+	. = ALIGN(4);
+	__image_copy_end = .;
+	_end = .;
+
+	.bss :
+	{
+		. = ALIGN(4);
+		__bss_start = .;
+		*(.bss*)
+		. = ALIGN(4);
+		__bss_end__ = .;
+	} > .sdram
+}
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
new file mode 100644
index 0000000..404e16a
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/spl.h
@@ -0,0 +1,34 @@
+/*
+ * (C) Copyright 2012
+ * Texas Instruments, <www.ti.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef	_ASM_ARCH_SPL_H_
+#define	_ASM_SPL_H_
+
+#define BOOT_DEVICE_NONE	0
+#define BOOT_DEVICE_XIP		1
+#define BOOT_DEVICE_NAND	2
+#define BOOT_DEVICE_ONE_NAND	3
+#define BOOT_DEVICE_MMC2	5 /*emmc*/
+#define BOOT_DEVICE_MMC1	6
+#define BOOT_DEVICE_XIPWAIT	7
+#define BOOT_DEVICE_MMC2_2      0xFF
+#endif
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index 50fb40f..b917a0a 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -64,3 +64,49 @@ int board_mmc_init(bd_t *bis)
 	return 0;
 }
 #endif
+
+#ifdef CONFIG_SPL_BUILD
+void sunxi_board_init(void)
+{
+	int power_failed = 0;
+	int ramsize;
+
+	printf("DRAM:");
+	ramsize = sunxi_dram_init();
+	if (!ramsize) {
+		printf(" ?");
+		ramsize = sunxi_dram_init();
+	}
+	if (!ramsize) {
+		printf(" ?");
+		ramsize = sunxi_dram_init();
+	}
+	printf(" %dMB\n", ramsize>>20);
+	if (!ramsize)
+		hang();
+
+#ifdef CONFIG_AXP209_POWER
+	power_failed |= axp209_init();
+	power_failed |= axp209_set_dcdc2(1400);
+	power_failed |= axp209_set_dcdc3(1250);
+	power_failed |= axp209_set_ldo2(3000);
+	power_failed |= axp209_set_ldo3(2800);
+	power_failed |= axp209_set_ldo4(2800);
+#endif
+
+	/*
+	 * Only clock up the CPU to full speed if we are reasonably
+	 * assured it's being powered with suitable core voltage
+	 */
+	if (!power_failed)
+		clock_set_pll1(1008000000);
+}
+
+#ifdef CONFIG_SPL_DISPLAY_PRINT
+void spl_display_print(void)
+{
+	printf("Board: %s\n", CONFIG_SYS_BOARD_NAME);
+}
+#endif
+
+#endif
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index bc1f200..b0dcfdb 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -134,7 +134,7 @@
  */
 #define CONFIG_SYS_NO_FLASH
 
-#define CONFIG_SYS_MONITOR_LEN		(256 << 10)	/* 256 KB */
+#define CONFIG_SYS_MONITOR_LEN		(512 << 10)	/* 512 KB */
 #define CONFIG_IDENT_STRING		" Allwinner Technology "
 
 #define CONFIG_ENV_OFFSET		(544 << 10) /* (8 + 24 + 512)KB */
@@ -190,6 +190,30 @@
 #define CONFIG_CMD_EXT4		/* with this we can access ext4 bootfs */
 #define CONFIG_CMD_ZFS		/* with this we can access ZFS bootfs */
 
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_BSS_START_ADDR	0x50000000
+#define CONFIG_SPL_BSS_MAX_SIZE		0x80000		/* 512 KB */
+
+#define CONFIG_SPL_TEXT_BASE		0x20		/* sram start+header */
+#define CONFIG_SPL_MAX_SIZE		0x8000		/* 32 KB */
+
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+#define CONFIG_SPL_LIBDISK_SUPPORT
+#define CONFIG_SPL_SERIAL_SUPPORT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_MMC_SUPPORT
+#define CONFIG_SPL_DISPLAY_PRINT
+
+/* end of 24KB in sram */
+#define LOW_LEVEL_SRAM_STACK		0x00006000
+#define CONFIG_SPL_STACK		LOW_LEVEL_SRAM_STACK
+#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/sunxi/u-boot-spl.lds"
+
+/* 32KB offset */
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR	64
+/* SPL starts at offset 8KiB im MMC and has the size of 24KiB */
+#define CONFIG_SPL_PAD_TO		24576		/* decimal for 'dd' */
+
 #undef CONFIG_CMD_FPGA
 #undef CONFIG_CMD_NET
 #undef CONFIG_CMD_NFS
@@ -210,4 +234,8 @@
 #define CONFIG_SUNXI_GPIO
 #define CONFIG_CMD_GPIO
 
+/* PMU */
+#define CONFIG_SPL_POWER_SUPPORT
+#define CONFIG_AXP209_POWER
+
 #endif /* __CONFIG_H */
diff --git a/spl/Makefile b/spl/Makefile
index 3195390..74d27b1 100644
--- a/spl/Makefile
+++ b/spl/Makefile
@@ -126,6 +126,10 @@ ifdef CONFIG_SAMSUNG
 ALL-y	+= $(obj)$(BOARD)-spl.bin
 endif
 
+ifdef CONFIG_SUNXI
+ALL-y	+= $(obj)sunxi-spl.bin
+endif
+
 all:	$(ALL-y)
 
 ifdef CONFIG_SAMSUNG
@@ -134,6 +138,12 @@ $(obj)$(BOARD)-spl.bin: $(obj)u-boot-spl.bin
 		$(obj)u-boot-spl.bin $(obj)$(BOARD)-spl.bin
 endif
 
+ifdef CONFIG_SUNXI
+$(obj)sunxi-spl.bin: $(obj)u-boot-spl.bin
+	$(OBJTREE)/tools/mksunxiboot \
+		$(obj)u-boot-spl.bin $(obj)sunxi-spl.bin
+endif
+
 $(obj)u-boot-spl.bin:	$(obj)u-boot-spl
 	$(OBJCOPY) $(OBJCFLAGS) -O binary $< $@
 
-- 
1.7.7.6




More information about the U-Boot mailing list