This enables the necessary clocks, in AHB0 and in PLL6_CFG. 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. Tested on and enabled for the cubietruck. Signed-off-by: Ian Campbell <[email protected]> --- arch/arm/cpu/armv7/sunxi/clock.c | 4 ++ boards.cfg | 4 +- drivers/block/Makefile | 1 + drivers/block/ahci.c | 15 ++++++- drivers/block/ahci_sunxi.c | 95 ++++++++++++++++++++++++++++++++++++++++ include/ahci.h | 9 ++++ include/configs/sunxi-common.h | 10 +++++ 7 files changed, 135 insertions(+), 3 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..c94d3f2 100644 --- a/boards.cfg +++ b/boards.cfg @@ -366,8 +366,8 @@ Active arm armv7 sunxi - sunxi 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 Cubietruck sun7i:CUBIETRUCK,SPL,SUNXI_GMAC,RGMII,STATUSLED=245,STATUSLED1=244,STATUSLED2=235,STATUSLED3=231,FAST_MBUS,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,SATAPWR=SUNXI_GPH(12) - 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 DNS_M82 sun4i:DNS_M82,SPL - 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..dbfbba9 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -88,6 +88,16 @@ #define CONFIG_SYS_NAND_BASE 0x00 #endif +#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 + #define CONFIG_CMD_MEMORY #define CONFIG_CMD_SETEXPR -- 1.8.5.3 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/groups/opt_out.
