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