
On Thu, Feb 20, 2014 at 8:48 AM, Ian Campbell ijc@hellion.org.uk wrote:
This enables the necessary clocks, in AHB0 and in PLL6_CFG. This is done for sun7i only since I don't have access to any other sunxi platforms with sata included.
The bulk of the code is taken from the Linux ahci sunxi platform driver patches, adjusted for u-boot.
This adds the "PORT_DMA" tweaks to the core driver, under a suitable ifdef.
This option is enabled for Cubieboard, Cubieboard2, Cubietruck and Olinuxino Micro based on contents of Linux DTS files, including SATA power pin config taken from the DTS. All build tested, but runtime tested on cubietruck (FEL) only.
Signed-off-by: Ian Campbell ijc@hellion.org.uk
v2:
make AHCI configurable per board, enabled for cubieboard, cubieboard2, cubietruck and Olinuxino Micro.
arch/arm/cpu/armv7/sunxi/clock.c | 4 ++ boards.cfg | 18 ++++---- drivers/block/Makefile | 1 + drivers/block/ahci.c | 15 ++++++- drivers/block/ahci_sunxi.c | 95 ++++++++++++++++++++++++++++++++++++++++ include/ahci.h | 9 ++++ include/configs/sunxi-common.h | 12 +++++ 7 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 drivers/block/ahci_sunxi.c
diff --git a/arch/arm/cpu/armv7/sunxi/clock.c b/arch/arm/cpu/armv7/sunxi/clock.c index 06bc283..2cc274b 100644 --- a/arch/arm/cpu/armv7/sunxi/clock.c +++ b/arch/arm/cpu/armv7/sunxi/clock.c @@ -51,6 +51,10 @@ static void clock_init_safe(void) #ifdef CONFIG_SUN7I writel(0x1 << 6 | readl(&ccm->ahb_gate0), &ccm->ahb_gate0); writel(0x1 << 31 | readl(&ccm->pll6_cfg), &ccm->pll6_cfg); +#ifdef CONFIG_SCSI_AHCI_SUNXI
writel(0x1 << 25 |readl(&ccm->ahb_gate0), &ccm->ahb_gate0);
writel(0x1 << 14 | readl(&ccm->pll6_cfg), &ccm->pll6_cfg);
+#endif #endif } #endif diff --git a/boards.cfg b/boards.cfg index 100acc8..987bc54 100644 --- a/boards.cfg +++ b/boards.cfg @@ -354,8 +354,8 @@ Active arm armv7 sunxi - sunxi Active arm armv7 sunxi - sunxi A13-OLinuXinoM sun5i:A13_OLINUXINOM,SPL,NO_AXP,STATUSLED=201,CONS_INDEX=2 - Active arm armv7 sunxi - sunxi A13-OLinuXinoM_FEL sun5i:A13_OLINUXINOM,SPL_FEL,NO_AXP,STATUSLED=201,CONS_INDEX=2 - Active arm armv7 sunxi - sunxi A13_MID sun5i:A13_MID,SPL,CONS_INDEX=2 - -Active arm armv7 sunxi - sunxi A20-OLinuXino_MICRO sun7i:A20_OLINUXINO_M,CONS_INDEX=1,STATUSLED=226,SPL,SUNXI_EMAC - -Active arm armv7 sunxi - sunxi A20-OLinuXino_MICRO_FEL sun7i:A20_OLINUXINO_M,CONS_INDEX=1,STATUSLED=226,SPL_FEL,SUNXI_EMAC - +Active arm armv7 sunxi - sunxi A20-OLinuXino_MICRO sun7i:A20_OLINUXINO_M,CONS_INDEX=1,STATUSLED=226,SPL,SUNXI_EMAC,AHCI,SATAPWR=SUNXI_GPB(8) - +Active arm armv7 sunxi - sunxi A20-OLinuXino_MICRO_FEL sun7i:A20_OLINUXINO_M,CONS_INDEX=1,STATUSLED=226,SPL_FEL,SUNXI_EMAC,AHCI,SATAPWR=SUNXI_GPB(8) - Active arm armv7 sunxi - sunxi Auxtek-T003 sun5i:AUXTEK_T003,SPL,AXP152_POWER,STATUSLED=34 - Active arm armv7 sunxi - sunxi Auxtek-T004 sun5i:AUXTEK_T004,SPL,AXP152_POWER,STATUSLED=34 - Active arm armv7 sunxi - sunxi ba10_tv_box sun4i:BA10_TV_BOX,SPL,SUNXI_EMAC - @@ -363,13 +363,13 @@ Active arm armv7 sunxi - sunxi Active arm armv7 sunxi - sunxi Coby_MID8042 sun4i:COBY_MID8042,SPL - Active arm armv7 sunxi - sunxi Coby_MID9742 sun4i:COBY_MID9742,SPL - Active arm armv7 sunxi - sunxi Colombus sun6i:COLOMBUS - -Active arm armv7 sunxi - sunxi Cubieboard sun4i:CUBIEBOARD,SPL,SUNXI_EMAC,STATUSLED=244,STATUSLED1=245 - -Active arm armv7 sunxi - sunxi Cubieboard2 sun7i:CUBIEBOARD2,SPL,SUNXI_GMAC,STATUSLED=244,STATUSLED1=245,FAST_MBUS - -Active arm armv7 sunxi - sunxi Cubieboard2_FEL sun7i:CUBIEBOARD2,SPL_FEL,SUNXI_GMAC,STATUSLED=244,STATUSLED1=245,FAST_MBUS - -Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,SPL,SUNXI_GMAC,RGMII,STATUSLED=245,STATUSLED1=244,STATUSLED2=235,STATUSLED3=231,FAST_MBUS - -Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL,SUNXI_GMAC,RGMII,STATUSLED=245,STATUSLED1=244,STATUSLED2=235,STATUSLED3=231,FAST_MBUS - -Active arm armv7 sunxi - sunxi Cubieboard_512 sun4i:CUBIEBOARD_512,SPL,SUNXI_EMAC,STATUSLED=244,STATUSLED1=245 - -Active arm armv7 sunxi - sunxi Cubieboard_FEL sun4i:CUBIEBOARD,SPL_FEL,SUNXI_EMAC,STATUSLED=244,STATUSLED1=245 - +Active arm armv7 sunxi - sunxi Cubieboard sun4i:CUBIEBOARD,SPL,SUNXI_EMAC,STATUSLED=244,STATUSLED1=245,AHCI,SATAPWR=SUNXI_GPB(8) - +Active arm armv7 sunxi - sunxi Cubieboard2 sun7i:CUBIEBOARD2,SPL,SUNXI_GMAC,STATUSLED=244,STATUSLED1=245,FAST_MBUS,AHCI,SATAPWR=SUNXI_GPB(8) - +Active arm armv7 sunxi - sunxi Cubieboard2_FEL sun7i:CUBIEBOARD2,SPL_FEL,SUNXI_GMAC,STATUSLED=244,STATUSLED1=245,FAST_MBUS,AHCI,SATAPWR=SUNXI_GPB(8) - +Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,SPL,SUNXI_GMAC,RGMII,STATUSLED=245,STATUSLED1=244,STATUSLED2=235,STATUSLED3=231,FAST_MBUS,AHCI,SATAPWR=SUNXI_GPH(12) - +Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL,SUNXI_GMAC,RGMII,STATUSLED=245,STATUSLED1=244,STATUSLED2=235,STATUSLED3=231,FAST_MBUS,AHCI,SATAPWR=SUNXI_GPH(12) - +Active arm armv7 sunxi - sunxi Cubieboard_512 sun4i:CUBIEBOARD_512,SPL,SUNXI_EMAC,STATUSLED=244,STATUSLED1=245,AHCI,SATAPWR=SUNXI_GPB(8) - +Active arm armv7 sunxi - sunxi Cubieboard_FEL sun4i:CUBIEBOARD,SPL_FEL,SUNXI_EMAC,STATUSLED=244,STATUSLED1=245,AHCI,SATAPWR=SUNXI_GPB(8) - Active arm armv7 sunxi - sunxi DNS_M82 sun4i:DNS_M82,SPL - Active arm armv7 sunxi - sunxi EOMA68_A10 sun4i:EOMA68_A10,SPL,MMC_SUNXI_SLOT=3,SUNXI_EMAC - Active arm armv7 sunxi - sunxi EOMA68_A10_FEL sun4i:EOMA68_A10,SPL_FEL,MMC_SUNXI_SLOT=3,SUNXI_EMAC - diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 4e94378..e77188b 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -6,6 +6,7 @@ #
obj-$(CONFIG_SCSI_AHCI) += ahci.o +obj-$(CONFIG_SCSI_AHCI_SUNXI) += ahci_sunxi.o obj-$(CONFIG_ATA_PIIX) += ata_piix.o obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o obj-$(CONFIG_FSL_SATA) += fsl_sata.o diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 90a0719..32be726 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -213,6 +213,13 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) msleep(500); }
+#ifdef CONFIG_SCSI_AHCI_SUNXI
tmp = readl(port_mmio + PORT_DMA);
tmp &= ~PORT_DMA_SETUP_MASK;
tmp |= PORT_DMA_SETUP_INIT;
writel_with_flush(tmp, port_mmio + PORT_DMA);
+#endif
/* Add the spinup command to whatever mode bits may * already be on in the command register. */
@@ -490,7 +497,7 @@ static int ahci_port_start(u8 port) struct ahci_ioports *pp = &(probe_ent->port[port]); volatile u8 *port_mmio = (volatile u8 *)pp->port_mmio; u32 port_status;
u32 mem;
u32 mem, tmp; debug("Enter start port: %d\n", port); port_status = readl(port_mmio + PORT_SCR_STAT);
@@ -540,6 +547,12 @@ static int ahci_port_start(u8 port)
writel_with_flush(pp->rx_fis, port_mmio + PORT_FIS_ADDR);
+#ifdef CONFIG_SCSI_AHCI_SUNXI
tmp = readl(port_mmio + PORT_DMA);
tmp &= ~PORT_DMA_SETUP_MASK;
tmp |= PORT_DMA_SETUP_INIT;
writel_with_flush(tmp, port_mmio + PORT_DMA);
+#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/block/ahci_sunxi.c b/drivers/block/ahci_sunxi.c new file mode 100644 index 0000000..2ae742d --- /dev/null +++ b/drivers/block/ahci_sunxi.c @@ -0,0 +1,95 @@ +#include <common.h> +#include <ahci.h> +#include <scsi.h> +#include <asm/io.h> +#include <asm/gpio.h>
+#define AHCI_BISTAFR 0x00a0 +#define AHCI_BISTCR 0x00a4 +#define AHCI_BISTFCTR 0x00a8 +#define AHCI_BISTSR 0x00ac +#define AHCI_BISTDECR 0x00b0 +#define AHCI_DIAGNR0 0x00b4 +#define AHCI_DIAGNR1 0x00b8 +#define AHCI_OOBR 0x00bc +#define AHCI_PHYCS0R 0x00c0 +#define AHCI_PHYCS1R 0x00c4 +#define AHCI_PHYCS2R 0x00c8 +#define AHCI_TIMER1MS 0x00e0 +#define AHCI_GPARAM1R 0x00e8 +#define AHCI_GPARAM2R 0x00ec +#define AHCI_PPARAMR 0x00f0 +#define AHCI_TESTR 0x00f4 +#define AHCI_VERSIONR 0x00f8 +#define AHCI_IDR 0x00fc +#define AHCI_RWCR 0x00fc +#define AHCI_P0DMACR 0x0170 +#define AHCI_P0PHYCR 0x0178 +#define AHCI_P0PHYSR 0x017c
These registers are not sunxi specific, but part of a certain vendor's IP found in several SOCs. I can't tell you who, but it shouldn't be too hard to figure out.
+#define BIT(x) (1<<x) +static u32 sunxi_getbits(u8 *reg, u8 mask, u8 shift) +{
return (readl(reg) >> shift) & mask;
+}
+static int sunxi_ahci_phy_init(u32 base) +{
u8 *reg_base = (u8 *)base;
u32 reg_val;
int timeout;
/* This magic is from the original code */
writel(0, reg_base + AHCI_RWCR);
mdelay(5);
setbits_le32(reg_base + AHCI_PHYCS1R, BIT(19));
clrsetbits_le32(reg_base + AHCI_PHYCS0R,
(0x7 << 24),
(0x5 << 24) | BIT(23) | BIT(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, BIT(28) | BIT(15));
clrbits_le32(reg_base + AHCI_PHYCS1R, BIT(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 = 0x100000;
do {
reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28);
} while (--timeout && (reg_val != 0x2));
if (!timeout)
printf("PHY power up failed.\n");
setbits_le32(reg_base + AHCI_PHYCS2R, (0x1 << 24));
timeout = 0x100000;
do {
reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24);
} while (--timeout && reg_val);
if (!timeout)
printf("PHY calibration failed.\n");
mdelay(15);
writel(0x7, reg_base + AHCI_RWCR);
I would guess this code or something very similar already exists in u-boot.
Rob