Blame view

drivers/ata/pata_cs5520.c 7.36 KB
3e0a4e858   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
669a5db41   Jeff Garzik   [libata] Add a bu...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   *	IDE tuning and bus mastering support for the CS5510/CS5520
   *	chipsets
   *
   *	The CS5510/CS5520 are slightly unusual devices. Unlike the
   *	typical IDE controllers they do bus mastering with the drive in
   *	PIO mode and smarter silicon.
   *
   *	The practical upshot of this is that we must always tune the
   *	drive for the right PIO mode. We must also ignore all the blacklists
   *	and the drive bus mastering DMA information. Also to confuse matters
   *	further we can do DMA on PIO only drives.
   *
   *	DMA on the 5510 also requires we disable_hlt() during DMA on early
   *	revisions.
   *
   *	*** This driver is strictly experimental ***
   *
   *	(c) Copyright Red Hat Inc 2002
   *
669a5db41   Jeff Garzik   [libata] Add a bu...
22
   * Documentation:
25985edce   Lucas De Marchi   Fix common misspe...
23
   *	Not publicly available.
669a5db41   Jeff Garzik   [libata] Add a bu...
24
25
26
27
   */
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/pci.h>
669a5db41   Jeff Garzik   [libata] Add a bu...
28
29
30
31
32
33
  #include <linux/blkdev.h>
  #include <linux/delay.h>
  #include <scsi/scsi_host.h>
  #include <linux/libata.h>
  
  #define DRV_NAME	"pata_cs5520"
2a3103ce4   Jeff Garzik   [libata] Bump dri...
34
  #define DRV_VERSION	"0.6.6"
669a5db41   Jeff Garzik   [libata] Add a bu...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  
  struct pio_clocks
  {
  	int address;
  	int assert;
  	int recovery;
  };
  
  static const struct pio_clocks cs5520_pio_clocks[]={
  	{3, 6, 11},
  	{2, 5, 6},
  	{1, 4, 3},
  	{1, 3, 2},
  	{1, 2, 1}
  };
  
  /**
   *	cs5520_set_timings	-	program PIO timings
   *	@ap: ATA port
   *	@adev: ATA device
   *
   *	Program the PIO mode timings for the controller according to the pio
   *	clocking table.
   */
  
  static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int pio)
  {
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  	int slave = adev->devno;
  
  	pio -= XFER_PIO_0;
  
  	/* Channel command timing */
  	pci_write_config_byte(pdev, 0x62 + ap->port_no,
  				(cs5520_pio_clocks[pio].recovery << 4) |
  				(cs5520_pio_clocks[pio].assert));
  	/* FIXME: should these use address ? */
  	/* Read command timing */
  	pci_write_config_byte(pdev, 0x64 +  4*ap->port_no + slave,
  				(cs5520_pio_clocks[pio].recovery << 4) |
  				(cs5520_pio_clocks[pio].assert));
  	/* Write command timing */
  	pci_write_config_byte(pdev, 0x66 +  4*ap->port_no + slave,
  				(cs5520_pio_clocks[pio].recovery << 4) |
  				(cs5520_pio_clocks[pio].assert));
  }
  
  /**
669a5db41   Jeff Garzik   [libata] Add a bu...
83
84
85
86
87
   *	cs5520_set_piomode	-	program PIO timings
   *	@ap: ATA port
   *	@adev: ATA device
   *
   *	Program the PIO mode timings for the controller according to the pio
940a68de5   Bartlomiej Zolnierkiewicz   pata_cs5520: remo...
88
   *	clocking table.
669a5db41   Jeff Garzik   [libata] Add a bu...
89
90
91
92
93
94
   */
  
  static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
  {
  	cs5520_set_timings(ap, adev, adev->pio_mode);
  }
669a5db41   Jeff Garzik   [libata] Add a bu...
95
  static struct scsi_host_template cs5520_sht = {
68d1d07b5   Tejun Heo   libata: implement...
96
  	ATA_BMDMA_SHT(DRV_NAME),
d26fc9551   Alan Cox   libata: Support c...
97
  	.sg_tablesize		= LIBATA_DUMB_MAX_PRD,
669a5db41   Jeff Garzik   [libata] Add a bu...
98
99
100
  };
  
  static struct ata_port_operations cs5520_port_ops = {
029cfd6b7   Tejun Heo   libata: implement...
101
  	.inherits		= &ata_bmdma_port_ops,
f47451c45   Tejun Heo   libata-sff: ata_s...
102
  	.qc_prep		= ata_bmdma_dumb_qc_prep,
029cfd6b7   Tejun Heo   libata: implement...
103
  	.cable_detect		= ata_cable_40wire,
669a5db41   Jeff Garzik   [libata] Add a bu...
104
  	.set_piomode		= cs5520_set_piomode,
669a5db41   Jeff Garzik   [libata] Add a bu...
105
  };
0ec249146   Greg Kroah-Hartman   Drivers: ata: rem...
106
  static int cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
669a5db41   Jeff Garzik   [libata] Add a bu...
107
  {
cbcdd8759   Tejun Heo   libata: implement...
108
109
  	static const unsigned int cmd_port[] = { 0x1F0, 0x170 };
  	static const unsigned int ctl_port[] = { 0x3F6, 0x376 };
5d728824e   Tejun Heo   libata: convert t...
110
111
  	struct ata_port_info pi = {
  		.flags		= ATA_FLAG_SLAVE_POSS,
14bdef982   Erik Inge Bolsø   [libata] convert ...
112
  		.pio_mask	= ATA_PIO4,
5d728824e   Tejun Heo   libata: convert t...
113
114
115
  		.port_ops	= &cs5520_port_ops,
  	};
  	const struct ata_port_info *ppi[2];
669a5db41   Jeff Garzik   [libata] Add a bu...
116
  	u8 pcicfg;
4ca4e4396   Al Viro   libata annotation...
117
  	void __iomem *iomap[5];
5d728824e   Tejun Heo   libata: convert t...
118
119
120
  	struct ata_host *host;
  	struct ata_ioports *ioaddr;
  	int i, rc;
669a5db41   Jeff Garzik   [libata] Add a bu...
121

f08048e94   Tejun Heo   libata: PCI devic...
122
123
124
  	rc = pcim_enable_device(pdev);
  	if (rc)
  		return rc;
669a5db41   Jeff Garzik   [libata] Add a bu...
125
  	/* IDE port enable bits */
5d728824e   Tejun Heo   libata: convert t...
126
  	pci_read_config_byte(pdev, 0x60, &pcicfg);
669a5db41   Jeff Garzik   [libata] Add a bu...
127
128
129
130
  
  	/* Check if the ATA ports are enabled */
  	if ((pcicfg & 3) == 0)
  		return -ENODEV;
5d728824e   Tejun Heo   libata: convert t...
131
132
133
134
135
  	ppi[0] = ppi[1] = &ata_dummy_port_info;
  	if (pcicfg & 1)
  		ppi[0] = &pi;
  	if (pcicfg & 2)
  		ppi[1] = &pi;
669a5db41   Jeff Garzik   [libata] Add a bu...
136
  	if ((pcicfg & 0x40) == 0) {
a44fec1fc   Joe Perches   ata: Convert dev_...
137
138
  		dev_warn(&pdev->dev, "DMA mode disabled. Enabling.
  ");
5d728824e   Tejun Heo   libata: convert t...
139
  		pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
669a5db41   Jeff Garzik   [libata] Add a bu...
140
  	}
5d728824e   Tejun Heo   libata: convert t...
141
142
143
144
145
  	pi.mwdma_mask = id->driver_data;
  
  	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
  	if (!host)
  		return -ENOMEM;
669a5db41   Jeff Garzik   [libata] Add a bu...
146
  	/* Perform set up for DMA */
094839164   Benjamin Herrenschmidt   PCI: Remove users...
147
  	if (pci_enable_device_io(pdev)) {
669a5db41   Jeff Garzik   [libata] Add a bu...
148
149
150
151
  		printk(KERN_ERR DRV_NAME ": unable to configure BAR2.
  ");
  		return -ENODEV;
  	}
5d728824e   Tejun Heo   libata: convert t...
152

b5e555561   Christoph Hellwig   libata: switch re...
153
  	if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) {
669a5db41   Jeff Garzik   [libata] Add a bu...
154
155
156
157
  		printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.
  ");
  		return -ENODEV;
  	}
669a5db41   Jeff Garzik   [libata] Add a bu...
158

5d728824e   Tejun Heo   libata: convert t...
159
  	/* Map IO ports and initialize host accordingly */
cbcdd8759   Tejun Heo   libata: implement...
160
161
162
163
  	iomap[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8);
  	iomap[1] = devm_ioport_map(&pdev->dev, ctl_port[0], 1);
  	iomap[2] = devm_ioport_map(&pdev->dev, cmd_port[1], 8);
  	iomap[3] = devm_ioport_map(&pdev->dev, ctl_port[1], 1);
5d728824e   Tejun Heo   libata: convert t...
164
  	iomap[4] = pcim_iomap(pdev, 2, 0);
0d5ff5667   Tejun Heo   libata: convert t...
165
166
167
  
  	if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
  		return -ENOMEM;
5d728824e   Tejun Heo   libata: convert t...
168
169
170
171
172
  	ioaddr = &host->ports[0]->ioaddr;
  	ioaddr->cmd_addr = iomap[0];
  	ioaddr->ctl_addr = iomap[1];
  	ioaddr->altstatus_addr = iomap[1];
  	ioaddr->bmdma_addr = iomap[4];
9363c3825   Tejun Heo   libata: rename SF...
173
  	ata_sff_std_ports(ioaddr);
5d728824e   Tejun Heo   libata: convert t...
174

cbcdd8759   Tejun Heo   libata: implement...
175
176
177
  	ata_port_desc(host->ports[0],
  		      "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]);
  	ata_port_pbar_desc(host->ports[0], 4, 0, "bmdma");
5d728824e   Tejun Heo   libata: convert t...
178
179
180
181
182
  	ioaddr = &host->ports[1]->ioaddr;
  	ioaddr->cmd_addr = iomap[2];
  	ioaddr->ctl_addr = iomap[3];
  	ioaddr->altstatus_addr = iomap[3];
  	ioaddr->bmdma_addr = iomap[4] + 8;
9363c3825   Tejun Heo   libata: rename SF...
183
  	ata_sff_std_ports(ioaddr);
5d728824e   Tejun Heo   libata: convert t...
184

cbcdd8759   Tejun Heo   libata: implement...
185
186
187
  	ata_port_desc(host->ports[1],
  		      "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]);
  	ata_port_pbar_desc(host->ports[1], 4, 8, "bmdma");
5d728824e   Tejun Heo   libata: convert t...
188
189
190
191
192
193
194
195
  	/* activate the host */
  	pci_set_master(pdev);
  	rc = ata_host_start(host);
  	if (rc)
  		return rc;
  
  	for (i = 0; i < 2; i++) {
  		static const int irq[] = { 14, 15 };
8c6b065b7   Alan Cox   pata_cs5520: Fix ...
196
  		struct ata_port *ap = host->ports[i];
5d728824e   Tejun Heo   libata: convert t...
197
198
199
200
201
  
  		if (ata_port_is_dummy(ap))
  			continue;
  
  		rc = devm_request_irq(&pdev->dev, irq[ap->port_no],
c3b288942   Tejun Heo   libata-sff: separ...
202
  				      ata_bmdma_interrupt, 0, DRV_NAME, host);
5d728824e   Tejun Heo   libata: convert t...
203
204
  		if (rc)
  			return rc;
4031826b3   Tejun Heo   libata: fix assig...
205

cbcdd8759   Tejun Heo   libata: implement...
206
  		ata_port_desc(ap, "irq %d", irq[i]);
5d728824e   Tejun Heo   libata: convert t...
207
208
209
  	}
  
  	return ata_host_register(host, &cs5520_sht);
669a5db41   Jeff Garzik   [libata] Add a bu...
210
  }
58eb8cd56   Bartlomiej Zolnierkiewicz   ata: use CONFIG_P...
211
  #ifdef CONFIG_PM_SLEEP
8501120f1   Alan Cox   [PATCH] pata_cs55...
212
213
214
215
216
217
218
  /**
   *	cs5520_reinit_one	-	device resume
   *	@pdev: PCI device
   *
   *	Do any reconfiguration work needed by a resume from RAM. We need
   *	to restore DMA mode support on BIOSen which disabled it
   */
f20b16ff7   Jeff Garzik   [libata] trim tra...
219

8501120f1   Alan Cox   [PATCH] pata_cs55...
220
221
  static int cs5520_reinit_one(struct pci_dev *pdev)
  {
0a86e1c85   Jingoo Han   ata: use pci_get_...
222
  	struct ata_host *host = pci_get_drvdata(pdev);
8501120f1   Alan Cox   [PATCH] pata_cs55...
223
  	u8 pcicfg;
f08048e94   Tejun Heo   libata: PCI devic...
224
225
226
227
228
  	int rc;
  
  	rc = ata_pci_device_do_resume(pdev);
  	if (rc)
  		return rc;
8501120f1   Alan Cox   [PATCH] pata_cs55...
229
230
231
  	pci_read_config_byte(pdev, 0x60, &pcicfg);
  	if ((pcicfg & 0x40) == 0)
  		pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
f08048e94   Tejun Heo   libata: PCI devic...
232
233
234
  
  	ata_host_resume(host);
  	return 0;
8501120f1   Alan Cox   [PATCH] pata_cs55...
235
  }
aa6de4942   Alan Cox   pata_cs5520: susp...
236
237
238
239
240
241
242
243
244
245
246
247
248
  
  /**
   *	cs5520_pci_device_suspend	-	device suspend
   *	@pdev: PCI device
   *
   *	We have to cut and waste bits from the standard method because
   *	the 5520 is a bit odd and not just a pure ATA device. As a result
   *	we must not disable it. The needed code is short and this avoids
   *	chip specific mess in the core code.
   */
  
  static int cs5520_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
  {
0a86e1c85   Jingoo Han   ata: use pci_get_...
249
  	struct ata_host *host = pci_get_drvdata(pdev);
aa6de4942   Alan Cox   pata_cs5520: susp...
250
251
252
253
254
255
256
257
258
  	int rc = 0;
  
  	rc = ata_host_suspend(host, mesg);
  	if (rc)
  		return rc;
  
  	pci_save_state(pdev);
  	return 0;
  }
58eb8cd56   Bartlomiej Zolnierkiewicz   ata: use CONFIG_P...
259
  #endif /* CONFIG_PM_SLEEP */
a84471fe2   Jeff Garzik   [libata] Trim tra...
260

669a5db41   Jeff Garzik   [libata] Add a bu...
261
262
  /* For now keep DMA off. We can set it for all but A rev CS5510 once the
     core ATA code can handle it */
2d2744fc8   Jeff Garzik   [libata] PCI ID t...
263
264
265
266
267
  static const struct pci_device_id pata_cs5520[] = {
  	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
  	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
  
  	{ },
669a5db41   Jeff Garzik   [libata] Add a bu...
268
269
270
271
272
273
  };
  
  static struct pci_driver cs5520_pci_driver = {
  	.name 		= DRV_NAME,
  	.id_table	= pata_cs5520,
  	.probe 		= cs5520_init_one,
2855568b1   Jeff Garzik   [libata] struct p...
274
  	.remove		= ata_pci_remove_one,
58eb8cd56   Bartlomiej Zolnierkiewicz   ata: use CONFIG_P...
275
  #ifdef CONFIG_PM_SLEEP
aa6de4942   Alan Cox   pata_cs5520: susp...
276
  	.suspend	= cs5520_pci_device_suspend,
8501120f1   Alan Cox   [PATCH] pata_cs55...
277
  	.resume		= cs5520_reinit_one,
438ac6d5e   Tejun Heo   libata: add missi...
278
  #endif
669a5db41   Jeff Garzik   [libata] Add a bu...
279
  };
2fc75da0c   Axel Lin   ata: use module_p...
280
  module_pci_driver(cs5520_pci_driver);
669a5db41   Jeff Garzik   [libata] Add a bu...
281
282
283
284
285
286
  
  MODULE_AUTHOR("Alan Cox");
  MODULE_DESCRIPTION("low-level driver for Cyrix CS5510/5520");
  MODULE_LICENSE("GPL");
  MODULE_DEVICE_TABLE(pci, pata_cs5520);
  MODULE_VERSION(DRV_VERSION);