Merge branch 'master' of git://git.denx.de/u-boot-arm
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile
index 6c70639..e9721b2 100644
--- a/arch/arm/cpu/armv7/sunxi/Makefile
+++ b/arch/arm/cpu/armv7/sunxi/Makefile
@@ -17,6 +17,9 @@
ifndef CONFIG_SPL_BUILD
obj-y += cpu_info.o
+ifdef CONFIG_ARMV7_PSCI
+obj-y += psci.o
+endif
endif
ifdef CONFIG_SPL_BUILD
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c
index 8f2cef3..f2cedbb 100644
--- a/arch/arm/cpu/armv7/sunxi/board.c
+++ b/arch/arm/cpu/armv7/sunxi/board.c
@@ -129,6 +129,11 @@
{
__maybe_unused int rc;
+#ifdef CONFIG_MACPWR
+ gpio_direction_output(CONFIG_MACPWR, 1);
+ mdelay(200);
+#endif
+
#ifdef CONFIG_SUNXI_EMAC
rc = sunxi_emac_initialize(bis);
if (rc < 0) {
diff --git a/arch/arm/cpu/armv7/sunxi/clock_sun4i.c b/arch/arm/cpu/armv7/sunxi/clock_sun4i.c
index b8b16cf..ecbdb01 100644
--- a/arch/arm/cpu/armv7/sunxi/clock_sun4i.c
+++ b/arch/arm/cpu/armv7/sunxi/clock_sun4i.c
@@ -39,6 +39,10 @@
setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_DMA);
#endif
writel(PLL6_CFG_DEFAULT, &ccm->pll6_cfg);
+#ifdef CONFIG_SUNXI_AHCI
+ setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_SATA);
+ setbits_le32(&ccm->pll6_cfg, 0x1 << CCM_PLL6_CTRL_SATA_EN_SHIFT);
+#endif
}
#endif
diff --git a/arch/arm/cpu/armv7/sunxi/psci.S b/arch/arm/cpu/armv7/sunxi/psci.S
new file mode 100644
index 0000000..0084c81
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/psci.S
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Based on code by Carl van Schaik <carl@ok-labs.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <asm/psci.h>
+#include <asm/arch/cpu.h>
+
+/*
+ * Memory layout:
+ *
+ * SECURE_RAM to text_end :
+ * ._secure_text section
+ * text_end to ALIGN_PAGE(text_end):
+ * nothing
+ * ALIGN_PAGE(text_end) to ALIGN_PAGE(text_end) + 0x1000)
+ * 1kB of stack per CPU (4 CPUs max).
+ */
+
+ .pushsection ._secure.text, "ax"
+
+ .arch_extension sec
+
+#define ONE_MS (CONFIG_SYS_CLK_FREQ / 1000)
+#define TEN_MS (10 * ONE_MS)
+
+.macro timer_wait reg, ticks
+ @ Program CNTP_TVAL
+ movw \reg, #(\ticks & 0xffff)
+ movt \reg, #(\ticks >> 16)
+ mcr p15, 0, \reg, c14, c2, 0
+ isb
+ @ Enable physical timer, mask interrupt
+ mov \reg, #3
+ mcr p15, 0, \reg, c14, c2, 1
+ @ Poll physical timer until ISTATUS is on
+1: isb
+ mrc p15, 0, \reg, c14, c2, 1
+ ands \reg, \reg, #4
+ bne 1b
+ @ Disable timer
+ mov \reg, #0
+ mcr p15, 0, \reg, c14, c2, 1
+ isb
+.endm
+
+.globl psci_arch_init
+psci_arch_init:
+ mrc p15, 0, r5, c1, c1, 0 @ Read SCR
+ bic r5, r5, #1 @ Secure mode
+ mcr p15, 0, r5, c1, c1, 0 @ Write SCR
+ isb
+
+ mrc p15, 0, r4, c0, c0, 5 @ MPIDR
+ and r4, r4, #3 @ cpu number in cluster
+ mov r5, #400 @ 1kB of stack per CPU
+ mul r4, r4, r5
+
+ adr r5, text_end @ end of text
+ add r5, r5, #0x2000 @ Skip two pages
+ lsr r5, r5, #12 @ Align to start of page
+ lsl r5, r5, #12
+ sub sp, r5, r4 @ here's our stack!
+
+ bx lr
+
+ @ r1 = target CPU
+ @ r2 = target PC
+.globl psci_cpu_on
+psci_cpu_on:
+ adr r0, _target_pc
+ str r2, [r0]
+ dsb
+
+ movw r0, #(SUNXI_CPUCFG_BASE & 0xffff)
+ movt r0, #(SUNXI_CPUCFG_BASE >> 16)
+
+ @ CPU mask
+ and r1, r1, #3 @ only care about first cluster
+ mov r4, #1
+ lsl r4, r4, r1
+
+ adr r6, _sunxi_cpu_entry
+ str r6, [r0, #0x1a4] @ PRIVATE_REG (boot vector)
+
+ @ Assert reset on target CPU
+ mov r6, #0
+ lsl r5, r1, #6 @ 64 bytes per CPU
+ add r5, r5, #0x40 @ Offset from base
+ add r5, r5, r0 @ CPU control block
+ str r6, [r5] @ Reset CPU
+
+ @ l1 invalidate
+ ldr r6, [r0, #0x184]
+ bic r6, r6, r4
+ str r6, [r0, #0x184]
+
+ @ Lock CPU
+ ldr r6, [r0, #0x1e4]
+ bic r6, r6, r4
+ str r6, [r0, #0x1e4]
+
+ @ Release power clamp
+ movw r6, #0x1ff
+ movt r6, #0
+1: lsrs r6, r6, #1
+ str r6, [r0, #0x1b0]
+ bne 1b
+
+ timer_wait r1, TEN_MS
+
+ @ Clear power gating
+ ldr r6, [r0, #0x1b4]
+ bic r6, r6, #1
+ str r6, [r0, #0x1b4]
+
+ @ Deassert reset on target CPU
+ mov r6, #3
+ str r6, [r5]
+
+ @ Unlock CPU
+ ldr r6, [r0, #0x1e4]
+ orr r6, r6, r4
+ str r6, [r0, #0x1e4]
+
+ mov r0, #ARM_PSCI_RET_SUCCESS @ Return PSCI_RET_SUCCESS
+ mov pc, lr
+
+_target_pc:
+ .word 0
+
+_sunxi_cpu_entry:
+ @ Set SMP bit
+ mrc p15, 0, r0, c1, c0, 1
+ orr r0, r0, #0x40
+ mcr p15, 0, r0, c1, c0, 1
+ isb
+
+ bl _nonsec_init
+ bl psci_arch_init
+
+ adr r0, _target_pc
+ ldr r0, [r0]
+ b _do_nonsec_entry
+
+text_end:
+ .popsection
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
index 928f3f2..1ba997a 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
@@ -218,10 +218,13 @@
#define CCM_PLL5_CTRL_BYPASS (0x1 << 30)
#define CCM_PLL5_CTRL_EN (0x1 << 31)
-#define CCM_PLL6_CTRL_N_SHIFT 8
-#define CCM_PLL6_CTRL_N_MASK (0x1f << CCM_PLL6_CTRL_N_SHIFT)
-#define CCM_PLL6_CTRL_K_SHIFT 4
-#define CCM_PLL6_CTRL_K_MASK (0x3 << CCM_PLL6_CTRL_K_SHIFT)
+#define CCM_PLL6_CTRL_EN 31
+#define CCM_PLL6_CTRL_BYPASS_EN 30
+#define CCM_PLL6_CTRL_SATA_EN_SHIFT 14
+#define CCM_PLL6_CTRL_N_SHIFT 8
+#define CCM_PLL6_CTRL_N_MASK (0x1f << CCM_PLL6_CTRL_N_SHIFT)
+#define CCM_PLL6_CTRL_K_SHIFT 4
+#define CCM_PLL6_CTRL_K_MASK (0x3 << CCM_PLL6_CTRL_K_SHIFT)
#define CCM_GPS_CTRL_RESET (0x1 << 0)
#define CCM_GPS_CTRL_GATE (0x1 << 1)
@@ -253,4 +256,8 @@
#define CCM_GMAC_CTRL_GPIT_MII (0x0 << 2)
#define CCM_GMAC_CTRL_GPIT_RGMII (0x1 << 2)
+#define CCM_USB_CTRL_PHY1_RST (0x1 << 1)
+#define CCM_USB_CTRL_PHY2_RST (0x1 << 2)
+#define CCM_USB_CTRL_PHYGATE (0x1 << 8)
+
#endif /* _SUNXI_CLOCK_SUN4I_H */
diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS
index 1a56608..b0b1804 100644
--- a/board/sunxi/MAINTAINERS
+++ b/board/sunxi/MAINTAINERS
@@ -2,11 +2,26 @@
M: Hans de Goede <hdegoede@redhat.com>
S: Maintained
F: board/sunxi/
-F: include/configs/sun5i.h
-F: configs/A13-OLinuXinoM_defconfig
F: include/configs/sun4i.h
+F: configs/A10-OLinuXino-Lime_defconfig
+F: configs/ba10_tv_box_defconfig
F: configs/Cubieboard_defconfig
+F: configs/Mele_A1000_defconfig
+F: configs/Mele_A1000G_defconfig
+F: configs/Mini-X_defconfig
+F: configs/Mini-X-1Gb_defconfig
+F: include/configs/sun5i.h
+F: configs/A10s-OLinuXino-M_defconfig
+F: configs/A13-OLinuXino_defconfig
+F: configs/A13-OLinuXinoM_defconfig
+F: configs/Auxtek-T004_defconfig
F: configs/r7-tv-dongle_defconfig
+F: include/configs/sun7i.h
+F: configs/A20-OLinuXino_MICRO_defconfig
+F: configs/Bananapi_defconfig
+F: configs/i12-tvbox_defconfig
+F: configs/Linksprite_pcDuino3_defconfig
+F: configs/qt840a_defconfig
CUBIEBOARD2 BOARD
M: Ian Campbell <ijc@hellion.org.uk>
diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile
index 62acb8f..cf001e7 100644
--- a/board/sunxi/Makefile
+++ b/board/sunxi/Makefile
@@ -10,8 +10,24 @@
#
obj-y += board.o
obj-$(CONFIG_SUNXI_GMAC) += gmac.o
+obj-$(CONFIG_SUNXI_AHCI) += ahci.o
+obj-$(CONFIG_A10_OLINUXINO_L) += dram_a10_olinuxino_l.o
+obj-$(CONFIG_A10S_OLINUXINO_M) += dram_a10s_olinuxino_m.o
+obj-$(CONFIG_A13_OLINUXINO) += dram_a13_olinuxino.o
obj-$(CONFIG_A13_OLINUXINOM) += dram_a13_oli_micro.o
+obj-$(CONFIG_A20_OLINUXINO_M) += dram_sun7i_384_1024_iow16.o
+# This is not a typo, uses the same mem settings as the a10s-olinuxino-m
+obj-$(CONFIG_AUXTEK_T004) += dram_a10s_olinuxino_m.o
+obj-$(CONFIG_BA10_TV_BOX) += dram_sun4i_384_1024_iow8.o
+obj-$(CONFIG_BANANAPI) += dram_bananapi.o
obj-$(CONFIG_CUBIEBOARD) += dram_cubieboard.o
obj-$(CONFIG_CUBIEBOARD2) += dram_cubieboard2.o
obj-$(CONFIG_CUBIETRUCK) += dram_cubietruck.o
+obj-$(CONFIG_I12_TVBOX) += dram_sun7i_384_1024_iow16.o
+obj-$(CONFIG_MELE_A1000) += dram_sun4i_360_512.o
+obj-$(CONFIG_MELE_A1000G) += dram_sun4i_360_1024_iow8.o
+obj-$(CONFIG_MINI_X) += dram_sun4i_360_512.o
+obj-$(CONFIG_MINI_X_1GB) += dram_sun4i_360_1024_iow16.o
+obj-$(CONFIG_PCDUINO3) += dram_linksprite_pcduino3.o
+obj-$(CONFIG_QT840A) += dram_sun7i_384_512_busw16_iow16.o
obj-$(CONFIG_R7DONGLE) += dram_r7dongle.o
diff --git a/board/sunxi/ahci.c b/board/sunxi/ahci.c
new file mode 100644
index 0000000..0c262ea
--- /dev/null
+++ b/board/sunxi/ahci.c
@@ -0,0 +1,84 @@
+#include <common.h>
+#include <ahci.h>
+#include <scsi.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+#define AHCI_PHYCS0R 0x00c0
+#define AHCI_PHYCS1R 0x00c4
+#define AHCI_PHYCS2R 0x00c8
+#define AHCI_RWCR 0x00fc
+
+/* This magic PHY initialisation was taken from the Allwinner releases
+ * and Linux driver, but is completely undocumented.
+ */
+static int sunxi_ahci_phy_init(u32 base)
+{
+ u8 *reg_base = (u8 *)base;
+ u32 reg_val;
+ int timeout;
+
+ writel(0, reg_base + AHCI_RWCR);
+ mdelay(5);
+
+ setbits_le32(reg_base + AHCI_PHYCS1R, 0x1 << 19);
+ clrsetbits_le32(reg_base + AHCI_PHYCS0R,
+ (0x7 << 24),
+ (0x5 << 24) | (0x1 << 23) | (0x1 << 18));
+ clrsetbits_le32(reg_base + AHCI_PHYCS1R,
+ (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
+ (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
+ setbits_le32(reg_base + AHCI_PHYCS1R, (0x1 << 28) | (0x1 << 15));
+ clrbits_le32(reg_base + AHCI_PHYCS1R, (0x1 << 19));
+ clrsetbits_le32(reg_base + AHCI_PHYCS0R, (0x7 << 20), (0x3 << 20));
+ clrsetbits_le32(reg_base + AHCI_PHYCS2R, (0x1f << 5), (0x19 << 5));
+ mdelay(5);
+
+ setbits_le32(reg_base + AHCI_PHYCS0R, (0x1 << 19));
+
+ timeout = 250; /* Power up takes approx 50 us */
+ for (;;) {
+ reg_val = readl(reg_base + AHCI_PHYCS0R) & (0x7 << 28);
+ if (reg_val == (0x2 << 28))
+ break;
+ if (--timeout == 0) {
+ printf("AHCI PHY power up failed.\n");
+ return -EIO;
+ }
+ udelay(1);
+ };
+
+ setbits_le32(reg_base + AHCI_PHYCS2R, (0x1 << 24));
+
+ timeout = 100; /* Calibration takes approx 10 us */
+ for (;;) {
+ reg_val = readl(reg_base + AHCI_PHYCS2R) & (0x1 << 24);
+ if (reg_val == 0x0)
+ break;
+ if (--timeout == 0) {
+ printf("AHCI PHY calibration failed.\n");
+ return -EIO;
+ }
+ udelay(1);
+ }
+
+ mdelay(15);
+
+ writel(0x7, reg_base + AHCI_RWCR);
+
+ return 0;
+}
+
+void scsi_init(void)
+{
+ printf("SUNXI SCSI INIT\n");
+#ifdef CONFIG_SATAPWR
+ gpio_direction_output(CONFIG_SATAPWR, 1);
+#endif
+
+ if (sunxi_ahci_phy_init(SUNXI_SATA_BASE) < 0)
+ return;
+
+ ahci_init(SUNXI_SATA_BASE);
+}
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/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/board/sunxi/dram_a13_olinuxino.c b/board/sunxi/dram_a13_olinuxino.c
new file mode 100644
index 0000000..ca96260
--- /dev/null
+++ b/board/sunxi/dram_a13_olinuxino.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 = 408,
+ .type = 3,
+ .rank_num = 1,
+ .density = 2048,
+ .io_width = 8,
+ .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 = 0,
+ .emr2 = 0x10,
+ .emr3 = 0,
+};
+
+unsigned long sunxi_dram_init(void)
+{
+ return dramc_init(&dram_para);
+}
diff --git a/board/sunxi/dram_bananapi.c b/board/sunxi/dram_bananapi.c
new file mode 100644
index 0000000..0ed7943
--- /dev/null
+++ b/board/sunxi/dram_bananapi.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 = 32,
+ .cas = 9,
+ .zq = 0x7f,
+ .odt_en = 0,
+ .size = 1024,
+ .tpr0 = 0x42d899b7,
+ .tpr1 = 0xa090,
+ .tpr2 = 0x22a00,
+ .tpr3 = 0x0,
+ .tpr4 = 0x1,
+ .tpr5 = 0x0,
+ .emr1 = 0x4,
+ .emr2 = 0x10,
+ .emr3 = 0x0,
+};
+
+unsigned long sunxi_dram_init(void)
+{
+ return dramc_init(&dram_para);
+}
diff --git a/board/sunxi/dram_linksprite_pcduino3.c b/board/sunxi/dram_linksprite_pcduino3.c
new file mode 100644
index 0000000..9cc6e19
--- /dev/null
+++ b/board/sunxi/dram_linksprite_pcduino3.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 = 32,
+ .cas = 9,
+ .zq = 0x7a,
+ .odt_en = 0,
+ .size = 1024,
+ .tpr0 = 0x42d899b7,
+ .tpr1 = 0xa090,
+ .tpr2 = 0x22a00,
+ .tpr3 = 0,
+ .tpr4 = 0,
+ .tpr5 = 0,
+ .emr1 = 0x4,
+ .emr2 = 0x10,
+ .emr3 = 0x0,
+};
+
+unsigned long sunxi_dram_init(void)
+{
+ return dramc_init(&dram_para);
+}
diff --git a/board/sunxi/dram_sun4i_360_1024_iow16.c b/board/sunxi/dram_sun4i_360_1024_iow16.c
new file mode 100644
index 0000000..3763713
--- /dev/null
+++ b/board/sunxi/dram_sun4i_360_1024_iow16.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 = 360,
+ .type = 3,
+ .rank_num = 1,
+ .density = 4096,
+ .io_width = 16,
+ .bus_width = 32,
+ .cas = 6,
+ .zq = 123,
+ .odt_en = 0,
+ .size = 1024,
+ .tpr0 = 0x30926692,
+ .tpr1 = 0x1090,
+ .tpr2 = 0x1a0c8,
+ .tpr3 = 0,
+ .tpr4 = 0,
+ .tpr5 = 0,
+ .emr1 = 0,
+ .emr2 = 0,
+ .emr3 = 0,
+};
+
+unsigned long sunxi_dram_init(void)
+{
+ return dramc_init(&dram_para);
+}
diff --git a/board/sunxi/dram_sun4i_360_1024_iow8.c b/board/sunxi/dram_sun4i_360_1024_iow8.c
new file mode 100644
index 0000000..2a5c9ed
--- /dev/null
+++ b/board/sunxi/dram_sun4i_360_1024_iow8.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 = 360,
+ .type = 3,
+ .rank_num = 1,
+ .density = 2048,
+ .io_width = 8,
+ .bus_width = 32,
+ .cas = 6,
+ .zq = 123,
+ .odt_en = 0,
+ .size = 1024,
+ .tpr0 = 0x30926692,
+ .tpr1 = 0x1090,
+ .tpr2 = 0x1a0c8,
+ .tpr3 = 0,
+ .tpr4 = 0,
+ .tpr5 = 0,
+ .emr1 = 0,
+ .emr2 = 0,
+ .emr3 = 0,
+};
+
+unsigned long sunxi_dram_init(void)
+{
+ return dramc_init(&dram_para);
+}
diff --git a/board/sunxi/dram_sun4i_360_512.c b/board/sunxi/dram_sun4i_360_512.c
new file mode 100644
index 0000000..48aa6e2
--- /dev/null
+++ b/board/sunxi/dram_sun4i_360_512.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 = 360,
+ .type = 3,
+ .rank_num = 1,
+ .density = 2048,
+ .io_width = 16,
+ .bus_width = 32,
+ .cas = 6,
+ .zq = 123,
+ .odt_en = 0,
+ .size = 512,
+ .tpr0 = 0x30926692,
+ .tpr1 = 0x1090,
+ .tpr2 = 0x1a0c8,
+ .tpr3 = 0,
+ .tpr4 = 0,
+ .tpr5 = 0,
+ .emr1 = 0,
+ .emr2 = 0,
+ .emr3 = 0,
+};
+
+unsigned long sunxi_dram_init(void)
+{
+ return dramc_init(&dram_para);
+}
diff --git a/board/sunxi/dram_sun4i_384_1024_iow8.c b/board/sunxi/dram_sun4i_384_1024_iow8.c
new file mode 100644
index 0000000..b0fcc55
--- /dev/null
+++ b/board/sunxi/dram_sun4i_384_1024_iow8.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 = 384,
+ .type = 3,
+ .rank_num = 1,
+ .density = 2048,
+ .io_width = 8,
+ .bus_width = 32,
+ .cas = 6,
+ .zq = 123,
+ .odt_en = 0,
+ .size = 1024,
+ .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/board/sunxi/dram_sun7i_384_1024_iow16.c b/board/sunxi/dram_sun7i_384_1024_iow16.c
new file mode 100644
index 0000000..04e4b1e
--- /dev/null
+++ b/board/sunxi/dram_sun7i_384_1024_iow16.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 = 384,
+ .type = 3,
+ .rank_num = 1,
+ .density = 4096,
+ .io_width = 16,
+ .bus_width = 32,
+ .cas = 9,
+ .zq = 0x7f,
+ .odt_en = 0,
+ .size = 1024,
+ .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/board/sunxi/dram_sun7i_384_512_busw16_iow16.c b/board/sunxi/dram_sun7i_384_512_busw16_iow16.c
new file mode 100644
index 0000000..2e36011
--- /dev/null
+++ b/board/sunxi/dram_sun7i_384_512_busw16_iow16.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 = 384,
+ .type = 3,
+ .rank_num = 1,
+ .density = 4096,
+ .io_width = 16,
+ .bus_width = 16,
+ .cas = 9,
+ .zq = 0x7f,
+ .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/configs/A10-OLinuXino-Lime_defconfig b/configs/A10-OLinuXino-Lime_defconfig
new file mode 100644
index 0000000..a414953
--- /dev/null
+++ b/configs/A10-OLinuXino-Lime_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="A10_OLINUXINO_L,SPL,AXP209_POWER,SUNXI_EMAC,AHCI,SATAPWR=SUNXI_GPC(3),USB_EHCI"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN4I=y
diff --git a/configs/A10s-OLinuXino-M_defconfig b/configs/A10s-OLinuXino-M_defconfig
new file mode 100644
index 0000000..1560ab1
--- /dev/null
+++ b/configs/A10s-OLinuXino-M_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="A10S_OLINUXINO_M,SPL,AXP152_POWER,SUNXI_EMAC,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPB(10)"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN5I=y
diff --git a/configs/A13-OLinuXinoM_defconfig b/configs/A13-OLinuXinoM_defconfig
index 1731200..fb510d5 100644
--- a/configs/A13-OLinuXinoM_defconfig
+++ b/configs/A13-OLinuXinoM_defconfig
@@ -1,4 +1,4 @@
CONFIG_SPL=y
-CONFIG_SYS_EXTRA_OPTIONS="A13_OLINUXINOM,SPL,CONS_INDEX=2"
+CONFIG_SYS_EXTRA_OPTIONS="A13_OLINUXINOM,SPL,CONS_INDEX=2,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(11)"
+S:CONFIG_ARM=y
+S:CONFIG_TARGET_SUN5I=y
diff --git a/configs/A13-OLinuXino_defconfig b/configs/A13-OLinuXino_defconfig
new file mode 100644
index 0000000..ba21136
--- /dev/null
+++ b/configs/A13-OLinuXino_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="A13_OLINUXINO,SPL,CONS_INDEX=2,AXP209_POWER,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(11)"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN5I=y
diff --git a/configs/A20-OLinuXino_MICRO_defconfig b/configs/A20-OLinuXino_MICRO_defconfig
new file mode 100644
index 0000000..52a857a
--- /dev/null
+++ b/configs/A20-OLinuXino_MICRO_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="A20_OLINUXINO_M,SPL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN7I=y
diff --git a/configs/Auxtek-T004_defconfig b/configs/Auxtek-T004_defconfig
new file mode 100644
index 0000000..643e628
--- /dev/null
+++ b/configs/Auxtek-T004_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="AUXTEK_T004,SPL,AXP152_POWER,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(13)"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN5I=y
diff --git a/configs/Bananapi_defconfig b/configs/Bananapi_defconfig
new file mode 100644
index 0000000..be3d815
--- /dev/null
+++ b/configs/Bananapi_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="BANANAPI,SPL,AXP209_POWER,SUNXI_GMAC,RGMII,MACPWR=SUNXI_GPH(23),AHCI,USB_EHCI"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN7I=y
diff --git a/configs/Cubieboard2_FEL_defconfig b/configs/Cubieboard2_FEL_defconfig
index 08f3159..63636b0 100644
--- a/configs/Cubieboard2_FEL_defconfig
+++ b/configs/Cubieboard2_FEL_defconfig
@@ -1,4 +1,4 @@
CONFIG_SPL=y
-CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL_FEL,SUNXI_GMAC"
+CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL_FEL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI"
+S:CONFIG_ARM=y
+S:CONFIG_TARGET_SUN7I=y
diff --git a/configs/Cubieboard2_defconfig b/configs/Cubieboard2_defconfig
index 122dac9..fa34c51 100644
--- a/configs/Cubieboard2_defconfig
+++ b/configs/Cubieboard2_defconfig
@@ -1,4 +1,4 @@
CONFIG_SPL=y
-CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL,SUNXI_GMAC"
+CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI"
+S:CONFIG_ARM=y
+S:CONFIG_TARGET_SUN7I=y
diff --git a/configs/Cubieboard_defconfig b/configs/Cubieboard_defconfig
index 29bf836..774029c 100644
--- a/configs/Cubieboard_defconfig
+++ b/configs/Cubieboard_defconfig
@@ -1,4 +1,4 @@
CONFIG_SPL=y
-CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD,SPL,AXP209_POWER,SUNXI_EMAC"
+CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD,SPL,AXP209_POWER,SUNXI_EMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI"
+S:CONFIG_ARM=y
+S:CONFIG_TARGET_SUN4I=y
diff --git a/configs/Cubietruck_FEL_defconfig b/configs/Cubietruck_FEL_defconfig
index b95c5fa..7ebf635 100644
--- a/configs/Cubietruck_FEL_defconfig
+++ b/configs/Cubietruck_FEL_defconfig
@@ -1,4 +1,4 @@
CONFIG_SPL=y
-CONFIG_SYS_EXTRA_OPTIONS="CUBIETRUCK,SPL_FEL,AXP209_POWER,SUNXI_GMAC,RGMII"
+CONFIG_SYS_EXTRA_OPTIONS="CUBIETRUCK,SPL_FEL,AXP209_POWER,SUNXI_GMAC,RGMII,AHCI,SATAPWR=SUNXI_GPH(12),USB_EHCI"
+S:CONFIG_ARM=y
+S:CONFIG_TARGET_SUN7I=y
diff --git a/configs/Cubietruck_defconfig b/configs/Cubietruck_defconfig
index 4c1e9a3..fbc9127 100644
--- a/configs/Cubietruck_defconfig
+++ b/configs/Cubietruck_defconfig
@@ -1,4 +1,4 @@
CONFIG_SPL=y
-CONFIG_SYS_EXTRA_OPTIONS="CUBIETRUCK,SPL,AXP209_POWER,SUNXI_GMAC,RGMII"
+CONFIG_SYS_EXTRA_OPTIONS="CUBIETRUCK,SPL,AXP209_POWER,SUNXI_GMAC,RGMII,AHCI,SATAPWR=SUNXI_GPH(12),USB_EHCI"
+S:CONFIG_ARM=y
+S:CONFIG_TARGET_SUN7I=y
diff --git a/configs/Linksprite_pcDuino3_defconfig b/configs/Linksprite_pcDuino3_defconfig
new file mode 100644
index 0000000..10ebcef
--- /dev/null
+++ b/configs/Linksprite_pcDuino3_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="PCDUINO3,SPL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPH(2),USB_EHCI"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN7I=y
diff --git a/configs/Mele_A1000G_defconfig b/configs/Mele_A1000G_defconfig
new file mode 100644
index 0000000..2079279
--- /dev/null
+++ b/configs/Mele_A1000G_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="MELE_A1000G,SPL,AXP209_POWER,SUNXI_EMAC,MACPWR=SUNXI_GPH(15),AHCI,USB_EHCI"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN4I=y
diff --git a/configs/Mele_A1000_defconfig b/configs/Mele_A1000_defconfig
new file mode 100644
index 0000000..13528ab
--- /dev/null
+++ b/configs/Mele_A1000_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="MELE_A1000,SPL,AXP209_POWER,SUNXI_EMAC,MACPWR=SUNXI_GPH(15),AHCI,USB_EHCI"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN4I=y
diff --git a/configs/Mini-X-1Gb_defconfig b/configs/Mini-X-1Gb_defconfig
new file mode 100644
index 0000000..61fa1de
--- /dev/null
+++ b/configs/Mini-X-1Gb_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="MINI_X_1GB,SPL,AXP209_POWER,USB_EHCI"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN4I=y
diff --git a/configs/Mini-X_defconfig b/configs/Mini-X_defconfig
new file mode 100644
index 0000000..ceb02c5
--- /dev/null
+++ b/configs/Mini-X_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="MINI_X,SPL,AXP209_POWER,USB_EHCI"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN4I=y
diff --git a/configs/ba10_tv_box_defconfig b/configs/ba10_tv_box_defconfig
new file mode 100644
index 0000000..02a2538
--- /dev/null
+++ b/configs/ba10_tv_box_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="BA10_TV_BOX,SPL,AXP209_POWER,SUNXI_EMAC,USB_EHCI,SUNXI_USB_VBUS1_GPIO=SUNXI_GPH(12)"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN4I=y
diff --git a/configs/i12-tvbox_defconfig b/configs/i12-tvbox_defconfig
new file mode 100644
index 0000000..ff86841
--- /dev/null
+++ b/configs/i12-tvbox_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="I12_TVBOX,SPL,AXP209_POWER,SUNXI_GMAC,MACPWR=SUNXI_GPH(21),USB_EHCI"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN7I=y
diff --git a/configs/qt840a_defconfig b/configs/qt840a_defconfig
new file mode 100644
index 0000000..acb100c
--- /dev/null
+++ b/configs/qt840a_defconfig
@@ -0,0 +1,4 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="QT840A,SPL,AXP209_POWER,SUNXI_GMAC,MACPWR=SUNXI_GPH(21),USB_EHCI"
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_SUN7I=y
diff --git a/configs/r7-tv-dongle_defconfig b/configs/r7-tv-dongle_defconfig
index 62e8c56..f0f97b0 100644
--- a/configs/r7-tv-dongle_defconfig
+++ b/configs/r7-tv-dongle_defconfig
@@ -1,4 +1,4 @@
CONFIG_SPL=y
-CONFIG_SYS_EXTRA_OPTIONS="R7DONGLE,SPL,AXP152_POWER"
+CONFIG_SYS_EXTRA_OPTIONS="R7DONGLE,SPL,AXP152_POWER,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(13)"
+S:CONFIG_ARM=y
+S:CONFIG_TARGET_SUN5I=y
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 4df8046..dce99ad 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -129,6 +129,14 @@
return 1;
}
+#ifdef CONFIG_SUNXI_AHCI
+/* The sunxi AHCI controller requires this undocumented setup */
+static void sunxi_dma_init(volatile u8 *port_mmio)
+{
+ clrsetbits_le32(port_mmio + PORT_P0DMACR, 0x0000ff00, 0x00004400);
+}
+#endif
+
static int ahci_host_init(struct ahci_probe_ent *probe_ent)
{
#ifndef CONFIG_SCSI_AHCI_PLAT
@@ -213,6 +221,10 @@
msleep(500);
}
+#ifdef CONFIG_SUNXI_AHCI
+ sunxi_dma_init(port_mmio);
+#endif
+
/* Add the spinup command to whatever mode bits may
* already be on in the command register.
*/
@@ -545,6 +557,10 @@
writel_with_flush(pp->rx_fis, port_mmio + PORT_FIS_ADDR);
+#ifdef CONFIG_SUNXI_AHCI
+ sunxi_dma_init(port_mmio);
+#endif
+
writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
PORT_CMD_START, port_mmio + PORT_CMD);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 04c1a64..c4f5157 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -35,6 +35,7 @@
obj-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o
+obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o
obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o
diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c
new file mode 100644
index 0000000..23617b7
--- /dev/null
+++ b/drivers/usb/host/ehci-sunxi.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2014 Roman Byshko
+ *
+ * Roman Byshko <rbyshko@gmail.com>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/arch/clock.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <common.h>
+#include "ehci.h"
+
+#define SUNXI_USB1_IO_BASE 0x01c14000
+#define SUNXI_USB2_IO_BASE 0x01c1c000
+
+#define SUNXI_USB_PMU_IRQ_ENABLE 0x800
+#define SUNXI_USB_CSR 0x01c13404
+#define SUNXI_USB_PASSBY_EN 1
+
+#define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10)
+#define SUNXI_EHCI_AHB_INCR4_BURST_EN (1 << 9)
+#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN (1 << 8)
+#define SUNXI_EHCI_ULPI_BYPASS_EN (1 << 0)
+
+static struct sunxi_ehci_hcd {
+ struct usb_hcd *hcd;
+ int usb_rst_mask;
+ int ahb_clk_mask;
+ int gpio_vbus;
+ void *csr;
+ int irq;
+ int id;
+} sunxi_echi_hcd[] = {
+ {
+ .usb_rst_mask = CCM_USB_CTRL_PHY1_RST,
+ .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0,
+ .gpio_vbus = CONFIG_SUNXI_USB_VBUS0_GPIO,
+ .csr = (void *)SUNXI_USB_CSR,
+ .irq = 39,
+ .id = 1,
+ },
+#if (CONFIG_USB_MAX_CONTROLLER_COUNT > 1)
+ {
+ .usb_rst_mask = CCM_USB_CTRL_PHY2_RST,
+ .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI1,
+ .gpio_vbus = CONFIG_SUNXI_USB_VBUS1_GPIO,
+ .csr = (void *)SUNXI_USB_CSR,
+ .irq = 40,
+ .id = 2,
+ }
+#endif
+};
+
+static int enabled_hcd_count;
+
+static void *get_io_base(int hcd_id)
+{
+ if (hcd_id == 1)
+ return (void *)SUNXI_USB1_IO_BASE;
+ else if (hcd_id == 2)
+ return (void *)SUNXI_USB2_IO_BASE;
+ else
+ return NULL;
+}
+
+static void usb_phy_write(struct sunxi_ehci_hcd *sunxi_ehci, int addr,
+ int data, int len)
+{
+ int j = 0, usbc_bit = 0;
+ void *dest = sunxi_ehci->csr;
+
+ usbc_bit = 1 << (sunxi_ehci->id * 2);
+ for (j = 0; j < len; j++) {
+ /* set the bit address to be written */
+ clrbits_le32(dest, 0xff << 8);
+ setbits_le32(dest, (addr + j) << 8);
+
+ clrbits_le32(dest, usbc_bit);
+ /* set data bit */
+ if (data & 0x1)
+ setbits_le32(dest, 1 << 7);
+ else
+ clrbits_le32(dest, 1 << 7);
+
+ setbits_le32(dest, usbc_bit);
+
+ clrbits_le32(dest, usbc_bit);
+
+ data >>= 1;
+ }
+}
+
+static void sunxi_usb_phy_init(struct sunxi_ehci_hcd *sunxi_ehci)
+{
+ /* The following comments are machine
+ * translated from Chinese, you have been warned!
+ */
+
+ /* adjust PHY's magnitude and rate */
+ usb_phy_write(sunxi_ehci, 0x20, 0x14, 5);
+
+ /* threshold adjustment disconnect */
+#ifdef CONFIG_SUN4I
+ usb_phy_write(sunxi_ehci, 0x2a, 3, 2);
+#else
+ usb_phy_write(sunxi_ehci, 0x2a, 2, 2);
+#endif
+
+ return;
+}
+
+static void sunxi_usb_passby(struct sunxi_ehci_hcd *sunxi_ehci, int enable)
+{
+ unsigned long bits = 0;
+ void *addr = get_io_base(sunxi_ehci->id) + SUNXI_USB_PMU_IRQ_ENABLE;
+
+ bits = SUNXI_EHCI_AHB_ICHR8_EN |
+ SUNXI_EHCI_AHB_INCR4_BURST_EN |
+ SUNXI_EHCI_AHB_INCRX_ALIGN_EN |
+ SUNXI_EHCI_ULPI_BYPASS_EN;
+
+ if (enable)
+ setbits_le32(addr, bits);
+ else
+ clrbits_le32(addr, bits);
+
+ return;
+}
+
+static void sunxi_ehci_enable(struct sunxi_ehci_hcd *sunxi_ehci)
+{
+ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+ setbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask);
+ setbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask);
+
+ sunxi_usb_phy_init(sunxi_ehci);
+
+ sunxi_usb_passby(sunxi_ehci, SUNXI_USB_PASSBY_EN);
+
+ gpio_direction_output(sunxi_ehci->gpio_vbus, 1);
+}
+
+static void sunxi_ehci_disable(struct sunxi_ehci_hcd *sunxi_ehci)
+{
+ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+ gpio_direction_output(sunxi_ehci->gpio_vbus, 0);
+
+ sunxi_usb_passby(sunxi_ehci, !SUNXI_USB_PASSBY_EN);
+
+ clrbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask);
+ clrbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask);
+}
+
+int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr,
+ struct ehci_hcor **hcor)
+{
+ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index];
+
+ /* enable common PHY only once */
+ if (index == 0)
+ setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
+
+ sunxi_ehci_enable(sunxi_ehci);
+
+ *hccr = get_io_base(sunxi_ehci->id);
+
+ *hcor = (struct ehci_hcor *)((uint32_t) *hccr
+ + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+ debug("sunxi-ehci: init hccr %x and hcor %x hc_length %d\n",
+ (uint32_t)*hccr, (uint32_t)*hcor,
+ (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+ enabled_hcd_count++;
+
+ return 0;
+}
+
+int ehci_hcd_stop(int index)
+{
+ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index];
+
+ sunxi_ehci_disable(sunxi_ehci);
+
+ /* disable common PHY only once, for the last enabled hcd */
+ if (enabled_hcd_count == 1)
+ clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
+
+ enabled_hcd_count--;
+
+ return 0;
+}
diff --git a/include/ahci.h b/include/ahci.h
index 90e8509..35b8a8c 100644
--- a/include/ahci.h
+++ b/include/ahci.h
@@ -58,6 +58,10 @@
#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
+#ifdef CONFIG_SUNXI_AHCI
+#define PORT_P0DMACR 0x70 /* SUNXI specific "DMA register" */
+#endif
+
/* PORT_IRQ_{STAT,MASK} bits */
#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */
#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
diff --git a/include/configs/sun4i.h b/include/configs/sun4i.h
index 037f995..5611ecc 100644
--- a/include/configs/sun4i.h
+++ b/include/configs/sun4i.h
@@ -16,6 +16,18 @@
#define CONFIG_SYS_PROMPT "sun4i# "
+#ifdef CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_SUNXI
+
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 2
+#ifndef CONFIG_SUNXI_USB_VBUS0_GPIO
+#define CONFIG_SUNXI_USB_VBUS0_GPIO SUNXI_GPH(6)
+#endif
+#ifndef CONFIG_SUNXI_USB_VBUS1_GPIO
+#define CONFIG_SUNXI_USB_VBUS1_GPIO SUNXI_GPH(3)
+#endif
+#endif
+
/*
* Include common sunxi configuration where most the settings are
*/
diff --git a/include/configs/sun5i.h b/include/configs/sun5i.h
index c6138b7..6066371 100644
--- a/include/configs/sun5i.h
+++ b/include/configs/sun5i.h
@@ -16,6 +16,11 @@
#define CONFIG_SYS_PROMPT "sun5i# "
+#ifdef CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_SUNXI
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#endif
+
/*
* Include common sunxi configuration where most the settings are
*/
diff --git a/include/configs/sun7i.h b/include/configs/sun7i.h
index d9be104..a902b84 100644
--- a/include/configs/sun7i.h
+++ b/include/configs/sun7i.h
@@ -17,6 +17,25 @@
#define CONFIG_SYS_PROMPT "sun7i# "
+#ifdef CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_SUNXI
+
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 2
+#ifndef CONFIG_SUNXI_USB_VBUS0_GPIO
+#define CONFIG_SUNXI_USB_VBUS0_GPIO SUNXI_GPH(6)
+#endif
+#ifndef CONFIG_SUNXI_USB_VBUS1_GPIO
+#define CONFIG_SUNXI_USB_VBUS1_GPIO SUNXI_GPH(3)
+#endif
+#endif
+
+#define CONFIG_ARMV7_VIRT 1
+#define CONFIG_ARMV7_NONSEC 1
+#define CONFIG_ARMV7_PSCI 1
+#define CONFIG_ARMV7_PSCI_NR_CPUS 2
+#define CONFIG_ARMV7_SECURE_BASE SUNXI_SRAM_B_BASE
+#define CONFIG_SYS_CLK_FREQ 24000000
+
/*
* Include common sunxi configuration where most the settings are
*/
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 8ab6429..6a3044f 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -57,6 +57,18 @@
#define PHYS_SDRAM_0 CONFIG_SYS_SDRAM_BASE
#define PHYS_SDRAM_0_SIZE 0x80000000 /* 2 GiB */
+#ifdef CONFIG_AHCI
+#define CONFIG_LIBATA
+#define CONFIG_SCSI_AHCI
+#define CONFIG_SCSI_AHCI_PLAT
+#define CONFIG_SUNXI_AHCI
+#define CONFIG_SYS_SCSI_MAX_SCSI_ID 1
+#define CONFIG_SYS_SCSI_MAX_LUN 1
+#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \
+ CONFIG_SYS_SCSI_MAX_LUN)
+#define CONFIG_CMD_SCSI
+#endif
+
#define CONFIG_CMD_MEMORY
#define CONFIG_CMD_SETEXPR
@@ -203,6 +215,12 @@
#define CONFIG_BOOTP_SEND_HOSTNAME
#endif
+#ifdef CONFIG_USB_EHCI
+#define CONFIG_CMD_USB
+#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+#define CONFIG_USB_STORAGE
+#endif
+
#if !defined CONFIG_ENV_IS_IN_MMC && \
!defined CONFIG_ENV_IS_IN_NAND && \
!defined CONFIG_ENV_IS_IN_FAT && \