瀏覽代碼

Merge branch 'u-boot-sunxi/master' into 'u-boot-arm/master'

Albert ARIBAUD 10 年之前
父節點
當前提交
1899fac925
共有 48 個文件被更改,包括 982 次插入13 次删除
  1. 3 0
      arch/arm/cpu/armv7/sunxi/Makefile
  2. 5 0
      arch/arm/cpu/armv7/sunxi/board.c
  3. 4 0
      arch/arm/cpu/armv7/sunxi/clock_sun4i.c
  4. 162 0
      arch/arm/cpu/armv7/sunxi/psci.S
  5. 11 4
      arch/arm/include/asm/arch-sunxi/clock_sun4i.h
  6. 17 2
      board/sunxi/MAINTAINERS
  7. 16 0
      board/sunxi/Makefile
  8. 84 0
      board/sunxi/ahci.c
  9. 31 0
      board/sunxi/dram_a10_olinuxino_l.c
  10. 31 0
      board/sunxi/dram_a10s_olinuxino_m.c
  11. 31 0
      board/sunxi/dram_a13_olinuxino.c
  12. 31 0
      board/sunxi/dram_bananapi.c
  13. 31 0
      board/sunxi/dram_linksprite_pcduino3.c
  14. 31 0
      board/sunxi/dram_sun4i_360_1024_iow16.c
  15. 31 0
      board/sunxi/dram_sun4i_360_1024_iow8.c
  16. 31 0
      board/sunxi/dram_sun4i_360_512.c
  17. 31 0
      board/sunxi/dram_sun4i_384_1024_iow8.c
  18. 31 0
      board/sunxi/dram_sun7i_384_1024_iow16.c
  19. 31 0
      board/sunxi/dram_sun7i_384_512_busw16_iow16.c
  20. 4 0
      configs/A10-OLinuXino-Lime_defconfig
  21. 4 0
      configs/A10s-OLinuXino-M_defconfig
  22. 1 1
      configs/A13-OLinuXinoM_defconfig
  23. 4 0
      configs/A13-OLinuXino_defconfig
  24. 4 0
      configs/A20-OLinuXino_MICRO_defconfig
  25. 4 0
      configs/Auxtek-T004_defconfig
  26. 4 0
      configs/Bananapi_defconfig
  27. 1 1
      configs/Cubieboard2_FEL_defconfig
  28. 1 1
      configs/Cubieboard2_defconfig
  29. 1 1
      configs/Cubieboard_defconfig
  30. 1 1
      configs/Cubietruck_FEL_defconfig
  31. 1 1
      configs/Cubietruck_defconfig
  32. 4 0
      configs/Linksprite_pcDuino3_defconfig
  33. 4 0
      configs/Mele_A1000G_defconfig
  34. 4 0
      configs/Mele_A1000_defconfig
  35. 4 0
      configs/Mini-X-1Gb_defconfig
  36. 4 0
      configs/Mini-X_defconfig
  37. 4 0
      configs/ba10_tv_box_defconfig
  38. 4 0
      configs/i12-tvbox_defconfig
  39. 4 0
      configs/qt840a_defconfig
  40. 1 1
      configs/r7-tv-dongle_defconfig
  41. 16 0
      drivers/block/ahci.c
  42. 1 0
      drivers/usb/host/Makefile
  43. 201 0
      drivers/usb/host/ehci-sunxi.c
  44. 4 0
      include/ahci.h
  45. 12 0
      include/configs/sun4i.h
  46. 5 0
      include/configs/sun5i.h
  47. 19 0
      include/configs/sun7i.h
  48. 18 0
      include/configs/sunxi-common.h

+ 3 - 0
arch/arm/cpu/armv7/sunxi/Makefile

@@ -17,6 +17,9 @@ obj-$(CONFIG_SUN7I)	+= clock_sun4i.o
 
 ifndef CONFIG_SPL_BUILD
 obj-y	+= cpu_info.o
+ifdef CONFIG_ARMV7_PSCI
+obj-y	+= psci.o
+endif
 endif
 
 ifdef CONFIG_SPL_BUILD

+ 5 - 0
arch/arm/cpu/armv7/sunxi/board.c

@@ -129,6 +129,11 @@ int cpu_eth_init(bd_t *bis)
 {
 	__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) {

+ 4 - 0
arch/arm/cpu/armv7/sunxi/clock_sun4i.c

@@ -39,6 +39,10 @@ void clock_init_safe(void)
 	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
 

+ 162 - 0
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

+ 11 - 4
arch/arm/include/asm/arch-sunxi/clock_sun4i.h

@@ -218,10 +218,13 @@ struct sunxi_ccm_reg {
 #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 @@ struct sunxi_ccm_reg {
 #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 */

+ 17 - 2
board/sunxi/MAINTAINERS

@@ -2,11 +2,26 @@ SUNXI BOARD
 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>

+ 16 - 0
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

+ 84 - 0
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);
+}

+ 31 - 0
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);
+}

+ 31 - 0
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);
+}

+ 31 - 0
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);
+}

+ 31 - 0
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);
+}

+ 31 - 0
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);
+}

+ 31 - 0
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);
+}

+ 31 - 0
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);
+}

+ 31 - 0
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);
+}

+ 31 - 0
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);
+}

+ 31 - 0
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);
+}

+ 31 - 0
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);
+}

+ 4 - 0
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

+ 4 - 0
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

+ 1 - 1
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

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
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

+ 1 - 1
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

+ 1 - 1
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

+ 1 - 1
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

+ 1 - 1
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

+ 1 - 1
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

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
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

+ 4 - 0
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

+ 1 - 1
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

+ 16 - 0
drivers/block/ahci.c

@@ -129,6 +129,14 @@ int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port)
 	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 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 			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 @@ static int ahci_port_start(u8 port)
 
 	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);

+ 1 - 0
drivers/usb/host/Makefile

@@ -35,6 +35,7 @@ obj-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o
 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

+ 201 - 0
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;
+}

+ 4 - 0
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 */

+ 12 - 0
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
  */

+ 5 - 0
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
  */

+ 19 - 0
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
  */

+ 18 - 0
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 && \