diff options
Diffstat (limited to 'drivers/ata/pata_qdi.c')
-rw-r--r-- | drivers/ata/pata_qdi.c | 366 |
1 files changed, 0 insertions, 366 deletions
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c deleted file mode 100644 index 45879dc6fa41..000000000000 --- a/drivers/ata/pata_qdi.c +++ /dev/null | |||
@@ -1,366 +0,0 @@ | |||
1 | /* | ||
2 | * pata_qdi.c - QDI VLB ATA controllers | ||
3 | * (C) 2006 Red Hat | ||
4 | * | ||
5 | * This driver mostly exists as a proof of concept for non PCI devices under | ||
6 | * libata. While the QDI6580 was 'neat' in 1993 it is no longer terribly | ||
7 | * useful. | ||
8 | * | ||
9 | * Tuning code written from the documentation at | ||
10 | * http://www.ryston.cz/petr/vlb/qd6500.html | ||
11 | * http://www.ryston.cz/petr/vlb/qd6580.html | ||
12 | * | ||
13 | * Probe code based on drivers/ide/legacy/qd65xx.c | ||
14 | * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by | ||
15 | * Samuel Thibault <samuel.thibault@ens-lyon.org> | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/blkdev.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <scsi/scsi_host.h> | ||
25 | #include <linux/libata.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | |||
28 | #define DRV_NAME "pata_qdi" | ||
29 | #define DRV_VERSION "0.3.1" | ||
30 | |||
31 | #define NR_HOST 4 /* Two 6580s */ | ||
32 | |||
33 | struct qdi_data { | ||
34 | unsigned long timing; | ||
35 | u8 clock[2]; | ||
36 | u8 last; | ||
37 | int fast; | ||
38 | struct platform_device *platform_dev; | ||
39 | |||
40 | }; | ||
41 | |||
42 | static struct ata_host *qdi_host[NR_HOST]; | ||
43 | static struct qdi_data qdi_data[NR_HOST]; | ||
44 | static int nr_qdi_host; | ||
45 | |||
46 | #ifdef MODULE | ||
47 | static int probe_qdi = 1; | ||
48 | #else | ||
49 | static int probe_qdi; | ||
50 | #endif | ||
51 | |||
52 | static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev) | ||
53 | { | ||
54 | struct ata_timing t; | ||
55 | struct qdi_data *qdi = ap->host->private_data; | ||
56 | int active, recovery; | ||
57 | u8 timing; | ||
58 | |||
59 | /* Get the timing data in cycles */ | ||
60 | ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); | ||
61 | |||
62 | if (qdi->fast) { | ||
63 | active = 8 - clamp_val(t.active, 1, 8); | ||
64 | recovery = 18 - clamp_val(t.recover, 3, 18); | ||
65 | } else { | ||
66 | active = 9 - clamp_val(t.active, 2, 9); | ||
67 | recovery = 15 - clamp_val(t.recover, 0, 15); | ||
68 | } | ||
69 | timing = (recovery << 4) | active | 0x08; | ||
70 | |||
71 | qdi->clock[adev->devno] = timing; | ||
72 | |||
73 | outb(timing, qdi->timing); | ||
74 | } | ||
75 | |||
76 | static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev) | ||
77 | { | ||
78 | struct ata_timing t; | ||
79 | struct qdi_data *qdi = ap->host->private_data; | ||
80 | int active, recovery; | ||
81 | u8 timing; | ||
82 | |||
83 | /* Get the timing data in cycles */ | ||
84 | ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); | ||
85 | |||
86 | if (qdi->fast) { | ||
87 | active = 8 - clamp_val(t.active, 1, 8); | ||
88 | recovery = 18 - clamp_val(t.recover, 3, 18); | ||
89 | } else { | ||
90 | active = 9 - clamp_val(t.active, 2, 9); | ||
91 | recovery = 15 - clamp_val(t.recover, 0, 15); | ||
92 | } | ||
93 | timing = (recovery << 4) | active | 0x08; | ||
94 | |||
95 | qdi->clock[adev->devno] = timing; | ||
96 | |||
97 | outb(timing, qdi->timing); | ||
98 | |||
99 | /* Clear the FIFO */ | ||
100 | if (adev->class != ATA_DEV_ATA) | ||
101 | outb(0x5F, (qdi->timing & 0xFFF0) + 3); | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * qdi_qc_issue - command issue | ||
106 | * @qc: command pending | ||
107 | * | ||
108 | * Called when the libata layer is about to issue a command. We wrap | ||
109 | * this interface so that we can load the correct ATA timings. | ||
110 | */ | ||
111 | |||
112 | static unsigned int qdi_qc_issue(struct ata_queued_cmd *qc) | ||
113 | { | ||
114 | struct ata_port *ap = qc->ap; | ||
115 | struct ata_device *adev = qc->dev; | ||
116 | struct qdi_data *qdi = ap->host->private_data; | ||
117 | |||
118 | if (qdi->clock[adev->devno] != qdi->last) { | ||
119 | if (adev->pio_mode) { | ||
120 | qdi->last = qdi->clock[adev->devno]; | ||
121 | outb(qdi->clock[adev->devno], qdi->timing); | ||
122 | } | ||
123 | } | ||
124 | return ata_sff_qc_issue(qc); | ||
125 | } | ||
126 | |||
127 | static unsigned int qdi_data_xfer(struct ata_device *dev, unsigned char *buf, | ||
128 | unsigned int buflen, int rw) | ||
129 | { | ||
130 | if (ata_id_has_dword_io(dev->id)) { | ||
131 | struct ata_port *ap = dev->link->ap; | ||
132 | int slop = buflen & 3; | ||
133 | |||
134 | if (rw == READ) | ||
135 | ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); | ||
136 | else | ||
137 | iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); | ||
138 | |||
139 | if (unlikely(slop)) { | ||
140 | __le32 pad; | ||
141 | if (rw == READ) { | ||
142 | pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); | ||
143 | memcpy(buf + buflen - slop, &pad, slop); | ||
144 | } else { | ||
145 | memcpy(&pad, buf + buflen - slop, slop); | ||
146 | iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); | ||
147 | } | ||
148 | buflen += 4 - slop; | ||
149 | } | ||
150 | } else | ||
151 | buflen = ata_sff_data_xfer(dev, buf, buflen, rw); | ||
152 | |||
153 | return buflen; | ||
154 | } | ||
155 | |||
156 | static struct scsi_host_template qdi_sht = { | ||
157 | ATA_PIO_SHT(DRV_NAME), | ||
158 | }; | ||
159 | |||
160 | static struct ata_port_operations qdi6500_port_ops = { | ||
161 | .inherits = &ata_sff_port_ops, | ||
162 | .qc_issue = qdi_qc_issue, | ||
163 | .sff_data_xfer = qdi_data_xfer, | ||
164 | .cable_detect = ata_cable_40wire, | ||
165 | .set_piomode = qdi6500_set_piomode, | ||
166 | }; | ||
167 | |||
168 | static struct ata_port_operations qdi6580_port_ops = { | ||
169 | .inherits = &qdi6500_port_ops, | ||
170 | .set_piomode = qdi6580_set_piomode, | ||
171 | }; | ||
172 | |||
173 | /** | ||
174 | * qdi_init_one - attach a qdi interface | ||
175 | * @type: Type to display | ||
176 | * @io: I/O port start | ||
177 | * @irq: interrupt line | ||
178 | * @fast: True if on a > 33Mhz VLB | ||
179 | * | ||
180 | * Register an ISA bus IDE interface. Such interfaces are PIO and we | ||
181 | * assume do not support IRQ sharing. | ||
182 | */ | ||
183 | |||
184 | static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast) | ||
185 | { | ||
186 | unsigned long ctl = io + 0x206; | ||
187 | struct platform_device *pdev; | ||
188 | struct ata_host *host; | ||
189 | struct ata_port *ap; | ||
190 | void __iomem *io_addr, *ctl_addr; | ||
191 | int ret; | ||
192 | |||
193 | /* | ||
194 | * Fill in a probe structure first of all | ||
195 | */ | ||
196 | |||
197 | pdev = platform_device_register_simple(DRV_NAME, nr_qdi_host, NULL, 0); | ||
198 | if (IS_ERR(pdev)) | ||
199 | return PTR_ERR(pdev); | ||
200 | |||
201 | ret = -ENOMEM; | ||
202 | io_addr = devm_ioport_map(&pdev->dev, io, 8); | ||
203 | ctl_addr = devm_ioport_map(&pdev->dev, ctl, 1); | ||
204 | if (!io_addr || !ctl_addr) | ||
205 | goto fail; | ||
206 | |||
207 | ret = -ENOMEM; | ||
208 | host = ata_host_alloc(&pdev->dev, 1); | ||
209 | if (!host) | ||
210 | goto fail; | ||
211 | ap = host->ports[0]; | ||
212 | |||
213 | if (type == 6580) { | ||
214 | ap->ops = &qdi6580_port_ops; | ||
215 | ap->pio_mask = ATA_PIO4; | ||
216 | ap->flags |= ATA_FLAG_SLAVE_POSS; | ||
217 | } else { | ||
218 | ap->ops = &qdi6500_port_ops; | ||
219 | ap->pio_mask = ATA_PIO2; /* Actually PIO3 !IORDY is possible */ | ||
220 | ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY; | ||
221 | } | ||
222 | |||
223 | ap->ioaddr.cmd_addr = io_addr; | ||
224 | ap->ioaddr.altstatus_addr = ctl_addr; | ||
225 | ap->ioaddr.ctl_addr = ctl_addr; | ||
226 | ata_sff_std_ports(&ap->ioaddr); | ||
227 | |||
228 | ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl); | ||
229 | |||
230 | /* | ||
231 | * Hook in a private data structure per channel | ||
232 | */ | ||
233 | ap->private_data = &qdi_data[nr_qdi_host]; | ||
234 | |||
235 | qdi_data[nr_qdi_host].timing = port; | ||
236 | qdi_data[nr_qdi_host].fast = fast; | ||
237 | qdi_data[nr_qdi_host].platform_dev = pdev; | ||
238 | |||
239 | printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io); | ||
240 | |||
241 | /* activate */ | ||
242 | ret = ata_host_activate(host, irq, ata_sff_interrupt, 0, &qdi_sht); | ||
243 | if (ret) | ||
244 | goto fail; | ||
245 | |||
246 | qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev); | ||
247 | return 0; | ||
248 | |||
249 | fail: | ||
250 | platform_device_unregister(pdev); | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * qdi_init - attach qdi interfaces | ||
256 | * | ||
257 | * Attach qdi IDE interfaces by scanning the ports it may occupy. | ||
258 | */ | ||
259 | |||
260 | static __init int qdi_init(void) | ||
261 | { | ||
262 | unsigned long flags; | ||
263 | static const unsigned long qd_port[2] = { 0x30, 0xB0 }; | ||
264 | static const unsigned long ide_port[2] = { 0x170, 0x1F0 }; | ||
265 | static const int ide_irq[2] = { 14, 15 }; | ||
266 | |||
267 | int ct = 0; | ||
268 | int i; | ||
269 | |||
270 | if (probe_qdi == 0) | ||
271 | return -ENODEV; | ||
272 | |||
273 | /* | ||
274 | * Check each possible QD65xx base address | ||
275 | */ | ||
276 | |||
277 | for (i = 0; i < 2; i++) { | ||
278 | unsigned long port = qd_port[i]; | ||
279 | u8 r, res; | ||
280 | |||
281 | |||
282 | if (request_region(port, 2, "pata_qdi")) { | ||
283 | /* Check for a card */ | ||
284 | local_irq_save(flags); | ||
285 | r = inb_p(port); | ||
286 | outb_p(0x19, port); | ||
287 | res = inb_p(port); | ||
288 | outb_p(r, port); | ||
289 | local_irq_restore(flags); | ||
290 | |||
291 | /* Fail */ | ||
292 | if (res == 0x19) | ||
293 | { | ||
294 | release_region(port, 2); | ||
295 | continue; | ||
296 | } | ||
297 | |||
298 | /* Passes the presence test */ | ||
299 | r = inb_p(port + 1); /* Check port agrees with port set */ | ||
300 | if ((r & 2) >> 1 != i) { | ||
301 | release_region(port, 2); | ||
302 | continue; | ||
303 | } | ||
304 | |||
305 | /* Check card type */ | ||
306 | if ((r & 0xF0) == 0xC0) { | ||
307 | /* QD6500: single channel */ | ||
308 | if (r & 8) { | ||
309 | /* Disabled ? */ | ||
310 | release_region(port, 2); | ||
311 | continue; | ||
312 | } | ||
313 | if (qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04) == 0) | ||
314 | ct++; | ||
315 | } | ||
316 | if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) { | ||
317 | /* QD6580: dual channel */ | ||
318 | if (!request_region(port + 2 , 2, "pata_qdi")) | ||
319 | { | ||
320 | release_region(port, 2); | ||
321 | continue; | ||
322 | } | ||
323 | res = inb(port + 3); | ||
324 | if (res & 1) { | ||
325 | /* Single channel mode */ | ||
326 | if (qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04) == 0) | ||
327 | ct++; | ||
328 | } else { | ||
329 | /* Dual channel mode */ | ||
330 | if (qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04) == 0) | ||
331 | ct++; | ||
332 | if (qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04) == 0) | ||
333 | ct++; | ||
334 | } | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | if (ct != 0) | ||
339 | return 0; | ||
340 | return -ENODEV; | ||
341 | } | ||
342 | |||
343 | static __exit void qdi_exit(void) | ||
344 | { | ||
345 | int i; | ||
346 | |||
347 | for (i = 0; i < nr_qdi_host; i++) { | ||
348 | ata_host_detach(qdi_host[i]); | ||
349 | /* Free the control resource. The 6580 dual channel has the resources | ||
350 | * claimed as a pair of 2 byte resources so we need no special cases... | ||
351 | */ | ||
352 | release_region(qdi_data[i].timing, 2); | ||
353 | platform_device_unregister(qdi_data[i].platform_dev); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | MODULE_AUTHOR("Alan Cox"); | ||
358 | MODULE_DESCRIPTION("low-level driver for qdi ATA"); | ||
359 | MODULE_LICENSE("GPL"); | ||
360 | MODULE_VERSION(DRV_VERSION); | ||
361 | |||
362 | module_init(qdi_init); | ||
363 | module_exit(qdi_exit); | ||
364 | |||
365 | module_param(probe_qdi, int, 0); | ||
366 | |||