diff options
Diffstat (limited to 'drivers/ide/legacy/qd65xx.c')
-rw-r--r-- | drivers/ide/legacy/qd65xx.c | 238 |
1 files changed, 84 insertions, 154 deletions
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c index 7016bdf4fcc1..6424af154325 100644 --- a/drivers/ide/legacy/qd65xx.c +++ b/drivers/ide/legacy/qd65xx.c | |||
@@ -11,11 +11,7 @@ | |||
11 | * | 11 | * |
12 | * QDI QD6500/QD6580 EIDE controller fast support | 12 | * QDI QD6500/QD6580 EIDE controller fast support |
13 | * | 13 | * |
14 | * Please set local bus speed using kernel parameter idebus | ||
15 | * for example, "idebus=33" stands for 33Mhz VLbus | ||
16 | * To activate controller support, use "ide0=qd65xx" | 14 | * To activate controller support, use "ide0=qd65xx" |
17 | * To enable tuning, use "hda=autotune hdb=autotune" | ||
18 | * To enable 2nd channel tuning (qd6580 only), use "hdc=autotune hdd=autotune" | ||
19 | */ | 15 | */ |
20 | 16 | ||
21 | /* | 17 | /* |
@@ -37,6 +33,8 @@ | |||
37 | #include <asm/system.h> | 33 | #include <asm/system.h> |
38 | #include <asm/io.h> | 34 | #include <asm/io.h> |
39 | 35 | ||
36 | #define DRV_NAME "qd65xx" | ||
37 | |||
40 | #include "qd65xx.h" | 38 | #include "qd65xx.h" |
41 | 39 | ||
42 | /* | 40 | /* |
@@ -88,12 +86,12 @@ | |||
88 | static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */ | 86 | static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */ |
89 | 87 | ||
90 | /* | 88 | /* |
91 | * qd_select: | 89 | * qd65xx_select: |
92 | * | 90 | * |
93 | * This routine is invoked from ide.c to prepare for access to a given drive. | 91 | * This routine is invoked to prepare for access to a given drive. |
94 | */ | 92 | */ |
95 | 93 | ||
96 | static void qd_select (ide_drive_t *drive) | 94 | static void qd65xx_select(ide_drive_t *drive) |
97 | { | 95 | { |
98 | u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) | | 96 | u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) | |
99 | (QD_TIMREG(drive) & 0x02); | 97 | (QD_TIMREG(drive) & 0x02); |
@@ -112,17 +110,18 @@ static void qd_select (ide_drive_t *drive) | |||
112 | 110 | ||
113 | static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time) | 111 | static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time) |
114 | { | 112 | { |
115 | u8 active_cycle,recovery_cycle; | 113 | int clk = ide_vlb_clk ? ide_vlb_clk : system_bus_clock(); |
114 | u8 act_cyc, rec_cyc; | ||
116 | 115 | ||
117 | if (system_bus_clock()<=33) { | 116 | if (clk <= 33) { |
118 | active_cycle = 9 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 9); | 117 | act_cyc = 9 - IDE_IN(active_time * clk / 1000 + 1, 2, 9); |
119 | recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15); | 118 | rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15); |
120 | } else { | 119 | } else { |
121 | active_cycle = 8 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 1, 8); | 120 | act_cyc = 8 - IDE_IN(active_time * clk / 1000 + 1, 1, 8); |
122 | recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18); | 121 | rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18); |
123 | } | 122 | } |
124 | 123 | ||
125 | return((recovery_cycle<<4) | 0x08 | active_cycle); | 124 | return (rec_cyc << 4) | 0x08 | act_cyc; |
126 | } | 125 | } |
127 | 126 | ||
128 | /* | 127 | /* |
@@ -133,10 +132,13 @@ static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery | |||
133 | 132 | ||
134 | static u8 qd6580_compute_timing (int active_time, int recovery_time) | 133 | static u8 qd6580_compute_timing (int active_time, int recovery_time) |
135 | { | 134 | { |
136 | u8 active_cycle = 17 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 17); | 135 | int clk = ide_vlb_clk ? ide_vlb_clk : system_bus_clock(); |
137 | u8 recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15); | 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); | ||
138 | 140 | ||
139 | return((recovery_cycle<<4) | active_cycle); | 141 | return (rec_cyc << 4) | act_cyc; |
140 | } | 142 | } |
141 | 143 | ||
142 | /* | 144 | /* |
@@ -168,36 +170,15 @@ static int qd_find_disk_type (ide_drive_t *drive, | |||
168 | } | 170 | } |
169 | 171 | ||
170 | /* | 172 | /* |
171 | * qd_timing_ok: | ||
172 | * | ||
173 | * check whether timings don't conflict | ||
174 | */ | ||
175 | |||
176 | static int qd_timing_ok (ide_drive_t drives[]) | ||
177 | { | ||
178 | return (IDE_IMPLY(drives[0].present && drives[1].present, | ||
179 | IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1), | ||
180 | QD_TIMING(drives) == QD_TIMING(drives+1)))); | ||
181 | /* if same timing register, must be same timing */ | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * qd_set_timing: | 173 | * qd_set_timing: |
186 | * | 174 | * |
187 | * records the timing, and enables selectproc as needed | 175 | * records the timing |
188 | */ | 176 | */ |
189 | 177 | ||
190 | static void qd_set_timing (ide_drive_t *drive, u8 timing) | 178 | static void qd_set_timing (ide_drive_t *drive, u8 timing) |
191 | { | 179 | { |
192 | ide_hwif_t *hwif = HWIF(drive); | ||
193 | |||
194 | drive->drive_data &= 0xff00; | 180 | drive->drive_data &= 0xff00; |
195 | drive->drive_data |= timing; | 181 | drive->drive_data |= timing; |
196 | if (qd_timing_ok(hwif->drives)) { | ||
197 | qd_select(drive); /* selects once */ | ||
198 | hwif->selectproc = NULL; | ||
199 | } else | ||
200 | hwif->selectproc = &qd_select; | ||
201 | 182 | ||
202 | printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); | 183 | printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); |
203 | } | 184 | } |
@@ -225,10 +206,11 @@ static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio) | |||
225 | 206 | ||
226 | static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio) | 207 | static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio) |
227 | { | 208 | { |
228 | int base = HWIF(drive)->select_data; | 209 | ide_hwif_t *hwif = drive->hwif; |
229 | unsigned int cycle_time; | 210 | unsigned int cycle_time; |
230 | int active_time = 175; | 211 | int active_time = 175; |
231 | int recovery_time = 415; /* worst case values from the dos driver */ | 212 | int recovery_time = 415; /* worst case values from the dos driver */ |
213 | u8 base = (hwif->config_data & 0xff00) >> 8; | ||
232 | 214 | ||
233 | if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) { | 215 | if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) { |
234 | cycle_time = ide_pio_cycle_time(drive, pio); | 216 | cycle_time = ide_pio_cycle_time(drive, pio); |
@@ -299,21 +281,10 @@ static int __init qd_testreg(int port) | |||
299 | return (readreg != QD_TESTVAL); | 281 | return (readreg != QD_TESTVAL); |
300 | } | 282 | } |
301 | 283 | ||
302 | /* | ||
303 | * qd_setup: | ||
304 | * | ||
305 | * called to setup an ata channel : adjusts attributes & links for tuning | ||
306 | */ | ||
307 | |||
308 | static void __init qd_setup(ide_hwif_t *hwif, int base, int config) | ||
309 | { | ||
310 | hwif->select_data = base; | ||
311 | hwif->config_data = config; | ||
312 | } | ||
313 | |||
314 | static void __init qd6500_port_init_devs(ide_hwif_t *hwif) | 284 | static void __init qd6500_port_init_devs(ide_hwif_t *hwif) |
315 | { | 285 | { |
316 | u8 base = hwif->select_data, config = QD_CONFIG(hwif); | 286 | u8 base = (hwif->config_data & 0xff00) >> 8; |
287 | u8 config = QD_CONFIG(hwif); | ||
317 | 288 | ||
318 | hwif->drives[0].drive_data = QD6500_DEF_DATA; | 289 | hwif->drives[0].drive_data = QD6500_DEF_DATA; |
319 | hwif->drives[1].drive_data = QD6500_DEF_DATA; | 290 | hwif->drives[1].drive_data = QD6500_DEF_DATA; |
@@ -322,9 +293,10 @@ static void __init qd6500_port_init_devs(ide_hwif_t *hwif) | |||
322 | static void __init qd6580_port_init_devs(ide_hwif_t *hwif) | 293 | static void __init qd6580_port_init_devs(ide_hwif_t *hwif) |
323 | { | 294 | { |
324 | u16 t1, t2; | 295 | u16 t1, t2; |
325 | u8 base = hwif->select_data, config = QD_CONFIG(hwif); | 296 | u8 base = (hwif->config_data & 0xff00) >> 8; |
297 | u8 config = QD_CONFIG(hwif); | ||
326 | 298 | ||
327 | if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) { | 299 | if (hwif->host_flags & IDE_HFLAG_SINGLE) { |
328 | t1 = QD6580_DEF_DATA; | 300 | t1 = QD6580_DEF_DATA; |
329 | t2 = QD6580_DEF_DATA2; | 301 | t2 = QD6580_DEF_DATA2; |
330 | } else | 302 | } else |
@@ -334,11 +306,23 @@ static void __init qd6580_port_init_devs(ide_hwif_t *hwif) | |||
334 | hwif->drives[1].drive_data = t2; | 306 | hwif->drives[1].drive_data = t2; |
335 | } | 307 | } |
336 | 308 | ||
309 | static const struct ide_port_ops qd6500_port_ops = { | ||
310 | .port_init_devs = qd6500_port_init_devs, | ||
311 | .set_pio_mode = qd6500_set_pio_mode, | ||
312 | .selectproc = qd65xx_select, | ||
313 | }; | ||
314 | |||
315 | static const struct ide_port_ops qd6580_port_ops = { | ||
316 | .port_init_devs = qd6580_port_init_devs, | ||
317 | .set_pio_mode = qd6580_set_pio_mode, | ||
318 | .selectproc = qd65xx_select, | ||
319 | }; | ||
320 | |||
337 | static const struct ide_port_info qd65xx_port_info __initdata = { | 321 | static const struct ide_port_info qd65xx_port_info __initdata = { |
322 | .name = DRV_NAME, | ||
338 | .chipset = ide_qd65xx, | 323 | .chipset = ide_qd65xx, |
339 | .host_flags = IDE_HFLAG_IO_32BIT | | 324 | .host_flags = IDE_HFLAG_IO_32BIT | |
340 | IDE_HFLAG_NO_DMA | | 325 | IDE_HFLAG_NO_DMA, |
341 | IDE_HFLAG_NO_AUTOTUNE, | ||
342 | .pio_mask = ATA_PIO4, | 326 | .pio_mask = ATA_PIO4, |
343 | }; | 327 | }; |
344 | 328 | ||
@@ -351,65 +335,41 @@ static const struct ide_port_info qd65xx_port_info __initdata = { | |||
351 | 335 | ||
352 | static int __init qd_probe(int base) | 336 | static int __init qd_probe(int base) |
353 | { | 337 | { |
354 | ide_hwif_t *hwif; | 338 | int rc; |
355 | u8 config, unit; | 339 | u8 config, unit, control; |
356 | u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; | 340 | struct ide_port_info d = qd65xx_port_info; |
357 | hw_regs_t hw[2]; | ||
358 | 341 | ||
359 | config = inb(QD_CONFIG_PORT); | 342 | config = inb(QD_CONFIG_PORT); |
360 | 343 | ||
361 | if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) | 344 | if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) |
362 | return 1; | 345 | return -ENODEV; |
363 | 346 | ||
364 | unit = ! (config & QD_CONFIG_IDE_BASEPORT); | 347 | unit = ! (config & QD_CONFIG_IDE_BASEPORT); |
365 | 348 | ||
366 | memset(&hw, 0, sizeof(hw)); | 349 | if (unit) |
350 | d.host_flags |= IDE_HFLAG_QD_2ND_PORT; | ||
367 | 351 | ||
368 | ide_std_init_ports(&hw[0], 0x1f0, 0x3f6); | 352 | switch (config & 0xf0) { |
369 | hw[0].irq = 14; | 353 | case QD_CONFIG_QD6500: |
354 | if (qd_testreg(base)) | ||
355 | return -ENODEV; /* bad register */ | ||
370 | 356 | ||
371 | ide_std_init_ports(&hw[1], 0x170, 0x376); | ||
372 | hw[1].irq = 15; | ||
373 | |||
374 | if ((config & 0xf0) == QD_CONFIG_QD6500) { | ||
375 | |||
376 | if (qd_testreg(base)) return 1; /* bad register */ | ||
377 | |||
378 | /* qd6500 found */ | ||
379 | |||
380 | hwif = &ide_hwifs[unit]; | ||
381 | printk(KERN_NOTICE "%s: qd6500 at %#x\n", hwif->name, base); | ||
382 | printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n", | ||
383 | config, QD_ID3); | ||
384 | |||
385 | if (config & QD_CONFIG_DISABLED) { | 357 | if (config & QD_CONFIG_DISABLED) { |
386 | printk(KERN_WARNING "qd6500 is disabled !\n"); | 358 | printk(KERN_WARNING "qd6500 is disabled !\n"); |
387 | return 1; | 359 | return -ENODEV; |
388 | } | 360 | } |
389 | 361 | ||
390 | ide_init_port_hw(hwif, &hw[unit]); | 362 | printk(KERN_NOTICE "qd6500 at %#x\n", base); |
391 | 363 | printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n", | |
392 | qd_setup(hwif, base, config); | 364 | config, QD_ID3); |
393 | |||
394 | hwif->port_init_devs = qd6500_port_init_devs; | ||
395 | hwif->set_pio_mode = &qd6500_set_pio_mode; | ||
396 | |||
397 | idx[unit] = unit; | ||
398 | |||
399 | ide_device_add(idx, &qd65xx_port_info); | ||
400 | |||
401 | return 1; | ||
402 | } | ||
403 | |||
404 | if (((config & 0xf0) == QD_CONFIG_QD6580_A) || | ||
405 | ((config & 0xf0) == QD_CONFIG_QD6580_B)) { | ||
406 | |||
407 | u8 control; | ||
408 | |||
409 | if (qd_testreg(base) || qd_testreg(base+0x02)) return 1; | ||
410 | /* bad registers */ | ||
411 | 365 | ||
412 | /* qd6580 found */ | 366 | d.port_ops = &qd6500_port_ops; |
367 | d.host_flags |= IDE_HFLAG_SINGLE; | ||
368 | break; | ||
369 | case QD_CONFIG_QD6580_A: | ||
370 | case QD_CONFIG_QD6580_B: | ||
371 | if (qd_testreg(base) || qd_testreg(base + 0x02)) | ||
372 | return -ENODEV; /* bad registers */ | ||
413 | 373 | ||
414 | control = inb(QD_CONTROL_PORT); | 374 | control = inb(QD_CONTROL_PORT); |
415 | 375 | ||
@@ -419,74 +379,44 @@ static int __init qd_probe(int base) | |||
419 | 379 | ||
420 | outb(QD_DEF_CONTR, QD_CONTROL_PORT); | 380 | outb(QD_DEF_CONTR, QD_CONTROL_PORT); |
421 | 381 | ||
422 | if (control & QD_CONTR_SEC_DISABLED) { | 382 | d.port_ops = &qd6580_port_ops; |
423 | /* secondary disabled */ | 383 | if (control & QD_CONTR_SEC_DISABLED) |
424 | 384 | d.host_flags |= IDE_HFLAG_SINGLE; | |
425 | hwif = &ide_hwifs[unit]; | ||
426 | printk(KERN_INFO "%s: qd6580: single IDE board\n", | ||
427 | hwif->name); | ||
428 | |||
429 | ide_init_port_hw(hwif, &hw[unit]); | ||
430 | |||
431 | qd_setup(hwif, base, config | (control << 8)); | ||
432 | |||
433 | hwif->port_init_devs = qd6580_port_init_devs; | ||
434 | hwif->set_pio_mode = &qd6580_set_pio_mode; | ||
435 | |||
436 | idx[unit] = unit; | ||
437 | 385 | ||
438 | ide_device_add(idx, &qd65xx_port_info); | 386 | printk(KERN_INFO "qd6580: %s IDE board\n", |
439 | 387 | (control & QD_CONTR_SEC_DISABLED) ? "single" : "dual"); | |
440 | return 1; | 388 | break; |
441 | } else { | 389 | default: |
442 | ide_hwif_t *mate; | 390 | return -ENODEV; |
443 | 391 | } | |
444 | hwif = &ide_hwifs[0]; | ||
445 | mate = &ide_hwifs[1]; | ||
446 | /* secondary enabled */ | ||
447 | printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n", | ||
448 | hwif->name, mate->name); | ||
449 | |||
450 | ide_init_port_hw(hwif, &hw[0]); | ||
451 | ide_init_port_hw(mate, &hw[1]); | ||
452 | |||
453 | qd_setup(hwif, base, config | (control << 8)); | ||
454 | |||
455 | hwif->port_init_devs = qd6580_port_init_devs; | ||
456 | hwif->set_pio_mode = &qd6580_set_pio_mode; | ||
457 | |||
458 | qd_setup(mate, base, config | (control << 8)); | ||
459 | |||
460 | mate->port_init_devs = qd6580_port_init_devs; | ||
461 | mate->set_pio_mode = &qd6580_set_pio_mode; | ||
462 | 392 | ||
463 | idx[0] = 0; | 393 | rc = ide_legacy_device_add(&d, (base << 8) | config); |
464 | idx[1] = 1; | ||
465 | 394 | ||
466 | ide_device_add(idx, &qd65xx_port_info); | 395 | if (d.host_flags & IDE_HFLAG_SINGLE) |
396 | return (rc == 0) ? 1 : rc; | ||
467 | 397 | ||
468 | return 0; /* no other qd65xx possible */ | 398 | return rc; |
469 | } | ||
470 | } | ||
471 | /* no qd65xx found */ | ||
472 | return 1; | ||
473 | } | 399 | } |
474 | 400 | ||
475 | int probe_qd65xx = 0; | 401 | static int probe_qd65xx; |
476 | 402 | ||
477 | module_param_named(probe, probe_qd65xx, bool, 0); | 403 | module_param_named(probe, probe_qd65xx, bool, 0); |
478 | MODULE_PARM_DESC(probe, "probe for QD65xx chipsets"); | 404 | MODULE_PARM_DESC(probe, "probe for QD65xx chipsets"); |
479 | 405 | ||
480 | static int __init qd65xx_init(void) | 406 | static int __init qd65xx_init(void) |
481 | { | 407 | { |
408 | int rc1, rc2 = -ENODEV; | ||
409 | |||
482 | if (probe_qd65xx == 0) | 410 | if (probe_qd65xx == 0) |
483 | return -ENODEV; | 411 | return -ENODEV; |
484 | 412 | ||
485 | if (qd_probe(0x30)) | 413 | rc1 = qd_probe(0x30); |
486 | qd_probe(0xb0); | 414 | if (rc1) |
487 | if (ide_hwifs[0].chipset != ide_qd65xx && | 415 | rc2 = qd_probe(0xb0); |
488 | ide_hwifs[1].chipset != ide_qd65xx) | 416 | |
417 | if (rc1 < 0 && rc2 < 0) | ||
489 | return -ENODEV; | 418 | return -ENODEV; |
419 | |||
490 | return 0; | 420 | return 0; |
491 | } | 421 | } |
492 | 422 | ||