[U-Boot] [PATCH v2 3/3] ahci: provide sunxi SATA driver using AHCI platform framework
Ian Campbell
ijc at hellion.org.uk
Thu Feb 20 15:48:16 CET 2014
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 at 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
+
+#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);
+
+ return 0;
+}
+
+void scsi_init(void)
+{
+ printf("SUNXI SCSI INIT\n");
+#ifdef CONFIG_SATAPWR
+ gpio_direction_output(CONFIG_SATAPWR, 1);
+#endif
+
+ sunxi_ahci_phy_init(SUNXI_SATA_BASE);
+
+ ahci_init(SUNXI_SATA_BASE);
+}
diff --git a/include/ahci.h b/include/ahci.h
index 90e8509..c94689c 100644
--- a/include/ahci.h
+++ b/include/ahci.h
@@ -58,6 +58,15 @@
#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
+#ifdef CONFIG_SCSI_AHCI_SUNXI
+#define PORT_DMA 0x70 /* SUNXI specific "DMA register" */
+
+#define PORT_DMA_SETUP_OFFSET 8 /* dma setup offset */
+#define PORT_DMA_SETUP_MASK (0xff << PORT_DMA_SETUP_OFFSET) /* dma mask */
+#define PORT_DMA_SETUP_INIT (0x44 << PORT_DMA_SETUP_OFFSET)
+#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/sunxi-common.h b/include/configs/sunxi-common.h
index d46a43f..be4c6b5 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -88,6 +88,18 @@
#define CONFIG_SYS_NAND_BASE 0x00
#endif
+#ifdef CONFIG_AHCI
+#define CONFIG_LIBATA
+#define CONFIG_SCSI_AHCI
+#define CONFIG_SCSI_AHCI_PLAT
+#define CONFIG_SCSI_AHCI_SUNXI
+#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
--
1.8.5.3
More information about the U-Boot
mailing list