linux/drivers/ata/ahci_qoriq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Freescale QorIQ AHCI SATA platform driver
   4 *
   5 * Copyright 2015 Freescale, Inc.
   6 *   Tang Yuantian <Yuantian.Tang@freescale.com>
   7 */
   8
   9#include <linux/acpi.h>
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/pm.h>
  13#include <linux/ahci_platform.h>
  14#include <linux/device.h>
  15#include <linux/of_address.h>
  16#include <linux/of.h>
  17#include <linux/of_device.h>
  18#include <linux/platform_device.h>
  19#include <linux/libata.h>
  20#include "ahci.h"
  21
  22#define DRV_NAME "ahci-qoriq"
  23
  24/* port register definition */
  25#define PORT_PHY1       0xA8
  26#define PORT_PHY2       0xAC
  27#define PORT_PHY3       0xB0
  28#define PORT_PHY4       0xB4
  29#define PORT_PHY5       0xB8
  30#define PORT_AXICC      0xBC
  31#define PORT_TRANS      0xC8
  32
  33/* port register default value */
  34#define AHCI_PORT_PHY_1_CFG     0xa003fffe
  35#define AHCI_PORT_PHY2_CFG      0x28184d1f
  36#define AHCI_PORT_PHY3_CFG      0x0e081509
  37#define AHCI_PORT_TRANS_CFG     0x08000029
  38#define AHCI_PORT_AXICC_CFG     0x3fffffff
  39
  40/* for ls1021a */
  41#define LS1021A_PORT_PHY2       0x28183414
  42#define LS1021A_PORT_PHY3       0x0e080e06
  43#define LS1021A_PORT_PHY4       0x064a080b
  44#define LS1021A_PORT_PHY5       0x2aa86470
  45#define LS1021A_AXICC_ADDR      0xC0
  46
  47#define SATA_ECC_DISABLE        0x00020000
  48#define ECC_DIS_ARMV8_CH2       0x80000000
  49#define ECC_DIS_LS1088A         0x40000000
  50
  51enum ahci_qoriq_type {
  52        AHCI_LS1021A,
  53        AHCI_LS1028A,
  54        AHCI_LS1043A,
  55        AHCI_LS2080A,
  56        AHCI_LS1046A,
  57        AHCI_LS1088A,
  58        AHCI_LS2088A,
  59        AHCI_LX2160A,
  60};
  61
  62struct ahci_qoriq_priv {
  63        struct ccsr_ahci *reg_base;
  64        enum ahci_qoriq_type type;
  65        void __iomem *ecc_addr;
  66        bool is_dmacoherent;
  67};
  68
  69static bool ecc_initialized;
  70
  71static const struct of_device_id ahci_qoriq_of_match[] = {
  72        { .compatible = "fsl,ls1021a-ahci", .data = (void *)AHCI_LS1021A},
  73        { .compatible = "fsl,ls1028a-ahci", .data = (void *)AHCI_LS1028A},
  74        { .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A},
  75        { .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A},
  76        { .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A},
  77        { .compatible = "fsl,ls1088a-ahci", .data = (void *)AHCI_LS1088A},
  78        { .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A},
  79        { .compatible = "fsl,lx2160a-ahci", .data = (void *)AHCI_LX2160A},
  80        {},
  81};
  82MODULE_DEVICE_TABLE(of, ahci_qoriq_of_match);
  83
  84static const struct acpi_device_id ahci_qoriq_acpi_match[] = {
  85        {"NXP0004", .driver_data = (kernel_ulong_t)AHCI_LX2160A},
  86        { }
  87};
  88MODULE_DEVICE_TABLE(acpi, ahci_qoriq_acpi_match);
  89
  90static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class,
  91                          unsigned long deadline)
  92{
  93        const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
  94        void __iomem *port_mmio = ahci_port_base(link->ap);
  95        u32 px_cmd, px_is, px_val;
  96        struct ata_port *ap = link->ap;
  97        struct ahci_port_priv *pp = ap->private_data;
  98        struct ahci_host_priv *hpriv = ap->host->private_data;
  99        struct ahci_qoriq_priv *qoriq_priv = hpriv->plat_data;
 100        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
 101        struct ata_taskfile tf;
 102        bool online;
 103        int rc;
 104        bool ls1021a_workaround = (qoriq_priv->type == AHCI_LS1021A);
 105
 106        DPRINTK("ENTER\n");
 107
 108        hpriv->stop_engine(ap);
 109
 110        /*
 111         * There is a errata on ls1021a Rev1.0 and Rev2.0 which is:
 112         * A-009042: The device detection initialization sequence
 113         * mistakenly resets some registers.
 114         *
 115         * Workaround for this is:
 116         * The software should read and store PxCMD and PxIS values
 117         * before issuing the device detection initialization sequence.
 118         * After the sequence is complete, software should restore the
 119         * PxCMD and PxIS with the stored values.
 120         */
 121        if (ls1021a_workaround) {
 122                px_cmd = readl(port_mmio + PORT_CMD);
 123                px_is = readl(port_mmio + PORT_IRQ_STAT);
 124        }
 125
 126        /* clear D2H reception area to properly wait for D2H FIS */
 127        ata_tf_init(link->device, &tf);
 128        tf.command = ATA_BUSY;
 129        ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 130
 131        rc = sata_link_hardreset(link, timing, deadline, &online,
 132                                 ahci_check_ready);
 133
 134        /* restore the PxCMD and PxIS on ls1021 */
 135        if (ls1021a_workaround) {
 136                px_val = readl(port_mmio + PORT_CMD);
 137                if (px_val != px_cmd)
 138                        writel(px_cmd, port_mmio + PORT_CMD);
 139
 140                px_val = readl(port_mmio + PORT_IRQ_STAT);
 141                if (px_val != px_is)
 142                        writel(px_is, port_mmio + PORT_IRQ_STAT);
 143        }
 144
 145        hpriv->start_engine(ap);
 146
 147        if (online)
 148                *class = ahci_dev_classify(ap);
 149
 150        DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
 151        return rc;
 152}
 153
 154static struct ata_port_operations ahci_qoriq_ops = {
 155        .inherits       = &ahci_ops,
 156        .hardreset      = ahci_qoriq_hardreset,
 157};
 158
 159static const struct ata_port_info ahci_qoriq_port_info = {
 160        .flags          = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
 161        .pio_mask       = ATA_PIO4,
 162        .udma_mask      = ATA_UDMA6,
 163        .port_ops       = &ahci_qoriq_ops,
 164};
 165
 166static struct scsi_host_template ahci_qoriq_sht = {
 167        AHCI_SHT(DRV_NAME),
 168};
 169
 170static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
 171{
 172        struct ahci_qoriq_priv *qpriv = hpriv->plat_data;
 173        void __iomem *reg_base = hpriv->mmio;
 174
 175        switch (qpriv->type) {
 176        case AHCI_LS1021A:
 177                if (!(qpriv->ecc_addr || ecc_initialized))
 178                        return -EINVAL;
 179                else if (qpriv->ecc_addr && !ecc_initialized)
 180                        writel(SATA_ECC_DISABLE, qpriv->ecc_addr);
 181                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
 182                writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2);
 183                writel(LS1021A_PORT_PHY3, reg_base + PORT_PHY3);
 184                writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4);
 185                writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5);
 186                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
 187                if (qpriv->is_dmacoherent)
 188                        writel(AHCI_PORT_AXICC_CFG,
 189                                        reg_base + LS1021A_AXICC_ADDR);
 190                break;
 191
 192        case AHCI_LS1043A:
 193                if (!(qpriv->ecc_addr || ecc_initialized))
 194                        return -EINVAL;
 195                else if (qpriv->ecc_addr && !ecc_initialized)
 196                        writel(readl(qpriv->ecc_addr) |
 197                               ECC_DIS_ARMV8_CH2,
 198                               qpriv->ecc_addr);
 199                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
 200                writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
 201                writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
 202                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
 203                if (qpriv->is_dmacoherent)
 204                        writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
 205                break;
 206
 207        case AHCI_LS2080A:
 208                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
 209                writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
 210                writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
 211                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
 212                if (qpriv->is_dmacoherent)
 213                        writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
 214                break;
 215
 216        case AHCI_LS1046A:
 217                if (!(qpriv->ecc_addr || ecc_initialized))
 218                        return -EINVAL;
 219                else if (qpriv->ecc_addr && !ecc_initialized)
 220                        writel(readl(qpriv->ecc_addr) |
 221                               ECC_DIS_ARMV8_CH2,
 222                               qpriv->ecc_addr);
 223                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
 224                writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
 225                writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
 226                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
 227                if (qpriv->is_dmacoherent)
 228                        writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
 229                break;
 230
 231        case AHCI_LS1028A:
 232        case AHCI_LS1088A:
 233        case AHCI_LX2160A:
 234                if (!(qpriv->ecc_addr || ecc_initialized))
 235                        return -EINVAL;
 236                else if (qpriv->ecc_addr && !ecc_initialized)
 237                        writel(readl(qpriv->ecc_addr) |
 238                               ECC_DIS_LS1088A,
 239                               qpriv->ecc_addr);
 240                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
 241                writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
 242                writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
 243                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
 244                if (qpriv->is_dmacoherent)
 245                        writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
 246                break;
 247
 248        case AHCI_LS2088A:
 249                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
 250                writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
 251                writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
 252                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
 253                if (qpriv->is_dmacoherent)
 254                        writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
 255                break;
 256        }
 257
 258        ecc_initialized = true;
 259        return 0;
 260}
 261
 262static int ahci_qoriq_probe(struct platform_device *pdev)
 263{
 264        struct device_node *np = pdev->dev.of_node;
 265        const struct acpi_device_id *acpi_id;
 266        struct device *dev = &pdev->dev;
 267        struct ahci_host_priv *hpriv;
 268        struct ahci_qoriq_priv *qoriq_priv;
 269        const struct of_device_id *of_id;
 270        struct resource *res;
 271        int rc;
 272
 273        hpriv = ahci_platform_get_resources(pdev, 0);
 274        if (IS_ERR(hpriv))
 275                return PTR_ERR(hpriv);
 276
 277        of_id = of_match_node(ahci_qoriq_of_match, np);
 278        acpi_id = acpi_match_device(ahci_qoriq_acpi_match, &pdev->dev);
 279        if (!(of_id || acpi_id))
 280                return -ENODEV;
 281
 282        qoriq_priv = devm_kzalloc(dev, sizeof(*qoriq_priv), GFP_KERNEL);
 283        if (!qoriq_priv)
 284                return -ENOMEM;
 285
 286        if (of_id)
 287                qoriq_priv->type = (enum ahci_qoriq_type)of_id->data;
 288        else
 289                qoriq_priv->type = (enum ahci_qoriq_type)acpi_id->driver_data;
 290
 291        if (unlikely(!ecc_initialized)) {
 292                res = platform_get_resource_byname(pdev,
 293                                                   IORESOURCE_MEM,
 294                                                   "sata-ecc");
 295                if (res) {
 296                        qoriq_priv->ecc_addr =
 297                                devm_ioremap_resource(dev, res);
 298                        if (IS_ERR(qoriq_priv->ecc_addr))
 299                                return PTR_ERR(qoriq_priv->ecc_addr);
 300                }
 301        }
 302
 303        if (device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT)
 304                qoriq_priv->is_dmacoherent = true;
 305
 306        rc = ahci_platform_enable_resources(hpriv);
 307        if (rc)
 308                return rc;
 309
 310        hpriv->plat_data = qoriq_priv;
 311        rc = ahci_qoriq_phy_init(hpriv);
 312        if (rc)
 313                goto disable_resources;
 314
 315        rc = ahci_platform_init_host(pdev, hpriv, &ahci_qoriq_port_info,
 316                                     &ahci_qoriq_sht);
 317        if (rc)
 318                goto disable_resources;
 319
 320        return 0;
 321
 322disable_resources:
 323        ahci_platform_disable_resources(hpriv);
 324
 325        return rc;
 326}
 327
 328#ifdef CONFIG_PM_SLEEP
 329static int ahci_qoriq_resume(struct device *dev)
 330{
 331        struct ata_host *host = dev_get_drvdata(dev);
 332        struct ahci_host_priv *hpriv = host->private_data;
 333        int rc;
 334
 335        rc = ahci_platform_enable_resources(hpriv);
 336        if (rc)
 337                return rc;
 338
 339        rc = ahci_qoriq_phy_init(hpriv);
 340        if (rc)
 341                goto disable_resources;
 342
 343        rc = ahci_platform_resume_host(dev);
 344        if (rc)
 345                goto disable_resources;
 346
 347        /* We resumed so update PM runtime state */
 348        pm_runtime_disable(dev);
 349        pm_runtime_set_active(dev);
 350        pm_runtime_enable(dev);
 351
 352        return 0;
 353
 354disable_resources:
 355        ahci_platform_disable_resources(hpriv);
 356
 357        return rc;
 358}
 359#endif
 360
 361static SIMPLE_DEV_PM_OPS(ahci_qoriq_pm_ops, ahci_platform_suspend,
 362                         ahci_qoriq_resume);
 363
 364static struct platform_driver ahci_qoriq_driver = {
 365        .probe = ahci_qoriq_probe,
 366        .remove = ata_platform_remove_one,
 367        .driver = {
 368                .name = DRV_NAME,
 369                .of_match_table = ahci_qoriq_of_match,
 370                .acpi_match_table = ahci_qoriq_acpi_match,
 371                .pm = &ahci_qoriq_pm_ops,
 372        },
 373};
 374module_platform_driver(ahci_qoriq_driver);
 375
 376MODULE_DESCRIPTION("Freescale QorIQ AHCI SATA platform driver");
 377MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
 378MODULE_LICENSE("GPL");
 379