From mboxrd@z Thu Jan 1 00:00:00 1970 From: Hans de Goede Date: Sat, 19 Jul 2014 14:34:08 +0200 Subject: [U-Boot] [PATCH 3/3] ahci: provide sunxi SATA driver using AHCI platform framework In-Reply-To: <1405712321-12334-3-git-send-email-ijc@hellion.org.uk> References: <1405712297.26270.16.camel@hastur.hellion.org.uk> <1405712321-12334-3-git-send-email-ijc@hellion.org.uk> Message-ID: <53CA65C0.2090406@redhat.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi, On 07/18/2014 09:38 PM, Ian Campbell 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 PHY setup is derived from the Alwinner releases and Linux, but is mostly > undocumented. > > The Allwinner AHCI controller also requires some magic (and, again, > undocumented) DMA initialisation when starting a port. This is added under a > suitable ifdef. > > This option is enabled for Cubieboard, Cubieboard2 and Cubietruck based on > contents of Linux DTS files, including SATA power pin config taken from the > DTS. All build tested, but runtime tested on Cubieboard2 and Cubietruck only. > > Signed-off-by: Ian Campbell Looks good to me: Acked-by: Hans de Goede Regards, Hans > --- > arch/arm/cpu/armv7/sunxi/clock_sun4i.c | 4 ++ > arch/arm/include/asm/arch-sunxi/clock_sun4i.h | 11 ++-- > board/sunxi/Makefile | 1 + > board/sunxi/ahci.c | 84 +++++++++++++++++++++++++++ > boards.cfg | 10 ++-- > drivers/block/ahci.c | 16 +++++ > include/ahci.h | 4 ++ > include/configs/sunxi-common.h | 12 ++++ > 8 files changed, 133 insertions(+), 9 deletions(-) > create mode 100644 board/sunxi/ahci.c > > diff --git a/arch/arm/cpu/armv7/sunxi/clock_sun4i.c b/arch/arm/cpu/armv7/sunxi/clock_sun4i.c > index b8b16cf..ecbdb01 100644 > --- a/arch/arm/cpu/armv7/sunxi/clock_sun4i.c > +++ b/arch/arm/cpu/armv7/sunxi/clock_sun4i.c > @@ -39,6 +39,10 @@ void clock_init_safe(void) > 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 > > diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h > index 928f3f2..2531cbd 100644 > --- a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h > +++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h > @@ -218,10 +218,13 @@ struct sunxi_ccm_reg { > #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) > diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile > index 62acb8f..03f55cc 100644 > --- a/board/sunxi/Makefile > +++ b/board/sunxi/Makefile > @@ -10,6 +10,7 @@ > # > 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 > diff --git a/board/sunxi/ahci.c b/board/sunxi/ahci.c > new file mode 100644 > index 0000000..0c262ea > --- /dev/null > +++ b/board/sunxi/ahci.c > @@ -0,0 +1,84 @@ > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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); > +} > diff --git a/boards.cfg b/boards.cfg > index 035b5c7..f69bd32 100644 > --- a/boards.cfg > +++ b/boards.cfg > @@ -378,11 +378,11 @@ Active arm armv7 s5pc1xx samsung goni > Active arm armv7 s5pc1xx samsung smdkc100 smdkc100 - Minkyu Kang > Active arm armv7 socfpga altera socfpga socfpga_cyclone5 - - > Active arm armv7 sunxi - sunxi A13-OLinuXinoM sun5i:A13_OLINUXINOM,SPL,CONS_INDEX=2 Hans de Goede > -Active arm armv7 sunxi - sunxi Cubieboard sun4i:CUBIEBOARD,SPL,AXP209_POWER,SUNXI_EMAC Hans de Goede > -Active arm armv7 sunxi - sunxi Cubieboard2 sun7i:CUBIEBOARD2,SPL,SUNXI_GMAC Ian Campbell :Hans de Goede > -Active arm armv7 sunxi - sunxi Cubieboard2_FEL sun7i:CUBIEBOARD2,SPL_FEL,SUNXI_GMAC Ian Campbell :Hans de Goede > -Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,SPL,AXP209_POWER,SUNXI_GMAC,RGMII Ian Campbell :Hans de Goede > -Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL,AXP209_POWER,SUNXI_GMAC,RGMII Ian Campbell :Hans de Goede > +Active arm armv7 sunxi - sunxi Cubieboard sun4i:CUBIEBOARD,SPL,AXP209_POWER,SUNXI_EMAC,AHCI,SATAPWR=SUNXI_GPB(8) Hans de Goede > +Active arm armv7 sunxi - sunxi Cubieboard2 sun7i:CUBIEBOARD2,SPL,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8) Ian Campbell :Hans de Goede > +Active arm armv7 sunxi - sunxi Cubieboard2_FEL sun7i:CUBIEBOARD2,SPL_FEL,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8) Ian Campbell :Hans de Goede > +Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,SPL,AXP209_POWER,SUNXI_GMAC,RGMII,AHCI,SATAPWR=SUNXI_GPH(12) Ian Campbell :Hans de Goede > +Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL,AXP209_POWER,SUNXI_GMAC,RGMII,AHCI,SATAPWR=SUNXI_GPH(12) Ian Campbell :Hans de Goede > Active arm armv7 sunxi - sunxi r7-tv-dongle sun5i:R7DONGLE,SPL,AXP152_POWER Hans de Goede > Active arm armv7 u8500 st-ericsson snowball snowball - Mathieu Poirier > Active arm armv7 u8500 st-ericsson u8500 u8500_href - - > diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c > index 4df8046..dce99ad 100644 > --- a/drivers/block/ahci.c > +++ b/drivers/block/ahci.c > @@ -129,6 +129,14 @@ int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port) > 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 > @@ -213,6 +221,10 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) > 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. > */ > @@ -545,6 +557,10 @@ static int ahci_port_start(u8 port) > > 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); > diff --git a/include/ahci.h b/include/ahci.h > index 90e8509..35b8a8c 100644 > --- a/include/ahci.h > +++ b/include/ahci.h > @@ -58,6 +58,10 @@ > #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 */ > diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h > index 845b004..43eb718 100644 > --- a/include/configs/sunxi-common.h > +++ b/include/configs/sunxi-common.h > @@ -57,6 +57,18 @@ > #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 > >