Root/drivers/ata/ahci_platform.c

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

Archive Download this file



interactive