linux/drivers/ata/ahci_platform.c
<<
>>
Prefs
   1/*
   2 * AHCI SATA platform driver
   3 *
   4 * Copyright 2004-2005  Red Hat, Inc.
   5 *   Jeff Garzik <jgarzik@pobox.com>
   6 * Copyright 2010  MontaVista Software, LLC.
   7 *   Anton Vorontsov <avorontsov@ru.mvista.com>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2, or (at your option)
  12 * any later version.
  13 */
  14
  15#include <linux/clk.h>
  16#include <linux/kernel.h>
  17#include <linux/gfp.h>
  18#include <linux/module.h>
  19#include <linux/pm.h>
  20#include <linux/init.h>
  21#include <linux/interrupt.h>
  22#include <linux/device.h>
  23#include <linux/platform_device.h>
  24#include <linux/libata.h>
  25#include <linux/ahci_platform.h>
  26#include "ahci.h"
  27
  28static void ahci_host_stop(struct ata_host *host);
  29
  30enum ahci_type {
  31        AHCI,           /* standard platform ahci */
  32        IMX53_AHCI,     /* ahci on i.mx53 */
  33        STRICT_AHCI,    /* delayed DMA engine start */
  34};
  35
  36static struct platform_device_id ahci_devtype[] = {
  37        {
  38                .name = "ahci",
  39                .driver_data = AHCI,
  40        }, {
  41                .name = "imx53-ahci",
  42                .driver_data = IMX53_AHCI,
  43        }, {
  44                .name = "strict-ahci",
  45                .driver_data = STRICT_AHCI,
  46        }, {
  47                /* sentinel */
  48        }
  49};
  50MODULE_DEVICE_TABLE(platform, ahci_devtype);
  51
  52static struct ata_port_operations ahci_platform_ops = {
  53        .inherits       = &ahci_ops,
  54        .host_stop      = ahci_host_stop,
  55};
  56
  57static struct ata_port_operations ahci_platform_retry_srst_ops = {
  58        .inherits       = &ahci_pmp_retry_srst_ops,
  59        .host_stop      = ahci_host_stop,
  60};
  61
  62static const struct ata_port_info ahci_port_info[] = {
  63        /* by features */
  64        [AHCI] = {
  65                .flags          = AHCI_FLAG_COMMON,
  66                .pio_mask       = ATA_PIO4,
  67                .udma_mask      = ATA_UDMA6,
  68                .port_ops       = &ahci_platform_ops,
  69        },
  70        [IMX53_AHCI] = {
  71                .flags          = AHCI_FLAG_COMMON,
  72                .pio_mask       = ATA_PIO4,
  73                .udma_mask      = ATA_UDMA6,
  74                .port_ops       = &ahci_platform_retry_srst_ops,
  75        },
  76        [STRICT_AHCI] = {
  77                AHCI_HFLAGS     (AHCI_HFLAG_DELAY_ENGINE),
  78                .flags          = AHCI_FLAG_COMMON,
  79                .pio_mask       = ATA_PIO4,
  80                .udma_mask      = ATA_UDMA6,
  81                .port_ops       = &ahci_platform_ops,
  82        },
  83};
  84
  85static struct scsi_host_template ahci_platform_sht = {
  86        AHCI_SHT("ahci_platform"),
  87};
  88
  89static int ahci_probe(struct platform_device *pdev)
  90{
  91        struct device *dev = &pdev->dev;
  92        struct ahci_platform_data *pdata = dev_get_platdata(dev);
  93        const struct platform_device_id *id = platform_get_device_id(pdev);
  94        struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0];
  95        const struct ata_port_info *ppi[] = { &pi, NULL };
  96        struct ahci_host_priv *hpriv;
  97        struct ata_host *host;
  98        struct resource *mem;
  99        int irq;
 100        int n_ports;
 101        int i;
 102        int rc;
 103
 104        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 105        if (!mem) {
 106                dev_err(dev, "no mmio space\n");
 107                return -EINVAL;
 108        }
 109
 110        irq = platform_get_irq(pdev, 0);
 111        if (irq <= 0) {
 112                dev_err(dev, "no irq\n");
 113                return -EINVAL;
 114        }
 115
 116        if (pdata && pdata->ata_port_info)
 117                pi = *pdata->ata_port_info;
 118
 119        hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
 120        if (!hpriv) {
 121                dev_err(dev, "can't alloc ahci_host_priv\n");
 122                return -ENOMEM;
 123        }
 124
 125        hpriv->flags |= (unsigned long)pi.private_data;
 126
 127        hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
 128        if (!hpriv->mmio) {
 129                dev_err(dev, "can't map %pR\n", mem);
 130                return -ENOMEM;
 131        }
 132
 133        hpriv->clk = clk_get(dev, NULL);
 134        if (IS_ERR(hpriv->clk)) {
 135                dev_err(dev, "can't get clock\n");
 136        } else {
 137                rc = clk_prepare_enable(hpriv->clk);
 138                if (rc) {
 139                        dev_err(dev, "clock prepare enable failed");
 140                        goto free_clk;
 141                }
 142        }
 143
 144        /*
 145         * Some platforms might need to prepare for mmio region access,
 146         * which could be done in the following init call. So, the mmio
 147         * region shouldn't be accessed before init (if provided) has
 148         * returned successfully.
 149         */
 150        if (pdata && pdata->init) {
 151                rc = pdata->init(dev, hpriv->mmio);
 152                if (rc)
 153                        goto disable_unprepare_clk;
 154        }
 155
 156        ahci_save_initial_config(dev, hpriv,
 157                pdata ? pdata->force_port_map : 0,
 158                pdata ? pdata->mask_port_map  : 0);
 159
 160        /* prepare host */
 161        if (hpriv->cap & HOST_CAP_NCQ)
 162                pi.flags |= ATA_FLAG_NCQ;
 163
 164        if (hpriv->cap & HOST_CAP_PMP)
 165                pi.flags |= ATA_FLAG_PMP;
 166
 167        ahci_set_em_messages(hpriv, &pi);
 168
 169        /* CAP.NP sometimes indicate the index of the last enabled
 170         * port, at other times, that of the last possible port, so
 171         * determining the maximum port number requires looking at
 172         * both CAP.NP and port_map.
 173         */
 174        n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
 175
 176        host = ata_host_alloc_pinfo(dev, ppi, n_ports);
 177        if (!host) {
 178                rc = -ENOMEM;
 179                goto pdata_exit;
 180        }
 181
 182        host->private_data = hpriv;
 183
 184        if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
 185                host->flags |= ATA_HOST_PARALLEL_SCAN;
 186        else
 187                printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
 188
 189        if (pi.flags & ATA_FLAG_EM)
 190                ahci_reset_em(host);
 191
 192        for (i = 0; i < host->n_ports; i++) {
 193                struct ata_port *ap = host->ports[i];
 194
 195                ata_port_desc(ap, "mmio %pR", mem);
 196                ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
 197
 198                /* set enclosure management message type */
 199                if (ap->flags & ATA_FLAG_EM)
 200                        ap->em_message_type = hpriv->em_msg_type;
 201
 202                /* disabled/not-implemented port */
 203                if (!(hpriv->port_map & (1 << i)))
 204                        ap->ops = &ata_dummy_port_ops;
 205        }
 206
 207        rc = ahci_reset_controller(host);
 208        if (rc)
 209                goto pdata_exit;
 210
 211        ahci_init_controller(host);
 212        ahci_print_info(host, "platform");
 213
 214        rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
 215                               &ahci_platform_sht);
 216        if (rc)
 217                goto pdata_exit;
 218
 219        return 0;
 220pdata_exit:
 221        if (pdata && pdata->exit)
 222                pdata->exit(dev);
 223disable_unprepare_clk:
 224        if (!IS_ERR(hpriv->clk))
 225                clk_disable_unprepare(hpriv->clk);
 226free_clk:
 227        if (!IS_ERR(hpriv->clk))
 228                clk_put(hpriv->clk);
 229        return rc;
 230}
 231
 232static void ahci_host_stop(struct ata_host *host)
 233{
 234        struct device *dev = host->dev;
 235        struct ahci_platform_data *pdata = dev_get_platdata(dev);
 236        struct ahci_host_priv *hpriv = host->private_data;
 237
 238        if (pdata && pdata->exit)
 239                pdata->exit(dev);
 240
 241        if (!IS_ERR(hpriv->clk)) {
 242                clk_disable_unprepare(hpriv->clk);
 243                clk_put(hpriv->clk);
 244        }
 245}
 246
 247#ifdef CONFIG_PM_SLEEP
 248static int ahci_suspend(struct device *dev)
 249{
 250        struct ahci_platform_data *pdata = dev_get_platdata(dev);
 251        struct ata_host *host = dev_get_drvdata(dev);
 252        struct ahci_host_priv *hpriv = host->private_data;
 253        void __iomem *mmio = hpriv->mmio;
 254        u32 ctl;
 255        int rc;
 256
 257        if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
 258                dev_err(dev, "firmware update required for suspend/resume\n");
 259                return -EIO;
 260        }
 261
 262        /*
 263         * AHCI spec rev1.1 section 8.3.3:
 264         * Software must disable interrupts prior to requesting a
 265         * transition of the HBA to D3 state.
 266         */
 267        ctl = readl(mmio + HOST_CTL);
 268        ctl &= ~HOST_IRQ_EN;
 269        writel(ctl, mmio + HOST_CTL);
 270        readl(mmio + HOST_CTL); /* flush */
 271
 272        rc = ata_host_suspend(host, PMSG_SUSPEND);
 273        if (rc)
 274                return rc;
 275
 276        if (pdata && pdata->suspend)
 277                return pdata->suspend(dev);
 278
 279        if (!IS_ERR(hpriv->clk))
 280                clk_disable_unprepare(hpriv->clk);
 281
 282        return 0;
 283}
 284
 285static int ahci_resume(struct device *dev)
 286{
 287        struct ahci_platform_data *pdata = dev_get_platdata(dev);
 288        struct ata_host *host = dev_get_drvdata(dev);
 289        struct ahci_host_priv *hpriv = host->private_data;
 290        int rc;
 291
 292        if (!IS_ERR(hpriv->clk)) {
 293                rc = clk_prepare_enable(hpriv->clk);
 294                if (rc) {
 295                        dev_err(dev, "clock prepare enable failed");
 296                        return rc;
 297                }
 298        }
 299
 300        if (pdata && pdata->resume) {
 301                rc = pdata->resume(dev);
 302                if (rc)
 303                        goto disable_unprepare_clk;
 304        }
 305
 306        if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
 307                rc = ahci_reset_controller(host);
 308                if (rc)
 309                        goto disable_unprepare_clk;
 310
 311                ahci_init_controller(host);
 312        }
 313
 314        ata_host_resume(host);
 315
 316        return 0;
 317
 318disable_unprepare_clk:
 319        if (!IS_ERR(hpriv->clk))
 320                clk_disable_unprepare(hpriv->clk);
 321
 322        return rc;
 323}
 324#endif
 325
 326static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
 327
 328static const struct of_device_id ahci_of_match[] = {
 329        { .compatible = "snps,spear-ahci", },
 330        {},
 331};
 332MODULE_DEVICE_TABLE(of, ahci_of_match);
 333
 334static struct platform_driver ahci_driver = {
 335        .probe = ahci_probe,
 336        .remove = ata_platform_remove_one,
 337        .driver = {
 338                .name = "ahci",
 339                .owner = THIS_MODULE,
 340                .of_match_table = ahci_of_match,
 341                .pm = &ahci_pm_ops,
 342        },
 343        .id_table       = ahci_devtype,
 344};
 345module_platform_driver(ahci_driver);
 346
 347MODULE_DESCRIPTION("AHCI SATA platform driver");
 348MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
 349MODULE_LICENSE("GPL");
 350MODULE_ALIAS("platform:ahci");
 351
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.