blob: 6fef1fa75c549ea3a442f617693882313c826844 [file] [log] [blame]
Anton Vorontsov1c2a49f2010-03-04 20:06:06 +03001/*
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>
Tejun Heofbaf6662010-03-30 02:52:43 +090016#include <linux/gfp.h>
Anton Vorontsov1c2a49f2010-03-04 20:06:06 +030017#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/device.h>
21#include <linux/platform_device.h>
22#include <linux/libata.h>
23#include <linux/ahci_platform.h>
24#include "ahci.h"
25
Tejun Heofad16e72010-09-21 09:25:48 +020026static struct scsi_host_template ahci_platform_sht = {
27 AHCI_SHT("ahci_platform"),
28};
29
Anton Vorontsov1c2a49f2010-03-04 20:06:06 +030030static int __init ahci_probe(struct platform_device *pdev)
31{
32 struct device *dev = &pdev->dev;
33 struct ahci_platform_data *pdata = dev->platform_data;
34 struct ata_port_info pi = {
35 .flags = AHCI_FLAG_COMMON,
36 .pio_mask = ATA_PIO4,
37 .udma_mask = ATA_UDMA6,
38 .port_ops = &ahci_ops,
39 };
40 const struct ata_port_info *ppi[] = { &pi, NULL };
41 struct ahci_host_priv *hpriv;
42 struct ata_host *host;
43 struct resource *mem;
44 int irq;
45 int n_ports;
46 int i;
47 int rc;
48
49 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
50 if (!mem) {
51 dev_err(dev, "no mmio space\n");
52 return -EINVAL;
53 }
54
55 irq = platform_get_irq(pdev, 0);
56 if (irq <= 0) {
57 dev_err(dev, "no irq\n");
58 return -EINVAL;
59 }
60
Anton Vorontsov1c2a49f2010-03-04 20:06:06 +030061 if (pdata && pdata->ata_port_info)
62 pi = *pdata->ata_port_info;
63
64 hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
65 if (!hpriv) {
Jassi Brar08354802010-06-25 18:21:19 +090066 dev_err(dev, "can't alloc ahci_host_priv\n");
67 return -ENOMEM;
Anton Vorontsov1c2a49f2010-03-04 20:06:06 +030068 }
69
70 hpriv->flags |= (unsigned long)pi.private_data;
71
72 hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
73 if (!hpriv->mmio) {
74 dev_err(dev, "can't map %pR\n", mem);
Jassi Brar08354802010-06-25 18:21:19 +090075 return -ENOMEM;
76 }
77
78 /*
79 * Some platforms might need to prepare for mmio region access,
80 * which could be done in the following init call. So, the mmio
81 * region shouldn't be accessed before init (if provided) has
82 * returned successfully.
83 */
84 if (pdata && pdata->init) {
85 rc = pdata->init(dev, hpriv->mmio);
86 if (rc)
87 return rc;
Anton Vorontsov1c2a49f2010-03-04 20:06:06 +030088 }
89
90 ahci_save_initial_config(dev, hpriv,
91 pdata ? pdata->force_port_map : 0,
92 pdata ? pdata->mask_port_map : 0);
93
94 /* prepare host */
95 if (hpriv->cap & HOST_CAP_NCQ)
96 pi.flags |= ATA_FLAG_NCQ;
97
98 if (hpriv->cap & HOST_CAP_PMP)
99 pi.flags |= ATA_FLAG_PMP;
100
101 ahci_set_em_messages(hpriv, &pi);
102
103 /* CAP.NP sometimes indicate the index of the last enabled
104 * port, at other times, that of the last possible port, so
105 * determining the maximum port number requires looking at
106 * both CAP.NP and port_map.
107 */
108 n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
109
110 host = ata_host_alloc_pinfo(dev, ppi, n_ports);
111 if (!host) {
112 rc = -ENOMEM;
113 goto err0;
114 }
115
116 host->private_data = hpriv;
117
118 if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
119 host->flags |= ATA_HOST_PARALLEL_SCAN;
120 else
121 printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
122
123 if (pi.flags & ATA_FLAG_EM)
124 ahci_reset_em(host);
125
126 for (i = 0; i < host->n_ports; i++) {
127 struct ata_port *ap = host->ports[i];
128
129 ata_port_desc(ap, "mmio %pR", mem);
130 ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
131
Anton Vorontsov1c2a49f2010-03-04 20:06:06 +0300132 /* set enclosure management message type */
133 if (ap->flags & ATA_FLAG_EM)
Jeff Garzik55787182010-05-14 17:23:37 -0400134 ap->em_message_type = hpriv->em_msg_type;
Anton Vorontsov1c2a49f2010-03-04 20:06:06 +0300135
136 /* disabled/not-implemented port */
137 if (!(hpriv->port_map & (1 << i)))
138 ap->ops = &ata_dummy_port_ops;
139 }
140
141 rc = ahci_reset_controller(host);
142 if (rc)
143 goto err0;
144
145 ahci_init_controller(host);
146 ahci_print_info(host, "platform");
147
148 rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
Tejun Heofad16e72010-09-21 09:25:48 +0200149 &ahci_platform_sht);
Anton Vorontsov1c2a49f2010-03-04 20:06:06 +0300150 if (rc)
151 goto err0;
152
153 return 0;
154err0:
155 if (pdata && pdata->exit)
156 pdata->exit(dev);
157 return rc;
158}
159
160static int __devexit ahci_remove(struct platform_device *pdev)
161{
162 struct device *dev = &pdev->dev;
163 struct ahci_platform_data *pdata = dev->platform_data;
164 struct ata_host *host = dev_get_drvdata(dev);
165
166 ata_host_detach(host);
167
168 if (pdata && pdata->exit)
169 pdata->exit(dev);
170
171 return 0;
172}
173
174static struct platform_driver ahci_driver = {
Anton Vorontsov1c2a49f2010-03-04 20:06:06 +0300175 .remove = __devexit_p(ahci_remove),
176 .driver = {
177 .name = "ahci",
178 .owner = THIS_MODULE,
179 },
180};
181
182static int __init ahci_init(void)
183{
184 return platform_driver_probe(&ahci_driver, ahci_probe);
185}
186module_init(ahci_init);
187
188static void __exit ahci_exit(void)
189{
190 platform_driver_unregister(&ahci_driver);
191}
192module_exit(ahci_exit);
193
194MODULE_DESCRIPTION("AHCI SATA platform driver");
195MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
196MODULE_LICENSE("GPL");
197MODULE_ALIAS("platform:ahci");