Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * AppliedMicro X-Gene SoC SATA Host Controller Driver
0004  *
0005  * Copyright (c) 2014, Applied Micro Circuits Corporation
0006  * Author: Loc Ho <lho@apm.com>
0007  *         Tuan Phan <tphan@apm.com>
0008  *         Suman Tripathi <stripathi@apm.com>
0009  *
0010  * NOTE: PM support is not currently available.
0011  */
0012 #include <linux/acpi.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/ahci_platform.h>
0016 #include <linux/of_address.h>
0017 #include <linux/of_device.h>
0018 #include <linux/of_irq.h>
0019 #include <linux/phy/phy.h>
0020 #include "ahci.h"
0021 
0022 #define DRV_NAME "xgene-ahci"
0023 
0024 /* Max # of disk per a controller */
0025 #define MAX_AHCI_CHN_PERCTR     2
0026 
0027 /* MUX CSR */
0028 #define SATA_ENET_CONFIG_REG        0x00000000
0029 #define  CFG_SATA_ENET_SELECT_MASK  0x00000001
0030 
0031 /* SATA core host controller CSR */
0032 #define SLVRDERRATTRIBUTES      0x00000000
0033 #define SLVWRERRATTRIBUTES      0x00000004
0034 #define MSTRDERRATTRIBUTES      0x00000008
0035 #define MSTWRERRATTRIBUTES      0x0000000c
0036 #define BUSCTLREG           0x00000014
0037 #define IOFMSTRWAUX         0x00000018
0038 #define INTSTATUSMASK           0x0000002c
0039 #define ERRINTSTATUS            0x00000030
0040 #define ERRINTSTATUSMASK        0x00000034
0041 
0042 /* SATA host AHCI CSR */
0043 #define PORTCFG             0x000000a4
0044 #define  PORTADDR_SET(dst, src) \
0045         (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f))
0046 #define PORTPHY1CFG     0x000000a8
0047 #define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \
0048         (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000))
0049 #define PORTPHY2CFG         0x000000ac
0050 #define PORTPHY3CFG         0x000000b0
0051 #define PORTPHY4CFG         0x000000b4
0052 #define PORTPHY5CFG         0x000000b8
0053 #define SCTL0               0x0000012C
0054 #define PORTPHY5CFG_RTCHG_SET(dst, src) \
0055         (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000))
0056 #define PORTAXICFG_EN_CONTEXT_SET(dst, src) \
0057         (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000))
0058 #define PORTAXICFG          0x000000bc
0059 #define PORTAXICFG_OUTTRANS_SET(dst, src) \
0060         (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000))
0061 #define PORTRANSCFG         0x000000c8
0062 #define PORTRANSCFG_RXWM_SET(dst, src)      \
0063         (((dst) & ~0x0000007f) | (((u32)(src)) & 0x0000007f))
0064 
0065 /* SATA host controller AXI CSR */
0066 #define INT_SLV_TMOMASK         0x00000010
0067 
0068 /* SATA diagnostic CSR */
0069 #define CFG_MEM_RAM_SHUTDOWN        0x00000070
0070 #define BLOCK_MEM_RDY           0x00000074
0071 
0072 /* Max retry for link down */
0073 #define MAX_LINK_DOWN_RETRY 3
0074 
0075 enum xgene_ahci_version {
0076     XGENE_AHCI_V1 = 1,
0077     XGENE_AHCI_V2,
0078 };
0079 
0080 struct xgene_ahci_context {
0081     struct ahci_host_priv *hpriv;
0082     struct device *dev;
0083     u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/
0084     u32 class[MAX_AHCI_CHN_PERCTR]; /* tracking the class of device */
0085     void __iomem *csr_core;     /* Core CSR address of IP */
0086     void __iomem *csr_diag;     /* Diag CSR address of IP */
0087     void __iomem *csr_axi;      /* AXI CSR address of IP */
0088     void __iomem *csr_mux;      /* MUX CSR address of IP */
0089 };
0090 
0091 static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
0092 {
0093     dev_dbg(ctx->dev, "Release memory from shutdown\n");
0094     writel(0x0, ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN);
0095     readl(ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */
0096     msleep(1);  /* reset may take up to 1ms */
0097     if (readl(ctx->csr_diag + BLOCK_MEM_RDY) != 0xFFFFFFFF) {
0098         dev_err(ctx->dev, "failed to release memory from shutdown\n");
0099         return -ENODEV;
0100     }
0101     return 0;
0102 }
0103 
0104 /**
0105  * xgene_ahci_poll_reg_val- Poll a register on a specific value.
0106  * @ap : ATA port of interest.
0107  * @reg : Register of interest.
0108  * @val : Value to be attained.
0109  * @interval : waiting interval for polling.
0110  * @timeout : timeout for achieving the value.
0111  */
0112 static int xgene_ahci_poll_reg_val(struct ata_port *ap,
0113                    void __iomem *reg, unsigned
0114                    int val, unsigned long interval,
0115                    unsigned long timeout)
0116 {
0117     unsigned long deadline;
0118     unsigned int tmp;
0119 
0120     tmp = ioread32(reg);
0121     deadline = ata_deadline(jiffies, timeout);
0122 
0123     while (tmp != val && time_before(jiffies, deadline)) {
0124         ata_msleep(ap, interval);
0125         tmp = ioread32(reg);
0126     }
0127 
0128     return tmp;
0129 }
0130 
0131 /**
0132  * xgene_ahci_restart_engine - Restart the dma engine.
0133  * @ap : ATA port of interest
0134  *
0135  * Waits for completion of multiple commands and restarts
0136  * the DMA engine inside the controller.
0137  */
0138 static int xgene_ahci_restart_engine(struct ata_port *ap)
0139 {
0140     struct ahci_host_priv *hpriv = ap->host->private_data;
0141     struct ahci_port_priv *pp = ap->private_data;
0142     void __iomem *port_mmio = ahci_port_base(ap);
0143     u32 fbs;
0144 
0145     /*
0146      * In case of PMP multiple IDENTIFY DEVICE commands can be
0147      * issued inside PxCI. So need to poll PxCI for the
0148      * completion of outstanding IDENTIFY DEVICE commands before
0149      * we restart the DMA engine.
0150      */
0151     if (xgene_ahci_poll_reg_val(ap, port_mmio +
0152                     PORT_CMD_ISSUE, 0x0, 1, 100))
0153           return -EBUSY;
0154 
0155     hpriv->stop_engine(ap);
0156     ahci_start_fis_rx(ap);
0157 
0158     /*
0159      * Enable the PxFBS.FBS_EN bit as it
0160      * gets cleared due to stopping the engine.
0161      */
0162     if (pp->fbs_supported) {
0163         fbs = readl(port_mmio + PORT_FBS);
0164         writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
0165         fbs = readl(port_mmio + PORT_FBS);
0166     }
0167 
0168     hpriv->start_engine(ap);
0169 
0170     return 0;
0171 }
0172 
0173 /**
0174  * xgene_ahci_qc_issue - Issue commands to the device
0175  * @qc: Command to issue
0176  *
0177  * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot
0178  * clear the BSY bit after receiving the PIO setup FIS. This results in the dma
0179  * state machine goes into the CMFatalErrorUpdate state and locks up. By
0180  * restarting the dma engine, it removes the controller out of lock up state.
0181  *
0182  * Due to H/W errata, the controller is unable to save the PMP
0183  * field fetched from command header before sending the H2D FIS.
0184  * When the device returns the PMP port field in the D2H FIS, there is
0185  * a mismatch and results in command completion failure. The
0186  * workaround is to write the pmp value to PxFBS.DEV field before issuing
0187  * any command to PMP.
0188  */
0189 static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
0190 {
0191     struct ata_port *ap = qc->ap;
0192     struct ahci_host_priv *hpriv = ap->host->private_data;
0193     struct xgene_ahci_context *ctx = hpriv->plat_data;
0194     int rc = 0;
0195     u32 port_fbs;
0196     void __iomem *port_mmio = ahci_port_base(ap);
0197 
0198     /*
0199      * Write the pmp value to PxFBS.DEV
0200      * for case of Port Mulitplier.
0201      */
0202     if (ctx->class[ap->port_no] == ATA_DEV_PMP) {
0203         port_fbs = readl(port_mmio + PORT_FBS);
0204         port_fbs &= ~PORT_FBS_DEV_MASK;
0205         port_fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
0206         writel(port_fbs, port_mmio + PORT_FBS);
0207     }
0208 
0209     if (unlikely((ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA) ||
0210         (ctx->last_cmd[ap->port_no] == ATA_CMD_PACKET) ||
0211         (ctx->last_cmd[ap->port_no] == ATA_CMD_SMART)))
0212         xgene_ahci_restart_engine(ap);
0213 
0214     rc = ahci_qc_issue(qc);
0215 
0216     /* Save the last command issued */
0217     ctx->last_cmd[ap->port_no] = qc->tf.command;
0218 
0219     return rc;
0220 }
0221 
0222 static bool xgene_ahci_is_memram_inited(struct xgene_ahci_context *ctx)
0223 {
0224     void __iomem *diagcsr = ctx->csr_diag;
0225 
0226     return (readl(diagcsr + CFG_MEM_RAM_SHUTDOWN) == 0 &&
0227             readl(diagcsr + BLOCK_MEM_RDY) == 0xFFFFFFFF);
0228 }
0229 
0230 /**
0231  * xgene_ahci_read_id - Read ID data from the specified device
0232  * @dev: device
0233  * @tf: proposed taskfile
0234  * @id: data buffer
0235  *
0236  * This custom read ID function is required due to the fact that the HW
0237  * does not support DEVSLP.
0238  */
0239 static unsigned int xgene_ahci_read_id(struct ata_device *dev,
0240                        struct ata_taskfile *tf, __le16 *id)
0241 {
0242     u32 err_mask;
0243 
0244     err_mask = ata_do_dev_read_id(dev, tf, id);
0245     if (err_mask)
0246         return err_mask;
0247 
0248     /*
0249      * Mask reserved area. Word78 spec of Link Power Management
0250      * bit15-8: reserved
0251      * bit7: NCQ autosence
0252      * bit6: Software settings preservation supported
0253      * bit5: reserved
0254      * bit4: In-order sata delivery supported
0255      * bit3: DIPM requests supported
0256      * bit2: DMA Setup FIS Auto-Activate optimization supported
0257      * bit1: DMA Setup FIX non-Zero buffer offsets supported
0258      * bit0: Reserved
0259      *
0260      * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP
0261      */
0262     id[ATA_ID_FEATURE_SUPP] &= cpu_to_le16(~(1 << 8));
0263 
0264     return 0;
0265 }
0266 
0267 static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
0268 {
0269     void __iomem *mmio = ctx->hpriv->mmio;
0270     u32 val;
0271 
0272     dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n",
0273         mmio, channel);
0274     val = readl(mmio + PORTCFG);
0275     val = PORTADDR_SET(val, channel == 0 ? 2 : 3);
0276     writel(val, mmio + PORTCFG);
0277     readl(mmio + PORTCFG);  /* Force a barrier */
0278     /* Disable fix rate */
0279     writel(0x0001fffe, mmio + PORTPHY1CFG);
0280     readl(mmio + PORTPHY1CFG); /* Force a barrier */
0281     writel(0x28183219, mmio + PORTPHY2CFG);
0282     readl(mmio + PORTPHY2CFG); /* Force a barrier */
0283     writel(0x13081008, mmio + PORTPHY3CFG);
0284     readl(mmio + PORTPHY3CFG); /* Force a barrier */
0285     writel(0x00480815, mmio + PORTPHY4CFG);
0286     readl(mmio + PORTPHY4CFG); /* Force a barrier */
0287     /* Set window negotiation */
0288     val = readl(mmio + PORTPHY5CFG);
0289     val = PORTPHY5CFG_RTCHG_SET(val, 0x300);
0290     writel(val, mmio + PORTPHY5CFG);
0291     readl(mmio + PORTPHY5CFG); /* Force a barrier */
0292     val = readl(mmio + PORTAXICFG);
0293     val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */
0294     val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */
0295     writel(val, mmio + PORTAXICFG);
0296     readl(mmio + PORTAXICFG); /* Force a barrier */
0297     /* Set the watermark threshold of the receive FIFO */
0298     val = readl(mmio + PORTRANSCFG);
0299     val = PORTRANSCFG_RXWM_SET(val, 0x30);
0300     writel(val, mmio + PORTRANSCFG);
0301 }
0302 
0303 /**
0304  * xgene_ahci_do_hardreset - Issue the actual COMRESET
0305  * @link: link to reset
0306  * @deadline: deadline jiffies for the operation
0307  * @online: Return value to indicate if device online
0308  *
0309  * Due to the limitation of the hardware PHY, a difference set of setting is
0310  * required for each supported disk speed - Gen3 (6.0Gbps), Gen2 (3.0Gbps),
0311  * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will
0312  * report disparity error and etc. In addition, during COMRESET, there can
0313  * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and
0314  * SERR_10B_8B_ERR, the PHY receiver line must be reseted. Also during long
0315  * reboot cycle regression, sometimes the PHY reports link down even if the
0316  * device is present because of speed negotiation failure. so need to retry
0317  * the COMRESET to get the link up. The following algorithm is followed to
0318  * proper configure the hardware PHY during COMRESET:
0319  *
0320  * Alg Part 1:
0321  * 1. Start the PHY at Gen3 speed (default setting)
0322  * 2. Issue the COMRESET
0323  * 3. If no link, go to Alg Part 3
0324  * 4. If link up, determine if the negotiated speed matches the PHY
0325  *    configured speed
0326  * 5. If they matched, go to Alg Part 2
0327  * 6. If they do not matched and first time, configure the PHY for the linked
0328  *    up disk speed and repeat step 2
0329  * 7. Go to Alg Part 2
0330  *
0331  * Alg Part 2:
0332  * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error
0333  *    reported in the register PORT_SCR_ERR, then reset the PHY receiver line
0334  * 2. Go to Alg Part 4
0335  *
0336  * Alg Part 3:
0337  * 1. Check the PORT_SCR_STAT to see whether device presence detected but PHY
0338  *    communication establishment failed and maximum link down attempts are
0339  *    less than Max attempts 3 then goto Alg Part 1.
0340  * 2. Go to Alg Part 4.
0341  *
0342  * Alg Part 4:
0343  * 1. Clear any pending from register PORT_SCR_ERR.
0344  *
0345  * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition
0346  *       and until the underlying PHY supports an method to reset the receiver
0347  *       line, on detection of SERR_DISPARITY or SERR_10B_8B_ERR errors,
0348  *       an warning message will be printed.
0349  */
0350 static int xgene_ahci_do_hardreset(struct ata_link *link,
0351                    unsigned long deadline, bool *online)
0352 {
0353     const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
0354     struct ata_port *ap = link->ap;
0355     struct ahci_host_priv *hpriv = ap->host->private_data;
0356     struct xgene_ahci_context *ctx = hpriv->plat_data;
0357     struct ahci_port_priv *pp = ap->private_data;
0358     u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
0359     void __iomem *port_mmio = ahci_port_base(ap);
0360     struct ata_taskfile tf;
0361     int link_down_retry = 0;
0362     int rc;
0363     u32 val, sstatus;
0364 
0365     do {
0366         /* clear D2H reception area to properly wait for D2H FIS */
0367         ata_tf_init(link->device, &tf);
0368         tf.status = ATA_BUSY;
0369         ata_tf_to_fis(&tf, 0, 0, d2h_fis);
0370         rc = sata_link_hardreset(link, timing, deadline, online,
0371                  ahci_check_ready);
0372         if (*online) {
0373             val = readl(port_mmio + PORT_SCR_ERR);
0374             if (val & (SERR_DISPARITY | SERR_10B_8B_ERR))
0375                 dev_warn(ctx->dev, "link has error\n");
0376             break;
0377         }
0378 
0379         sata_scr_read(link, SCR_STATUS, &sstatus);
0380     } while (link_down_retry++ < MAX_LINK_DOWN_RETRY &&
0381          (sstatus & 0xff) == 0x1);
0382 
0383     /* clear all errors if any pending */
0384     val = readl(port_mmio + PORT_SCR_ERR);
0385     writel(val, port_mmio + PORT_SCR_ERR);
0386 
0387     return rc;
0388 }
0389 
0390 static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class,
0391                 unsigned long deadline)
0392 {
0393     struct ata_port *ap = link->ap;
0394         struct ahci_host_priv *hpriv = ap->host->private_data;
0395     void __iomem *port_mmio = ahci_port_base(ap);
0396     bool online;
0397     int rc;
0398     u32 portcmd_saved;
0399     u32 portclb_saved;
0400     u32 portclbhi_saved;
0401     u32 portrxfis_saved;
0402     u32 portrxfishi_saved;
0403 
0404     /* As hardreset resets these CSR, save it to restore later */
0405     portcmd_saved = readl(port_mmio + PORT_CMD);
0406     portclb_saved = readl(port_mmio + PORT_LST_ADDR);
0407     portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI);
0408     portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR);
0409     portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI);
0410 
0411     hpriv->stop_engine(ap);
0412 
0413     rc = xgene_ahci_do_hardreset(link, deadline, &online);
0414 
0415     /* As controller hardreset clears them, restore them */
0416     writel(portcmd_saved, port_mmio + PORT_CMD);
0417     writel(portclb_saved, port_mmio + PORT_LST_ADDR);
0418     writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI);
0419     writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR);
0420     writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI);
0421 
0422     hpriv->start_engine(ap);
0423 
0424     if (online)
0425         *class = ahci_dev_classify(ap);
0426 
0427     return rc;
0428 }
0429 
0430 static void xgene_ahci_host_stop(struct ata_host *host)
0431 {
0432     struct ahci_host_priv *hpriv = host->private_data;
0433 
0434     ahci_platform_disable_resources(hpriv);
0435 }
0436 
0437 /**
0438  * xgene_ahci_pmp_softreset - Issue the softreset to the drives connected
0439  *                            to Port Multiplier.
0440  * @link: link to reset
0441  * @class: Return value to indicate class of device
0442  * @deadline: deadline jiffies for the operation
0443  *
0444  * Due to H/W errata, the controller is unable to save the PMP
0445  * field fetched from command header before sending the H2D FIS.
0446  * When the device returns the PMP port field in the D2H FIS, there is
0447  * a mismatch and results in command completion failure. The workaround
0448  * is to write the pmp value to PxFBS.DEV field before issuing any command
0449  * to PMP.
0450  */
0451 static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
0452               unsigned long deadline)
0453 {
0454     int pmp = sata_srst_pmp(link);
0455     struct ata_port *ap = link->ap;
0456     u32 rc;
0457     void __iomem *port_mmio = ahci_port_base(ap);
0458     u32 port_fbs;
0459 
0460     /*
0461      * Set PxFBS.DEV field with pmp
0462      * value.
0463      */
0464     port_fbs = readl(port_mmio + PORT_FBS);
0465     port_fbs &= ~PORT_FBS_DEV_MASK;
0466     port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
0467     writel(port_fbs, port_mmio + PORT_FBS);
0468 
0469     rc = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
0470 
0471     return rc;
0472 }
0473 
0474 /**
0475  * xgene_ahci_softreset - Issue the softreset to the drive.
0476  * @link: link to reset
0477  * @class: Return value to indicate class of device
0478  * @deadline: deadline jiffies for the operation
0479  *
0480  * Due to H/W errata, the controller is unable to save the PMP
0481  * field fetched from command header before sending the H2D FIS.
0482  * When the device returns the PMP port field in the D2H FIS, there is
0483  * a mismatch and results in command completion failure. The workaround
0484  * is to write the pmp value to PxFBS.DEV field before issuing any command
0485  * to PMP. Here is the algorithm to detect PMP :
0486  *
0487  * 1. Save the PxFBS value
0488  * 2. Program PxFBS.DEV with pmp value send by framework. Framework sends
0489  *    0xF for both PMP/NON-PMP initially
0490  * 3. Issue softreset
0491  * 4. If signature class is PMP goto 6
0492  * 5. restore the original PxFBS and goto 3
0493  * 6. return
0494  */
0495 static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class,
0496               unsigned long deadline)
0497 {
0498     int pmp = sata_srst_pmp(link);
0499     struct ata_port *ap = link->ap;
0500     struct ahci_host_priv *hpriv = ap->host->private_data;
0501     struct xgene_ahci_context *ctx = hpriv->plat_data;
0502     void __iomem *port_mmio = ahci_port_base(ap);
0503     u32 port_fbs;
0504     u32 port_fbs_save;
0505     u32 retry = 1;
0506     u32 rc;
0507 
0508     port_fbs_save = readl(port_mmio + PORT_FBS);
0509 
0510     /*
0511      * Set PxFBS.DEV field with pmp
0512      * value.
0513      */
0514     port_fbs = readl(port_mmio + PORT_FBS);
0515     port_fbs &= ~PORT_FBS_DEV_MASK;
0516     port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
0517     writel(port_fbs, port_mmio + PORT_FBS);
0518 
0519 softreset_retry:
0520     rc = ahci_do_softreset(link, class, pmp,
0521                    deadline, ahci_check_ready);
0522 
0523     ctx->class[ap->port_no] = *class;
0524     if (*class != ATA_DEV_PMP) {
0525         /*
0526          * Retry for normal drives without
0527          * setting PxFBS.DEV field with pmp value.
0528          */
0529         if (retry--) {
0530             writel(port_fbs_save, port_mmio + PORT_FBS);
0531             goto softreset_retry;
0532         }
0533     }
0534 
0535     return rc;
0536 }
0537 
0538 /**
0539  * xgene_ahci_handle_broken_edge_irq - Handle the broken irq.
0540  * @host: Host that recieved the irq
0541  * @irq_masked: HOST_IRQ_STAT value
0542  *
0543  * For hardware with broken edge trigger latch
0544  * the HOST_IRQ_STAT register misses the edge interrupt
0545  * when clearing of HOST_IRQ_STAT register and hardware
0546  * reporting the PORT_IRQ_STAT register at the
0547  * same clock cycle.
0548  * As such, the algorithm below outlines the workaround.
0549  *
0550  * 1. Read HOST_IRQ_STAT register and save the state.
0551  * 2. Clear the HOST_IRQ_STAT register.
0552  * 3. Read back the HOST_IRQ_STAT register.
0553  * 4. If HOST_IRQ_STAT register equals to zero, then
0554  *    traverse the rest of port's PORT_IRQ_STAT register
0555  *    to check if an interrupt is triggered at that point else
0556  *    go to step 6.
0557  * 5. If PORT_IRQ_STAT register of rest ports is not equal to zero
0558  *    then update the state of HOST_IRQ_STAT saved in step 1.
0559  * 6. Handle port interrupts.
0560  * 7. Exit
0561  */
0562 static int xgene_ahci_handle_broken_edge_irq(struct ata_host *host,
0563                          u32 irq_masked)
0564 {
0565     struct ahci_host_priv *hpriv = host->private_data;
0566     void __iomem *port_mmio;
0567     int i;
0568 
0569     if (!readl(hpriv->mmio + HOST_IRQ_STAT)) {
0570         for (i = 0; i < host->n_ports; i++) {
0571             if (irq_masked & (1 << i))
0572                 continue;
0573 
0574             port_mmio = ahci_port_base(host->ports[i]);
0575             if (readl(port_mmio + PORT_IRQ_STAT))
0576                 irq_masked |= (1 << i);
0577         }
0578     }
0579 
0580     return ahci_handle_port_intr(host, irq_masked);
0581 }
0582 
0583 static irqreturn_t xgene_ahci_irq_intr(int irq, void *dev_instance)
0584 {
0585     struct ata_host *host = dev_instance;
0586     struct ahci_host_priv *hpriv;
0587     unsigned int rc = 0;
0588     void __iomem *mmio;
0589     u32 irq_stat, irq_masked;
0590 
0591     hpriv = host->private_data;
0592     mmio = hpriv->mmio;
0593 
0594     /* sigh.  0xffffffff is a valid return from h/w */
0595     irq_stat = readl(mmio + HOST_IRQ_STAT);
0596     if (!irq_stat)
0597         return IRQ_NONE;
0598 
0599     irq_masked = irq_stat & hpriv->port_map;
0600 
0601     spin_lock(&host->lock);
0602 
0603     /*
0604      * HOST_IRQ_STAT behaves as edge triggered latch meaning that
0605      * it should be cleared before all the port events are cleared.
0606      */
0607     writel(irq_stat, mmio + HOST_IRQ_STAT);
0608 
0609     rc = xgene_ahci_handle_broken_edge_irq(host, irq_masked);
0610 
0611     spin_unlock(&host->lock);
0612 
0613     return IRQ_RETVAL(rc);
0614 }
0615 
0616 static struct ata_port_operations xgene_ahci_v1_ops = {
0617     .inherits = &ahci_ops,
0618     .host_stop = xgene_ahci_host_stop,
0619     .hardreset = xgene_ahci_hardreset,
0620     .read_id = xgene_ahci_read_id,
0621     .qc_issue = xgene_ahci_qc_issue,
0622     .softreset = xgene_ahci_softreset,
0623     .pmp_softreset = xgene_ahci_pmp_softreset
0624 };
0625 
0626 static const struct ata_port_info xgene_ahci_v1_port_info = {
0627     .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
0628     .pio_mask = ATA_PIO4,
0629     .udma_mask = ATA_UDMA6,
0630     .port_ops = &xgene_ahci_v1_ops,
0631 };
0632 
0633 static struct ata_port_operations xgene_ahci_v2_ops = {
0634     .inherits = &ahci_ops,
0635     .host_stop = xgene_ahci_host_stop,
0636     .hardreset = xgene_ahci_hardreset,
0637     .read_id = xgene_ahci_read_id,
0638 };
0639 
0640 static const struct ata_port_info xgene_ahci_v2_port_info = {
0641     .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
0642     .pio_mask = ATA_PIO4,
0643     .udma_mask = ATA_UDMA6,
0644     .port_ops = &xgene_ahci_v2_ops,
0645 };
0646 
0647 static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv)
0648 {
0649     struct xgene_ahci_context *ctx = hpriv->plat_data;
0650     int i;
0651     int rc;
0652     u32 val;
0653 
0654     /* Remove IP RAM out of shutdown */
0655     rc = xgene_ahci_init_memram(ctx);
0656     if (rc)
0657         return rc;
0658 
0659     for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++)
0660         xgene_ahci_set_phy_cfg(ctx, i);
0661 
0662     /* AXI disable Mask */
0663     writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT);
0664     readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */
0665     writel(0, ctx->csr_core + INTSTATUSMASK);
0666     val = readl(ctx->csr_core + INTSTATUSMASK); /* Force a barrier */
0667     dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n",
0668         INTSTATUSMASK, val);
0669 
0670     writel(0x0, ctx->csr_core + ERRINTSTATUSMASK);
0671     readl(ctx->csr_core + ERRINTSTATUSMASK); /* Force a barrier */
0672     writel(0x0, ctx->csr_axi + INT_SLV_TMOMASK);
0673     readl(ctx->csr_axi + INT_SLV_TMOMASK);
0674 
0675     /* Enable AXI Interrupt */
0676     writel(0xffffffff, ctx->csr_core + SLVRDERRATTRIBUTES);
0677     writel(0xffffffff, ctx->csr_core + SLVWRERRATTRIBUTES);
0678     writel(0xffffffff, ctx->csr_core + MSTRDERRATTRIBUTES);
0679     writel(0xffffffff, ctx->csr_core + MSTWRERRATTRIBUTES);
0680 
0681     /* Enable coherency */
0682     val = readl(ctx->csr_core + BUSCTLREG);
0683     val &= ~0x00000002;     /* Enable write coherency */
0684     val &= ~0x00000001;     /* Enable read coherency */
0685     writel(val, ctx->csr_core + BUSCTLREG);
0686 
0687     val = readl(ctx->csr_core + IOFMSTRWAUX);
0688     val |= (1 << 3);        /* Enable read coherency */
0689     val |= (1 << 9);        /* Enable write coherency */
0690     writel(val, ctx->csr_core + IOFMSTRWAUX);
0691     val = readl(ctx->csr_core + IOFMSTRWAUX);
0692     dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n",
0693         IOFMSTRWAUX, val);
0694 
0695     return rc;
0696 }
0697 
0698 static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx)
0699 {
0700     u32 val;
0701 
0702     /* Check for optional MUX resource */
0703     if (!ctx->csr_mux)
0704         return 0;
0705 
0706     val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
0707     val &= ~CFG_SATA_ENET_SELECT_MASK;
0708     writel(val, ctx->csr_mux + SATA_ENET_CONFIG_REG);
0709     val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
0710     return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
0711 }
0712 
0713 static struct scsi_host_template ahci_platform_sht = {
0714     AHCI_SHT(DRV_NAME),
0715 };
0716 
0717 #ifdef CONFIG_ACPI
0718 static const struct acpi_device_id xgene_ahci_acpi_match[] = {
0719     { "APMC0D0D", XGENE_AHCI_V1},
0720     { "APMC0D32", XGENE_AHCI_V2},
0721     {},
0722 };
0723 MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match);
0724 #endif
0725 
0726 static const struct of_device_id xgene_ahci_of_match[] = {
0727     {.compatible = "apm,xgene-ahci", .data = (void *) XGENE_AHCI_V1},
0728     {.compatible = "apm,xgene-ahci-v2", .data = (void *) XGENE_AHCI_V2},
0729     { /* sentinel */ }
0730 };
0731 MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
0732 
0733 static int xgene_ahci_probe(struct platform_device *pdev)
0734 {
0735     struct device *dev = &pdev->dev;
0736     struct ahci_host_priv *hpriv;
0737     struct xgene_ahci_context *ctx;
0738     struct resource *res;
0739     const struct of_device_id *of_devid;
0740     enum xgene_ahci_version version = XGENE_AHCI_V1;
0741     const struct ata_port_info *ppi[] = { &xgene_ahci_v1_port_info,
0742                           &xgene_ahci_v2_port_info };
0743     int rc;
0744 
0745     hpriv = ahci_platform_get_resources(pdev, 0);
0746     if (IS_ERR(hpriv))
0747         return PTR_ERR(hpriv);
0748 
0749     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0750     if (!ctx)
0751         return -ENOMEM;
0752 
0753     hpriv->plat_data = ctx;
0754     ctx->hpriv = hpriv;
0755     ctx->dev = dev;
0756 
0757     /* Retrieve the IP core resource */
0758     res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0759     ctx->csr_core = devm_ioremap_resource(dev, res);
0760     if (IS_ERR(ctx->csr_core))
0761         return PTR_ERR(ctx->csr_core);
0762 
0763     /* Retrieve the IP diagnostic resource */
0764     res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
0765     ctx->csr_diag = devm_ioremap_resource(dev, res);
0766     if (IS_ERR(ctx->csr_diag))
0767         return PTR_ERR(ctx->csr_diag);
0768 
0769     /* Retrieve the IP AXI resource */
0770     res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
0771     ctx->csr_axi = devm_ioremap_resource(dev, res);
0772     if (IS_ERR(ctx->csr_axi))
0773         return PTR_ERR(ctx->csr_axi);
0774 
0775     /* Retrieve the optional IP mux resource */
0776     res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
0777     if (res) {
0778         void __iomem *csr = devm_ioremap_resource(dev, res);
0779         if (IS_ERR(csr))
0780             return PTR_ERR(csr);
0781 
0782         ctx->csr_mux = csr;
0783     }
0784 
0785     of_devid = of_match_device(xgene_ahci_of_match, dev);
0786     if (of_devid) {
0787         if (of_devid->data)
0788             version = (enum xgene_ahci_version) of_devid->data;
0789     }
0790 #ifdef CONFIG_ACPI
0791     else {
0792         const struct acpi_device_id *acpi_id;
0793         struct acpi_device_info *info;
0794         acpi_status status;
0795 
0796         acpi_id = acpi_match_device(xgene_ahci_acpi_match, &pdev->dev);
0797         if (!acpi_id) {
0798             dev_warn(&pdev->dev, "No node entry in ACPI table. Assume version1\n");
0799             version = XGENE_AHCI_V1;
0800         } else if (acpi_id->driver_data) {
0801             version = (enum xgene_ahci_version) acpi_id->driver_data;
0802             status = acpi_get_object_info(ACPI_HANDLE(&pdev->dev), &info);
0803             if (ACPI_FAILURE(status)) {
0804                 dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n",
0805                     __func__);
0806                 version = XGENE_AHCI_V1;
0807             } else {
0808                 if (info->valid & ACPI_VALID_CID)
0809                     version = XGENE_AHCI_V2;
0810                 kfree(info);
0811             }
0812         }
0813     }
0814 #endif
0815 
0816     dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core,
0817         hpriv->mmio);
0818 
0819     /* Select ATA */
0820     if ((rc = xgene_ahci_mux_select(ctx))) {
0821         dev_err(dev, "SATA mux selection failed error %d\n", rc);
0822         return -ENODEV;
0823     }
0824 
0825     if (xgene_ahci_is_memram_inited(ctx)) {
0826         dev_info(dev, "skip clock and PHY initialization\n");
0827         goto skip_clk_phy;
0828     }
0829 
0830     /* Due to errata, HW requires full toggle transition */
0831     rc = ahci_platform_enable_clks(hpriv);
0832     if (rc)
0833         goto disable_resources;
0834     ahci_platform_disable_clks(hpriv);
0835 
0836     rc = ahci_platform_enable_resources(hpriv);
0837     if (rc)
0838         goto disable_resources;
0839 
0840     /* Configure the host controller */
0841     xgene_ahci_hw_init(hpriv);
0842 skip_clk_phy:
0843 
0844     switch (version) {
0845     case XGENE_AHCI_V1:
0846         hpriv->flags = AHCI_HFLAG_NO_NCQ;
0847         break;
0848     case XGENE_AHCI_V2:
0849         hpriv->flags |= AHCI_HFLAG_YES_FBS;
0850         hpriv->irq_handler = xgene_ahci_irq_intr;
0851         break;
0852     default:
0853         break;
0854     }
0855 
0856     rc = ahci_platform_init_host(pdev, hpriv, ppi[version - 1],
0857                      &ahci_platform_sht);
0858     if (rc)
0859         goto disable_resources;
0860 
0861     dev_dbg(dev, "X-Gene SATA host controller initialized\n");
0862     return 0;
0863 
0864 disable_resources:
0865     ahci_platform_disable_resources(hpriv);
0866     return rc;
0867 }
0868 
0869 static struct platform_driver xgene_ahci_driver = {
0870     .probe = xgene_ahci_probe,
0871     .remove = ata_platform_remove_one,
0872     .driver = {
0873         .name = DRV_NAME,
0874         .of_match_table = xgene_ahci_of_match,
0875         .acpi_match_table = ACPI_PTR(xgene_ahci_acpi_match),
0876     },
0877 };
0878 
0879 module_platform_driver(xgene_ahci_driver);
0880 
0881 MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver");
0882 MODULE_AUTHOR("Loc Ho <lho@apm.com>");
0883 MODULE_LICENSE("GPL");
0884 MODULE_VERSION("0.4");