diff options
Diffstat (limited to 'arch/arm/cpu/armv7')
-rw-r--r-- | arch/arm/cpu/armv7/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/at91/config.mk | 10 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/Makefile | 25 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/board.c | 111 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/clock.c | 25 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/clock_sun4i.c | 188 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/config.mk | 8 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/cpu_info.c | 19 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/dram.c | 593 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/pinmux.c | 61 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/start.c | 1 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/timer.c | 113 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds | 77 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/u-boot-spl.lds | 52 |
14 files changed, 1284 insertions, 1 deletions
diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile index ab869b1..232118d 100644 --- a/arch/arm/cpu/armv7/Makefile +++ b/arch/arm/cpu/armv7/Makefile @@ -12,7 +12,7 @@ obj-y += cache_v7.o obj-y += cpu.o obj-y += syslib.o -ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY),) +ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY)$(CONFIG_SUNXI),) ifneq ($(CONFIG_SKIP_LOWLEVEL_INIT),y) obj-y += lowlevel_init.o endif diff --git a/arch/arm/cpu/armv7/at91/config.mk b/arch/arm/cpu/armv7/at91/config.mk new file mode 100644 index 0000000..09eab70 --- /dev/null +++ b/arch/arm/cpu/armv7/at91/config.mk @@ -0,0 +1,10 @@ +# +# Copyright (C) 2014, Andreas Bießmann <andreas.devel@googlemail.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# +ifdef CONFIG_SPL_BUILD +ALL-y += boot.bin +else +ALL-y += u-boot.img +endif diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile new file mode 100644 index 0000000..a64bfa1 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -0,0 +1,25 @@ +# +# (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net> +# +# Based on some other Makefile +# (C) Copyright 2000-2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# +obj-y += timer.o +obj-y += board.o +obj-y += clock.o +obj-y += pinmux.o +obj-$(CONFIG_SUN7I) += clock_sun4i.o + +ifndef CONFIG_SPL_BUILD +obj-y += cpu_info.o +endif + +ifdef CONFIG_SPL_BUILD +obj-$(CONFIG_SUN7I) += dram.o +ifdef CONFIG_SPL_FEL +obj-y += start.o +endif +endif diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c new file mode 100644 index 0000000..49c9448 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -0,0 +1,111 @@ +/* + * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net> + * + * (C) Copyright 2007-2011 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + * + * Some init for sunxi platform. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <netdev.h> +#include <miiphy.h> +#include <serial.h> +#ifdef CONFIG_SPL_BUILD +#include <spl.h> +#endif +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/gpio.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/timer.h> + +#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, nand 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 confirmation data available in SPL yet. Hardcode bootmode */ +u32 spl_boot_mode(void) +{ + return MMCSD_MODE_RAW; +} +#endif + +int gpio_init(void) +{ + sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUN4I_GPB22_UART0_TX); + sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUN4I_GPB23_UART0_RX); + sunxi_gpio_set_pull(SUNXI_GPB(23), 1); + + return 0; +} + +void reset_cpu(ulong addr) +{ +} + +/* do some early init */ +void s_init(void) +{ +#if !defined CONFIG_SPL_BUILD && (defined CONFIG_SUN7I || defined CONFIG_SUN6I) + /* Enable SMP mode for CPU0, by setting bit 6 of Auxiliary Ctl reg */ + asm volatile( + "mrc p15, 0, r0, c1, c0, 1\n" + "orr r0, r0, #1 << 6\n" + "mcr p15, 0, r0, c1, c0, 1\n"); +#endif + + clock_init(); + timer_init(); + gpio_init(); + +#ifdef CONFIG_SPL_BUILD + gd = &gdata; + preloader_console_init(); + + sunxi_board_init(); +#endif +} + +#ifndef CONFIG_SYS_DCACHE_OFF +void enable_caches(void) +{ + /* Enable D-cache. I-cache is already enabled in start.S */ + dcache_enable(); +} +#endif + +#ifdef CONFIG_CMD_NET +/* + * Initializes on-chip ethernet controllers. + * to override, implement board_eth_init() + */ +int cpu_eth_init(bd_t *bis) +{ + int rc; + +#ifdef CONFIG_SUNXI_GMAC + rc = sunxi_gmac_initialize(bis); + if (rc < 0) { + printf("sunxi: failed to initialize gmac\n"); + return rc; + } +#endif + + return 0; +} +#endif diff --git a/arch/arm/cpu/armv7/sunxi/clock.c b/arch/arm/cpu/armv7/sunxi/clock.c new file mode 100644 index 0000000..47fb70f --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/clock.c @@ -0,0 +1,25 @@ +/* + * (C) Copyright 2007-2012 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + * + * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/gpio.h> +#include <asm/arch/sys_proto.h> + +int clock_init(void) +{ +#ifdef CONFIG_SPL_BUILD + clock_init_safe(); +#endif + clock_init_uart(); + + return 0; +} diff --git a/arch/arm/cpu/armv7/sunxi/clock_sun4i.c b/arch/arm/cpu/armv7/sunxi/clock_sun4i.c new file mode 100644 index 0000000..5a7da3c --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/clock_sun4i.c @@ -0,0 +1,188 @@ +/* + * sun4i, sun5i and sun7i specific clock code + * + * (C) Copyright 2007-2012 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + * + * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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 +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 << AXI_DIV_SHIFT | + AHB_DIV_2 << AHB_DIV_SHIFT | + APB0_DIV_1 << APB0_DIV_SHIFT | + CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT, + &ccm->cpu_ahb_apb0_cfg); + writel(PLL1_CFG_DEFAULT, &ccm->pll1_cfg); + sdelay(200); + writel(AXI_DIV_1 << AXI_DIV_SHIFT | + AHB_DIV_2 << AHB_DIV_SHIFT | + APB0_DIV_1 << APB0_DIV_SHIFT | + CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT, + &ccm->cpu_ahb_apb0_cfg); +#ifdef CONFIG_SUN7I + writel(0x1 << AHB_GATE_OFFSET_DMA | readl(&ccm->ahb_gate0), + &ccm->ahb_gate0); +#endif + writel(PLL6_CFG_DEFAULT, &ccm->pll6_cfg); +} +#endif + +void clock_init_uart(void) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + + /* uart clock source is apb1 */ + writel(APB1_CLK_SRC_OSC24M| + APB1_CLK_RATE_N_1| + APB1_CLK_RATE_M(1), + &ccm->apb1_clk_div_cfg); + + /* open the clock for uart */ + setbits_le32(&ccm->apb1_gate, + CLK_GATE_OPEN << (APB1_GATE_UART_SHIFT+CONFIG_CONS_INDEX-1)); +} + +int clock_twi_onoff(int port, int state) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + + if (port > 2) + return -1; + + /* set the apb clock gate for twi */ + if (state) + setbits_le32(&ccm->apb1_gate, + CLK_GATE_OPEN << (APB1_GATE_TWI_SHIFT+port)); + else + clrbits_le32(&ccm->apb1_gate, + CLK_GATE_OPEN << (APB1_GATE_TWI_SHIFT+port)); + + return 0; +} + +#ifdef CONFIG_SPL_BUILD +#define PLL1_CFG(N, K, M, P) ( 1 << CCM_PLL1_CFG_ENABLE_SHIFT | \ + 0 << CCM_PLL1_CFG_VCO_RST_SHIFT | \ + 8 << CCM_PLL1_CFG_VCO_BIAS_SHIFT | \ + 0 << CCM_PLL1_CFG_PLL4_EXCH_SHIFT | \ + 16 << CCM_PLL1_CFG_BIAS_CUR_SHIFT | \ + (P)<< CCM_PLL1_CFG_DIVP_SHIFT | \ + 2 << CCM_PLL1_CFG_LCK_TMR_SHIFT | \ + (N)<< CCM_PLL1_CFG_FACTOR_N_SHIFT | \ + (K)<< CCM_PLL1_CFG_FACTOR_K_SHIFT | \ + 0 << CCM_PLL1_CFG_SIG_DELT_PAT_IN_SHIFT | \ + 0 << CCM_PLL1_CFG_SIG_DELT_PAT_EN_SHIFT | \ + (M)<< CCM_PLL1_CFG_FACTOR_M_SHIFT) + +static struct { + u32 pll1_cfg; + unsigned int freq; +} pll1_para[] = { + /* This array must be ordered by frequency. */ + { 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}, + /* Final catchall entry */ + { PLL1_CFG(31, 1, 0, 0), ~0}, +}; + +void clock_set_pll1(unsigned 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 = DIV_ROUND_UP(hz, 432000000); /* Max 450MHz */ + ahb = DIV_ROUND_UP(hz/axi, 204000000); /* Max 250MHz */ + apb0 = 2; /* Max 150MHz */ + + printf("CPU: %uHz, AXI/AHB/APB: %d/%d/%d\n", hz, axi, ahb, apb0); + + /* 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 << AXI_DIV_SHIFT | + AHB_DIV_2 << AHB_DIV_SHIFT | + APB0_DIV_1 << APB0_DIV_SHIFT | + CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT, + &ccm->cpu_ahb_apb0_cfg); + sdelay(20); + + /* Configure sys clock divisors */ + writel(axi << AXI_DIV_SHIFT | + ahb << AHB_DIV_SHIFT | + apb0 << APB0_DIV_SHIFT | + CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT, + &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 << AXI_DIV_SHIFT | + ahb << AHB_DIV_SHIFT | + apb0 << APB0_DIV_SHIFT | + CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT, + &ccm->cpu_ahb_apb0_cfg); + sdelay(20); +} +#endif + +unsigned int clock_get_pll6(void) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + uint32_t rval = readl(&ccm->pll6_cfg); + int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT); + int k = ((rval & CCM_PLL6_CTRL_K_MASK) >> CCM_PLL6_CTRL_K_SHIFT) + 1; + return 24000000 * n * k / 2; +} diff --git a/arch/arm/cpu/armv7/sunxi/config.mk b/arch/arm/cpu/armv7/sunxi/config.mk new file mode 100644 index 0000000..00f5ffc --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/config.mk @@ -0,0 +1,8 @@ +# Build a combined spl + u-boot image +ifdef CONFIG_SPL +ifndef CONFIG_SPL_BUILD +ifndef CONFIG_SPL_FEL +ALL-y += u-boot-sunxi-with-spl.bin +endif +endif +endif diff --git a/arch/arm/cpu/armv7/sunxi/cpu_info.c b/arch/arm/cpu/armv7/sunxi/cpu_info.c new file mode 100644 index 0000000..b4c3d5c --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/cpu_info.c @@ -0,0 +1,19 @@ +/* + * (C) Copyright 2007-2011 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> + +#ifdef CONFIG_DISPLAY_CPUINFO +int print_cpuinfo(void) +{ + puts("CPU: Allwinner A20 (SUN7I)\n"); + return 0; +} +#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..b43c4b4 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -0,0 +1,593 @@ +/* + * sunxi DRAM controller initialization + * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net> + * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.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@allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * Unfortunately the only documentation we have on the sun7i DRAM + * controller is Allwinner boot0 + boot1 code, and that code uses + * magic numbers & shifts with no explanations. Hence this code is + * rather undocumented and full of magic. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/dram.h> +#include <asm/arch/timer.h> +#include <asm/arch/sys_proto.h> + +#define CPU_CFG_CHIP_VER(n) ((n) << 6) +#define CPU_CFG_CHIP_VER_MASK CPU_CFG_CHIP_VER(0x3) +#define CPU_CFG_CHIP_REV_A 0x0 +#define CPU_CFG_CHIP_REV_C1 0x1 +#define CPU_CFG_CHIP_REV_C2 0x2 +#define CPU_CFG_CHIP_REV_B 0x3 + +/* + * Wait up to 1s for mask to be clear in given reg. + */ +static void await_completion(u32 *reg, u32 mask) +{ + unsigned long tmo = timer_get_us() + 1000000; + + while (readl(reg) & mask) { + if (timer_get_us() > tmo) + panic("Timeout initialising DRAM\n"); + } +} + +static void mctl_ddr3_reset(void) +{ + struct sunxi_dram_reg *dram = + (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + + clrbits_le32(&dram->mcr, DRAM_MCR_RESET); + udelay(2); + setbits_le32(&dram->mcr, DRAM_MCR_RESET); +} + +static void mctl_set_drive(void) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + + clrsetbits_le32(&dram->mcr, DRAM_MCR_MODE_NORM(0x3) | (0x3 << 28), + DRAM_MCR_MODE_EN(0x3) | + 0xffc); +} + +static void mctl_itm_disable(void) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + + clrsetbits_le32(&dram->ccr, DRAM_CCR_INIT, DRAM_CCR_ITM_OFF); +} + +static void mctl_itm_enable(void) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + + clrbits_le32(&dram->ccr, DRAM_CCR_ITM_OFF); +} + +static void mctl_enable_dll0(u32 phase) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + + clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, + ((phase >> 16) & 0x3f) << 6); + clrsetbits_le32(&dram->dllcr[0], DRAM_DLLCR_NRESET, DRAM_DLLCR_DISABLE); + udelay(2); + + clrbits_le32(&dram->dllcr[0], DRAM_DLLCR_NRESET | DRAM_DLLCR_DISABLE); + udelay(22); + + clrsetbits_le32(&dram->dllcr[0], DRAM_DLLCR_DISABLE, DRAM_DLLCR_NRESET); + udelay(22); +} + +/* + * Note: This differs from pm/standby in that it checks the bus width + */ +static void mctl_enable_dllx(u32 phase) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + u32 i, n, bus_width; + + bus_width = readl(&dram->dcr); + + if ((bus_width & DRAM_DCR_BUS_WIDTH_MASK) == + DRAM_DCR_BUS_WIDTH(DRAM_DCR_BUS_WIDTH_32BIT)) + n = DRAM_DCR_NR_DLLCR_32BIT; + else + n = DRAM_DCR_NR_DLLCR_16BIT; + + for (i = 1; i < n; i++) { + clrsetbits_le32(&dram->dllcr[i], 0xf << 14, + (phase & 0xf) << 14); + clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET, + DRAM_DLLCR_DISABLE); + phase >>= 4; + } + udelay(2); + + for (i = 1; i < n; i++) + clrbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET | + DRAM_DLLCR_DISABLE); + udelay(22); + + for (i = 1; i < n; i++) + clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_DISABLE, + DRAM_DLLCR_NRESET); + udelay(22); +} + +static u32 hpcr_value[32] = { +#ifdef CONFIG_SUN7I + 0x0301, 0x0301, 0x0301, 0x0301, + 0x0301, 0x0301, 0x0301, 0x0301, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0x1031, 0x1031, 0x0735, 0x1035, + 0x1035, 0x0731, 0x1031, 0x0735, + 0x1035, 0x1031, 0x0731, 0x1035, + 0x0001, 0x1031, 0, 0x1031 + /* last row differs from boot0 source table + * 0x1031, 0x0301, 0x0301, 0x0731 + * but boot0 code skips #28 and #30, and sets #29 and #31 to the + * value from #28 entry (0x1031) + */ +#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 &= ~CCM_PLL5_CTRL_M_MASK; /* set M to 0 (x1) */ + reg_val &= ~CCM_PLL5_CTRL_K_MASK; /* set K to 0 (x1) */ + reg_val &= ~CCM_PLL5_CTRL_N_MASK; /* set N to 0 (x0) */ + reg_val &= ~CCM_PLL5_CTRL_P_MASK; /* set P to 0 (x1) */ + if (clk >= 540 && clk < 552) { + /* dram = 540MHz, pll5p = 540MHz */ + reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); + reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3)); + reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(15)); + reg_val |= CCM_PLL5_CTRL_P(1); + } else if (clk >= 512 && clk < 528) { + /* dram = 512MHz, pll5p = 384MHz */ + reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(3)); + reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(4)); + reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(16)); + reg_val |= CCM_PLL5_CTRL_P(2); + } else if (clk >= 496 && clk < 504) { + /* dram = 496MHz, pll5p = 372MHz */ + reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(3)); + reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2)); + reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(31)); + reg_val |= CCM_PLL5_CTRL_P(2); + } else if (clk >= 468 && clk < 480) { + /* dram = 468MHz, pll5p = 468MHz */ + reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); + reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3)); + reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(13)); + reg_val |= CCM_PLL5_CTRL_P(1); + } else if (clk >= 396 && clk < 408) { + /* dram = 396MHz, pll5p = 396MHz */ + reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); + reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3)); + reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(11)); + reg_val |= CCM_PLL5_CTRL_P(1); + } else { + /* any other frequency that is a multiple of 24 */ + reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); + reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2)); + reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(clk / 24)); + reg_val |= CCM_PLL5_CTRL_P(CCM_PLL5_CTRL_P_X(2)); + } + reg_val &= ~CCM_PLL5_CTRL_VCO_GAIN; /* PLL VCO Gain off */ + reg_val |= CCM_PLL5_CTRL_EN; /* PLL On */ + writel(reg_val, &ccm->pll5_cfg); + udelay(5500); + + setbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_DDR_CLK); + +#if defined(CONFIG_SUN4I) || defined(CONFIG_SUN7I) + /* reset GPS */ + clrbits_le32(&ccm->gps_clk_cfg, CCM_GPS_CTRL_RESET | CCM_GPS_CTRL_GATE); + setbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_GPS); + udelay(1); + clrbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_GPS); +#endif + + /* setup MBUS clock */ + reg_val = CCM_MBUS_CTRL_GATE | + CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL6) | + CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(2)) | + CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(2)); + writel(reg_val, &ccm->mbus_clk_cfg); + + /* + * open DRAMC AHB & DLL register clock + * close it first + */ + clrbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_SDRAM | CCM_AHB_GATE_DLL); + udelay(22); + + /* then open it */ + setbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_SDRAM | CCM_AHB_GATE_DLL); + udelay(22); +} + +static int dramc_scan_readpipe(void) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + u32 reg_val; + + /* data training trigger */ +#ifdef CONFIG_SUN7I + clrbits_le32(&dram->csr, DRAM_CSR_FAILED); +#endif + setbits_le32(&dram->ccr, DRAM_CCR_DATA_TRAINING); + + /* check whether data training process has completed */ + await_completion(&dram->ccr, DRAM_CCR_DATA_TRAINING); + + /* check data training result */ + reg_val = readl(&dram->csr); + if (reg_val & DRAM_CSR_FAILED) + return -1; + + return 0; +} + +static int dramc_scan_dll_para(void) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + const u32 dqs_dly[7] = {0x3, 0x2, 0x1, 0x0, 0xe, 0xd, 0xc}; + const u32 clk_dly[15] = {0x07, 0x06, 0x05, 0x04, 0x03, + 0x02, 0x01, 0x00, 0x08, 0x10, + 0x18, 0x20, 0x28, 0x30, 0x38}; + u32 clk_dqs_count[15]; + u32 dqs_i, clk_i, cr_i; + u32 max_val, min_val; + u32 dqs_index, clk_index; + + /* Find DQS_DLY Pass Count for every CLK_DLY */ + for (clk_i = 0; clk_i < 15; clk_i++) { + clk_dqs_count[clk_i] = 0; + clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, + (clk_dly[clk_i] & 0x3f) << 6); + for (dqs_i = 0; dqs_i < 7; dqs_i++) { + for (cr_i = 1; cr_i < 5; cr_i++) { + clrsetbits_le32(&dram->dllcr[cr_i], + 0x4f << 14, + (dqs_dly[dqs_i] & 0x4f) << 14); + } + udelay(2); + if (dramc_scan_readpipe() == 0) + clk_dqs_count[clk_i]++; + } + } + /* Test DQS_DLY Pass Count for every CLK_DLY from up to down */ + for (dqs_i = 15; dqs_i > 0; dqs_i--) { + max_val = 15; + min_val = 15; + for (clk_i = 0; clk_i < 15; clk_i++) { + if (clk_dqs_count[clk_i] == dqs_i) { + max_val = clk_i; + if (min_val == 15) + min_val = clk_i; + } + } + if (max_val < 15) + break; + } + + /* Check if Find a CLK_DLY failed */ + if (!dqs_i) + goto fail; + + /* Find the middle index of CLK_DLY */ + clk_index = (max_val + min_val) >> 1; + if ((max_val == (15 - 1)) && (min_val > 0)) + /* if CLK_DLY[MCTL_CLK_DLY_COUNT] is very good, then the middle + * value can be more close to the max_val + */ + clk_index = (15 + clk_index) >> 1; + else if ((max_val < (15 - 1)) && (min_val == 0)) + /* if CLK_DLY[0] is very good, then the middle value can be more + * close to the min_val + */ + clk_index >>= 1; + if (clk_dqs_count[clk_index] < dqs_i) + clk_index = min_val; + + /* Find the middle index of DQS_DLY for the CLK_DLY got above, and Scan + * read pipe again + */ + clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, + (clk_dly[clk_index] & 0x3f) << 6); + max_val = 7; + min_val = 7; + for (dqs_i = 0; dqs_i < 7; dqs_i++) { + clk_dqs_count[dqs_i] = 0; + for (cr_i = 1; cr_i < 5; cr_i++) { + clrsetbits_le32(&dram->dllcr[cr_i], + 0x4f << 14, + (dqs_dly[dqs_i] & 0x4f) << 14); + } + udelay(2); + if (dramc_scan_readpipe() == 0) { + clk_dqs_count[dqs_i] = 1; + max_val = dqs_i; + if (min_val == 7) + min_val = dqs_i; + } + } + + if (max_val < 7) { + dqs_index = (max_val + min_val) >> 1; + if ((max_val == (7-1)) && (min_val > 0)) + dqs_index = (7 + dqs_index) >> 1; + else if ((max_val < (7-1)) && (min_val == 0)) + dqs_index >>= 1; + if (!clk_dqs_count[dqs_index]) + dqs_index = min_val; + for (cr_i = 1; cr_i < 5; cr_i++) { + clrsetbits_le32(&dram->dllcr[cr_i], + 0x4f << 14, + (dqs_dly[dqs_index] & 0x4f) << 14); + } + udelay(2); + return dramc_scan_readpipe(); + } + +fail: + clrbits_le32(&dram->dllcr[0], 0x3f << 6); + for (cr_i = 1; cr_i < 5; cr_i++) + clrbits_le32(&dram->dllcr[cr_i], 0x4f << 14); + udelay(2); + + return dramc_scan_readpipe(); +} + +static void dramc_clock_output_en(u32 on) +{ +#if defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I) + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + + if (on) + setbits_le32(&dram->mcr, DRAM_MCR_DCLK_OUT); + else + clrbits_le32(&dram->mcr, DRAM_MCR_DCLK_OUT); +#endif +} + +static const u16 tRFC_table[2][6] = { + /* 256Mb 512Mb 1Gb 2Gb 4Gb 8Gb */ + /* DDR2 75ns 105ns 127.5ns 195ns 327.5ns invalid */ + { 77, 108, 131, 200, 336, 336 }, + /* DDR3 invalid 90ns 110ns 160ns 300ns 350ns */ + { 93, 93, 113, 164, 308, 359 } +}; + +static void dramc_set_autorefresh_cycle(u32 clk, u32 type, u32 density) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + u32 tRFC, tREFI; + + tRFC = (tRFC_table[type][density] * clk + 1023) >> 10; + tREFI = (7987 * clk) >> 10; /* <= 7.8us */ + + writel(DRAM_DRR_TREFI(tREFI) | DRAM_DRR_TRFC(tRFC), &dram->drr); +} + +unsigned long dramc_init(struct dram_para *para) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + u32 reg_val; + u32 density; + int ret_val; + + /* check input dram parameter structure */ + if (!para) + return 0; + + /* setup DRAM relative clock */ + mctl_setup_dram_clock(para->clock); + + /* reset external DRAM */ + mctl_set_drive(); + + /* dram clock off */ + dramc_clock_output_en(0); + + mctl_itm_disable(); + mctl_enable_dll0(para->tpr3); + + /* configure external DRAM */ + reg_val = 0x0; + if (para->type == DRAM_MEMORY_TYPE_DDR3) + reg_val |= DRAM_DCR_TYPE_DDR3; + reg_val |= DRAM_DCR_IO_WIDTH(para->io_width >> 3); + + if (para->density == 256) + density = DRAM_DCR_CHIP_DENSITY_256M; + else if (para->density == 512) + density = DRAM_DCR_CHIP_DENSITY_512M; + else if (para->density == 1024) + density = DRAM_DCR_CHIP_DENSITY_1024M; + else if (para->density == 2048) + density = DRAM_DCR_CHIP_DENSITY_2048M; + else if (para->density == 4096) + density = DRAM_DCR_CHIP_DENSITY_4096M; + else if (para->density == 8192) + density = DRAM_DCR_CHIP_DENSITY_8192M; + else + density = DRAM_DCR_CHIP_DENSITY_256M; + + reg_val |= DRAM_DCR_CHIP_DENSITY(density); + reg_val |= DRAM_DCR_BUS_WIDTH((para->bus_width >> 3) - 1); + reg_val |= DRAM_DCR_RANK_SEL(para->rank_num - 1); + reg_val |= DRAM_DCR_CMD_RANK_ALL; + reg_val |= DRAM_DCR_MODE(DRAM_DCR_MODE_INTERLEAVE); + writel(reg_val, &dram->dcr); + +#ifdef CONFIG_SUN7I + setbits_le32(&dram->zqcr1, (0x1 << 24) | (0x1 << 1)); + if (para->tpr4 & 0x2) + clrsetbits_le32(&dram->zqcr1, (0x1 << 24), (0x1 << 1)); + dramc_clock_output_en(1); +#endif + +#if (defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I)) + /* 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_SUN7I + /* Set CKE Delay to about 1ms */ + setbits_le32(&dram->idcr, 0x1ffff); +#endif + +#ifdef CONFIG_SUN7I + if ((readl(&dram->ppwrsctl) & 0x1) != 0x1) + mctl_ddr3_reset(); + else + setbits_le32(&dram->mcr, DRAM_MCR_RESET); +#endif + + udelay(1); + + await_completion(&dram->ccr, DRAM_CCR_INIT); + + mctl_enable_dllx(para->tpr3); + + /* set refresh period */ + dramc_set_autorefresh_cycle(para->clock, para->type - 2, density); + + /* set timing parameters */ + writel(para->tpr0, &dram->tpr0); + writel(para->tpr1, &dram->tpr1); + writel(para->tpr2, &dram->tpr2); + + if (para->type == DRAM_MEMORY_TYPE_DDR3) { + reg_val = DRAM_MR_BURST_LENGTH(0x0); +#if (defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I)) + reg_val |= DRAM_MR_POWER_DOWN; +#endif + reg_val |= DRAM_MR_CAS_LAT(para->cas - 4); + reg_val |= DRAM_MR_WRITE_RECOVERY(0x5); + } else if (para->type == DRAM_MEMORY_TYPE_DDR2) { + reg_val = DRAM_MR_BURST_LENGTH(0x2); + reg_val |= DRAM_MR_CAS_LAT(para->cas); + reg_val |= DRAM_MR_WRITE_RECOVERY(0x5); + } + 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, DRAM_CCR_DQS_DRIFT_COMP, DRAM_CCR_DQS_GATE); + +#ifdef CONFIG_SUN7I + /* Command rate timing mode 2T & 1T */ + if (para->tpr4 & 0x1) + setbits_le32(&dram->ccr, DRAM_CCR_COMMAND_RATE_1T); +#endif + /* reset external DRAM */ + setbits_le32(&dram->ccr, DRAM_CCR_INIT); + await_completion(&dram->ccr, DRAM_CCR_INIT); + +#ifdef CONFIG_SUN7I + /* setup zq calibration manual */ + reg_val = readl(&dram->ppwrsctl); + if ((reg_val & 0x1) == 1) { + /* super_standby_flag = 1 */ + + reg_val = readl(0x01c20c00 + 0x120); /* rtc */ + reg_val &= 0x000fffff; + reg_val |= 0x17b00000; + writel(reg_val, &dram->zqcr0); + + /* exit self-refresh state */ + clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x12 << 27); + /* check whether command has been executed */ + await_completion(&dram->dcr, 0x1 << 31); + + udelay(2); + + /* dram pad hold off */ + setbits_le32(&dram->ppwrsctl, 0x16510000); + + await_completion(&dram->ppwrsctl, 0x1); + + /* exit self-refresh state */ + clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x12 << 27); + + /* check whether command has been executed */ + await_completion(&dram->dcr, 0x1 << 31); + + udelay(2); + + /* issue a refresh command */ + clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x13 << 27); + await_completion(&dram->dcr, 0x1 << 31); + + udelay(2); + } +#endif + + /* scan read pipe value */ + mctl_itm_enable(); + if (para->tpr3 & (0x1 << 31)) { + ret_val = dramc_scan_dll_para(); + if (ret_val == 0) + para->tpr3 = + (((readl(&dram->dllcr[0]) >> 6) & 0x3f) << 16) | + (((readl(&dram->dllcr[1]) >> 14) & 0xf) << 0) | + (((readl(&dram->dllcr[2]) >> 14) & 0xf) << 4) | + (((readl(&dram->dllcr[3]) >> 14) & 0xf) << 8) | + (((readl(&dram->dllcr[4]) >> 14) & 0xf) << 12 + ); + } else { + 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_0, PHYS_SDRAM_0_SIZE); +} diff --git a/arch/arm/cpu/armv7/sunxi/pinmux.c b/arch/arm/cpu/armv7/sunxi/pinmux.c new file mode 100644 index 0000000..1f2843f --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/pinmux.c @@ -0,0 +1,61 @@ +/* + * (C) Copyright 2007-2011 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/gpio.h> + +int sunxi_gpio_set_cfgpin(u32 pin, u32 val) +{ + u32 bank = GPIO_BANK(pin); + u32 index = GPIO_CFG_INDEX(pin); + u32 offset = GPIO_CFG_OFFSET(pin); + struct sunxi_gpio *pio = BANK_TO_GPIO(bank); + + clrsetbits_le32(&pio->cfg[0] + index, 0xf << offset, val << offset); + + return 0; +} + +int sunxi_gpio_get_cfgpin(u32 pin) +{ + u32 cfg; + u32 bank = GPIO_BANK(pin); + u32 index = GPIO_CFG_INDEX(pin); + u32 offset = GPIO_CFG_OFFSET(pin); + struct sunxi_gpio *pio = BANK_TO_GPIO(bank); + + cfg = readl(&pio->cfg[0] + index); + cfg >>= offset; + + return cfg & 0xf; +} + +int sunxi_gpio_set_drv(u32 pin, u32 val) +{ + u32 bank = GPIO_BANK(pin); + u32 index = GPIO_DRV_INDEX(pin); + u32 offset = GPIO_DRV_OFFSET(pin); + struct sunxi_gpio *pio = BANK_TO_GPIO(bank); + + clrsetbits_le32(&pio->drv[0] + index, 0x3 << offset, val << offset); + + return 0; +} + +int sunxi_gpio_set_pull(u32 pin, u32 val) +{ + u32 bank = GPIO_BANK(pin); + u32 index = GPIO_PULL_INDEX(pin); + u32 offset = GPIO_PULL_OFFSET(pin); + struct sunxi_gpio *pio = BANK_TO_GPIO(bank); + + clrsetbits_le32(&pio->pull[0] + index, 0x3 << offset, val << offset); + + return 0; +} diff --git a/arch/arm/cpu/armv7/sunxi/start.c b/arch/arm/cpu/armv7/sunxi/start.c new file mode 100644 index 0000000..6b392fa --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/start.c @@ -0,0 +1 @@ +/* Intentionally empty. Only needed to get FEL SPL link line right */ diff --git a/arch/arm/cpu/armv7/sunxi/timer.c b/arch/arm/cpu/armv7/sunxi/timer.c new file mode 100644 index 0000000..3626389 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/timer.c @@ -0,0 +1,113 @@ +/* + * (C) Copyright 2007-2011 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/timer.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define TIMER_MODE (0x0 << 7) /* continuous mode */ +#define TIMER_DIV (0x0 << 4) /* pre scale 1 */ +#define TIMER_SRC (0x1 << 2) /* osc24m */ +#define TIMER_RELOAD (0x1 << 1) /* reload internal value */ +#define TIMER_EN (0x1 << 0) /* enable timer */ + +#define TIMER_CLOCK (24 * 1000 * 1000) +#define COUNT_TO_USEC(x) ((x) / 24) +#define USEC_TO_COUNT(x) ((x) * 24) +#define TICKS_PER_HZ (TIMER_CLOCK / CONFIG_SYS_HZ) +#define TICKS_TO_HZ(x) ((x) / TICKS_PER_HZ) + +#define TIMER_LOAD_VAL 0xffffffff + +#define TIMER_NUM 0 /* we use timer 0 */ + +/* read the 32-bit timer */ +static ulong read_timer(void) +{ + struct sunxi_timer_reg *timers = + (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; + struct sunxi_timer *timer = &timers->timer[TIMER_NUM]; + + /* + * The hardware timer counts down, therefore we invert to + * produce an incrementing timer. + */ + return ~readl(&timer->val); +} + +/* init timer register */ +int timer_init(void) +{ + struct sunxi_timer_reg *timers = + (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; + struct sunxi_timer *timer = &timers->timer[TIMER_NUM]; + writel(TIMER_LOAD_VAL, &timer->inter); + writel(TIMER_MODE | TIMER_DIV | TIMER_SRC | TIMER_RELOAD | TIMER_EN, + &timer->ctl); + + return 0; +} + +/* timer without interrupts */ +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +ulong get_timer_masked(void) +{ + /* current tick value */ + ulong now = TICKS_TO_HZ(read_timer()); + + if (now >= gd->arch.lastinc) /* normal (non rollover) */ + gd->arch.tbl += (now - gd->arch.lastinc); + else { + /* rollover */ + gd->arch.tbl += (TICKS_TO_HZ(TIMER_LOAD_VAL) + - gd->arch.lastinc) + now; + } + gd->arch.lastinc = now; + + return gd->arch.tbl; +} + +/* delay x useconds */ +void __udelay(unsigned long usec) +{ + long tmo = USEC_TO_COUNT(usec); + ulong now, last = read_timer(); + + while (tmo > 0) { + now = read_timer(); + if (now > last) /* normal (non rollover) */ + tmo -= now - last; + else /* rollover */ + tmo -= TIMER_LOAD_VAL - last + now; + last = now; + } +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds new file mode 100644 index 0000000..364e35c --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2013 + * Henrik Nordstrom <henrik@henriknordstrom.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(s_init) +SECTIONS +{ + . = 0x00002000; + + . = ALIGN(4); + .text : + { + *(.text.s_init) + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { + *(.data*) + } + + . = ALIGN(4); + . = .; + + . = ALIGN(4); + .rel.dyn : { + __rel_dyn_start = .; + *(.rel*) + __rel_dyn_end = .; + } + + .dynsym : { + __dynsym_start = .; + *(.dynsym) + } + + . = ALIGN(4); + .note.gnu.build-id : + { + *(.note.gnu.build-id) + } + _end = .; + + . = ALIGN(4096); + .mmutable : { + *(.mmutable) + } + + .bss_start __rel_dyn_start (OVERLAY) : { + KEEP(*(.__bss_start)); + __bss_base = .; + } + + .bss __bss_base (OVERLAY) : { + *(.bss*) + . = ALIGN(4); + __bss_limit = .; + } + + .bss_end __bss_limit (OVERLAY) : { + KEEP(*(.__bss_end)); + } + + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } + /DISCARD/ : { *(.note*) } +} 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..5008028 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2012 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + * + * Based on omap-common/u-boot-spl.lds: + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * Aneesh V <aneesh@ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ +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 +} |