commit
90b51c33f3
@ -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 |
@ -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 |
@ -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 |
@ -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; |
||||
} |
@ -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; |
||||
} |
@ -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 |
@ -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 |
@ -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); |
||||
} |
@ -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; |
||||
} |
@ -0,0 +1 @@ |
||||
/* Intentionally empty. Only needed to get FEL SPL link line right */ |
@ -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; |
||||
} |
@ -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*) } |
||||
} |
@ -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 |
||||
} |
@ -0,0 +1,29 @@ |
||||
/*
|
||||
* (C) Copyright 2007-2011 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Tom Cubie <tangliang@allwinnertech.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _SUNXI_CLOCK_H |
||||
#define _SUNXI_CLOCK_H |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
#define CLK_GATE_OPEN 0x1 |
||||
#define CLK_GATE_CLOSE 0x0 |
||||
|
||||
/* clock control module regs definition */ |
||||
#include <asm/arch/clock_sun4i.h> |
||||
|
||||
#ifndef __ASSEMBLY__ |
||||
int clock_init(void); |
||||
int clock_twi_onoff(int port, int state); |
||||
void clock_set_pll1(unsigned int hz); |
||||
unsigned int clock_get_pll6(void); |
||||
void clock_init_safe(void); |
||||
void clock_init_uart(void); |
||||
#endif |
||||
|
||||
#endif /* _SUNXI_CLOCK_H */ |
@ -0,0 +1,256 @@ |
||||
/*
|
||||
* sun4i, sun5i and sun7i clock register definitions |
||||
* |
||||
* (C) Copyright 2007-2011 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Tom Cubie <tangliang@allwinnertech.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _SUNXI_CLOCK_SUN4I_H |
||||
#define _SUNXI_CLOCK_SUN4I_H |
||||
|
||||
struct sunxi_ccm_reg { |
||||
u32 pll1_cfg; /* 0x00 pll1 control */ |
||||
u32 pll1_tun; /* 0x04 pll1 tuning */ |
||||
u32 pll2_cfg; /* 0x08 pll2 control */ |
||||
u32 pll2_tun; /* 0x0c pll2 tuning */ |
||||
u32 pll3_cfg; /* 0x10 pll3 control */ |
||||
u8 res0[0x4]; |
||||
u32 pll4_cfg; /* 0x18 pll4 control */ |
||||
u8 res1[0x4]; |
||||
u32 pll5_cfg; /* 0x20 pll5 control */ |
||||
u32 pll5_tun; /* 0x24 pll5 tuning */ |
||||
u32 pll6_cfg; /* 0x28 pll6 control */ |
||||
u32 pll6_tun; /* 0x2c pll6 tuning */ |
||||
u32 pll7_cfg; /* 0x30 pll7 control */ |
||||
u32 pll1_tun2; /* 0x34 pll5 tuning2 */ |
||||
u8 res2[0x4]; |
||||
u32 pll5_tun2; /* 0x3c pll5 tuning2 */ |
||||
u8 res3[0xc]; |
||||
u32 pll_lock_dbg; /* 0x4c pll lock time debug */ |
||||
u32 osc24m_cfg; /* 0x50 osc24m control */ |
||||
u32 cpu_ahb_apb0_cfg; /* 0x54 cpu,ahb and apb0 divide ratio */ |
||||
u32 apb1_clk_div_cfg; /* 0x58 apb1 clock dividor */ |
||||
u32 axi_gate; /* 0x5c axi module clock gating */ |
||||
u32 ahb_gate0; /* 0x60 ahb module clock gating 0 */ |
||||
u32 ahb_gate1; /* 0x64 ahb module clock gating 1 */ |
||||
u32 apb0_gate; /* 0x68 apb0 module clock gating */ |
||||
u32 apb1_gate; /* 0x6c apb1 module clock gating */ |
||||
u8 res4[0x10]; |
||||
u32 nand_sclk_cfg; /* 0x80 nand sub clock control */ |
||||
u32 ms_sclk_cfg; /* 0x84 memory stick sub clock control */ |
||||
u32 sd0_clk_cfg; /* 0x88 sd0 clock control */ |
||||
u32 sd1_clk_cfg; /* 0x8c sd1 clock control */ |
||||
u32 sd2_clk_cfg; /* 0x90 sd2 clock control */ |
||||
u32 sd3_clk_cfg; /* 0x94 sd3 clock control */ |
||||
u32 ts_clk_cfg; /* 0x98 transport stream clock control */ |
||||
u32 ss_clk_cfg; /* 0x9c */ |
||||
u32 spi0_clk_cfg; /* 0xa0 */ |
||||
u32 spi1_clk_cfg; /* 0xa4 */ |
||||
u32 spi2_clk_cfg; /* 0xa8 */ |
||||
u32 pata_clk_cfg; /* 0xac */ |
||||
u32 ir0_clk_cfg; /* 0xb0 */ |
||||
u32 ir1_clk_cfg; /* 0xb4 */ |
||||
u32 iis_clk_cfg; /* 0xb8 */ |
||||
u32 ac97_clk_cfg; /* 0xbc */ |
||||
u32 spdif_clk_cfg; /* 0xc0 */ |
||||
u32 keypad_clk_cfg; /* 0xc4 */ |
||||
u32 sata_clk_cfg; /* 0xc8 */ |
||||
u32 usb_clk_cfg; /* 0xcc */ |
||||
u32 gps_clk_cfg; /* 0xd0 */ |
||||
u32 spi3_clk_cfg; /* 0xd4 */ |
||||
u8 res5[0x28]; |
||||
u32 dram_clk_cfg; /* 0x100 */ |
||||
u32 be0_clk_cfg; /* 0x104 */ |
||||
u32 be1_clk_cfg; /* 0x108 */ |
||||
u32 fe0_clk_cfg; /* 0x10c */ |
||||
u32 fe1_clk_cfg; /* 0x110 */ |
||||
u32 mp_clk_cfg; /* 0x114 */ |
||||
u32 lcd0_ch0_clk_cfg; /* 0x118 */ |
||||
u32 lcd1_ch0_clk_cfg; /* 0x11c */ |
||||
u32 csi_isp_clk_cfg; /* 0x120 */ |
||||
u8 res6[0x4]; |
||||
u32 tvd_clk_reg; /* 0x128 */ |
||||
u32 lcd0_ch1_clk_cfg; /* 0x12c */ |
||||
u32 lcd1_ch1_clk_cfg; /* 0x130 */ |
||||
u32 csi0_clk_cfg; /* 0x134 */ |
||||
u32 csi1_clk_cfg; /* 0x138 */ |
||||
u32 ve_clk_cfg; /* 0x13c */ |
||||
u32 audio_codec_clk_cfg; /* 0x140 */ |
||||
u32 avs_clk_cfg; /* 0x144 */ |
||||
u32 ace_clk_cfg; /* 0x148 */ |
||||
u32 lvds_clk_cfg; /* 0x14c */ |
||||
u32 hdmi_clk_cfg; /* 0x150 */ |
||||
u32 mali_clk_cfg; /* 0x154 */ |
||||
u8 res7[0x4]; |
||||
u32 mbus_clk_cfg; /* 0x15c */ |
||||
u8 res8[0x4]; |
||||
u32 gmac_clk_cfg; /* 0x164 */ |
||||
}; |
||||
|
||||
/* apb1 bit field */ |
||||
#define APB1_CLK_SRC_OSC24M (0x0 << 24) |
||||
#define APB1_CLK_SRC_PLL6 (0x1 << 24) |
||||
#define APB1_CLK_SRC_LOSC (0x2 << 24) |
||||
#define APB1_CLK_SRC_MASK (0x3 << 24) |
||||
#define APB1_CLK_RATE_N_1 (0x0 << 16) |
||||
#define APB1_CLK_RATE_N_2 (0x1 << 16) |
||||
#define APB1_CLK_RATE_N_4 (0x2 << 16) |
||||
#define APB1_CLK_RATE_N_8 (0x3 << 16) |
||||
#define APB1_CLK_RATE_N_MASK (3 << 16) |
||||
#define APB1_CLK_RATE_M(m) (((m)-1) << 0) |
||||
#define APB1_CLK_RATE_M_MASK (0x1f << 0) |
||||
|
||||
/* apb1 gate field */ |
||||
#define APB1_GATE_UART_SHIFT (16) |
||||
#define APB1_GATE_UART_MASK (0xff << APB1_GATE_UART_SHIFT) |
||||
#define APB1_GATE_TWI_SHIFT (0) |
||||
#define APB1_GATE_TWI_MASK (0xf << APB1_GATE_TWI_SHIFT) |
||||
|
||||
/* clock divide */ |
||||
#define AXI_DIV_SHIFT (0) |
||||
#define AXI_DIV_1 0 |
||||
#define AXI_DIV_2 1 |
||||
#define AXI_DIV_3 2 |
||||
#define AXI_DIV_4 3 |
||||
#define AHB_DIV_SHIFT (4) |
||||
#define AHB_DIV_1 0 |
||||
#define AHB_DIV_2 1 |
||||
#define AHB_DIV_4 2 |
||||
#define AHB_DIV_8 3 |
||||
#define APB0_DIV_SHIFT (8) |
||||
#define APB0_DIV_1 0 |
||||
#define APB0_DIV_2 1 |
||||
#define APB0_DIV_4 2 |
||||
#define APB0_DIV_8 3 |
||||
#define CPU_CLK_SRC_SHIFT (16) |
||||
#define CPU_CLK_SRC_OSC24M 1 |
||||
#define CPU_CLK_SRC_PLL1 2 |
||||
|
||||
#define CCM_PLL1_CFG_ENABLE_SHIFT 31 |
||||
#define CCM_PLL1_CFG_VCO_RST_SHIFT 30 |
||||
#define CCM_PLL1_CFG_VCO_BIAS_SHIFT 26 |
||||
#define CCM_PLL1_CFG_PLL4_EXCH_SHIFT 25 |
||||
#define CCM_PLL1_CFG_BIAS_CUR_SHIFT 20 |
||||
#define CCM_PLL1_CFG_DIVP_SHIFT 16 |
||||
#define CCM_PLL1_CFG_LCK_TMR_SHIFT 13 |
||||
#define CCM_PLL1_CFG_FACTOR_N_SHIFT 8 |
||||
#define CCM_PLL1_CFG_FACTOR_K_SHIFT 4 |
||||
#define CCM_PLL1_CFG_SIG_DELT_PAT_IN_SHIFT 3 |
||||
#define CCM_PLL1_CFG_SIG_DELT_PAT_EN_SHIFT 2 |
||||
#define CCM_PLL1_CFG_FACTOR_M_SHIFT 0 |
||||
|
||||
#define PLL1_CFG_DEFAULT 0xa1005000 |
||||
|
||||
#define PLL6_CFG_DEFAULT 0xa1009911 |
||||
|
||||
/* nand clock */ |
||||
#define NAND_CLK_SRC_OSC24 0 |
||||
#define NAND_CLK_DIV_N 0 |
||||
#define NAND_CLK_DIV_M 0 |
||||
|
||||
/* gps clock */ |
||||
#define GPS_SCLK_GATING_OFF 0 |
||||
#define GPS_RESET 0 |
||||
|
||||
/* ahb clock gate bit offset */ |
||||
#define AHB_GATE_OFFSET_GPS 26 |
||||
#define AHB_GATE_OFFSET_SATA 25 |
||||
#define AHB_GATE_OFFSET_PATA 24 |
||||
#define AHB_GATE_OFFSET_SPI3 23 |
||||
#define AHB_GATE_OFFSET_SPI2 22 |
||||
#define AHB_GATE_OFFSET_SPI1 21 |
||||
#define AHB_GATE_OFFSET_SPI0 20 |
||||
#define AHB_GATE_OFFSET_TS0 18 |
||||
#define AHB_GATE_OFFSET_EMAC 17 |
||||
#define AHB_GATE_OFFSET_ACE 16 |
||||
#define AHB_GATE_OFFSET_DLL 15 |
||||
#define AHB_GATE_OFFSET_SDRAM 14 |
||||
#define AHB_GATE_OFFSET_NAND 13 |
||||
#define AHB_GATE_OFFSET_MS 12 |
||||
#define AHB_GATE_OFFSET_MMC3 11 |
||||
#define AHB_GATE_OFFSET_MMC2 10 |
||||
#define AHB_GATE_OFFSET_MMC1 9 |
||||
#define AHB_GATE_OFFSET_MMC0 8 |
||||
#define AHB_GATE_OFFSET_MMC(n) (AHB_GATE_OFFSET_MMC0 + (n)) |
||||
#define AHB_GATE_OFFSET_BIST 7 |
||||
#define AHB_GATE_OFFSET_DMA 6 |
||||
#define AHB_GATE_OFFSET_SS 5 |
||||
#define AHB_GATE_OFFSET_USB_OHCI1 4 |
||||
#define AHB_GATE_OFFSET_USB_EHCI1 3 |
||||
#define AHB_GATE_OFFSET_USB_OHCI0 2 |
||||
#define AHB_GATE_OFFSET_USB_EHCI0 1 |
||||
#define AHB_GATE_OFFSET_USB 0 |
||||
|
||||
/* ahb clock gate bit offset (second register) */ |
||||
#define AHB_GATE_OFFSET_GMAC 17 |
||||
|
||||
#define CCM_AHB_GATE_GPS (0x1 << 26) |
||||
#define CCM_AHB_GATE_SDRAM (0x1 << 14) |
||||
#define CCM_AHB_GATE_DLL (0x1 << 15) |
||||
#define CCM_AHB_GATE_ACE (0x1 << 16) |
||||
|
||||
#define CCM_PLL5_CTRL_M(n) (((n) & 0x3) << 0) |
||||
#define CCM_PLL5_CTRL_M_MASK CCM_PLL5_CTRL_M(0x3) |
||||
#define CCM_PLL5_CTRL_M_X(n) ((n) - 1) |
||||
#define CCM_PLL5_CTRL_M1(n) (((n) & 0x3) << 2) |
||||
#define CCM_PLL5_CTRL_M1_MASK CCM_PLL5_CTRL_M1(0x3) |
||||
#define CCM_PLL5_CTRL_M1_X(n) ((n) - 1) |
||||
#define CCM_PLL5_CTRL_K(n) (((n) & 0x3) << 4) |
||||
#define CCM_PLL5_CTRL_K_MASK CCM_PLL5_CTRL_K(0x3) |
||||
#define CCM_PLL5_CTRL_K_X(n) ((n) - 1) |
||||
#define CCM_PLL5_CTRL_LDO (0x1 << 7) |
||||
#define CCM_PLL5_CTRL_N(n) (((n) & 0x1f) << 8) |
||||
#define CCM_PLL5_CTRL_N_MASK CCM_PLL5_CTRL_N(0x1f) |
||||
#define CCM_PLL5_CTRL_N_X(n) (n) |
||||
#define CCM_PLL5_CTRL_P(n) (((n) & 0x3) << 16) |
||||
#define CCM_PLL5_CTRL_P_MASK CCM_PLL5_CTRL_P(0x3) |
||||
#define CCM_PLL5_CTRL_P_X(n) ((n) - 1) |
||||
#define CCM_PLL5_CTRL_BW (0x1 << 18) |
||||
#define CCM_PLL5_CTRL_VCO_GAIN (0x1 << 19) |
||||
#define CCM_PLL5_CTRL_BIAS(n) (((n) & 0x1f) << 20) |
||||
#define CCM_PLL5_CTRL_BIAS_MASK CCM_PLL5_CTRL_BIAS(0x1f) |
||||
#define CCM_PLL5_CTRL_BIAS_X(n) ((n) - 1) |
||||
#define CCM_PLL5_CTRL_VCO_BIAS (0x1 << 25) |
||||
#define CCM_PLL5_CTRL_DDR_CLK (0x1 << 29) |
||||
#define CCM_PLL5_CTRL_BYPASS (0x1 << 30) |
||||
#define CCM_PLL5_CTRL_EN (0x1 << 31) |
||||
|
||||
#define CCM_PLL6_CTRL_N_SHIFT 8 |
||||
#define CCM_PLL6_CTRL_N_MASK (0x1f << CCM_PLL6_CTRL_N_SHIFT) |
||||
#define CCM_PLL6_CTRL_K_SHIFT 4 |
||||
#define CCM_PLL6_CTRL_K_MASK (0x3 << CCM_PLL6_CTRL_K_SHIFT) |
||||
|
||||
#define CCM_GPS_CTRL_RESET (0x1 << 0) |
||||
#define CCM_GPS_CTRL_GATE (0x1 << 1) |
||||
|
||||
#define CCM_DRAM_CTRL_DCLK_OUT (0x1 << 15) |
||||
|
||||
#define CCM_MBUS_CTRL_M(n) (((n) & 0xf) << 0) |
||||
#define CCM_MBUS_CTRL_M_MASK CCM_MBUS_CTRL_M(0xf) |
||||
#define CCM_MBUS_CTRL_M_X(n) ((n) - 1) |
||||
#define CCM_MBUS_CTRL_N(n) (((n) & 0xf) << 16) |
||||
#define CCM_MBUS_CTRL_N_MASK CCM_MBUS_CTRL_N(0xf) |
||||
#define CCM_MBUS_CTRL_N_X(n) (((n) >> 3) ? 3 : (((n) >> 2) ? 2 : (((n) >> 1) ? 1 : 0))) |
||||
#define CCM_MBUS_CTRL_CLK_SRC(n) (((n) & 0x3) << 24) |
||||
#define CCM_MBUS_CTRL_CLK_SRC_MASK CCM_MBUS_CTRL_CLK_SRC(0x3) |
||||
#define CCM_MBUS_CTRL_CLK_SRC_HOSC 0x0 |
||||
#define CCM_MBUS_CTRL_CLK_SRC_PLL6 0x1 |
||||
#define CCM_MBUS_CTRL_CLK_SRC_PLL5 0x2 |
||||
#define CCM_MBUS_CTRL_GATE (0x1 << 31) |
||||
|
||||
#define CCM_MMC_CTRL_OSCM24 (0x0 << 24) |
||||
#define CCM_MMC_CTRL_PLL6 (0x1 << 24) |
||||
#define CCM_MMC_CTRL_PLL5 (0x2 << 24) |
||||
|
||||
#define CCM_MMC_CTRL_ENABLE (0x1 << 31) |
||||
|
||||
#define CCM_GMAC_CTRL_TX_CLK_SRC_MII 0x0 |
||||
#define CCM_GMAC_CTRL_TX_CLK_SRC_EXT_RGMII 0x1 |
||||
#define CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII 0x2 |
||||
#define CCM_GMAC_CTRL_GPIT_MII (0x0 << 2) |
||||
#define CCM_GMAC_CTRL_GPIT_RGMII (0x1 << 2) |
||||
|
||||
#endif /* _SUNXI_CLOCK_SUN4I_H */ |
@ -0,0 +1,122 @@ |
||||
/*
|
||||
* (C) Copyright 2007-2011 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Tom Cubie <tangliang@allwinnertech.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _SUNXI_CPU_H |
||||
#define _SUNXI_CPU_H |
||||
|
||||
#define SUNXI_SRAM_A1_BASE 0x00000000 |
||||
#define SUNXI_SRAM_A1_SIZE (16 * 1024) /* 16 kiB */ |
||||
|
||||
#define SUNXI_SRAM_A2_BASE 0x00004000 /* 16 kiB */ |
||||
#define SUNXI_SRAM_A3_BASE 0x00008000 /* 13 kiB */ |
||||
#define SUNXI_SRAM_A4_BASE 0x0000b400 /* 3 kiB */ |
||||
#define SUNXI_SRAM_D_BASE 0x00010000 /* 4 kiB */ |
||||
#define SUNXI_SRAM_B_BASE 0x00020000 /* 64 kiB (secure) */ |
||||
|
||||
#define SUNXI_SRAMC_BASE 0x01c00000 |
||||
#define SUNXI_DRAMC_BASE 0x01c01000 |
||||
#define SUNXI_DMA_BASE 0x01c02000 |
||||
#define SUNXI_NFC_BASE 0x01c03000 |
||||
#define SUNXI_TS_BASE 0x01c04000 |
||||
#define SUNXI_SPI0_BASE 0x01c05000 |
||||
#define SUNXI_SPI1_BASE 0x01c06000 |
||||
#define SUNXI_MS_BASE 0x01c07000 |
||||
#define SUNXI_TVD_BASE 0x01c08000 |
||||
#define SUNXI_CSI0_BASE 0x01c09000 |
||||
#define SUNXI_TVE0_BASE 0x01c0a000 |
||||
#define SUNXI_EMAC_BASE 0x01c0b000 |
||||
#define SUNXI_LCD0_BASE 0x01c0C000 |
||||
#define SUNXI_LCD1_BASE 0x01c0d000 |
||||
#define SUNXI_VE_BASE 0x01c0e000 |
||||
#define SUNXI_MMC0_BASE 0x01c0f000 |
||||
#define SUNXI_MMC1_BASE 0x01c10000 |
||||
#define SUNXI_MMC2_BASE 0x01c11000 |
||||
#define SUNXI_MMC3_BASE 0x01c12000 |
||||
#define SUNXI_USB0_BASE 0x01c13000 |
||||
#define SUNXI_USB1_BASE 0x01c14000 |
||||
#define SUNXI_SS_BASE 0x01c15000 |
||||
#define SUNXI_HDMI_BASE 0x01c16000 |
||||
#define SUNXI_SPI2_BASE 0x01c17000 |
||||
#define SUNXI_SATA_BASE 0x01c18000 |
||||
#define SUNXI_PATA_BASE 0x01c19000 |
||||
#define SUNXI_ACE_BASE 0x01c1a000 |
||||
#define SUNXI_TVE1_BASE 0x01c1b000 |
||||
#define SUNXI_USB2_BASE 0x01c1c000 |
||||
#define SUNXI_CSI1_BASE 0x01c1d000 |
||||
#define SUNXI_TZASC_BASE 0x01c1e000 |
||||
#define SUNXI_SPI3_BASE 0x01c1f000 |
||||
|
||||
#define SUNXI_CCM_BASE 0x01c20000 |
||||
#define SUNXI_INTC_BASE 0x01c20400 |
||||
#define SUNXI_PIO_BASE 0x01c20800 |
||||
#define SUNXI_TIMER_BASE 0x01c20c00 |
||||
#define SUNXI_SPDIF_BASE 0x01c21000 |
||||
#define SUNXI_AC97_BASE 0x01c21400 |
||||
#define SUNXI_IR0_BASE 0x01c21800 |
||||
#define SUNXI_IR1_BASE 0x01c21c00 |
||||
|
||||
#define SUNXI_IIS_BASE 0x01c22400 |
||||
#define SUNXI_LRADC_BASE 0x01c22800 |
||||
#define SUNXI_AD_DA_BASE 0x01c22c00 |
||||
#define SUNXI_KEYPAD_BASE 0x01c23000 |
||||
#define SUNXI_TZPC_BASE 0x01c23400 |
||||
#define SUNXI_SID_BASE 0x01c23800 |
||||
#define SUNXI_SJTAG_BASE 0x01c23c00 |
||||
|
||||
#define SUNXI_TP_BASE 0x01c25000 |
||||
#define SUNXI_PMU_BASE 0x01c25400 |
||||
#define SUNXI_CPUCFG_BASE 0x01c25c00 |
||||
|
||||
#define SUNXI_UART0_BASE 0x01c28000 |
||||
#define SUNXI_UART1_BASE 0x01c28400 |
||||
#define SUNXI_UART2_BASE 0x01c28800 |
||||
#define SUNXI_UART3_BASE 0x01c28c00 |
||||
#define SUNXI_UART4_BASE 0x01c29000 |
||||
#define SUNXI_UART5_BASE 0x01c29400 |
||||
#define SUNXI_UART6_BASE 0x01c29800 |
||||
#define SUNXI_UART7_BASE 0x01c29c00 |
||||
#define SUNXI_PS2_0_BASE 0x01c2a000 |
||||
#define SUNXI_PS2_1_BASE 0x01c2a400 |
||||
|
||||
#define SUNXI_TWI0_BASE 0x01c2ac00 |
||||
#define SUNXI_TWI1_BASE 0x01c2b000 |
||||
#define SUNXI_TWI2_BASE 0x01c2b400 |
||||
|
||||
#define SUNXI_CAN_BASE 0x01c2bc00 |
||||
|
||||
#define SUNXI_SCR_BASE 0x01c2c400 |
||||
|
||||
#define SUNXI_GPS_BASE 0x01c30000 |
||||
#define SUNXI_MALI400_BASE 0x01c40000 |
||||
#define SUNXI_GMAC_BASE 0x01c50000 |
||||
|
||||
/* module sram */ |
||||
#define SUNXI_SRAM_C_BASE 0x01d00000 |
||||
|
||||
#define SUNXI_DE_FE0_BASE 0x01e00000 |
||||
#define SUNXI_DE_FE1_BASE 0x01e20000 |
||||
#define SUNXI_DE_BE0_BASE 0x01e60000 |
||||
#define SUNXI_DE_BE1_BASE 0x01e40000 |
||||
#define SUNXI_MP_BASE 0x01e80000 |
||||
#define SUNXI_AVG_BASE 0x01ea0000 |
||||
|
||||
/* CoreSight Debug Module */ |
||||
#define SUNXI_CSDM_BASE 0x3f500000 |
||||
|
||||
#define SUNXI_DDRII_DDRIII_BASE 0x40000000 /* 2 GiB */ |
||||
|
||||
#define SUNXI_BROM_BASE 0xffff0000 /* 32 kiB */ |
||||
|
||||
#define SUNXI_CPU_CFG (SUNXI_TIMER_BASE + 0x13c) |
||||
|
||||
#ifndef __ASSEMBLY__ |
||||
void sunxi_board_init(void); |
||||
void sunxi_reset(void); |
||||
#endif /* __ASSEMBLY__ */ |
||||
|
||||
#endif /* _CPU_H */ |
@ -0,0 +1,179 @@ |
||||
/*
|
||||
* (C) Copyright 2007-2012 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Berg Xing <bergxing@allwinnertech.com> |
||||
* Tom Cubie <tangliang@allwinnertech.com> |
||||
* |
||||
* Sunxi platform dram register definition. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _SUNXI_DRAM_H |
||||
#define _SUNXI_DRAM_H |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
struct sunxi_dram_reg { |
||||
u32 ccr; /* 0x00 controller configuration register */ |
||||
u32 dcr; /* 0x04 dram configuration register */ |
||||
u32 iocr; /* 0x08 i/o configuration register */ |
||||
u32 csr; /* 0x0c controller status register */ |
||||
u32 drr; /* 0x10 dram refresh register */ |
||||
u32 tpr0; /* 0x14 dram timing parameters register 0 */ |
||||
u32 tpr1; /* 0x18 dram timing parameters register 1 */ |
||||
u32 tpr2; /* 0x1c dram timing parameters register 2 */ |
||||
u32 gdllcr; /* 0x20 global dll control register */ |
||||
u8 res0[0x28]; |
||||
u32 rslr0; /* 0x4c rank system latency register */ |
||||
u32 rslr1; /* 0x50 rank system latency register */ |
||||
u8 res1[0x8]; |
||||
u32 rdgr0; /* 0x5c rank dqs gating register */ |
||||
u32 rdgr1; /* 0x60 rank dqs gating register */ |
||||
u8 res2[0x34]; |
||||
u32 odtcr; /* 0x98 odt configuration register */ |
||||
u32 dtr0; /* 0x9c data training register 0 */ |
||||
u32 dtr1; /* 0xa0 data training register 1 */ |
||||
u32 dtar; /* 0xa4 data training address register */ |
||||
u32 zqcr0; /* 0xa8 zq control register 0 */ |
||||
u32 zqcr1; /* 0xac zq control register 1 */ |
||||
u32 zqsr; /* 0xb0 zq status register */ |
||||
u32 idcr; /* 0xb4 initializaton delay configure reg */ |
||||
u8 res3[0x138]; |
||||
u32 mr; /* 0x1f0 mode register */ |
||||
u32 emr; /* 0x1f4 extended mode register */ |
||||
u32 emr2; /* 0x1f8 extended mode register */ |
||||
u32 emr3; /* 0x1fc extended mode register */ |
||||
u32 dllctr; /* 0x200 dll control register */ |
||||
u32 dllcr[5]; /* 0x204 dll control register 0(byte 0) */ |
||||
/* 0x208 dll control register 1(byte 1) */ |
||||
/* 0x20c dll control register 2(byte 2) */ |
||||
/* 0x210 dll control register 3(byte 3) */ |
||||
/* 0x214 dll control register 4(byte 4) */ |
||||
u32 dqtr0; /* 0x218 dq timing register */ |
||||
u32 dqtr1; /* 0x21c dq timing register */ |
||||
u32 dqtr2; /* 0x220 dq timing register */ |
||||
u32 dqtr3; /* 0x224 dq timing register */ |
||||
u32 dqstr; /* 0x228 dqs timing register */ |
||||
u32 dqsbtr; /* 0x22c dqsb timing register */ |
||||
u32 mcr; /* 0x230 mode configure register */ |
||||
u8 res[0x8]; |
||||
u32 ppwrsctl; /* 0x23c pad power save control */ |
||||
u32 apr; /* 0x240 arbiter period register */ |
||||
u32 pldtr; /* 0x244 priority level data threshold reg */ |
||||
u8 res5[0x8]; |
||||
u32 hpcr[32]; /* 0x250 host port configure register */ |
||||
u8 res6[0x10]; |
||||
u32 csel; /* 0x2e0 controller select register */ |
||||
}; |
||||
|
||||
struct dram_para { |
||||
u32 clock; |
||||
u32 type; |
||||
u32 rank_num; |
||||
u32 density; |
||||
u32 io_width; |
||||
u32 bus_width; |
||||
u32 cas; |
||||
u32 zq; |
||||
u32 odt_en; |
||||
u32 size; |
||||
u32 tpr0; |
||||
u32 tpr1; |
||||
u32 tpr2; |
||||
u32 tpr3; |
||||
u32 tpr4; |
||||
u32 tpr5; |
||||
u32 emr1; |
||||
u32 emr2; |
||||
u32 emr3; |
||||
}; |
||||
|
||||
#define DRAM_CCR_COMMAND_RATE_1T (0x1 << 5) |
||||
#define DRAM_CCR_DQS_GATE (0x1 << 14) |
||||
#define DRAM_CCR_DQS_DRIFT_COMP (0x1 << 17) |
||||
#define DRAM_CCR_ITM_OFF (0x1 << 28) |
||||
#define DRAM_CCR_DATA_TRAINING (0x1 << 30) |
||||
#define DRAM_CCR_INIT (0x1 << 31) |
||||
|
||||
#define DRAM_MEMORY_TYPE_DDR1 1 |
||||
#define DRAM_MEMORY_TYPE_DDR2 2 |
||||
#define DRAM_MEMORY_TYPE_DDR3 3 |
||||
#define DRAM_MEMORY_TYPE_LPDDR2 4 |
||||
#define DRAM_MEMORY_TYPE_LPDDR 5 |
||||
#define DRAM_DCR_TYPE (0x1 << 0) |
||||
#define DRAM_DCR_TYPE_DDR2 0x0 |
||||
#define DRAM_DCR_TYPE_DDR3 0x1 |
||||
#define DRAM_DCR_IO_WIDTH(n) (((n) & 0x3) << 1) |
||||
#define DRAM_DCR_IO_WIDTH_MASK DRAM_DCR_IO_WIDTH(0x3) |
||||
#define DRAM_DCR_IO_WIDTH_8BIT 0x0 |
||||
#define DRAM_DCR_IO_WIDTH_16BIT 0x1 |
||||
#define DRAM_DCR_CHIP_DENSITY(n) (((n) & 0x7) << 3) |
||||
#define DRAM_DCR_CHIP_DENSITY_MASK DRAM_DCR_CHIP_DENSITY(0x7) |
||||
#define DRAM_DCR_CHIP_DENSITY_256M 0x0 |
||||
#define DRAM_DCR_CHIP_DENSITY_512M 0x1 |
||||
#define DRAM_DCR_CHIP_DENSITY_1024M 0x2 |
||||
#define DRAM_DCR_CHIP_DENSITY_2048M 0x3 |
||||
#define DRAM_DCR_CHIP_DENSITY_4096M 0x4 |
||||
#define DRAM_DCR_CHIP_DENSITY_8192M 0x5 |
||||
#define DRAM_DCR_BUS_WIDTH(n) (((n) & 0x7) << 6) |
||||
#define DRAM_DCR_BUS_WIDTH_MASK DRAM_DCR_BUS_WIDTH(0x7) |
||||
#define DRAM_DCR_BUS_WIDTH_32BIT 0x3 |
||||
#define DRAM_DCR_BUS_WIDTH_16BIT 0x1 |
||||
#define DRAM_DCR_BUS_WIDTH_8BIT 0x0 |
||||
#define DRAM_DCR_NR_DLLCR_32BIT 5 |
||||
#define DRAM_DCR_NR_DLLCR_16BIT 3 |
||||
#define DRAM_DCR_NR_DLLCR_8BIT 2 |
||||
#define DRAM_DCR_RANK_SEL(n) (((n) & 0x3) << 10) |
||||
#define DRAM_DCR_RANK_SEL_MASK DRAM_DCR_CMD_RANK(0x3) |
||||
#define DRAM_DCR_CMD_RANK_ALL (0x1 << 12) |
||||
#define DRAM_DCR_MODE(n) (((n) & 0x3) << 13) |
||||
#define DRAM_DCR_MODE_MASK DRAM_DCR_MODE(0x3) |
||||
#define DRAM_DCR_MODE_SEQ 0x0 |
||||
#define DRAM_DCR_MODE_INTERLEAVE 0x1 |
||||
|
||||
#define DRAM_CSR_FAILED (0x1 << 20) |
||||
|
||||
#define DRAM_DRR_TRFC(n) ((n) & 0xff) |
||||
#define DRAM_DRR_TREFI(n) (((n) & 0xffff) << 8) |
||||
#define DRAM_DRR_BURST(n) ((((n) - 1) & 0xf) << 24) |
||||
|
||||
#define DRAM_MCR_MODE_NORM(n) (((n) & 0x3) << 0) |
||||
#define DRAM_MCR_MODE_NORM_MASK DRAM_MCR_MOD_NORM(0x3) |
||||
#define DRAM_MCR_MODE_DQ_OUT(n) (((n) & 0x3) << 2) |
||||
#define DRAM_MCR_MODE_DQ_OUT_MASK DRAM_MCR_MODE_DQ_OUT(0x3) |
||||
#define DRAM_MCR_MODE_ADDR_OUT(n) (((n) & 0x3) << 4) |
||||
#define DRAM_MCR_MODE_ADDR_OUT_MASK DRAM_MCR_MODE_ADDR_OUT(0x3) |
||||
#define DRAM_MCR_MODE_DQ_IN_OUT(n) (((n) & 0x3) << 6) |
||||
#define DRAM_MCR_MODE_DQ_IN_OUT_MASK DRAM_MCR_MODE_DQ_IN_OUT(0x3) |
||||
#define DRAM_MCR_MODE_DQ_TURNON_DELAY(n) (((n) & 0x7) << 8) |
||||
#define DRAM_MCR_MODE_DQ_TURNON_DELAY_MASK DRAM_MCR_MODE_DQ_TURNON_DELAY(0x7) |
||||
#define DRAM_MCR_MODE_ADDR_IN (0x1 << 11) |
||||
#define DRAM_MCR_RESET (0x1 << 12) |
||||
#define DRAM_MCR_MODE_EN(n) (((n) & 0x3) << 13) |
||||
#define DRAM_MCR_MODE_EN_MASK DRAM_MCR_MOD_EN(0x3) |
||||
#define DRAM_MCR_DCLK_OUT (0x1 << 16) |
||||
|
||||
#define DRAM_DLLCR_NRESET (0x1 << 30) |
||||
#define DRAM_DLLCR_DISABLE (0x1 << 31) |
||||
|
||||
#define DRAM_ZQCR0_IMP_DIV(n) (((n) & 0xff) << 20) |
||||
#define DRAM_ZQCR0_IMP_DIV_MASK DRAM_ZQCR0_IMP_DIV(0xff) |
||||
|
||||
#define DRAM_IOCR_ODT_EN(n) ((((n) & 0x3) << 30) | ((n) & 0x3) << 0) |
||||
#define DRAM_IOCR_ODT_EN_MASK DRAM_IOCR_ODT_EN(0x3) |
||||
|
||||
#define DRAM_MR_BURST_LENGTH(n) (((n) & 0x7) << 0) |
||||
#define DRAM_MR_BURST_LENGTH_MASK DRAM_MR_BURST_LENGTH(0x7) |
||||
#define DRAM_MR_CAS_LAT(n) (((n) & 0x7) << 4) |
||||
#define DRAM_MR_CAS_LAT_MASK DRAM_MR_CAS_LAT(0x7) |
||||
#define DRAM_MR_WRITE_RECOVERY(n) (((n) & 0x7) << 9) |
||||
#define DRAM_MR_WRITE_RECOVERY_MASK DRAM_MR_WRITE_RECOVERY(0x7) |
||||
#define DRAM_MR_POWER_DOWN (0x1 << 12) |
||||
|
||||
#define DRAM_CSEL_MAGIC 0x16237495 |
||||
|
||||
unsigned long sunxi_dram_init(void); |
||||
unsigned long dramc_init(struct dram_para *para); |
||||
|
||||
#endif /* _SUNXI_DRAM_H */ |
@ -0,0 +1,147 @@ |
||||
/*
|
||||
* (C) Copyright 2007-2012 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Tom Cubie <tangliang@allwinnertech.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _SUNXI_GPIO_H |
||||
#define _SUNXI_GPIO_H |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
/*
|
||||
* sunxi has 9 banks of gpio, they are: |
||||
* PA0 - PA17 | PB0 - PB23 | PC0 - PC24 |
||||
* PD0 - PD27 | PE0 - PE31 | PF0 - PF5 |
||||
* PG0 - PG9 | PH0 - PH27 | PI0 - PI12 |
||||
*/ |
||||
|
||||
#define SUNXI_GPIO_A 0 |
||||
#define SUNXI_GPIO_B 1 |
||||
#define SUNXI_GPIO_C 2 |
||||
#define SUNXI_GPIO_D 3 |
||||
#define SUNXI_GPIO_E 4 |
||||
#define SUNXI_GPIO_F 5 |
||||
#define SUNXI_GPIO_G 6 |
||||
#define SUNXI_GPIO_H 7 |
||||
#define SUNXI_GPIO_I 8 |
||||
#define SUNXI_GPIO_BANKS 9 |
||||
|
||||
struct sunxi_gpio { |
||||
u32 cfg[4]; |
||||
u32 dat; |
||||
u32 drv[2]; |
||||
u32 pull[2]; |
||||
}; |
||||
|
||||
/* gpio interrupt control */ |
||||
struct sunxi_gpio_int { |
||||
u32 cfg[3]; |
||||
u32 ctl; |
||||
u32 sta; |
||||
u32 deb; /* interrupt debounce */ |
||||
}; |
||||
|
||||
struct sunxi_gpio_reg { |
||||
struct sunxi_gpio gpio_bank[SUNXI_GPIO_BANKS]; |
||||
u8 res[0xbc]; |
||||
struct sunxi_gpio_int gpio_int; |
||||
}; |
||||
|
||||
#define BANK_TO_GPIO(bank) \ |
||||
&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank] |
||||
|
||||
#define GPIO_BANK(pin) ((pin) >> 5) |
||||
#define GPIO_NUM(pin) ((pin) & 0x1f) |
||||
|
||||
#define GPIO_CFG_INDEX(pin) (((pin) & 0x1f) >> 3) |
||||
#define GPIO_CFG_OFFSET(pin) ((((pin) & 0x1f) & 0x7) << 2) |
||||
|
||||
#define GPIO_DRV_INDEX(pin) (((pin) & 0x1f) >> 4) |
||||
#define GPIO_DRV_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1) |
||||
|
||||
#define GPIO_PULL_INDEX(pin) (((pin) & 0x1f) >> 4) |
||||
#define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1) |
||||
|
||||
/* GPIO bank sizes */ |
||||
#define SUNXI_GPIO_A_NR 32 |
||||
#define SUNXI_GPIO_B_NR 32 |
||||
#define SUNXI_GPIO_C_NR 32 |
||||
#define SUNXI_GPIO_D_NR 32 |
||||
#define SUNXI_GPIO_E_NR 32 |
||||
#define SUNXI_GPIO_F_NR 32 |
||||
#define SUNXI_GPIO_G_NR 32 |
||||
#define SUNXI_GPIO_H_NR 32 |
||||
#define SUNXI_GPIO_I_NR 32 |
||||
|
||||
#define SUNXI_GPIO_NEXT(__gpio) \ |
||||
((__gpio##_START) + (__gpio##_NR) + 0) |
||||
|
||||
enum sunxi_gpio_number { |
||||
SUNXI_GPIO_A_START = 0, |
||||
SUNXI_GPIO_B_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_A), |
||||
SUNXI_GPIO_C_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_B), |
||||
SUNXI_GPIO_D_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_C), |
||||
SUNXI_GPIO_E_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_D), |
||||
SUNXI_GPIO_F_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_E), |
||||
SUNXI_GPIO_G_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_F), |
||||
SUNXI_GPIO_H_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_G), |
||||
SUNXI_GPIO_I_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_H), |
||||
}; |
||||
|
||||
/* SUNXI GPIO number definitions */ |
||||
#define SUNXI_GPA(_nr) (SUNXI_GPIO_A_START + (_nr)) |
||||
#define SUNXI_GPB(_nr) (SUNXI_GPIO_B_START + (_nr)) |
||||
#define SUNXI_GPC(_nr) (SUNXI_GPIO_C_START + (_nr)) |
||||
#define SUNXI_GPD(_nr) (SUNXI_GPIO_D_START + (_nr)) |
||||
#define SUNXI_GPE(_nr) (SUNXI_GPIO_E_START + (_nr)) |
||||
#define SUNXI_GPF(_nr) (SUNXI_GPIO_F_START + (_nr)) |
||||
#define SUNXI_GPG(_nr) (SUNXI_GPIO_G_START + (_nr)) |
||||
#define SUNXI_GPH(_nr) (SUNXI_GPIO_H_START + (_nr)) |
||||
#define SUNXI_GPI(_nr) (SUNXI_GPIO_I_START + (_nr)) |
||||
|
||||
/* GPIO pin function config */ |
||||
#define SUNXI_GPIO_INPUT 0 |
||||
#define SUNXI_GPIO_OUTPUT 1 |
||||
|
||||
#define SUNXI_GPA0_EMAC 2 |
||||
#define SUN7I_GPA0_GMAC 5 |
||||
|
||||
#define SUNXI_GPB0_TWI0 2 |
||||
|
||||
#define SUN4I_GPB22_UART0_TX 2 |
||||
#define SUN4I_GPB23_UART0_RX 2 |
||||
|
||||
#define SUN5I_GPB19_UART0_TX 2 |
||||
#define SUN5I_GPB20_UART0_RX 2 |
||||
|
||||
#define SUN5I_GPG3_UART1_TX 4 |
||||
#define SUN5I_GPG4_UART1_RX 4 |
||||
|
||||
#define SUNXI_GPC6_SDC2 3 |
||||
|
||||
#define SUNXI_GPF0_SDC0 2 |
||||
|
||||
#define SUNXI_GPF2_SDC0 2 |
||||
#define SUNXI_GPF2_UART0_TX 4 |
||||
#define SUNXI_GPF4_UART0_RX 4 |
||||
|
||||
#define SUN4I_GPG0_SDC1 4 |
||||
|
||||
#define SUN4I_GPH22_SDC1 5 |
||||
|
||||
#define SUN4I_GPI4_SDC3 2 |
||||
|
||||
/* GPIO pin pull-up/down config */ |
||||
#define SUNXI_GPIO_PULL_DISABLE 0 |
||||
#define SUNXI_GPIO_PULL_UP 1 |
||||
#define SUNXI_GPIO_PULL_DOWN 2 |
||||
|
||||
int sunxi_gpio_set_cfgpin(u32 pin, u32 val); |
||||
int sunxi_gpio_get_cfgpin(u32 pin); |
||||
int sunxi_gpio_set_drv(u32 pin, u32 val); |
||||
int sunxi_gpio_set_pull(u32 pin, u32 val); |
||||
|
||||
#endif /* _SUNXI_GPIO_H */ |
@ -0,0 +1,124 @@ |
||||
/*
|
||||
* (C) Copyright 2007-2011 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Aaron <leafy.myeh@allwinnertech.com> |
||||
* |
||||
* MMC register definition for allwinner sunxi platform. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _SUNXI_MMC_H |
||||
#define _SUNXI_MMC_H |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
struct sunxi_mmc { |
||||
u32 gctrl; /* 0x00 global control */ |
||||
u32 clkcr; /* 0x04 clock control */ |
||||
u32 timeout; /* 0x08 time out */ |
||||
u32 width; /* 0x0c bus width */ |
||||
u32 blksz; /* 0x10 block size */ |
||||
u32 bytecnt; /* 0x14 byte count */ |
||||
u32 cmd; /* 0x18 command */ |
||||
u32 arg; /* 0x1c argument */ |
||||
u32 resp0; /* 0x20 response 0 */ |
||||
u32 resp1; /* 0x24 response 1 */ |
||||
u32 resp2; /* 0x28 response 2 */ |
||||
u32 resp3; /* 0x2c response 3 */ |
||||
u32 imask; /* 0x30 interrupt mask */ |
||||
u32 mint; /* 0x34 masked interrupt status */ |
||||
u32 rint; /* 0x38 raw interrupt status */ |
||||
u32 status; /* 0x3c status */ |
||||
u32 ftrglevel; /* 0x40 FIFO threshold watermark*/ |
||||
u32 funcsel; /* 0x44 function select */ |
||||
u32 cbcr; /* 0x48 CIU byte count */ |
||||
u32 bbcr; /* 0x4c BIU byte count */ |
||||
u32 dbgc; /* 0x50 debug enable */ |
||||
u32 res0[11]; |
||||
u32 dmac; /* 0x80 internal DMA control */ |
||||
u32 dlba; /* 0x84 internal DMA descr list base address */ |
||||
u32 idst; /* 0x88 internal DMA status */ |
||||
u32 idie; /* 0x8c internal DMA interrupt enable */ |
||||
u32 chda; /* 0x90 */ |
||||
u32 cbda; /* 0x94 */ |
||||
u32 res1[26]; |
||||
u32 fifo; /* 0x100 FIFO access address */ |
||||
}; |
||||
|
||||
#define SUNXI_MMC_CLK_POWERSAVE (0x1 << 17) |
||||
#define SUNXI_MMC_CLK_ENABLE (0x1 << 16) |
||||
#define SUNXI_MMC_CLK_DIVIDER_MASK (0xff) |
||||
|
||||
#define SUNXI_MMC_GCTRL_SOFT_RESET (0x1 << 0) |
||||
#define SUNXI_MMC_GCTRL_FIFO_RESET (0x1 << 1) |
||||
#define SUNXI_MMC_GCTRL_DMA_RESET (0x1 << 2) |
||||
#define SUNXI_MMC_GCTRL_RESET (SUNXI_MMC_GCTRL_SOFT_RESET|\ |
||||
SUNXI_MMC_GCTRL_FIFO_RESET|\
|
||||
SUNXI_MMC_GCTRL_DMA_RESET) |
||||
#define SUNXI_MMC_GCTRL_DMA_ENABLE (0x1 << 5) |
||||
#define SUNXI_MMC_GCTRL_ACCESS_BY_AHB (0x1 << 31) |
||||
|
||||
#define SUNXI_MMC_CMD_RESP_EXPIRE (0x1 << 6) |
||||
#define SUNXI_MMC_CMD_LONG_RESPONSE (0x1 << 7) |
||||
#define SUNXI_MMC_CMD_CHK_RESPONSE_CRC (0x1 << 8) |
||||
#define SUNXI_MMC_CMD_DATA_EXPIRE (0x1 << 9) |
||||
#define SUNXI_MMC_CMD_WRITE (0x1 << 10) |
||||
#define SUNXI_MMC_CMD_AUTO_STOP (0x1 << 12) |
||||
#define SUNXI_MMC_CMD_WAIT_PRE_OVER (0x1 << 13) |
||||
#define SUNXI_MMC_CMD_SEND_INIT_SEQ (0x1 << 15) |
||||
#define SUNXI_MMC_CMD_UPCLK_ONLY (0x1 << 21) |
||||
#define SUNXI_MMC_CMD_START (0x1 << 31) |
||||
|
||||
#define SUNXI_MMC_RINT_RESP_ERROR (0x1 << 1) |
||||
#define SUNXI_MMC_RINT_COMMAND_DONE (0x1 << 2) |
||||
#define SUNXI_MMC_RINT_DATA_OVER (0x1 << 3) |
||||
#define SUNXI_MMC_RINT_TX_DATA_REQUEST (0x1 << 4) |
||||
#define SUNXI_MMC_RINT_RX_DATA_REQUEST (0x1 << 5) |
||||
#define SUNXI_MMC_RINT_RESP_CRC_ERROR (0x1 << 6) |
||||
#define SUNXI_MMC_RINT_DATA_CRC_ERROR (0x1 << 7) |
||||
#define SUNXI_MMC_RINT_RESP_TIMEOUT (0x1 << 8) |
||||
#define SUNXI_MMC_RINT_DATA_TIMEOUT (0x1 << 9) |
||||
#define SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE (0x1 << 10) |
||||
#define SUNXI_MMC_RINT_FIFO_RUN_ERROR (0x1 << 11) |
||||
#define SUNXI_MMC_RINT_HARD_WARE_LOCKED (0x1 << 12) |
||||
#define SUNXI_MMC_RINT_START_BIT_ERROR (0x1 << 13) |
||||
#define SUNXI_MMC_RINT_AUTO_COMMAND_DONE (0x1 << 14) |
||||
#define SUNXI_MMC_RINT_END_BIT_ERROR (0x1 << 15) |
||||
#define SUNXI_MMC_RINT_SDIO_INTERRUPT (0x1 << 16) |
||||
#define SUNXI_MMC_RINT_CARD_INSERT (0x1 << 30) |
||||
#define SUNXI_MMC_RINT_CARD_REMOVE (0x1 << 31) |
||||
#define SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT \ |
||||
(SUNXI_MMC_RINT_RESP_ERROR | \
|
||||
SUNXI_MMC_RINT_RESP_CRC_ERROR | \
|
||||
SUNXI_MMC_RINT_DATA_CRC_ERROR | \
|
||||
SUNXI_MMC_RINT_RESP_TIMEOUT | \
|
||||
SUNXI_MMC_RINT_DATA_TIMEOUT | \
|
||||
SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE | \
|
||||
SUNXI_MMC_RINT_FIFO_RUN_ERROR | \
|
||||
SUNXI_MMC_RINT_HARD_WARE_LOCKED | \
|
||||
SUNXI_MMC_RINT_START_BIT_ERROR | \
|
||||
SUNXI_MMC_RINT_END_BIT_ERROR) /* 0xbfc2 */ |
||||
#define SUNXI_MMC_RINT_INTERRUPT_DONE_BIT \ |
||||
(SUNXI_MMC_RINT_AUTO_COMMAND_DONE | \
|
||||
SUNXI_MMC_RINT_DATA_OVER | \
|
||||
SUNXI_MMC_RINT_COMMAND_DONE | \
|
||||
SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE) |
||||
|
||||
#define SUNXI_MMC_STATUS_RXWL_FLAG (0x1 << 0) |
||||
#define SUNXI_MMC_STATUS_TXWL_FLAG (0x1 << 1) |
||||
#define SUNXI_MMC_STATUS_FIFO_EMPTY (0x1 << 2) |
||||
#define SUNXI_MMC_STATUS_FIFO_FULL (0x1 << 3) |
||||
#define SUNXI_MMC_STATUS_CARD_PRESENT (0x1 << 8) |
||||
#define SUNXI_MMC_STATUS_CARD_DATA_BUSY (0x1 << 9) |
||||
#define SUNXI_MMC_STATUS_DATA_FSM_BUSY (0x1 << 10) |
||||
|
||||
#define SUNXI_MMC_IDMAC_RESET (0x1 << 0) |
||||
#define SUNXI_MMC_IDMAC_FIXBURST (0x1 << 1) |
||||
#define SUNXI_MMC_IDMAC_ENABLE (0x1 << 7) |
||||
|
||||
#define SUNXI_MMC_IDIE_TXIRQ (0x1 << 0) |
||||
#define SUNXI_MMC_IDIE_RXIRQ (0x1 << 1) |
||||
|
||||
int sunxi_mmc_init(int sdc_no); |
||||
#endif /* _SUNXI_MMC_H */ |
@ -0,0 +1,20 @@ |
||||
/*
|
||||
* This is a copy of omap3/spl.h: |
||||
* |
||||
* (C) Copyright 2012 |
||||
* Texas Instruments, <www.ti.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
#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 |
@ -0,0 +1,16 @@ |
||||
/*
|
||||
* (C) Copyright 2007-2012 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Tom Cubie <tangliang@allwinnertech.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _SYS_PROTO_H_ |
||||
#define _SYS_PROTO_H_ |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
void sdelay(unsigned long); |
||||
|
||||
#endif |
@ -0,0 +1,88 @@ |
||||
/*
|
||||
* (C) Copyright 2007-2011 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Tom Cubie <tangliang@allwinnertech.com> |
||||
* |
||||
* Configuration settings for the Allwinner A10-evb board. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _SUNXI_TIMER_H_ |
||||
#define _SUNXI_TIMER_H_ |
||||
|
||||
#ifndef __ASSEMBLY__ |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
/* General purpose timer */ |
||||
struct sunxi_timer { |
||||
u32 ctl; |
||||
u32 inter; |
||||
u32 val; |
||||
u8 res[4]; |
||||
}; |
||||
|
||||
/* Audio video sync*/ |
||||
struct sunxi_avs { |
||||
u32 ctl; /* 0x80 */ |
||||
u32 cnt0; /* 0x84 */ |
||||
u32 cnt1; /* 0x88 */ |
||||
u32 div; /* 0x8c */ |
||||
}; |
||||
|
||||
/* 64 bit counter */ |
||||
struct sunxi_64cnt { |
||||
u32 ctl; /* 0xa0 */ |
||||
u32 lo; /* 0xa4 */ |
||||
u32 hi; /* 0xa8 */ |
||||
}; |
||||
|
||||
/* Watchdog */ |
||||
struct sunxi_wdog { |
||||
u32 ctl; /* 0x90 */ |
||||
u32 mode; /* 0x94 */ |
||||
}; |
||||
|
||||
/* Rtc */ |
||||
struct sunxi_rtc { |
||||
u32 ctl; /* 0x100 */ |
||||
u32 yymmdd; /* 0x104 */ |
||||
u32 hhmmss; /* 0x108 */ |
||||
}; |
||||
|
||||
/* Alarm */ |
||||
struct sunxi_alarm { |
||||
u32 ddhhmmss; /* 0x10c */ |
||||
u32 hhmmss; /* 0x110 */ |
||||
u32 en; /* 0x114 */ |
||||
u32 irqen; /* 0x118 */ |
||||
u32 irqsta; /* 0x11c */ |
||||
}; |
||||
|
||||
/* Timer general purpose register */ |
||||
struct sunxi_tgp { |
||||
u32 tgpd; |
||||
}; |
||||
|
||||
struct sunxi_timer_reg { |
||||
u32 tirqen; /* 0x00 */ |
||||
u32 tirqsta; /* 0x04 */ |
||||
u8 res1[8]; |
||||
struct sunxi_timer timer[6]; /* We have 6 timers */ |
||||
u8 res2[16]; |
||||
struct sunxi_avs avs; |
||||
struct sunxi_wdog wdog; |
||||
u8 res3[8]; |
||||
struct sunxi_64cnt cnt64; |
||||
u8 res4[0x58]; |
||||
struct sunxi_rtc rtc; |
||||
struct sunxi_alarm alarm; |
||||
struct sunxi_tgp tgp[4]; |
||||
u8 res5[8]; |
||||
u32 cpu_cfg; |
||||
}; |
||||
|
||||
#endif /* __ASSEMBLY__ */ |
||||
|
||||
#endif |
@ -0,0 +1,13 @@ |
||||
#
|
||||
# (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
|
||||
#
|
||||
# Based on some other board Makefile
|
||||
#
|
||||
# (C) Copyright 2000-2003
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
obj-y += board.o
|
||||
obj-$(CONFIG_SUNXI_GMAC) += gmac.o
|
||||
obj-$(CONFIG_CUBIETRUCK) += dram_cubietruck.o
|
@ -0,0 +1,120 @@ |
||||
/*
|
||||
* (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net> |
||||
* (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net> |
||||
* |
||||
* (C) Copyright 2007-2011 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Tom Cubie <tangliang@allwinnertech.com> |
||||
* |
||||
* Some board init for the Allwinner A10-evb board. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/clock.h> |
||||
#include <asm/arch/dram.h> |
||||
#include <asm/arch/gpio.h> |
||||
#include <asm/arch/mmc.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
/* add board specific code here */ |
||||
int board_init(void) |
||||
{ |
||||
int id_pfr1; |
||||
|
||||
gd->bd->bi_boot_params = (PHYS_SDRAM_0 + 0x100); |
||||
|
||||
asm volatile("mrc p15, 0, %0, c0, c1, 1" : "=r"(id_pfr1)); |
||||
debug("id_pfr1: 0x%08x\n", id_pfr1); |
||||
/* Generic Timer Extension available? */ |
||||
if ((id_pfr1 >> 16) & 0xf) { |
||||
debug("Setting CNTFRQ\n"); |
||||
/* CNTFRQ == 24 MHz */ |
||||
asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r"(24000000)); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int dram_init(void) |
||||
{ |
||||
gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
#ifdef CONFIG_GENERIC_MMC |
||||
static void mmc_pinmux_setup(int sdc) |
||||
{ |
||||
unsigned int pin; |
||||
|
||||
switch (sdc) { |
||||
case 0: |
||||
/* D1-PF0, D0-PF1, CLK-PF2, CMD-PF3, D3-PF4, D4-PF5 */ |
||||
for (pin = SUNXI_GPF(0); pin <= SUNXI_GPF(5); pin++) { |
||||
sunxi_gpio_set_cfgpin(pin, SUNXI_GPF0_SDC0); |
||||
sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); |
||||
sunxi_gpio_set_drv(pin, 2); |
||||
} |
||||
break; |
||||
|
||||
case 1: |
||||
/* CMD-PH22, CLK-PH23, D0~D3-PH24~27 : 5 */ |
||||
for (pin = SUNXI_GPH(22); pin <= SUNXI_GPH(27); pin++) { |
||||
sunxi_gpio_set_cfgpin(pin, SUN4I_GPH22_SDC1); |
||||
sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); |
||||
sunxi_gpio_set_drv(pin, 2); |
||||
} |
||||
break; |
||||
|
||||
case 2: |
||||
/* CMD-PC6, CLK-PC7, D0-PC8, D1-PC9, D2-PC10, D3-PC11 */ |
||||
for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(11); pin++) { |
||||
sunxi_gpio_set_cfgpin(pin, SUNXI_GPC6_SDC2); |
||||
sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); |
||||
sunxi_gpio_set_drv(pin, 2); |
||||
} |
||||
break; |
||||
|
||||
case 3: |
||||
/* CMD-PI4, CLK-PI5, D0~D3-PI6~9 : 2 */ |
||||
for (pin = SUNXI_GPI(4); pin <= SUNXI_GPI(9); pin++) { |
||||
sunxi_gpio_set_cfgpin(pin, SUN4I_GPI4_SDC3); |
||||
sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); |
||||
sunxi_gpio_set_drv(pin, 2); |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
printf("sunxi: invalid MMC slot %d for pinmux setup\n", sdc); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
int board_mmc_init(bd_t *bis) |
||||
{ |
||||
mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT); |
||||
sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT); |
||||
#if !defined (CONFIG_SPL_BUILD) && defined (CONFIG_MMC_SUNXI_SLOT_EXTRA) |
||||
mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT_EXTRA); |
||||
sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT_EXTRA); |
||||
#endif |
||||
|
||||
return 0; |
||||
} |
||||
#endif |
||||
|
||||
#ifdef CONFIG_SPL_BUILD |
||||
void sunxi_board_init(void) |
||||
{ |
||||
unsigned long ramsize; |
||||
|
||||
printf("DRAM:"); |
||||
ramsize = sunxi_dram_init(); |
||||
printf(" %lu MiB\n", ramsize >> 20); |
||||
if (!ramsize) |
||||
hang(); |
||||
} |
||||
#endif |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 432, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 4096, |
||||
.io_width = 8, |
||||
.bus_width = 32, |
||||
.cas = 9, |
||||
.zq = 0x7f, |
||||
.odt_en = 0, |
||||
.size = 2048, |
||||
.tpr0 = 0x42d899b7, |
||||
.tpr1 = 0xa090, |
||||
.tpr2 = 0x22a00, |
||||
.tpr3 = 0x0, |
||||
.tpr4 = 0x1, |
||||
.tpr5 = 0x0, |
||||
.emr1 = 0x4, |
||||
.emr2 = 0x10, |
||||
.emr3 = 0x0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,32 @@ |
||||
#include <common.h> |
||||
#include <netdev.h> |
||||
#include <miiphy.h> |
||||
#include <asm/gpio.h> |
||||
#include <asm/io.h> |
||||
#include <asm/arch/clock.h> |
||||
#include <asm/arch/gpio.h> |
||||
|
||||
int sunxi_gmac_initialize(bd_t *bis) |
||||
{ |
||||
int pin; |
||||
struct sunxi_ccm_reg *const ccm = |
||||
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE; |
||||
|
||||
/* Set up clock gating */ |
||||
setbits_le32(&ccm->ahb_gate1, 0x1 << AHB_GATE_OFFSET_GMAC); |
||||
|
||||
/* Set MII clock */ |
||||
setbits_le32(&ccm->gmac_clk_cfg, CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII | |
||||
CCM_GMAC_CTRL_GPIT_RGMII); |
||||
|
||||
/* Configure pin mux settings for GMAC */ |
||||
for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(16); pin++) { |
||||
/* skip unused pins in RGMII mode */ |
||||
if (pin == SUNXI_GPA(9) || pin == SUNXI_GPA(14)) |
||||
continue; |
||||
sunxi_gpio_set_cfgpin(pin, SUN7I_GPA0_GMAC); |
||||
sunxi_gpio_set_drv(pin, 3); |
||||
} |
||||
|
||||
return designware_initialize(SUNXI_GMAC_BASE, PHY_INTERFACE_MODE_RGMII); |
||||
} |
@ -0,0 +1,503 @@ |
||||
/*
|
||||
* (C) Copyright 2007-2011 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Aaron <leafy.myeh@allwinnertech.com> |
||||
* |
||||
* MMC driver for allwinner sunxi platform. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <malloc.h> |
||||
#include <mmc.h> |
||||
#include <asm/io.h> |
||||
#include <asm/arch/clock.h> |
||||
#include <asm/arch/cpu.h> |
||||
#include <asm/arch/mmc.h> |
||||
|
||||
struct sunxi_mmc_des { |
||||
u32 reserved1_1:1; |
||||
u32 dic:1; /* disable interrupt on completion */ |
||||
u32 last_des:1; /* 1-this data buffer is the last buffer */ |
||||
u32 first_des:1; /* 1-data buffer is the first buffer,
|
||||
0-data buffer contained in the next |
||||
descriptor is 1st buffer */ |
||||
u32 des_chain:1; /* 1-the 2nd address in the descriptor is the
|
||||
next descriptor address */ |
||||
u32 end_of_ring:1; /* 1-last descriptor flag when using dual
|
||||
data buffer in descriptor */ |
||||
u32 reserved1_2:24; |
||||
u32 card_err_sum:1; /* transfer error flag */ |
||||
u32 own:1; /* des owner:1-idma owns it, 0-host owns it */ |
||||
#define SDXC_DES_NUM_SHIFT 16 |
||||
#define SDXC_DES_BUFFER_MAX_LEN (1 << SDXC_DES_NUM_SHIFT) |
||||
u32 data_buf1_sz:16; |
||||
u32 data_buf2_sz:16; |
||||
u32 buf_addr_ptr1; |
||||
u32 buf_addr_ptr2; |
||||
}; |
||||
|
||||
struct sunxi_mmc_host { |
||||
unsigned mmc_no; |
||||
uint32_t *mclkreg; |
||||
unsigned database; |
||||
unsigned fatal_err; |
||||
unsigned mod_clk; |
||||
struct sunxi_mmc *reg; |
||||
struct mmc_config cfg; |
||||
}; |
||||
|
||||
/* support 4 mmc hosts */ |
||||
struct sunxi_mmc_host mmc_host[4]; |
||||
|
||||
static int mmc_resource_init(int sdc_no) |
||||
{ |
||||
struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; |
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; |
||||
|
||||
debug("init mmc %d resource\n", sdc_no); |
||||
|
||||
switch (sdc_no) { |
||||
case 0: |
||||
mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE; |
||||
mmchost->mclkreg = &ccm->sd0_clk_cfg; |
||||
break; |
||||
case 1: |
||||
mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE; |
||||
mmchost->mclkreg = &ccm->sd1_clk_cfg; |
||||
break; |
||||
case 2: |
||||
mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE; |
||||
mmchost->mclkreg = &ccm->sd2_clk_cfg; |
||||
break; |
||||
case 3: |
||||
mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE; |
||||
mmchost->mclkreg = &ccm->sd3_clk_cfg; |
||||
break; |
||||
default: |
||||
printf("Wrong mmc number %d\n", sdc_no); |
||||
return -1; |
||||
} |
||||
mmchost->database = (unsigned int)mmchost->reg + 0x100; |
||||
mmchost->mmc_no = sdc_no; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mmc_clk_io_on(int sdc_no) |
||||
{ |
||||
unsigned int pll_clk; |
||||
unsigned int divider; |
||||
struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; |
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; |
||||
|
||||
debug("init mmc %d clock and io\n", sdc_no); |
||||
|
||||
/* config ahb clock */ |
||||
setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no)); |
||||
|
||||
/* config mod clock */ |
||||
pll_clk = clock_get_pll6(); |
||||
/* should be close to 100 MHz but no more, so round up */ |
||||
divider = ((pll_clk + 99999999) / 100000000) - 1; |
||||
writel(CCM_MMC_CTRL_ENABLE | CCM_MMC_CTRL_PLL6 | divider, |
||||
mmchost->mclkreg); |
||||
mmchost->mod_clk = pll_clk / (divider + 1); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mmc_update_clk(struct mmc *mmc) |
||||
{ |
||||
struct sunxi_mmc_host *mmchost = mmc->priv; |
||||
unsigned int cmd; |
||||
unsigned timeout_msecs = 2000; |
||||
|
||||
cmd = SUNXI_MMC_CMD_START | |
||||
SUNXI_MMC_CMD_UPCLK_ONLY | |
||||
SUNXI_MMC_CMD_WAIT_PRE_OVER; |
||||
writel(cmd, &mmchost->reg->cmd); |
||||
while (readl(&mmchost->reg->cmd) & SUNXI_MMC_CMD_START) { |
||||
if (!timeout_msecs--) |
||||
return -1; |
||||
udelay(1000); |
||||
} |
||||
|
||||
/* clock update sets various irq status bits, clear these */ |
||||
writel(readl(&mmchost->reg->rint), &mmchost->reg->rint); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mmc_config_clock(struct mmc *mmc, unsigned div) |
||||
{ |
||||
struct sunxi_mmc_host *mmchost = mmc->priv; |
||||
unsigned rval = readl(&mmchost->reg->clkcr); |
||||
|
||||
/* Disable Clock */ |
||||
rval &= ~SUNXI_MMC_CLK_ENABLE; |
||||
writel(rval, &mmchost->reg->clkcr); |
||||
if (mmc_update_clk(mmc)) |
||||
return -1; |
||||
|
||||
/* Change Divider Factor */ |
||||
rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK; |
||||
rval |= div; |
||||
writel(rval, &mmchost->reg->clkcr); |
||||
if (mmc_update_clk(mmc)) |
||||
return -1; |
||||
/* Re-enable Clock */ |
||||
rval |= SUNXI_MMC_CLK_ENABLE; |
||||
writel(rval, &mmchost->reg->clkcr); |
||||
|
||||
if (mmc_update_clk(mmc)) |
||||
return -1; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void mmc_set_ios(struct mmc *mmc) |
||||
{ |
||||
struct sunxi_mmc_host *mmchost = mmc->priv; |
||||
unsigned int clkdiv = 0; |
||||
|
||||
debug("set ios: bus_width: %x, clock: %d, mod_clk: %d\n", |
||||
mmc->bus_width, mmc->clock, mmchost->mod_clk); |
||||
|
||||
/* Change clock first */ |
||||
clkdiv = (mmchost->mod_clk + (mmc->clock >> 1)) / mmc->clock / 2; |
||||
if (mmc->clock) { |
||||
if (mmc_config_clock(mmc, clkdiv)) { |
||||
mmchost->fatal_err = 1; |
||||
return; |
||||
} |
||||
} |
||||
|
||||
/* Change bus width */ |
||||
if (mmc->bus_width == 8) |
||||
writel(0x2, &mmchost->reg->width); |
||||
else if (mmc->bus_width == 4) |
||||
writel(0x1, &mmchost->reg->width); |
||||
else |
||||
writel(0x0, &mmchost->reg->width); |
||||
} |
||||
|
||||
static int mmc_core_init(struct mmc *mmc) |
||||
{ |
||||
struct sunxi_mmc_host *mmchost = mmc->priv; |
||||
|
||||
/* Reset controller */ |
||||
writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data) |
||||
{ |
||||
struct sunxi_mmc_host *mmchost = mmc->priv; |
||||
const int reading = !!(data->flags & MMC_DATA_READ); |
||||
const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY : |
||||
SUNXI_MMC_STATUS_FIFO_FULL; |
||||
unsigned i; |
||||
unsigned byte_cnt = data->blocksize * data->blocks; |
||||
unsigned timeout_msecs = 2000; |
||||
unsigned *buff = (unsigned int *)(reading ? data->dest : data->src); |
||||
|
||||
for (i = 0; i < (byte_cnt >> 2); i++) { |
||||
while (readl(&mmchost->reg->status) & status_bit) { |
||||
if (!timeout_msecs--) |
||||
return -1; |
||||
udelay(1000); |
||||
} |
||||
|
||||
if (reading) |
||||
buff[i] = readl(mmchost->database); |
||||
else |
||||
writel(buff[i], mmchost->database); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mmc_trans_data_by_dma(struct mmc *mmc, struct mmc_data *data) |
||||
{ |
||||
struct sunxi_mmc_host *mmchost = mmc->priv; |
||||
unsigned byte_cnt = data->blocksize * data->blocks; |
||||
unsigned char *buff; |
||||
unsigned des_idx = 0; |
||||
unsigned buff_frag_num = |
||||
(byte_cnt + SDXC_DES_BUFFER_MAX_LEN - 1) >> SDXC_DES_NUM_SHIFT; |
||||
unsigned remain; |
||||
unsigned i, rval; |
||||
ALLOC_CACHE_ALIGN_BUFFER(struct sunxi_mmc_des, pdes, buff_frag_num); |
||||
|
||||
buff = data->flags & MMC_DATA_READ ? |
||||
(unsigned char *)data->dest : (unsigned char *)data->src; |
||||
remain = byte_cnt & (SDXC_DES_BUFFER_MAX_LEN - 1); |
||||
|
||||
flush_cache((unsigned long)buff, (unsigned long)byte_cnt); |
||||
for (i = 0; i < buff_frag_num; i++, des_idx++) { |
||||
memset((void *)&pdes[des_idx], 0, sizeof(struct sunxi_mmc_des)); |
||||
pdes[des_idx].des_chain = 1; |
||||
pdes[des_idx].own = 1; |
||||
pdes[des_idx].dic = 1; |
||||
if (buff_frag_num > 1 && i != buff_frag_num - 1) |
||||
pdes[des_idx].data_buf1_sz = 0; /* 0 == max_len */ |
||||
else |
||||
pdes[des_idx].data_buf1_sz = remain; |
||||
|
||||
pdes[des_idx].buf_addr_ptr1 = |
||||
(u32) buff + i * SDXC_DES_BUFFER_MAX_LEN; |
||||
if (i == 0) |
||||
pdes[des_idx].first_des = 1; |
||||
|
||||
if (i == buff_frag_num - 1) { |
||||
pdes[des_idx].dic = 0; |
||||
pdes[des_idx].last_des = 1; |
||||
pdes[des_idx].end_of_ring = 1; |
||||
pdes[des_idx].buf_addr_ptr2 = 0; |
||||
} else { |
||||
pdes[des_idx].buf_addr_ptr2 = (u32)&pdes[des_idx + 1]; |
||||
} |
||||
} |
||||
flush_cache((unsigned long)pdes, |
||||
sizeof(struct sunxi_mmc_des) * (des_idx + 1)); |
||||
|
||||
rval = readl(&mmchost->reg->gctrl); |
||||
/* Enable DMA */ |
||||
writel(rval | SUNXI_MMC_GCTRL_DMA_RESET | SUNXI_MMC_GCTRL_DMA_ENABLE, |
||||
&mmchost->reg->gctrl); |
||||
/* Reset iDMA */ |
||||
writel(SUNXI_MMC_IDMAC_RESET, &mmchost->reg->dmac); |
||||
/* Enable iDMA */ |
||||
writel(SUNXI_MMC_IDMAC_FIXBURST | SUNXI_MMC_IDMAC_ENABLE, |
||||
&mmchost->reg->dmac); |
||||
rval = readl(&mmchost->reg->idie) & |
||||
~(SUNXI_MMC_IDIE_TXIRQ|SUNXI_MMC_IDIE_RXIRQ); |
||||
if (data->flags & MMC_DATA_WRITE) |
||||
rval |= SUNXI_MMC_IDIE_TXIRQ; |
||||
else |
||||
rval |= SUNXI_MMC_IDIE_RXIRQ; |
||||
writel(rval, &mmchost->reg->idie); |
||||
writel((u32) pdes, &mmchost->reg->dlba); |
||||
writel((0x2 << 28) | (0x7 << 16) | (0x01 << 3), |
||||
&mmchost->reg->ftrglevel); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void mmc_enable_dma_accesses(struct mmc *mmc, int dma) |
||||
{ |
||||
struct sunxi_mmc_host *mmchost = mmc->priv; |
||||
|
||||
unsigned int gctrl = readl(&mmchost->reg->gctrl); |
||||
if (dma) |
||||
gctrl &= ~SUNXI_MMC_GCTRL_ACCESS_BY_AHB; |
||||
else |
||||
gctrl |= SUNXI_MMC_GCTRL_ACCESS_BY_AHB; |
||||
writel(gctrl, &mmchost->reg->gctrl); |
||||
} |
||||
|
||||
static int mmc_rint_wait(struct mmc *mmc, unsigned int timeout_msecs, |
||||
unsigned int done_bit, const char *what) |
||||
{ |
||||
struct sunxi_mmc_host *mmchost = mmc->priv; |
||||
unsigned int status; |
||||
|
||||
do { |
||||
status = readl(&mmchost->reg->rint); |
||||
if (!timeout_msecs-- || |
||||
(status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) { |
||||
debug("%s timeout %x\n", what, |
||||
status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT); |
||||
return TIMEOUT; |
||||
} |
||||
udelay(1000); |
||||
} while (!(status & done_bit)); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, |
||||
struct mmc_data *data) |
||||
{ |
||||
struct sunxi_mmc_host *mmchost = mmc->priv; |
||||
unsigned int cmdval = SUNXI_MMC_CMD_START; |
||||
unsigned int timeout_msecs; |
||||
int error = 0; |
||||
unsigned int status = 0; |
||||
unsigned int usedma = 0; |
||||
unsigned int bytecnt = 0; |
||||
|
||||
if (mmchost->fatal_err) |
||||
return -1; |
||||
if (cmd->resp_type & MMC_RSP_BUSY) |
||||
debug("mmc cmd %d check rsp busy\n", cmd->cmdidx); |
||||
if (cmd->cmdidx == 12) |
||||
return 0; |
||||
|
||||
if (!cmd->cmdidx) |
||||
cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ; |
||||
if (cmd->resp_type & MMC_RSP_PRESENT) |
||||
cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE; |
||||
if (cmd->resp_type & MMC_RSP_136) |
||||
cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE; |
||||
if (cmd->resp_type & MMC_RSP_CRC) |
||||
cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC; |
||||
|
||||
if (data) { |
||||
if ((u32) data->dest & 0x3) { |
||||
error = -1; |
||||
goto out; |
||||
} |
||||
|
||||
cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER; |
||||
if (data->flags & MMC_DATA_WRITE) |
||||
cmdval |= SUNXI_MMC_CMD_WRITE; |
||||
if (data->blocks > 1) |
||||
cmdval |= SUNXI_MMC_CMD_AUTO_STOP; |
||||
writel(data->blocksize, &mmchost->reg->blksz); |
||||
writel(data->blocks * data->blocksize, &mmchost->reg->bytecnt); |
||||
} |
||||
|
||||
debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", mmchost->mmc_no, |
||||
cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg); |
||||
writel(cmd->cmdarg, &mmchost->reg->arg); |
||||
|
||||
if (!data) |
||||
writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd); |
||||
|
||||
/*
|
||||
* transfer data and check status |
||||
* STATREG[2] : FIFO empty |
||||
* STATREG[3] : FIFO full |
||||
*/ |
||||
if (data) { |
||||
int ret = 0; |
||||
|
||||
bytecnt = data->blocksize * data->blocks; |
||||
debug("trans data %d bytes\n", bytecnt); |
||||
#if defined(CONFIG_MMC_SUNXI_USE_DMA) && !defined(CONFIG_SPL_BUILD) |
||||
if (bytecnt > 64) { |
||||
#else |
||||
if (0) { |
||||
#endif |
||||
usedma = 1; |
||||
mmc_enable_dma_accesses(mmc, 1); |
||||
ret = mmc_trans_data_by_dma(mmc, data); |
||||
writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd); |
||||
} else { |
||||
mmc_enable_dma_accesses(mmc, 0); |
||||
writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd); |
||||
ret = mmc_trans_data_by_cpu(mmc, data); |
||||
} |
||||
if (ret) { |
||||
error = readl(&mmchost->reg->rint) & \
|
||||
SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT; |
||||
error = TIMEOUT; |
||||
goto out; |
||||
} |
||||
} |
||||
|
||||
error = mmc_rint_wait(mmc, 0xfffff, SUNXI_MMC_RINT_COMMAND_DONE, "cmd"); |
||||
if (error) |
||||
goto out; |
||||
|
||||
if (data) { |
||||
timeout_msecs = usedma ? 120 * bytecnt : 120; |
||||
debug("cacl timeout %x msec\n", timeout_msecs); |
||||
error = mmc_rint_wait(mmc, timeout_msecs, |
||||
data->blocks > 1 ? |
||||
SUNXI_MMC_RINT_AUTO_COMMAND_DONE : |
||||
SUNXI_MMC_RINT_DATA_OVER, |
||||
"data"); |
||||
if (error) |
||||
goto out; |
||||
} |
||||
|
||||
if (cmd->resp_type & MMC_RSP_BUSY) { |
||||
timeout_msecs = 2000; |
||||
do { |
||||
status = readl(&mmchost->reg->status); |
||||
if (!timeout_msecs--) { |
||||
debug("busy timeout\n"); |
||||
error = TIMEOUT; |
||||
goto out; |
||||
} |
||||
udelay(1000); |
||||
} while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY); |
||||
} |
||||
|
||||
if (cmd->resp_type & MMC_RSP_136) { |
||||
cmd->response[0] = readl(&mmchost->reg->resp3); |
||||
cmd->response[1] = readl(&mmchost->reg->resp2); |
||||
cmd->response[2] = readl(&mmchost->reg->resp1); |
||||
cmd->response[3] = readl(&mmchost->reg->resp0); |
||||
debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n", |
||||
cmd->response[3], cmd->response[2], |
||||
cmd->response[1], cmd->response[0]); |
||||
} else { |
||||
cmd->response[0] = readl(&mmchost->reg->resp0); |
||||
debug("mmc resp 0x%08x\n", cmd->response[0]); |
||||
} |
||||
out: |
||||
if (data && usedma) { |
||||
/* IDMASTAREG
|
||||
* IDST[0] : idma tx int |
||||
* IDST[1] : idma rx int |
||||
* IDST[2] : idma fatal bus error |
||||
* IDST[4] : idma descriptor invalid |
||||
* IDST[5] : idma error summary |
||||
* IDST[8] : idma normal interrupt sumary |
||||
* IDST[9] : idma abnormal interrupt sumary |
||||
*/ |
||||
status = readl(&mmchost->reg->idst); |
||||
writel(status, &mmchost->reg->idst); |
||||
writel(0, &mmchost->reg->idie); |
||||
writel(0, &mmchost->reg->dmac); |
||||
writel(readl(&mmchost->reg->gctrl) & ~SUNXI_MMC_GCTRL_DMA_ENABLE, |
||||
&mmchost->reg->gctrl); |
||||
} |
||||
if (error < 0) { |
||||
writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl); |
||||
mmc_update_clk(mmc); |
||||
} |
||||
writel(0xffffffff, &mmchost->reg->rint); |
||||
writel(readl(&mmchost->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET, |
||||
&mmchost->reg->gctrl); |
||||
|
||||
return error; |
||||
} |
||||
|
||||
static const struct mmc_ops sunxi_mmc_ops = { |
||||
.send_cmd = mmc_send_cmd, |
||||
.set_ios = mmc_set_ios, |
||||
.init = mmc_core_init, |
||||
}; |
||||
|
||||
int sunxi_mmc_init(int sdc_no) |
||||
{ |
||||
struct mmc_config *cfg = &mmc_host[sdc_no].cfg; |
||||
|
||||
memset(&mmc_host[sdc_no], 0, sizeof(struct sunxi_mmc_host)); |
||||
|
||||
cfg->name = "SUNXI SD/MMC"; |
||||
cfg->ops = &sunxi_mmc_ops; |
||||
|
||||
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; |
||||
cfg->host_caps = MMC_MODE_4BIT; |
||||
cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; |
||||
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; |
||||
|
||||
cfg->f_min = 400000; |
||||
cfg->f_max = 52000000; |
||||
|
||||
mmc_resource_init(sdc_no); |
||||
mmc_clk_io_on(sdc_no); |
||||
|
||||
if (mmc_create(cfg, &mmc_host[sdc_no]) == NULL) |
||||
return -1; |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,24 @@ |
||||
/*
|
||||
* (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net> |
||||
* (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net> |
||||
* |
||||
* Configuration settings for the Allwinner A20 (sun7i) CPU |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
#ifndef __CONFIG_H |
||||
#define __CONFIG_H |
||||
|
||||
/*
|
||||
* A20 specific configuration |
||||
*/ |
||||
#define CONFIG_SUN7I /* sun7i SoC generation */ |
||||
|
||||
#define CONFIG_SYS_PROMPT "sun7i# " |
||||
|
||||
/*
|
||||
* Include common sunxi configuration where most the settings are |
||||
*/ |
||||
#include <configs/sunxi-common.h> |
||||
|
||||
#endif /* __CONFIG_H */ |
@ -0,0 +1,195 @@ |
||||
/*
|
||||
* (C) Copyright 2012-2012 Henrik Nordstrom <henrik@henriknordstrom.net> |
||||
* |
||||
* (C) Copyright 2007-2011 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Tom Cubie <tangliang@allwinnertech.com> |
||||
* |
||||
* Configuration settings for the Allwinner sunxi series of boards. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _SUNXI_COMMON_CONFIG_H |
||||
#define _SUNXI_COMMON_CONFIG_H |
||||
|
||||
/*
|
||||
* High Level Configuration Options |
||||
*/ |
||||
#define CONFIG_SUNXI /* sunxi family */ |
||||
#ifdef CONFIG_SPL_BUILD |
||||
#ifndef CONFIG_SPL_FEL |
||||
#define CONFIG_SYS_THUMB_BUILD /* Thumbs mode to save space in SPL */ |
||||
#endif |
||||
#endif |
||||
|
||||
#include <asm/arch/cpu.h> /* get chip and board defs */ |
||||
|
||||
#define CONFIG_SYS_TEXT_BASE 0x4a000000 |
||||
|
||||
/*
|
||||
* Display CPU information |
||||
*/ |
||||
#define CONFIG_DISPLAY_CPUINFO |
||||
|
||||
/* Serial & console */ |
||||
#define CONFIG_SYS_NS16550 |
||||
#define CONFIG_SYS_NS16550_SERIAL |
||||
/* ns16550 reg in the low bits of cpu reg */ |
||||
#define CONFIG_SYS_NS16550_REG_SIZE -4 |
||||
#define CONFIG_SYS_NS16550_CLK 24000000 |
||||
#define CONFIG_SYS_NS16550_COM1 SUNXI_UART0_BASE |
||||
#define CONFIG_SYS_NS16550_COM2 SUNXI_UART1_BASE |
||||
#define CONFIG_SYS_NS16550_COM3 SUNXI_UART2_BASE |
||||
#define CONFIG_SYS_NS16550_COM4 SUNXI_UART3_BASE |
||||
|
||||
/* DRAM Base */ |
||||
#define CONFIG_SYS_SDRAM_BASE 0x40000000 |
||||
#define CONFIG_SYS_INIT_RAM_ADDR 0x0 |
||||
#define CONFIG_SYS_INIT_RAM_SIZE 0x8000 /* 32 KiB */ |
||||
|
||||
#define CONFIG_SYS_INIT_SP_OFFSET \ |
||||
(CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE) |
||||
#define CONFIG_SYS_INIT_SP_ADDR \ |
||||
(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET) |
||||
|
||||
#define CONFIG_NR_DRAM_BANKS 1 |
||||
#define PHYS_SDRAM_0 CONFIG_SYS_SDRAM_BASE |
||||
#define PHYS_SDRAM_0_SIZE 0x80000000 /* 2 GiB */ |
||||
|
||||
#define CONFIG_CMD_MEMORY |
||||
#define CONFIG_CMD_SETEXPR |
||||
|
||||
#define CONFIG_SETUP_MEMORY_TAGS |
||||
#define CONFIG_CMDLINE_TAG |
||||
#define CONFIG_INITRD_TAG |
||||
|
||||
/* mmc config */ |
||||
#define CONFIG_MMC |
||||
#define CONFIG_GENERIC_MMC |
||||
#define CONFIG_CMD_MMC |
||||
#define CONFIG_MMC_SUNXI |
||||
#define CONFIG_MMC_SUNXI_SLOT 0 |
||||
#define CONFIG_MMC_SUNXI_USE_DMA |
||||
#define CONFIG_ENV_IS_IN_MMC |
||||
#define CONFIG_SYS_MMC_ENV_DEV 0 /* first detected MMC controller */ |
||||
|
||||
/* 4MB of malloc() pool */ |
||||
#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (4 << 20)) |
||||
|
||||
/*
|
||||
* Miscellaneous configurable options |
||||
*/ |
||||
#define CONFIG_CMD_ECHO |
||||
#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ |
||||
#define CONFIG_SYS_PBSIZE 384 /* Print Buffer Size */ |
||||
#define CONFIG_SYS_MAXARGS 16 /* max number of command args */ |
||||
#define CONFIG_SYS_GENERIC_BOARD |
||||
|
||||
/* Boot Argument Buffer Size */ |
||||
#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE |
||||
|
||||
#define CONFIG_SYS_LOAD_ADDR 0x48000000 /* default load address */ |
||||
|
||||
/* standalone support */ |
||||
#define CONFIG_STANDALONE_LOAD_ADDR 0x48000000 |
||||
|
||||
#define CONFIG_SYS_HZ 1000 |
||||
|
||||
/* baudrate */ |
||||
#define CONFIG_BAUDRATE 115200 |
||||
|
||||
/* The stack sizes are set up in start.S using the settings below */ |
||||
#define CONFIG_STACKSIZE (256 << 10) /* 256 KiB */ |
||||
|
||||
/* FLASH and environment organization */ |
||||
|
||||
#define CONFIG_SYS_NO_FLASH |
||||
|
||||
#define CONFIG_SYS_MONITOR_LEN (512 << 10) /* 512 KiB */ |
||||
#define CONFIG_IDENT_STRING " Allwinner Technology" |
||||
|
||||
#define CONFIG_ENV_OFFSET (544 << 10) /* (8 + 24 + 512) KiB */ |
||||
#define CONFIG_ENV_SIZE (128 << 10) /* 128 KiB */ |
||||
|
||||
#define CONFIG_EXTRA_ENV_SETTINGS \ |
||||
"bootm_size=0x10000000\0" |
||||
|
||||
#define CONFIG_SYS_BOOT_GET_CMDLINE |
||||
|
||||
#include <config_cmd_default.h> |
||||
|
||||
#define CONFIG_FAT_WRITE /* enable write access */ |
||||
|
||||
#define CONFIG_SPL_FRAMEWORK |
||||
#define CONFIG_SPL_LIBCOMMON_SUPPORT |
||||
#define CONFIG_SPL_SERIAL_SUPPORT |
||||
#define CONFIG_SPL_LIBGENERIC_SUPPORT |
||||
|
||||
#ifdef CONFIG_SPL_FEL |
||||
|
||||
#define CONFIG_SPL |
||||
#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds" |
||||
#define CONFIG_SPL_START_S_PATH "arch/arm/cpu/armv7/sunxi" |
||||
#define CONFIG_SPL_TEXT_BASE 0x2000 |
||||
#define CONFIG_SPL_MAX_SIZE 0x4000 /* 16 KiB */ |
||||
|
||||
#else /* CONFIG_SPL */ |
||||
|
||||
#define CONFIG_SPL_BSS_START_ADDR 0x4ff80000 |
||||
#define CONFIG_SPL_BSS_MAX_SIZE 0x80000 /* 512 KiB */ |
||||
|
||||
#define CONFIG_SPL_TEXT_BASE 0x20 /* sram start+header */ |
||||
#define CONFIG_SPL_MAX_SIZE 0x5fe0 /* 24KB on sun4i/sun7i */ |
||||
|
||||
#define CONFIG_SPL_LIBDISK_SUPPORT |
||||
#define CONFIG_SPL_MMC_SUPPORT |
||||
|
||||
#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/sunxi/u-boot-spl.lds" |
||||
|
||||
#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 80 /* 40KiB */ |
||||
#define CONFIG_SPL_PAD_TO 32768 /* decimal for 'dd' */ |
||||
|
||||
#endif /* CONFIG_SPL */ |
||||
|
||||
/* end of 32 KiB in sram */ |
||||
#define LOW_LEVEL_SRAM_STACK 0x00008000 /* End of sram */ |
||||
#define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK |
||||
#define CONFIG_SYS_SPL_MALLOC_START 0x4ff00000 |
||||
#define CONFIG_SYS_SPL_MALLOC_SIZE 0x00080000 /* 512 KiB */ |
||||
|
||||
#undef CONFIG_CMD_FPGA |
||||
#undef CONFIG_CMD_NET |
||||
#undef CONFIG_CMD_NFS |
||||
|
||||
#define CONFIG_CONS_INDEX 1 /* UART0 */ |
||||
|
||||
#ifdef CONFIG_SUNXI_GMAC |
||||
#define CONFIG_DESIGNWARE_ETH /* GMAC can use designware driver */ |
||||
#define CONFIG_DW_AUTONEG |
||||
#define CONFIG_PHY_GIGE /* GMAC can use gigabit PHY */ |
||||
#define CONFIG_PHY_ADDR 1 |
||||
#define CONFIG_MII /* MII PHY management */ |
||||
#define CONFIG_PHYLIB |
||||
#endif |
||||
|
||||
#ifdef CONFIG_CMD_NET |
||||
#define CONFIG_CMD_NFS |
||||
#define CONFIG_CMD_DNS |
||||
#define CONFIG_NETCONSOLE |
||||
#define CONFIG_BOOTP_DNS2 |
||||
#define CONFIG_BOOTP_SEND_HOSTNAME |
||||
#endif |
||||
|
||||
#if !defined CONFIG_ENV_IS_IN_MMC && \ |
||||
!defined CONFIG_ENV_IS_IN_NAND && \
|
||||
!defined CONFIG_ENV_IS_IN_FAT && \
|
||||
!defined CONFIG_ENV_IS_IN_SPI_FLASH |
||||
#define CONFIG_ENV_IS_NOWHERE |
||||
#endif |
||||
|
||||
#ifndef CONFIG_SPL_BUILD |
||||
#include <config_distro_defaults.h> |
||||
#endif |
||||
|
||||
#endif /* _SUNXI_COMMON_CONFIG_H */ |
@ -0,0 +1,51 @@ |
||||
/*
|
||||
* (C) Copyright 2014 Andreas Bießmann <andreas.devel@googlemail.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
/*
|
||||
* This is a host tool for generating an appropriate string out of board |
||||
* configuration. The string is required for correct generation of PMECC |
||||
* header which in turn is required for NAND flash booting of Atmel AT91 style |
||||
* hardware. |
||||
* |
||||
* See doc/README.atmel_pmecc for more information. |
||||
*/ |
||||
|
||||
#include <config.h> |
||||
#include <stdlib.h> |
||||
|
||||
static int pmecc_get_ecc_bytes(int cap, int sector_size) |
||||
{ |
||||
int m = 12 + sector_size / 512; |
||||
return (m * cap + 7) / 8; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
unsigned int use_pmecc = 0; |
||||
unsigned int sector_per_page; |
||||
unsigned int sector_size = CONFIG_PMECC_SECTOR_SIZE; |
||||
unsigned int oob_size = CONFIG_SYS_NAND_OOBSIZE; |
||||
unsigned int ecc_bits = CONFIG_PMECC_CAP; |
||||
unsigned int ecc_offset; |
||||
|
||||
#ifdef CONFIG_ATMEL_NAND_HW_PMECC |
||||
use_pmecc = 1; |
||||
#endif |
||||
|
||||
sector_per_page = CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_PMECC_SECTOR_SIZE; |
||||
ecc_offset = oob_size - |
||||
pmecc_get_ecc_bytes(ecc_bits, sector_size) * sector_per_page; |
||||
|
||||
printf("usePmecc=%d,", use_pmecc); |
||||
printf("sectorPerPage=%d,", sector_per_page); |
||||
printf("sectorSize=%d,", sector_size); |
||||
printf("spareSize=%d,", oob_size); |
||||
printf("eccBits=%d,", ecc_bits); |
||||
printf("eccOffset=%d", ecc_offset); |
||||
printf("\n"); |
||||
|
||||
exit(EXIT_SUCCESS); |
||||
} |
@ -0,0 +1,342 @@ |
||||
/*
|
||||
* (C) Copyright 2014 |
||||
* Andreas Bießmann <andreas.devel@googlemail.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include "imagetool.h" |
||||
#include "mkimage.h" |
||||
|
||||
#include <image.h> |
||||
|
||||
#define pr_err(fmt, args...) fprintf(stderr, "atmelimage Error: " fmt, ##args) |
||||
|
||||
static int atmel_check_image_type(uint8_t type) |
||||
{ |
||||
if (type == IH_TYPE_ATMELIMAGE) |
||||
return EXIT_SUCCESS; |
||||
else |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
static uint32_t nand_pmecc_header[52]; |
||||
|
||||
/*
|
||||
* A helper struct for parsing the mkimage -n parameter |
||||
* |
||||
* Keep in same order as the configs array! |
||||
*/ |
||||
static struct pmecc_config { |
||||
int use_pmecc; |
||||
int sector_per_page; |
||||
int spare_size; |
||||
int ecc_bits; |
||||
int sector_size; |
||||
int ecc_offset; |
||||
} pmecc; |
||||
|
||||
/*
|
||||
* Strings used for configure the PMECC header via -n mkimage switch |
||||
* |
||||
* We estimate a coma separated list of key=value pairs. The mkimage -n |
||||
* parameter argument should not contain any whitespace. |
||||
* |
||||
* Keep in same order as struct pmecc_config! |
||||
*/ |
||||
static const char * const configs[] = { |
||||
"usePmecc", |
||||
"sectorPerPage", |
||||
"spareSize", |
||||
"eccBits", |
||||
"sectorSize", |
||||
"eccOffset" |
||||
}; |
||||
|
||||
static int atmel_find_pmecc_parameter_in_token(const char *token) |
||||
{ |
||||
size_t pos; |
||||
char *param; |
||||
|
||||
debug("token: '%s'\n", token); |
||||
|
||||
for (pos = 0; pos < ARRAY_SIZE(configs); pos++) { |
||||
if (strncmp(token, configs[pos], strlen(configs[pos])) == 0) { |
||||
param = strstr(token, "="); |
||||
if (!param) |
||||
goto err; |
||||
|
||||
param++; |
||||
debug("\t%s parameter: '%s'\n", configs[pos], param); |
||||
|
||||
switch (pos) { |
||||
case 0: |
||||
pmecc.use_pmecc = strtol(param, NULL, 10); |
||||
return EXIT_SUCCESS; |
||||
case 1: |
||||
pmecc.sector_per_page = strtol(param, NULL, 10); |
||||
return EXIT_SUCCESS; |
||||
case 2: |
||||
pmecc.spare_size = strtol(param, NULL, 10); |
||||
return EXIT_SUCCESS; |
||||
case 3: |
||||
pmecc.ecc_bits = strtol(param, NULL, 10); |
||||
return EXIT_SUCCESS; |
||||
case 4: |
||||
pmecc.sector_size = strtol(param, NULL, 10); |
||||
return EXIT_SUCCESS; |
||||
case 5: |
||||
pmecc.ecc_offset = strtol(param, NULL, 10); |
||||
return EXIT_SUCCESS; |
||||
} |
||||
} |
||||
} |
||||
|
||||
err: |
||||
pr_err("Could not find parameter in token '%s'\n", token); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
static int atmel_parse_pmecc_params(char *txt) |
||||
{ |
||||
char *token; |
||||
|
||||
token = strtok(txt, ","); |
||||
while (token != NULL) { |
||||
if (atmel_find_pmecc_parameter_in_token(token)) |
||||
return EXIT_FAILURE; |
||||
|
||||
token = strtok(NULL, ","); |
||||
} |
||||
|
||||
return EXIT_SUCCESS; |
||||
} |
||||
|
||||
static int atmel_verify_header(unsigned char *ptr, int image_size, |
||||
struct image_tool_params *params) |
||||
{ |
||||
uint32_t *ints = (uint32_t *)ptr; |
||||
size_t pos; |
||||
size_t size = image_size; |
||||
|
||||
/* check if we have an PMECC header attached */ |
||||
for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++) |
||||
if (ints[pos] >> 28 != 0xC) |
||||
break; |
||||
|
||||
if (pos == ARRAY_SIZE(nand_pmecc_header)) { |
||||
ints += ARRAY_SIZE(nand_pmecc_header); |
||||
size -= sizeof(nand_pmecc_header); |
||||
} |
||||
|
||||
/* check the seven interrupt vectors of binary */ |
||||
for (pos = 0; pos < 7; pos++) { |
||||
debug("atmelimage: interrupt vector #%d is 0x%08X\n", pos+1, |
||||
ints[pos]); |
||||
/*
|
||||
* all vectors except the 6'th one must contain valid |
||||
* LDR or B Opcode |
||||
*/ |
||||
if (pos == 5) |
||||
/* 6'th vector has image size set, check later */ |
||||
continue; |
||||
if ((ints[pos] & 0xff000000) == 0xea000000) |
||||
/* valid B Opcode */ |
||||
continue; |
||||
if ((ints[pos] & 0xfffff000) == 0xe59ff000) |
||||
/* valid LDR (I=0, P=1, U=1, B=0, W=0, L=1) */ |
||||
continue; |
||||
/* ouch, one of the checks has missed ... */ |
||||
return 1; |
||||
} |
||||
|
||||
return ints[5] != cpu_to_le32(size); |
||||
} |
||||
|
||||
static void atmel_print_pmecc_header(const uint32_t word) |
||||
{ |
||||
int val; |
||||
|
||||
printf("\t\tPMECC header\n"); |
||||
|
||||
printf("\t\t====================\n"); |
||||
|
||||
val = (word >> 18) & 0x1ff; |
||||
printf("\t\teccOffset: %9i\n", val); |
||||
|
||||
val = (((word >> 16) & 0x3) == 0) ? 512 : 1024; |
||||
printf("\t\tsectorSize: %8i\n", val); |
||||
|
||||
if (((word >> 13) & 0x7) <= 2) |
||||
val = (2 << ((word >> 13) & 0x7)); |
||||
else |
||||
val = (12 << (((word >> 13) & 0x7) - 3)); |
||||
printf("\t\teccBitReq: %9i\n", val); |
||||
|
||||
val = (word >> 4) & 0x1ff; |
||||
printf("\t\tspareSize: %9i\n", val); |
||||
|
||||
val = (1 << ((word >> 1) & 0x3)); |
||||
printf("\t\tnbSectorPerPage: %3i\n", val); |
||||
|
||||
printf("\t\tusePmecc: %10i\n", word & 0x1); |
||||
printf("\t\t====================\n"); |
||||
} |
||||
|
||||
static void atmel_print_header(const void *ptr) |
||||
{ |
||||
uint32_t *ints = (uint32_t *)ptr; |
||||
size_t pos; |
||||
|
||||
/* check if we have an PMECC header attached */ |
||||
for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++) |
||||
if (ints[pos] >> 28 != 0xC) |
||||
break; |
||||
|
||||
if (pos == ARRAY_SIZE(nand_pmecc_header)) { |
||||
printf("Image Type:\tATMEL ROM-Boot Image with PMECC Header\n"); |
||||
atmel_print_pmecc_header(ints[0]); |
||||
pos += 5; |
||||
} else { |
||||
printf("Image Type:\tATMEL ROM-Boot Image without PMECC Header\n"); |
||||
pos = 5; |
||||
} |
||||
printf("\t\t6'th vector has %u set\n", le32_to_cpu(ints[pos])); |
||||
} |
||||
|
||||
static void atmel_set_header(void *ptr, struct stat *sbuf, int ifd, |
||||
struct image_tool_params *params) |
||||
{ |
||||
/* just save the image size into 6'th interrupt vector */ |
||||
uint32_t *ints = (uint32_t *)ptr; |
||||
size_t cnt; |
||||
size_t pos = 5; |
||||
size_t size = sbuf->st_size; |
||||
|
||||
for (cnt = 0; cnt < ARRAY_SIZE(nand_pmecc_header); cnt++) |
||||
if (ints[cnt] >> 28 != 0xC) |
||||
break; |
||||
|
||||
if (cnt == ARRAY_SIZE(nand_pmecc_header)) { |
||||
pos += ARRAY_SIZE(nand_pmecc_header); |
||||
size -= sizeof(nand_pmecc_header); |
||||
} |
||||
|
||||
ints[pos] = cpu_to_le32(size); |
||||
} |
||||
|
||||
static int atmel_check_params(struct image_tool_params *params) |
||||
{ |
||||
if (strlen(params->imagename) > 0) |
||||
if (atmel_parse_pmecc_params(params->imagename)) |
||||
return EXIT_FAILURE; |
||||
|
||||
return !(!params->eflag && |
||||
!params->fflag && |
||||
!params->xflag && |
||||
((params->dflag && !params->lflag) || |
||||
(params->lflag && !params->dflag))); |
||||
} |
||||
|
||||
static int atmel_vrec_header(struct image_tool_params *params, |
||||
struct image_type_params *tparams) |
||||
{ |
||||
uint32_t tmp; |
||||
size_t pos; |
||||
|
||||
if (strlen(params->imagename) == 0) |
||||
return EXIT_SUCCESS; |
||||
|
||||
tmp = 0xC << 28; |
||||
|
||||
tmp |= (pmecc.ecc_offset & 0x1ff) << 18; |
||||
|
||||
switch (pmecc.sector_size) { |
||||
case 512: |
||||
tmp |= 0 << 16; |
||||
break; |
||||
case 1024: |
||||
tmp |= 1 << 16; |
||||
break; |
||||
|
||||
default: |
||||
pr_err("Wrong sectorSize (%i) for PMECC header\n", |
||||
pmecc.sector_size); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
switch (pmecc.ecc_bits) { |
||||
case 2: |
||||
tmp |= 0 << 13; |
||||
break; |
||||
case 4: |
||||
tmp |= 1 << 13; |
||||
break; |
||||
case 8: |
||||
tmp |= 2 << 13; |
||||
break; |
||||
case 12: |
||||
tmp |= 3 << 13; |
||||
break; |
||||
case 24: |
||||
tmp |= 4 << 13; |
||||
break; |
||||
|
||||
default: |
||||
pr_err("Wrong eccBits (%i) for PMECC header\n", |
||||
pmecc.ecc_bits); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
tmp |= (pmecc.spare_size & 0x1ff) << 4; |
||||
|
||||
switch (pmecc.sector_per_page) { |
||||
case 1: |
||||
tmp |= 0 << 1; |
||||
break; |
||||
case 2: |
||||
tmp |= 1 << 1; |
||||
break; |
||||
case 4: |
||||
tmp |= 2 << 1; |
||||
break; |
||||
case 8: |
||||
tmp |= 3 << 1; |
||||
break; |
||||
|
||||
default: |
||||
pr_err("Wrong sectorPerPage (%i) for PMECC header\n", |
||||
pmecc.sector_per_page); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
if (pmecc.use_pmecc) |
||||
tmp |= 1; |
||||
|
||||
for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++) |
||||
nand_pmecc_header[pos] = tmp; |
||||
|
||||
debug("PMECC header filled 52 times with 0x%08X\n", tmp); |
||||
|
||||
tparams->header_size = sizeof(nand_pmecc_header); |
||||
tparams->hdr = nand_pmecc_header; |
||||
|
||||
return EXIT_SUCCESS; |
||||
} |
||||
|
||||
static struct image_type_params atmelimage_params = { |
||||
.name = "ATMEL ROM-Boot Image support", |
||||
.header_size = 0, |
||||
.hdr = NULL, |
||||
.check_image_type = atmel_check_image_type, |
||||
.verify_header = atmel_verify_header, |
||||
.print_header = atmel_print_header, |
||||
.set_header = atmel_set_header, |
||||
.check_params = atmel_check_params, |
||||
.vrec_header = atmel_vrec_header, |
||||
}; |
||||
|
||||
void init_atmel_image_type(void) |
||||
{ |
||||
register_image_type(&atmelimage_params); |
||||
} |
@ -0,0 +1,142 @@ |
||||
/*
|
||||
* (C) Copyright 2007-2011 |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* Tom Cubie <tangliang@allwinnertech.com> |
||||
* |
||||
* a simple tool to generate bootable image for sunxi platform. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
#include <fcntl.h> |
||||
#include <stdio.h> |
||||
#include <unistd.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
|
||||
/* boot head definition from sun4i boot code */ |
||||
struct boot_file_head { |
||||
uint32_t b_instruction; /* one intruction jumping to real code */ |
||||
uint8_t magic[8]; /* ="eGON.BT0" or "eGON.BT1", not C-style str */ |
||||
uint32_t check_sum; /* generated by PC */ |
||||
uint32_t length; /* generated by PC */ |
||||
/*
|
||||
* We use a simplified header, only filling in what is needed |
||||
* by the boot ROM. To be compatible with Allwinner tools we |
||||
* would need to implement the proper fields here instead of |
||||
* padding. |
||||
*/ |
||||
uint8_t pad[12]; /* align to 32 bytes */ |
||||
}; |
||||
|
||||
#define BOOT0_MAGIC "eGON.BT0" |
||||
#define STAMP_VALUE 0x5F0A6C39 |
||||
|
||||
/* check sum functon from sun4i boot code */ |
||||
int gen_check_sum(struct boot_file_head *head_p) |
||||
{ |
||||
uint32_t length; |
||||
uint32_t *buf; |
||||
uint32_t loop; |
||||
uint32_t i; |
||||
uint32_t sum; |
||||
|
||||
length = head_p->length; |
||||
if ((length & 0x3) != 0) /* must 4-byte-aligned */ |
||||
return -1; |
||||
buf = (uint32_t *)head_p; |
||||
head_p->check_sum = STAMP_VALUE; /* fill stamp */ |
||||
loop = length >> 2; |
||||
|
||||
/* calculate the sum */ |
||||
for (i = 0, sum = 0; i < loop; i++) |
||||
sum += buf[i]; |
||||
|
||||
/* write back check sum */ |
||||
head_p->check_sum = sum; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
#define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a)-1) |
||||
#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) |
||||
|
||||
#define SUN4I_SRAM_SIZE 0x7600 /* 0x7748+ is used by BROM */ |
||||
#define SRAM_LOAD_MAX_SIZE (SUN4I_SRAM_SIZE - sizeof(struct boot_file_head)) |
||||
#define BLOCK_SIZE 512 |
||||
|
||||
struct boot_img { |
||||
struct boot_file_head header; |
||||
char code[SRAM_LOAD_MAX_SIZE]; |
||||
char pad[BLOCK_SIZE]; |
||||
}; |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
int fd_in, fd_out; |
||||
struct boot_img img; |
||||
unsigned file_size, load_size; |
||||
int count; |
||||
|
||||
if (argc < 2) { |
||||
printf("\tThis program makes an input bin file to sun4i " \
|
||||
"bootable image.\n" \
|
||||
"\tUsage: %s input_file out_putfile\n", argv[0]); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
fd_in = open(argv[1], O_RDONLY); |
||||
if (fd_in < 0) { |
||||
perror("Open input file"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
memset(img.pad, 0, BLOCK_SIZE); |
||||
|
||||
/* get input file size */ |
||||
file_size = lseek(fd_in, 0, SEEK_END); |
||||
|
||||
if (file_size > SRAM_LOAD_MAX_SIZE) { |
||||
fprintf(stderr, "ERROR: File too large!\n"); |
||||
return EXIT_FAILURE; |
||||
} else { |
||||
load_size = ALIGN(file_size, sizeof(int)); |
||||
} |
||||
|
||||
fd_out = open(argv[2], O_WRONLY | O_CREAT, 0666); |
||||
if (fd_out < 0) { |
||||
perror("Open output file"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
/* read file to buffer to calculate checksum */ |
||||
lseek(fd_in, 0, SEEK_SET); |
||||
count = read(fd_in, img.code, load_size); |
||||
if (count != load_size) { |
||||
perror("Reading input image"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
/* fill the header */ |
||||
img.header.b_instruction = /* b instruction */ |
||||
0xEA000000 | /* jump to the first instr after the header */ |
||||
((sizeof(struct boot_file_head) / sizeof(int) - 2) |
||||
& 0x00FFFFFF); |
||||
memcpy(img.header.magic, BOOT0_MAGIC, 8); /* no '0' termination */ |
||||
img.header.length = |
||||
ALIGN(load_size + sizeof(struct boot_file_head), BLOCK_SIZE); |
||||
gen_check_sum(&img.header); |
||||
|
||||
count = write(fd_out, &img, img.header.length); |
||||
if (count != img.header.length) { |
||||
perror("Writing output"); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
close(fd_in); |
||||
close(fd_out); |
||||
|
||||
return EXIT_SUCCESS; |
||||
} |
Loading…
Reference in new issue