xref: /openbmc/linux/drivers/ata/pata_marvell.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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