1*81d01bfaSLoc Ho /* 2*81d01bfaSLoc Ho * AppliedMicro X-Gene SoC SATA Host Controller Driver 3*81d01bfaSLoc Ho * 4*81d01bfaSLoc Ho * Copyright (c) 2014, Applied Micro Circuits Corporation 5*81d01bfaSLoc Ho * Author: Loc Ho <lho@apm.com> 6*81d01bfaSLoc Ho * Tuan Phan <tphan@apm.com> 7*81d01bfaSLoc Ho * Suman Tripathi <stripathi@apm.com> 8*81d01bfaSLoc Ho * 9*81d01bfaSLoc Ho * This program is free software; you can redistribute it and/or modify it 10*81d01bfaSLoc Ho * under the terms of the GNU General Public License as published by the 11*81d01bfaSLoc Ho * Free Software Foundation; either version 2 of the License, or (at your 12*81d01bfaSLoc Ho * option) any later version. 13*81d01bfaSLoc Ho * 14*81d01bfaSLoc Ho * This program is distributed in the hope that it will be useful, 15*81d01bfaSLoc Ho * but WITHOUT ANY WARRANTY; without even the implied warranty of 16*81d01bfaSLoc Ho * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17*81d01bfaSLoc Ho * GNU General Public License for more details. 18*81d01bfaSLoc Ho * 19*81d01bfaSLoc Ho * You should have received a copy of the GNU General Public License 20*81d01bfaSLoc Ho * along with this program. If not, see <http://www.gnu.org/licenses/>. 21*81d01bfaSLoc Ho * 22*81d01bfaSLoc Ho * NOTE: PM support is not currently available. 23*81d01bfaSLoc Ho * 24*81d01bfaSLoc Ho */ 25*81d01bfaSLoc Ho #include <linux/module.h> 26*81d01bfaSLoc Ho #include <linux/platform_device.h> 27*81d01bfaSLoc Ho #include <linux/ahci_platform.h> 28*81d01bfaSLoc Ho #include <linux/of_address.h> 29*81d01bfaSLoc Ho #include <linux/of_irq.h> 30*81d01bfaSLoc Ho #include <linux/phy/phy.h> 31*81d01bfaSLoc Ho #include "ahci.h" 32*81d01bfaSLoc Ho 33*81d01bfaSLoc Ho /* Max # of disk per a controller */ 34*81d01bfaSLoc Ho #define MAX_AHCI_CHN_PERCTR 2 35*81d01bfaSLoc Ho 36*81d01bfaSLoc Ho /* MUX CSR */ 37*81d01bfaSLoc Ho #define SATA_ENET_CONFIG_REG 0x00000000 38*81d01bfaSLoc Ho #define CFG_SATA_ENET_SELECT_MASK 0x00000001 39*81d01bfaSLoc Ho 40*81d01bfaSLoc Ho /* SATA core host controller CSR */ 41*81d01bfaSLoc Ho #define SLVRDERRATTRIBUTES 0x00000000 42*81d01bfaSLoc Ho #define SLVWRERRATTRIBUTES 0x00000004 43*81d01bfaSLoc Ho #define MSTRDERRATTRIBUTES 0x00000008 44*81d01bfaSLoc Ho #define MSTWRERRATTRIBUTES 0x0000000c 45*81d01bfaSLoc Ho #define BUSCTLREG 0x00000014 46*81d01bfaSLoc Ho #define IOFMSTRWAUX 0x00000018 47*81d01bfaSLoc Ho #define INTSTATUSMASK 0x0000002c 48*81d01bfaSLoc Ho #define ERRINTSTATUS 0x00000030 49*81d01bfaSLoc Ho #define ERRINTSTATUSMASK 0x00000034 50*81d01bfaSLoc Ho 51*81d01bfaSLoc Ho /* SATA host AHCI CSR */ 52*81d01bfaSLoc Ho #define PORTCFG 0x000000a4 53*81d01bfaSLoc Ho #define PORTADDR_SET(dst, src) \ 54*81d01bfaSLoc Ho (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f)) 55*81d01bfaSLoc Ho #define PORTPHY1CFG 0x000000a8 56*81d01bfaSLoc Ho #define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \ 57*81d01bfaSLoc Ho (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000)) 58*81d01bfaSLoc Ho #define PORTPHY2CFG 0x000000ac 59*81d01bfaSLoc Ho #define PORTPHY3CFG 0x000000b0 60*81d01bfaSLoc Ho #define PORTPHY4CFG 0x000000b4 61*81d01bfaSLoc Ho #define PORTPHY5CFG 0x000000b8 62*81d01bfaSLoc Ho #define SCTL0 0x0000012C 63*81d01bfaSLoc Ho #define PORTPHY5CFG_RTCHG_SET(dst, src) \ 64*81d01bfaSLoc Ho (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000)) 65*81d01bfaSLoc Ho #define PORTAXICFG_EN_CONTEXT_SET(dst, src) \ 66*81d01bfaSLoc Ho (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000)) 67*81d01bfaSLoc Ho #define PORTAXICFG 0x000000bc 68*81d01bfaSLoc Ho #define PORTAXICFG_OUTTRANS_SET(dst, src) \ 69*81d01bfaSLoc Ho (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000)) 70*81d01bfaSLoc Ho 71*81d01bfaSLoc Ho /* SATA host controller AXI CSR */ 72*81d01bfaSLoc Ho #define INT_SLV_TMOMASK 0x00000010 73*81d01bfaSLoc Ho 74*81d01bfaSLoc Ho /* SATA diagnostic CSR */ 75*81d01bfaSLoc Ho #define CFG_MEM_RAM_SHUTDOWN 0x00000070 76*81d01bfaSLoc Ho #define BLOCK_MEM_RDY 0x00000074 77*81d01bfaSLoc Ho 78*81d01bfaSLoc Ho struct xgene_ahci_context { 79*81d01bfaSLoc Ho struct ahci_host_priv *hpriv; 80*81d01bfaSLoc Ho struct device *dev; 81*81d01bfaSLoc Ho void __iomem *csr_core; /* Core CSR address of IP */ 82*81d01bfaSLoc Ho void __iomem *csr_diag; /* Diag CSR address of IP */ 83*81d01bfaSLoc Ho void __iomem *csr_axi; /* AXI CSR address of IP */ 84*81d01bfaSLoc Ho void __iomem *csr_mux; /* MUX CSR address of IP */ 85*81d01bfaSLoc Ho }; 86*81d01bfaSLoc Ho 87*81d01bfaSLoc Ho static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) 88*81d01bfaSLoc Ho { 89*81d01bfaSLoc Ho dev_dbg(ctx->dev, "Release memory from shutdown\n"); 90*81d01bfaSLoc Ho writel(0x0, ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); 91*81d01bfaSLoc Ho readl(ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */ 92*81d01bfaSLoc Ho msleep(1); /* reset may take up to 1ms */ 93*81d01bfaSLoc Ho if (readl(ctx->csr_diag + BLOCK_MEM_RDY) != 0xFFFFFFFF) { 94*81d01bfaSLoc Ho dev_err(ctx->dev, "failed to release memory from shutdown\n"); 95*81d01bfaSLoc Ho return -ENODEV; 96*81d01bfaSLoc Ho } 97*81d01bfaSLoc Ho return 0; 98*81d01bfaSLoc Ho } 99*81d01bfaSLoc Ho 100*81d01bfaSLoc Ho /** 101*81d01bfaSLoc Ho * xgene_ahci_read_id - Read ID data from the specified device 102*81d01bfaSLoc Ho * @dev: device 103*81d01bfaSLoc Ho * @tf: proposed taskfile 104*81d01bfaSLoc Ho * @id: data buffer 105*81d01bfaSLoc Ho * 106*81d01bfaSLoc Ho * This custom read ID function is required due to the fact that the HW 107*81d01bfaSLoc Ho * does not support DEVSLP and the controller state machine may get stuck 108*81d01bfaSLoc Ho * after processing the ID query command. 109*81d01bfaSLoc Ho */ 110*81d01bfaSLoc Ho static unsigned int xgene_ahci_read_id(struct ata_device *dev, 111*81d01bfaSLoc Ho struct ata_taskfile *tf, u16 *id) 112*81d01bfaSLoc Ho { 113*81d01bfaSLoc Ho u32 err_mask; 114*81d01bfaSLoc Ho void __iomem *port_mmio = ahci_port_base(dev->link->ap); 115*81d01bfaSLoc Ho 116*81d01bfaSLoc Ho err_mask = ata_do_dev_read_id(dev, tf, id); 117*81d01bfaSLoc Ho if (err_mask) 118*81d01bfaSLoc Ho return err_mask; 119*81d01bfaSLoc Ho 120*81d01bfaSLoc Ho /* 121*81d01bfaSLoc Ho * Mask reserved area. Word78 spec of Link Power Management 122*81d01bfaSLoc Ho * bit15-8: reserved 123*81d01bfaSLoc Ho * bit7: NCQ autosence 124*81d01bfaSLoc Ho * bit6: Software settings preservation supported 125*81d01bfaSLoc Ho * bit5: reserved 126*81d01bfaSLoc Ho * bit4: In-order sata delivery supported 127*81d01bfaSLoc Ho * bit3: DIPM requests supported 128*81d01bfaSLoc Ho * bit2: DMA Setup FIS Auto-Activate optimization supported 129*81d01bfaSLoc Ho * bit1: DMA Setup FIX non-Zero buffer offsets supported 130*81d01bfaSLoc Ho * bit0: Reserved 131*81d01bfaSLoc Ho * 132*81d01bfaSLoc Ho * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP 133*81d01bfaSLoc Ho */ 134*81d01bfaSLoc Ho id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8); 135*81d01bfaSLoc Ho 136*81d01bfaSLoc Ho /* 137*81d01bfaSLoc Ho * Due to HW errata, restart the port if no other command active. 138*81d01bfaSLoc Ho * Otherwise the controller may get stuck. 139*81d01bfaSLoc Ho */ 140*81d01bfaSLoc Ho if (!readl(port_mmio + PORT_CMD_ISSUE)) { 141*81d01bfaSLoc Ho writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD); 142*81d01bfaSLoc Ho readl(port_mmio + PORT_CMD); /* Force a barrier */ 143*81d01bfaSLoc Ho writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD); 144*81d01bfaSLoc Ho readl(port_mmio + PORT_CMD); /* Force a barrier */ 145*81d01bfaSLoc Ho } 146*81d01bfaSLoc Ho return 0; 147*81d01bfaSLoc Ho } 148*81d01bfaSLoc Ho 149*81d01bfaSLoc Ho static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel) 150*81d01bfaSLoc Ho { 151*81d01bfaSLoc Ho void __iomem *mmio = ctx->hpriv->mmio; 152*81d01bfaSLoc Ho u32 val; 153*81d01bfaSLoc Ho 154*81d01bfaSLoc Ho dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n", 155*81d01bfaSLoc Ho mmio, channel); 156*81d01bfaSLoc Ho val = readl(mmio + PORTCFG); 157*81d01bfaSLoc Ho val = PORTADDR_SET(val, channel == 0 ? 2 : 3); 158*81d01bfaSLoc Ho writel(val, mmio + PORTCFG); 159*81d01bfaSLoc Ho readl(mmio + PORTCFG); /* Force a barrier */ 160*81d01bfaSLoc Ho /* Disable fix rate */ 161*81d01bfaSLoc Ho writel(0x0001fffe, mmio + PORTPHY1CFG); 162*81d01bfaSLoc Ho readl(mmio + PORTPHY1CFG); /* Force a barrier */ 163*81d01bfaSLoc Ho writel(0x5018461c, mmio + PORTPHY2CFG); 164*81d01bfaSLoc Ho readl(mmio + PORTPHY2CFG); /* Force a barrier */ 165*81d01bfaSLoc Ho writel(0x1c081907, mmio + PORTPHY3CFG); 166*81d01bfaSLoc Ho readl(mmio + PORTPHY3CFG); /* Force a barrier */ 167*81d01bfaSLoc Ho writel(0x1c080815, mmio + PORTPHY4CFG); 168*81d01bfaSLoc Ho readl(mmio + PORTPHY4CFG); /* Force a barrier */ 169*81d01bfaSLoc Ho /* Set window negotiation */ 170*81d01bfaSLoc Ho val = readl(mmio + PORTPHY5CFG); 171*81d01bfaSLoc Ho val = PORTPHY5CFG_RTCHG_SET(val, 0x300); 172*81d01bfaSLoc Ho writel(val, mmio + PORTPHY5CFG); 173*81d01bfaSLoc Ho readl(mmio + PORTPHY5CFG); /* Force a barrier */ 174*81d01bfaSLoc Ho val = readl(mmio + PORTAXICFG); 175*81d01bfaSLoc Ho val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */ 176*81d01bfaSLoc Ho val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */ 177*81d01bfaSLoc Ho writel(val, mmio + PORTAXICFG); 178*81d01bfaSLoc Ho readl(mmio + PORTAXICFG); /* Force a barrier */ 179*81d01bfaSLoc Ho } 180*81d01bfaSLoc Ho 181*81d01bfaSLoc Ho /** 182*81d01bfaSLoc Ho * xgene_ahci_do_hardreset - Issue the actual COMRESET 183*81d01bfaSLoc Ho * @link: link to reset 184*81d01bfaSLoc Ho * @deadline: deadline jiffies for the operation 185*81d01bfaSLoc Ho * @online: Return value to indicate if device online 186*81d01bfaSLoc Ho * 187*81d01bfaSLoc Ho * Due to the limitation of the hardware PHY, a difference set of setting is 188*81d01bfaSLoc Ho * required for each supported disk speed - Gen3 (6.0Gbps), Gen2 (3.0Gbps), 189*81d01bfaSLoc Ho * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will 190*81d01bfaSLoc Ho * report disparity error and etc. In addition, during COMRESET, there can 191*81d01bfaSLoc Ho * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and 192*81d01bfaSLoc Ho * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following 193*81d01bfaSLoc Ho * algorithm is followed to proper configure the hardware PHY during COMRESET: 194*81d01bfaSLoc Ho * 195*81d01bfaSLoc Ho * Alg Part 1: 196*81d01bfaSLoc Ho * 1. Start the PHY at Gen3 speed (default setting) 197*81d01bfaSLoc Ho * 2. Issue the COMRESET 198*81d01bfaSLoc Ho * 3. If no link, go to Alg Part 3 199*81d01bfaSLoc Ho * 4. If link up, determine if the negotiated speed matches the PHY 200*81d01bfaSLoc Ho * configured speed 201*81d01bfaSLoc Ho * 5. If they matched, go to Alg Part 2 202*81d01bfaSLoc Ho * 6. If they do not matched and first time, configure the PHY for the linked 203*81d01bfaSLoc Ho * up disk speed and repeat step 2 204*81d01bfaSLoc Ho * 7. Go to Alg Part 2 205*81d01bfaSLoc Ho * 206*81d01bfaSLoc Ho * Alg Part 2: 207*81d01bfaSLoc Ho * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error 208*81d01bfaSLoc Ho * reported in the register PORT_SCR_ERR, then reset the PHY receiver line 209*81d01bfaSLoc Ho * 2. Go to Alg Part 3 210*81d01bfaSLoc Ho * 211*81d01bfaSLoc Ho * Alg Part 3: 212*81d01bfaSLoc Ho * 1. Clear any pending from register PORT_SCR_ERR. 213*81d01bfaSLoc Ho * 214*81d01bfaSLoc Ho * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition 215*81d01bfaSLoc Ho * and until the underlying PHY supports an method to reset the receiver 216*81d01bfaSLoc Ho * line, on detection of SERR_DISPARITY or SERR_10B_8B_ERR errors, 217*81d01bfaSLoc Ho * an warning message will be printed. 218*81d01bfaSLoc Ho */ 219*81d01bfaSLoc Ho static int xgene_ahci_do_hardreset(struct ata_link *link, 220*81d01bfaSLoc Ho unsigned long deadline, bool *online) 221*81d01bfaSLoc Ho { 222*81d01bfaSLoc Ho const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); 223*81d01bfaSLoc Ho struct ata_port *ap = link->ap; 224*81d01bfaSLoc Ho struct ahci_host_priv *hpriv = ap->host->private_data; 225*81d01bfaSLoc Ho struct xgene_ahci_context *ctx = hpriv->plat_data; 226*81d01bfaSLoc Ho struct ahci_port_priv *pp = ap->private_data; 227*81d01bfaSLoc Ho u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 228*81d01bfaSLoc Ho void __iomem *port_mmio = ahci_port_base(ap); 229*81d01bfaSLoc Ho struct ata_taskfile tf; 230*81d01bfaSLoc Ho int rc; 231*81d01bfaSLoc Ho u32 val; 232*81d01bfaSLoc Ho 233*81d01bfaSLoc Ho /* clear D2H reception area to properly wait for D2H FIS */ 234*81d01bfaSLoc Ho ata_tf_init(link->device, &tf); 235*81d01bfaSLoc Ho tf.command = ATA_BUSY; 236*81d01bfaSLoc Ho ata_tf_to_fis(&tf, 0, 0, d2h_fis); 237*81d01bfaSLoc Ho rc = sata_link_hardreset(link, timing, deadline, online, 238*81d01bfaSLoc Ho ahci_check_ready); 239*81d01bfaSLoc Ho 240*81d01bfaSLoc Ho val = readl(port_mmio + PORT_SCR_ERR); 241*81d01bfaSLoc Ho if (val & (SERR_DISPARITY | SERR_10B_8B_ERR)) 242*81d01bfaSLoc Ho dev_warn(ctx->dev, "link has error\n"); 243*81d01bfaSLoc Ho 244*81d01bfaSLoc Ho /* clear all errors if any pending */ 245*81d01bfaSLoc Ho val = readl(port_mmio + PORT_SCR_ERR); 246*81d01bfaSLoc Ho writel(val, port_mmio + PORT_SCR_ERR); 247*81d01bfaSLoc Ho 248*81d01bfaSLoc Ho return rc; 249*81d01bfaSLoc Ho } 250*81d01bfaSLoc Ho 251*81d01bfaSLoc Ho static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class, 252*81d01bfaSLoc Ho unsigned long deadline) 253*81d01bfaSLoc Ho { 254*81d01bfaSLoc Ho struct ata_port *ap = link->ap; 255*81d01bfaSLoc Ho struct ahci_host_priv *hpriv = ap->host->private_data; 256*81d01bfaSLoc Ho void __iomem *port_mmio = ahci_port_base(ap); 257*81d01bfaSLoc Ho bool online; 258*81d01bfaSLoc Ho int rc; 259*81d01bfaSLoc Ho u32 portcmd_saved; 260*81d01bfaSLoc Ho u32 portclb_saved; 261*81d01bfaSLoc Ho u32 portclbhi_saved; 262*81d01bfaSLoc Ho u32 portrxfis_saved; 263*81d01bfaSLoc Ho u32 portrxfishi_saved; 264*81d01bfaSLoc Ho 265*81d01bfaSLoc Ho /* As hardreset resets these CSR, save it to restore later */ 266*81d01bfaSLoc Ho portcmd_saved = readl(port_mmio + PORT_CMD); 267*81d01bfaSLoc Ho portclb_saved = readl(port_mmio + PORT_LST_ADDR); 268*81d01bfaSLoc Ho portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI); 269*81d01bfaSLoc Ho portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR); 270*81d01bfaSLoc Ho portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI); 271*81d01bfaSLoc Ho 272*81d01bfaSLoc Ho ahci_stop_engine(ap); 273*81d01bfaSLoc Ho 274*81d01bfaSLoc Ho rc = xgene_ahci_do_hardreset(link, deadline, &online); 275*81d01bfaSLoc Ho 276*81d01bfaSLoc Ho /* As controller hardreset clears them, restore them */ 277*81d01bfaSLoc Ho writel(portcmd_saved, port_mmio + PORT_CMD); 278*81d01bfaSLoc Ho writel(portclb_saved, port_mmio + PORT_LST_ADDR); 279*81d01bfaSLoc Ho writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI); 280*81d01bfaSLoc Ho writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR); 281*81d01bfaSLoc Ho writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI); 282*81d01bfaSLoc Ho 283*81d01bfaSLoc Ho hpriv->start_engine(ap); 284*81d01bfaSLoc Ho 285*81d01bfaSLoc Ho if (online) 286*81d01bfaSLoc Ho *class = ahci_dev_classify(ap); 287*81d01bfaSLoc Ho 288*81d01bfaSLoc Ho return rc; 289*81d01bfaSLoc Ho } 290*81d01bfaSLoc Ho 291*81d01bfaSLoc Ho static void xgene_ahci_host_stop(struct ata_host *host) 292*81d01bfaSLoc Ho { 293*81d01bfaSLoc Ho struct ahci_host_priv *hpriv = host->private_data; 294*81d01bfaSLoc Ho 295*81d01bfaSLoc Ho ahci_platform_disable_resources(hpriv); 296*81d01bfaSLoc Ho } 297*81d01bfaSLoc Ho 298*81d01bfaSLoc Ho static struct ata_port_operations xgene_ahci_ops = { 299*81d01bfaSLoc Ho .inherits = &ahci_ops, 300*81d01bfaSLoc Ho .host_stop = xgene_ahci_host_stop, 301*81d01bfaSLoc Ho .hardreset = xgene_ahci_hardreset, 302*81d01bfaSLoc Ho .read_id = xgene_ahci_read_id, 303*81d01bfaSLoc Ho }; 304*81d01bfaSLoc Ho 305*81d01bfaSLoc Ho static const struct ata_port_info xgene_ahci_port_info = { 306*81d01bfaSLoc Ho AHCI_HFLAGS(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ), 307*81d01bfaSLoc Ho .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ, 308*81d01bfaSLoc Ho .pio_mask = ATA_PIO4, 309*81d01bfaSLoc Ho .udma_mask = ATA_UDMA6, 310*81d01bfaSLoc Ho .port_ops = &xgene_ahci_ops, 311*81d01bfaSLoc Ho }; 312*81d01bfaSLoc Ho 313*81d01bfaSLoc Ho static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv) 314*81d01bfaSLoc Ho { 315*81d01bfaSLoc Ho struct xgene_ahci_context *ctx = hpriv->plat_data; 316*81d01bfaSLoc Ho int i; 317*81d01bfaSLoc Ho int rc; 318*81d01bfaSLoc Ho u32 val; 319*81d01bfaSLoc Ho 320*81d01bfaSLoc Ho /* Remove IP RAM out of shutdown */ 321*81d01bfaSLoc Ho rc = xgene_ahci_init_memram(ctx); 322*81d01bfaSLoc Ho if (rc) 323*81d01bfaSLoc Ho return rc; 324*81d01bfaSLoc Ho 325*81d01bfaSLoc Ho for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++) 326*81d01bfaSLoc Ho xgene_ahci_set_phy_cfg(ctx, i); 327*81d01bfaSLoc Ho 328*81d01bfaSLoc Ho /* AXI disable Mask */ 329*81d01bfaSLoc Ho writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT); 330*81d01bfaSLoc Ho readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */ 331*81d01bfaSLoc Ho writel(0, ctx->csr_core + INTSTATUSMASK); 332*81d01bfaSLoc Ho readl(ctx->csr_core + INTSTATUSMASK); /* Force a barrier */ 333*81d01bfaSLoc Ho dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n", 334*81d01bfaSLoc Ho INTSTATUSMASK, val); 335*81d01bfaSLoc Ho 336*81d01bfaSLoc Ho writel(0x0, ctx->csr_core + ERRINTSTATUSMASK); 337*81d01bfaSLoc Ho readl(ctx->csr_core + ERRINTSTATUSMASK); /* Force a barrier */ 338*81d01bfaSLoc Ho writel(0x0, ctx->csr_axi + INT_SLV_TMOMASK); 339*81d01bfaSLoc Ho readl(ctx->csr_axi + INT_SLV_TMOMASK); 340*81d01bfaSLoc Ho 341*81d01bfaSLoc Ho /* Enable AXI Interrupt */ 342*81d01bfaSLoc Ho writel(0xffffffff, ctx->csr_core + SLVRDERRATTRIBUTES); 343*81d01bfaSLoc Ho writel(0xffffffff, ctx->csr_core + SLVWRERRATTRIBUTES); 344*81d01bfaSLoc Ho writel(0xffffffff, ctx->csr_core + MSTRDERRATTRIBUTES); 345*81d01bfaSLoc Ho writel(0xffffffff, ctx->csr_core + MSTWRERRATTRIBUTES); 346*81d01bfaSLoc Ho 347*81d01bfaSLoc Ho /* Enable coherency */ 348*81d01bfaSLoc Ho val = readl(ctx->csr_core + BUSCTLREG); 349*81d01bfaSLoc Ho val &= ~0x00000002; /* Enable write coherency */ 350*81d01bfaSLoc Ho val &= ~0x00000001; /* Enable read coherency */ 351*81d01bfaSLoc Ho writel(val, ctx->csr_core + BUSCTLREG); 352*81d01bfaSLoc Ho 353*81d01bfaSLoc Ho val = readl(ctx->csr_core + IOFMSTRWAUX); 354*81d01bfaSLoc Ho val |= (1 << 3); /* Enable read coherency */ 355*81d01bfaSLoc Ho val |= (1 << 9); /* Enable write coherency */ 356*81d01bfaSLoc Ho writel(val, ctx->csr_core + IOFMSTRWAUX); 357*81d01bfaSLoc Ho val = readl(ctx->csr_core + IOFMSTRWAUX); 358*81d01bfaSLoc Ho dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n", 359*81d01bfaSLoc Ho IOFMSTRWAUX, val); 360*81d01bfaSLoc Ho 361*81d01bfaSLoc Ho return rc; 362*81d01bfaSLoc Ho } 363*81d01bfaSLoc Ho 364*81d01bfaSLoc Ho static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx) 365*81d01bfaSLoc Ho { 366*81d01bfaSLoc Ho u32 val; 367*81d01bfaSLoc Ho 368*81d01bfaSLoc Ho /* Check for optional MUX resource */ 369*81d01bfaSLoc Ho if (IS_ERR(ctx->csr_mux)) 370*81d01bfaSLoc Ho return 0; 371*81d01bfaSLoc Ho 372*81d01bfaSLoc Ho val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG); 373*81d01bfaSLoc Ho val &= ~CFG_SATA_ENET_SELECT_MASK; 374*81d01bfaSLoc Ho writel(val, ctx->csr_mux + SATA_ENET_CONFIG_REG); 375*81d01bfaSLoc Ho val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG); 376*81d01bfaSLoc Ho return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0; 377*81d01bfaSLoc Ho } 378*81d01bfaSLoc Ho 379*81d01bfaSLoc Ho static int xgene_ahci_probe(struct platform_device *pdev) 380*81d01bfaSLoc Ho { 381*81d01bfaSLoc Ho struct device *dev = &pdev->dev; 382*81d01bfaSLoc Ho struct ahci_host_priv *hpriv; 383*81d01bfaSLoc Ho struct xgene_ahci_context *ctx; 384*81d01bfaSLoc Ho struct resource *res; 385*81d01bfaSLoc Ho int rc; 386*81d01bfaSLoc Ho 387*81d01bfaSLoc Ho hpriv = ahci_platform_get_resources(pdev); 388*81d01bfaSLoc Ho if (IS_ERR(hpriv)) 389*81d01bfaSLoc Ho return PTR_ERR(hpriv); 390*81d01bfaSLoc Ho 391*81d01bfaSLoc Ho ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 392*81d01bfaSLoc Ho if (!ctx) 393*81d01bfaSLoc Ho return -ENOMEM; 394*81d01bfaSLoc Ho 395*81d01bfaSLoc Ho hpriv->plat_data = ctx; 396*81d01bfaSLoc Ho ctx->hpriv = hpriv; 397*81d01bfaSLoc Ho ctx->dev = dev; 398*81d01bfaSLoc Ho 399*81d01bfaSLoc Ho /* Retrieve the IP core resource */ 400*81d01bfaSLoc Ho res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 401*81d01bfaSLoc Ho ctx->csr_core = devm_ioremap_resource(dev, res); 402*81d01bfaSLoc Ho if (IS_ERR(ctx->csr_core)) 403*81d01bfaSLoc Ho return PTR_ERR(ctx->csr_core); 404*81d01bfaSLoc Ho 405*81d01bfaSLoc Ho /* Retrieve the IP diagnostic resource */ 406*81d01bfaSLoc Ho res = platform_get_resource(pdev, IORESOURCE_MEM, 2); 407*81d01bfaSLoc Ho ctx->csr_diag = devm_ioremap_resource(dev, res); 408*81d01bfaSLoc Ho if (IS_ERR(ctx->csr_diag)) 409*81d01bfaSLoc Ho return PTR_ERR(ctx->csr_diag); 410*81d01bfaSLoc Ho 411*81d01bfaSLoc Ho /* Retrieve the IP AXI resource */ 412*81d01bfaSLoc Ho res = platform_get_resource(pdev, IORESOURCE_MEM, 3); 413*81d01bfaSLoc Ho ctx->csr_axi = devm_ioremap_resource(dev, res); 414*81d01bfaSLoc Ho if (IS_ERR(ctx->csr_axi)) 415*81d01bfaSLoc Ho return PTR_ERR(ctx->csr_axi); 416*81d01bfaSLoc Ho 417*81d01bfaSLoc Ho /* Retrieve the optional IP mux resource */ 418*81d01bfaSLoc Ho res = platform_get_resource(pdev, IORESOURCE_MEM, 4); 419*81d01bfaSLoc Ho ctx->csr_mux = devm_ioremap_resource(dev, res); 420*81d01bfaSLoc Ho 421*81d01bfaSLoc Ho dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core, 422*81d01bfaSLoc Ho hpriv->mmio); 423*81d01bfaSLoc Ho 424*81d01bfaSLoc Ho /* Select ATA */ 425*81d01bfaSLoc Ho if ((rc = xgene_ahci_mux_select(ctx))) { 426*81d01bfaSLoc Ho dev_err(dev, "SATA mux selection failed error %d\n", rc); 427*81d01bfaSLoc Ho return -ENODEV; 428*81d01bfaSLoc Ho } 429*81d01bfaSLoc Ho 430*81d01bfaSLoc Ho /* Due to errata, HW requires full toggle transition */ 431*81d01bfaSLoc Ho rc = ahci_platform_enable_clks(hpriv); 432*81d01bfaSLoc Ho if (rc) 433*81d01bfaSLoc Ho goto disable_resources; 434*81d01bfaSLoc Ho ahci_platform_disable_clks(hpriv); 435*81d01bfaSLoc Ho 436*81d01bfaSLoc Ho rc = ahci_platform_enable_resources(hpriv); 437*81d01bfaSLoc Ho if (rc) 438*81d01bfaSLoc Ho goto disable_resources; 439*81d01bfaSLoc Ho 440*81d01bfaSLoc Ho /* Configure the host controller */ 441*81d01bfaSLoc Ho xgene_ahci_hw_init(hpriv); 442*81d01bfaSLoc Ho 443*81d01bfaSLoc Ho /* 444*81d01bfaSLoc Ho * Setup DMA mask. This is preliminary until the DMA range is sorted 445*81d01bfaSLoc Ho * out. 446*81d01bfaSLoc Ho */ 447*81d01bfaSLoc Ho rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); 448*81d01bfaSLoc Ho if (rc) { 449*81d01bfaSLoc Ho dev_err(dev, "Unable to set dma mask\n"); 450*81d01bfaSLoc Ho goto disable_resources; 451*81d01bfaSLoc Ho } 452*81d01bfaSLoc Ho 453*81d01bfaSLoc Ho rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, 0, 0); 454*81d01bfaSLoc Ho if (rc) 455*81d01bfaSLoc Ho goto disable_resources; 456*81d01bfaSLoc Ho 457*81d01bfaSLoc Ho dev_dbg(dev, "X-Gene SATA host controller initialized\n"); 458*81d01bfaSLoc Ho return 0; 459*81d01bfaSLoc Ho 460*81d01bfaSLoc Ho disable_resources: 461*81d01bfaSLoc Ho ahci_platform_disable_resources(hpriv); 462*81d01bfaSLoc Ho return rc; 463*81d01bfaSLoc Ho } 464*81d01bfaSLoc Ho 465*81d01bfaSLoc Ho static const struct of_device_id xgene_ahci_of_match[] = { 466*81d01bfaSLoc Ho {.compatible = "apm,xgene-ahci"}, 467*81d01bfaSLoc Ho {}, 468*81d01bfaSLoc Ho }; 469*81d01bfaSLoc Ho MODULE_DEVICE_TABLE(of, xgene_ahci_of_match); 470*81d01bfaSLoc Ho 471*81d01bfaSLoc Ho static struct platform_driver xgene_ahci_driver = { 472*81d01bfaSLoc Ho .probe = xgene_ahci_probe, 473*81d01bfaSLoc Ho .remove = ata_platform_remove_one, 474*81d01bfaSLoc Ho .driver = { 475*81d01bfaSLoc Ho .name = "xgene-ahci", 476*81d01bfaSLoc Ho .owner = THIS_MODULE, 477*81d01bfaSLoc Ho .of_match_table = xgene_ahci_of_match, 478*81d01bfaSLoc Ho }, 479*81d01bfaSLoc Ho }; 480*81d01bfaSLoc Ho 481*81d01bfaSLoc Ho module_platform_driver(xgene_ahci_driver); 482*81d01bfaSLoc Ho 483*81d01bfaSLoc Ho MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver"); 484*81d01bfaSLoc Ho MODULE_AUTHOR("Loc Ho <lho@apm.com>"); 485*81d01bfaSLoc Ho MODULE_LICENSE("GPL"); 486*81d01bfaSLoc Ho MODULE_VERSION("0.4"); 487