1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/module.h>
24#include <linux/types.h>
25#include <linux/kernel.h>
26#include <linux/delay.h>
27#include <linux/timer.h>
28#include <linux/mm.h>
29#include <linux/ioport.h>
30#include <linux/blkdev.h>
31#include <linux/ide.h>
32#include <linux/init.h>
33#include <asm/io.h>
34
35#define DRV_NAME "qd65xx"
36
37#include "qd65xx.h"
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85static int timings[4]={-1,-1,-1,-1};
86
87
88
89
90
91
92
93static void qd65xx_dev_select(ide_drive_t *drive)
94{
95 u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
96 (QD_TIMREG(drive) & 0x02);
97
98 if (timings[index] != QD_TIMING(drive))
99 outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
100
101 outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
102}
103
104
105
106
107
108
109
110
111
112static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
113{
114 int clk = ide_vlb_clk ? ide_vlb_clk : 50;
115 u8 act_cyc, rec_cyc;
116
117 if (clk <= 33) {
118 act_cyc = 9 - IDE_IN(active_time * clk / 1000 + 1, 2, 9);
119 rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15);
120 } else {
121 act_cyc = 8 - IDE_IN(active_time * clk / 1000 + 1, 1, 8);
122 rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18);
123 }
124
125 return (rec_cyc << 4) | 0x08 | act_cyc;
126}
127
128
129
130
131
132
133
134static u8 qd6580_compute_timing (int active_time, int recovery_time)
135{
136 int clk = ide_vlb_clk ? ide_vlb_clk : 50;
137 u8 act_cyc, rec_cyc;
138
139 act_cyc = 17 - IDE_IN(active_time * clk / 1000 + 1, 2, 17);
140 rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 2, 15);
141
142 return (rec_cyc << 4) | act_cyc;
143}
144
145
146
147
148
149
150
151static int qd_find_disk_type (ide_drive_t *drive,
152 int *active_time, int *recovery_time)
153{
154 struct qd65xx_timing_s *p;
155 char *m = (char *)&drive->id[ATA_ID_PROD];
156 char model[ATA_ID_PROD_LEN];
157
158 if (*m == 0)
159 return 0;
160
161 strncpy(model, m, ATA_ID_PROD_LEN);
162 ide_fixstring(model, ATA_ID_PROD_LEN, 1);
163
164 for (p = qd65xx_timing ; p->offset != -1 ; p++) {
165 if (!strncmp(p->model, model+p->offset, 4)) {
166 printk(KERN_DEBUG "%s: listed !\n", drive->name);
167 *active_time = p->active;
168 *recovery_time = p->recovery;
169 return 1;
170 }
171 }
172 return 0;
173}
174
175
176
177
178
179
180
181static void qd_set_timing (ide_drive_t *drive, u8 timing)
182{
183 unsigned long data = (unsigned long)ide_get_drivedata(drive);
184
185 data &= 0xff00;
186 data |= timing;
187 ide_set_drivedata(drive, (void *)data);
188
189 printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
190}
191
192static void qd6500_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
193{
194 u16 *id = drive->id;
195 int active_time = 175;
196 int recovery_time = 415;
197
198
199 if (!qd_find_disk_type(drive, &active_time, &recovery_time) &&
200 (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) &&
201 id[ATA_ID_EIDE_PIO] >= 240) {
202 printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
203 id[ATA_ID_OLD_PIO_MODES] & 0xff);
204 active_time = 110;
205 recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120;
206 }
207
208 qd_set_timing(drive, qd6500_compute_timing(drive->hwif,
209 active_time, recovery_time));
210}
211
212static void qd6580_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
213{
214 const u8 pio = drive->pio_mode - XFER_PIO_0;
215 struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
216 unsigned int cycle_time;
217 int active_time = 175;
218 int recovery_time = 415;
219 u8 base = (hwif->config_data & 0xff00) >> 8;
220
221 if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
222 cycle_time = ide_pio_cycle_time(drive, pio);
223
224 switch (pio) {
225 case 0: break;
226 case 3:
227 if (cycle_time >= 110) {
228 active_time = 86;
229 recovery_time = cycle_time - 102;
230 } else
231 printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
232 break;
233 case 4:
234 if (cycle_time >= 69) {
235 active_time = 70;
236 recovery_time = cycle_time - 61;
237 } else
238 printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
239 break;
240 default:
241 if (cycle_time >= 180) {
242 active_time = 110;
243 recovery_time = cycle_time - 120;
244 } else {
245 active_time = t->active;
246 recovery_time = cycle_time - active_time;
247 }
248 }
249 printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
250 }
251
252 if (!hwif->channel && drive->media != ide_disk) {
253 outb(0x5f, QD_CONTROL_PORT);
254 printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
255 "and post-write buffer on %s.\n",
256 drive->name, hwif->name);
257 }
258
259 qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
260}
261
262
263
264
265
266
267
268static int __init qd_testreg(int port)
269{
270 unsigned long flags;
271 u8 savereg, readreg;
272
273 local_irq_save(flags);
274 savereg = inb_p(port);
275 outb_p(QD_TESTVAL, port);
276 readreg = inb_p(port);
277 outb(savereg, port);
278 local_irq_restore(flags);
279
280 if (savereg == QD_TESTVAL) {
281 printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
282 printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
283 printk(KERN_ERR "Assuming qd65xx is not present.\n");
284 return 1;
285 }
286
287 return (readreg != QD_TESTVAL);
288}
289
290static void __init qd6500_init_dev(ide_drive_t *drive)
291{
292 ide_hwif_t *hwif = drive->hwif;
293 u8 base = (hwif->config_data & 0xff00) >> 8;
294 u8 config = QD_CONFIG(hwif);
295
296 ide_set_drivedata(drive, (void *)QD6500_DEF_DATA);
297}
298
299static void __init qd6580_init_dev(ide_drive_t *drive)
300{
301 ide_hwif_t *hwif = drive->hwif;
302 u16 t1, t2;
303 u8 base = (hwif->config_data & 0xff00) >> 8;
304 u8 config = QD_CONFIG(hwif);
305
306 if (hwif->host_flags & IDE_HFLAG_SINGLE) {
307 t1 = QD6580_DEF_DATA;
308 t2 = QD6580_DEF_DATA2;
309 } else
310 t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
311
312 ide_set_drivedata(drive, (void *)((drive->dn & 1) ? t2 : t1));
313}
314
315static const struct ide_tp_ops qd65xx_tp_ops = {
316 .exec_command = ide_exec_command,
317 .read_status = ide_read_status,
318 .read_altstatus = ide_read_altstatus,
319 .write_devctl = ide_write_devctl,
320
321 .dev_select = qd65xx_dev_select,
322 .tf_load = ide_tf_load,
323 .tf_read = ide_tf_read,
324
325 .input_data = ide_input_data,
326 .output_data = ide_output_data,
327};
328
329static const struct ide_port_ops qd6500_port_ops = {
330 .init_dev = qd6500_init_dev,
331 .set_pio_mode = qd6500_set_pio_mode,
332};
333
334static const struct ide_port_ops qd6580_port_ops = {
335 .init_dev = qd6580_init_dev,
336 .set_pio_mode = qd6580_set_pio_mode,
337};
338
339static const struct ide_port_info qd65xx_port_info __initconst = {
340 .name = DRV_NAME,
341 .tp_ops = &qd65xx_tp_ops,
342 .chipset = ide_qd65xx,
343 .host_flags = IDE_HFLAG_IO_32BIT |
344 IDE_HFLAG_NO_DMA,
345 .pio_mask = ATA_PIO4,
346};
347
348
349
350
351
352
353
354
355static int __init qd_probe(int base)
356{
357 int rc;
358 u8 config, unit, control;
359 struct ide_port_info d = qd65xx_port_info;
360
361 config = inb(QD_CONFIG_PORT);
362
363 if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
364 return -ENODEV;
365
366 unit = ! (config & QD_CONFIG_IDE_BASEPORT);
367
368 if (unit)
369 d.host_flags |= IDE_HFLAG_QD_2ND_PORT;
370
371 switch (config & 0xf0) {
372 case QD_CONFIG_QD6500:
373 if (qd_testreg(base))
374 return -ENODEV;
375
376 if (config & QD_CONFIG_DISABLED) {
377 printk(KERN_WARNING "qd6500 is disabled !\n");
378 return -ENODEV;
379 }
380
381 printk(KERN_NOTICE "qd6500 at %#x\n", base);
382 printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
383 config, QD_ID3);
384
385 d.port_ops = &qd6500_port_ops;
386 d.host_flags |= IDE_HFLAG_SINGLE;
387 break;
388 case QD_CONFIG_QD6580_A:
389 case QD_CONFIG_QD6580_B:
390 if (qd_testreg(base) || qd_testreg(base + 0x02))
391 return -ENODEV;
392
393 control = inb(QD_CONTROL_PORT);
394
395 printk(KERN_NOTICE "qd6580 at %#x\n", base);
396 printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
397 config, control, QD_ID3);
398
399 outb(QD_DEF_CONTR, QD_CONTROL_PORT);
400
401 d.port_ops = &qd6580_port_ops;
402 if (control & QD_CONTR_SEC_DISABLED)
403 d.host_flags |= IDE_HFLAG_SINGLE;
404
405 printk(KERN_INFO "qd6580: %s IDE board\n",
406 (control & QD_CONTR_SEC_DISABLED) ? "single" : "dual");
407 break;
408 default:
409 return -ENODEV;
410 }
411
412 rc = ide_legacy_device_add(&d, (base << 8) | config);
413
414 if (d.host_flags & IDE_HFLAG_SINGLE)
415 return (rc == 0) ? 1 : rc;
416
417 return rc;
418}
419
420static bool probe_qd65xx;
421
422module_param_named(probe, probe_qd65xx, bool, 0);
423MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
424
425static int __init qd65xx_init(void)
426{
427 int rc1, rc2 = -ENODEV;
428
429 if (probe_qd65xx == 0)
430 return -ENODEV;
431
432 rc1 = qd_probe(0x30);
433 if (rc1)
434 rc2 = qd_probe(0xb0);
435
436 if (rc1 < 0 && rc2 < 0)
437 return -ENODEV;
438
439 return 0;
440}
441
442module_init(qd65xx_init);
443
444MODULE_AUTHOR("Samuel Thibault");
445MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
446MODULE_LICENSE("GPL");
447