109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
275742cb4SAlan Cox /*
375742cb4SAlan Cox * Marvell PATA driver.
475742cb4SAlan Cox *
575742cb4SAlan Cox * For the moment we drive the PATA port in legacy mode. That
675742cb4SAlan Cox * isn't making full use of the device functionality but it is
775742cb4SAlan Cox * easy to get working.
875742cb4SAlan Cox *
9ab771630SAlan Cox * (c) 2006 Red Hat
1075742cb4SAlan Cox */
1175742cb4SAlan Cox
1275742cb4SAlan Cox #include <linux/kernel.h>
1375742cb4SAlan Cox #include <linux/module.h>
1475742cb4SAlan Cox #include <linux/pci.h>
1575742cb4SAlan Cox #include <linux/blkdev.h>
1675742cb4SAlan Cox #include <linux/delay.h>
1775742cb4SAlan Cox #include <linux/device.h>
1875742cb4SAlan Cox #include <scsi/scsi_host.h>
1975742cb4SAlan Cox #include <linux/libata.h>
2075742cb4SAlan Cox #include <linux/ata.h>
2175742cb4SAlan Cox
2275742cb4SAlan Cox #define DRV_NAME "pata_marvell"
235b66c829SAlan Cox #define DRV_VERSION "0.1.6"
245b66c829SAlan Cox
255b66c829SAlan Cox /**
265b66c829SAlan Cox * marvell_pata_active - check if PATA is active
275b66c829SAlan Cox * @pdev: PCI device
285b66c829SAlan Cox *
295b66c829SAlan Cox * Returns 1 if the PATA port may be active. We know how to check this
305b66c829SAlan Cox * for the 6145 but not the other devices
315b66c829SAlan Cox */
325b66c829SAlan Cox
marvell_pata_active(struct pci_dev * pdev)335b66c829SAlan Cox static int marvell_pata_active(struct pci_dev *pdev)
345b66c829SAlan Cox {
355b66c829SAlan Cox u32 devices;
365b66c829SAlan Cox void __iomem *barp;
375b66c829SAlan Cox
385b66c829SAlan Cox /* We don't yet know how to do this for other devices */
395b66c829SAlan Cox if (pdev->device != 0x6145)
405b66c829SAlan Cox return 1;
415b66c829SAlan Cox
425b66c829SAlan Cox barp = pci_iomap(pdev, 5, 0x10);
435b66c829SAlan Cox if (barp == NULL)
445b66c829SAlan Cox return -ENOMEM;
455b66c829SAlan Cox
465b66c829SAlan Cox devices = ioread32(barp + 0x0C);
475b66c829SAlan Cox pci_iounmap(pdev, barp);
485b66c829SAlan Cox
495b66c829SAlan Cox if (devices & 0x10)
505b66c829SAlan Cox return 1;
515b66c829SAlan Cox return 0;
525b66c829SAlan Cox }
5375742cb4SAlan Cox
5475742cb4SAlan Cox /**
552a2beac9SBartlomiej Zolnierkiewicz * marvell_pre_reset - probe begin
56cc0680a5STejun Heo * @link: link
57d4b2bab4STejun Heo * @deadline: deadline jiffies for the operation
5875742cb4SAlan Cox *
5975742cb4SAlan Cox * Perform the PATA port setup we need.
6075742cb4SAlan Cox */
6175742cb4SAlan Cox
marvell_pre_reset(struct ata_link * link,unsigned long deadline)62cc0680a5STejun Heo static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
6375742cb4SAlan Cox {
64cc0680a5STejun Heo struct ata_port *ap = link->ap;
6575742cb4SAlan Cox struct pci_dev *pdev = to_pci_dev(ap->host->dev);
6675742cb4SAlan Cox
675b66c829SAlan Cox if (pdev->device == 0x6145 && ap->port_no == 0 &&
685b66c829SAlan Cox !marvell_pata_active(pdev)) /* PATA enable ? */
6975742cb4SAlan Cox return -ENOENT;
7027c78b37SJeff Garzik
719363c382STejun Heo return ata_sff_prereset(link, deadline);
72307c6054SAlan Cox }
7375742cb4SAlan Cox
marvell_cable_detect(struct ata_port * ap)74307c6054SAlan Cox static int marvell_cable_detect(struct ata_port *ap)
75307c6054SAlan Cox {
7675742cb4SAlan Cox /* Cable type */
7775742cb4SAlan Cox switch(ap->port_no)
7875742cb4SAlan Cox {
7975742cb4SAlan Cox case 0:
80aafa9f95SZheyu Ma if (!ap->ioaddr.bmdma_addr)
81aafa9f95SZheyu Ma return ATA_CBL_PATA_UNK;
820d5ff566STejun Heo if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1)
83307c6054SAlan Cox return ATA_CBL_PATA40;
84307c6054SAlan Cox return ATA_CBL_PATA80;
8575742cb4SAlan Cox case 1: /* Legacy SATA port */
86307c6054SAlan Cox return ATA_CBL_SATA;
8775742cb4SAlan Cox }
88d4b2bab4STejun Heo
89307c6054SAlan Cox BUG();
90307c6054SAlan Cox return 0; /* Our BUG macro needs the right markup */
9175742cb4SAlan Cox }
9275742cb4SAlan Cox
9375742cb4SAlan Cox /* No PIO or DMA methods needed for this device */
9475742cb4SAlan Cox
95*25df73d9SBart Van Assche static const struct scsi_host_template marvell_sht = {
9668d1d07bSTejun Heo ATA_BMDMA_SHT(DRV_NAME),
9775742cb4SAlan Cox };
9875742cb4SAlan Cox
99029cfd6bSTejun Heo static struct ata_port_operations marvell_ops = {
100029cfd6bSTejun Heo .inherits = &ata_bmdma_port_ops,
101307c6054SAlan Cox .cable_detect = marvell_cable_detect,
102887125e3STejun Heo .prereset = marvell_pre_reset,
10375742cb4SAlan Cox };
10475742cb4SAlan Cox
10575742cb4SAlan Cox
10675742cb4SAlan Cox /**
10775742cb4SAlan Cox * marvell_init_one - Register Marvell ATA PCI device with kernel services
10875742cb4SAlan Cox * @pdev: PCI device to register
109a446e2fbSLee Jones * @id: PCI device ID
11075742cb4SAlan Cox *
11175742cb4SAlan Cox * Called from kernel PCI layer.
11275742cb4SAlan Cox *
11375742cb4SAlan Cox * LOCKING:
11475742cb4SAlan Cox * Inherited from PCI layer (may sleep).
11575742cb4SAlan Cox *
11675742cb4SAlan Cox * RETURNS:
11775742cb4SAlan Cox * Zero on success, or -ERRNO value.
11875742cb4SAlan Cox */
11975742cb4SAlan Cox
marvell_init_one(struct pci_dev * pdev,const struct pci_device_id * id)12075742cb4SAlan Cox static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
12175742cb4SAlan Cox {
1221626aeb8STejun Heo static const struct ata_port_info info = {
1231d2808fdSJeff Garzik .flags = ATA_FLAG_SLAVE_POSS,
12475742cb4SAlan Cox
12514bdef98SErik Inge Bolsø .pio_mask = ATA_PIO4,
12614bdef98SErik Inge Bolsø .mwdma_mask = ATA_MWDMA2,
127bf6263a8SJeff Garzik .udma_mask = ATA_UDMA5,
12875742cb4SAlan Cox
12975742cb4SAlan Cox .port_ops = &marvell_ops,
13075742cb4SAlan Cox };
1311626aeb8STejun Heo static const struct ata_port_info info_sata = {
13275742cb4SAlan Cox /* Slave possible as its magically mapped not real */
1331d2808fdSJeff Garzik .flags = ATA_FLAG_SLAVE_POSS,
13475742cb4SAlan Cox
13514bdef98SErik Inge Bolsø .pio_mask = ATA_PIO4,
13614bdef98SErik Inge Bolsø .mwdma_mask = ATA_MWDMA2,
137bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6,
13875742cb4SAlan Cox
13975742cb4SAlan Cox .port_ops = &marvell_ops,
14075742cb4SAlan Cox };
1411626aeb8STejun Heo const struct ata_port_info *ppi[] = { &info, &info_sata };
14275742cb4SAlan Cox
14375742cb4SAlan Cox if (pdev->device == 0x6101)
1441626aeb8STejun Heo ppi[1] = &ata_dummy_port_info;
14575742cb4SAlan Cox
1465219d653SJavier Martinez Canillas #if IS_ENABLED(CONFIG_SATA_AHCI)
1475b66c829SAlan Cox if (!marvell_pata_active(pdev)) {
14821f0e60aSHannes Reinecke dev_info(&pdev->dev,
14921f0e60aSHannes Reinecke "PATA port not active, deferring to AHCI driver.\n");
1505b66c829SAlan Cox return -ENODEV;
1515b66c829SAlan Cox }
1525b66c829SAlan Cox #endif
1531c5afdf7STejun Heo return ata_pci_bmdma_init_one(pdev, ppi, &marvell_sht, NULL, 0);
15475742cb4SAlan Cox }
15575742cb4SAlan Cox
15675742cb4SAlan Cox static const struct pci_device_id marvell_pci_tbl[] = {
15775742cb4SAlan Cox { PCI_DEVICE(0x11AB, 0x6101), },
158d36ee189SAlan Cox { PCI_DEVICE(0x11AB, 0x6121), },
159d36ee189SAlan Cox { PCI_DEVICE(0x11AB, 0x6123), },
16075742cb4SAlan Cox { PCI_DEVICE(0x11AB, 0x6145), },
161f920fe1cSPaweł Drewniak { PCI_DEVICE(0x1B4B, 0x91A0), },
162f920fe1cSPaweł Drewniak { PCI_DEVICE(0x1B4B, 0x91A4), },
163f920fe1cSPaweł Drewniak
16475742cb4SAlan Cox { } /* terminate list */
16575742cb4SAlan Cox };
16675742cb4SAlan Cox
16775742cb4SAlan Cox static struct pci_driver marvell_pci_driver = {
16875742cb4SAlan Cox .name = DRV_NAME,
16975742cb4SAlan Cox .id_table = marvell_pci_tbl,
17075742cb4SAlan Cox .probe = marvell_init_one,
17175742cb4SAlan Cox .remove = ata_pci_remove_one,
17258eb8cd5SBartlomiej Zolnierkiewicz #ifdef CONFIG_PM_SLEEP
17330ced0f0SAlan .suspend = ata_pci_device_suspend,
17430ced0f0SAlan .resume = ata_pci_device_resume,
175438ac6d5STejun Heo #endif
17675742cb4SAlan Cox };
17775742cb4SAlan Cox
1782fc75da0SAxel Lin module_pci_driver(marvell_pci_driver);
17975742cb4SAlan Cox
18075742cb4SAlan Cox MODULE_AUTHOR("Alan Cox");
18175742cb4SAlan Cox MODULE_DESCRIPTION("SCSI low-level driver for Marvell ATA in legacy mode");
18275742cb4SAlan Cox MODULE_LICENSE("GPL");
18375742cb4SAlan Cox MODULE_DEVICE_TABLE(pci, marvell_pci_tbl);
18475742cb4SAlan Cox MODULE_VERSION(DRV_VERSION);
185