[U-Boot] [PATCH 11/22] ARM: sunxi: U-Boot SPL capable of booting directly from MMC
Luka Perkov
luka at openwrt.org
Sun Nov 25 16:11:34 CET 2012
Hi Henrik,
On Sun, Nov 25, 2012 at 12:44:17PM +0100, Henrik Nordström wrote:
> 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*/
Add spaces in comment above.
> +#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
Luka
More information about the U-Boot
mailing list