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