2 * AHCI SATA platform driver
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>
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)
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>
26 static struct scsi_host_template ahci_platform_sht
= {
27 AHCI_SHT("ahci_platform"),
30 static int __init
ahci_probe(struct platform_device
*pdev
)
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
,
37 .udma_mask
= ATA_UDMA6
,
38 .port_ops
= &ahci_ops
,
40 const struct ata_port_info
*ppi
[] = { &pi
, NULL
};
41 struct ahci_host_priv
*hpriv
;
42 struct ata_host
*host
;
49 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
51 dev_err(dev
, "no mmio space\n");
55 irq
= platform_get_irq(pdev
, 0);
57 dev_err(dev
, "no irq\n");
61 if (pdata
&& pdata
->ata_port_info
)
62 pi
= *pdata
->ata_port_info
;
64 hpriv
= devm_kzalloc(dev
, sizeof(*hpriv
), GFP_KERNEL
);
66 dev_err(dev
, "can't alloc ahci_host_priv\n");
70 hpriv
->flags
|= (unsigned long)pi
.private_data
;
72 hpriv
->mmio
= devm_ioremap(dev
, mem
->start
, resource_size(mem
));
74 dev_err(dev
, "can't map %pR\n", mem
);
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.
84 if (pdata
&& pdata
->init
) {
85 rc
= pdata
->init(dev
, hpriv
->mmio
);
90 ahci_save_initial_config(dev
, hpriv
,
91 pdata
? pdata
->force_port_map
: 0,
92 pdata
? pdata
->mask_port_map
: 0);
95 if (hpriv
->cap
& HOST_CAP_NCQ
)
96 pi
.flags
|= ATA_FLAG_NCQ
;
98 if (hpriv
->cap
& HOST_CAP_PMP
)
99 pi
.flags
|= ATA_FLAG_PMP
;
101 ahci_set_em_messages(hpriv
, &pi
);
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.
108 n_ports
= max(ahci_nr_ports(hpriv
->cap
), fls(hpriv
->port_map
));
110 host
= ata_host_alloc_pinfo(dev
, ppi
, n_ports
);
116 host
->private_data
= hpriv
;
118 if (!(hpriv
->cap
& HOST_CAP_SSS
) || ahci_ignore_sss
)
119 host
->flags
|= ATA_HOST_PARALLEL_SCAN
;
121 printk(KERN_INFO
"ahci: SSS flag set, parallel bus scan disabled\n");
123 if (pi
.flags
& ATA_FLAG_EM
)
126 for (i
= 0; i
< host
->n_ports
; i
++) {
127 struct ata_port
*ap
= host
->ports
[i
];
129 ata_port_desc(ap
, "mmio %pR", mem
);
130 ata_port_desc(ap
, "port 0x%x", 0x100 + ap
->port_no
* 0x80);
132 /* set enclosure management message type */
133 if (ap
->flags
& ATA_FLAG_EM
)
134 ap
->em_message_type
= hpriv
->em_msg_type
;
136 /* disabled/not-implemented port */
137 if (!(hpriv
->port_map
& (1 << i
)))
138 ap
->ops
= &ata_dummy_port_ops
;
141 rc
= ahci_reset_controller(host
);
145 ahci_init_controller(host
);
146 ahci_print_info(host
, "platform");
148 rc
= ata_host_activate(host
, irq
, ahci_interrupt
, IRQF_SHARED
,
155 if (pdata
&& pdata
->exit
)
160 static int __devexit
ahci_remove(struct platform_device
*pdev
)
162 struct device
*dev
= &pdev
->dev
;
163 struct ahci_platform_data
*pdata
= dev
->platform_data
;
164 struct ata_host
*host
= dev_get_drvdata(dev
);
166 ata_host_detach(host
);
168 if (pdata
&& pdata
->exit
)
174 static struct platform_driver ahci_driver
= {
175 .remove
= __devexit_p(ahci_remove
),
178 .owner
= THIS_MODULE
,
182 static int __init
ahci_init(void)
184 return platform_driver_probe(&ahci_driver
, ahci_probe
);
186 module_init(ahci_init
);
188 static void __exit
ahci_exit(void)
190 platform_driver_unregister(&ahci_driver
);
192 module_exit(ahci_exit
);
194 MODULE_DESCRIPTION("AHCI SATA platform driver");
195 MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
196 MODULE_LICENSE("GPL");
197 MODULE_ALIAS("platform:ahci");