From bfce5e0179ad059035df28558724ff60af708e09 Mon Sep 17 00:00:00 2001 From: "JosephChan@via.com.tw" Date: Wed, 30 Jul 2008 12:32:48 -0700 Subject: pata_via: add VX800 flag; add function for fixing h/w bugs Add flag VIA_SATA_PATA for vx800, VX800 uses the same chipset(0x0581/0x5324) as CX700, which has 1 PATA channel(Master/Slave) and 1 SATA channel(Master/Slave) Add function . This is to fix the internal bug of VIA chipsets, which will reset the device register after changing the IEN bit in CTL register Signed-off-by: Joseph Chan Cc: Tejun Heo Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/pata_via.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) (limited to 'drivers/ata') diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 708ed144ede9..57d951b11f2d 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -98,7 +98,8 @@ static const struct via_isa_bridge { u8 rev_max; u16 flags; } via_isa_bridges[] = { - { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, + { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 | + VIA_BAD_AST | VIA_SATA_PATA }, { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA }, @@ -322,6 +323,65 @@ static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev) via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]); } +/** + * via_ata_sff_tf_load - send taskfile registers to host controller + * @ap: Port to which output is sent + * @tf: ATA taskfile register set + * + * Outputs ATA taskfile to standard ATA host controller. + * + * Note: This is to fix the internal bug of via chipsets, which + * will reset the device register after changing the IEN bit on + * ctl register + */ +static void via_ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + iowrite8(tf->ctl, ioaddr->ctl_addr); + iowrite8(tf->device, ioaddr->device_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + iowrite8(tf->hob_feature, ioaddr->feature_addr); + iowrite8(tf->hob_nsect, ioaddr->nsect_addr); + iowrite8(tf->hob_lbal, ioaddr->lbal_addr); + iowrite8(tf->hob_lbam, ioaddr->lbam_addr); + iowrite8(tf->hob_lbah, ioaddr->lbah_addr); + VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", + tf->hob_feature, + tf->hob_nsect, + tf->hob_lbal, + tf->hob_lbam, + tf->hob_lbah); + } + + if (is_addr) { + iowrite8(tf->feature, ioaddr->feature_addr); + iowrite8(tf->nsect, ioaddr->nsect_addr); + iowrite8(tf->lbal, ioaddr->lbal_addr); + iowrite8(tf->lbam, ioaddr->lbam_addr); + iowrite8(tf->lbah, ioaddr->lbah_addr); + VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", + tf->feature, + tf->nsect, + tf->lbal, + tf->lbam, + tf->lbah); + } + + if (tf->flags & ATA_TFLAG_DEVICE) { + iowrite8(tf->device, ioaddr->device_addr); + VPRINTK("device 0x%X\n", tf->device); + } + + ata_wait_idle(ap); +} + static struct scsi_host_template via_sht = { ATA_BMDMA_SHT(DRV_NAME), }; @@ -332,11 +392,13 @@ static struct ata_port_operations via_port_ops = { .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, .prereset = via_pre_reset, + .sff_tf_load = via_ata_tf_load, }; static struct ata_port_operations via_port_ops_noirq = { .inherits = &via_port_ops, .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_tf_load = via_ata_tf_load, }; /** -- cgit v1.2.3