[U-Boot] [PATCH v2 0/3] uboot sata support for sunxi platform

This is the second version of my series to add support for AHCI to the sunxi platform. This uses the existing ahci platform support already present in u-boot. Most of the sunxi specific code comes from the Linux platform patches.
As requested I am also cross posting to the main uboot mailing list since the first two patches are generic and don't rely on sunxi stuff and so could go into mainline now.
I've tested this only on cubietruck, but it is enabled for Olinino Micro, cubieboard and cubieboard2 based on inspection of the Linux DTS files.
Since last time I've made this a per-board option rather than enabling for all sunxi platforms, some of which may not have a SATA connector, or even an AHCI controller in the processor at all.
Ian.

This allow the platform to register the platform ahci device.
Signed-off-by: Ian Campbell ijc@hellion.org.uk --- In theory this could perhaps be used by highbank. I have access to a Midway system (close enough for testing purposes, I think) but since Calxeda has folded I'm not sure it is worth it, and I am not entirely keen on reflashing firmware on the system I have access too (no safety net)... --- arch/arm/lib/board.c | 6 ++++++ drivers/block/ahci.c | 5 +++++ 2 files changed, 11 insertions(+)
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 34f50b0..fe381a3 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -33,6 +33,7 @@ #include <nand.h> #include <onenand_uboot.h> #include <mmc.h> +#include <scsi.h> #include <libfdt.h> #include <fdtdec.h> #include <post.h> @@ -593,6 +594,11 @@ void board_init_r(gd_t *id, ulong dest_addr) mmc_initialize(gd->bd); #endif
+#ifdef CONFIG_CMD_SCSI + puts("SCSI: "); + scsi_init(); +#endif + #ifdef CONFIG_HAS_DATAFLASH AT91F_DataflashInit(); dataflash_print_info(); diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 0daad36..d5370fa 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -924,6 +924,11 @@ int ahci_init(u32 base) err_out: return rc; } + +void __weak scsi_init(void) +{ +} + #endif
/*

On Thu, Feb 20, 2014 at 8:48 AM, Ian Campbell ijc@hellion.org.uk wrote:
This allow the platform to register the platform ahci device.
Signed-off-by: Ian Campbell ijc@hellion.org.uk
In theory this could perhaps be used by highbank. I have access to a Midway system (close enough for testing purposes, I think) but since Calxeda has folded I'm not sure it is worth it, and I am not entirely keen on reflashing firmware on the system I have access too (no safety net)...
You can actually chainload highbank/midway u-boot. Load u-boot.bin to 0x8000 and do "go 0x8000".
You can't really brick a system by updating u-boot. There are a few things not in mainline, but it is mainly the env which is separate.
Rob
arch/arm/lib/board.c | 6 ++++++ drivers/block/ahci.c | 5 +++++ 2 files changed, 11 insertions(+)
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 34f50b0..fe381a3 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -33,6 +33,7 @@ #include <nand.h> #include <onenand_uboot.h> #include <mmc.h> +#include <scsi.h> #include <libfdt.h> #include <fdtdec.h> #include <post.h> @@ -593,6 +594,11 @@ void board_init_r(gd_t *id, ulong dest_addr) mmc_initialize(gd->bd); #endif
+#ifdef CONFIG_CMD_SCSI
puts("SCSI: ");
scsi_init();
+#endif
#ifdef CONFIG_HAS_DATAFLASH AT91F_DataflashInit(); dataflash_print_info(); diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 0daad36..d5370fa 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -924,6 +924,11 @@ int ahci_init(u32 base) err_out: return rc; }
+void __weak scsi_init(void) +{ +}
#endif
/*
1.8.5.3
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

I have observed timeouts on a cubietruck.
The increase to 40ms is completely arbitrary and Works For Me(tm). I couldn't find a good reference for how long you are supposed to wait, although googling around it seems like tens of ms rather than single digits is more common. I don't think there is any harm in waiting a bit longer.
Signed-off-by: Ian Campbell ijc@hellion.org.uk --- drivers/block/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index d5370fa..90a0719 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -41,7 +41,7 @@ u16 *ataid[AHCI_MAX_PORTS]; #define WAIT_MS_SPINUP 20000 #define WAIT_MS_DATAIO 5000 #define WAIT_MS_FLUSH 5000 -#define WAIT_MS_LINKUP 4 +#define WAIT_MS_LINKUP 40
static inline u32 ahci_port_base(u32 base, u32 port) {

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

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

On Thu, 2014-02-20 at 09:24 -0600, Rob Herring wrote:
+#define AHCI_PHYCS0R 0x00c0 +#define AHCI_PHYCS1R 0x00c4 +#define AHCI_PHYCS2R 0x00c8
[...]
+#define AHCI_RWCR 0x00fc
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.
Actually, only the 4 above are used here and if I'm guessing which certain vendor you mean correctly then the code for those has these in its register map as reserved and doesn't touch them (this is true in both of the similar drivers I looked at).
The rest of the registers in that list did look a lot the DW part (judging from the existing u-boot drivers) though.
+#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) +{
[...magic...]
I would guess this code or something very similar already exists in u-boot.
I've had a look in the most obvious files in drivers/block/ and I don't see anything. Perhaps I should look harder.
FWIW I also couldn't find anything similar in linux/drivers/ata.
Ian.

On Thu, Feb 20, 2014 at 10:06 AM, Ian Campbell ijc@hellion.org.uk wrote:
On Thu, 2014-02-20 at 09:24 -0600, Rob Herring wrote:
+#define AHCI_PHYCS0R 0x00c0 +#define AHCI_PHYCS1R 0x00c4 +#define AHCI_PHYCS2R 0x00c8
[...]
+#define AHCI_RWCR 0x00fc
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.
Actually, only the 4 above are used here and if I'm guessing which certain vendor you mean correctly then the code for those has these in its register map as reserved and doesn't touch them (this is true in both of the similar drivers I looked at).
The rest of the registers in that list did look a lot the DW part (judging from the existing u-boot drivers) though.
There may be others that do this setup in firmware.
+#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) +{
[...magic...]
I would guess this code or something very similar already exists in u-boot.
I've had a look in the most obvious files in drivers/block/ and I don't see anything. Perhaps I should look harder.
FWIW I also couldn't find anything similar in linux/drivers/ata.
I thought iMX needed something like this, but it doesn't look like it now. Perhaps they figured out the bootrom is doing all this and it is not really necessary to redo.
I don't really have any concrete suggestions here. I'm just highlighting potential duplication. We already have 2 AHCI drivers in u-boot. I think dwc_ahsata.c is the cleaner implementation, but ahci.c is probably more well tested now. The Chromium folks have done various fixes as has Calxeda. I think dwc_ahsata.c is only used for i.MX and SATA is not the primary storage interface for most i.MX designs.
Rob

On Thu, 2014-02-20 at 14:06 -0600, Rob Herring wrote:
On Thu, Feb 20, 2014 at 10:06 AM, Ian Campbell ijc@hellion.org.uk wrote:
On Thu, 2014-02-20 at 09:24 -0600, Rob Herring wrote:
+#define AHCI_PHYCS0R 0x00c0 +#define AHCI_PHYCS1R 0x00c4 +#define AHCI_PHYCS2R 0x00c8
[...]
+#define AHCI_RWCR 0x00fc
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.
Actually, only the 4 above are used here and if I'm guessing which certain vendor you mean correctly then the code for those has these in its register map as reserved and doesn't touch them (this is true in both of the similar drivers I looked at).
The rest of the registers in that list did look a lot the DW part (judging from the existing u-boot drivers) though.
There may be others that do this setup in firmware.
Someone pointed me to http://linux-sunxi.org/Used_IP_cores which suggests that while the SATA block is DW the PHY might be Allwinner's own -- that would fit with having found a bunch of unusual registers in a gap in the DW address map...
In v3 I'll drop all the unused #defines, which apart from being the sane thing to do ought to make it look less like I'm duplicating DW stuff here.
+#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) +{
[...magic...]
I would guess this code or something very similar already exists in u-boot.
I've had a look in the most obvious files in drivers/block/ and I don't see anything. Perhaps I should look harder.
FWIW I also couldn't find anything similar in linux/drivers/ata.
I thought iMX needed something like this, but it doesn't look like it now. Perhaps they figured out the bootrom is doing all this and it is not really necessary to redo.
I don't really have any concrete suggestions here. I'm just highlighting potential duplication.
Thanks for doing so, I don't want to be responsible for YASD (Yet Another SATA Driver...)
We already have 2 AHCI drivers in u-boot. I think dwc_ahsata.c is the cleaner implementation, but ahci.c is probably more well tested now. The Chromium folks have done various fixes as has Calxeda. I think dwc_ahsata.c is only used for i.MX and SATA is not the primary storage interface for most i.MX designs.
It looked to me like the ahci.c one was a better bet going forward, since it seems more generic etc and it supports the "platform ahci" model, which was a good fit. Also I knew ahci.c was good from my use on the Calxeda platforms.
I could try switching to dwc_ahsata.c if people strongly prefer.
Ian.
participants (2)
-
Ian Campbell
-
Rob Herring