Linux Audio

Check our new training course

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