The LDT fixes in particular fix some potentially random strange behaviour.
[davej-history.git] / drivers / ide / qd6580.c
blob5787b73f21a4703a4062895e75bdbb956a67e9be
1 /*
2 * linux/drivers/ide/qd6580.c Version 0.04 June 4, 2000
4 * Copyright (C) 1996-2000 Linus Torvalds & author (see below)
5 */
7 /*
8 * Version 0.03 Cleaned auto-tune, added probe
9 * Version 0.04 Added second channel tuning
11 * QDI QD6580 EIDE controller fast support
13 * To activate controller support use kernel parameter "ide0=qd6580"
14 * To enable tuning use kernel parameter "ide0=autotune"
15 * To enable tuning second channel (not really tested),
16 * use parameter "ide1=autotune"
19 /*
20 * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
21 * Samuel Thibault <samuel.thibault@fnac.net>
24 #undef REALLY_SLOW_IO /* most systems can safely undef this */
26 #include <linux/types.h>
27 #include <linux/kernel.h>
28 #include <linux/delay.h>
29 #include <linux/timer.h>
30 #include <linux/mm.h>
31 #include <linux/ioport.h>
32 #include <linux/blkdev.h>
33 #include <linux/hdreg.h>
34 #include <linux/ide.h>
35 #include <linux/init.h>
37 #include <asm/io.h>
39 #include "ide_modes.h"
42 * I/O ports are 0xb0-0xb3
43 * or 0x30-0x33
44 * -- this is a dual IDE interface with I/O chips
46 * More research on qd6580 being done by willmore@cig.mot.com (David)
47 * More Information given by Petr Sourcek (petr@ryston.cz)
48 * http://www.ryston.cz/petr/vlb
52 * 0xb0: Timer1
55 * 0xb1: Config
57 * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170
58 * (? Strange: the Dos driver uses it, and then forces baseport to 0x1f0 ?)
59 * bit 1: qd baseport: 1 = 0xb0 ; 0 = 0x30
60 * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
61 * bit 3: 1 for qd6580
62 * upper nibble is either 1010 or 0101, or else it isn't a qd6580
65 * 0xb2: Timer2
68 * 0xb3: Control
70 * bits 0-3 must always be set 1
71 * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
72 * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
73 * 0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
74 * channel 1 for hdc & hdd
75 * bit 1 : 1 = only disks on primary port
76 * 0 = disks & ATAPI devices on primary port
77 * bit 2-4 : always 0
78 * bit 5 : status, but of what ?
79 * bit 6 : always set 1 by dos driver
80 * bit 7 : set 1 for non-ATAPI devices (read-ahead and post-write buffer ?)
83 /* truncates a in [b,c] */
84 #define IDE_IN(a,b,c) ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
86 typedef struct ide_hd_timings_s {
87 int active_time; /* Active pulse (ns) minimum */
88 int recovery_time; /* Recovery pulse (ns) minimum */
89 } ide_hd_timings_t;
91 static int basePort; /* base port address (0x30 or 0xb0) */
92 static byte config; /* config register of qd6580 */
93 static byte control; /* control register of qd6580 */
95 static int bus_clock; /* Vesa local bus clock (ns) */
96 static int tuned=0; /* to remember whether we've already been tuned */
97 static int snd_tuned=0; /* to remember whether we've already been tuned */
98 static int nb_disks_prim=0; /* number of disk drives on primary port */
101 * write_reg
103 * writes the specified byte on the specified register
106 static void write_reg ( byte content, byte reg )
108 unsigned long flags;
110 save_flags(flags); /* all CPUs */
111 cli(); /* all CPUs */
112 outb_p(content,reg);
113 inb(0x3f6);
114 restore_flags(flags); /* all CPUs */
118 * tune_drive
120 * Finds timings for the specified drive, returns it in struct t
123 static void tune_drive ( ide_drive_t *drive, byte pio, ide_hd_timings_t *t )
125 ide_pio_data_t d;
127 t->active_time = 175;
128 t->recovery_time = 415; /* worst cases values from the dos driver */
130 if (!drive->present) { /* not present : free to give any timing */
131 t->active_time = 0;
132 t->recovery_time = 0;
133 return;
136 pio = ide_get_best_pio_mode(drive, pio, 255, &d);
137 pio = IDE_MIN(pio,4);
139 switch (pio) {
140 case 0: break;
141 case 3:
142 if (d.cycle_time >= 110) {
143 t->active_time = 86;
144 t->recovery_time = d.cycle_time-102;
145 } else {
146 printk("%s: Strange recovery time !\n",drive->name);
147 return;
149 break;
150 case 4:
151 if (d.cycle_time >= 69) {
152 t->active_time = 70;
153 t->recovery_time = d.cycle_time-61;
154 } else {
155 printk("%s: Strange recovery time !\n",drive->name);
156 return;
158 break;
159 default:
160 if (d.cycle_time >= 180) {
161 t->active_time = 110;
162 t->recovery_time = d.cycle_time - 120;
163 } else {
164 t->active_time = ide_pio_timings[pio].active_time;
165 t->recovery_time = d.cycle_time
166 -t->active_time;
169 printk("%s: PIO mode%d, tim1=%dns tim2=%dns\n", drive->name, pio, t->active_time, t->recovery_time);
171 if (drive->media == ide_disk)
172 nb_disks_prim++;
173 else {
174 /* need to disable read-ahead FIFO and post-write buffer for ATAPI drives*/
175 write_reg(0x5f,basePort+0x03);
176 printk("%s: Warning: please try to connect this drive to secondary IDE port\nto improve data transfer rate on primary IDE port.\n",drive->name);
181 * tune_snd_drive
183 * Finds timings for the specified drive, using second channel rules
186 static void tune_snd_drive ( ide_drive_t *drive, byte pio, ide_hd_timings_t *t )
188 ide_pio_data_t d;
190 t->active_time = 175;
191 t->recovery_time = 415;
193 if (!drive->present) { /* not present : free to give any timing */
194 t->active_time = 0;
195 t->recovery_time = 0;
196 return;
199 pio = ide_get_best_pio_mode(drive, pio, 255, &d);
201 if ((pio) && (d.cycle_time >= 180)) {
202 t->active_time = 115;
203 t->recovery_time = d.cycle_time - 115;
205 printk("%s: PIO mode%d, tim1=%dns tim2=%dns\n", drive->name, pio, t->active_time, t->recovery_time);
207 if ((drive->media == ide_disk) && (nb_disks_prim<2)) {
208 /* a disk drive on secondary port while there's room on primary, which is the
209 * only one that has read-ahead fifo and post-write buffer ? What a waste !*/
210 printk("%s: Warning: please try to connect this drive to primary IDE port\nto improve data transfer rate.\n",drive->name);
215 * compute_timing
217 * computes the timing value where
218 * lower nibble is active time, in count of VLB clocks, 17-(from 2 to 17)
219 * upper nibble is recovery time, in count of VLB clocks, 15-(from 2 to 15)
222 static byte compute_timing ( char name[6], ide_hd_timings_t *t )
224 byte active_cycle;
225 byte recovery_cycle;
226 byte parameter;
228 active_cycle = 17-IDE_IN(t->active_time / bus_clock + 1, 2, 17);
229 recovery_cycle = 15-IDE_IN(t->recovery_time / bus_clock + 1, 2, 15);
231 parameter = active_cycle | (recovery_cycle<<4);
233 printk("%s: tim1=%dns tim2=%dns => %#x\n", name, t[0].active_time, t[0].recovery_time, parameter);
234 return(parameter);
238 * tune_ide
240 * Tunes the whole hwif, ie tunes each drives, and in case we have to share,
241 * takes the worse timings to tune qd6580
244 static void tune_ide ( ide_hwif_t *hwif, byte pio )
246 unsigned long flags;
247 ide_hd_timings_t t[2]={{0,0},{0,0}};
248 int bus_speed = ide_system_bus_speed ();
250 bus_clock = 1000 / bus_speed;
252 save_flags(flags); /* all CPUs */
253 cli(); /* all CPUs */
254 outb( (bus_clock<30) ? 0x0 : 0x0a, basePort + 0x02);
255 outb( 0x40 | ((control & 0x02) ? 0x9f:0x1f), basePort+0x03);
256 restore_flags(flags);
258 tune_drive (&hwif->drives[0], pio, &t[0]);
259 tune_drive (&hwif->drives[1], pio, &t[1]);
261 if (control & 0x01) { /* only primary port enabled, can tune separately */
262 write_reg(compute_timing (hwif->drives[0].name, &t[0]),basePort);
263 write_reg(compute_timing (hwif->drives[1].name, &t[1]),basePort+0x02);
264 } else { /* both ports enabled, we have to share */
266 t[0].active_time = IDE_MAX(t[0].active_time, t[1].active_time);
267 t[0].recovery_time = IDE_MAX(t[0].recovery_time,t[1].recovery_time);
268 write_reg(compute_timing (hwif->name, &t[0]),basePort);
273 * tune_snd_ide
275 * Tunes the whole secondary hwif, ie tunes each drives, and takes the worse
276 * timings to tune qd6580
279 static void tune_snd_ide ( ide_hwif_t *hwif, byte pio )
281 ide_hd_timings_t t[2]={{0,0},{0,0}};
283 tune_snd_drive (&hwif->drives[0], pio, &t[0]);
284 tune_snd_drive (&hwif->drives[1], pio, &t[1]);
286 t[0].active_time = IDE_MAX(t[0].active_time, t[1].active_time);
287 t[0].recovery_time = IDE_MAX(t[0].recovery_time,t[1].recovery_time);
289 write_reg(compute_timing (hwif->name, &t[0]),basePort+0x02);
293 * tune_qd6580
295 * tunes the hwif if not tuned
298 static void tune_qd6580 (ide_drive_t *drive, byte pio)
300 if (! tuned) {
301 tune_ide(HWIF(drive), pio);
302 tuned = 1;
307 * tune_snd_qd6580
309 * tunes the second hwif if not tuned
312 static void tune_snd_qd6580 (ide_drive_t *drive, byte pio)
314 if (! snd_tuned) {
315 tune_snd_ide(HWIF(drive), pio);
316 snd_tuned = 1;
321 * testreg
323 * tests if the given port is a register
326 static int __init testreg(int port)
328 byte savereg;
329 byte readreg;
330 unsigned long flags;
332 save_flags(flags); /* all CPUs */
333 cli(); /* all CPUs */
334 savereg = inb(port);
335 outb_p(0x15,port); /* safe value */
336 readreg = inb_p(port);
337 outb(savereg,port);
338 restore_flags(flags); /* all CPUs */
340 if (savereg == 0x15) {
341 printk("Outch ! the probe for qd6580 isn't reliable !\n");
342 printk("Please contact maintainers to tell about your hardware\n");
343 printk("Assuming qd6580 is not present.\n");
344 return 0;
347 return (readreg == 0x15);
351 * trybase:
353 * tries to find a qd6580 at the given base and save it if found
356 static int __init trybase (int base)
358 unsigned long flags;
360 save_flags(flags); /* all CPUs */
361 cli(); /* all CPUs */
362 config = inb(base+0x01);
363 control = inb(base+0x03);
364 restore_flags(flags); /* all CPUs */
366 if (((config & 0xf0) != 0x50) && ((config & 0xf0) != 0xa0)) return(0);
367 if (! ( ((config & 0x02) == 0x0) == (base == 0x30) ) ) return (0);
369 /* Seems to be OK, let's use it */
371 basePort = base;
372 return(testreg(base));
376 * probe:
378 * probes qd6580 at 0xb0 (the default) or 0x30
381 static int __init probe (void)
383 return (trybase(0xb0) ? 1 : trybase(0x30));
387 * init_qd6580:
389 * called at the very beginning of initialization ; should just probe and link
392 void __init init_qd6580 (void)
394 if (! probe()) {
395 printk("qd6580: not found\n");
396 return;
399 printk("qd6580: base=%#x, config=%#x, control=%#x\n", basePort, config, control);
401 ide_hwifs[0].chipset = ide_qd6580;
402 ide_hwifs[0].tuneproc = &tune_qd6580;
403 if (!(control & 0x01)) {
404 ide_hwifs[1].chipset = ide_qd6580;
405 ide_hwifs[1].tuneproc = &tune_snd_qd6580;
406 ide_hwifs[0].mate = &ide_hwifs[1];
407 ide_hwifs[1].mate = &ide_hwifs[0];
408 ide_hwifs[1].channel = 1;