[U-Boot] [PATCH 3/3] ahci: provide sunxi SATA driver using AHCI platform framework

Hans de Goede
2014-07-19T12:34:08Z

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 <ijc@hellion.org.uk>

Looks good to me:

Acked-by: Hans de Goede <hdegoede@redhat.com>

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 <common.h>
> +#include <ahci.h>
> +#include <scsi.h>
> +#include <errno.h>
> +#include <asm/io.h>
> +#include <asm/gpio.h>
> +
> +#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 <mk7.kang@samsung.com>
> 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 <hdegoede@redhat.com>
> -Active arm armv7 sunxi - sunxi Cubieboard sun4i:CUBIEBOARD,SPL,AXP209_POWER,SUNXI_EMAC Hans de Goede <hdegoede@redhat.com>
> -Active arm armv7 sunxi - sunxi Cubieboard2 sun7i:CUBIEBOARD2,SPL,SUNXI_GMAC Ian Campbell <ijc@hellion.org.uk>:Hans de Goede <hdegoede@redhat.com>
> -Active arm armv7 sunxi - sunxi Cubieboard2_FEL sun7i:CUBIEBOARD2,SPL_FEL,SUNXI_GMAC Ian Campbell <ijc@hellion.org.uk>:Hans de Goede <hdegoede@redhat.com>
> -Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,SPL,AXP209_POWER,SUNXI_GMAC,RGMII Ian Campbell <ijc@hellion.org.uk>:Hans de Goede <hdegoede@redhat.com>
> -Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL,AXP209_POWER,SUNXI_GMAC,RGMII Ian Campbell <ijc@hellion.org.uk>:Hans de Goede <hdegoede@redhat.com>
> +Active arm armv7 sunxi - sunxi Cubieboard sun4i:CUBIEBOARD,SPL,AXP209_POWER,SUNXI_EMAC,AHCI,SATAPWR=SUNXI_GPB(8) Hans de Goede <hdegoede@redhat.com>
> +Active arm armv7 sunxi - sunxi Cubieboard2 sun7i:CUBIEBOARD2,SPL,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8) Ian Campbell <ijc@hellion.org.uk>:Hans de Goede <hdegoede@redhat.com>
> +Active arm armv7 sunxi - sunxi Cubieboard2_FEL sun7i:CUBIEBOARD2,SPL_FEL,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8) Ian Campbell <ijc@hellion.org.uk>:Hans de Goede <hdegoede@redhat.com>
> +Active arm armv7 sunxi - sunxi Cubietruck sun7i:CUBIETRUCK,SPL,AXP209_POWER,SUNXI_GMAC,RGMII,AHCI,SATAPWR=SUNXI_GPH(12) Ian Campbell <ijc@hellion.org.uk>:Hans de Goede <hdegoede@redhat.com>
> +Active arm armv7 sunxi - sunxi Cubietruck_FEL sun7i:CUBIETRUCK,SPL_FEL,AXP209_POWER,SUNXI_GMAC,RGMII,AHCI,SATAPWR=SUNXI_GPH(12) Ian Campbell <ijc@hellion.org.uk>:Hans de Goede <hdegoede@redhat.com>
> Active arm armv7 sunxi - sunxi r7-tv-dongle sun5i:R7DONGLE,SPL,AXP152_POWER Hans de Goede <hdegoede@redhat.com>
> Active arm armv7 u8500 st-ericsson snowball snowball - Mathieu Poirier <mathieu.poirier@linaro.org>
> 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
>
>