aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2007-07-08 02:29:42 -0400
committerJeff Garzik <jeff@garzik.org>2007-07-09 12:17:35 -0400
commitcd70c26617f4686355263be4533ce8030242740e (patch)
tree20313e5c0a996b5c95ce46ba8ed796271316ef28 /drivers
parent469248abf00dfa813356b372ffe153b85f27f4bf (diff)
[libata] AHCI: Add support for Marvell AHCI-like chips (initially 6145)
Add support for the SATA portion of Marvell's AHCI-compatible chips. The PATA port capability, also available via AHCI, is disabled until support is completed. NCQ and PCI MSI are disabled by default. Marvell says "we use NCQ" in their drivers but "we do not use PCI MSI." Theoretically that implies we need to fix ahci.c to work with Marvell NCQ, but one wonders why Marvell NCQ is any different from other AHCI chips. Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/ahci.c51
1 files changed, 48 insertions, 3 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index f66e2a50158b..11e4eb9f304e 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -46,7 +46,7 @@
46#include <linux/libata.h> 46#include <linux/libata.h>
47 47
48#define DRV_NAME "ahci" 48#define DRV_NAME "ahci"
49#define DRV_VERSION "2.2" 49#define DRV_VERSION "2.3"
50 50
51 51
52enum { 52enum {
@@ -81,6 +81,7 @@ enum {
81 board_ahci_vt8251 = 2, 81 board_ahci_vt8251 = 2,
82 board_ahci_ign_iferr = 3, 82 board_ahci_ign_iferr = 3,
83 board_ahci_sb600 = 4, 83 board_ahci_sb600 = 4,
84 board_ahci_mv = 5,
84 85
85 /* global controller registers */ 86 /* global controller registers */
86 HOST_CAP = 0x00, /* host capabilities */ 87 HOST_CAP = 0x00, /* host capabilities */
@@ -171,6 +172,8 @@ enum {
171 AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ 172 AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */
172 AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ 173 AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */
173 AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ 174 AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */
175 AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */
176 AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */
174 177
175 AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 178 AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
176 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 179 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
@@ -364,6 +367,18 @@ static const struct ata_port_info ahci_port_info[] = {
364 .udma_mask = ATA_UDMA6, 367 .udma_mask = ATA_UDMA6,
365 .port_ops = &ahci_ops, 368 .port_ops = &ahci_ops,
366 }, 369 },
370 /* board_ahci_mv */
371 {
372 .sht = &ahci_sht,
373 .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
374 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
375 ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI |
376 AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI |
377 AHCI_FLAG_MV_PATA,
378 .pio_mask = 0x1f, /* pio0-4 */
379 .udma_mask = ATA_UDMA6,
380 .port_ops = &ahci_ops,
381 },
367}; 382};
368 383
369static const struct pci_device_id ahci_pci_tbl[] = { 384static const struct pci_device_id ahci_pci_tbl[] = {
@@ -459,6 +474,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
459 { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ 474 { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
460 { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ 475 { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
461 476
477 /* Marvell */
478 { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
479
462 /* Generic, PCI class code for AHCI */ 480 /* Generic, PCI class code for AHCI */
463 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 481 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
464 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, 482 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
@@ -544,6 +562,20 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
544 hpriv->saved_port_map = port_map; 562 hpriv->saved_port_map = port_map;
545 } 563 }
546 564
565 /*
566 * Temporary Marvell 6145 hack: PATA port presence
567 * is asserted through the standard AHCI port
568 * presence register, as bit 4 (counting from 0)
569 */
570 if (pi->flags & AHCI_FLAG_MV_PATA) {
571 dev_printk(KERN_ERR, &pdev->dev,
572 "MV_AHCI HACK: port_map %x -> %x\n",
573 hpriv->port_map,
574 hpriv->port_map & 0xf);
575
576 port_map &= 0xf;
577 }
578
547 /* cross check port_map and cap.n_ports */ 579 /* cross check port_map and cap.n_ports */
548 if (pi->flags & AHCI_FLAG_HONOR_PI) { 580 if (pi->flags & AHCI_FLAG_HONOR_PI) {
549 u32 tmp_port_map = port_map; 581 u32 tmp_port_map = port_map;
@@ -856,12 +888,25 @@ static void ahci_init_controller(struct ata_host *host)
856 struct pci_dev *pdev = to_pci_dev(host->dev); 888 struct pci_dev *pdev = to_pci_dev(host->dev);
857 void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 889 void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
858 int i; 890 int i;
891 void __iomem *port_mmio;
859 u32 tmp; 892 u32 tmp;
860 893
894 if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) {
895 port_mmio = __ahci_port_base(host, 4);
896
897 writel(0, port_mmio + PORT_IRQ_MASK);
898
899 /* clear port IRQ */
900 tmp = readl(port_mmio + PORT_IRQ_STAT);
901 VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
902 if (tmp)
903 writel(tmp, port_mmio + PORT_IRQ_STAT);
904 }
905
861 for (i = 0; i < host->n_ports; i++) { 906 for (i = 0; i < host->n_ports; i++) {
862 struct ata_port *ap = host->ports[i]; 907 struct ata_port *ap = host->ports[i];
863 void __iomem *port_mmio = ahci_port_base(ap);
864 908
909 port_mmio = ahci_port_base(ap);
865 if (ata_port_is_dummy(ap)) 910 if (ata_port_is_dummy(ap))
866 continue; 911 continue;
867 912
@@ -1738,7 +1783,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1738 if (rc) 1783 if (rc)
1739 return rc; 1784 return rc;
1740 1785
1741 if (pci_enable_msi(pdev)) 1786 if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev))
1742 pci_intx(pdev, 1); 1787 pci_intx(pdev, 1);
1743 1788
1744 hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); 1789 hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);