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
 
 
 #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)
 
 #
 obj-y  += board.o
 obj-$(CONFIG_SUNXI_GMAC)       += gmac.o
+obj-$(CONFIG_SUNXI_AHCI)       += ahci.o
 obj-$(CONFIG_A13_OLINUXINOM)   += dram_a13_oli_micro.o
 obj-$(CONFIG_CUBIEBOARD)       += dram_cubieboard.o
 obj-$(CONFIG_CUBIEBOARD2)      += dram_cubieboard2.o
 
--- /dev/null
+#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);
+}
 
 CONFIG_SPL=y
-CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL_FEL,SUNXI_GMAC"
+CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL_FEL,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8)"
 +S:CONFIG_ARM=y
 +S:CONFIG_TARGET_SUN7I=y
 
 CONFIG_SPL=y
-CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL,SUNXI_GMAC"
+CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8)"
 +S:CONFIG_ARM=y
 +S:CONFIG_TARGET_SUN7I=y
 
 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)"
 +S:CONFIG_ARM=y
 +S:CONFIG_TARGET_SUN4I=y
 
 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)"
 +S:CONFIG_ARM=y
 +S:CONFIG_TARGET_SUN7I=y
 
 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)"
 +S:CONFIG_ARM=y
 +S:CONFIG_TARGET_SUN7I=y
 
        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
                        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.
                 */
 
        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);
 
 #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 */
 
 #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