aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2010-01-18 02:20:00 -0500
committerDavid S. Miller <davem@davemloft.net>2010-01-19 04:41:58 -0500
commitf931a5d5785d7b7c44871bd7ad2762e29dfddf29 (patch)
treeaf04196b29f9ee7644e6e274dde8fa106a2b7abc /drivers
parenta13e4865fac374f2edf2666b66f2f88e527db2b7 (diff)
via82cxxx: workaround h/w bugs
Add custom struct ide_tp_ops instance to fix the internal bug of some VIA chipsets which will reset the device register after changing the nIEN bit in the device control register. Based on commit bfce5e0 for pata_via host driver. Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ide/via82cxxx.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
index 11b3e711451a..46e8ddbdf031 100644
--- a/drivers/ide/via82cxxx.c
+++ b/drivers/ide/via82cxxx.c
@@ -107,6 +107,7 @@ struct via82cxxx_dev
107{ 107{
108 struct via_isa_bridge *via_config; 108 struct via_isa_bridge *via_config;
109 unsigned int via_80w; 109 unsigned int via_80w;
110 u8 cached_device[2];
110}; 111};
111 112
112/** 113/**
@@ -382,10 +383,66 @@ static const struct ide_port_ops via_port_ops = {
382 .cable_detect = via82cxxx_cable_detect, 383 .cable_detect = via82cxxx_cable_detect,
383}; 384};
384 385
386static void via_write_devctl(ide_hwif_t *hwif, u8 ctl)
387{
388 struct via82cxxx_dev *vdev = hwif->host->host_priv;
389
390 outb(ctl, hwif->io_ports.ctl_addr);
391 outb(vdev->cached_device[hwif->channel], hwif->io_ports.device_addr);
392}
393
394static void __via_dev_select(ide_drive_t *drive, u8 select)
395{
396 ide_hwif_t *hwif = drive->hwif;
397 struct via82cxxx_dev *vdev = hwif->host->host_priv;
398
399 outb(select, hwif->io_ports.device_addr);
400 vdev->cached_device[hwif->channel] = select;
401}
402
403static void via_dev_select(ide_drive_t *drive)
404{
405 __via_dev_select(drive, drive->select | ATA_DEVICE_OBS);
406}
407
408static void via_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
409{
410 ide_hwif_t *hwif = drive->hwif;
411 struct ide_io_ports *io_ports = &hwif->io_ports;
412
413 if (valid & IDE_VALID_FEATURE)
414 outb(tf->feature, io_ports->feature_addr);
415 if (valid & IDE_VALID_NSECT)
416 outb(tf->nsect, io_ports->nsect_addr);
417 if (valid & IDE_VALID_LBAL)
418 outb(tf->lbal, io_ports->lbal_addr);
419 if (valid & IDE_VALID_LBAM)
420 outb(tf->lbam, io_ports->lbam_addr);
421 if (valid & IDE_VALID_LBAH)
422 outb(tf->lbah, io_ports->lbah_addr);
423 if (valid & IDE_VALID_DEVICE)
424 __via_dev_select(drive, tf->device);
425}
426
427const struct ide_tp_ops via_tp_ops = {
428 .exec_command = ide_exec_command,
429 .read_status = ide_read_status,
430 .read_altstatus = ide_read_altstatus,
431 .write_devctl = via_write_devctl,
432
433 .dev_select = via_dev_select,
434 .tf_load = via_tf_load,
435 .tf_read = ide_tf_read,
436
437 .input_data = ide_input_data,
438 .output_data = ide_output_data,
439};
440
385static const struct ide_port_info via82cxxx_chipset __devinitdata = { 441static const struct ide_port_info via82cxxx_chipset __devinitdata = {
386 .name = DRV_NAME, 442 .name = DRV_NAME,
387 .init_chipset = init_chipset_via82cxxx, 443 .init_chipset = init_chipset_via82cxxx,
388 .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } }, 444 .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
445 .tp_ops = &via_tp_ops,
389 .port_ops = &via_port_ops, 446 .port_ops = &via_port_ops,
390 .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST | 447 .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST |
391 IDE_HFLAG_POST_SET_MODE | 448 IDE_HFLAG_POST_SET_MODE |