[U-Boot] [PATCH u-boot sunxi 00/12] sun4i (v2) + sun5i + pmic + emac support

Hi All,
Here is my continued work on getting various additional sunxi bits ready for upstreaming on top of Ian's sun7i upstreaming work.
As a basis I'm using Ian's v1 series, without GMAC as that is in a bit of flux and with various cleanups which were later added to the u-boot-sunxi repo squashed in, for a full series starting from v2014.01 (for now), see: https://github.com/jwrdegoede/u-boot-sunxi/tree/v2014.01-sunxi
There are 3 FIXUP patches in here which are intended to be squashed into Ian's work. Ian, can you please pick these up ?
The rest speaks for itself I hope. With this series we're pretty close to feature parity with the u-boot-sunxi branch.
Besides GMAC support the folliwing things are missing: -uart0 on port F (mmc0 pins) support -gpio command support -status-led support -falcon boot -boards, boards, boards -printing of board-name as part of the banner
I plan to fix the last one in the next version of my patch-set, note I've no plans to work on the other ones, they are all nice to have, but not really crucial to have IMHO.
Regards,
Hans

There is no way to reset the cpu, so use the watchdog for this.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/board.c | 7 +++++++ arch/arm/include/asm/arch-sunxi/timer.h | 4 ++++ 2 files changed, 11 insertions(+)
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index e95f4e5..4fd5bcc 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -54,6 +54,13 @@ int gpio_init(void)
void reset_cpu(ulong addr) { + static const struct sunxi_wdog *wdog = + &((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->wdog; + + /* Set the watchdog for its shortest interval (.5s) and wait */ + writel(WDT_MODE_RESET_EN | WDT_MODE_EN, &wdog->mode); + writel(WDT_CTRL_RESTART, &wdog->ctl); + while (1); }
/* do some early init */ diff --git a/arch/arm/include/asm/arch-sunxi/timer.h b/arch/arm/include/asm/arch-sunxi/timer.h index 6aacfd7..c29d3a0 100644 --- a/arch/arm/include/asm/arch-sunxi/timer.h +++ b/arch/arm/include/asm/arch-sunxi/timer.h @@ -11,6 +11,10 @@ #ifndef _SUNXI_TIMER_H_ #define _SUNXI_TIMER_H_
+#define WDT_CTRL_RESTART (0x1 << 0) +#define WDT_MODE_EN (0x1 << 0) +#define WDT_MODE_RESET_EN (0x1 << 1) + #ifndef __ASSEMBLY__
#include <linux/types.h>

On Tue, 2014-03-18 at 00:00 +0100, Hans de Goede wrote:
There is no way to reset the cpu, so use the watchdog for this.
Did you see https://www.mail-archive.com/u-boot@lists.denx.de/msg134259.html ?
Signed-off-by: Hans de Goede hdegoede@redhat.com
arch/arm/cpu/armv7/sunxi/board.c | 7 +++++++ arch/arm/include/asm/arch-sunxi/timer.h | 4 ++++ 2 files changed, 11 insertions(+)
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index e95f4e5..4fd5bcc 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -54,6 +54,13 @@ int gpio_init(void)
void reset_cpu(ulong addr) {
- static const struct sunxi_wdog *wdog =
&((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->wdog;
- /* Set the watchdog for its shortest interval (.5s) and wait */
- writel(WDT_MODE_RESET_EN | WDT_MODE_EN, &wdog->mode);
- writel(WDT_CTRL_RESTART, &wdog->ctl);
- while (1);
}
/* do some early init */ diff --git a/arch/arm/include/asm/arch-sunxi/timer.h b/arch/arm/include/asm/arch-sunxi/timer.h index 6aacfd7..c29d3a0 100644 --- a/arch/arm/include/asm/arch-sunxi/timer.h +++ b/arch/arm/include/asm/arch-sunxi/timer.h @@ -11,6 +11,10 @@ #ifndef _SUNXI_TIMER_H_ #define _SUNXI_TIMER_H_
+#define WDT_CTRL_RESTART (0x1 << 0) +#define WDT_MODE_EN (0x1 << 0) +#define WDT_MODE_RESET_EN (0x1 << 1)
#ifndef __ASSEMBLY__
#include <linux/types.h>

Hi,
On 03/18/2014 11:25 AM, Ian Campbell wrote:
On Tue, 2014-03-18 at 00:00 +0100, Hans de Goede wrote:
There is no way to reset the cpu, so use the watchdog for this.
Did you see https://www.mail-archive.com/u-boot@lists.denx.de/msg134259.html ?
Ah no, but I've read it now.
I think it would be better to focus on all the other more important bits for now, and then we can look into adding some sort of generic watchdog support later.
In the mean time I would like to carry this patch, since having "reset" work can be quite useful, and it is just 3 lines (not counting the lines which we would still need with the generic watchdog support).
Regards,
Hans
Signed-off-by: Hans de Goede hdegoede@redhat.com
arch/arm/cpu/armv7/sunxi/board.c | 7 +++++++ arch/arm/include/asm/arch-sunxi/timer.h | 4 ++++ 2 files changed, 11 insertions(+)
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index e95f4e5..4fd5bcc 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -54,6 +54,13 @@ int gpio_init(void)
void reset_cpu(ulong addr) {
- static const struct sunxi_wdog *wdog =
&((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->wdog;
- /* Set the watchdog for its shortest interval (.5s) and wait */
- writel(WDT_MODE_RESET_EN | WDT_MODE_EN, &wdog->mode);
- writel(WDT_CTRL_RESTART, &wdog->ctl);
- while (1);
}
/* do some early init */ diff --git a/arch/arm/include/asm/arch-sunxi/timer.h b/arch/arm/include/asm/arch-sunxi/timer.h index 6aacfd7..c29d3a0 100644 --- a/arch/arm/include/asm/arch-sunxi/timer.h +++ b/arch/arm/include/asm/arch-sunxi/timer.h @@ -11,6 +11,10 @@ #ifndef _SUNXI_TIMER_H_ #define _SUNXI_TIMER_H_
+#define WDT_CTRL_RESTART (0x1 << 0) +#define WDT_MODE_EN (0x1 << 0) +#define WDT_MODE_RESET_EN (0x1 << 1)
#ifndef __ASSEMBLY__
#include <linux/types.h>

On Sat, 2014-03-22 at 17:16 +0100, Hans de Goede wrote:
Hi,
On 03/18/2014 11:25 AM, Ian Campbell wrote:
On Tue, 2014-03-18 at 00:00 +0100, Hans de Goede wrote:
There is no way to reset the cpu, so use the watchdog for this.
Did you see https://www.mail-archive.com/u-boot@lists.denx.de/msg134259.html ?
Ah no, but I've read it now.
I think it would be better to focus on all the other more important bits for now, and then we can look into adding some sort of generic watchdog support later.
OK, I wanted to avoid divergence between the upstreaming effort at u-boot-sunxi.git as much as possible, but in this case I think the impact is small enough to be acceptable.
In the mean time I would like to carry this patch, since having "reset" work can be quite useful,
Absolutely!
(While I'm here: thanks for applying those other patches)
Ian

Add #ifdef CONFIG_SUN7I were appropriate to make adding sun4i / sun5i support later easier.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 4fd5bcc..07f8c12 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -66,7 +66,7 @@ void reset_cpu(ulong addr) /* do some early init */ void s_init(void) { -#if !defined CONFIG_SPL_BUILD +#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"

Add #ifdef CONFIG_SUN7I were appropriate to make adding sun4i / sun5i support later easier.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/clock.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm/cpu/armv7/sunxi/clock.c b/arch/arm/cpu/armv7/sunxi/clock.c index 9cdcc8a..dd01be6 100644 --- a/arch/arm/cpu/armv7/sunxi/clock.c +++ b/arch/arm/cpu/armv7/sunxi/clock.c @@ -33,10 +33,12 @@ static void clock_init_safe(void) 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

Add #ifdef CONFIG_SUN?I were appropriate to make adding sun4i / sun5i support later easier.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/dram.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index fd3f488..555b75d 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -116,6 +116,7 @@ static void mctl_enable_dllx(u32 phase) }
static u32 hpcr_value[32] = { +#ifdef CONFIG_SUN7I 0x0301, 0x0301, 0x0301, 0x0301, 0x0301, 0x0301, 0x0301, 0x0301, 0, 0, 0, 0, @@ -129,6 +130,7 @@ static u32 hpcr_value[32] = { * 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) @@ -162,11 +164,13 @@ static void mctl_setup_dram_clock(u32 clk)
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 | @@ -193,7 +197,9 @@ static int dramc_scan_readpipe(void) 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 */ @@ -320,15 +326,17 @@ fail:
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; @@ -342,6 +350,7 @@ static void dramc_set_autorefresh_cycle(u32 clk) reg_val |= 0x8 << 24; writel(reg_val, &dram->drr); } +#endif /* SUN5I */
unsigned long dramc_init(struct dram_para *para) { @@ -392,24 +401,32 @@ unsigned long dramc_init(struct dram_para *para) 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);
@@ -427,7 +444,9 @@ unsigned long dramc_init(struct dram_para *para)
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) { @@ -444,13 +463,16 @@ unsigned long dramc_init(struct dram_para *para) /* 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) { @@ -486,6 +508,7 @@ unsigned long dramc_init(struct dram_para *para)
udelay(2); } +#endif
/* scan read pipe value */ mctl_itm_enable();

Based linux-sunxi#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01.
As well as the following signed-off-by the sunxi branch shows commits to the new sun4i dram bits by:
Berg Xing bergxing@allwinnertech.com Tom Cubie tangliang@allwinnertech.com
Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Stefan Roese sr@denx.de Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/cpu_info.c | 7 +++ arch/arm/cpu/armv7/sunxi/dram.c | 108 ++++++++++++++++++++++++++++++++++++ board/sunxi/Makefile | 3 +- board/sunxi/dram_a10_olinuxino_l.c | 31 +++++++++++ boards.cfg | 1 + drivers/mmc/sunxi_mmc.c | 10 ++++ include/configs/sun4i.h | 23 ++++++++ 7 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 board/sunxi/dram_a10_olinuxino_l.c create mode 100644 include/configs/sun4i.h
diff --git a/arch/arm/cpu/armv7/sunxi/cpu_info.c b/arch/arm/cpu/armv7/sunxi/cpu_info.c index b4c3d5c..b4b5089 100644 --- a/arch/arm/cpu/armv7/sunxi/cpu_info.c +++ b/arch/arm/cpu/armv7/sunxi/cpu_info.c @@ -13,7 +13,14 @@ #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) { +#ifdef CONFIG_SUN4I + puts("CPU: Allwinner A10 (SUN4I)\n"); +#elif defined CONFIG_SUN7I puts("CPU: Allwinner A20 (SUN7I)\n"); +#else +#warning Please update cpu_info.c with correct CPU information + puts("CPU: SUNXI Family\n"); +#endif return 0; } #endif diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 555b75d..37edede 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -33,6 +33,21 @@ static void mctl_ddr3_reset(void) struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+#ifdef CONFIG_SUN4I + struct sunxi_timer_reg *timer = + (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; + u32 reg_val; + + writel(0, &timer->cpu_cfg); + reg_val = readl(&timer->cpu_cfg); + + if ((reg_val & CPU_CFG_CHIP_VER_MASK) != + CPU_CFG_CHIP_VER(CPU_CFG_CHIP_REV_A)) { + setbits_le32(&dram->mcr, DRAM_MCR_RESET); + udelay(2); + clrbits_le32(&dram->mcr, DRAM_MCR_RESET); + } else +#endif { clrbits_le32(&dram->mcr, DRAM_MCR_RESET); udelay(2); @@ -44,7 +59,11 @@ static void mctl_set_drive(void) { struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+#ifdef CONFIG_SUN7I clrsetbits_le32(&dram->mcr, DRAM_MCR_MODE_NORM(0x3) | (0x3 << 28), +#else + clrsetbits_le32(&dram->mcr, DRAM_MCR_MODE_NORM(0x3), +#endif DRAM_MCR_MODE_EN(0x3) | 0xffc); } @@ -96,7 +115,11 @@ static void mctl_enable_dllx(u32 phase) n = DRAM_DCR_NR_DLLCR_16BIT;
for (i = 1; i < n; i++) { +#ifdef CONFIG_SUN7I clrsetbits_le32(&dram->dllcr[i], 0xf << 14, +#else + clrsetbits_le32(&dram->dllcr[i], 0x4 << 14, +#endif (phase & 0xf) << 14); clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET, DRAM_DLLCR_DISABLE); @@ -116,6 +139,16 @@ static void mctl_enable_dllx(u32 phase) }
static u32 hpcr_value[32] = { +#ifdef CONFIG_SUN4I + 0x0301, 0x0301, 0x0301, 0x0301, + 0x0301, 0x0301, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0x1031, 0x1031, 0x0735, 0x1035, + 0x1035, 0x0731, 0x1031, 0x0735, + 0x1035, 0x1031, 0x0731, 0x1035, + 0x1031, 0x0301, 0x0301, 0x0731 +#endif #ifdef CONFIG_SUN7I 0x0301, 0x0301, 0x0301, 0x0301, 0x0301, 0x0301, 0x0301, 0x0301, @@ -174,20 +207,34 @@ static void mctl_setup_dram_clock(u32 clk)
/* setup MBUS clock */ reg_val = CCM_MBUS_CTRL_GATE | +#if defined(CONFIG_SUN7I) 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)); +#else /* defined(CONFIG_SUN7I) */ + CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL5) | + CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(1)) | + CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(2)); +#endif writel(reg_val, &ccm->mbus_clk_cfg);
/* * open DRAMC AHB & DLL register clock * close it first */ +#if defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I) clrbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_SDRAM | CCM_AHB_GATE_DLL); +#else + clrbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_SDRAM); +#endif udelay(22);
/* then open it */ +#if defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I) setbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_SDRAM | CCM_AHB_GATE_DLL); +#else + setbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_SDRAM); +#endif udelay(22); }
@@ -334,8 +381,42 @@ static void dramc_clock_output_en(u32 on) else clrbits_le32(&dram->mcr, DRAM_MCR_DCLK_OUT); #endif +#ifdef CONFIG_SUN4I + struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + if (on) + setbits_le32(&ccm->dram_clk_cfg, CCM_DRAM_CTRL_DCLK_OUT); + else + clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAM_CTRL_DCLK_OUT); +#endif }
+#ifdef CONFIG_SUN4I +static void dramc_set_autorefresh_cycle(u32 clk) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + u32 reg_val; + u32 tmp_val; + u32 reg_dcr; + + if (clk < 600) { + reg_dcr = readl(&dram->dcr); + if ((reg_dcr & DRAM_DCR_CHIP_DENSITY_MASK) <= + DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_1024M)) + reg_val = (131 * clk) >> 10; + else + reg_val = (336 * clk) >> 10; + + tmp_val = (7987 * clk) >> 10; + tmp_val = tmp_val * 9 - 200; + reg_val |= tmp_val << 8; + reg_val |= 0x8 << 24; + writel(reg_val, &dram->drr); + } else { + writel(0x0, &dram->drr); + } +} +#endif /* SUN4I */ + #if defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I) static void dramc_set_autorefresh_cycle(u32 clk) { @@ -366,11 +447,19 @@ unsigned long dramc_init(struct dram_para *para) mctl_setup_dram_clock(para->clock);
/* reset external DRAM */ +#ifndef CONFIG_SUN7I + mctl_ddr3_reset(); +#endif mctl_set_drive();
/* dram clock off */ dramc_clock_output_en(0);
+#ifdef CONFIG_SUN4I + /* select dram controller 1 */ + writel(DRAM_CSEL_MAGIC, &dram->csel); +#endif + mctl_itm_disable(); mctl_enable_dll0(para->tpr3);
@@ -426,6 +515,9 @@ unsigned long dramc_init(struct dram_para *para) mctl_ddr3_reset(); else setbits_le32(&dram->mcr, DRAM_MCR_RESET); +#else + /* dram clock on */ + dramc_clock_output_en(1); #endif
udelay(1); @@ -434,6 +526,22 @@ unsigned long dramc_init(struct dram_para *para)
mctl_enable_dllx(para->tpr3);
+#ifdef CONFIG_SUN4I + /* set odt impendance divide ratio */ + reg_val = ((para->zq) >> 8) & 0xfffff; + reg_val |= ((para->zq) & 0xff) << 20; + reg_val |= (para->zq) & 0xf0000000; + writel(reg_val, &dram->zqcr0); +#endif + +#ifdef CONFIG_SUN4I + /* set I/O configure register */ + reg_val = 0x00cc0000; + reg_val |= (para->odt_en) & 0x3; + reg_val |= ((para->odt_en) & 0x3) << 30; + writel(reg_val, &dram->iocr); +#endif + /* set refresh period */ dramc_set_autorefresh_cycle(para->clock);
diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile index 6483bf4..590ca42 100644 --- a/board/sunxi/Makefile +++ b/board/sunxi/Makefile @@ -9,4 +9,5 @@ # SPDX-License-Identifier: GPL-2.0+ # obj-y += board.o -obj-y += dram_cubietruck.o +obj-$(CONFIG_A10_OLINUXINO_L) += dram_a10_olinuxino_l.o +obj-$(CONFIG_CUBIETRUCK) += dram_cubietruck.o diff --git a/board/sunxi/dram_a10_olinuxino_l.c b/board/sunxi/dram_a10_olinuxino_l.c new file mode 100644 index 0000000..24a1bd9 --- /dev/null +++ b/board/sunxi/dram_a10_olinuxino_l.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 = 480, + .type = 3, + .rank_num = 1, + .density = 4096, + .io_width = 16, + .bus_width = 16, + .cas = 6, + .zq = 123, + .odt_en = 0, + .size = 512, + .tpr0 = 0x30926692, + .tpr1 = 0x1090, + .tpr2 = 0x1a0c8, + .tpr3 = 0, + .tpr4 = 0, + .tpr5 = 0, + .emr1 = 0x4, + .emr2 = 0, + .emr3 = 0, +}; + +unsigned long sunxi_dram_init(void) +{ + return dramc_init(&dram_para); +} diff --git a/boards.cfg b/boards.cfg index a513376..07dd65a 100644 --- a/boards.cfg +++ b/boards.cfg @@ -353,6 +353,7 @@ Active arm armv7 rmobile renesas koelsch 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 A10-OLinuXino-Lime sun4i:A10_OLINUXINO_L,SPL - Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,SPL - 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 diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index e052af5..80e4369 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -71,10 +71,20 @@ struct sunxi_mmc_des { 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 */ +#ifdef CONFIG_SUN4I +#define SDXC_DES_NUM_SHIFT 13 +#define SDXC_DES_BUFFER_MAX_LEN (1 << SDXC_DES_NUM_SHIFT) + u32 data_buf1_sz:13; + u32 data_buf2_sz:13; + u32 reserverd2_1:6; +#elif defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I) #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; +#else +#error ">>>> Wrong Platform for MMC <<<<" +#endif u32 buf_addr_ptr1; u32 buf_addr_ptr2; }; diff --git a/include/configs/sun4i.h b/include/configs/sun4i.h new file mode 100644 index 0000000..6560b65 --- /dev/null +++ b/include/configs/sun4i.h @@ -0,0 +1,23 @@ +/* + * (C) Copyright 2012-2013 Henrik Nordstrom henrik@henriknordstrom.net + * + * Configuration settings for the Allwinner A10 (sun4i) CPU + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * A10 specific configuration + */ +#define CONFIG_SUN4I /* sun4i SoC generation */ + +#define CONFIG_SYS_PROMPT "sun4i# " + +/* + * Include common sunxi configuration where most the settings are + */ +#include <configs/sunxi-common.h> + +#endif /* __CONFIG_H */

Based linux-sunxi#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01.
As well as the following signed-off-by the sunxi branch shows commits to the sun5i dram bits by:
Berg Xing bergxing@allwinnertech.com Tom Cubie tangliang@allwinnertech.com
Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Stefan Roese sr@denx.de Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/board.c | 12 ++++++++++++ arch/arm/cpu/armv7/sunxi/clock.c | 5 +++++ arch/arm/cpu/armv7/sunxi/cpu_info.c | 3 +++ arch/arm/cpu/armv7/sunxi/dram.c | 15 +++++++++++++++ arch/arm/include/asm/arch-sunxi/clock.h | 7 +++++++ board/sunxi/Makefile | 1 + board/sunxi/dram_a10s_olinuxino_m.c | 31 +++++++++++++++++++++++++++++++ boards.cfg | 1 + include/configs/sun5i.h | 23 +++++++++++++++++++++++ include/configs/sunxi-common.h | 2 ++ 10 files changed, 100 insertions(+) create mode 100644 board/sunxi/dram_a10s_olinuxino_m.c create mode 100644 include/configs/sun5i.h
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 07f8c12..72eed16 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -45,9 +45,21 @@ u32 spl_boot_mode(void)
int gpio_init(void) { +#if CONFIG_CONS_INDEX == 1 && (defined(CONFIG_SUN4I) || defined(CONFIG_SUN7I)) 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); +#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_SUN5I) + sunxi_gpio_set_cfgpin(SUNXI_GPB(19), SUN5I_GPB19_UART0_TX); + sunxi_gpio_set_cfgpin(SUNXI_GPB(20), SUN5I_GPB20_UART0_RX); + sunxi_gpio_set_pull(SUNXI_GPB(20), 1); +#elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_SUN5I) + sunxi_gpio_set_cfgpin(SUNXI_GPG(3), SUN5I_GPG3_UART1_TX); + sunxi_gpio_set_cfgpin(SUNXI_GPG(4), SUN5I_GPG4_UART1_RX); + sunxi_gpio_set_pull(SUNXI_GPG(4), 1); +#else +#error Unsupported console port number. Please fix pin mux settings in board.c +#endif
return 0; } diff --git a/arch/arm/cpu/armv7/sunxi/clock.c b/arch/arm/cpu/armv7/sunxi/clock.c index dd01be6..22c89b8 100644 --- a/arch/arm/cpu/armv7/sunxi/clock.c +++ b/arch/arm/cpu/armv7/sunxi/clock.c @@ -33,6 +33,11 @@ static void clock_init_safe(void) APB0_DIV_1 << APB0_DIV_SHIFT | CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT, &ccm->cpu_ahb_apb0_cfg); +#ifdef CONFIG_SUN5I + /* Power on reset default for PLL6 is 2400 MHz, which is faster then + * it can reliable do :| Set it to a 600 MHz instead. */ + writel(PLL6_CFG_DEFAULT, &ccm->pll6_cfg); +#endif #ifdef CONFIG_SUN7I writel(0x1 << AHB_GATE_OFFSET_DMA | readl(&ccm->ahb_gate0), &ccm->ahb_gate0); diff --git a/arch/arm/cpu/armv7/sunxi/cpu_info.c b/arch/arm/cpu/armv7/sunxi/cpu_info.c index b4b5089..a388a53 100644 --- a/arch/arm/cpu/armv7/sunxi/cpu_info.c +++ b/arch/arm/cpu/armv7/sunxi/cpu_info.c @@ -15,6 +15,9 @@ int print_cpuinfo(void) { #ifdef CONFIG_SUN4I puts("CPU: Allwinner A10 (SUN4I)\n"); +#elif defined CONFIG_SUN5I + /* TODO: Distinguish A13/A10s */ + puts("CPU: Allwinner A13/A10s (SUN5I)\n"); #elif defined CONFIG_SUN7I puts("CPU: Allwinner A20 (SUN7I)\n"); #else diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 37edede..781f9b5 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -139,6 +139,16 @@ static void mctl_enable_dllx(u32 phase) }
static u32 hpcr_value[32] = { +#ifdef CONFIG_SUN5I + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0x1031, 0x1031, 0x0735, 0x1035, + 0x1035, 0x0731, 0x1031, 0, + 0x0301, 0x0301, 0x0301, 0x0301, + 0x0301, 0x0301, 0x0301, 0 +#endif #ifdef CONFIG_SUN4I 0x0301, 0x0301, 0x0301, 0x0301, 0x0301, 0x0301, 0, 0, @@ -446,6 +456,11 @@ unsigned long dramc_init(struct dram_para *para) /* setup DRAM relative clock */ mctl_setup_dram_clock(para->clock);
+#ifdef CONFIG_SUN5I + /* Disable any pad power save control */ + writel(0, &dram->ppwrsctl); +#endif + /* reset external DRAM */ #ifndef CONFIG_SUN7I mctl_ddr3_reset(); diff --git a/arch/arm/include/asm/arch-sunxi/clock.h b/arch/arm/include/asm/arch-sunxi/clock.h index 77a9b91..b889c11 100644 --- a/arch/arm/include/asm/arch-sunxi/clock.h +++ b/arch/arm/include/asm/arch-sunxi/clock.h @@ -119,8 +119,15 @@ struct sunxi_ccm_reg {
#define PLL1_CFG_DEFAULT 0xa1005000
+#ifdef CONFIG_SUN5I +#define PLL6_CFG_DEFAULT 0x21009911 +#endif #define PLL6_ENABLE_OFFSET 31
+#ifdef CONFIG_SUN5I +#define AHB_CLK_SRC_AXI 0 +#endif + #define CLK_GATE_OPEN 0x1 #define CLK_GATE_CLOSE 0x0
diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile index 590ca42..8e284d4 100644 --- a/board/sunxi/Makefile +++ b/board/sunxi/Makefile @@ -10,4 +10,5 @@ # obj-y += board.o obj-$(CONFIG_A10_OLINUXINO_L) += dram_a10_olinuxino_l.o +obj-$(CONFIG_A10S_OLINUXINO_M) += dram_a10s_olinuxino_m.o obj-$(CONFIG_CUBIETRUCK) += dram_cubietruck.o diff --git a/board/sunxi/dram_a10s_olinuxino_m.c b/board/sunxi/dram_a10s_olinuxino_m.c new file mode 100644 index 0000000..8900539 --- /dev/null +++ b/board/sunxi/dram_a10s_olinuxino_m.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 = 4096, + .io_width = 16, + .bus_width = 16, + .cas = 9, + .zq = 123, + .odt_en = 0, + .size = 512, + .tpr0 = 0x42d899b7, + .tpr1 = 0xa090, + .tpr2 = 0x22a00, + .tpr3 = 0, + .tpr4 = 0, + .tpr5 = 0, + .emr1 = 0x4, + .emr2 = 0x10, + .emr3 = 0, +}; + +unsigned long sunxi_dram_init(void) +{ + return dramc_init(&dram_para); +} diff --git a/boards.cfg b/boards.cfg index 07dd65a..bae0797 100644 --- a/boards.cfg +++ b/boards.cfg @@ -354,6 +354,7 @@ Active arm armv7 s5pc1xx samsung goni 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 A10-OLinuXino-Lime sun4i:A10_OLINUXINO_L,SPL - +Active arm armv7 sunxi - sunxi A10s-OLinuXino-M sun5i:A10S_OLINUXINO_M,SPL - Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,SPL - 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 diff --git a/include/configs/sun5i.h b/include/configs/sun5i.h new file mode 100644 index 0000000..43f0d67 --- /dev/null +++ b/include/configs/sun5i.h @@ -0,0 +1,23 @@ +/* + * (C) Copyright 2012-2013 Henrik Nordstrom henrik@henriknordstrom.net + * + * Configuration settings for the Allwinner A13 (sun5i) CPU + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * High Level Configuration Options + */ +#define CONFIG_SUN5I /* sun5i SoC generation */ + +#define CONFIG_SYS_PROMPT "sun5i# " + +/* + * 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 index 2bfea55..fe41b89 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -176,7 +176,9 @@ #undef CONFIG_CMD_NET #undef CONFIG_CMD_NFS
+#ifndef CONFIG_CONS_INDEX #define CONFIG_CONS_INDEX 1 /* UART0 */ +#endif
#if !defined CONFIG_ENV_IS_IN_MMC && \ !defined CONFIG_ENV_IS_IN_NAND && \

From: Henrik Nordstrom henrik@henriknordstrom.net
Based linux-sunxi#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01.
As well as the following signed-off-by the sunxi branch shows commits to the sunxi_i2c.c file by:
Stefan Roese sr@denx.de
Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/board.c | 6 + arch/arm/include/asm/arch-sunxi/i2c.h | 169 ++++++++++++++++++++++ drivers/i2c/Makefile | 1 + drivers/i2c/sunxi_i2c.c | 260 ++++++++++++++++++++++++++++++++++ include/configs/sunxi-common.h | 8 ++ 5 files changed, 444 insertions(+) create mode 100644 arch/arm/include/asm/arch-sunxi/i2c.h create mode 100644 drivers/i2c/sunxi_i2c.c
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 72eed16..b00bf89 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -11,6 +11,7 @@ */
#include <common.h> +#include <i2c.h> #include <serial.h> #ifdef CONFIG_SPL_BUILD #include <spl.h> @@ -94,6 +95,11 @@ void s_init(void) gd = &gdata; preloader_console_init();
+#ifdef CONFIG_SPL_I2C_SUPPORT + /* Needed early by sunxi_board_init if PMU is enabled */ + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +#endif + sunxi_board_init(); #endif } diff --git a/arch/arm/include/asm/arch-sunxi/i2c.h b/arch/arm/include/asm/arch-sunxi/i2c.h new file mode 100644 index 0000000..74c2d18 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/i2c.h @@ -0,0 +1,169 @@ +/* + * (C) Copyright 2012 Henrik Nordstrom henrik@henriknordstrom.net + * + * Based on sun4i linux kernle i2c.h + * (C) Copyright 2007-2012 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Tom Cubie tanglaing@allwinnertech.com + * Victor Wei weiziheng@allwinnertech.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _SUNXI_I2C_H_ +#define _SUNXI_I2C_H_ + +struct i2c { + u32 saddr; /* 31:8bit res,7-1bit for slave addr,0 bit for GCE */ + u32 xsaddr; /* 31:8bit res,7-0bit for second addr in 10bit addr */ + u32 data; /* 31:8bit res, 7-0bit send or receive data byte */ + u32 ctl; /* INT_EN,BUS_EN,M_STA,INT_FLAG,A_ACK */ + u32 status; /* 28 interrupt types + 0xf8 normal type = 29 */ + u32 clkr; /* 31:7bit res,6-3bit,CLK_M,2-0bit CLK_N */ + u32 reset; /* 31:1bit res;0bit,write 1 to clear 0. */ + u32 efr; /* 31:2bit res,1:0 bit data byte follow read comand */ + u32 lctl; /* 31:6bits res 5:0bit for sda&scl control */ +}; + +/* TWI address register */ +#define TWI_GCE_EN (0x1 << 0) /* gen call addr enable slave mode */ +#define TWI_ADDR_MASK (0x7f << 1) /* 7:1bits */ +#define TWI_XADDR_MASK 0xff /* 7:0bits for extend slave address */ + +#define TWI_DATA_MASK 0xff /* 7:0bits for send or received */ + +/* TWI Control Register Bit Fields */ +/* 1:0 bits reserved */ +/* set 1 to send A_ACK,then low level on SDA */ +#define TWI_CTL_ACK (0x1 << 2) +/* INT_FLAG,interrupt status flag: set '1' when interrupt coming */ +#define TWI_CTL_INTFLG (0x1 << 3) +#define TWI_CTL_STP (0x1 << 4) /* M_STP,Automatic clear 0 */ +#define TWI_CTL_STA (0x1 << 5) /* M_STA,atutomatic clear 0 */ +#define TWI_CTL_BUSEN (0x1 << 6) /* BUS_EN, mastr mode should be set 1 */ +#define TWI_CTL_INTEN (0x1 << 7) /* INT_EN */ +/* 31:8 bit reserved */ + +/* + * TWI Clock Register Bit Fields & Masks,default value:0x0000_0000 + * Fin is APB CLOCK INPUT; + * Fsample = F0 = Fin/2^CLK_N; + * F1 = F0/(CLK_M+1); + * + * Foscl = F1/10 = Fin/(2^CLK_N * (CLK_M+1)*10); + * Foscl is clock SCL;standard mode:100KHz or fast mode:400KHz + */ + +#define TWI_CLK_DIV_M (0xf << 3) /* 6:3bit */ +#define TWI_CLK_DIV_N (0x7 << 0) /* 2:0bit */ +#define TWI_CLK_DIV(N, M) ((((N) & 0xf) << 3) | (((M) & 0x7) << 0)) + +/* TWI Soft Reset Register Bit Fields & Masks */ +/* write 1 to clear 0, when complete soft reset clear 0 */ +#define TWI_SRST_SRST (0x1 << 0) + +/* TWI Enhance Feature Register Bit Fields & Masks */ +/* default -- 0x0 */ +/* 00:no,01: 1byte, 10:2 bytes, 11: 3bytes */ +#define TWI_EFR_MASK (0x3 << 0) +#define TWI_EFR_WARC_0 (0x0 << 0) +#define TWI_EFR_WARC_1 (0x1 << 0) +#define TWI_EFR_WARC_2 (0x2 << 0) +#define TWI_EFR_WARC_3 (0x3 << 0) + +/* twi line control register -default value: 0x0000_003a */ +/* SDA line state control enable ,1:enable;0:disable */ +#define TWI_LCR_SDA_EN (0x01 << 0) +/* SDA line state control bit, 1:high level;0:low level */ +#define TWI_LCR_SDA_CTL (0x01 << 1) +/* SCL line state control enable ,1:enable;0:disable */ +#define TWI_LCR_SCL_EN (0x01 << 2) +/* SCL line state control bit, 1:high level;0:low level */ +#define TWI_LCR_SCL_CTL (0x01 << 3) +/* current state of SDA,readonly bit */ +#define TWI_LCR_SDA_STATE_MASK (0x01 << 4) +/* current state of SCL,readonly bit */ +#define TWI_LCR_SCL_STATE_MASK (0x01 << 5) +/* 31:6bits reserved */ +#define TWI_LCR_IDLE_STATUS 0x3a + +/* TWI Status Register Bit Fields & Masks */ +#define TWI_STAT_MASK 0xff +/* 7:0 bits use only,default is 0xf8 */ +#define TWI_STAT_BUS_ERR 0x00 /* BUS ERROR */ + +/* Master mode use only */ +#define TWI_STAT_TX_STA 0x08 /* START condition transmitted */ +/* Repeated START condition transmitted */ +#define TWI_STAT_TX_RESTA 0x10 +/* Address+Write bit transmitted, ACK received */ +#define TWI_STAT_TX_AW_ACK 0x18 +/* Address+Write bit transmitted, ACK not received */ +#define TWI_STAT_TX_AW_NAK 0x20 +/* data byte transmitted in master mode,ack received */ +#define TWI_STAT_TXD_ACK 0x28 +/* data byte transmitted in master mode ,ack not received */ +#define TWI_STAT_TXD_NAK 0x30 +/* arbitration lost in address or data byte */ +#define TWI_STAT_ARBLOST 0x38 +/* Address+Read bit transmitted, ACK received */ +#define TWI_STAT_TX_AR_ACK 0x40 +/* Address+Read bit transmitted, ACK not received */ +#define TWI_STAT_TX_AR_NAK 0x48 +/* Second Address byte + Write bit transmitted, ACK received */ +#define TWI_STAT_TX_2AW_ACK 0xd0 +/* Second Address byte + Write bit transmitted, ACK received */ +#define TWI_STAT_TX_2AW_NAK 0xd8 +/* data byte received in master mode ,ack transmitted */ +#define TWI_STAT_RXD_ACK 0x50 +/* date byte received in master mode,not ack transmitted */ +#define TWI_STAT_RXD_NAK 0x58 + +/* Slave mode use only */ +/* Slave address+Write bit received, ACK transmitted */ +#define TWI_STAT_RXWS_ACK 0x60 +/* + * Arbitration lost in address as master, slave address + Write bit received, + * ACK transmitted + */ +#define TWI_STAT_ARBLOST_RXWS_ACK 0x68 +/* General Call address received, ACK transmitted */ +#define TWI_STAT_RXGCAS_ACK 0x70 +/* + * Arbitration lost in address as master, General Call address received, + * ACK transmitted + */ +#define TWI_STAT_ARBLOST_RXGCAS_ACK 0x78 +/* Data byte received after slave address received, ACK transmitted */ +#define TWI_STAT_RXDS_ACK 0x80 +/* Data byte received after slave address received, not ACK transmitted */ +#define TWI_STAT_RXDS_NAK 0x88 +/* Data byte received after General Call received, ACK transmitted */ +#define TWI_STAT_RXDGCAS_ACK 0x90 +/* Data byte received after General Call received, not ACK transmitted */ +#define TWI_STAT_RXDGCAS_NAK 0x98 +/* STOP or repeated START condition received in slave */ +#define TWI_STAT_RXSTPS_RXRESTAS 0xa0 +/* Slave address + Read bit received, ACK transmitted */ +#define TWI_STAT_RXRS_ACK 0xa8 +/* + * Arbitration lost in address as master, slave address + Read bit received, + * ACK transmitted + */ +#define TWI_STAT_ARBLOST_SLAR_ACK 0xb0 +/* Data byte transmitted in slave mode, ACK received */ +#define TWI_STAT_TXDS_ACK 0xb8 +/* Data byte transmitted in slave mode, ACK not received */ +#define TWI_STAT_TXDS_NAK 0xc0 +/* Last byte transmitted in slave mode, ACK received */ +#define TWI_STAT_TXDSL_ACK 0xc8 + +/* 10bit Address, second part of address */ +/* Second Address byte+Write bit transmitted,ACK received */ +#define TWI_STAT_TX_SAW_ACK 0xd0 +/* Second Address byte+Write bit transmitted,ACK not received */ +#define TWI_STAT_TX_SAW_NAK 0xd8 + +/* No relevant status infomation,INT_FLAG = 0 */ +#define TWI_STAT_IDLE 0xf8 + +#endif diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index fa3a875..2a44db4 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o obj-$(CONFIG_U8500_I2C) += u8500_i2c.o obj-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o +obj-$(CONFIG_SUNXI_I2C) += sunxi_i2c.o obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o diff --git a/drivers/i2c/sunxi_i2c.c b/drivers/i2c/sunxi_i2c.c new file mode 100644 index 0000000..9a542f6 --- /dev/null +++ b/drivers/i2c/sunxi_i2c.c @@ -0,0 +1,260 @@ +/* + * (C) Copyright 2012 Henrik Nordstrom henrik@henriknordstrom.net + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <i2c.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/cpu.h> +#include <asm/arch/gpio.h> +#include <asm/arch/i2c.h> + +static struct i2c __attribute__ ((section(".data"))) *i2c_base = + (struct i2c *)0x1c2ac00; + +void i2c_init(int speed, int slaveaddr) +{ + int timeout = 0x2ff; + + sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUNXI_GPB0_TWI0); + sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUNXI_GPB0_TWI0); + clock_twi_onoff(0, 1); + + /* Enable the i2c bus */ + writel(TWI_CTL_BUSEN, &i2c_base->ctl); + + /* 400KHz operation M=2, N=1, 24MHz APB clock */ + writel(TWI_CLK_DIV(2, 1), &i2c_base->clkr); + writel(TWI_SRST_SRST, &i2c_base->reset); + + while ((readl(&i2c_base->reset) & TWI_SRST_SRST) && timeout--); +} + +int i2c_probe(uchar chip) +{ + return -1; +} + +static int i2c_wait_ctl(int mask, int state) +{ + int timeout = 0x2ff; + int value = state ? mask : 0; + + debug("i2c_wait_ctl(%x == %x), ctl=%x, status=%x\n", mask, value, + i2c_base->ctl, i2c_base->status); + + while (((readl(&i2c_base->ctl) & mask) != value) && timeout-- > 0); + + debug("i2c_wait_ctl(), timeout=%d, ctl=%x, status=%x\n", timeout, + i2c_base->ctl, i2c_base->status); + + if (timeout != 0) + return 0; + else + return -1; +} + +static void i2c_clear_irq(void) +{ + writel(readl(&i2c_base->ctl) & ~TWI_CTL_INTFLG, &i2c_base->ctl); +} + +static int i2c_wait_irq(void) +{ + return i2c_wait_ctl(TWI_CTL_INTFLG, 1); +} + +static int i2c_wait_status(int status) +{ + int timeout = 0x2ff; + + while (readl(&i2c_base->status) != status && timeout-- > 0); + + if (timeout != 0) + return 0; + else + return -1; +} + +static int i2c_wait_irq_status(int status) +{ + if (i2c_wait_irq() != 0) + return -1; + + if (readl(&i2c_base->status) != status) + return -1; + + return 0; +} + +static int i2c_wait_bus_idle(void) +{ + int timeout = 0x2ff; + + while (readl(&i2c_base->lctl) != 0x3a && timeout-- > 0); + + if (timeout != 0) + return 0; + else + return -1; +} + +static int i2c_stop(void) +{ + u32 ctl; + + ctl = readl(&i2c_base->ctl) & 0xc0; + ctl |= TWI_CTL_STP; + + writel(ctl, &i2c_base->ctl); + + /* dummy to delay one I/O operation to make sure it's started */ + (void)readl(&i2c_base->ctl); + + if (i2c_wait_ctl(TWI_CTL_STP, 0) != 0) + return -1; + if (i2c_wait_status(TWI_STAT_IDLE)) + return -1; + if (i2c_wait_bus_idle() != 0) + return -1; + + return 0; +} + +static int i2c_send_data(u8 data, u8 status) +{ + debug("i2c_write(%02x, %x), ctl=%x, status=%x\n", data, status, + i2c_base->ctl, i2c_base->status); + + writel(data, &i2c_base->data); + i2c_clear_irq(); + + if (i2c_wait_irq_status(status) != 0) + return -1; + + return 0; +} + +static int i2c_start(int status) +{ + u32 ctl; + + debug("i2c_start(%x), ctl=%x, status=%x\n", status, i2c_base->ctl, + i2c_base->status); + /* Check that the controller is idle */ + if (status == TWI_STAT_TX_STA && + readl(&i2c_base->status) != TWI_STAT_IDLE) { + return -1; + } + + writel(0, &i2c_base->efr); + + /* Send start */ + ctl = readl(&i2c_base->ctl); + ctl |= TWI_CTL_STA; /* Set start bit */ + ctl &= ~TWI_CTL_INTFLG; /* Clear int flag */ + writel(ctl, &i2c_base->ctl); + + if (i2c_wait_ctl(TWI_CTL_STA, 0) != 0) + return -1; + if (i2c_wait_irq_status(status) != 0) + return -1; + + return 0; +} + +int i2c_do_read(uchar chip, uint addr, int alen, uchar *buffer, int len) +{ + u32 status; + u32 ctl; + + if (i2c_start(TWI_STAT_TX_STA) != 0) + return -1; + + /* Send chip address */ + if (i2c_send_data(chip << 1 | 0, TWI_STAT_TX_AW_ACK) != 0) + return -1; + + /* Send data address */ + if (i2c_send_data(addr, TWI_STAT_TXD_ACK) != 0) + return -1; + + /* Send restart for read */ + if (i2c_start(TWI_STAT_TX_RESTA) != 0) + return -1; + + /* Send chip address */ + if (i2c_send_data(chip << 1 | 1, TWI_STAT_TX_AR_ACK) != 0) + return -1; + + /* Set ACK mode */ + ctl = readl(&i2c_base->ctl); + ctl |= TWI_CTL_ACK; + writel(ctl, &i2c_base->ctl); + status = TWI_STAT_RXD_ACK; + + /* Read data */ + while (len > 0) { + if (len == 1) { + /* Set NACK mode (last byte) */ + ctl = readl(&i2c_base->ctl); + ctl &= ~TWI_CTL_ACK; + writel(ctl, &i2c_base->ctl); + status = TWI_STAT_RXD_NAK; + } + + i2c_clear_irq(); + if (i2c_wait_irq_status(status) != 0) + return -1; + + *buffer++ = readl(&i2c_base->data); + len--; + } + + return 0; +} + +int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) +{ + int rc = i2c_do_read(chip, addr, alen, buffer, len); + + i2c_stop(); + + return rc; +} + +static int i2c_do_write(uchar chip, uint addr, int alen, uchar *buffer, + int len) +{ + if (i2c_start(TWI_STAT_TX_STA) != 0) + return -1; + + /* Send chip address */ + if (i2c_send_data(chip << 1 | 0, TWI_STAT_TX_AW_ACK) != 0) + return -1; + + /* Send data address */ + if (i2c_send_data(addr, TWI_STAT_TXD_ACK) != 0) + return -1; + + /* Send data */ + while (len > 0) { + if (i2c_send_data(*buffer++, TWI_STAT_TXD_ACK) != 0) + return -1; + len--; + } + + return 0; +} + +int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +{ + int rc = i2c_do_write(chip, addr, alen, buffer, len); + + i2c_stop(); + + return rc; +} diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index fe41b89..1f2bcb5 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -176,6 +176,14 @@ #undef CONFIG_CMD_NET #undef CONFIG_CMD_NFS
+/* I2C */ +#define CONFIG_SPL_I2C_SUPPORT +#define CONFIG_SYS_I2C_SPEED 400000 +#define CONFIG_HARD_I2C +#define CONFIG_SUNXI_I2C +#define CONFIG_SYS_I2C_SLAVE 0x7f +#define CONFIG_CMD_I2C + #ifndef CONFIG_CONS_INDEX #define CONFIG_CONS_INDEX 1 /* UART0 */ #endif

Hello Hans,
Am 18.03.2014 00:00, schrieb Hans de Goede:
From: Henrik Nordstromhenrik@henriknordstrom.net
Based linux-sunxi#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01.
As well as the following signed-off-by the sunxi branch shows commits to the sunxi_i2c.c file by:
Stefan Roesesr@denx.de
Signed-off-by: Henrik Nordstromhenrik@henriknordstrom.net Signed-off-by: Oliver Schinagloliver@schinagl.nl Signed-off-by: Hans de Goedehdegoede@redhat.com
arch/arm/cpu/armv7/sunxi/board.c | 6 + arch/arm/include/asm/arch-sunxi/i2c.h | 169 ++++++++++++++++++++++ drivers/i2c/Makefile | 1 + drivers/i2c/sunxi_i2c.c | 260 ++++++++++++++++++++++++++++++++++ include/configs/sunxi-common.h | 8 ++ 5 files changed, 444 insertions(+) create mode 100644 arch/arm/include/asm/arch-sunxi/i2c.h create mode 100644 drivers/i2c/sunxi_i2c.c
[...]
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index fa3a875..2a44db4 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o obj-$(CONFIG_U8500_I2C) += u8500_i2c.o obj-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o +obj-$(CONFIG_SUNXI_I2C) += sunxi_i2c.o
please use:
CONFIG_SYS_I2C_SUNXI
obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o diff --git a/drivers/i2c/sunxi_i2c.c b/drivers/i2c/sunxi_i2c.c new file mode 100644 index 0000000..9a542f6 --- /dev/null +++ b/drivers/i2c/sunxi_i2c.c @@ -0,0 +1,260 @@ +/*
- (C) Copyright 2012 Henrik Nordstromhenrik@henriknordstrom.net
- SPDX-License-Identifier: GPL-2.0+
- */
+#include<common.h> +#include<i2c.h> +#include<asm/io.h> +#include<asm/arch/clock.h> +#include<asm/arch/cpu.h> +#include<asm/arch/gpio.h> +#include<asm/arch/i2c.h>
+static struct i2c __attribute__ ((section(".data"))) *i2c_base =
- (struct i2c *)0x1c2ac00;
Please no magic numbers, use a define instead.
+void i2c_init(int speed, int slaveaddr)
[...]
+int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +{
- int rc = i2c_do_write(chip, addr, alen, buffer, len);
- i2c_stop();
- return rc;
+}
Please update to the new i2c multibus/multiadpater framework
Dummy question, there is another "twi" driver in drivers/i2c
bfin-twi_i2c.c
are they compatible?
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index fe41b89..1f2bcb5 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -176,6 +176,14 @@ #undef CONFIG_CMD_NET #undef CONFIG_CMD_NFS
+/* I2C */ +#define CONFIG_SPL_I2C_SUPPORT +#define CONFIG_SYS_I2C_SPEED 400000 +#define CONFIG_HARD_I2C
NACK, please use no longer HARD_I2C, switch instead to CONFIG_SYS_I2C
+#define CONFIG_SUNXI_I2C +#define CONFIG_SYS_I2C_SLAVE 0x7f +#define CONFIG_CMD_I2C
- #ifndef CONFIG_CONS_INDEX #define CONFIG_CONS_INDEX 1 /* UART0 */ #endif
bye, Heiko

Hi,
On 03/18/2014 08:54 AM, Heiko Schocher wrote:
Hello Hans,
Am 18.03.2014 00:00, schrieb Hans de Goede:
From: Henrik Nordstromhenrik@henriknordstrom.net
Based linux-sunxi#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01.
As well as the following signed-off-by the sunxi branch shows commits to the sunxi_i2c.c file by:
Stefan Roesesr@denx.de
Signed-off-by: Henrik Nordstromhenrik@henriknordstrom.net Signed-off-by: Oliver Schinagloliver@schinagl.nl Signed-off-by: Hans de Goedehdegoede@redhat.com
arch/arm/cpu/armv7/sunxi/board.c | 6 + arch/arm/include/asm/arch-sunxi/i2c.h | 169 ++++++++++++++++++++++ drivers/i2c/Makefile | 1 + drivers/i2c/sunxi_i2c.c | 260 ++++++++++++++++++++++++++++++++++ include/configs/sunxi-common.h | 8 ++ 5 files changed, 444 insertions(+) create mode 100644 arch/arm/include/asm/arch-sunxi/i2c.h create mode 100644 drivers/i2c/sunxi_i2c.c
[...]
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index fa3a875..2a44db4 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o obj-$(CONFIG_U8500_I2C) += u8500_i2c.o obj-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o +obj-$(CONFIG_SUNXI_I2C) += sunxi_i2c.o
please use:
CONFIG_SYS_I2C_SUNXI
Ok.
obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o diff --git a/drivers/i2c/sunxi_i2c.c b/drivers/i2c/sunxi_i2c.c new file mode 100644 index 0000000..9a542f6 --- /dev/null +++ b/drivers/i2c/sunxi_i2c.c @@ -0,0 +1,260 @@ +/*
- (C) Copyright 2012 Henrik Nordstromhenrik@henriknordstrom.net
- SPDX-License-Identifier: GPL-2.0+
- */
+#include<common.h> +#include<i2c.h> +#include<asm/io.h> +#include<asm/arch/clock.h> +#include<asm/arch/cpu.h> +#include<asm/arch/gpio.h> +#include<asm/arch/i2c.h>
+static struct i2c __attribute__ ((section(".data"))) *i2c_base =
- (struct i2c *)0x1c2ac00;
Please no magic numbers, use a define instead.
+void i2c_init(int speed, int slaveaddr)
[...]
+int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +{
- int rc = i2c_do_write(chip, addr, alen, buffer, len);
- i2c_stop();
- return rc;
+}
Please update to the new i2c multibus/multiadpater framework
Dummy question, there is another "twi" driver in drivers/i2c
bfin-twi_i2c.c
are they compatible?
No, but that is a good point, in the kernel we ended up using the i2c-mv64xxx driver as that is the same controller. I should have thought of doing the same for u-boot instead of just taking Allwinner's driver.
I've just completed writing a patch-set which uses the mvtwsi driver instead of introducing a new driver. While working on this I found 2 issues in the driver, for which I'll be sending patches shortly.
Regards,
Hans

From: Henrik Nordstrom henrik@henriknordstrom.net
Based linux-sunxi#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01.
As well as the following signed-off-by the sunxi branch shows commits to the axp209.c file by:
Stefan Roese sr@denx.de
Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Hans de Goede hdegoede@redhat.com --- board/sunxi/board.c | 26 ++++++ boards.cfg | 6 +- drivers/power/Makefile | 1 + drivers/power/axp209.c | 199 +++++++++++++++++++++++++++++++++++++++++ include/axp209.h | 15 ++++ include/configs/sunxi-common.h | 5 ++ 6 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 drivers/power/axp209.c create mode 100644 include/axp209.h
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 06c9264..4b1a154 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -12,6 +12,9 @@ */
#include <common.h> +#ifdef CONFIG_AXP209_POWER +#include <axp209.h> +#endif #include <asm/arch/clock.h> #include <asm/arch/dram.h> #include <asm/arch/mmc.h> @@ -59,6 +62,7 @@ int board_mmc_init(bd_t *bis) #ifdef CONFIG_SPL_BUILD void sunxi_board_init(void) { + int power_failed = 0; unsigned long ramsize;
printf("DRAM:"); @@ -66,5 +70,27 @@ void sunxi_board_init(void) printf(" %lu MiB\n", ramsize >> 20); if (!ramsize) hang(); + +#ifdef CONFIG_AXP209_POWER + power_failed |= axp209_init(); + power_failed |= axp209_set_dcdc2(1400); + power_failed |= axp209_set_dcdc3(1250); + power_failed |= axp209_set_ldo2(3000); + power_failed |= axp209_set_ldo3(2800); + power_failed |= axp209_set_ldo4(2800); +#endif + + /* + * Only clock up the CPU to full speed if we are reasonably + * assured it's being powered with suitable core voltage + */ + if (!power_failed) +#ifdef CONFIG_SUN7I + clock_set_pll1(912000000); +#else + clock_set_pll1(1008000000); +#endif + else + printf("Failed to set core voltage! Can't set CPU frequency\n"); } #endif diff --git a/boards.cfg b/boards.cfg index bae0797..21395dd 100644 --- a/boards.cfg +++ b/boards.cfg @@ -353,10 +353,10 @@ Active arm armv7 rmobile renesas koelsch 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 A10-OLinuXino-Lime sun4i:A10_OLINUXINO_L,SPL - +Active arm armv7 sunxi - sunxi A10-OLinuXino-Lime sun4i:A10_OLINUXINO_L,AXP209_POWER,SPL - Active arm armv7 sunxi - sunxi A10s-OLinuXino-M sun5i:A10S_OLINUXINO_M,SPL - -Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,SPL - -Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL - +Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,AXP209_POWER,SPL - +Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,AXP209_POWER,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 diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 53ff97d..063ac8f 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -5,6 +5,7 @@ # SPDX-License-Identifier: GPL-2.0+ #
+obj-$(CONFIG_AXP209_POWER) += axp209.o obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o obj-$(CONFIG_FTPMU010_POWER) += ftpmu010.o obj-$(CONFIG_TPS6586X_POWER) += tps6586x.o diff --git a/drivers/power/axp209.c b/drivers/power/axp209.c new file mode 100644 index 0000000..799e6b0 --- /dev/null +++ b/drivers/power/axp209.c @@ -0,0 +1,199 @@ +/* + * (C) Copyright 2012 + * Henrik Nordstrom henrik@henriknordstrom.net + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <i2c.h> +#include <axp209.h> + +enum axp209_reg { + AXP209_POWER_STATUS = 0x00, + AXP209_CHIP_VERSION = 0x03, + AXP209_DCDC2_VOLTAGE = 0x23, + AXP209_DCDC3_VOLTAGE = 0x27, + AXP209_LDO24_VOLTAGE = 0x28, + AXP209_LDO3_VOLTAGE = 0x29, + AXP209_IRQ_STATUS3 = 0x4a, + AXP209_IRQ_STATUS5 = 0x4c, + AXP209_SHUTDOWN = 0x32, +}; + +#define AXP209_POWER_STATUS_ON_BY_DC (1<<0) + +#define AXP209_IRQ3_PEK_SHORT (1<<1) +#define AXP209_IRQ3_PEK_LONG (1<<0) + +#define AXP209_IRQ5_PEK_UP (1<<6) +#define AXP209_IRQ5_PEK_DOWN (1<<5) + +int axp209_write(enum axp209_reg reg, u8 val) +{ + return i2c_write(0x34, reg, 1, &val, 1); +} + +int axp209_read(enum axp209_reg reg, u8 *val) +{ + return i2c_read(0x34, reg, 1, val, 1); +} + +int axp209_set_dcdc2(int mvolt) +{ + int cfg = (mvolt - 700) / 25; + int rc; + u8 current; + + if (cfg < 0) + cfg = 0; + if (cfg > (1 << 6) - 1) + cfg = (1 << 6) - 1; + + /* Do we really need to be this gentle? It has built-in voltage slope */ + while ((rc = axp209_read(AXP209_DCDC2_VOLTAGE, ¤t)) == 0 && + current != cfg) { + if (current < cfg) + current++; + else + current--; + + rc = axp209_write(AXP209_DCDC2_VOLTAGE, current); + if (rc) + break; + } + + return rc; +} + +int axp209_set_dcdc3(int mvolt) +{ + int cfg = (mvolt - 700) / 25; + u8 reg; + int rc; + + if (cfg < 0) + cfg = 0; + if (cfg > (1 << 7) - 1) + cfg = (1 << 7) - 1; + + rc = axp209_write(AXP209_DCDC3_VOLTAGE, cfg); + rc |= axp209_read(AXP209_DCDC3_VOLTAGE, ®); + + return rc; +} + +int axp209_set_ldo2(int mvolt) +{ + int cfg = (mvolt - 1800) / 100; + int rc; + u8 reg; + + if (cfg < 0) + cfg = 0; + if (cfg > 15) + cfg = 15; + + rc = axp209_read(AXP209_LDO24_VOLTAGE, ®); + if (rc) + return rc; + + reg = (reg & 0x0f) | (cfg << 4); + rc = axp209_write(AXP209_LDO24_VOLTAGE, reg); + if (rc) + return rc; + + return 0; +} + +int axp209_set_ldo3(int mvolt) +{ + int cfg = (mvolt - 700) / 25; + + if (cfg < 0) + cfg = 0; + if (cfg > 127) + cfg = 127; + if (mvolt == -1) + cfg = 0x80; /* detemined by LDO3IN pin */ + + return axp209_write(AXP209_LDO3_VOLTAGE, cfg); +} + +int axp209_set_ldo4(int mvolt) +{ + int cfg = (mvolt - 1800) / 100; + int rc; + static const int vindex[] = { + 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500, + 2700, 2800, 3000, 3100, 3200, 3300 + }; + u8 reg; + + /* Translate mvolt to register cfg value, requested <= selected */ + for (cfg = 0; mvolt < vindex[cfg] && cfg < 15; cfg++); + + rc = axp209_read(AXP209_LDO24_VOLTAGE, ®); + if (rc) + return rc; + + /* LDO4 configuration is in lower 4 bits */ + reg = (reg & 0xf0) | (cfg << 0); + rc = axp209_write(AXP209_LDO24_VOLTAGE, reg); + if (rc) + return rc; + + return 0; +} + +void axp209_poweroff(void) +{ + u8 val; + + if (axp209_read(AXP209_SHUTDOWN, &val) != 0) + return; + + val |= 1 << 7; + + if (axp209_write(AXP209_SHUTDOWN, val) != 0) + return; + + udelay(10000); /* wait for power to drain */ +} + +int axp209_init(void) +{ + u8 ver; + int rc; + + rc = axp209_read(AXP209_CHIP_VERSION, &ver); + if (rc) + return rc; + + /* Low 4 bits is chip version */ + ver &= 0x0f; + + if (ver != 0x1) + return -1; + + return 0; +} + +int axp209_poweron_by_dc(void) +{ + u8 v; + + if (axp209_read(AXP209_POWER_STATUS, &v)) + return 0; + return (v & AXP209_POWER_STATUS_ON_BY_DC); +} + +int axp209_power_button(void) +{ + u8 v; + + if (axp209_read(AXP209_IRQ_STATUS5, &v)) + return 0; + axp209_write(AXP209_IRQ_STATUS5, AXP209_IRQ5_PEK_DOWN); + return v & AXP209_IRQ5_PEK_DOWN; +} diff --git a/include/axp209.h b/include/axp209.h new file mode 100644 index 0000000..9edfa3f --- /dev/null +++ b/include/axp209.h @@ -0,0 +1,15 @@ +/* + * (C) Copyright 2012 Henrik Nordstrom henrik@henriknordstrom.net + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +extern int axp209_set_dcdc2(int mvolt); +extern int axp209_set_dcdc3(int mvolt); +extern int axp209_set_ldo2(int mvolt); +extern int axp209_set_ldo3(int mvolt); +extern int axp209_set_ldo4(int mvolt); +extern void axp209_poweroff(void); +extern int axp209_init(void); +extern int axp209_poweron_by_dc(void); +extern int axp209_power_button(void); diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 1f2bcb5..027a1ec 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -184,6 +184,11 @@ #define CONFIG_SYS_I2C_SLAVE 0x7f #define CONFIG_CMD_I2C
+/* PMU */ +#if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER +#define CONFIG_SPL_POWER_SUPPORT +#endif + #ifndef CONFIG_CONS_INDEX #define CONFIG_CONS_INDEX 1 /* UART0 */ #endif

Based linux-sunxi#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in ldscripts" vs v2014.01.
As well as the following signed-off-by the sunxi branch shows commits to the axp152.c file by:
Stefan Roese sr@denx.de Simon "theRat"
Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Ian Campbell ijc@hellion.org.uk --- board/sunxi/board.c | 10 ++++ boards.cfg | 2 +- drivers/power/Makefile | 1 + drivers/power/axp152.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ include/axp152.h | 11 +++++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 drivers/power/axp152.c create mode 100644 include/axp152.h
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 4b1a154..e9801b9 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -12,6 +12,9 @@ */
#include <common.h> +#ifdef CONFIG_AXP152_POWER +#include <axp152.h> +#endif #ifdef CONFIG_AXP209_POWER #include <axp209.h> #endif @@ -71,6 +74,13 @@ void sunxi_board_init(void) if (!ramsize) hang();
+#ifdef CONFIG_AXP152_POWER + power_failed = axp152_init(); + power_failed |= axp152_set_dcdc2(1400); + power_failed |= axp152_set_dcdc3(1500); + power_failed |= axp152_set_dcdc4(1250); + power_failed |= axp152_set_ldo2(3000); +#endif #ifdef CONFIG_AXP209_POWER power_failed |= axp209_init(); power_failed |= axp209_set_dcdc2(1400); diff --git a/boards.cfg b/boards.cfg index 21395dd..20f7510 100644 --- a/boards.cfg +++ b/boards.cfg @@ -354,7 +354,7 @@ Active arm armv7 s5pc1xx samsung goni 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 A10-OLinuXino-Lime sun4i:A10_OLINUXINO_L,AXP209_POWER,SPL - -Active arm armv7 sunxi - sunxi A10s-OLinuXino-M sun5i:A10S_OLINUXINO_M,SPL - +Active arm armv7 sunxi - sunxi A10s-OLinuXino-M sun5i:A10S_OLINUXINO_M,AXP152_POWER,SPL - Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,AXP209_POWER,SPL - Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,AXP209_POWER,SPL_FEL - Active arm armv7 u8500 st-ericsson snowball snowball - Mathieu Poirier mathieu.poirier@linaro.org diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 063ac8f..dc64e4d 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -5,6 +5,7 @@ # SPDX-License-Identifier: GPL-2.0+ #
+obj-$(CONFIG_AXP152_POWER) += axp152.o obj-$(CONFIG_AXP209_POWER) += axp209.o obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o obj-$(CONFIG_FTPMU010_POWER) += ftpmu010.o diff --git a/drivers/power/axp152.c b/drivers/power/axp152.c new file mode 100644 index 0000000..a7a7909 --- /dev/null +++ b/drivers/power/axp152.c @@ -0,0 +1,122 @@ +/* + * (C) Copyright 2012 + * Henrik Nordstrom henrik@henriknordstrom.net + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <i2c.h> +#include <axp152.h> + +enum axp152_reg { + AXP152_CHIP_VERSION = 0x3, + AXP152_DCDC2_VOLTAGE = 0x23, + AXP152_DCDC3_VOLTAGE = 0x27, + AXP152_DCDC4_VOLTAGE = 0x2B, + AXP152_LDO2_VOLTAGE = 0x2A, + AXP152_SHUTDOWN = 0x32, +}; + +int axp152_write(enum axp152_reg reg, u8 val) +{ + return i2c_write(0x30, reg, 1, &val, 1); +} + +int axp152_read(enum axp152_reg reg, u8 *val) +{ + return i2c_read(0x30, reg, 1, val, 1); +} + +int axp152_set_dcdc2(int mvolt) +{ + int target = (mvolt - 700) / 25; + int rc; + u8 current; + + if (target < 0) + target = 0; + if (target > (1<<6)-1) + target = (1<<6)-1; + /* Do we really need to be this gentle? It has built-in voltage slope */ + while ((rc = axp152_read(AXP152_DCDC2_VOLTAGE, ¤t)) == 0 && + current != target) { + if (current < target) + current++; + else + current--; + rc = axp152_write(AXP152_DCDC2_VOLTAGE, current); + if (rc) + break; + } + return rc; +} + +int axp152_set_dcdc3(int mvolt) +{ + int target = (mvolt - 700) / 50; + u8 reg; + int rc; + + if (target < 0) + target = 0; + if (target > (1<<6)-1) + target = (1<<6)-1; + rc = axp152_write(AXP152_DCDC3_VOLTAGE, target); + rc |= axp152_read(AXP152_DCDC3_VOLTAGE, ®); + return rc; +} + +int axp152_set_dcdc4(int mvolt) +{ + int target = (mvolt - 700) / 25; + u8 reg; + int rc; + + if (target < 0) + target = 0; + if (target > (1<<7)-1) + target = (1<<7)-1; + rc = axp152_write(AXP152_DCDC4_VOLTAGE, target); + rc |= axp152_read(AXP152_DCDC4_VOLTAGE, ®); + return rc; +} + +int axp152_set_ldo2(int mvolt) +{ + int target = (mvolt - 700) / 100; + int rc; + u8 reg; + + if (target < 0) + target = 0; + if (target > 31) + target = 31; + rc = axp152_write(AXP152_LDO2_VOLTAGE, target); + rc |= axp152_read(AXP152_LDO2_VOLTAGE, ®); + return rc; +} + +void axp152_poweroff(void) +{ + u8 val; + + if (axp152_read(AXP152_SHUTDOWN, &val) != 0) + return; + val |= 1 << 7; + if (axp152_write(AXP152_SHUTDOWN, val) != 0) + return; + udelay(10000); /* wait for power to drain */ +} + +int axp152_init(void) +{ + u8 ver; + int rc; + + rc = axp152_read(AXP152_CHIP_VERSION, &ver); + if (rc) + return rc; + if (ver != 0x05) + return -1; + return 0; +} diff --git a/include/axp152.h b/include/axp152.h new file mode 100644 index 0000000..b34c194 --- /dev/null +++ b/include/axp152.h @@ -0,0 +1,11 @@ +/* + * (C) Copyright 2012 Henrik Nordstrom henrik@henriknordstrom.net + * + * SPDX-License-Identifier: GPL-2.0+ + */ +int axp152_set_dcdc2(int mvolt); +int axp152_set_dcdc3(int mvolt); +int axp152_set_dcdc4(int mvolt); +int axp152_set_ldo2(int mvolt); +void axp152_poweroff(void); +int axp152_init(void);

From: Emilio López emilio@elopez.com.ar
For qualifying hardware, we can run MBUS at 400MHz without risking stability if we raise the DCDC3 voltage to 1.3V .
This is desirable since on A20 the MBUS is a significant bottle-neck for some workloads.
This has been tested on 50 pieces of Cubieboard2 by Cubietech and no issues of any kind were reported.
Signed-off-by: Emilio López emilio@elopez.com.ar Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/dram.c | 6 +++++- board/sunxi/board.c | 4 ++++ boards.cfg | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 781f9b5..9061f98 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -217,7 +217,11 @@ static void mctl_setup_dram_clock(u32 clk)
/* setup MBUS clock */ reg_val = CCM_MBUS_CTRL_GATE | -#if defined(CONFIG_SUN7I) +#if defined(CONFIG_SUN7I) && defined(CONFIG_FAST_MBUS) + CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL6) | + CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(1)) | + CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(3)); +#elif defined(CONFIG_SUN7I) && !defined(CONFIG_FAST_MBUS) 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)); diff --git a/board/sunxi/board.c b/board/sunxi/board.c index e9801b9..4dadf2b 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -84,7 +84,11 @@ void sunxi_board_init(void) #ifdef CONFIG_AXP209_POWER power_failed |= axp209_init(); power_failed |= axp209_set_dcdc2(1400); +#ifdef CONFIG_FAST_MBUS + power_failed |= axp209_set_dcdc3(1300); +#else power_failed |= axp209_set_dcdc3(1250); +#endif power_failed |= axp209_set_ldo2(3000); power_failed |= axp209_set_ldo3(2800); power_failed |= axp209_set_ldo4(2800); diff --git a/boards.cfg b/boards.cfg index 20f7510..82d2c6a 100644 --- a/boards.cfg +++ b/boards.cfg @@ -355,8 +355,8 @@ Active arm armv7 s5pc1xx samsung smdkc100 Active arm armv7 socfpga altera socfpga socfpga_cyclone5 - - Active arm armv7 sunxi - sunxi A10-OLinuXino-Lime sun4i:A10_OLINUXINO_L,AXP209_POWER,SPL - Active arm armv7 sunxi - sunxi A10s-OLinuXino-M sun5i:A10S_OLINUXINO_M,AXP152_POWER,SPL - -Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,AXP209_POWER,SPL - -Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,AXP209_POWER,SPL_FEL - +Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,AXP209_POWER,FAST_MBUS,SPL - +Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,AXP209_POWER,FAST_MBUS,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

From: Stefan Roese sr@denx.de
There have been 3 versions of the sunxi_emac support patch during its development. Somehow version 2 ended up in upstream u-boot where as the u-boot-sunxi git repo got version 3.
This bumps the version in upstream u-boot to version 3 of the patch: - Initialize MII clock earlier so mii access to allow independent use - Name change from WEMAC to EMAC to match mainline kernel & chip manual - Cosmetic code cleanup
Signed-off-by: Stefan Roese sr@denx.de Signed-off-by: Henrik Nordstrom henrik@henriknordstrom.net Signed-off-by: Oliver Schinagl oliver@schinagl.nl Signed-off-by: Hans de Goede hdegoede@redhat.com --- drivers/net/Makefile | 2 +- drivers/net/sunxi_emac.c | 521 +++++++++++++++++++++++++++++++++++++++++++++ drivers/net/sunxi_wemac.c | 525 ---------------------------------------------- include/netdev.h | 2 +- 4 files changed, 523 insertions(+), 527 deletions(-) create mode 100644 drivers/net/sunxi_emac.c delete mode 100644 drivers/net/sunxi_wemac.c
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 7f9ce90..d905fef 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,7 +50,7 @@ obj-$(CONFIG_RTL8169) += rtl8169.o 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_EMAC) += sunxi_emac.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_emac.c b/drivers/net/sunxi_emac.c new file mode 100644 index 0000000..5a06d68 --- /dev/null +++ b/drivers/net/sunxi_emac.c @@ -0,0 +1,521 @@ +/* + * sunxi_emac.c -- Allwinner A10 ethernet driver + * + * (C) Copyright 2012, Stefan Roese sr@denx.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <linux/err.h> +#include <malloc.h> +#include <miiphy.h> +#include <net.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/gpio.h> + +/* EMAC register */ +struct emac_regs { + u32 ctl; /* 0x00 */ + u32 tx_mode; /* 0x04 */ + u32 tx_flow; /* 0x08 */ + u32 tx_ctl0; /* 0x0c */ + u32 tx_ctl1; /* 0x10 */ + u32 tx_ins; /* 0x14 */ + u32 tx_pl0; /* 0x18 */ + u32 tx_pl1; /* 0x1c */ + u32 tx_sta; /* 0x20 */ + u32 tx_io_data; /* 0x24 */ + u32 tx_io_data1;/* 0x28 */ + u32 tx_tsvl0; /* 0x2c */ + u32 tx_tsvh0; /* 0x30 */ + u32 tx_tsvl1; /* 0x34 */ + u32 tx_tsvh1; /* 0x38 */ + u32 rx_ctl; /* 0x3c */ + u32 rx_hash0; /* 0x40 */ + u32 rx_hash1; /* 0x44 */ + u32 rx_sta; /* 0x48 */ + u32 rx_io_data; /* 0x4c */ + u32 rx_fbc; /* 0x50 */ + u32 int_ctl; /* 0x54 */ + u32 int_sta; /* 0x58 */ + u32 mac_ctl0; /* 0x5c */ + u32 mac_ctl1; /* 0x60 */ + u32 mac_ipgt; /* 0x64 */ + u32 mac_ipgr; /* 0x68 */ + u32 mac_clrt; /* 0x6c */ + u32 mac_maxf; /* 0x70 */ + u32 mac_supp; /* 0x74 */ + u32 mac_test; /* 0x78 */ + u32 mac_mcfg; /* 0x7c */ + u32 mac_mcmd; /* 0x80 */ + u32 mac_madr; /* 0x84 */ + u32 mac_mwtd; /* 0x88 */ + u32 mac_mrdd; /* 0x8c */ + u32 mac_mind; /* 0x90 */ + u32 mac_ssrr; /* 0x94 */ + u32 mac_a0; /* 0x98 */ + u32 mac_a1; /* 0x9c */ +}; + +/* SRAMC register */ +struct sunxi_sramc_regs { + u32 ctrl0; + u32 ctrl1; +}; + +/* 0: Disable 1: Aborted frame enable(default) */ +#define EMAC_TX_AB_M (0x1 << 0) +/* 0: CPU 1: DMA(default) */ +#define EMAC_TX_TM (0x1 << 1) + +#define EMAC_TX_SETUP (0) + +/* 0: DRQ asserted 1: DRQ automatically(default) */ +#define EMAC_RX_DRQ_MODE (0x1 << 1) +/* 0: CPU 1: DMA(default) */ +#define EMAC_RX_TM (0x1 << 2) +/* 0: Normal(default) 1: Pass all Frames */ +#define EMAC_RX_PA (0x1 << 4) +/* 0: Normal(default) 1: Pass Control Frames */ +#define EMAC_RX_PCF (0x1 << 5) +/* 0: Normal(default) 1: Pass Frames with CRC Error */ +#define EMAC_RX_PCRCE (0x1 << 6) +/* 0: Normal(default) 1: Pass Frames with Length Error */ +#define EMAC_RX_PLE (0x1 << 7) +/* 0: Normal 1: Pass Frames length out of range(default) */ +#define EMAC_RX_POR (0x1 << 8) +/* 0: Not accept 1: Accept unicast Packets(default) */ +#define EMAC_RX_UCAD (0x1 << 16) +/* 0: Normal(default) 1: DA Filtering */ +#define EMAC_RX_DAF (0x1 << 17) +/* 0: Not accept 1: Accept multicast Packets(default) */ +#define EMAC_RX_MCO (0x1 << 20) +/* 0: Disable(default) 1: Enable Hash filter */ +#define EMAC_RX_MHF (0x1 << 21) +/* 0: Not accept 1: Accept Broadcast Packets(default) */ +#define EMAC_RX_BCO (0x1 << 22) +/* 0: Disable(default) 1: Enable SA Filtering */ +#define EMAC_RX_SAF (0x1 << 24) +/* 0: Normal(default) 1: Inverse Filtering */ +#define EMAC_RX_SAIF (0x1 << 25) + +#define EMAC_RX_SETUP (EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \ + EMAC_RX_MCO | EMAC_RX_BCO) + +/* 0: Disable 1: Enable Receive Flow Control(default) */ +#define EMAC_MAC_CTL0_RFC (0x1 << 2) +/* 0: Disable 1: Enable Transmit Flow Control(default) */ +#define EMAC_MAC_CTL0_TFC (0x1 << 3) + +#define EMAC_MAC_CTL0_SETUP (EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC) + +/* 0: Disable 1: Enable MAC Frame Length Checking(default) */ +#define EMAC_MAC_CTL1_FLC (0x1 << 1) +/* 0: Disable(default) 1: Enable Huge Frame */ +#define EMAC_MAC_CTL1_HF (0x1 << 2) +/* 0: Disable(default) 1: Enable MAC Delayed CRC */ +#define EMAC_MAC_CTL1_DCRC (0x1 << 3) +/* 0: Disable 1: Enable MAC CRC(default) */ +#define EMAC_MAC_CTL1_CRC (0x1 << 4) +/* 0: Disable 1: Enable MAC PAD Short frames(default) */ +#define EMAC_MAC_CTL1_PC (0x1 << 5) +/* 0: Disable(default) 1: Enable MAC PAD Short frames and append CRC */ +#define EMAC_MAC_CTL1_VC (0x1 << 6) +/* 0: Disable(default) 1: Enable MAC auto detect Short frames */ +#define EMAC_MAC_CTL1_ADP (0x1 << 7) +/* 0: Disable(default) 1: Enable */ +#define EMAC_MAC_CTL1_PRE (0x1 << 8) +/* 0: Disable(default) 1: Enable */ +#define EMAC_MAC_CTL1_LPE (0x1 << 9) +/* 0: Disable(default) 1: Enable no back off */ +#define EMAC_MAC_CTL1_NB (0x1 << 12) +/* 0: Disable(default) 1: Enable */ +#define EMAC_MAC_CTL1_BNB (0x1 << 13) +/* 0: Disable(default) 1: Enable */ +#define EMAC_MAC_CTL1_ED (0x1 << 14) + +#define EMAC_MAC_CTL1_SETUP (EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \ + EMAC_MAC_CTL1_PC) + +#define EMAC_MAC_IPGT 0x15 + +#define EMAC_MAC_NBTB_IPG1 0xc +#define EMAC_MAC_NBTB_IPG2 0x12 + +#define EMAC_MAC_CW 0x37 +#define EMAC_MAC_RM 0xf + +#define EMAC_MAC_MFL 0x0600 + +/* Receive status */ +#define EMAC_CRCERR (0x1 << 4) +#define EMAC_LENERR (0x3 << 5) + +#define DMA_CPU_TRRESHOLD 2000 + +struct emac_eth_dev { + u32 speed; + u32 duplex; + u32 phy_configured; + int link_printed; +}; + +struct emac_rxhdr { + s16 rx_len; + u16 rx_status; +}; + +static void emac_inblk_32bit(void *reg, void *data, int count) +{ + int cnt = (count + 3) >> 2; + + if (cnt) { + u32 *buf = data; + + do { + u32 x = readl(reg); + *buf++ = x; + } while (--cnt); + } +} + +static void emac_outblk_32bit(void *reg, void *data, int count) +{ + int cnt = (count + 3) >> 2; + + if (cnt) { + const u32 *buf = data; + + do { + writel(*buf++, reg); + } while (--cnt); + } +} + +/* Read a word from phyxcer */ +static int emac_phy_read(const char *devname, unsigned char addr, + unsigned char reg, unsigned short *value) +{ + struct eth_device *dev = eth_get_dev_by_name(devname); + struct emac_regs *regs = (struct emac_regs *)dev->iobase; + + /* issue the phy address and reg */ + writel(addr << 8 | reg, ®s->mac_madr); + + /* pull up the phy io line */ + writel(0x1, ®s->mac_mcmd); + + /* Wait read complete */ + mdelay(1); + + /* push down the phy io line */ + writel(0x0, ®s->mac_mcmd); + + /* and write data */ + *value = readl(®s->mac_mrdd); + + return 0; +} + +/* Write a word to phyxcer */ +static int emac_phy_write(const char *devname, unsigned char addr, + unsigned char reg, unsigned short value) +{ + struct eth_device *dev = eth_get_dev_by_name(devname); + struct emac_regs *regs = (struct emac_regs *)dev->iobase; + + /* issue the phy address and reg */ + writel(addr << 8 | reg, ®s->mac_madr); + + /* pull up the phy io line */ + writel(0x1, ®s->mac_mcmd); + + /* Wait write complete */ + mdelay(1); + + /* push down the phy io line */ + writel(0x0, ®s->mac_mcmd); + + /* and write data */ + writel(value, ®s->mac_mwtd); + + return 0; +} + +static void emac_setup(struct eth_device *dev) +{ + struct emac_regs *regs = (struct emac_regs *)dev->iobase; + u32 reg_val; + u16 phy_val; + u32 duplex_flag; + + /* Set up TX */ + writel(EMAC_TX_SETUP, ®s->tx_mode); + + /* Set up RX */ + writel(EMAC_RX_SETUP, ®s->rx_ctl); + + /* Set MAC */ + /* Set MAC CTL0 */ + writel(EMAC_MAC_CTL0_SETUP, ®s->mac_ctl0); + + /* Set MAC CTL1 */ + emac_phy_read(dev->name, 1, 0, &phy_val); + debug("PHY SETUP, reg 0 value: %x\n", phy_val); + duplex_flag = !!(phy_val & (1 << 8)); + + reg_val = 0; + if (duplex_flag) + reg_val = (0x1 << 0); + writel(EMAC_MAC_CTL1_SETUP | reg_val, ®s->mac_ctl1); + + /* Set up IPGT */ + writel(EMAC_MAC_IPGT, ®s->mac_ipgt); + + /* Set up IPGR */ + writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), ®s->mac_ipgr); + + /* Set up Collison window */ + writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), ®s->mac_clrt); + + /* Set up Max Frame Length */ + writel(EMAC_MAC_MFL, ®s->mac_maxf); +} + +static void emac_reset(struct eth_device *dev) +{ + struct emac_regs *regs = (struct emac_regs *)dev->iobase; + + debug("resetting device\n"); + + /* RESET device */ + writel(0, ®s->ctl); + udelay(200); + + writel(1, ®s->ctl); + udelay(200); +} + +static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd) +{ + struct emac_regs *regs = (struct emac_regs *)dev->iobase; + struct emac_eth_dev *priv = dev->priv; + u16 phy_reg; + + /* Init EMAC */ + + /* Flush RX FIFO */ + setbits_le32(®s->rx_ctl, 0x8); + udelay(1); + + /* Init MAC */ + + /* Soft reset MAC */ + clrbits_le32(®s->mac_ctl0, 0x1 << 15); + + /* Clear RX counter */ + writel(0x0, ®s->rx_fbc); + udelay(1); + + /* Set up EMAC */ + emac_setup(dev); + + writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 | + dev->enetaddr[2], ®s->mac_a1); + writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 | + dev->enetaddr[5], ®s->mac_a0); + + mdelay(1); + + emac_reset(dev); + + /* PHY POWER UP */ + emac_phy_read(dev->name, 1, 0, &phy_reg); + emac_phy_write(dev->name, 1, 0, phy_reg & (~(0x1 << 11))); + mdelay(1); + + emac_phy_read(dev->name, 1, 0, &phy_reg); + + priv->speed = miiphy_speed(dev->name, 0); + priv->duplex = miiphy_duplex(dev->name, 0); + + /* Print link status only once */ + if (!priv->link_printed) { + printf("ENET Speed is %d Mbps - %s duplex connection\n", + priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL"); + priv->link_printed = 1; + } + + /* Set EMAC SPEED depend on PHY */ + clrsetbits_le32(®s->mac_supp, 1 << 8, + ((phy_reg & (0x1 << 13)) >> 13) << 8); + + /* Set duplex depend on phy */ + clrsetbits_le32(®s->mac_ctl1, 1 << 0, + ((phy_reg & (0x1 << 8)) >> 8) << 0); + + /* Enable RX/TX */ + setbits_le32(®s->ctl, 0x7); + + return 0; +} + +static void sunxi_emac_eth_halt(struct eth_device *dev) +{ + /* Nothing to do here */ +} + +static int sunxi_emac_eth_recv(struct eth_device *dev) +{ + struct emac_regs *regs = (struct emac_regs *)dev->iobase; + struct emac_rxhdr rxhdr; + u32 rxcount; + u32 reg_val; + int rx_len; + int rx_status; + int good_packet; + + /* Check packet ready or not */ + + /* Race warning: The first packet might arrive with + * the interrupts disabled, but the second will fix + */ + rxcount = readl(®s->rx_fbc); + if (!rxcount) { + /* Had one stuck? */ + rxcount = readl(®s->rx_fbc); + if (!rxcount) + return 0; + } + + reg_val = readl(®s->rx_io_data); + if (reg_val != 0x0143414d) { + /* Disable RX */ + clrbits_le32(®s->ctl, 0x1 << 2); + + /* Flush RX FIFO */ + setbits_le32(®s->rx_ctl, 0x1 << 3); + while (readl(®s->rx_ctl) & (0x1 << 3)) + ; + + /* Enable RX */ + setbits_le32(®s->ctl, 0x1 << 2); + + return 0; + } + + /* A packet ready now + * Get status/length + */ + good_packet = 1; + + emac_inblk_32bit(®s->rx_io_data, &rxhdr, sizeof(rxhdr)); + + rx_len = rxhdr.rx_len; + rx_status = rxhdr.rx_status; + + /* Packet Status check */ + if (rx_len < 0x40) { + good_packet = 0; + debug("RX: Bad Packet (runt)\n"); + } + + /* rx_status is identical to RSR register. */ + if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) { + good_packet = 0; + if (rx_status & EMAC_CRCERR) + printf("crc error\n"); + if (rx_status & EMAC_LENERR) + printf("length error\n"); + } + + /* Move data from EMAC */ + if (good_packet) { + if (rx_len > DMA_CPU_TRRESHOLD) { + printf("Received packet is too big (len=%d)\n", rx_len); + } else { + emac_inblk_32bit((void *)®s->rx_io_data, + NetRxPackets[0], rx_len); + + /* Pass to upper layer */ + NetReceive(NetRxPackets[0], rx_len); + return rx_len; + } + } + + return 0; +} + +static int sunxi_emac_eth_send(struct eth_device *dev, void *packet, int len) +{ + struct emac_regs *regs = (struct emac_regs *)dev->iobase; + + /* Select channel 0 */ + writel(0, ®s->tx_ins); + + /* Write packet */ + emac_outblk_32bit((void *)®s->tx_io_data, packet, len); + + /* Set TX len */ + writel(len, ®s->tx_pl0); + + /* Start translate from fifo to phy */ + setbits_le32(®s->tx_ctl0, 1); + + return 0; +} + +int sunxi_emac_initialize(void) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + struct sunxi_sramc_regs *sram = + (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE; + struct emac_regs *regs = + (struct emac_regs *)SUNXI_EMAC_BASE; + struct eth_device *dev; + struct emac_eth_dev *priv; + int pin; + + dev = malloc(sizeof(*dev)); + if (dev == NULL) + return -ENOMEM; + + priv = (struct emac_eth_dev *)malloc(sizeof(struct emac_eth_dev)); + if (!priv) { + free(dev); + return -ENOMEM; + } + + memset(dev, 0, sizeof(*dev)); + memset(priv, 0, sizeof(struct emac_eth_dev)); + + /* Map SRAM to EMAC */ + setbits_le32(&sram->ctrl1, 0x5 << 2); + + /* Configure pin mux settings for MII Ethernet */ + for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++) + sunxi_gpio_set_cfgpin(pin, SUNXI_GPA0_EMAC); + + /* Set up clock gating */ + setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_EMAC); + + /* Set MII clock */ + clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2); + + dev->iobase = (int)regs; + dev->priv = priv; + dev->init = sunxi_emac_eth_init; + dev->halt = sunxi_emac_eth_halt; + dev->send = sunxi_emac_eth_send; + dev->recv = sunxi_emac_eth_recv; + strcpy(dev->name, "emac"); + + eth_register(dev); + + miiphy_register(dev->name, emac_phy_read, emac_phy_write); + + return 0; +} diff --git a/drivers/net/sunxi_wemac.c b/drivers/net/sunxi_wemac.c deleted file mode 100644 index 699a381..0000000 --- a/drivers/net/sunxi_wemac.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * sunxi_wemac.c -- Allwinner A10 ethernet driver - * - * (C) Copyright 2012, Stefan Roese sr@denx.de - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <malloc.h> -#include <net.h> -#include <miiphy.h> -#include <linux/err.h> -#include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/gpio.h> - -/* EMAC register */ -struct wemac_regs { - u32 ctl; /* 0x00 */ - u32 tx_mode; /* 0x04 */ - u32 tx_flow; /* 0x08 */ - u32 tx_ctl0; /* 0x0c */ - u32 tx_ctl1; /* 0x10 */ - u32 tx_ins; /* 0x14 */ - u32 tx_pl0; /* 0x18 */ - u32 tx_pl1; /* 0x1c */ - u32 tx_sta; /* 0x20 */ - u32 tx_io_data; /* 0x24 */ - u32 tx_io_data1; /* 0x28 */ - u32 tx_tsvl0; /* 0x2c */ - u32 tx_tsvh0; /* 0x30 */ - u32 tx_tsvl1; /* 0x34 */ - u32 tx_tsvh1; /* 0x38 */ - u32 rx_ctl; /* 0x3c */ - u32 rx_hash0; /* 0x40 */ - u32 rx_hash1; /* 0x44 */ - u32 rx_sta; /* 0x48 */ - u32 rx_io_data; /* 0x4c */ - u32 rx_fbc; /* 0x50 */ - u32 int_ctl; /* 0x54 */ - u32 int_sta; /* 0x58 */ - u32 mac_ctl0; /* 0x5c */ - u32 mac_ctl1; /* 0x60 */ - u32 mac_ipgt; /* 0x64 */ - u32 mac_ipgr; /* 0x68 */ - u32 mac_clrt; /* 0x6c */ - u32 mac_maxf; /* 0x70 */ - u32 mac_supp; /* 0x74 */ - u32 mac_test; /* 0x78 */ - u32 mac_mcfg; /* 0x7c */ - u32 mac_mcmd; /* 0x80 */ - u32 mac_madr; /* 0x84 */ - u32 mac_mwtd; /* 0x88 */ - u32 mac_mrdd; /* 0x8c */ - u32 mac_mind; /* 0x90 */ - u32 mac_ssrr; /* 0x94 */ - u32 mac_a0; /* 0x98 */ - u32 mac_a1; /* 0x9c */ -}; - -/* SRAMC register */ -struct sunxi_sramc_regs { - u32 ctrl0; - u32 ctrl1; -}; - -/* 0: Disable 1: Aborted frame enable(default) */ -#define EMAC_TX_AB_M (0x1 << 0) -/* 0: CPU 1: DMA(default) */ -#define EMAC_TX_TM (0x1 << 1) - -#define EMAC_TX_SETUP (0) - -/* 0: DRQ asserted 1: DRQ automatically(default) */ -#define EMAC_RX_DRQ_MODE (0x1 << 1) -/* 0: CPU 1: DMA(default) */ -#define EMAC_RX_TM (0x1 << 2) -/* 0: Normal(default) 1: Pass all Frames */ -#define EMAC_RX_PA (0x1 << 4) -/* 0: Normal(default) 1: Pass Control Frames */ -#define EMAC_RX_PCF (0x1 << 5) -/* 0: Normal(default) 1: Pass Frames with CRC Error */ -#define EMAC_RX_PCRCE (0x1 << 6) -/* 0: Normal(default) 1: Pass Frames with Length Error */ -#define EMAC_RX_PLE (0x1 << 7) -/* 0: Normal 1: Pass Frames length out of range(default) */ -#define EMAC_RX_POR (0x1 << 8) -/* 0: Not accept 1: Accept unicast Packets(default) */ -#define EMAC_RX_UCAD (0x1 << 16) -/* 0: Normal(default) 1: DA Filtering */ -#define EMAC_RX_DAF (0x1 << 17) -/* 0: Not accept 1: Accept multicast Packets(default) */ -#define EMAC_RX_MCO (0x1 << 20) -/* 0: Disable(default) 1: Enable Hash filter */ -#define EMAC_RX_MHF (0x1 << 21) -/* 0: Not accept 1: Accept Broadcast Packets(default) */ -#define EMAC_RX_BCO (0x1 << 22) -/* 0: Disable(default) 1: Enable SA Filtering */ -#define EMAC_RX_SAF (0x1 << 24) -/* 0: Normal(default) 1: Inverse Filtering */ -#define EMAC_RX_SAIF (0x1 << 25) - -#define EMAC_RX_SETUP (EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \ - EMAC_RX_MCO | EMAC_RX_BCO) - -/* 0: Disable 1: Enable Receive Flow Control(default) */ -#define EMAC_MAC_CTL0_RFC (0x1 << 2) -/* 0: Disable 1: Enable Transmit Flow Control(default) */ -#define EMAC_MAC_CTL0_TFC (0x1 << 3) - -#define EMAC_MAC_CTL0_SETUP (EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC) - -/* 0: Disable 1: Enable MAC Frame Length Checking(default) */ -#define EMAC_MAC_CTL1_FLC (0x1 << 1) -/* 0: Disable(default) 1: Enable Huge Frame */ -#define EMAC_MAC_CTL1_HF (0x1 << 2) -/* 0: Disable(default) 1: Enable MAC Delayed CRC */ -#define EMAC_MAC_CTL1_DCRC (0x1 << 3) -/* 0: Disable 1: Enable MAC CRC(default) */ -#define EMAC_MAC_CTL1_CRC (0x1 << 4) -/* 0: Disable 1: Enable MAC PAD Short frames(default) */ -#define EMAC_MAC_CTL1_PC (0x1 << 5) -/* 0: Disable(default) 1: Enable MAC PAD Short frames and append CRC */ -#define EMAC_MAC_CTL1_VC (0x1 << 6) -/* 0: Disable(default) 1: Enable MAC auto detect Short frames */ -#define EMAC_MAC_CTL1_ADP (0x1 << 7) -/* 0: Disable(default) 1: Enable */ -#define EMAC_MAC_CTL1_PRE (0x1 << 8) -/* 0: Disable(default) 1: Enable */ -#define EMAC_MAC_CTL1_LPE (0x1 << 9) -/* 0: Disable(default) 1: Enable no back off */ -#define EMAC_MAC_CTL1_NB (0x1 << 12) -/* 0: Disable(default) 1: Enable */ -#define EMAC_MAC_CTL1_BNB (0x1 << 13) -/* 0: Disable(default) 1: Enable */ -#define EMAC_MAC_CTL1_ED (0x1 << 14) - -#define EMAC_MAC_CTL1_SETUP (EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \ - EMAC_MAC_CTL1_PC) - -#define EMAC_MAC_IPGT 0x15 - -#define EMAC_MAC_NBTB_IPG1 0xC -#define EMAC_MAC_NBTB_IPG2 0x12 - -#define EMAC_MAC_CW 0x37 -#define EMAC_MAC_RM 0xF - -#define EMAC_MAC_MFL 0x0600 - -/* Receive status */ -#define EMAC_CRCERR (1 << 4) -#define EMAC_LENERR (3 << 5) - -#define DMA_CPU_TRRESHOLD 2000 - -struct wemac_eth_dev { - u32 speed; - u32 duplex; - u32 phy_configured; - int link_printed; -}; - -struct wemac_rxhdr { - s16 rx_len; - u16 rx_status; -}; - -static void wemac_inblk_32bit(void *reg, void *data, int count) -{ - int cnt = (count + 3) >> 2; - - if (cnt) { - u32 *buf = data; - - do { - u32 x = readl(reg); - *buf++ = x; - } while (--cnt); - } -} - -static void wemac_outblk_32bit(void *reg, void *data, int count) -{ - int cnt = (count + 3) >> 2; - - if (cnt) { - const u32 *buf = data; - - do { - writel(*buf++, reg); - } while (--cnt); - } -} - -/* - * Read a word from phyxcer - */ -static int wemac_phy_read(const char *devname, unsigned char addr, - unsigned char reg, unsigned short *value) -{ - struct eth_device *dev = eth_get_dev_by_name(devname); - struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; - - /* issue the phy address and reg */ - writel(addr << 8 | reg, ®s->mac_madr); - - /* pull up the phy io line */ - writel(0x1, ®s->mac_mcmd); - - /* Wait read complete */ - mdelay(1); - - /* push down the phy io line */ - writel(0x0, ®s->mac_mcmd); - - /* and write data */ - *value = readl(®s->mac_mrdd); - - return 0; -} - -/* - * Write a word to phyxcer - */ -static int wemac_phy_write(const char *devname, unsigned char addr, - unsigned char reg, unsigned short value) -{ - struct eth_device *dev = eth_get_dev_by_name(devname); - struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; - - /* issue the phy address and reg */ - writel(addr << 8 | reg, ®s->mac_madr); - - /* pull up the phy io line */ - writel(0x1, ®s->mac_mcmd); - - /* Wait write complete */ - mdelay(1); - - /* push down the phy io line */ - writel(0x0, ®s->mac_mcmd); - - /* and write data */ - writel(value, ®s->mac_mwtd); - - return 0; -} - -static void emac_setup(struct eth_device *dev) -{ - struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; - u32 reg_val; - u16 phy_val; - u32 duplex_flag; - - /* Set up TX */ - writel(EMAC_TX_SETUP, ®s->tx_mode); - - /* Set up RX */ - writel(EMAC_RX_SETUP, ®s->rx_ctl); - - /* Set MAC */ - /* Set MAC CTL0 */ - writel(EMAC_MAC_CTL0_SETUP, ®s->mac_ctl0); - - /* Set MAC CTL1 */ - wemac_phy_read(dev->name, 1, 0, &phy_val); - debug("PHY SETUP, reg 0 value: %x\n", phy_val); - duplex_flag = !!(phy_val & (1 << 8)); - - reg_val = 0; - if (duplex_flag) - reg_val = (0x1 << 0); - writel(EMAC_MAC_CTL1_SETUP | reg_val, ®s->mac_ctl1); - - /* Set up IPGT */ - writel(EMAC_MAC_IPGT, ®s->mac_ipgt); - - /* Set up IPGR */ - writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), ®s->mac_ipgr); - - /* Set up Collison window */ - writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), ®s->mac_clrt); - - /* Set up Max Frame Length */ - writel(EMAC_MAC_MFL, ®s->mac_maxf); -} - -static void wemac_reset(struct eth_device *dev) -{ - struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; - - debug("resetting device\n"); - - /* RESET device */ - writel(0, ®s->ctl); - udelay(200); - - writel(1, ®s->ctl); - udelay(200); -} - -static int sunxi_wemac_eth_init(struct eth_device *dev, bd_t *bd) -{ - struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; - struct wemac_eth_dev *priv = dev->priv; - u16 phy_reg; - - /* Init EMAC */ - - /* Flush RX FIFO */ - setbits_le32(®s->rx_ctl, 0x8); - udelay(1); - - /* Init MAC */ - - /* Soft reset MAC */ - clrbits_le32(®s->mac_ctl0, 1 << 15); - - /* Set MII clock */ - clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2); - - /* Clear RX counter */ - writel(0x0, ®s->rx_fbc); - udelay(1); - - /* Set up EMAC */ - emac_setup(dev); - - writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 | - dev->enetaddr[2], ®s->mac_a1); - writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 | - dev->enetaddr[5], ®s->mac_a0); - - mdelay(1); - - wemac_reset(dev); - - /* PHY POWER UP */ - wemac_phy_read(dev->name, 1, 0, &phy_reg); - wemac_phy_write(dev->name, 1, 0, phy_reg & (~(1 << 11))); - mdelay(1); - - wemac_phy_read(dev->name, 1, 0, &phy_reg); - - priv->speed = miiphy_speed(dev->name, 0); - priv->duplex = miiphy_duplex(dev->name, 0); - - /* Print link status only once */ - if (!priv->link_printed) { - printf("ENET Speed is %d Mbps - %s duplex connection\n", - priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL"); - priv->link_printed = 1; - } - - /* Set EMAC SPEED depend on PHY */ - clrsetbits_le32(®s->mac_supp, 1 << 8, - ((phy_reg & (1 << 13)) >> 13) << 8); - - /* Set duplex depend on phy */ - clrsetbits_le32(®s->mac_ctl1, 1 << 0, - ((phy_reg & (1 << 8)) >> 8) << 0); - - /* Enable RX/TX */ - setbits_le32(®s->ctl, 0x7); - - return 0; -} - -static void sunxi_wemac_eth_halt(struct eth_device *dev) -{ - /* Nothing to do here */ -} - -static int sunxi_wemac_eth_recv(struct eth_device *dev) -{ - struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; - struct wemac_rxhdr rxhdr; - u32 rxcount; - u32 reg_val; - int rx_len; - int rx_status; - int good_packet; - - /* Check packet ready or not */ - - /* - * Race warning: The first packet might arrive with - * the interrupts disabled, but the second will fix - */ - rxcount = readl(®s->rx_fbc); - if (!rxcount) { - /* Had one stuck? */ - rxcount = readl(®s->rx_fbc); - if (!rxcount) - return 0; - } - - reg_val = readl(®s->rx_io_data); - if (reg_val != 0x0143414d) { - /* Disable RX */ - clrbits_le32(®s->ctl, 1 << 2); - - /* Flush RX FIFO */ - setbits_le32(®s->rx_ctl, 1 << 3); - while (readl(®s->rx_ctl) & (1 << 3)) - ; - - /* Enable RX */ - setbits_le32(®s->ctl, 1 << 2); - - return 0; - } - - /* - * A packet ready now - * Get status/length - */ - good_packet = 1; - - wemac_inblk_32bit(®s->rx_io_data, &rxhdr, sizeof(rxhdr)); - - rx_len = rxhdr.rx_len; - rx_status = rxhdr.rx_status; - - /* Packet Status check */ - if (rx_len < 0x40) { - good_packet = 0; - debug("RX: Bad Packet (runt)\n"); - } - - /* rx_status is identical to RSR register. */ - if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) { - good_packet = 0; - if (rx_status & EMAC_CRCERR) - printf("crc error\n"); - if (rx_status & EMAC_LENERR) - printf("length error\n"); - } - - /* Move data from WEMAC */ - if (good_packet) { - if (rx_len > DMA_CPU_TRRESHOLD) { - printf("Received packet is too big (len=%d)\n", rx_len); - } else { - wemac_inblk_32bit((void *)®s->rx_io_data, - NetRxPackets[0], rx_len); - - /* Pass to upper layer */ - NetReceive(NetRxPackets[0], rx_len); - return rx_len; - } - } - - return 0; -} - -static int sunxi_wemac_eth_send(struct eth_device *dev, void *packet, int len) -{ - struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; - - /* Select channel 0 */ - writel(0, ®s->tx_ins); - - /* Write packet */ - wemac_outblk_32bit((void *)®s->tx_io_data, packet, len); - - /* Set TX len */ - writel(len, ®s->tx_pl0); - - /* Start translate from fifo to phy */ - setbits_le32(®s->tx_ctl0, 1); - - return 0; -} - -int sunxi_wemac_initialize(void) -{ - struct sunxi_ccm_reg *const ccm = - (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; - struct sunxi_sramc_regs *sram = - (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE; - struct eth_device *dev; - struct wemac_eth_dev *priv; - int pin; - - dev = malloc(sizeof(*dev)); - if (dev == NULL) - return -ENOMEM; - - priv = (struct wemac_eth_dev *)malloc(sizeof(struct wemac_eth_dev)); - if (!priv) { - free(dev); - return -ENOMEM; - } - - memset(dev, 0, sizeof(*dev)); - memset(priv, 0, sizeof(struct wemac_eth_dev)); - - /* Map SRAM to EMAC */ - setbits_le32(&sram->ctrl1, 0x5 << 2); - - /* Configure pin mux settings for MII Ethernet */ - for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++) - sunxi_gpio_set_cfgpin(pin, 2); - - /* Set up clock gating */ - setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_EMAC); - - dev->iobase = SUNXI_EMAC_BASE; - dev->priv = priv; - dev->init = sunxi_wemac_eth_init; - dev->halt = sunxi_wemac_eth_halt; - dev->send = sunxi_wemac_eth_send; - dev->recv = sunxi_wemac_eth_recv; - strcpy(dev->name, "wemac"); - - eth_register(dev); - - miiphy_register(dev->name, wemac_phy_read, wemac_phy_write); - - return 0; -} diff --git a/include/netdev.h b/include/netdev.h index 47fa80d..16ee4ce 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -79,7 +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_wemac_initialize(bd_t *bis); +int sunxi_emac_initialize(bd_t *bis); int tsi108_eth_initialize(bd_t *bis); int uec_standard_init(bd_t *bis); int uli526x_initialize(bd_t *bis);

Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/board.c | 17 +++++++++++++++++ boards.cfg | 4 ++-- include/configs/sunxi-common.h | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index b00bf89..4e0ef14 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -12,6 +12,8 @@
#include <common.h> #include <i2c.h> +#include <netdev.h> +#include <miiphy.h> #include <serial.h> #ifdef CONFIG_SPL_BUILD #include <spl.h> @@ -111,3 +113,18 @@ void enable_caches(void) dcache_enable(); } #endif + +#if defined(CONFIG_SUNXI_EMAC) || defined(CONFIG_SUNXI_GMAC) +/* + * Initializes on-chip ethernet controllers. + * to override, implement board_eth_init() + */ +int cpu_eth_init(bd_t *bis) +{ +#ifdef CONFIG_SUNXI_EMAC + sunxi_emac_initialize(bis); +#endif + + return 0; +} +#endif diff --git a/boards.cfg b/boards.cfg index 82d2c6a..28f6fbc 100644 --- a/boards.cfg +++ b/boards.cfg @@ -353,8 +353,8 @@ Active arm armv7 rmobile renesas koelsch 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 A10-OLinuXino-Lime sun4i:A10_OLINUXINO_L,AXP209_POWER,SPL - -Active arm armv7 sunxi - sunxi A10s-OLinuXino-M sun5i:A10S_OLINUXINO_M,AXP152_POWER,SPL - +Active arm armv7 sunxi - sunxi A10-OLinuXino-Lime sun4i:A10_OLINUXINO_L,AXP209_POWER,SUNXI_EMAC,SPL - +Active arm armv7 sunxi - sunxi A10s-OLinuXino-M sun5i:A10S_OLINUXINO_M,AXP152_POWER,SUNXI_EMAC,SPL - Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,AXP209_POWER,FAST_MBUS,SPL - Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,AXP209_POWER,FAST_MBUS,SPL_FEL - Active arm armv7 u8500 st-ericsson snowball snowball - Mathieu Poirier mathieu.poirier@linaro.org diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 027a1ec..b83e50e 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -193,6 +193,38 @@ #define CONFIG_CONS_INDEX 1 /* UART0 */ #endif
+/* Ethernet support */ +#ifdef CONFIG_SUNXI_EMAC +#define CONFIG_MII /* MII PHY management */ +#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 && \

On Tue, 2014-03-18 at 00:00 +0100, Hans de Goede wrote:
There are 3 FIXUP patches in here which are intended to be squashed into Ian's work. Ian, can you please pick these up ?
Consensus seems to be that including these "useless" ifdefs in the initial sun7i series makes future series to add other sun?i, so sure.
I'm hoping to rebase to current sunxi+the cleanups I just sent out towards the end of the week and send out a v2 based on that, hopefully we can do the merge up to v2014.04-rc2 in time for a v3.
I've got a small amount of WIP mmc cleanup going on, but that's looking like the biggest issue so far. I'm doing OK at removing magic numbers using existing comments and the Linux driver etc but some of the timing loops I'm not all that confident in changing -- so at least that bit will likely miss v2.
Ian.

Tested-by: Matt Porter matt.porter@linaro.org Signed-off-by: Tom Rini trini@ti.com --- board/sunxi/Makefile | 1 + board/sunxi/dram_a13_oli_micro.c | 32 ++++++++++++++++++++++++++++++++ boards.cfg | 1 + 3 files changed, 34 insertions(+) create mode 100644 board/sunxi/dram_a13_oli_micro.c
diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile index 8e284d4..a49e28e 100644 --- a/board/sunxi/Makefile +++ b/board/sunxi/Makefile @@ -11,4 +11,5 @@ obj-y += board.o obj-$(CONFIG_A10_OLINUXINO_L) += dram_a10_olinuxino_l.o obj-$(CONFIG_A10S_OLINUXINO_M) += dram_a10s_olinuxino_m.o +obj-$(CONFIG_A13_OLINUXINOM) += dram_a13_oli_micro.o obj-$(CONFIG_CUBIETRUCK) += dram_cubietruck.o diff --git a/board/sunxi/dram_a13_oli_micro.c b/board/sunxi/dram_a13_oli_micro.c new file mode 100644 index 0000000..8154ea2 --- /dev/null +++ b/board/sunxi/dram_a13_oli_micro.c @@ -0,0 +1,32 @@ +/* this file is generated, don't edit it yourself */ + +#include <common.h> +#include <asm/arch/dram.h> + +static struct dram_para dram_para = { + .clock = 408, + .type = 3, + .rank_num = 1, + .density = 2048, + .io_width = 16, + .bus_width = 16, + .cas = 9, + .zq = 123, + .odt_en = 0, + .size = 256, + .tpr0 = 0x42d899b7, + .tpr1 = 0xa090, + .tpr2 = 0x22a00, + .tpr3 = 0, + .tpr4 = 0, + .tpr5 = 0, + .emr1 = 0, + .emr2 = 0x10, + .emr3 = 0, + +}; + +unsigned long sunxi_dram_init(void) +{ + return dramc_init(&dram_para); +} diff --git a/boards.cfg b/boards.cfg index 28f6fbc..b695a10 100644 --- a/boards.cfg +++ b/boards.cfg @@ -355,6 +355,7 @@ Active arm armv7 s5pc1xx samsung smdkc100 Active arm armv7 socfpga altera socfpga socfpga_cyclone5 - - Active arm armv7 sunxi - sunxi A10-OLinuXino-Lime sun4i:A10_OLINUXINO_L,AXP209_POWER,SUNXI_EMAC,SPL - Active arm armv7 sunxi - sunxi A10s-OLinuXino-M sun5i:A10S_OLINUXINO_M,AXP152_POWER,SUNXI_EMAC,SPL - +Active arm armv7 sunxi - sunxi A13-OLinuXinoM sun5i:A13_OLINUXINOM,SPL,NO_AXP,STATUSLED=201,CONS_INDEX=2 - Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,AXP209_POWER,FAST_MBUS,SPL - Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,AXP209_POWER,FAST_MBUS,SPL_FEL - Active arm armv7 u8500 st-ericsson snowball snowball - Mathieu Poirier mathieu.poirier@linaro.org

Hi Tom,
On Thu, 20 Mar 2014 08:49:37 -0400, Tom Rini trini@ti.com wrote:
Tested-by: Matt Porter matt.porter@linaro.org Signed-off-by: Tom Rini trini@ti.com
Where does this patch come from? The source tree it applies to is not that of mainline U-Boot. If this is actually an RFC that I should look into, (as the PW state says), then which repository does it apply to?
Amicalement,

Hi,
On 06/09/2014 08:50 AM, Albert ARIBAUD wrote:
Hi Tom,
On Thu, 20 Mar 2014 08:49:37 -0400, Tom Rini trini@ti.com wrote:
Tested-by: Matt Porter matt.porter@linaro.org Signed-off-by: Tom Rini trini@ti.com
Where does this patch come from? The source tree it applies to is not that of mainline U-Boot. If this is actually an RFC that I should look into, (as the PW state says), then which repository does it apply to?
This was posted by Tom as an add on patch to my: "[PATCH u-boot sunxi 00/12] sun4i (v2) + sun5i + pmic + emac support"
Series, which was a series on top of one of Ian's sun7i support series:
http://lists.denx.de/pipermail/u-boot/2014-March/175656.html
In the mean time (as you know) Ians' series has gone upstream and I've continued working on the series in question, with Ian reviewing it. Actually I've just send you a pull-req with the bits of this series which are ready to go upstream. Which includes support for the A13-OLinuXinoM as part of the "sunxi: Add sun5i support" patch.
Regards,
Hans

Hi Hans,
On Mon, 09 Jun 2014 09:56:01 +0200, Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 06/09/2014 08:50 AM, Albert ARIBAUD wrote:
Hi Tom,
On Thu, 20 Mar 2014 08:49:37 -0400, Tom Rini trini@ti.com wrote:
Tested-by: Matt Porter matt.porter@linaro.org Signed-off-by: Tom Rini trini@ti.com
Where does this patch come from? The source tree it applies to is not that of mainline U-Boot. If this is actually an RFC that I should look into, (as the PW state says), then which repository does it apply to?
This was posted by Tom as an add on patch to my: "[PATCH u-boot sunxi 00/12] sun4i (v2) + sun5i + pmic + emac support"
Series, which was a series on top of one of Ian's sun7i support series:
http://lists.denx.de/pipermail/u-boot/2014-March/175656.html
In the mean time (as you know) Ians' series has gone upstream and I've continued working on the series in question, with Ian reviewing it. Actually I've just send you a pull-req with the bits of this series which are ready to go upstream. Which includes support for the A13-OLinuXinoM as part of the "sunxi: Add sun5i support" patch.
Thanks. Unfortunately, I had lost track of the dependencies -- which is a live example of why patches with dependencies should mention them explicitly after their commit message (not in it, though, as once applied, the dependency info is not relevant any more), so that folks like me can reconstruct the information. :)
I'll process you patch series -- not "pull request", as I only pull from other (ARM-related only) U-Boot repos :) -- in a few days, then I'll handle Tom's patch.
Regards,
Hans
Amicalement,

Hi,
On 06/10/2014 09:25 AM, Albert ARIBAUD wrote:
Hi Hans,
On Mon, 09 Jun 2014 09:56:01 +0200, Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 06/09/2014 08:50 AM, Albert ARIBAUD wrote:
Hi Tom,
On Thu, 20 Mar 2014 08:49:37 -0400, Tom Rini trini@ti.com wrote:
Tested-by: Matt Porter matt.porter@linaro.org Signed-off-by: Tom Rini trini@ti.com
Where does this patch come from? The source tree it applies to is not that of mainline U-Boot. If this is actually an RFC that I should look into, (as the PW state says), then which repository does it apply to?
This was posted by Tom as an add on patch to my: "[PATCH u-boot sunxi 00/12] sun4i (v2) + sun5i + pmic + emac support"
Series, which was a series on top of one of Ian's sun7i support series:
http://lists.denx.de/pipermail/u-boot/2014-March/175656.html
In the mean time (as you know) Ians' series has gone upstream and I've continued working on the series in question, with Ian reviewing it. Actually I've just send you a pull-req with the bits of this series which are ready to go upstream. Which includes support for the A13-OLinuXinoM as part of the "sunxi: Add sun5i support" patch.
Thanks. Unfortunately, I had lost track of the dependencies -- which is a live example of why patches with dependencies should mention them explicitly after their commit message (not in it, though, as once applied, the dependency info is not relevant any more), so that folks like me can reconstruct the information. :)
I'll process you patch series -- not "pull request", as I only pull from other (ARM-related only) U-Boot repos :) -- in a few days, then I'll handle Tom's patch.
Adding support for the A13-OLinuXinoM has been integrated into my series, so you can drop Tom's patch.
Note I've a lot more allwinner boards (all olimex variants, various mele devices, various mk802 and mk805 variants), which I plan to add support for (these are already support in the u-boot-sunxi git repository), but I'm trying to upstream things in small batches. Let me know if you want me to speed things up and queue up more patches.
Regards,
Hans

Hi Hans,
On Tue, 10 Jun 2014 09:48:48 +0200, Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 06/10/2014 09:25 AM, Albert ARIBAUD wrote:
Hi Hans,
On Mon, 09 Jun 2014 09:56:01 +0200, Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 06/09/2014 08:50 AM, Albert ARIBAUD wrote:
Hi Tom,
On Thu, 20 Mar 2014 08:49:37 -0400, Tom Rini trini@ti.com wrote:
Tested-by: Matt Porter matt.porter@linaro.org Signed-off-by: Tom Rini trini@ti.com
Where does this patch come from? The source tree it applies to is not that of mainline U-Boot. If this is actually an RFC that I should look into, (as the PW state says), then which repository does it apply to?
This was posted by Tom as an add on patch to my: "[PATCH u-boot sunxi 00/12] sun4i (v2) + sun5i + pmic + emac support"
Series, which was a series on top of one of Ian's sun7i support series:
http://lists.denx.de/pipermail/u-boot/2014-March/175656.html
In the mean time (as you know) Ians' series has gone upstream and I've continued working on the series in question, with Ian reviewing it. Actually I've just send you a pull-req with the bits of this series which are ready to go upstream. Which includes support for the A13-OLinuXinoM as part of the "sunxi: Add sun5i support" patch.
Thanks. Unfortunately, I had lost track of the dependencies -- which is a live example of why patches with dependencies should mention them explicitly after their commit message (not in it, though, as once applied, the dependency info is not relevant any more), so that folks like me can reconstruct the information. :)
I'll process you patch series -- not "pull request", as I only pull from other (ARM-related only) U-Boot repos :) -- in a few days, then I'll handle Tom's patch.
Adding support for the A13-OLinuXinoM has been integrated into my series, so you can drop Tom's patch.
Ok.
Note I've a lot more allwinner boards (all olimex variants, various mele devices, various mk802 and mk805 variants), which I plan to add support for (these are already support in the u-boot-sunxi git repository), but I'm trying to upstream things in small batches. Let me know if you want me to speed things up and queue up more patches.
No need to speed things up right now as any new patch series posted at this time would only be considered for next merge window. Right now, I'd only take a new patch for 2014.07 if it was a bug fix, or maybe a really trivial *and* really useful addition.
Regards,
Hans
Amicalement,
participants (5)
-
Albert ARIBAUD
-
Hans de Goede
-
Heiko Schocher
-
Ian Campbell
-
Tom Rini