[U-Boot] [PATCH v2 0/9] sunxi: initial upstreamining effort

This is my second cut at an upstreamable series based upon the https://github.com/linux-sunxi/u-boot-sunxi.git#sunxi tree. The intention is to present a minimal starting point for upstreaming to which support for other processors, peripherals, boards etc can be added in the future. Therefore this has been stripped right back and currently supports only sun7i processors AKA Allwinner A20 and the cubietruck board. Supported peripherals are UART, MMC and Ethernet.
The code here is from u-boot-sunxi.git#sunxi[0] changeset d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in and applies to u-boot v2014.04-rc2.
Global changes in v2: - Use SPDX-License-Identifier - Resync with u-boot-sunxi.git - Lot of updates to the individual patches, see the individual commit messages (checkpatch.pl fixes, magic number removal etc). - Pulled the Ethernet stuff before the MMC and non-FEL boot stuff. The MMC stuff (which non-FEL boot needs) still needs some more cleanup, but the reordering means that the initial part of the series could in principal go in.
This series can also be found at:
git://gitorious.org/ijc/u-boot.git sunxi-mainlining-v2
The merged sunxi tree which it is based on is:
git://gitorious.org/ijc/u-boot.git sunxi-merge-v2014.04-rc2
There is no SMP here, since that relies on the PSCI support from Marc Zyngier which has yet to land in mainline AFAIK.
I've tried to give corect credit and S-o-b based upon: git log --pretty='%aN' linux-sunxi/sunxi -- [PATHS] | sort -u git log linux-sunxi/sunxi -- [PATHS] | grep -i signed.off.by | sort -u Manual inspection
This will tend to over credit, since it will include folks who contributed code which has since been removed as well as those who contributed code which is not included in this patch set, but I think it is better to be conservative and include too many rather than incorrectly exclude people. Doing better than this would be IMHO too hard to be worth it (e.g. git blame would prefer a recent whitespace cleanup to the actual author of the code and prefer someone did code motion over the original author, so it would be a massive & manual process).

This has been stripped back for mainlining and supports only sun7i. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Alejandro Mery Carl van Schaik Stefan Roese Tom Cubie yemao
Signed-off-by: Alexandru Gagniuc mr.nuke.me@gmail.com Signed-off-by: Chen-Yu Tsai wens@csie.org Signed-off-by: Emilio López emilio@elopez.com.ar Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Jens Kuske jenskuske@gmail.com Signed-off-by: Luke Leighton lkcl@lkcl.net Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Ian Campbell ijc@hellion.org.uk
--- v2: Based on u-boot-sunxi.git#sunxi d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in: - define magic numbers - simplify get_tbclk - correct clock_set_pll1 prototype - add CONFIG_SUN7I to simplify future SUN?I support. - defines for MMC AHB clocks
v1: Based on u-boot-sunxi.git#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01. --- arch/arm/cpu/armv7/sunxi/Makefile | 11 ++ arch/arm/cpu/armv7/sunxi/clock.c | 180 +++++++++++++++++++++ arch/arm/cpu/armv7/sunxi/timer.c | 102 ++++++++++++ arch/arm/include/asm/arch-sunxi/clock.h | 237 ++++++++++++++++++++++++++++ arch/arm/include/asm/arch-sunxi/sys_proto.h | 17 ++ arch/arm/include/asm/arch-sunxi/timer.h | 88 +++++++++++ 6 files changed, 635 insertions(+) create mode 100644 arch/arm/cpu/armv7/sunxi/Makefile create mode 100644 arch/arm/cpu/armv7/sunxi/clock.c create mode 100644 arch/arm/cpu/armv7/sunxi/timer.c create mode 100644 arch/arm/include/asm/arch-sunxi/clock.h create mode 100644 arch/arm/include/asm/arch-sunxi/sys_proto.h create mode 100644 arch/arm/include/asm/arch-sunxi/timer.h
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile new file mode 100644 index 0000000..787a127 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -0,0 +1,11 @@ +# +# (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 += clock.o diff --git a/arch/arm/cpu/armv7/sunxi/clock.c b/arch/arm/cpu/armv7/sunxi/clock.c new file mode 100644 index 0000000..dd01be6 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/clock.c @@ -0,0 +1,180 @@ +/* + * (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 +static void clock_init_safe(void) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + + /* Set safe defaults until PMU is configured */ + writel(AXI_DIV_1 << 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); + writel(0x1 << PLL6_ENABLE_OFFSET | readl(&ccm->pll6_cfg), + &ccm->pll6_cfg); +#endif +} +#endif + +int clock_init(void) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + +#ifdef CONFIG_SPL_BUILD + clock_init_safe(); +#endif + + /* uart clock source is apb1 */ + sr32(&ccm->apb1_clk_div_cfg, 24, 2, APB1_CLK_SRC_OSC24M); + sr32(&ccm->apb1_clk_div_cfg, 16, 2, APB1_FACTOR_N); + sr32(&ccm->apb1_clk_div_cfg, 0, 5, APB1_FACTOR_M); + + /* open the clock for uart */ + sr32(&ccm->apb1_gate, 16 + CONFIG_CONS_INDEX - 1, 1, CLK_GATE_OPEN); + + return 0; +} + +/* Return PLL5 frequency in Hz + * Note: Assumes PLL5 reference is 24MHz clock + */ +unsigned int clock_get_pll5(void) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + uint32_t rval = readl(&ccm->pll5_cfg); + int n = (rval >> 8) & 0x1f; + int k = ((rval >> 4) & 3) + 1; + int p = 1 << ((rval >> 16) & 3); + return 24000000 * n * k / p; +} + +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 apb1 clock gate for twi */ + sr32(&ccm->apb1_gate, 0 + port, 1, state); + + return 0; +} + +#ifdef CONFIG_SPL_BUILD +#define PLL1_CFG(N, K, M, P) (1 << 31 | 0 << 30 | 8 << 26 | 0 << 25 | \ + 16 << 20 | (P) << 16 | 2 << 13 | (N) << 8 | \ + (K) << 4 | 0 << 3 | 0 << 2 | (M) << 0) +#define RDIV(a, b) ((a + (b) - 1) / (b)) + +struct { + u32 pll1_cfg; + unsigned int freq; +} pll1_para[] = { + { PLL1_CFG(16, 0, 0, 0), 384000000 }, + { PLL1_CFG(16, 1, 0, 0), 768000000 }, + { PLL1_CFG(20, 1, 0, 0), 960000000 }, + { PLL1_CFG(21, 1, 0, 0), 1008000000}, + { PLL1_CFG(22, 1, 0, 0), 1056000000}, + { PLL1_CFG(23, 1, 0, 0), 1104000000}, + { PLL1_CFG(24, 1, 0, 0), 1152000000}, + { PLL1_CFG(25, 1, 0, 0), 1200000000}, + { PLL1_CFG(26, 1, 0, 0), 1248000000}, + { PLL1_CFG(27, 1, 0, 0), 1296000000}, + { PLL1_CFG(28, 1, 0, 0), 1344000000}, + { PLL1_CFG(29, 1, 0, 0), 1392000000}, + { PLL1_CFG(30, 1, 0, 0), 1440000000}, + { PLL1_CFG(31, 1, 0, 0), 1488000000}, + { PLL1_CFG(31, 1, 0, 0), ~0}, +}; + +void clock_set_pll1(int hz) +{ + int i = 0; + int axi, ahb, apb0; + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + + /* Find target frequency */ + while (pll1_para[i].freq < hz) + i++; + + hz = pll1_para[i].freq; + + /* Calculate system clock divisors */ + axi = RDIV(hz, 432000000); /* Max 450MHz */ + ahb = RDIV(hz/axi, 204000000); /* Max 250MHz */ + apb0 = 2; /* Max 150MHz */ + + printf("CPU: %dHz, 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 diff --git a/arch/arm/cpu/armv7/sunxi/timer.c b/arch/arm/cpu/armv7/sunxi/timer.c new file mode 100644 index 0000000..d0d9953 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/timer.c @@ -0,0 +1,102 @@ +/* + * (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 */ + +static struct sunxi_timer *timer_base = + &((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->timer[TIMER_NUM]; + +/* macro to read the 32 bit timer: since it decrements, we invert read value */ +#define READ_TIMER() (~readl(&timer_base->val)) + +/* init timer register */ +int timer_init(void) +{ + writel(TIMER_LOAD_VAL, &timer_base->inter); + writel(TIMER_MODE | TIMER_DIV | TIMER_SRC | TIMER_RELOAD | TIMER_EN, + &timer_base->ctl); + + return 0; +} + +/* timer without interrupts */ +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +ulong get_timer_masked(void) +{ + /* current tick value */ + ulong now = TICKS_TO_HZ(READ_TIMER()); + + if (now >= gd->arch.lastinc) /* normal (non rollover) */ + gd->arch.tbl += (now - gd->arch.lastinc); + else { + /* rollover */ + gd->arch.tbl += (TICKS_TO_HZ(TIMER_LOAD_VAL) + - gd->arch.lastinc) + now; + } + gd->arch.lastinc = now; + + return gd->arch.tbl; +} + +/* delay x useconds */ +void __udelay(unsigned long usec) +{ + long tmo = USEC_TO_COUNT(usec); + ulong now, last = READ_TIMER(); + + while (tmo > 0) { + now = READ_TIMER(); + if (now > last) /* normal (non rollover) */ + tmo -= now - last; + else /* rollover */ + tmo -= TIMER_LOAD_VAL - last + now; + last = now; + } +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} diff --git a/arch/arm/include/asm/arch-sunxi/clock.h b/arch/arm/include/asm/arch-sunxi/clock.h new file mode 100644 index 0000000..defd229 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/clock.h @@ -0,0 +1,237 @@ +/* + * (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> + +/* clock control module regs definition */ + +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 0 +#define APB1_FACTOR_M 0 +#define APB1_FACTOR_N 0 + +/* 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 PLL1_CFG_DEFAULT 0xa1005000 + +#define PLL6_ENABLE_OFFSET 31 + +#define CLK_GATE_OPEN 0x1 +#define CLK_GATE_CLOSE 0x0 + +/* 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_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) + + +#ifndef __ASSEMBLY__ +int clock_init(void); +int clock_twi_onoff(int port, int state); +void clock_set_pll1(int hz); +unsigned int clock_get_pll5(void); +#endif + +#endif /* _SUNXI_CLOCK_H */ diff --git a/arch/arm/include/asm/arch-sunxi/sys_proto.h b/arch/arm/include/asm/arch-sunxi/sys_proto.h new file mode 100644 index 0000000..61b29d8 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/sys_proto.h @@ -0,0 +1,17 @@ +/* + * (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 sr32(u32 *, u32, u32, u32); +void sdelay(unsigned long); + +#endif diff --git a/arch/arm/include/asm/arch-sunxi/timer.h b/arch/arm/include/asm/arch-sunxi/timer.h new file mode 100644 index 0000000..6aacfd7 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/timer.h @@ -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

On Friday, March 21, 2014 at 10:54:18 PM, Ian Campbell wrote:
This has been stripped back for mainlining and supports only sun7i. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
[...]
+int clock_init(void) +{
- struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+#ifdef CONFIG_SPL_BUILD
- clock_init_safe();
+#endif
- /* uart clock source is apb1 */
- sr32(&ccm->apb1_clk_div_cfg, 24, 2, APB1_CLK_SRC_OSC24M);
- sr32(&ccm->apb1_clk_div_cfg, 16, 2, APB1_FACTOR_N);
- sr32(&ccm->apb1_clk_div_cfg, 0, 5, APB1_FACTOR_M);
sr32() is not defined anywhere.
- /* open the clock for uart */
- sr32(&ccm->apb1_gate, 16 + CONFIG_CONS_INDEX - 1, 1, CLK_GATE_OPEN);
- return 0;
+}
+/* Return PLL5 frequency in Hz
- Note: Assumes PLL5 reference is 24MHz clock
- */
+unsigned int clock_get_pll5(void) +{
- struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- uint32_t rval = readl(&ccm->pll5_cfg);
- int n = (rval >> 8) & 0x1f;
- int k = ((rval >> 4) & 3) + 1;
- int p = 1 << ((rval >> 16) & 3);
- return 24000000 * n * k / p;
Please fix the magic values here. [...]
+#ifdef CONFIG_SPL_BUILD +#define PLL1_CFG(N, K, M, P) (1 << 31 | 0 << 30 | 8 << 26 | 0 << 25 |
\
16 << 20 | (P) << 16 | 2 << 13 | (N) << 8 | \
(K) << 4 | 0 << 3 | 0 << 2 | (M) << 0)
Here is well.
+#define RDIV(a, b) ((a + (b) - 1) / (b))
This is some kind of DIV_ROUND_UP() from include/common.h ?
[...]
- /* 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);
What is sdelay() function all about ?
[...]
+static struct sunxi_timer *timer_base =
- &((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->timer[TIMER_NUM];
+/* macro to read the 32 bit timer: since it decrements, we invert read value */ +#define READ_TIMER() (~readl(&timer_base->val))
This macro has to go, just use ~readl() in place. But still, why do you use that negation in "~readl()" anyway ?
[...]

On 03/24/2014 09:52 PM, Marek Vasut wrote:
On Friday, March 21, 2014 at 10:54:18 PM, Ian Campbell wrote:
This has been stripped back for mainlining and supports only sun7i. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
[...]
+int clock_init(void) +{
- struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+#ifdef CONFIG_SPL_BUILD
- clock_init_safe();
+#endif
- /* uart clock source is apb1 */
- sr32(&ccm->apb1_clk_div_cfg, 24, 2, APB1_CLK_SRC_OSC24M);
- sr32(&ccm->apb1_clk_div_cfg, 16, 2, APB1_FACTOR_N);
- sr32(&ccm->apb1_clk_div_cfg, 0, 5, APB1_FACTOR_M);
sr32() is not defined anywhere.
it should be defined in arch/arm/include/asm/arch-sunxi/sys_proto.h and comes from arch/arm/cpu/armv7/syslib.c
it was added for the ti omap's
I've got a local cleanup patch set where I fixed this already to clrsetbits_le32
- /* open the clock for uart */
- sr32(&ccm->apb1_gate, 16 + CONFIG_CONS_INDEX - 1, 1, CLK_GATE_OPEN);
- return 0;
+}
+/* Return PLL5 frequency in Hz
- Note: Assumes PLL5 reference is 24MHz clock
- */
+unsigned int clock_get_pll5(void) +{
- struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- uint32_t rval = readl(&ccm->pll5_cfg);
- int n = (rval >> 8) & 0x1f;
- int k = ((rval >> 4) & 3) + 1;
- int p = 1 << ((rval >> 16) & 3);
- return 24000000 * n * k / p;
Please fix the magic values here. [...]
Same here, got that in my local tree too
+#ifdef CONFIG_SPL_BUILD +#define PLL1_CFG(N, K, M, P) (1 << 31 | 0 << 30 | 8 << 26 | 0 << 25 |
\
16 << 20 | (P) << 16 | 2 << 13 | (N) << 8 | \
(K) << 4 | 0 << 3 | 0 << 2 | (M) << 0)
Here is well.
dito :)
+#define RDIV(a, b) ((a + (b) - 1) / (b))
This is some kind of DIV_ROUND_UP() from include/common.h ?
[...]
That one i didn't have;
Ian, I guess you can verify that generic macro works for here?
- /* 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);
What is sdelay() function all about ?
It also is from arch/arm/include/asm/arch-sunxi/sys_proto.h and I thought all where replaced with udelays
With the sr32 and sdelays gone everywhere, sunxi/sys_proto.h can even go!
[...]
+static struct sunxi_timer *timer_base =
- &((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->timer[TIMER_NUM];
+/* macro to read the 32 bit timer: since it decrements, we invert read value */ +#define READ_TIMER() (~readl(&timer_base->val))
This macro has to go, just use ~readl() in place. But still, why do you use that negation in "~readl()" anyway ?
[...]
Olliver

On Monday, March 24, 2014 at 11:42:17 PM, Olliver Schinagl wrote:
On 03/24/2014 09:52 PM, Marek Vasut wrote:
On Friday, March 21, 2014 at 10:54:18 PM, Ian Campbell wrote:
This has been stripped back for mainlining and supports only sun7i. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
[...]
+int clock_init(void) +{
- struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+#ifdef CONFIG_SPL_BUILD
- clock_init_safe();
+#endif
- /* uart clock source is apb1 */
- sr32(&ccm->apb1_clk_div_cfg, 24, 2, APB1_CLK_SRC_OSC24M);
- sr32(&ccm->apb1_clk_div_cfg, 16, 2, APB1_FACTOR_N);
- sr32(&ccm->apb1_clk_div_cfg, 0, 5, APB1_FACTOR_M);
sr32() is not defined anywhere.
it should be defined in arch/arm/include/asm/arch-sunxi/sys_proto.h and comes from arch/arm/cpu/armv7/syslib.c
it was added for the ti omap's
I've got a local cleanup patch set where I fixed this already to clrsetbits_le32
It's not part of this patch, but then, use clrsetbits_le32() instead of course.
- /* open the clock for uart */
- sr32(&ccm->apb1_gate, 16 + CONFIG_CONS_INDEX - 1, 1, CLK_GATE_OPEN);
- return 0;
+}
+/* Return PLL5 frequency in Hz
- Note: Assumes PLL5 reference is 24MHz clock
- */
+unsigned int clock_get_pll5(void) +{
- struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- uint32_t rval = readl(&ccm->pll5_cfg);
- int n = (rval >> 8) & 0x1f;
- int k = ((rval >> 4) & 3) + 1;
- int p = 1 << ((rval >> 16) & 3);
- return 24000000 * n * k / p;
Please fix the magic values here. [...]
Same here, got that in my local tree too
Then make it part of the V3 please.
[...]

Dear Olliver Schinagl,
In message 5330B4C9.10302@schinagl.nl you wrote:
sr32() is not defined anywhere.
it should be defined in arch/arm/include/asm/arch-sunxi/sys_proto.h and comes from arch/arm/cpu/armv7/syslib.c
Please avoid using sr32() alltogether. It is basically only used in a single file (arch/arm/cpu/armv7/omap3/clock.c) [plus a single call in board/ti/panda/panda.c] and should be replaced by standard I/O accessor functions. I will prepare a patch to remove it from mainline soon, so better don't start using it.
Thanks.
Wolfgang Denk

On Mon, 2014-03-24 at 23:42 +0100, Olliver Schinagl wrote: [...]
I've got a local cleanup patch set where I fixed this already to clrsetbits_le32 [...] Same here, got that in my local tree too
Could you post what you've got please?
+#ifdef CONFIG_SPL_BUILD +#define PLL1_CFG(N, K, M, P) (1 << 31 | 0 << 30 | 8 << 26 | 0 << 25 |
\
16 << 20 | (P) << 16 | 2 << 13 | (N) << 8 | \
(K) << 4 | 0 << 3 | 0 << 2 | (M) << 0)
Here is well.
dito :)
+#define RDIV(a, b) ((a + (b) - 1) / (b))
This is some kind of DIV_ROUND_UP() from include/common.h ?
[...]
That one i didn't have;
Ian, I guess you can verify that generic macro works for here?
Yeah, I'll look into that and all the other feedback from Marek.
Ian.

On Mon, 2014-03-24 at 23:42 +0100, Olliver Schinagl wrote:
On 03/24/2014 09:52 PM, Marek Vasut wrote:
- /* 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);
What is sdelay() function all about ?
It also is from arch/arm/include/asm/arch-sunxi/sys_proto.h and I thought all where replaced with udelays
Since these sdelays() are used while we are frobbing around with the clocks I'm not sure that switching to udelay is possible/wise. sdelay is documented as: * sdelay() - simple spin loop. Will be constant time as * its generally used in bypass conditions only. This * is necessary until timers are accessible.
IOW it sounds like it is designed to be used in exactly these circumstances.
Given the lack of documentation for what is actually required by the hardware when changing these clocks I'm a bit reluctant to go changing things.
Ian.

On Sunday, April 13, 2014 at 09:55:57 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 23:42 +0100, Olliver Schinagl wrote:
On 03/24/2014 09:52 PM, Marek Vasut wrote:
- /* 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);
What is sdelay() function all about ?
It also is from arch/arm/include/asm/arch-sunxi/sys_proto.h and I thought all where replaced with udelays
Since these sdelays() are used while we are frobbing around with the clocks I'm not sure that switching to udelay is possible/wise. sdelay is documented as:
- sdelay() - simple spin loop. Will be constant time as
- its generally used in bypass conditions only. This
- is necessary until timers are accessible.
IOW it sounds like it is designed to be used in exactly these circumstances.
Given the lack of documentation for what is actually required by the hardware when changing these clocks I'm a bit reluctant to go changing things.
Don't you have an clock-agnostic timer in the chip ? If not, well, can't be helped.
Best regards, Marek Vasut

On Mon, 2014-03-24 at 21:52 +0100, Marek Vasut wrote:
On Friday, March 21, 2014 at 10:54:18 PM, Ian Campbell wrote:
This has been stripped back for mainlining and supports only sun7i. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
[...]
Thanks for all your feedback here and on the other patches, I'll sort it all out.
Ian.

On Mon, 2014-03-24 at 21:52 +0100, Marek Vasut wrote:
+static struct sunxi_timer *timer_base =
&((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->timer[TIMER_NUM];
+/* macro to read the 32 bit timer: since it decrements, we invert read value */ +#define READ_TIMER() (~readl(&timer_base->val))
This macro has to go, just use ~readl() in place. But still, why do you use that negation in "~readl()" anyway ?
The comment right above it explains why: the timer counts backwards and inverting it accounts for that.
This is subtle enough that I don't think using ~readl() in place in the 3 callers would be an improvement.
Ian.

On Thursday, March 27, 2014 at 10:29:56 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 21:52 +0100, Marek Vasut wrote:
+static struct sunxi_timer *timer_base =
&((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->timer[TIMER_NUM];
+/* macro to read the 32 bit timer: since it decrements, we invert read value */ +#define READ_TIMER() (~readl(&timer_base->val))
This macro has to go, just use ~readl() in place. But still, why do you use that negation in "~readl()" anyway ?
The comment right above it explains why: the timer counts backwards and inverting it accounts for that.
This is subtle enough that I don't think using ~readl() in place in the 3 callers would be an improvement.
Please do it, we don't want any implementers down the line using this "READ_TIMER()" call and getting hit by "timer_base undefined" . That macro hides the dependency on this symbol, while if you expanded it in-place, the dependency would be explicit. I really do want to see that macro gone, sorry.
Best regards, Marek Vasut

On Thu, 2014-03-27 at 23:00 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 10:29:56 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 21:52 +0100, Marek Vasut wrote:
+static struct sunxi_timer *timer_base =
&((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->timer[TIMER_NUM];
+/* macro to read the 32 bit timer: since it decrements, we invert read value */ +#define READ_TIMER() (~readl(&timer_base->val))
This macro has to go, just use ~readl() in place. But still, why do you use that negation in "~readl()" anyway ?
The comment right above it explains why: the timer counts backwards and inverting it accounts for that.
This is subtle enough that I don't think using ~readl() in place in the 3 callers would be an improvement.
Please do it, we don't want any implementers down the line using this "READ_TIMER()" call and getting hit by "timer_base undefined" . That macro hides the dependency on this symbol, while if you expanded it in-place, the dependency would be explicit. I really do want to see that macro gone, sorry.
How about a static inline instead of the macro? I'm thinking with a body: { struct sunxi_timer *timers = (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; return timers[TIMER_NUM]->val; } With something similar in timer_init then both the macro and the static global timer_base can be dropped.
BTW this macro is in arch/arm/cpu/armv7/sunxi/timer.c not a header, so I'm not sure which implementers down the line you were worried about using it in some other context where it breaks.
Ian.

On Thursday, March 27, 2014 at 11:12:38 PM, Ian Campbell wrote:
On Thu, 2014-03-27 at 23:00 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 10:29:56 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 21:52 +0100, Marek Vasut wrote:
+static struct sunxi_timer *timer_base =
&((struct sunxi_timer_reg
*)SUNXI_TIMER_BASE)->timer[TIMER_NUM]; + +/* macro to read the 32 bit timer: since it decrements, we invert read value */ +#define READ_TIMER() (~readl(&timer_base->val))
This macro has to go, just use ~readl() in place. But still, why do you use that negation in "~readl()" anyway ?
The comment right above it explains why: the timer counts backwards and inverting it accounts for that.
This is subtle enough that I don't think using ~readl() in place in the 3 callers would be an improvement.
Please do it, we don't want any implementers down the line using this "READ_TIMER()" call and getting hit by "timer_base undefined" . That macro hides the dependency on this symbol, while if you expanded it in-place, the dependency would be explicit. I really do want to see that macro gone, sorry.
How about a static inline instead of the macro? I'm thinking with a body: { struct sunxi_timer *timers = (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; return timers[TIMER_NUM]->val; } With something similar in timer_init then both the macro and the static global timer_base can be dropped.
That's just wrapping a readl() into another function, which seems unnecessary really.
BTW this macro is in arch/arm/cpu/armv7/sunxi/timer.c not a header, so I'm not sure which implementers down the line you were worried about using it in some other context where it breaks.
People plumbing in the timer.c file who are not aware the macro has a dependency which is not passed as it's parameter.
Best regards, Marek Vasut

On Thu, 2014-03-27 at 23:36 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 11:12:38 PM, Ian Campbell wrote:
On Thu, 2014-03-27 at 23:00 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 10:29:56 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 21:52 +0100, Marek Vasut wrote:
+static struct sunxi_timer *timer_base =
&((struct sunxi_timer_reg
*)SUNXI_TIMER_BASE)->timer[TIMER_NUM]; + +/* macro to read the 32 bit timer: since it decrements, we invert read value */ +#define READ_TIMER() (~readl(&timer_base->val))
This macro has to go, just use ~readl() in place. But still, why do you use that negation in "~readl()" anyway ?
The comment right above it explains why: the timer counts backwards and inverting it accounts for that.
This is subtle enough that I don't think using ~readl() in place in the 3 callers would be an improvement.
Please do it, we don't want any implementers down the line using this "READ_TIMER()" call and getting hit by "timer_base undefined" . That macro hides the dependency on this symbol, while if you expanded it in-place, the dependency would be explicit. I really do want to see that macro gone, sorry.
How about a static inline instead of the macro? I'm thinking with a body: { struct sunxi_timer *timers = (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; return timers[TIMER_NUM]->val; } With something similar in timer_init then both the macro and the static global timer_base can be dropped.
That's just wrapping a readl() into another function, which seems unnecessary really.
Sorry, but I think inlining the readl (and along with it the interesting/subtle) inverting functionality is a terrible idea, it should be wrapped in some sort of accessor precisely because it is not a raw readl.
I'm going to make it a function as I suggested.
BTW this macro is in arch/arm/cpu/armv7/sunxi/timer.c not a header, so I'm not sure which implementers down the line you were worried about using it in some other context where it breaks.
People plumbing in the timer.c file who are not aware the macro has a dependency which is not passed as it's parameter.
What people? What plumbing? I've no idea what you are concerned about here.
Ian.

On Friday, March 28, 2014 at 09:20:17 AM, Ian Campbell wrote:
On Thu, 2014-03-27 at 23:36 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 11:12:38 PM, Ian Campbell wrote:
On Thu, 2014-03-27 at 23:00 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 10:29:56 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 21:52 +0100, Marek Vasut wrote:
> +static struct sunxi_timer *timer_base = > + &((struct sunxi_timer_reg > *)SUNXI_TIMER_BASE)->timer[TIMER_NUM]; + > +/* macro to read the 32 bit timer: since it decrements, we > invert read value */ +#define READ_TIMER() > (~readl(&timer_base->val))
This macro has to go, just use ~readl() in place. But still, why do you use that negation in "~readl()" anyway ?
The comment right above it explains why: the timer counts backwards and inverting it accounts for that.
This is subtle enough that I don't think using ~readl() in place in the 3 callers would be an improvement.
Please do it, we don't want any implementers down the line using this "READ_TIMER()" call and getting hit by "timer_base undefined" . That macro hides the dependency on this symbol, while if you expanded it in-place, the dependency would be explicit. I really do want to see that macro gone, sorry.
How about a static inline instead of the macro? I'm thinking with a body: {
struct sunxi_timer *timers = (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; return timers[TIMER_NUM]->val;
} With something similar in timer_init then both the macro and the static global timer_base can be dropped.
That's just wrapping a readl() into another function, which seems unnecessary really.
Sorry, but I think inlining the readl (and along with it the interesting/subtle) inverting functionality is a terrible idea, it should be wrapped in some sort of accessor precisely because it is not a raw readl.
I'm going to make it a function as I suggested.
BTW this macro is in arch/arm/cpu/armv7/sunxi/timer.c not a header, so I'm not sure which implementers down the line you were worried about using it in some other context where it breaks.
People plumbing in the timer.c file who are not aware the macro has a dependency which is not passed as it's parameter.
What people? What plumbing? I've no idea what you are concerned about here.
OK, I will wait for V3 of the patch since this discussion have gone awry . Let's talk about V3 , ok ? :)
Best regards, Marek Vasut

Hi,
On 03/28/2014 09:20 AM, Ian Campbell wrote:
On Thu, 2014-03-27 at 23:36 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 11:12:38 PM, Ian Campbell wrote:
On Thu, 2014-03-27 at 23:00 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 10:29:56 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 21:52 +0100, Marek Vasut wrote:
> +static struct sunxi_timer *timer_base = > + &((struct sunxi_timer_reg > *)SUNXI_TIMER_BASE)->timer[TIMER_NUM]; + > +/* macro to read the 32 bit timer: since it decrements, we invert > read value */ +#define READ_TIMER() (~readl(&timer_base->val))
This macro has to go, just use ~readl() in place. But still, why do you use that negation in "~readl()" anyway ?
The comment right above it explains why: the timer counts backwards and inverting it accounts for that.
This is subtle enough that I don't think using ~readl() in place in the 3 callers would be an improvement.
Please do it, we don't want any implementers down the line using this "READ_TIMER()" call and getting hit by "timer_base undefined" . That macro hides the dependency on this symbol, while if you expanded it in-place, the dependency would be explicit. I really do want to see that macro gone, sorry.
How about a static inline instead of the macro? I'm thinking with a body: { struct sunxi_timer *timers = (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; return timers[TIMER_NUM]->val; } With something similar in timer_init then both the macro and the static global timer_base can be dropped.
That's just wrapping a readl() into another function, which seems unnecessary really.
Sorry, but I think inlining the readl (and along with it the interesting/subtle) inverting functionality is a terrible idea, it should be wrapped in some sort of accessor precisely because it is not a raw readl.
I'm going to make it a function as I suggested.
BTW this macro is in arch/arm/cpu/armv7/sunxi/timer.c not a header, so I'm not sure which implementers down the line you were worried about using it in some other context where it breaks.
People plumbing in the timer.c file who are not aware the macro has a dependency which is not passed as it's parameter.
What people? What plumbing? I've no idea what you are concerned about here.
I think what Marek is concerned about is people making some global u-boot change which for some reason requires fixing up a bunch of platform specific files, and they end up touching our timer.c without ever test-compiling it.
These kind of things happen in qemu / the kernel too. In this case they could move a READ_TIMER() somewhere where the timer_base is not defined. Your suggestion of making it a proper function will fix that though, and I think is the best solution.
Regards,
Hans

On Friday, March 28, 2014 at 09:25:40 AM, Hans de Goede wrote:
Hi,
On 03/28/2014 09:20 AM, Ian Campbell wrote:
On Thu, 2014-03-27 at 23:36 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 11:12:38 PM, Ian Campbell wrote:
On Thu, 2014-03-27 at 23:00 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 10:29:56 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 21:52 +0100, Marek Vasut wrote: >> +static struct sunxi_timer *timer_base = >> + &((struct sunxi_timer_reg >> *)SUNXI_TIMER_BASE)->timer[TIMER_NUM]; + >> +/* macro to read the 32 bit timer: since it decrements, we invert >> read value */ +#define READ_TIMER() (~readl(&timer_base->val)) > > This macro has to go, just use ~readl() in place. But still, why do > you use that negation in "~readl()" anyway ?
The comment right above it explains why: the timer counts backwards and inverting it accounts for that.
This is subtle enough that I don't think using ~readl() in place in the 3 callers would be an improvement.
Please do it, we don't want any implementers down the line using this "READ_TIMER()" call and getting hit by "timer_base undefined" . That macro hides the dependency on this symbol, while if you expanded it in-place, the dependency would be explicit. I really do want to see that macro gone, sorry.
How about a static inline instead of the macro? I'm thinking with a body: {
struct sunxi_timer *timers = (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; return timers[TIMER_NUM]->val;
} With something similar in timer_init then both the macro and the static global timer_base can be dropped.
That's just wrapping a readl() into another function, which seems unnecessary really.
Sorry, but I think inlining the readl (and along with it the interesting/subtle) inverting functionality is a terrible idea, it should be wrapped in some sort of accessor precisely because it is not a raw readl.
I'm going to make it a function as I suggested.
BTW this macro is in arch/arm/cpu/armv7/sunxi/timer.c not a header, so I'm not sure which implementers down the line you were worried about using it in some other context where it breaks.
People plumbing in the timer.c file who are not aware the macro has a dependency which is not passed as it's parameter.
What people? What plumbing? I've no idea what you are concerned about here.
I think what Marek is concerned about is people making some global u-boot change which for some reason requires fixing up a bunch of platform specific files, and they end up touching our timer.c without ever test-compiling it.
We don't do such changes without test-compiling those (most of us don't and those who do ... well ... tsk tsk tsk ! ;-) ).
These kind of things happen in qemu / the kernel too. In this case they could move a READ_TIMER() somewhere where the timer_base is not defined.
Yeah.
Your suggestion of making it a proper function will fix that though, and I think is the best solution.
I think wrapping a plain readl() into a function is not necessary, but I will wait for V3 to see it in action and then I will decide .

This has been stripped back for mainlining and supports only sun7i. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Carl van Schaik Henrik Nordstrom Stefan Roese Tom Cubie
Signed-off-by: Chen-Yu Tsai wens@csie.org Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Ma Haijun mahaijuns@gmail.com Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Ian Campbell ijc@hellion.org.uk Reviewed-by: Tom Rini trini@ti.com --- v2: Based on u-boot-sunxi.git#sunxi d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in: - Additional pin definitions
v1: Based on u-boot-sunxi.git#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01. --- arch/arm/cpu/armv7/sunxi/Makefile | 1 + arch/arm/cpu/armv7/sunxi/pinmux.c | 80 ++++++++++++++++++ arch/arm/include/asm/arch-sunxi/gpio.h | 145 +++++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 arch/arm/cpu/armv7/sunxi/pinmux.c create mode 100644 arch/arm/include/asm/arch-sunxi/gpio.h
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile index 787a127..b3ef8a0 100644 --- a/arch/arm/cpu/armv7/sunxi/Makefile +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -9,3 +9,4 @@ # obj-y += timer.o obj-y += clock.o +obj-y += pinmux.o diff --git a/arch/arm/cpu/armv7/sunxi/pinmux.c b/arch/arm/cpu/armv7/sunxi/pinmux.c new file mode 100644 index 0000000..8f5cbfe --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/pinmux.c @@ -0,0 +1,80 @@ +/* + * (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 cfg; + u32 bank = GPIO_BANK(pin); + u32 index = GPIO_CFG_INDEX(pin); + u32 offset = GPIO_CFG_OFFSET(pin); + struct sunxi_gpio *pio = + &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank]; + + cfg = readl(&pio->cfg[0] + index); + cfg &= ~(0xf << offset); + cfg |= val << offset; + + writel(cfg, &pio->cfg[0] + index); + + 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 = + &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank]; + + cfg = readl(&pio->cfg[0] + index); + cfg >>= offset; + + return cfg & 0xf; +} + +int sunxi_gpio_set_drv(u32 pin, u32 val) +{ + u32 drv; + u32 bank = GPIO_BANK(pin); + u32 index = GPIO_DRV_INDEX(pin); + u32 offset = GPIO_DRV_OFFSET(pin); + struct sunxi_gpio *pio = + &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank]; + + drv = readl(&pio->drv[0] + index); + drv &= ~(0x3 << offset); + drv |= val << offset; + + writel(drv, &pio->drv[0] + index); + + return 0; +} + +int sunxi_gpio_set_pull(u32 pin, u32 val) +{ + u32 pull; + u32 bank = GPIO_BANK(pin); + u32 index = GPIO_PULL_INDEX(pin); + u32 offset = GPIO_PULL_OFFSET(pin); + struct sunxi_gpio *pio = + &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank]; + + pull = readl(&pio->pull[0] + index); + pull &= ~(0x3 << offset); + pull |= val << offset; + + writel(pull, &pio->pull[0] + index); + + return 0; +} diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h new file mode 100644 index 0000000..802f347 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -0,0 +1,145 @@ +/* + * (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 + +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[9]; + u8 res[0xbc]; + struct sunxi_gpio_int gpio_int; +}; + +#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); +int name_to_gpio(const char *name); +#define name_to_gpio name_to_gpio + +#endif /* _SUNXI_GPIO_H */

On Friday, March 21, 2014 at 10:54:19 PM, Ian Campbell wrote: [...]
diff --git a/arch/arm/cpu/armv7/sunxi/pinmux.c b/arch/arm/cpu/armv7/sunxi/pinmux.c new file mode 100644 index 0000000..8f5cbfe --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/pinmux.c @@ -0,0 +1,80 @@ +/*
- (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 cfg;
- u32 bank = GPIO_BANK(pin);
- u32 index = GPIO_CFG_INDEX(pin);
- u32 offset = GPIO_CFG_OFFSET(pin);
- struct sunxi_gpio *pio =
&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank];
- cfg = readl(&pio->cfg[0] + index);
- cfg &= ~(0xf << offset);
- cfg |= val << offset;
- writel(cfg, &pio->cfg[0] + index);
clrsetbits_le32() here.
- 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 =
&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank];
- cfg = readl(&pio->cfg[0] + index);
- cfg >>= offset;
- return cfg & 0xf;
+}
+int sunxi_gpio_set_drv(u32 pin, u32 val) +{
- u32 drv;
- u32 bank = GPIO_BANK(pin);
- u32 index = GPIO_DRV_INDEX(pin);
- u32 offset = GPIO_DRV_OFFSET(pin);
- struct sunxi_gpio *pio =
&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank];
- drv = readl(&pio->drv[0] + index);
- drv &= ~(0x3 << offset);
- drv |= val << offset;
- writel(drv, &pio->drv[0] + index);
Here as well.
- return 0;
+}
+int sunxi_gpio_set_pull(u32 pin, u32 val) +{
- u32 pull;
- u32 bank = GPIO_BANK(pin);
- u32 index = GPIO_PULL_INDEX(pin);
- u32 offset = GPIO_PULL_OFFSET(pin);
- struct sunxi_gpio *pio =
&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank];
- pull = readl(&pio->pull[0] + index);
- pull &= ~(0x3 << offset);
- pull |= val << offset;
- writel(pull, &pio->pull[0] + index);
Same here.
- return 0;
+}
[...]
+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); +int name_to_gpio(const char *name); +#define name_to_gpio name_to_gpio
What is this ugly define doing here ?

On Mon, 2014-03-24 at 21:54 +0100, Marek Vasut wrote:
cfg = readl(&pio->cfg[0] + index);
cfg &= ~(0xf << offset);
cfg |= val << offset;
writel(cfg, &pio->cfg[0] + index);
clrsetbits_le32() here.
I looked at this transform in a few different contexts and one concern I had was that readl and writel have barriers in them (after the read and before the write respectively) while clrsetbits and friends do not. I don't think this will matter for the read/modify/write bit twiddling itself (since there are register dependencies) but I was slightly concerned that the barriers were hiding the lack of explicit barriers which would be required between the various reads/writes.
But I think I am probably being overly cautious here and the obvious transformation can be made. Anyone got any thoughts?
Ian.

On Wednesday, March 26, 2014 at 09:30:38 AM, Ian Campbell wrote:
On Mon, 2014-03-24 at 21:54 +0100, Marek Vasut wrote:
cfg = readl(&pio->cfg[0] + index);
cfg &= ~(0xf << offset);
cfg |= val << offset;
writel(cfg, &pio->cfg[0] + index);
clrsetbits_le32() here.
I looked at this transform in a few different contexts and one concern I had was that readl and writel have barriers in them (after the read and before the write respectively) while clrsetbits and friends do not. I don't think this will matter for the read/modify/write bit twiddling itself (since there are register dependencies) but I was slightly concerned that the barriers were hiding the lack of explicit barriers which would be required between the various reads/writes.
But I think I am probably being overly cautious here and the obvious transformation can be made. Anyone got any thoughts?
+CC Tom, Albert .
Best regards, Marek Vasut

Dear Ian,
[Cc: list truncated / changed]
In message 1395822638.29683.9.camel@dagon.hellion.org.uk you wrote:
I looked at this transform in a few different contexts and one concern I had was that readl and writel have barriers in them (after the read and before the write respectively) while clrsetbits and friends do not. I
They are supposed to. They map to the out_##type() / in_##type() standard I/O accessors which are supposed to be suitable to access device registers.
I can see that the ARM implementation maps this to __raw_write##type() / __raw_read##type() and then to __arch_put##type() / __arch_get##type() which indeed do not include MBs.
But I think I am probably being overly cautious here and the obvious transformation can be made. Anyone got any thoughts?
I'm not an expert for ARM, but this indeed looks suspiscious - thanks for reporting this.
It is conspicuous that Linux does not use out_##type() / in_##type() for ARM, and instead uses iowrite##type() / ioread##type() - which do include MBs.
Albert - what do you think?
Best regards,
Wolfgang Denk

On Wed, 2014-03-26 at 10:01 +0100, Wolfgang Denk wrote:
I'm not an expert for ARM, but this indeed looks suspiscious - thanks for reporting this.
FYI I made the change which prompted this and the resulting code was the same see https://groups.google.com/forum/#!topic/linux-sunxi/REZ18q0wcDY The barriers were only ever compile barrier() type, not cpu barriers.
So the open coded thing was effectively: v = read(); barrier(); v = fiddlebits(b) barrier(); write(v);
Whereas the code using clrsetbits is basically: write(fiddlebits(read()))
Which I think is OK in this case at least. Not sure about the general case.
Ian.

On Mon, 2014-03-24 at 21:54 +0100, Marek Vasut wrote:
+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); +int name_to_gpio(const char *name); +#define name_to_gpio name_to_gpio
What is this ugly define doing here ?
common/cmd_gpio.c uses the #ifndef name_to_gpio pattern to provide (or not) a default fallback implementation. I think this is a reasonably (but not very) common idiom for such cases where the non-default variant is not best expressed as a macro.
Ian.

On Wednesday, March 26, 2014 at 09:33:01 AM, Ian Campbell wrote:
On Mon, 2014-03-24 at 21:54 +0100, Marek Vasut wrote:
+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); +int name_to_gpio(const char *name); +#define name_to_gpio name_to_gpio
What is this ugly define doing here ?
common/cmd_gpio.c uses the #ifndef name_to_gpio pattern to provide (or not) a default fallback implementation. I think this is a reasonably (but not very) common idiom for such cases where the non-default variant is not best expressed as a macro.
This should be fixed, the name_to_gpio() there should be replaced by a __weak function. (patch is welcome)
Nonetheless, in your case, please don't do #define FOO FOO, but choose some sensible name for the function.
Best regards, Marek Vasut

Dear Ian Campbell,
In message 1395822781.29683.12.camel@dagon.hellion.org.uk you wrote:
On Mon, 2014-03-24 at 21:54 +0100, Marek Vasut wrote:
+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); +int name_to_gpio(const char *name); +#define name_to_gpio name_to_gpio
What is this ugly define doing here ?
common/cmd_gpio.c uses the #ifndef name_to_gpio pattern to provide (or not) a default fallback implementation. I think this is a reasonably (but not very) common idiom for such cases where the non-default variant is not best expressed as a macro.
Please add a comment to explain that.
Thanks.
Best regards,
Wolfgang Denk

On Wed, 2014-03-26 at 10:03 +0100, Wolfgang Denk wrote:
Dear Ian Campbell,
In message 1395822781.29683.12.camel@dagon.hellion.org.uk you wrote:
On Mon, 2014-03-24 at 21:54 +0100, Marek Vasut wrote:
+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); +int name_to_gpio(const char *name); +#define name_to_gpio name_to_gpio
What is this ugly define doing here ?
common/cmd_gpio.c uses the #ifndef name_to_gpio pattern to provide (or not) a default fallback implementation. I think this is a reasonably (but not very) common idiom for such cases where the non-default variant is not best expressed as a macro.
Please add a comment to explain that.
Unless you object I think I'll do as Marek suggested name the function sunxi_name_to_gpio and make the #define to that, it seems more consistent that way.
Ian.

On Wednesday, March 26, 2014 at 10:39:16 AM, Ian Campbell wrote:
On Wed, 2014-03-26 at 10:03 +0100, Wolfgang Denk wrote:
Dear Ian Campbell,
In message 1395822781.29683.12.camel@dagon.hellion.org.uk you wrote:
On Mon, 2014-03-24 at 21:54 +0100, Marek Vasut wrote:
+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); +int name_to_gpio(const char *name); +#define name_to_gpio name_to_gpio
What is this ugly define doing here ?
common/cmd_gpio.c uses the #ifndef name_to_gpio pattern to provide (or not) a default fallback implementation. I think this is a reasonably (but not very) common idiom for such cases where the non-default variant is not best expressed as a macro.
Please add a comment to explain that.
Unless you object I think I'll do as Marek suggested name the function sunxi_name_to_gpio and make the #define to that, it seems more consistent that way.
I'd suggest you fix cmd_gpio.c while at it too ;-)
Best regards, Marek Vasut

Dear Ian Campbell,
In message 1395826756.22808.13.camel@kazak.uk.xensource.com you wrote:
Please add a comment to explain that.
Unless you object I think I'll do as Marek suggested name the function sunxi_name_to_gpio and make the #define to that, it seems more consistent that way.
That's better, indeed. Thanks.
Best regards,
Wolfgang Denk

This has been stripped back for mainlining and supports only sun7i. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Alejandro Mery Carl van Schaik Tom Cubie
Signed-off-by: Alexandru Gagniuc mr.nuke.me@gmail.com Signed-off-by: Emilio López emilio@elopez.com.ar Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Luke Leighton lkcl@lkcl.net Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Stefan Roese sr@denx.de Signed-off-by: Ian Campbell ijc@hellion.org.uk --- v2: Based on u-boot-sunxi.git#sunxi d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in: - remove redundant braces in mctl_ddr3_reset - remove incorrect call to mctl_ddr3_reset. - add CONFIG_SUN7I to simplify future SUN?I support. - add a comment about the magic numbers from the a/w code dumps - fix a bunch of checkpatch.pl issues
v1: Based on u-boot-sunxi.git#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01. --- arch/arm/cpu/armv7/sunxi/Makefile | 1 + arch/arm/cpu/armv7/sunxi/dram.c | 548 +++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-sunxi/dram.h | 175 +++++++++++ 3 files changed, 724 insertions(+) create mode 100644 arch/arm/cpu/armv7/sunxi/dram.c create mode 100644 arch/arm/include/asm/arch-sunxi/dram.h
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile index b3ef8a0..3485404 100644 --- a/arch/arm/cpu/armv7/sunxi/Makefile +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -8,5 +8,6 @@ # SPDX-License-Identifier: GPL-2.0+ # obj-y += timer.o +obj-y += dram.o obj-y += clock.o obj-y += pinmux.o diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c new file mode 100644 index 0000000..f03734d --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -0,0 +1,548 @@ +/* + * 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 + +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_M(CCM_PLL5_CTRL_M_X(2)); + reg_val &= ~CCM_PLL5_CTRL_K_MASK; /* set K to 0 (x1) */ + reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2)); + reg_val &= ~CCM_PLL5_CTRL_N_MASK; /* set N to 0 (x0) */ + reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(clk / 24)); + reg_val &= ~CCM_PLL5_CTRL_P_MASK; /* set P to 0 (x1) */ + 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 */ + while (readl(&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 +} + +#if defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I) +static void dramc_set_autorefresh_cycle(u32 clk) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + u32 reg_val; + u32 tmp_val; + reg_val = 0x83; + + tmp_val = (7987 * clk) >> 10; + tmp_val = tmp_val * 9 - 200; + reg_val |= tmp_val << 8; + reg_val |= 0x8 << 24; + writel(reg_val, &dram->drr); +} +#endif /* SUN5I */ + +unsigned long dramc_init(struct dram_para *para) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + u32 reg_val; + int ret_val; + + /* check input dram parameter structure */ + if (!para) + return 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) + reg_val |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_256M); + else if (para->density == 512) + reg_val |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_512M); + else if (para->density == 1024) + reg_val |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_1024M); + else if (para->density == 2048) + reg_val |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_2048M); + else if (para->density == 4096) + reg_val |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_4096M); + else if (para->density == 8192) + reg_val |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_8192M); + else + reg_val |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_256M); + + 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); + + while (readl(&dram->ccr) & DRAM_CCR_INIT) + ; + + mctl_enable_dllx(para->tpr3); + + /* set refresh period */ + dramc_set_autorefresh_cycle(para->clock); + + /* set timing parameters */ + writel(para->tpr0, &dram->tpr0); + writel(para->tpr1, &dram->tpr1); + writel(para->tpr2, &dram->tpr2); + + 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); + while (readl(&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 */ + while (readl(&dram->dcr) & (0x1 << 31)) + ; + + udelay(2); + + /* dram pad hold off */ + setbits_le32(&dram->ppwrsctl, 0x16510000); + + while (readl(&dram->ppwrsctl) & 0x1) + ; + + /* exit self-refresh state */ + clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x12 << 27); + + /* check whether command has been executed */ + while (readl(&dram->dcr) & (0x1 << 31)) + ; + udelay(2); + + /* issue a refresh command */ + clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x13 << 27); + while (readl(&dram->dcr) & (0x1 << 31)) + ; + + udelay(2); + } +#endif + + /* scan read pipe value */ + mctl_itm_enable(); + if (para->tpr3 & (0x1 << 31)) { + ret_val = dramc_scan_dll_para(); + if (ret_val == 0) + para->tpr3 = + (((readl(&dram->dllcr[0]) >> 6) & 0x3f) << 16) | + (((readl(&dram->dllcr[1]) >> 14) & 0xf) << 0) | + (((readl(&dram->dllcr[2]) >> 14) & 0xf) << 4) | + (((readl(&dram->dllcr[3]) >> 14) & 0xf) << 8) | + (((readl(&dram->dllcr[4]) >> 14) & 0xf) << 12 + ); + } else { + ret_val = dramc_scan_readpipe(); + } + + if (ret_val < 0) + return 0; + + /* configure all host port */ + mctl_configure_hostport(); + + return get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE); +} diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h new file mode 100644 index 0000000..041a02d --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -0,0 +1,175 @@ +/* + * (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_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 */

This has been stripped back for mainlining and supports only sun7i. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Almo Nito Carl van Schaik FUKAUMI Naoki hehopmajieh j Sergey Lapin Tom Cubie
Signed-off-by: Aleksei Mamlin mamlinav@gmail.com Signed-off-by: Alexandru Gagniuc mr.nuke.me@gmail.com Signed-off-by: Chen-Yu Tsai wens@csie.org Signed-off-by: Emilio López emilio@elopez.com.ar Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Jens Kuske jenskuske@gmail.com Signed-off-by: Luc Verhaegen libv@skynet.be Signed-off-by: Luke Leighton lkcl@lkcl.net Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Patrick Wood patrickhwood@gmail.com Signed-off-by: Stefan Roese sr@denx.de Signed-off-by: Wills Wang wills.wang.open@gmail.com Signed-off-by: Ian Campbell ijc@hellion.org.uk --- v2: Based on u-boot-sunxi.git#sunxi d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in: - just init dram once - remove clock ramping until power control is implemented - add CONFIG_SUN7I to simplify future SUN?I support. - fix a typo
v1: Based on u-boot-sunxi.git#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01. --- arch/arm/cpu/armv7/sunxi/Makefile | 11 +++ arch/arm/cpu/armv7/sunxi/board.c | 88 ++++++++++++++++++++++++ arch/arm/cpu/armv7/sunxi/cpu_info.c | 19 ++++++ arch/arm/cpu/armv7/sunxi/start.c | 1 + arch/arm/include/asm/arch-sunxi/cpu.h | 122 ++++++++++++++++++++++++++++++++++ board/sunxi/Makefile | 11 +++ board/sunxi/board.c | 57 ++++++++++++++++ 7 files changed, 309 insertions(+) create mode 100644 arch/arm/cpu/armv7/sunxi/board.c create mode 100644 arch/arm/cpu/armv7/sunxi/cpu_info.c create mode 100644 arch/arm/cpu/armv7/sunxi/start.c create mode 100644 arch/arm/include/asm/arch-sunxi/cpu.h create mode 100644 board/sunxi/Makefile create mode 100644 board/sunxi/board.c
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile index 3485404..d85b647 100644 --- a/arch/arm/cpu/armv7/sunxi/Makefile +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -9,5 +9,16 @@ # obj-y += timer.o obj-y += dram.o +obj-y += board.o obj-y += clock.o obj-y += pinmux.o + +ifndef CONFIG_SPL_BUILD +obj-y += cpu_info.o +endif + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_FEL +obj-y += start.o +endif +endif diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c new file mode 100644 index 0000000..4a29b4b --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -0,0 +1,88 @@ +/* + * (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 <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 + /* 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, #0x40\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 diff --git a/arch/arm/cpu/armv7/sunxi/cpu_info.c b/arch/arm/cpu/armv7/sunxi/cpu_info.c new file mode 100644 index 0000000..b4c3d5c --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/cpu_info.c @@ -0,0 +1,19 @@ +/* + * (C) Copyright 2007-2011 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Tom Cubie tangliang@allwinnertech.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> + +#ifdef CONFIG_DISPLAY_CPUINFO +int print_cpuinfo(void) +{ + puts("CPU: Allwinner A20 (SUN7I)\n"); + return 0; +} +#endif diff --git a/arch/arm/cpu/armv7/sunxi/start.c b/arch/arm/cpu/armv7/sunxi/start.c new file mode 100644 index 0000000..6b392fa --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/start.c @@ -0,0 +1 @@ +/* Intentionally empty. Only needed to get FEL SPL link line right */ diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h new file mode 100644 index 0000000..9330058 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/cpu.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 0x01c00000 +#define SUNXI_SRAM_B_BASE 0x01c00000 /* 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 /* sun7i only ? */ + +#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); +extern void sunxi_reset(void); +#endif /* __ASSEMBLY__ */ + +#endif /* _CPU_H */ diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile new file mode 100644 index 0000000..559112e --- /dev/null +++ b/board/sunxi/Makefile @@ -0,0 +1,11 @@ +# +# (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 diff --git a/board/sunxi/board.c b/board/sunxi/board.c new file mode 100644 index 0000000..328334a --- /dev/null +++ b/board/sunxi/board.c @@ -0,0 +1,57 @@ +/* + * (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> + +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_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

Dear Ian Campbell,
In message 1395438866-1193-4-git-send-email-ijc@hellion.org.uk you wrote:
This has been stripped back for mainlining and supports only sun7i. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Almo Nito Carl van Schaik FUKAUMI Naoki hehopmajieh j Sergey Lapin Tom Cubie
Sorry, this is a NAK for these patches.
"These changes are not useful by themselves but are split out to make the patch sizes more manageable." This is not how we work. Patches have to implement specific features, or fix specific bugs. And they have to maintain bisectability of the code.
And we need a useful commit message that explains clearly what the patch is doing, and why.
And we implement the same Developer's Certificate of Origin as used in Linux, so we need real names and working e-mail addresses in the Signed-off-by lines - a cursory mentioning that some mysterious "j" or some "hehopmajieh" authored some code is not sufficient.
Best regards,
Wolfgang Denk

On Saturday, March 22, 2014 07:52:54 AM Wolfgang Denk wrote:
And we implement the same Developer's Certificate of Origin as used in Linux, so we need real names and working e-mail addresses in the Signed-off-by lines - a cursory mentioning that some mysterious "j" or some "hehopmajieh" authored some code is not sufficient.
This is a convoluted one. Tom Cubie, for example, is an allwinner employee which authored the original code. That code was released under the GPL by allwinner. People signing-off on this code are certifying point (b) for the allwinner dump, and/or point (a) for modifications done on top of that code. I hope this clears up the SOB situation.
Alex

Hi,
On 03/22/2014 07:52 AM, Wolfgang Denk wrote:
Dear Ian Campbell,
In message 1395438866-1193-4-git-send-email-ijc@hellion.org.uk you wrote:
This has been stripped back for mainlining and supports only sun7i. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Almo Nito Carl van Schaik FUKAUMI Naoki hehopmajieh j Sergey Lapin Tom Cubie
Sorry, this is a NAK for these patches.
"These changes are not useful by themselves but are split out to make the patch sizes more manageable." This is not how we work. Patches have to implement specific features, or fix specific bugs. And they have to maintain bisectability of the code.
These patches do implement specific features, like dram init, timer/clk init, etc. They just don't enable them yet as by themselves they are not useful.
The patches also maintain bisectability since they don't touch any existing files until the patch 5 and 6 come into play, and the changes in patch 5 keep things compiling just fine.
FWIW I believe the split-up Ian has done makes sense. But if you insist I guess we can merge patch 1-6 (the minimum set to get something working) into 1 big patch.
Regards,
Hans

On Sat, 2014-03-22 at 10:04 +0100, Hans de Goede wrote:
Sorry, this is a NAK for these patches.
"These changes are not useful by themselves but are split out to make the patch sizes more manageable." This is not how we work. Patches have to implement specific features, or fix specific bugs. And they have to maintain bisectability of the code.
These patches do implement specific features, like dram init, timer/clk init, etc. They just don't enable them yet as by themselves they are not useful.
The patches also maintain bisectability since they don't touch any existing files until the patch 5 and 6 come into play, and the changes in patch 5 keep things compiling just fine.
That's correct, the initial 4 patches add specific subsystem support for sunxi but none of it is built until patch 5 at which point things work.
FWIW I believe the split-up Ian has done makes sense. But if you insist I guess we can merge patch 1-6 (the minimum set to get something working) into 1 big patch.
Personally I think that would hinder review more than help, but if that is what is required I'll do it.
Ian.

Dear Hans de Goede,
In message 532D5238.6080606@redhat.com you wrote:
"These changes are not useful by themselves but are split out to make the patch sizes more manageable." This is not how we work. Patches have to implement specific features, or fix specific bugs. And they have to maintain bisectability of the code.
These patches do implement specific features, like dram init, timer/clk init, etc. They just don't enable them yet as by themselves they are not useful.
Well, then at least the commit meSsage needs some serious rework.
The patches also maintain bisectability since they don't touch any existing files until the patch 5 and 6 come into play, and the changes in patch 5 keep things compiling just fine.
I think I have seen some interdependencies between the patches - like referring to stuff that gets only added in later patches?
FWIW I believe the split-up Ian has done makes sense. But if you insist I guess we can merge patch 1-6 (the minimum set to get something working) into 1 big patch.
I did not look too thoroughly at the content. In any case, we need clear and descriptive commit messages, and proper attribution / SoB lines.
Best regards,
Wolfgang Denk

On Sat, 2014-03-22 at 13:27 +0100, Wolfgang Denk wrote:
Dear Hans de Goede,
In message 532D5238.6080606@redhat.com you wrote:
"These changes are not useful by themselves but are split out to make the patch sizes more manageable." This is not how we work. Patches have to implement specific features, or fix specific bugs. And they have to maintain bisectability of the code.
These patches do implement specific features, like dram init, timer/clk init, etc. They just don't enable them yet as by themselves they are not useful.
Well, then at least the commit meSsage needs some serious rework.
I will add some more description for the next round.
The patches also maintain bisectability since they don't touch any existing files until the patch 5 and 6 come into play, and the changes in patch 5 keep things compiling just fine.
I think I have seen some interdependencies between the patches - like referring to stuff that gets only added in later patches?
I don't believe so, bisectability is maintained because there are no build targets until patch #5 and from that point on every step builds. Obviously at every step (including #1..#5) there is no impact on any other platform.
Ian.

This has been stripped back for mainlining and supports only sun7i booting via FEL mode. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Almo Nito Carl van Schaik FUKAUMI Naoki hehopmajieh j Sergey Lapin Tom Cubie
Signed-off-by: Adam Sampson ats@offog.org Signed-off-by: Aleksei Mamlin mamlinav@gmail.com Signed-off-by: Chen-Yu Tsai wens@csie.org Signed-off-by: Emilio López emilio@elopez.com.ar Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Jens Kuske jenskuske@gmail.com Signed-off-by: Luc Verhaegen libv@skynet.be Signed-off-by: Luke Leighton lkcl@lkcl.net Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Patrick Wood patrickhwood@gmail.com Signed-off-by: Stefan Roese sr@denx.de Signed-off-by: Wills Wang wills.wang.open@gmail.com Signed-off-by: Ian Campbell ijc@hellion.org.uk --- v2: Based on u-boot-sunxi.git#sunxi d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in: - sunxi-common.h updates, including pulling some command additions back from the non-FEL patch and switchin to bootm_size not BOOTMAPSZ
v1: Based on u-boot-sunxi.git#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01. --- arch/arm/cpu/armv7/Makefile | 2 +- arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds | 59 +++++++++++ arch/arm/include/asm/arch-sunxi/spl.h | 20 ++++ board/sunxi/Makefile | 1 + include/configs/sun7i.h | 24 +++++ include/configs/sunxi-common.h | 153 ++++++++++++++++++++++++++++ 6 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds create mode 100644 arch/arm/include/asm/arch-sunxi/spl.h create mode 100644 include/configs/sun7i.h create mode 100644 include/configs/sunxi-common.h
diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile index 119ebb3..ddf00f3 100644 --- a/arch/arm/cpu/armv7/Makefile +++ b/arch/arm/cpu/armv7/Makefile @@ -12,7 +12,7 @@ obj-y += cache_v7.o obj-y += cpu.o obj-y += syslib.o
-ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY),) +ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY)$(CONFIG_SUNXI),) ifneq ($(CONFIG_SKIP_LOWLEVEL_INIT),y) obj-y += lowlevel_init.o endif diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds new file mode 100644 index 0000000..cf02300 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds @@ -0,0 +1,59 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(s_init) +SECTIONS +{ + . = 0x00002000; + . = ALIGN(4); + .text : + { + *(.text.s_init) + *(.text*) + } + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + . = ALIGN(4); + .data : { + *(.data*) + } + . = ALIGN(4); + . = .; + . = ALIGN(4); + .rel.dyn : { + __rel_dyn_start = .; + *(.rel*) + __rel_dyn_end = .; + } + .dynsym : { + __dynsym_start = .; + *(.dynsym) + } + . = ALIGN(4); + .note.gnu.build-id : + { + *(.note.gnu.build-id) + } + _end = .; + . = ALIGN(4096); + .mmutable : { + *(.mmutable) + } + .bss_start __rel_dyn_start (OVERLAY) : { + KEEP(*(.__bss_start)); + __bss_base = .; + } + .bss __bss_base (OVERLAY) : { + *(.bss*) + . = ALIGN(4); + __bss_limit = .; + } + .bss_end __bss_limit (OVERLAY) : { + KEEP(*(.__bss_end)); + } + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } + /DISCARD/ : { *(.note*) } +} diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h new file mode 100644 index 0000000..ff871bc --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/spl.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 diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile index 559112e..6483bf4 100644 --- a/board/sunxi/Makefile +++ b/board/sunxi/Makefile @@ -9,3 +9,4 @@ # SPDX-License-Identifier: GPL-2.0+ # obj-y += board.o +obj-y += dram_cubietruck.o diff --git a/include/configs/sun7i.h b/include/configs/sun7i.h new file mode 100644 index 0000000..9b693f7 --- /dev/null +++ b/include/configs/sun7i.h @@ -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 */ diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h new file mode 100644 index 0000000..114cb36 --- /dev/null +++ b/include/configs/sunxi-common.h @@ -0,0 +1,153 @@ +/* + * (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 */ + +#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 +#define CONFIG_CMDLINE_EDITING + +/* + * Size of malloc() pool + * 1MB = 0x100000, 0x100000 = 1024 * 1024 + */ +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (1 << 20)) + +/* Flat Device Tree (FDT/DT) support */ +#define CONFIG_OF_LIBFDT + +/* + * Miscellaneous configurable options + */ +#define CONFIG_SYS_LONGHELP /* undef to save memory */ +#define CONFIG_SYS_HUSH_PARSER /* use "hush" command parser */ +#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 */ + +/* Boot Argument Buffer Size */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE + +#define CONFIG_SYS_LOAD_ADDR 0x50000000 /* default load address */ + +/* standalone support */ +#define CONFIG_STANDALONE_LOAD_ADDR 0x50000000 + +#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_SIZE (128 << 10) /* 128 KiB */ + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "bootm_size=0x20000000\0" + +#define CONFIG_BOOTDELAY 3 +#define CONFIG_SYS_BOOT_GET_CMDLINE +#define CONFIG_AUTO_COMPLETE + +#include <config_cmd_default.h> + +/* Accept zimage + raw ramdisk without mkimage headers */ +#define CONFIG_CMD_BOOTZ +#define CONFIG_SUPPORT_RAW_INITRD + +#define CONFIG_DOS_PARTITION +#define CONFIG_CMD_FAT /* with this we can access fat bootfs */ +#define CONFIG_FAT_WRITE /* enable write access */ +#define CONFIG_CMD_EXT2 /* with this we can access ext2 bootfs */ +#define CONFIG_CMD_EXT4 /* with this we can access ext4 bootfs */ + +#define CONFIG_SPL_FRAMEWORK +#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT + +#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 */ +/* end of 32 KiB in sram */ +#define LOW_LEVEL_SRAM_STACK 0x00008000 +#define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK + +#undef CONFIG_CMD_FPGA +#undef CONFIG_CMD_NET +#undef CONFIG_CMD_NFS + +#define CONFIG_CONS_INDEX 1 /* UART0 */ + +#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 + +#endif /* _SUNXI_COMMON_CONFIG_H */

Dear Ian Campbell,
In message 1395438866-1193-5-git-send-email-ijc@hellion.org.uk you wrote:
This has been stripped back for mainlining and supports only sun7i booting via FEL mode. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following:
What does that mean? I cannot find these names in the SoB lines?
Almo Nito Carl van Schaik FUKAUMI Naoki hehopmajieh j
And these are not actually names ... nor do we have the e-mail addresses...
Best regards,
Wolfgang Denk

On Sat, 2014-03-22 at 07:46 +0100, Wolfgang Denk wrote:
Dear Ian Campbell,
In message 1395438866-1193-5-git-send-email-ijc@hellion.org.uk you wrote:
This has been stripped back for mainlining and supports only sun7i booting via FEL mode. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following:
What does that mean? I cannot find these names in the SoB lines?
I explained the process by which I arrived at these lists in 0/9. It means that they appear as an author for a commit in the history in the u-boot-sunxi.git, but did not supply an S-o-b. However I am adding my own S-o-b under clause (b) of the DCO, which I believe applies here.
It's entirely possible that none of these peoples' contributions still remain in the files being upstreamed, but figuring that out for sure would be a large and manual task. As I explained in 0/9 I prefer to over-credit by mentioning people whose actual contributions no longer remain rather than fail to credit someone whose contribution does remain. Even if their code doesn't remain it could be argued that they contributed to the evolution of the code. I didn't really want to get into the whole question of whether any individual contribution was sufficient to deserve credit or substantive enough to endow a copyright claim etc.
(git blame does not help here BTW, it will just tell you the last person to touch a line, not whether that change was substantive from a copyright PoV etc)
Almo Nito Carl van Schaik FUKAUMI Naoki hehopmajieh j
And these are not actually names ... nor do we have the e-mail addresses...
I have email addresses from the commit authorship, which I should indeed have included here, I shall definitely do that for v3. Please let me know whether or not I should also spend hours trawling down the precise pedigree of each line of code.
Ian.

Dear Ian,
In message 1395482650.2234.104.camel@hastur.hellion.org.uk you wrote:
What does that mean? I cannot find these names in the SoB lines?
I explained the process by which I arrived at these lists in 0/9. It means that they appear as an author for a commit in the history in the u-boot-sunxi.git, but did not supply an S-o-b. However I am adding my own S-o-b under clause (b) of the DCO, which I believe applies here.
Please read (again) what the Developer's Certificate of Origin means. It appears that such code would fall under clause (c):
The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.
Did for example "j" or "hehopmajieh" provide such certificates to you?
It's entirely possible that none of these peoples' contributions still remain in the files being upstreamed, but figuring that out for sure would be a large and manual task. As I explained in 0/9 I prefer to over-credit by mentioning people whose actual contributions no longer remain rather than fail to credit someone whose contribution does
The Sob is only partially for crediting; the major purpose is to make sure we really have the full rights to distribute such code under the listed licenses. To guarantee that, the chain of certificates mustnot be interrupted.
I have email addresses from the commit authorship, which I should indeed have included here, I shall definitely do that for v3. Please let me know whether or not I should also spend hours trawling down the precise pedigree of each line of code.
The SoB lines need real names plus real, working mail addresses. The Linux "Documentation/SubmittingPatches" filemakes this clear:
using your real name (sorry, no pseudonyms or anonymous contributions.)
Best regards,
Wolfgang Denk

Hi,
On 03/22/2014 01:33 PM, Wolfgang Denk wrote:
Dear Ian,
In message 1395482650.2234.104.camel@hastur.hellion.org.uk you wrote:
What does that mean? I cannot find these names in the SoB lines?
I explained the process by which I arrived at these lists in 0/9. It means that they appear as an author for a commit in the history in the u-boot-sunxi.git, but did not supply an S-o-b. However I am adding my own S-o-b under clause (b) of the DCO, which I believe applies here.
Please read (again) what the Developer's Certificate of Origin means. It appears that such code would fall under clause (c):
The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.
No as said before the parts for which we don't have a Signed-off-by for falls under b), since we took it from existing code which has clear GPLv2+ license headers on each and every file.
b) Reads:
(b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or
Did for example "j" or "hehopmajieh" provide such certificates to you?
It's entirely possible that none of these peoples' contributions still remain in the files being upstreamed, but figuring that out for sure would be a large and manual task. As I explained in 0/9 I prefer to over-credit by mentioning people whose actual contributions no longer remain rather than fail to credit someone whose contribution does
The Sob is only partially for crediting; the major purpose is to make sure we really have the full rights to distribute such code under the listed licenses. To guarantee that, the chain of certificates mustnot be interrupted.
Right, and we do since the files we're basing our work on is GPLv2+ licensed, the purpose of the listing of extra names other then the Signed-off-by: tags is for solely for attribution.
I have email addresses from the commit authorship, which I should indeed have included here, I shall definitely do that for v3. Please let me know whether or not I should also spend hours trawling down the precise pedigree of each line of code.
The SoB lines need real names plus real, working mail addresses. The Linux "Documentation/SubmittingPatches" filemakes this clear:
using your real name (sorry, no pseudonyms or anonymous contributions.)
Right but these are not Signed-off-by lines. Just as I may thank a tester in a commit message with just his name because he does not want me to disclose his email address, we are attributing people here with just there names.
Note in some cases we do have email addresses and Ian has said he will add those in the next version, but we cannot magically conjure up Signed-off-by's which we don't have, and section b) says we don't need to since all the original files have a clear GPLv2+ license header.
Regards,
Hans

On Sat, 2014-03-22 at 16:12 +0100, Hans de Goede wrote:
Hi,
On 03/22/2014 01:33 PM, Wolfgang Denk wrote:
Dear Ian,
In message 1395482650.2234.104.camel@hastur.hellion.org.uk you wrote:
What does that mean? I cannot find these names in the SoB lines?
I explained the process by which I arrived at these lists in 0/9. It means that they appear as an author for a commit in the history in the u-boot-sunxi.git, but did not supply an S-o-b. However I am adding my own S-o-b under clause (b) of the DCO, which I believe applies here.
Please read (again) what the Developer's Certificate of Origin means. It appears that such code would fall under clause (c):
The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.
No as said before the parts for which we don't have a Signed-off-by for falls under b), since we took it from existing code which has clear GPLv2+ license headers on each and every file.
Thanks, this is just what I was just about to say.
b) Reads:
(b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or
Did for example "j" or "hehopmajieh" provide such certificates to you?
It's entirely possible that none of these peoples' contributions still remain in the files being upstreamed, but figuring that out for sure would be a large and manual task. As I explained in 0/9 I prefer to over-credit by mentioning people whose actual contributions no longer remain rather than fail to credit someone whose contribution does
The Sob is only partially for crediting; the major purpose is to make sure we really have the full rights to distribute such code under the listed licenses. To guarantee that, the chain of certificates mustnot be interrupted.
Right, and we do since the files we're basing our work on is GPLv2+ licensed, the purpose of the listing of extra names other then the Signed-off-by: tags is for solely for attribution.
Right.
Note in some cases we do have email addresses and Ian has said he will add those in the next version,
Actually in every case we have email addresses, I just omitted them up until now (since a credit doesn't strictly need one).

Dear Hans de Goede,
In message 532DA872.5000606@redhat.com you wrote:
No as said before the parts for which we don't have a Signed-off-by for falls under b), since we took it from existing code which has clear GPLv2+ license headers on each and every file.
Can the code be properly attributed, i. e. does it have proper Signed-off-by: lines?
using your real name (sorry, no pseudonyms or anonymous contributions.)
Right but these are not Signed-off-by lines. Just as I may thank a tester in a commit message with just his name because he does not want me to disclose his email address, we are attributing people here with just there names.
If these people attributed to the code, we should have their commits with their respective Signed-off-by: lines.
Note in some cases we do have email addresses and Ian has said he will add those in the next version, but we cannot magically conjure up Signed-off-by's which we don't have, and section b) says we don't need to since all the original files have a clear GPLv2+ license header.
I don't see this so simple. The code was derived from some earlier mainline U-Boot version, for which a proper chain of SoBs was in place. Then the code was modified in some ways by some unknown people who did not provide their Developer's Certificate of Origin. So what gives us reason to believe that these modifications can be freely reused, i. e. that they do not for example violate third party IP rights?
Section (b) applies for example in cases where an employer has a team of people working on such tasks, and uses a single contact as interface to the community, so the original authors are not directly visible. But unless you contract such work (and make sure fromt he contract terms that you have the appropriate rights), it is IMO difficult or impossible to certify the Developer's Certificate of Origin for modifications done by others - the fact that there was a license header in the code before is good, but not good enough.
Best regards,
Wolfgang Denk

Hi,
On 03/22/2014 08:31 PM, Wolfgang Denk wrote:
Dear Hans de Goede,
In message 532DA872.5000606@redhat.com you wrote:
No as said before the parts for which we don't have a Signed-off-by for falls under b), since we took it from existing code which has clear GPLv2+ license headers on each and every file.
Can the code be properly attributed, i. e. does it have proper Signed-off-by: lines?
using your real name (sorry, no pseudonyms or anonymous contributions.)
Right but these are not Signed-off-by lines. Just as I may thank a tester in a commit message with just his name because he does not want me to disclose his email address, we are attributing people here with just there names.
If these people attributed to the code, we should have their commits with their respective Signed-off-by: lines.
No, just no. How hard is it to read ? section b) clearly states:
"The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications ..."
Nothing more nothing less, you're reading a whole lot stuff in between the lines which is not there. Esp. notice the "to the best of my knowledge".
I don't remember the exact details, as I was not really active in the sunci community at the time, but after some discussion we got the u-boot code from Allwinner themselves, under the GPL, with GPL headers in place. See ie the first commit in the sunxi repo: https://github.com/linux-sunxi/u-boot-sunxi/commit/a38e8203867075a3cabc2d690...
Which even has Tom Cubie tangliang@allwinnertech.com set as author, but does not have his Signed-off-by, but does has "Henrik Nordstrom henrik@henriknordstrom.net" Signed-off-by, which is 100% ok under section b).
Regards,
Hans
p.s.
This will be my last mail in the thread wrt the whole Signed-off-by discussion, your needless strict reading of the s-o-b guidelines is causing way too much negative energy for me. I hope you and Ian can work out a solution for this.

On Friday, March 21, 2014 at 10:54:22 PM, Ian Campbell wrote:
This has been stripped back for mainlining and supports only sun7i booting via FEL mode. These changes are not useful by themselves but are split out to make the patch sizes more manageable.
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Almo Nito Carl van Schaik FUKAUMI Naoki hehopmajieh j Sergey Lapin Tom Cubie
Signed-off-by: Adam Sampson ats@offog.org Signed-off-by: Aleksei Mamlin mamlinav@gmail.com Signed-off-by: Chen-Yu Tsai wens@csie.org Signed-off-by: Emilio López emilio@elopez.com.ar Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Jens Kuske jenskuske@gmail.com Signed-off-by: Luc Verhaegen libv@skynet.be Signed-off-by: Luke Leighton lkcl@lkcl.net Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Patrick Wood patrickhwood@gmail.com Signed-off-by: Stefan Roese sr@denx.de Signed-off-by: Wills Wang wills.wang.open@gmail.com Signed-off-by: Ian Campbell ijc@hellion.org.uk
v2: Based on u-boot-sunxi.git#sunxi d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in: - sunxi-common.h updates, including pulling some command additions back from the non-FEL patch and switchin to bootm_size not BOOTMAPSZ
v1: Based on u-boot-sunxi.git#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01.
arch/arm/cpu/armv7/Makefile | 2 +- arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds | 59 +++++++++++ arch/arm/include/asm/arch-sunxi/spl.h | 20 ++++ board/sunxi/Makefile | 1 + include/configs/sun7i.h | 24 +++++ include/configs/sunxi-common.h | 153 ++++++++++++++++++++++++++++ 6 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds create mode 100644 arch/arm/include/asm/arch-sunxi/spl.h create mode 100644 include/configs/sun7i.h create mode 100644 include/configs/sunxi-common.h
diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile index 119ebb3..ddf00f3 100644 --- a/arch/arm/cpu/armv7/Makefile +++ b/arch/arm/cpu/armv7/Makefile @@ -12,7 +12,7 @@ obj-y += cache_v7.o obj-y += cpu.o obj-y += syslib.o
-ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CON FIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY),) +ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CON FIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY)$(CONFIG_SUNXI), ) ifneq ($(CONFIG_SKIP_LOWLEVEL_INIT),y) obj-y += lowlevel_init.o endif diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds new file mode 100644 index 0000000..cf02300 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds @@ -0,0 +1,59 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(s_init) +SECTIONS +{
- . = 0x00002000;
- . = ALIGN(4);
- .text :
- {
This file is unreadable. Can you not actually merge it into u-boot-spl.lds with some #ifdef ?
[...]
+/*
- 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)
The braces are not needed .
+#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
[...]

On Mon, 2014-03-24 at 22:01 +0100, Marek Vasut wrote:
diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds new file mode 100644 index 0000000..cf02300 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds
This file is unreadable. Can you not actually merge it into u-boot-spl.lds with some #ifdef ?
They look pretty much entirely different to me. I should sort out the whitespace and stuff though, it is a mess in that regard. Perhaps that will help.
Ian.

On Thursday, March 27, 2014 at 11:05:21 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 22:01 +0100, Marek Vasut wrote:
diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds new file mode 100644 index 0000000..cf02300 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds
This file is unreadable. Can you not actually merge it into u-boot-spl.lds with some #ifdef ?
They look pretty much entirely different to me. I should sort out the whitespace and stuff though, it is a mess in that regard. Perhaps that will help.
Likely, but is it really necessary for those two files to be so different or is this some legacy stuff in the sunxi-specific .lds file?
Best regards, Marek Vasut

On Thu, 2014-03-27 at 23:37 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 11:05:21 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 22:01 +0100, Marek Vasut wrote:
diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds new file mode 100644 index 0000000..cf02300 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds
This file is unreadable. Can you not actually merge it into u-boot-spl.lds with some #ifdef ?
They look pretty much entirely different to me. I should sort out the whitespace and stuff though, it is a mess in that regard. Perhaps that will help.
Likely, but is it really necessary for those two files to be so different or is this some legacy stuff in the sunxi-specific .lds file?
The standard lds file is pretty standard. This -fel version is for a special boot mode which sunxi processors have[0] which allows for booting over USB OTG, so the image needs to be built appropriately.
Ian.

On Friday, March 28, 2014 at 09:26:50 AM, Ian Campbell wrote:
On Thu, 2014-03-27 at 23:37 +0100, Marek Vasut wrote:
On Thursday, March 27, 2014 at 11:05:21 PM, Ian Campbell wrote:
On Mon, 2014-03-24 at 22:01 +0100, Marek Vasut wrote:
diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds new file mode 100644 index 0000000..cf02300 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl-fel.lds
This file is unreadable. Can you not actually merge it into u-boot-spl.lds with some #ifdef ?
They look pretty much entirely different to me. I should sort out the whitespace and stuff though, it is a mess in that regard. Perhaps that will help.
Likely, but is it really necessary for those two files to be so different or is this some legacy stuff in the sunxi-specific .lds file?
The standard lds file is pretty standard. This -fel version is for a special boot mode which sunxi processors have[0] which allows for booting over USB OTG, so the image needs to be built appropriately.
OK, I will need to fix up my mk802 rev. 1 (the old and crappy one ! ) and check this FEL stuff. I would really want to avoid one more linker script if possible, since it adds to maintainance overhead and technological debt ... but if you say it's necessary, I will not block it.
btw. try popping up at #u-boot @ irc.freenode.net , it'd be nice to have you around!
Best regards, Marek Vasut

Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Ian Campbell ijc@hellion.org.uk Reviewed-by: Tom Rini trini@ti.com --- v2: Based on u-boot-sunxi.git#sunxi d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in.
v1: Based on u-boot-sunxi.git#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01. --- board/sunxi/dram_cubietruck.c | 31 +++++++++++++++++++++++++++++++ boards.cfg | 1 + 2 files changed, 32 insertions(+) create mode 100644 board/sunxi/dram_cubietruck.c
diff --git a/board/sunxi/dram_cubietruck.c b/board/sunxi/dram_cubietruck.c new file mode 100644 index 0000000..1e7c94a --- /dev/null +++ b/board/sunxi/dram_cubietruck.c @@ -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 = 8192, + .io_width = 16, + .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); +} diff --git a/boards.cfg b/boards.cfg index a32f46b..031da3d 100644 --- a/boards.cfg +++ b/boards.cfg @@ -366,6 +366,7 @@ Active arm armv7 rmobile renesas lager Active arm armv7 s5pc1xx samsung goni s5p_goni - Mateusz Zalega m.zalega@samsung.com Active arm armv7 s5pc1xx samsung smdkc100 smdkc100 - Minkyu Kang mk7.kang@samsung.com Active arm armv7 socfpga altera socfpga socfpga_cyclone5 - - +Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL - Active arm armv7 u8500 st-ericsson snowball snowball - Mathieu Poirier mathieu.poirier@linaro.org Active arm armv7 u8500 st-ericsson u8500 u8500_href - - Active arm armv7 vf610 freescale vf610twr vf610twr vf610twr:IMX_CONFIG=board/freescale/vf610twr/imximage.cfg Alison Wang b18965@freescale.com

Signed-off-by: Chen-Yu Tsai wens@csie.org Signed-off-by: Jens Kuske jenskuske@gmail.com Signed-off-by: Ian Campbell ijc@hellion.org.uk --- v2: Based on u-boot-sunxi.git#sunxi d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in: - drop accidentally doubled hunk - use gpio setup functions - moved before mmc patches
v1: Based on u-bootx-sunxi.git#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01. --- arch/arm/cpu/armv7/sunxi/board.c | 15 +++++++++++++++ boards.cfg | 2 +- drivers/net/Makefile | 1 + drivers/net/sunxi_gmac.c | 34 ++++++++++++++++++++++++++++++++++ include/configs/sunxi-common.h | 37 +++++++++++++++++++++++++++++++++++++ include/netdev.h | 1 + 6 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 drivers/net/sunxi_gmac.c
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 4a29b4b..ad9840b 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -11,6 +11,8 @@ */
#include <common.h> +#include <netdev.h> +#include <miiphy.h> #include <serial.h> #ifdef CONFIG_SPL_BUILD #include <spl.h> @@ -86,3 +88,16 @@ void enable_caches(void) dcache_enable(); } #endif + +#if defined(CONFIG_SUNXI_GMAC) +/* + * Initializes on-chip ethernet controllers. + * to override, implement board_eth_init() + */ +int cpu_eth_init(bd_t *bis) +{ + sunxi_gmac_initialize(bis); + + return 0; +} +#endif diff --git a/boards.cfg b/boards.cfg index 031da3d..3134e9e 100644 --- a/boards.cfg +++ b/boards.cfg @@ -366,7 +366,7 @@ Active arm armv7 rmobile renesas lager Active arm armv7 s5pc1xx samsung goni s5p_goni - Mateusz Zalega m.zalega@samsung.com Active arm armv7 s5pc1xx samsung smdkc100 smdkc100 - Minkyu Kang mk7.kang@samsung.com Active arm armv7 socfpga altera socfpga socfpga_cyclone5 - - -Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL - +Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL,SUNXI_GMAC,RGMII - Active arm armv7 u8500 st-ericsson snowball snowball - Mathieu Poirier mathieu.poirier@linaro.org Active arm armv7 u8500 st-ericsson u8500 u8500_href - - Active arm armv7 vf610 freescale vf610twr vf610twr vf610twr:IMX_CONFIG=board/freescale/vf610twr/imximage.cfg Alison Wang b18965@freescale.com diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 7f9ce90..2300c00 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_SUNXI_WEMAC) += sunxi_wemac.o +obj-$(CONFIG_SUNXI_GMAC) += sunxi_gmac.o obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o diff --git a/drivers/net/sunxi_gmac.c b/drivers/net/sunxi_gmac.c new file mode 100644 index 0000000..13b7d70 --- /dev/null +++ b/drivers/net/sunxi_gmac.c @@ -0,0 +1,34 @@ +#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); + } + + designware_initialize(SUNXI_GMAC_BASE, PHY_INTERFACE_MODE_RGMII); + + return 0; +} diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 114cb36..1cb798d 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -143,6 +143,43 @@
#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_SYS_DCACHE_OFF /* dw driver doesn't support dcache */ +#define CONFIG_MII /* MII PHY management */ +#define CONFIG_PHYLIB +#define CONFIG_CMD_MII +#define CONFIG_CMD_NET +#endif + +#ifdef CONFIG_CMD_NET +#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_CMD_NFS +#define CONFIG_CMD_SNTP +#define CONFIG_TIMESTAMP /* Needed by SNTP */ +#define CONFIG_CMD_DNS +#define CONFIG_NETCONSOLE +#define CONFIG_BOOTP_SUBNETMASK +#define CONFIG_BOOTP_GATEWAY +#define CONFIG_BOOTP_HOSTNAME +#define CONFIG_BOOTP_NISDOMAIN +#define CONFIG_BOOTP_BOOTPATH +#define CONFIG_BOOTP_BOOTFILESIZE +#define CONFIG_BOOTP_DNS +#define CONFIG_BOOTP_DNS2 +#define CONFIG_BOOTP_SEND_HOSTNAME +#define CONFIG_BOOTP_NTPSERVER +#define CONFIG_BOOTP_TIMEOFFSET +#define CONFIG_BOOTP_MAY_FAIL +#define CONFIG_BOOTP_SERVERIP +#define CONFIG_BOOTP_DHCP_REQUEST_DELAY 50000 +#define CONFIG_CMD_ELF +#endif + #if !defined CONFIG_ENV_IS_IN_MMC && \ !defined CONFIG_ENV_IS_IN_NAND && \ !defined CONFIG_ENV_IS_IN_FAT && \ diff --git a/include/netdev.h b/include/netdev.h index 32b5073..fc4a2f8 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -79,6 +79,7 @@ int sh_eth_initialize(bd_t *bis); int skge_initialize(bd_t *bis); int smc91111_initialize(u8 dev_num, int base_addr); int smc911x_initialize(u8 dev_num, int base_addr); +int sunxi_gmac_initialize(bd_t *bis); int sunxi_wemac_initialize(bd_t *bis); int tsi108_eth_initialize(bd_t *bis); int uec_standard_init(bd_t *bis);

As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Stefan Roese Tom Cubie yemao
Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Luke Leighton lkcl@lkcl.net Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Wills Wang wills.wang.open@gmail.com Signed-off-by: Ian Campbell ijc@hellion.org.uk Cc: Pantelis Antoniou panto@antoniou-consulting.com --- Pantelis, most of your review comments have been addressed but not all, in particular the timeout loops aren't sorted yet, but I wanted to get the rest of the series reposted.
v2: Based on u-boot-sunxi.git#sunxi d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in: - use proper gpio interfaces, removing awkward casts and some magic numbers. - remove magic numbers - other cleanups
v1: Based on linux-sunxi#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01. --- arch/arm/include/asm/arch-sunxi/mmc.h | 124 +++++++ board/sunxi/board.c | 13 + drivers/mmc/Makefile | 1 + drivers/mmc/sunxi_mmc.c | 625 ++++++++++++++++++++++++++++++++++ include/configs/sunxi-common.h | 11 + 5 files changed, 774 insertions(+) create mode 100644 arch/arm/include/asm/arch-sunxi/mmc.h create mode 100644 drivers/mmc/sunxi_mmc.c
diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h new file mode 100644 index 0000000..97b14c3 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/mmc.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) SMC Global Control Register */ + u32 clkcr; /* (0x04) SMC Clock Control Register */ + u32 timeout; /* (0x08) SMC Time Out Register */ + u32 width; /* (0x0c) SMC Bus Width Register */ + u32 blksz; /* (0x10) SMC Block Size Register */ + u32 bytecnt; /* (0x14) SMC Byte Count Register */ + u32 cmd; /* (0x18) SMC Command Register */ + u32 arg; /* (0x1c) SMC Argument Register */ + u32 resp0; /* (0x20) SMC Response Register 0 */ + u32 resp1; /* (0x24) SMC Response Register 1 */ + u32 resp2; /* (0x28) SMC Response Register 2 */ + u32 resp3; /* (0x2c) SMC Response Register 3 */ + u32 imask; /* (0x30) SMC Interrupt Mask Register */ + u32 mint; /* (0x34) SMC Masked Interrupt Status Reg */ + u32 rint; /* (0x38) SMC Raw Interrupt Status Register */ + u32 status; /* (0x3c) SMC Status Register */ + u32 ftrglevel; /* (0x40) SMC FIFO Threshold Watermark Reg */ + u32 funcsel; /* (0x44) SMC Function Select Register */ + u32 cbcr; /* (0x48) SMC CIU Byte Count Register */ + u32 bbcr; /* (0x4c) SMC BIU Byte Count Register */ + u32 dbgc; /* (0x50) SMC Debug Enable Register */ + u32 res0[11]; /* (0x54~0x7c) */ + u32 dmac; /* (0x80) SMC IDMAC Control Register */ + u32 dlba; /* (0x84) SMC IDMAC Descr List Base Addr Reg */ + u32 idst; /* (0x88) SMC IDMAC Status Register */ + u32 idie; /* (0x8c) SMC IDMAC Interrupt Enable Register */ + u32 chda; /* (0x90) */ + u32 cbda; /* (0x94) */ + u32 res1[26]; /* (0x98~0xff) */ + u32 fifo; /* (0x100) SMC 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 */ diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 328334a..06c9264 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -14,6 +14,7 @@ #include <common.h> #include <asm/arch/clock.h> #include <asm/arch/dram.h> +#include <asm/arch/mmc.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -43,6 +44,18 @@ int dram_init(void) return 0; }
+#ifdef CONFIG_GENERIC_MMC +int board_mmc_init(bd_t *bis) +{ + sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT); +#if !defined (CONFIG_SPL_BUILD) && defined (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) { diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 931922b..5e67098 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o obj-$(CONFIG_DWMMC) += dw_mmc.o obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o +obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o ifdef CONFIG_SPL_BUILD diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c new file mode 100644 index 0000000..bb31e05 --- /dev/null +++ b/drivers/mmc/sunxi_mmc.c @@ -0,0 +1,625 @@ +/* + * (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/gpio.h> +#include <asm/arch/mmc.h> + +static void dumphex32(char *name, char *base, int len) +{ + __u32 i; + + debug("dump %s registers:", name); + for (i = 0; i < len; i += 4) { + if (!(i & 0xf)) + debug("\n0x%p : ", base + i); + debug("0x%08x ", readl(base + i)); + } + debug("\n"); +} + +static void dumpmmcreg(struct sunxi_mmc *reg) +{ + debug("dump mmc registers:\n"); + debug("gctrl 0x%08x\n", reg->gctrl); + debug("clkcr 0x%08x\n", reg->clkcr); + debug("timeout 0x%08x\n", reg->timeout); + debug("width 0x%08x\n", reg->width); + debug("blksz 0x%08x\n", reg->blksz); + debug("bytecnt 0x%08x\n", reg->bytecnt); + debug("cmd 0x%08x\n", reg->cmd); + debug("arg 0x%08x\n", reg->arg); + debug("resp0 0x%08x\n", reg->resp0); + debug("resp1 0x%08x\n", reg->resp1); + debug("resp2 0x%08x\n", reg->resp2); + debug("resp3 0x%08x\n", reg->resp3); + debug("imask 0x%08x\n", reg->imask); + debug("mint 0x%08x\n", reg->mint); + debug("rint 0x%08x\n", reg->rint); + debug("status 0x%08x\n", reg->status); + debug("ftrglevel 0x%08x\n", reg->ftrglevel); + debug("funcsel 0x%08x\n", reg->funcsel); + debug("dmac 0x%08x\n", reg->dmac); + debug("dlba 0x%08x\n", reg->dlba); + debug("idst 0x%08x\n", reg->idst); + debug("idie 0x%08x\n", reg->idie); +} + +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; +}; + +/* support 4 mmc hosts */ +struct mmc mmc_dev[4]; +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 pin; + unsigned int rval; + unsigned int pll5_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 gpio */ + switch (sdc_no) { + 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: +#if CONFIG_MMC1_PG + /* PG0-CMD, PG1-CLK, PG2~5-D0~3 : 4 */ + for (pin = SUNXI_GPG(0); pin <= SUNXI_GPG(5); pin++) { + sunxi_gpio_set_cfgpin(pin, SUN4I_GPG0_SDC1); + sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); + sunxi_gpio_set_drv(pin, 2); + } +#else + /* PH22-CMD, PH23-CLK, PH24~27-D0~D3 : 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); + } +#endif + 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: + /* PI4-CMD, PI5-CLK, PI6~9-D0~D3 : 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: + return -1; + } + + /* config ahb clock */ + rval = readl(&ccm->ahb_gate0); + rval |= 1 << AHB_GATE_OFFSET_MMC(sdc_no); + writel(rval, &ccm->ahb_gate0); + + /* config mod clock */ + pll5_clk = clock_get_pll5(); + if (pll5_clk > 400000000) + divider = 4; + else + divider = 3; + writel(CCM_MMC_CTRL_ENABLE | CCM_MMC_CTRL_PLL5 | divider, + mmchost->mclkreg); + mmchost->mod_clk = pll5_clk / (divider + 1); + + dumphex32("ccmu", (char *)SUNXI_CCM_BASE, 0x100); + dumphex32("gpio", (char *)SUNXI_PIO_BASE, 0x100); + dumphex32("mmc", (char *)mmchost->reg, 0x100); + dumpmmcreg(mmchost->reg); + + return 0; +} + +static int mmc_update_clk(struct mmc *mmc) +{ + struct sunxi_mmc_host *mmchost = (struct sunxi_mmc_host *)mmc->priv; + unsigned int cmd; + unsigned timeout = 0xfffff; + + 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) && timeout--) + ; + if (!timeout) + return -1; + + /* 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 = (struct sunxi_mmc_host *)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 = (struct sunxi_mmc_host *)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 = (struct sunxi_mmc_host *)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 = (struct sunxi_mmc_host *)mmc->priv; + unsigned i; + unsigned byte_cnt = data->blocksize * data->blocks; + unsigned *buff; + unsigned timeout = 0xfffff; + + if (data->flags & MMC_DATA_READ) { + buff = (unsigned int *)data->dest; + for (i = 0; i < (byte_cnt >> 2); i++) { + while (--timeout && + (readl(&mmchost->reg->status) & + SUNXI_MMC_STATUS_FIFO_EMPTY)) + ; + if (timeout <= 0) + goto out; + buff[i] = readl(mmchost->database); + timeout = 0xfffff; + } + } else { + buff = (unsigned int *)data->src; + for (i = 0; i < (byte_cnt >> 2); i++) { + while (--timeout && + (readl(&mmchost->reg->status) & + SUNXI_MMC_STATUS_FIFO_FULL)) + ; + if (timeout <= 0) + goto out; + writel(buff[i], mmchost->database); + timeout = 0xfffff; + } + } + +out: + if (timeout <= 0) + return -1; + + return 0; +} + +static int mmc_trans_data_by_dma(struct mmc *mmc, struct mmc_data *data) +{ + struct sunxi_mmc_host *mmchost = (struct sunxi_mmc_host *)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); + if (!remain) + remain = SDXC_DES_BUFFER_MAX_LEN; + + 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 = + (SDXC_DES_BUFFER_MAX_LEN - + 1) & SDXC_DES_BUFFER_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]; + } + debug("frag %d, remain %d, des[%d](%08x): ", + i, remain, des_idx, (u32)&pdes[des_idx]); + debug("[0] = %08x, [1] = %08x, [2] = %08x, [3] = %08x\n", + (u32)((u32 *)&pdes[des_idx])[0], + (u32)((u32 *)&pdes[des_idx])[1], + (u32)((u32 *)&pdes[des_idx])[2], + (u32)((u32 *)&pdes[des_idx])[3]); + } + 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 = (struct sunxi_mmc_host *)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, signed int timeout, + unsigned int done_bit, const char *what) +{ + struct sunxi_mmc_host *mmchost = (struct sunxi_mmc_host *)mmc->priv; + unsigned int status; + + do { + status = readl(&mmchost->reg->rint); + if (!timeout-- || + (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) { + debug("%s timeout %x\n", what, + status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT); + return TIMEOUT; + } + } 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 = (struct sunxi_mmc_host *)mmc->priv; + unsigned int cmdval = SUNXI_MMC_CMD_START; + signed int timeout = 0; + 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 = usedma ? 0xffff * bytecnt : 0xffff; + debug("cacl timeout %x\n", timeout); + error = mmc_rint_wait(mmc, timeout, + 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 = 0xfffff; + do { + status = readl(&mmchost->reg->status); + if (!timeout--) { + debug("busy timeout\n"); + error = TIMEOUT; + goto out; + } + } 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; +} + +int sunxi_mmc_init(int sdc_no) +{ + struct mmc *mmc; + + memset(&mmc_dev[sdc_no], 0, sizeof(struct mmc)); + memset(&mmc_host[sdc_no], 0, sizeof(struct sunxi_mmc_host)); + mmc = &mmc_dev[sdc_no]; + + sprintf(mmc->name, "SUNXI SD/MMC"); + mmc->priv = &mmc_host[sdc_no]; + mmc->send_cmd = mmc_send_cmd; + mmc->set_ios = mmc_set_ios; + mmc->init = mmc_core_init; + + mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; + mmc->host_caps = MMC_MODE_4BIT; + mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + + mmc->f_min = 400000; + mmc->f_max = 52000000; + + mmc_resource_init(sdc_no); + mmc_clk_io_on(sdc_no); + + mmc_register(mmc); + + return 0; +} diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 1cb798d..ed70c4e 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -60,6 +60,16 @@ #define CONFIG_INITRD_TAG #define CONFIG_CMDLINE_EDITING
+/* 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 */ + /* * Size of malloc() pool * 1MB = 0x100000, 0x100000 = 1024 * 1024 @@ -102,6 +112,7 @@ #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 \

On Friday, March 21, 2014 at 10:54:25 PM, Ian Campbell wrote:
As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Stefan Roese Tom Cubie yemao
Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Luke Leighton lkcl@lkcl.net Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Wills Wang wills.wang.open@gmail.com Signed-off-by: Ian Campbell ijc@hellion.org.uk Cc: Pantelis Antoniou panto@antoniou-consulting.com
[...]
+static void dumphex32(char *name, char *base, int len) +{
- __u32 i;
- debug("dump %s registers:", name);
- for (i = 0; i < len; i += 4) {
if (!(i & 0xf))
debug("\n0x%p : ", base + i);
debug("0x%08x ", readl(base + i));
- }
- debug("\n");
+}
Looks like print_hex_dump() reimplementation ...
[...]
+static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data) +{
- struct sunxi_mmc_host *mmchost = (struct sunxi_mmc_host *)mmc->priv;
- unsigned i;
- unsigned byte_cnt = data->blocksize * data->blocks;
- unsigned *buff;
- unsigned timeout = 0xfffff;
- if (data->flags & MMC_DATA_READ) {
buff = (unsigned int *)data->dest;
for (i = 0; i < (byte_cnt >> 2); i++) {
while (--timeout &&
(readl(&mmchost->reg->status) &
SUNXI_MMC_STATUS_FIFO_EMPTY))
;
if (timeout <= 0)
goto out;
buff[i] = readl(mmchost->database);
timeout = 0xfffff;
}
- } else {
buff = (unsigned int *)data->src;
for (i = 0; i < (byte_cnt >> 2); i++) {
while (--timeout &&
(readl(&mmchost->reg->status) &
SUNXI_MMC_STATUS_FIFO_FULL))
;
if (timeout <= 0)
goto out;
writel(buff[i], mmchost->database);
timeout = 0xfffff;
Are these two branches almost the same ? Why not just clear that up by squashing them into one with a small if (...) at the begining of this function ?
[...]
+static int mmc_trans_data_by_dma(struct mmc *mmc, struct mmc_data *data) +{
- struct sunxi_mmc_host *mmchost = (struct sunxi_mmc_host *)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);
- if (!remain)
remain = SDXC_DES_BUFFER_MAX_LEN;
- 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 =
(SDXC_DES_BUFFER_MAX_LEN -
1) & SDXC_DES_BUFFER_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];
}
debug("frag %d, remain %d, des[%d](%08x): ",
i, remain, des_idx, (u32)&pdes[des_idx]);
debug("[0] = %08x, [1] = %08x, [2] = %08x, [3] = %08x\n",
(u32)((u32 *)&pdes[des_idx])[0],
(u32)((u32 *)&pdes[des_idx])[1],
(u32)((u32 *)&pdes[des_idx])[2],
(u32)((u32 *)&pdes[des_idx])[3]);
Yum, this pointer voodoo looks tasty (and ready for fixing up ... ). [...]

As well as the following signed-off-by the sunxi branch shows commits to these files authored by the following: Henrik Nordstrom Tom Cubie
Signed-off-by: Stefan Roese sr@denx.de Signed-off-by: Ian Campbell ijc@hellion.org.uk --- v2: Based on u-boot-sunxi.git#sunxi d9aa5dd3d15c "sunxi: mmc: checkpatch whitespace fixes" with v2014.04-rc2 merged in: - mksunxiboot cleanups - rebase on Kbuild stuff
v1: Based on u-boot-sunxi.git#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01. --- Makefile | 10 +++ arch/arm/cpu/armv7/sunxi/config.mk | 8 ++ arch/arm/cpu/armv7/sunxi/u-boot-spl.lds | 52 +++++++++++ boards.cfg | 1 + include/configs/sunxi-common.h | 26 ++++++ spl/Makefile | 13 +++ tools/.gitignore | 1 + tools/Makefile | 2 + tools/mksunxiboot.README | 13 +++ tools/mksunxiboot.c | 153 ++++++++++++++++++++++++++++++++ 10 files changed, 279 insertions(+) create mode 100644 arch/arm/cpu/armv7/sunxi/config.mk create mode 100644 arch/arm/cpu/armv7/sunxi/u-boot-spl.lds create mode 100644 tools/mksunxiboot.README create mode 100644 tools/mksunxiboot.c
diff --git a/Makefile b/Makefile index b795338..31ea0ab 100644 --- a/Makefile +++ b/Makefile @@ -876,6 +876,13 @@ OBJCOPYFLAGS_u-boot.spr = -I binary -O binary --pad-to=$(CONFIG_SPL_PAD_TO) \ u-boot.spr: spl/u-boot-spl.img u-boot.img FORCE $(call if_changed,pad_cat)
+ifneq ($(CONFIG_SUNXI),) +OBJCOPYFLAGS_u-boot-sunxi-with-spl.bin = -I binary -O binary \ + --pad-to=$(CONFIG_SPL_PAD_TO) --gap-fill=0xff +u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img FORCE + $(call if_changed,pad_cat) +endif + ifneq ($(CONFIG_TEGRA),) OBJCOPYFLAGS_u-boot-nodtb-tegra.bin = -O binary --pad-to=$(CONFIG_SYS_TEXT_BASE) u-boot-nodtb-tegra.bin: spl/u-boot-spl u-boot.bin FORCE @@ -1087,6 +1094,9 @@ spl/u-boot-spl.bin: spl/u-boot-spl spl/u-boot-spl: tools prepare $(Q)$(MAKE) obj=spl -f $(srctree)/spl/Makefile all
+spl/sunxi-spl.bin: spl/u-boot-spl + @: + tpl/u-boot-tpl.bin: tools prepare $(Q)$(MAKE) obj=tpl -f $(srctree)/spl/Makefile all CONFIG_TPL_BUILD=y
diff --git a/arch/arm/cpu/armv7/sunxi/config.mk b/arch/arm/cpu/armv7/sunxi/config.mk new file mode 100644 index 0000000..00f5ffc --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/config.mk @@ -0,0 +1,8 @@ +# Build a combined spl + u-boot image +ifdef CONFIG_SPL +ifndef CONFIG_SPL_BUILD +ifndef CONFIG_SPL_FEL +ALL-y += u-boot-sunxi-with-spl.bin +endif +endif +endif diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds new file mode 100644 index 0000000..5008028 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2012 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Tom Cubie tangliang@allwinnertech.com + * + * Based on omap-common/u-boot-spl.lds: + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, garyj@denx.de + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * Aneesh V aneesh@ti.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\ + LENGTH = CONFIG_SPL_MAX_SIZE } +MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \ + LENGTH = CONFIG_SPL_BSS_MAX_SIZE } + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + .text : + { + __start = .; + arch/arm/cpu/armv7/start.o (.text) + *(.text*) + } > .sram + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram + + . = ALIGN(4); + .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram + + . = ALIGN(4); + __image_copy_end = .; + _end = .; + + .bss : + { + . = ALIGN(4); + __bss_start = .; + *(.bss*) + . = ALIGN(4); + __bss_end = .; + } > .sdram +} diff --git a/boards.cfg b/boards.cfg index 3134e9e..e8cdfbc 100644 --- a/boards.cfg +++ b/boards.cfg @@ -366,6 +366,7 @@ Active arm armv7 rmobile renesas lager Active arm armv7 s5pc1xx samsung goni s5p_goni - Mateusz Zalega m.zalega@samsung.com Active arm armv7 s5pc1xx samsung smdkc100 smdkc100 - Minkyu Kang mk7.kang@samsung.com Active arm armv7 socfpga altera socfpga socfpga_cyclone5 - - +Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,SPL,SUNXI_GMAC,RGMII - Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL,SUNXI_GMAC,RGMII - Active arm armv7 u8500 st-ericsson snowball snowball - Mathieu Poirier mathieu.poirier@linaro.org Active arm armv7 u8500 st-ericsson u8500 u8500_href - - diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index ed70c4e..e6c2760 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -17,6 +17,11 @@ * 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 */
@@ -139,11 +144,32 @@ #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 0x50000000 +#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 #define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK diff --git a/spl/Makefile b/spl/Makefile index bb3d349..9a6b265 100644 --- a/spl/Makefile +++ b/spl/Makefile @@ -188,6 +188,12 @@ ifdef CONFIG_SAMSUNG ALL-y += $(obj)/$(BOARD)-spl.bin endif
+ifdef CONFIG_SUNXI +ifndef CONFIG_SPL_FEL +ALL-y += $(obj)/sunxi-spl.bin +endif +endif + all: $(ALL-y)
ifdef CONFIG_SAMSUNG @@ -215,6 +221,13 @@ ifneq ($(CONFIG_SPL_TEXT_BASE),) LDFLAGS_$(SPL_BIN) += -Ttext $(CONFIG_SPL_TEXT_BASE) endif
+ifdef CONFIG_SUNXI +quiet_cmd_mksunxiboot = MKSUNXI $@ +cmd_mksunxiboot = $(OBJTREE)/tools/mksunxiboot $< $@ +$(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin + $(call if_changed,mksunxiboot) +endif + quiet_cmd_u-boot-spl = LD $@ cmd_u-boot-spl = cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \ $(patsubst $(obj)/%,%,$(u-boot-spl-init)) --start-group \ diff --git a/tools/.gitignore b/tools/.gitignore index 2a90dfe..3ad5db3 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -9,6 +9,7 @@ /mkexynosspl /mpc86x_clk /mxsboot +/mksunxiboot /ncb /proftool /relocate-rela diff --git a/tools/Makefile b/tools/Makefile index bac6aaf..63e00a8 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -120,6 +120,8 @@ hostprogs-$(CONFIG_MX23) += mxsboot$(SFX) hostprogs-$(CONFIG_MX28) += mxsboot$(SFX) HOSTCFLAGS_mxsboot$(SFX).o := -pedantic
+hostprogs-$(CONFIG_SUNXI) += mksunxiboot$(SFX) + hostprogs-$(CONFIG_NETCONSOLE) += ncb$(SFX) hostprogs-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
diff --git a/tools/mksunxiboot.README b/tools/mksunxiboot.README new file mode 100644 index 0000000..5838778 --- /dev/null +++ b/tools/mksunxiboot.README @@ -0,0 +1,13 @@ +This program make a arm binary file can be loaded by Allwinner A10 and related +chips from storage media such as nand and mmc. + +More information about A10 boot, please refer to +http://rhombus-tech.net/allwinner_a10/a10_boot_process/ + +To compile this program, just type make, you will get 'mksunxiboot'. + +To use it, +$./mksunxiboot u-boot.bin u-boot-mmc.bin +then you can write it to a mmc card with dd. +$sudo dd if=u-boot-mmc.bin of=/dev/sdb bs=1024 seek=8 +then insert your mmc card to your A10 tablet, you can boot from mmc card. diff --git a/tools/mksunxiboot.c b/tools/mksunxiboot.c new file mode 100644 index 0000000..864841e --- /dev/null +++ b/tools/mksunxiboot.c @@ -0,0 +1,153 @@ +/* + * (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> + +typedef unsigned char u8; +typedef unsigned int u32; + +/* boot head definition from sun4i boot code */ +struct boot_file_head { + u32 jump_instruction; /* one intruction jumping to real code */ + u8 magic[8]; /* ="eGON.BT0" or "eGON.BT1", not C-style str */ + u32 check_sum; /* generated by PC */ + u32 length; /* generated by PC */ +#if 1 + /* We use a simplified header, only filling in what is needed by the + * boot ROM. To be compatible with Allwinner tools the larger header + * below should be used, followed by a custom header if desired. */ + u8 pad[12]; /* align to 32 bytes */ +#else + u32 pub_head_size; /* the size of boot_file_head */ + u8 pub_head_vsn[4]; /* the version of boot_file_head */ + u8 file_head_vsn[4]; /* the version of boot0_file_head or + boot1_file_head */ + u8 Boot_vsn[4]; /* Boot version */ + u8 eGON_vsn[4]; /* eGON version */ + u8 platform[8]; /* platform information */ +#endif +}; + +#define BOOT0_MAGIC "eGON.BT0" +#define STAMP_VALUE 0x5F0A6C39 + +/* check sum functon from sun4i boot code */ +int gen_check_sum(void *boot_buf) +{ + struct boot_file_head *head_p; + u32 length; + u32 *buf; + u32 loop; + u32 i; + u32 sum; + + head_p = (struct boot_file_head *)boot_buf; + length = head_p->length; + if ((length & 0x3) != 0) /* must 4-byte-aligned */ + return -1; + buf = (u32 *)boot_buf; + 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((void *)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.jump_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((void *)&img); + + count = write(fd_out, (void *)&img, img.header.length); + if (count != img.header.length) { + perror("Writing output"); + return EXIT_FAILURE; + } + + close(fd_in); + close(fd_out); + + return EXIT_SUCCESS; +}

Dear Ian Campbell,
In message 1395438845.2234.95.camel@hastur.hellion.org.uk you wrote:
This is my second cut at an upstreamable series based upon the https://github.com/linux-sunxi/u-boot-sunxi.git#sunxi tree. The intention is to present a minimal starting point for upstreaming to which support for other processors, peripherals, boards etc can be added in the future. Therefore this has been stripped right back and currently supports only sun7i processors AKA Allwinner A20 and the cubietruck board. Supported peripherals are UART, MMC and Ethernet.
Sorry, this is a full NAK for the whole series. See previous comments to [5/9] and [4/9].
Best regards,
Wolfgang Denk

fre 2014-03-21 klockan 21:54 +0000 skrev Ian Campbell:
I've tried to give corect credit and S-o-b based upon: git log --pretty='%aN' linux-sunxi/sunxi -- [PATHS] | sort -u git log linux-sunxi/sunxi -- [PATHS] | grep -i signed.off.by | sort -u Manual inspection
As you noticed there is S-o-b lines missing on most of my commits in sunxi branch. This was corrected in the sunxi-patchqueue branch where previous patchset were prepared for mainlining.
Please add an implicit S-o-b line on any arch/arm/cpu/armv7/sunxi/ or board/sunxi/ on patches including code I have committed.
Regards Henrik

On Mon, 2014-03-24 at 01:14 +0100, Henrik Nordström wrote:
fre 2014-03-21 klockan 21:54 +0000 skrev Ian Campbell:
I've tried to give corect credit and S-o-b based upon: git log --pretty='%aN' linux-sunxi/sunxi -- [PATHS] | sort -u git log linux-sunxi/sunxi -- [PATHS] | grep -i signed.off.by | sort -u Manual inspection
As you noticed there is S-o-b lines missing on most of my commits in sunxi branch. This was corrected in the sunxi-patchqueue branch where previous patchset were prepared for mainlining.
Please add an implicit S-o-b line on any arch/arm/cpu/armv7/sunxi/ or board/sunxi/ on patches including code I have committed.
I will do. Thank you very much!
Ian.
participants (7)
-
Hans de Goede
-
Henrik Nordström
-
Ian Campbell
-
Marek Vasut
-
mrnuke
-
Olliver Schinagl
-
Wolfgang Denk