12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2c5754b52SOlliver Schinagl /* 3c5754b52SOlliver Schinagl * Allwinner sunxi AHCI SATA platform driver 4c5754b52SOlliver Schinagl * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl> 5c5754b52SOlliver Schinagl * Copyright 2014 Hans de Goede <hdegoede@redhat.com> 6c5754b52SOlliver Schinagl * 7c5754b52SOlliver Schinagl * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov 8c5754b52SOlliver Schinagl * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>, 9c5754b52SOlliver Schinagl * Daniel Wang <danielwang@allwinnertech.com> 10c5754b52SOlliver Schinagl */ 11c5754b52SOlliver Schinagl 12c5754b52SOlliver Schinagl #include <linux/ahci_platform.h> 13c5754b52SOlliver Schinagl #include <linux/clk.h> 14c5754b52SOlliver Schinagl #include <linux/errno.h> 15c5754b52SOlliver Schinagl #include <linux/kernel.h> 16c5754b52SOlliver Schinagl #include <linux/module.h> 17c5754b52SOlliver Schinagl #include <linux/of_device.h> 18c5754b52SOlliver Schinagl #include <linux/platform_device.h> 19c5754b52SOlliver Schinagl #include <linux/regulator/consumer.h> 20c5754b52SOlliver Schinagl #include "ahci.h" 21c5754b52SOlliver Schinagl 22018d5ef2SAkinobu Mita #define DRV_NAME "ahci-sunxi" 23018d5ef2SAkinobu Mita 2435c16a8fSHans de Goede /* Insmod parameters */ 2535c16a8fSHans de Goede static bool enable_pmp; 2635c16a8fSHans de Goede module_param(enable_pmp, bool, 0); 2735c16a8fSHans de Goede MODULE_PARM_DESC(enable_pmp, 2835c16a8fSHans de Goede "Enable support for sata port multipliers, only use if you use a pmp!"); 2935c16a8fSHans de Goede 30c5754b52SOlliver Schinagl #define AHCI_BISTAFR 0x00a0 31c5754b52SOlliver Schinagl #define AHCI_BISTCR 0x00a4 32c5754b52SOlliver Schinagl #define AHCI_BISTFCTR 0x00a8 33c5754b52SOlliver Schinagl #define AHCI_BISTSR 0x00ac 34c5754b52SOlliver Schinagl #define AHCI_BISTDECR 0x00b0 35c5754b52SOlliver Schinagl #define AHCI_DIAGNR0 0x00b4 36c5754b52SOlliver Schinagl #define AHCI_DIAGNR1 0x00b8 37c5754b52SOlliver Schinagl #define AHCI_OOBR 0x00bc 38c5754b52SOlliver Schinagl #define AHCI_PHYCS0R 0x00c0 39c5754b52SOlliver Schinagl #define AHCI_PHYCS1R 0x00c4 40c5754b52SOlliver Schinagl #define AHCI_PHYCS2R 0x00c8 41c5754b52SOlliver Schinagl #define AHCI_TIMER1MS 0x00e0 42c5754b52SOlliver Schinagl #define AHCI_GPARAM1R 0x00e8 43c5754b52SOlliver Schinagl #define AHCI_GPARAM2R 0x00ec 44c5754b52SOlliver Schinagl #define AHCI_PPARAMR 0x00f0 45c5754b52SOlliver Schinagl #define AHCI_TESTR 0x00f4 46c5754b52SOlliver Schinagl #define AHCI_VERSIONR 0x00f8 47c5754b52SOlliver Schinagl #define AHCI_IDR 0x00fc 48c5754b52SOlliver Schinagl #define AHCI_RWCR 0x00fc 49c5754b52SOlliver Schinagl #define AHCI_P0DMACR 0x0170 50c5754b52SOlliver Schinagl #define AHCI_P0PHYCR 0x0178 51c5754b52SOlliver Schinagl #define AHCI_P0PHYSR 0x017c 52c5754b52SOlliver Schinagl 53c5754b52SOlliver Schinagl static void sunxi_clrbits(void __iomem *reg, u32 clr_val) 54c5754b52SOlliver Schinagl { 55c5754b52SOlliver Schinagl u32 reg_val; 56c5754b52SOlliver Schinagl 57c5754b52SOlliver Schinagl reg_val = readl(reg); 58c5754b52SOlliver Schinagl reg_val &= ~(clr_val); 59c5754b52SOlliver Schinagl writel(reg_val, reg); 60c5754b52SOlliver Schinagl } 61c5754b52SOlliver Schinagl 62c5754b52SOlliver Schinagl static void sunxi_setbits(void __iomem *reg, u32 set_val) 63c5754b52SOlliver Schinagl { 64c5754b52SOlliver Schinagl u32 reg_val; 65c5754b52SOlliver Schinagl 66c5754b52SOlliver Schinagl reg_val = readl(reg); 67c5754b52SOlliver Schinagl reg_val |= set_val; 68c5754b52SOlliver Schinagl writel(reg_val, reg); 69c5754b52SOlliver Schinagl } 70c5754b52SOlliver Schinagl 71c5754b52SOlliver Schinagl static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val) 72c5754b52SOlliver Schinagl { 73c5754b52SOlliver Schinagl u32 reg_val; 74c5754b52SOlliver Schinagl 75c5754b52SOlliver Schinagl reg_val = readl(reg); 76c5754b52SOlliver Schinagl reg_val &= ~(clr_val); 77c5754b52SOlliver Schinagl reg_val |= set_val; 78c5754b52SOlliver Schinagl writel(reg_val, reg); 79c5754b52SOlliver Schinagl } 80c5754b52SOlliver Schinagl 81c5754b52SOlliver Schinagl static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift) 82c5754b52SOlliver Schinagl { 83c5754b52SOlliver Schinagl return (readl(reg) >> shift) & mask; 84c5754b52SOlliver Schinagl } 85c5754b52SOlliver Schinagl 86c5754b52SOlliver Schinagl static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base) 87c5754b52SOlliver Schinagl { 88c5754b52SOlliver Schinagl u32 reg_val; 89c5754b52SOlliver Schinagl int timeout; 90c5754b52SOlliver Schinagl 91c5754b52SOlliver Schinagl /* This magic is from the original code */ 92c5754b52SOlliver Schinagl writel(0, reg_base + AHCI_RWCR); 93d2ec147aSHans de Goede msleep(5); 94c5754b52SOlliver Schinagl 95c5754b52SOlliver Schinagl sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19)); 96c5754b52SOlliver Schinagl sunxi_clrsetbits(reg_base + AHCI_PHYCS0R, 97c5754b52SOlliver Schinagl (0x7 << 24), 98c5754b52SOlliver Schinagl (0x5 << 24) | BIT(23) | BIT(18)); 99c5754b52SOlliver Schinagl sunxi_clrsetbits(reg_base + AHCI_PHYCS1R, 100c5754b52SOlliver Schinagl (0x3 << 16) | (0x1f << 8) | (0x3 << 6), 101c5754b52SOlliver Schinagl (0x2 << 16) | (0x6 << 8) | (0x2 << 6)); 102c5754b52SOlliver Schinagl sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15)); 103c5754b52SOlliver Schinagl sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19)); 104c5754b52SOlliver Schinagl sunxi_clrsetbits(reg_base + AHCI_PHYCS0R, 105c5754b52SOlliver Schinagl (0x7 << 20), (0x3 << 20)); 106c5754b52SOlliver Schinagl sunxi_clrsetbits(reg_base + AHCI_PHYCS2R, 107c5754b52SOlliver Schinagl (0x1f << 5), (0x19 << 5)); 108d2ec147aSHans de Goede msleep(5); 109c5754b52SOlliver Schinagl 110c5754b52SOlliver Schinagl sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19)); 111c5754b52SOlliver Schinagl 112c5754b52SOlliver Schinagl timeout = 250; /* Power up takes aprox 50 us */ 113c5754b52SOlliver Schinagl do { 114c5754b52SOlliver Schinagl reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28); 115c5754b52SOlliver Schinagl if (reg_val == 0x02) 116c5754b52SOlliver Schinagl break; 117c5754b52SOlliver Schinagl 118c5754b52SOlliver Schinagl if (--timeout == 0) { 119c5754b52SOlliver Schinagl dev_err(dev, "PHY power up failed.\n"); 120c5754b52SOlliver Schinagl return -EIO; 121c5754b52SOlliver Schinagl } 122c5754b52SOlliver Schinagl udelay(1); 123c5754b52SOlliver Schinagl } while (1); 124c5754b52SOlliver Schinagl 125c5754b52SOlliver Schinagl sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24)); 126c5754b52SOlliver Schinagl 127c5754b52SOlliver Schinagl timeout = 100; /* Calibration takes aprox 10 us */ 128c5754b52SOlliver Schinagl do { 129c5754b52SOlliver Schinagl reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24); 130c5754b52SOlliver Schinagl if (reg_val == 0x00) 131c5754b52SOlliver Schinagl break; 132c5754b52SOlliver Schinagl 133c5754b52SOlliver Schinagl if (--timeout == 0) { 134c5754b52SOlliver Schinagl dev_err(dev, "PHY calibration failed.\n"); 135c5754b52SOlliver Schinagl return -EIO; 136c5754b52SOlliver Schinagl } 137c5754b52SOlliver Schinagl udelay(1); 138c5754b52SOlliver Schinagl } while (1); 139c5754b52SOlliver Schinagl 140d2ec147aSHans de Goede msleep(15); 141c5754b52SOlliver Schinagl 142c5754b52SOlliver Schinagl writel(0x7, reg_base + AHCI_RWCR); 143c5754b52SOlliver Schinagl 144c5754b52SOlliver Schinagl return 0; 145c5754b52SOlliver Schinagl } 146c5754b52SOlliver Schinagl 147c5754b52SOlliver Schinagl static void ahci_sunxi_start_engine(struct ata_port *ap) 148c5754b52SOlliver Schinagl { 149c5754b52SOlliver Schinagl void __iomem *port_mmio = ahci_port_base(ap); 150c5754b52SOlliver Schinagl struct ahci_host_priv *hpriv = ap->host->private_data; 151c5754b52SOlliver Schinagl 152120357eaSUenal Mutlu /* Setup DMA before DMA start 153120357eaSUenal Mutlu * 154120357eaSUenal Mutlu * NOTE: A similar SoC with SATA/AHCI by Texas Instruments documents 155120357eaSUenal Mutlu * this Vendor Specific Port (P0DMACR, aka PxDMACR) in its 156120357eaSUenal Mutlu * User's Guide document (TMS320C674x/OMAP-L1x Processor 157120357eaSUenal Mutlu * Serial ATA (SATA) Controller, Literature Number: SPRUGJ8C, 158120357eaSUenal Mutlu * March 2011, Chapter 4.33 Port DMA Control Register (P0DMACR), 159120357eaSUenal Mutlu * p.68, https://www.ti.com/lit/ug/sprugj8c/sprugj8c.pdf) 160120357eaSUenal Mutlu * as equivalent to the following struct: 161120357eaSUenal Mutlu * 162120357eaSUenal Mutlu * struct AHCI_P0DMACR_t 163120357eaSUenal Mutlu * { 164120357eaSUenal Mutlu * unsigned TXTS : 4; 165120357eaSUenal Mutlu * unsigned RXTS : 4; 166120357eaSUenal Mutlu * unsigned TXABL : 4; 167120357eaSUenal Mutlu * unsigned RXABL : 4; 168120357eaSUenal Mutlu * unsigned Reserved : 16; 169120357eaSUenal Mutlu * }; 170120357eaSUenal Mutlu * 171120357eaSUenal Mutlu * TXTS: Transmit Transaction Size (TX_TRANSACTION_SIZE). 172120357eaSUenal Mutlu * This field defines the DMA transaction size in DWORDs for 173120357eaSUenal Mutlu * transmit (system bus read, device write) operation. [...] 174120357eaSUenal Mutlu * 175120357eaSUenal Mutlu * RXTS: Receive Transaction Size (RX_TRANSACTION_SIZE). 176120357eaSUenal Mutlu * This field defines the Port DMA transaction size in DWORDs 177120357eaSUenal Mutlu * for receive (system bus write, device read) operation. [...] 178120357eaSUenal Mutlu * 179120357eaSUenal Mutlu * TXABL: Transmit Burst Limit. 180120357eaSUenal Mutlu * This field allows software to limit the VBUSP master read 181120357eaSUenal Mutlu * burst size. [...] 182120357eaSUenal Mutlu * 183120357eaSUenal Mutlu * RXABL: Receive Burst Limit. 184120357eaSUenal Mutlu * Allows software to limit the VBUSP master write burst 185120357eaSUenal Mutlu * size. [...] 186120357eaSUenal Mutlu * 187120357eaSUenal Mutlu * Reserved: Reserved. 188120357eaSUenal Mutlu * 189120357eaSUenal Mutlu * 190120357eaSUenal Mutlu * NOTE: According to the above document, the following alternative 191120357eaSUenal Mutlu * to the code below could perhaps be a better option 192120357eaSUenal Mutlu * (or preparation) for possible further improvements later: 193120357eaSUenal Mutlu * sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ffff, 194120357eaSUenal Mutlu * 0x00000033); 195120357eaSUenal Mutlu */ 196120357eaSUenal Mutlu sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ffff, 0x00004433); 197c5754b52SOlliver Schinagl 198c5754b52SOlliver Schinagl /* Start DMA */ 199c5754b52SOlliver Schinagl sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START); 200c5754b52SOlliver Schinagl } 201c5754b52SOlliver Schinagl 202c5754b52SOlliver Schinagl static const struct ata_port_info ahci_sunxi_port_info = { 203f6bca4d9STimo Sigurdsson .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ | ATA_FLAG_NO_DIPM, 204c5754b52SOlliver Schinagl .pio_mask = ATA_PIO4, 205c5754b52SOlliver Schinagl .udma_mask = ATA_UDMA6, 206c5754b52SOlliver Schinagl .port_ops = &ahci_platform_ops, 207c5754b52SOlliver Schinagl }; 208c5754b52SOlliver Schinagl 209018d5ef2SAkinobu Mita static struct scsi_host_template ahci_platform_sht = { 210018d5ef2SAkinobu Mita AHCI_SHT(DRV_NAME), 211018d5ef2SAkinobu Mita }; 212018d5ef2SAkinobu Mita 213c5754b52SOlliver Schinagl static int ahci_sunxi_probe(struct platform_device *pdev) 214c5754b52SOlliver Schinagl { 215c5754b52SOlliver Schinagl struct device *dev = &pdev->dev; 216c5754b52SOlliver Schinagl struct ahci_host_priv *hpriv; 217c5754b52SOlliver Schinagl int rc; 218c5754b52SOlliver Schinagl 21976dfb49dSCorentin Labbe hpriv = ahci_platform_get_resources(pdev, AHCI_PLATFORM_GET_RESETS); 220c5754b52SOlliver Schinagl if (IS_ERR(hpriv)) 221c5754b52SOlliver Schinagl return PTR_ERR(hpriv); 222c5754b52SOlliver Schinagl 223c5754b52SOlliver Schinagl hpriv->start_engine = ahci_sunxi_start_engine; 224c5754b52SOlliver Schinagl 225c5754b52SOlliver Schinagl rc = ahci_platform_enable_resources(hpriv); 226c5754b52SOlliver Schinagl if (rc) 227c5754b52SOlliver Schinagl return rc; 228c5754b52SOlliver Schinagl 229c5754b52SOlliver Schinagl rc = ahci_sunxi_phy_init(dev, hpriv->mmio); 230c5754b52SOlliver Schinagl if (rc) 231c5754b52SOlliver Schinagl goto disable_resources; 232c5754b52SOlliver Schinagl 233725c7b57SAntoine Ténart hpriv->flags = AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | 23435c16a8fSHans de Goede AHCI_HFLAG_YES_NCQ; 23535c16a8fSHans de Goede 23635c16a8fSHans de Goede /* 23735c16a8fSHans de Goede * The sunxi sata controller seems to be unable to successfully do a 23835c16a8fSHans de Goede * soft reset if no pmp is attached, so disable pmp use unless 23935c16a8fSHans de Goede * requested, otherwise directly attached disks do not work. 24035c16a8fSHans de Goede */ 24135c16a8fSHans de Goede if (!enable_pmp) 24235c16a8fSHans de Goede hpriv->flags |= AHCI_HFLAG_NO_PMP; 243f9f36917SKefeng Wang 244018d5ef2SAkinobu Mita rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, 245018d5ef2SAkinobu Mita &ahci_platform_sht); 246c5754b52SOlliver Schinagl if (rc) 247c5754b52SOlliver Schinagl goto disable_resources; 248c5754b52SOlliver Schinagl 249c5754b52SOlliver Schinagl return 0; 250c5754b52SOlliver Schinagl 251c5754b52SOlliver Schinagl disable_resources: 252c5754b52SOlliver Schinagl ahci_platform_disable_resources(hpriv); 253c5754b52SOlliver Schinagl return rc; 254c5754b52SOlliver Schinagl } 255c5754b52SOlliver Schinagl 256c5754b52SOlliver Schinagl #ifdef CONFIG_PM_SLEEP 2571bf9d885SBartlomiej Zolnierkiewicz static int ahci_sunxi_resume(struct device *dev) 258c5754b52SOlliver Schinagl { 259c5754b52SOlliver Schinagl struct ata_host *host = dev_get_drvdata(dev); 260c5754b52SOlliver Schinagl struct ahci_host_priv *hpriv = host->private_data; 261c5754b52SOlliver Schinagl int rc; 262c5754b52SOlliver Schinagl 263c5754b52SOlliver Schinagl rc = ahci_platform_enable_resources(hpriv); 264c5754b52SOlliver Schinagl if (rc) 265c5754b52SOlliver Schinagl return rc; 266c5754b52SOlliver Schinagl 267c5754b52SOlliver Schinagl rc = ahci_sunxi_phy_init(dev, hpriv->mmio); 268c5754b52SOlliver Schinagl if (rc) 269c5754b52SOlliver Schinagl goto disable_resources; 270c5754b52SOlliver Schinagl 271c5754b52SOlliver Schinagl rc = ahci_platform_resume_host(dev); 272c5754b52SOlliver Schinagl if (rc) 273c5754b52SOlliver Schinagl goto disable_resources; 274c5754b52SOlliver Schinagl 275c5754b52SOlliver Schinagl return 0; 276c5754b52SOlliver Schinagl 277c5754b52SOlliver Schinagl disable_resources: 278c5754b52SOlliver Schinagl ahci_platform_disable_resources(hpriv); 279c5754b52SOlliver Schinagl return rc; 280c5754b52SOlliver Schinagl } 281c5754b52SOlliver Schinagl #endif 282c5754b52SOlliver Schinagl 283c5754b52SOlliver Schinagl static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend, 284c5754b52SOlliver Schinagl ahci_sunxi_resume); 285c5754b52SOlliver Schinagl 286c5754b52SOlliver Schinagl static const struct of_device_id ahci_sunxi_of_match[] = { 287c5754b52SOlliver Schinagl { .compatible = "allwinner,sun4i-a10-ahci", }, 28876dfb49dSCorentin Labbe { .compatible = "allwinner,sun8i-r40-ahci", }, 289*5e776d7bSGeert Uytterhoeven { /* sentinel */ } 290c5754b52SOlliver Schinagl }; 291c5754b52SOlliver Schinagl MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match); 292c5754b52SOlliver Schinagl 293c5754b52SOlliver Schinagl static struct platform_driver ahci_sunxi_driver = { 294c5754b52SOlliver Schinagl .probe = ahci_sunxi_probe, 295c5754b52SOlliver Schinagl .remove = ata_platform_remove_one, 296c5754b52SOlliver Schinagl .driver = { 297018d5ef2SAkinobu Mita .name = DRV_NAME, 298c5754b52SOlliver Schinagl .of_match_table = ahci_sunxi_of_match, 299c5754b52SOlliver Schinagl .pm = &ahci_sunxi_pm_ops, 300c5754b52SOlliver Schinagl }, 301c5754b52SOlliver Schinagl }; 302c5754b52SOlliver Schinagl module_platform_driver(ahci_sunxi_driver); 303c5754b52SOlliver Schinagl 304c5754b52SOlliver Schinagl MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver"); 305c5754b52SOlliver Schinagl MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>"); 306c5754b52SOlliver Schinagl MODULE_LICENSE("GPL"); 307