xref: /openbmc/linux/drivers/ata/pata_opti.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2669a5db4SJeff Garzik /*
3669a5db4SJeff Garzik  * pata_opti.c 	- ATI PATA for new ATA layer
4669a5db4SJeff Garzik  *			  (C) 2005 Red Hat Inc
5669a5db4SJeff Garzik  *
6669a5db4SJeff Garzik  * Based on
7669a5db4SJeff Garzik  *  linux/drivers/ide/pci/opti621.c		Version 0.7	Sept 10, 2002
8669a5db4SJeff Garzik  *
9669a5db4SJeff Garzik  *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
10669a5db4SJeff Garzik  *
11669a5db4SJeff Garzik  * Authors:
12669a5db4SJeff Garzik  * Jaromir Koutek <miri@punknet.cz>,
13669a5db4SJeff Garzik  * Jan Harkes <jaharkes@cwi.nl>,
14669a5db4SJeff Garzik  * Mark Lord <mlord@pobox.com>
15669a5db4SJeff Garzik  * Some parts of code are from ali14xx.c and from rz1000.c.
16669a5db4SJeff Garzik  *
17669a5db4SJeff Garzik  * Also consulted the FreeBSD prototype driver by Kevin Day to try
18669a5db4SJeff Garzik  * and resolve some confusions. Further documentation can be found in
19669a5db4SJeff Garzik  * Ralf Brown's interrupt list
20669a5db4SJeff Garzik  *
21669a5db4SJeff Garzik  * If you have other variants of the Opti range (Viper/Vendetta) please
22669a5db4SJeff Garzik  * try this driver with those PCI idents and report back. For the later
23669a5db4SJeff Garzik  * chips see the pata_optidma driver
24669a5db4SJeff Garzik  *
25669a5db4SJeff Garzik  */
26669a5db4SJeff Garzik 
27669a5db4SJeff Garzik #include <linux/kernel.h>
28669a5db4SJeff Garzik #include <linux/module.h>
29669a5db4SJeff Garzik #include <linux/pci.h>
30669a5db4SJeff Garzik #include <linux/blkdev.h>
31669a5db4SJeff Garzik #include <linux/delay.h>
32669a5db4SJeff Garzik #include <scsi/scsi_host.h>
33669a5db4SJeff Garzik #include <linux/libata.h>
34669a5db4SJeff Garzik 
35669a5db4SJeff Garzik #define DRV_NAME "pata_opti"
36a0fcdc02SJeff Garzik #define DRV_VERSION "0.2.9"
37669a5db4SJeff Garzik 
38669a5db4SJeff Garzik enum {
39669a5db4SJeff Garzik 	READ_REG	= 0,	/* index of Read cycle timing register */
40669a5db4SJeff Garzik 	WRITE_REG 	= 1,	/* index of Write cycle timing register */
41669a5db4SJeff Garzik 	CNTRL_REG 	= 3,	/* index of Control register */
42669a5db4SJeff Garzik 	STRAP_REG 	= 5,	/* index of Strap register */
43669a5db4SJeff Garzik 	MISC_REG 	= 6	/* index of Miscellaneous register */
44669a5db4SJeff Garzik };
45669a5db4SJeff Garzik 
46669a5db4SJeff Garzik /**
47669a5db4SJeff Garzik  *	opti_pre_reset		-	probe begin
48cc0680a5STejun Heo  *	@link: ATA link
49d4b2bab4STejun Heo  *	@deadline: deadline jiffies for the operation
50669a5db4SJeff Garzik  *
51669a5db4SJeff Garzik  *	Set up cable type and use generic probe init
52669a5db4SJeff Garzik  */
53669a5db4SJeff Garzik 
opti_pre_reset(struct ata_link * link,unsigned long deadline)54cc0680a5STejun Heo static int opti_pre_reset(struct ata_link *link, unsigned long deadline)
55669a5db4SJeff Garzik {
56cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
57669a5db4SJeff Garzik 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
58669a5db4SJeff Garzik 	static const struct pci_bits opti_enable_bits[] = {
59669a5db4SJeff Garzik 		{ 0x45, 1, 0x80, 0x00 },
60669a5db4SJeff Garzik 		{ 0x40, 1, 0x08, 0x00 }
61669a5db4SJeff Garzik 	};
62669a5db4SJeff Garzik 
63c961922bSAlan Cox 	if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
64c961922bSAlan Cox 		return -ENOENT;
65d4b2bab4STejun Heo 
669363c382STejun Heo 	return ata_sff_prereset(link, deadline);
67669a5db4SJeff Garzik }
68669a5db4SJeff Garzik 
69669a5db4SJeff Garzik /**
70669a5db4SJeff Garzik  *	opti_write_reg		-	control register setup
71669a5db4SJeff Garzik  *	@ap: ATA port
72dee1d6f3SLee Jones  *	@val: value
73669a5db4SJeff Garzik  *	@reg: control register number
74669a5db4SJeff Garzik  *
75669a5db4SJeff Garzik  *	The Opti uses magic 'trapdoor' register accesses to do configuration
76669a5db4SJeff Garzik  *	rather than using PCI space as other controllers do. The double inw
77669a5db4SJeff Garzik  *	on the error register activates configuration mode. We can then write
78669a5db4SJeff Garzik  *	the control register
79669a5db4SJeff Garzik  */
80669a5db4SJeff Garzik 
opti_write_reg(struct ata_port * ap,u8 val,int reg)81669a5db4SJeff Garzik static void opti_write_reg(struct ata_port *ap, u8 val, int reg)
82669a5db4SJeff Garzik {
830d5ff566STejun Heo 	void __iomem *regio = ap->ioaddr.cmd_addr;
84669a5db4SJeff Garzik 
85669a5db4SJeff Garzik 	/* These 3 unlock the control register access */
860d5ff566STejun Heo 	ioread16(regio + 1);
870d5ff566STejun Heo 	ioread16(regio + 1);
880d5ff566STejun Heo 	iowrite8(3, regio + 2);
89669a5db4SJeff Garzik 
90669a5db4SJeff Garzik 	/* Do the I/O */
910d5ff566STejun Heo 	iowrite8(val, regio + reg);
92669a5db4SJeff Garzik 
93669a5db4SJeff Garzik 	/* Relock */
940d5ff566STejun Heo 	iowrite8(0x83, regio + 2);
95669a5db4SJeff Garzik }
96669a5db4SJeff Garzik 
97669a5db4SJeff Garzik /**
98669a5db4SJeff Garzik  *	opti_set_piomode	-	set initial PIO mode data
99669a5db4SJeff Garzik  *	@ap: ATA interface
100669a5db4SJeff Garzik  *	@adev: ATA device
101669a5db4SJeff Garzik  *
102669a5db4SJeff Garzik  *	Called to do the PIO mode setup. Timing numbers are taken from
103669a5db4SJeff Garzik  *	the FreeBSD driver then pre computed to keep the code clean. There
104669a5db4SJeff Garzik  *	are two tables depending on the hardware clock speed.
105669a5db4SJeff Garzik  */
106669a5db4SJeff Garzik 
opti_set_piomode(struct ata_port * ap,struct ata_device * adev)107669a5db4SJeff Garzik static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev)
108669a5db4SJeff Garzik {
109669a5db4SJeff Garzik 	struct ata_device *pair = ata_dev_pair(adev);
110669a5db4SJeff Garzik 	int clock;
111669a5db4SJeff Garzik 	int pio = adev->pio_mode - XFER_PIO_0;
1120d5ff566STejun Heo 	void __iomem *regio = ap->ioaddr.cmd_addr;
113669a5db4SJeff Garzik 	u8 addr;
114669a5db4SJeff Garzik 
115669a5db4SJeff Garzik 	/* Address table precomputed with prefetch off and a DCLK of 2 */
116669a5db4SJeff Garzik 	static const u8 addr_timing[2][5] = {
117669a5db4SJeff Garzik 		{ 0x30, 0x20, 0x20, 0x10, 0x10 },
118669a5db4SJeff Garzik 		{ 0x20, 0x20, 0x10, 0x10, 0x10 }
119669a5db4SJeff Garzik 	};
120669a5db4SJeff Garzik 	static const u8 data_rec_timing[2][5] = {
121669a5db4SJeff Garzik 		{ 0x6B, 0x56, 0x42, 0x32, 0x31 },
122669a5db4SJeff Garzik 		{ 0x58, 0x44, 0x32, 0x22, 0x21 }
123669a5db4SJeff Garzik 	};
124669a5db4SJeff Garzik 
1250d5ff566STejun Heo 	iowrite8(0xff, regio + 5);
1260d5ff566STejun Heo 	clock = ioread16(regio + 5) & 1;
127669a5db4SJeff Garzik 
128669a5db4SJeff Garzik 	/*
129669a5db4SJeff Garzik  	 *	As with many controllers the address setup time is shared
130669a5db4SJeff Garzik  	 *	and must suit both devices if present.
131669a5db4SJeff Garzik 	 */
132669a5db4SJeff Garzik 
133669a5db4SJeff Garzik 	addr = addr_timing[clock][pio];
134669a5db4SJeff Garzik 	if (pair) {
135669a5db4SJeff Garzik 		/* Hardware constraint */
136669a5db4SJeff Garzik 		u8 pair_addr = addr_timing[clock][pair->pio_mode - XFER_PIO_0];
137669a5db4SJeff Garzik 		if (pair_addr > addr)
138669a5db4SJeff Garzik 			addr = pair_addr;
139669a5db4SJeff Garzik 	}
140669a5db4SJeff Garzik 
141669a5db4SJeff Garzik 	/* Commence primary programming sequence */
142669a5db4SJeff Garzik 	opti_write_reg(ap, adev->devno, MISC_REG);
143669a5db4SJeff Garzik 	opti_write_reg(ap, data_rec_timing[clock][pio], READ_REG);
144669a5db4SJeff Garzik 	opti_write_reg(ap, data_rec_timing[clock][pio], WRITE_REG);
145669a5db4SJeff Garzik 	opti_write_reg(ap, addr, MISC_REG);
146669a5db4SJeff Garzik 
147669a5db4SJeff Garzik 	/* Programming sequence complete, override strapping */
148669a5db4SJeff Garzik 	opti_write_reg(ap, 0x85, CNTRL_REG);
149669a5db4SJeff Garzik }
150669a5db4SJeff Garzik 
151*25df73d9SBart Van Assche static const struct scsi_host_template opti_sht = {
15268d1d07bSTejun Heo 	ATA_PIO_SHT(DRV_NAME),
153669a5db4SJeff Garzik };
154669a5db4SJeff Garzik 
155669a5db4SJeff Garzik static struct ata_port_operations opti_port_ops = {
156029cfd6bSTejun Heo 	.inherits	= &ata_sff_port_ops,
157a0fcdc02SJeff Garzik 	.cable_detect	= ata_cable_40wire,
158029cfd6bSTejun Heo 	.set_piomode	= opti_set_piomode,
159a1efdabaSTejun Heo 	.prereset	= opti_pre_reset,
160669a5db4SJeff Garzik };
161669a5db4SJeff Garzik 
opti_init_one(struct pci_dev * dev,const struct pci_device_id * id)162669a5db4SJeff Garzik static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
163669a5db4SJeff Garzik {
1641626aeb8STejun Heo 	static const struct ata_port_info info = {
1651d2808fdSJeff Garzik 		.flags = ATA_FLAG_SLAVE_POSS,
16614bdef98SErik Inge Bolsø 		.pio_mask = ATA_PIO4,
167669a5db4SJeff Garzik 		.port_ops = &opti_port_ops
168669a5db4SJeff Garzik 	};
1691626aeb8STejun Heo 	const struct ata_port_info *ppi[] = { &info, NULL };
170669a5db4SJeff Garzik 
17106296a1eSJoe Perches 	ata_print_version_once(&dev->dev, DRV_VERSION);
172669a5db4SJeff Garzik 
17316ea0fc9SAlan Cox 	return ata_pci_sff_init_one(dev, ppi, &opti_sht, NULL, 0);
174669a5db4SJeff Garzik }
175669a5db4SJeff Garzik 
176669a5db4SJeff Garzik static const struct pci_device_id opti[] = {
1772d2744fcSJeff Garzik 	{ PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
1782d2744fcSJeff Garzik 	{ PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 },
1792d2744fcSJeff Garzik 
1802d2744fcSJeff Garzik 	{ },
181669a5db4SJeff Garzik };
182669a5db4SJeff Garzik 
183669a5db4SJeff Garzik static struct pci_driver opti_pci_driver = {
184669a5db4SJeff Garzik 	.name 		= DRV_NAME,
185669a5db4SJeff Garzik 	.id_table	= opti,
186669a5db4SJeff Garzik 	.probe 		= opti_init_one,
18730ced0f0SAlan 	.remove		= ata_pci_remove_one,
18858eb8cd5SBartlomiej Zolnierkiewicz #ifdef CONFIG_PM_SLEEP
18930ced0f0SAlan 	.suspend	= ata_pci_device_suspend,
19030ced0f0SAlan 	.resume		= ata_pci_device_resume,
191438ac6d5STejun Heo #endif
192669a5db4SJeff Garzik };
193669a5db4SJeff Garzik 
1942fc75da0SAxel Lin module_pci_driver(opti_pci_driver);
195669a5db4SJeff Garzik 
196669a5db4SJeff Garzik MODULE_AUTHOR("Alan Cox");
197669a5db4SJeff Garzik MODULE_DESCRIPTION("low-level driver for Opti 621/621X");
198669a5db4SJeff Garzik MODULE_LICENSE("GPL");
199669a5db4SJeff Garzik MODULE_DEVICE_TABLE(pci, opti);
200669a5db4SJeff Garzik MODULE_VERSION(DRV_VERSION);
201