|
@@ -44,11 +44,16 @@
|
|
|
#include <linux/libata.h>
|
|
|
|
|
|
#define DRV_NAME "sata_via"
|
|
|
-#define DRV_VERSION "2.3"
|
|
|
+#define DRV_VERSION "2.4"
|
|
|
|
|
|
+/*
|
|
|
+ * vt8251 is different from other sata controllers of VIA. It has two
|
|
|
+ * channels, each channel has both Master and Slave slot.
|
|
|
+ */
|
|
|
enum board_ids_enum {
|
|
|
vt6420,
|
|
|
vt6421,
|
|
|
+ vt8251,
|
|
|
};
|
|
|
|
|
|
enum {
|
|
@@ -70,6 +75,8 @@ enum {
|
|
|
static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
|
|
|
static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
|
|
|
static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
|
|
|
+static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val);
|
|
|
+static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val);
|
|
|
static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
|
|
|
static void svia_noop_freeze(struct ata_port *ap);
|
|
|
static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
|
|
@@ -79,12 +86,12 @@ static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
|
|
|
|
|
|
static const struct pci_device_id svia_pci_tbl[] = {
|
|
|
{ PCI_VDEVICE(VIA, 0x5337), vt6420 },
|
|
|
- { PCI_VDEVICE(VIA, 0x0591), vt6420 },
|
|
|
- { PCI_VDEVICE(VIA, 0x3149), vt6420 },
|
|
|
- { PCI_VDEVICE(VIA, 0x3249), vt6421 },
|
|
|
- { PCI_VDEVICE(VIA, 0x5287), vt6420 },
|
|
|
+ { PCI_VDEVICE(VIA, 0x0591), vt6420 }, /* 2 sata chnls (Master) */
|
|
|
+ { PCI_VDEVICE(VIA, 0x3149), vt6420 }, /* 2 sata chnls (Master) */
|
|
|
+ { PCI_VDEVICE(VIA, 0x3249), vt6421 }, /* 2 sata chnls, 1 pata chnl */
|
|
|
{ PCI_VDEVICE(VIA, 0x5372), vt6420 },
|
|
|
{ PCI_VDEVICE(VIA, 0x7372), vt6420 },
|
|
|
+ { PCI_VDEVICE(VIA, 0x5287), vt8251 }, /* 2 sata chnls (Master/Slave) */
|
|
|
|
|
|
{ } /* terminate list */
|
|
|
};
|
|
@@ -128,6 +135,13 @@ static struct ata_port_operations vt6421_sata_ops = {
|
|
|
.scr_write = svia_scr_write,
|
|
|
};
|
|
|
|
|
|
+static struct ata_port_operations vt8251_ops = {
|
|
|
+ .inherits = &svia_base_ops,
|
|
|
+ .hardreset = sata_std_hardreset,
|
|
|
+ .scr_read = vt8251_scr_read,
|
|
|
+ .scr_write = vt8251_scr_write,
|
|
|
+};
|
|
|
+
|
|
|
static const struct ata_port_info vt6420_port_info = {
|
|
|
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
|
|
|
.pio_mask = 0x1f,
|
|
@@ -152,6 +166,15 @@ static struct ata_port_info vt6421_pport_info = {
|
|
|
.port_ops = &vt6421_pata_ops,
|
|
|
};
|
|
|
|
|
|
+static struct ata_port_info vt8251_port_info = {
|
|
|
+ .flags = ATA_FLAG_SATA | ATA_FLAG_SLAVE_POSS |
|
|
|
+ ATA_FLAG_NO_LEGACY,
|
|
|
+ .pio_mask = 0x1f,
|
|
|
+ .mwdma_mask = 0x07,
|
|
|
+ .udma_mask = ATA_UDMA6,
|
|
|
+ .port_ops = &vt8251_ops,
|
|
|
+};
|
|
|
+
|
|
|
MODULE_AUTHOR("Jeff Garzik");
|
|
|
MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
|
|
|
MODULE_LICENSE("GPL");
|
|
@@ -174,6 +197,83 @@ static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
|
|
|
+{
|
|
|
+ static const u8 ipm_tbl[] = { 1, 2, 6, 0 };
|
|
|
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
|
|
|
+ int slot = 2 * link->ap->port_no + link->pmp;
|
|
|
+ u32 v = 0;
|
|
|
+ u8 raw;
|
|
|
+
|
|
|
+ switch (scr) {
|
|
|
+ case SCR_STATUS:
|
|
|
+ pci_read_config_byte(pdev, 0xA0 + slot, &raw);
|
|
|
+
|
|
|
+ /* read the DET field, bit0 and 1 of the config byte */
|
|
|
+ v |= raw & 0x03;
|
|
|
+
|
|
|
+ /* read the SPD field, bit4 of the configure byte */
|
|
|
+ if (raw & (1 << 4))
|
|
|
+ v |= 0x02 << 4;
|
|
|
+ else
|
|
|
+ v |= 0x01 << 4;
|
|
|
+
|
|
|
+ /* read the IPM field, bit2 and 3 of the config byte */
|
|
|
+ v |= ipm_tbl[(raw >> 2) & 0x3];
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SCR_ERROR:
|
|
|
+ /* devices other than 5287 uses 0xA8 as base */
|
|
|
+ WARN_ON(pdev->device != 0x5287);
|
|
|
+ pci_read_config_dword(pdev, 0xB0 + slot * 4, &v);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SCR_CONTROL:
|
|
|
+ pci_read_config_byte(pdev, 0xA4 + slot, &raw);
|
|
|
+
|
|
|
+ /* read the DET field, bit0 and bit1 */
|
|
|
+ v |= ((raw & 0x02) << 1) | (raw & 0x01);
|
|
|
+
|
|
|
+ /* read the IPM field, bit2 and bit3 */
|
|
|
+ v |= ((raw >> 2) & 0x03) << 8;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ *val = v;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val)
|
|
|
+{
|
|
|
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
|
|
|
+ int slot = 2 * link->ap->port_no + link->pmp;
|
|
|
+ u32 v = 0;
|
|
|
+
|
|
|
+ switch (scr) {
|
|
|
+ case SCR_ERROR:
|
|
|
+ /* devices other than 5287 uses 0xA8 as base */
|
|
|
+ WARN_ON(pdev->device != 0x5287);
|
|
|
+ pci_write_config_dword(pdev, 0xB0 + slot * 4, val);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ case SCR_CONTROL:
|
|
|
+ /* set the DET field */
|
|
|
+ v |= ((val & 0x4) >> 1) | (val & 0x1);
|
|
|
+
|
|
|
+ /* set the IPM field */
|
|
|
+ v |= ((val >> 8) & 0x3) << 2;
|
|
|
+
|
|
|
+ pci_write_config_byte(pdev, 0xA4 + slot, v);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* svia_tf_load - send taskfile registers to host controller
|
|
|
* @ap: Port to which output is sent
|
|
@@ -396,6 +496,30 @@ static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
|
|
|
+{
|
|
|
+ const struct ata_port_info *ppi[] = { &vt8251_port_info, NULL };
|
|
|
+ struct ata_host *host;
|
|
|
+ int i, rc;
|
|
|
+
|
|
|
+ rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+ *r_host = host;
|
|
|
+
|
|
|
+ rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
|
|
|
+ if (rc) {
|
|
|
+ dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n");
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 8251 hosts four sata ports as M/S of the two channels */
|
|
|
+ for (i = 0; i < host->n_ports; i++)
|
|
|
+ ata_slave_link_init(host->ports[i]);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static void svia_configure(struct pci_dev *pdev)
|
|
|
{
|
|
|
u8 tmp8;
|
|
@@ -451,10 +575,10 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
|
- if (board_id == vt6420)
|
|
|
- bar_sizes = &svia_bar_sizes[0];
|
|
|
- else
|
|
|
+ if (board_id == vt6421)
|
|
|
bar_sizes = &vt6421_bar_sizes[0];
|
|
|
+ else
|
|
|
+ bar_sizes = &svia_bar_sizes[0];
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
|
|
|
if ((pci_resource_start(pdev, i) == 0) ||
|
|
@@ -467,12 +591,19 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
- if (board_id == vt6420)
|
|
|
+ switch (board_id) {
|
|
|
+ case vt6420:
|
|
|
rc = vt6420_prepare_host(pdev, &host);
|
|
|
- else
|
|
|
+ break;
|
|
|
+ case vt6421:
|
|
|
rc = vt6421_prepare_host(pdev, &host);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
+ break;
|
|
|
+ case vt8251:
|
|
|
+ rc = vt8251_prepare_host(pdev, &host);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
svia_configure(pdev);
|
|
|
|