--- sata_via.c.orig 2005-10-28 13:49:49.000000000 +0800
+++ sata_via.c 2005-10-28 13:46:24.000000000 +0800
@@ -59,7 +59,7 @@
PORT0 = (1 << 1),
PORT1 = (1 << 0),
ALL_PORTS = PORT0 | PORT1,
- N_PORTS = 2,
+ N_PORTS = 3,
NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
@@ -104,9 +104,14 @@
.bios_param = ata_std_bios_param,
.ordered_flush = 1,
};
+static void via_pata_phy_reset(struct ata_port *ap);
+static void via_pata_set_piomode (struct ata_port *ap, struct ata_device *adev);
+static void via_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static struct ata_port_operations svia_sata_ops = {
.port_disable = ata_port_disable,
+ .set_piomode = via_pata_set_piomode,
+ .set_dmamode = via_pata_set_dmamode,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -114,7 +119,7 @@
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = sata_phy_reset,
+ .phy_reset = via_pata_phy_reset,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -129,9 +134,6 @@
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
- .scr_read = svia_scr_read,
- .scr_write = svia_scr_write,
-
.port_start = ata_port_start,
.port_stop = ata_port_stop,
};
@@ -196,9 +198,6 @@
probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS;
probe_ent->port[port].bmdma_addr = bmdma_addr;
- scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port);
- probe_ent->port[port].scr_addr = scr_addr;
-
ata_std_ports(&probe_ent->port[port]);
}
@@ -233,7 +232,7 @@
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->sht = &svia_sht;
- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
+ probe_ent->host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
ATA_FLAG_NO_LEGACY;
probe_ent->port_ops = &svia_sata_ops;
probe_ent->n_ports = N_PORTS;
@@ -248,6 +247,165 @@
return probe_ent;
}
+/* add functions for pata */
+
+
+/**
+ * via_pata_cbl_detect - Probe host controller cable detect info
+ * @ap: Port for which cable detect info is desired
+ *
+ * Read 80c cable indicator from ATA PCI device's PCI config
+ * register. This register is normally set by firmware (BIOS).
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static void via_pata_cbl_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ int cfg_addr;
+ u8 tmp, mask;
+
+ if (ap->port_no == 2) { /* PATA channel in VT6421 */
+ ap->cbl = ATA_CBL_PATA80;
+ cfg_addr = 0xB3;
+ pci_read_config_byte(pdev, cfg_addr, &tmp);
+ if (tmp & 0x10) { /* 40pin cable */
+ ap->cbl = ATA_CBL_PATA40;
+ } else { /* 80pin cable */
+ ap->cbl = ATA_CBL_PATA80;
+ }
+ } else { /* channel 0 and 1 are SATA channels */
+ ap->cbl = ATA_CBL_SATA;
+ }
+
+ return;
+}
+
+/**
+ * via_pata_phy_reset - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * Probe PATA phy.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void via_pata_phy_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+
+ via_pata_cbl_detect(ap);
+
+ ata_port_probe(ap);
+
+ ata_bus_reset(ap);
+}
+
+
+/**
+ * via_pata_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ * @pio: PIO mode, 0 - 4
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void via_pata_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host_set->dev);
+
+ u8 cfg_byte;
+ int cfg_addr;
+
+ if (ap->port_no != 2) { /* SATA channel in VT6421 */
+ /* no need to set */
+ return;
+ }
+
+
+ cfg_addr = 0xAB;
+ switch (adev->pio_mode & 0x07) {
+ case 0:
+ cfg_byte = 0xa8;
+ break;
+ case 1:
+ cfg_byte = 0x65;
+ break;
+ case 2:
+ cfg_byte = 0x65;
+ break;
+ case 3:
+ cfg_byte = 0x31;
+ break;
+ case 4:
+ cfg_byte = 0x20;
+ break;
+ default:
+ cfg_byte = 0x20;
+ }
+
+ pci_write_config_byte (dev, cfg_addr, cfg_byte);
+}
+
+/**
+ * via_pata_set_dmamode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ * @udma: udma mode, 0 - 6
+ *
+ * Set UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void via_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host_set->dev);
+
+ u8 cfg_byte;
+ int cfg_addr;
+
+ if (ap->port_no != 2) { /* SATA channel in VT6421 */
+ /* no need to set */
+ return;
+ }
+
+ cfg_addr = 0xB3;
+ switch (adev->dma_mode & 0x07) {
+ case 0:
+ cfg_byte = 0xee;
+ break;
+ case 1:
+ cfg_byte = 0xe8;
+ break;
+ case 2:
+ cfg_byte = 0xe6;
+ break;
+ case 3:
+ cfg_byte = 0xe4;
+ break;
+ case 4:
+ cfg_byte = 0xe2;
+ break;
+ case 5:
+ cfg_byte = 0xe1;
+ break;
+ case 6:
+ cfg_byte = 0xe0;
+ break;
+ default:
+ cfg_byte = 0xe0;
+ }
+
+ pci_write_config_byte (dev, cfg_addr, cfg_byte);
+}
static void svia_configure(struct pci_dev *pdev)
{
Jeff Garzik wrote:
>
> + switch (adev->dma_mode & 0x07) {
> + case 0:
> + cfg_byte = 0xee;
> + break;
> + case 1:
> + cfg_byte = 0xe8;
> + break;
> + case 2:
> + cfg_byte = 0xe6;
> + break;
> + case 3:
> + cfg_byte = 0xe4;
> + break;
> + case 4:
> + cfg_byte = 0xe2;
> + break;
> + case 5:
> + cfg_byte = 0xe1;
> + break;
> + case 6:
> + cfg_byte = 0xe0;
> + break;
> + default:
> + cfg_byte = 0xe0;
> + }
Mmm.. replace all that with this (?):
u8 cfg_bytes[8] = {0xee, 0xe8, 0xe6, 0xe4, 0xe2, 0xe1, 0xe0, 0xe0};
cfg_byte = cfg_bytes[adev->dma_mode & 7];
-ml
Jeff Garzik wrote:
>
> VIA contributed the attached update to sata_via, which adds support for
> the third (PATA) port, and switches around the reset method a bit.
Too many inline busy-waits.. needs to use timers & callbacks instead.
But it might do in the interim, until that stuff gets fixed.
Cheers