Blame view

drivers/ata/pata_atiixp.c 8.5 KB
669a5db41   Jeff Garzik   [libata] Add a bu...
1
2
3
  /*
   * pata_atiixp.c 	- ATI PATA for new ATA layer
   *			  (C) 2005 Red Hat Inc
e99846f18   Bartlomiej Zolnierkiewicz   [libata] pata_ati...
4
   *			  (C) 2009-2010 Bartlomiej Zolnierkiewicz
669a5db41   Jeff Garzik   [libata] Add a bu...
5
6
7
8
9
10
11
12
13
14
15
16
17
   *
   * Based on
   *
   *  linux/drivers/ide/pci/atiixp.c	Version 0.01-bart2	Feb. 26, 2004
   *
   *  Copyright (C) 2003 ATI Inc. <hyu@ati.com>
   *  Copyright (C) 2004 Bartlomiej Zolnierkiewicz
   *
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/pci.h>
669a5db41   Jeff Garzik   [libata] Add a bu...
18
19
20
21
  #include <linux/blkdev.h>
  #include <linux/delay.h>
  #include <scsi/scsi_host.h>
  #include <linux/libata.h>
1117c811a   Arnd Hannemann   pata_atiixp: over...
22
  #include <linux/dmi.h>
669a5db41   Jeff Garzik   [libata] Add a bu...
23
24
  
  #define DRV_NAME "pata_atiixp"
2a3103ce4   Jeff Garzik   [libata] Bump dri...
25
  #define DRV_VERSION "0.4.6"
669a5db41   Jeff Garzik   [libata] Add a bu...
26
27
28
29
30
31
32
33
34
  
  enum {
  	ATIIXP_IDE_PIO_TIMING	= 0x40,
  	ATIIXP_IDE_MWDMA_TIMING	= 0x44,
  	ATIIXP_IDE_PIO_CONTROL	= 0x48,
  	ATIIXP_IDE_PIO_MODE	= 0x4a,
  	ATIIXP_IDE_UDMA_CONTROL	= 0x54,
  	ATIIXP_IDE_UDMA_MODE 	= 0x56
  };
1117c811a   Arnd Hannemann   pata_atiixp: over...
35
36
37
38
39
40
41
42
43
44
45
  static const struct dmi_system_id attixp_cable_override_dmi_table[] = {
  	{
  		/* Board has onboard PATA<->SATA converters */
  		.ident = "MSI E350DM-E33",
  		.matches = {
  			DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
  			DMI_MATCH(DMI_BOARD_NAME, "E350DM-E33(MS-7720)"),
  		},
  	},
  	{ }
  };
847086069   Alan Cox   pata_atiixp: supp...
46
47
48
49
  static int atiixp_cable_detect(struct ata_port *ap)
  {
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  	u8 udma;
1117c811a   Arnd Hannemann   pata_atiixp: over...
50
51
  	if (dmi_check_system(attixp_cable_override_dmi_table))
  		return ATA_CBL_PATA40_SHORT;
847086069   Alan Cox   pata_atiixp: supp...
52
53
54
55
56
57
58
  	/* Hack from drivers/ide/pci. Really we want to know how to do the
  	   raw detection not play follow the bios mode guess */
  	pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
  	if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40)
  		return  ATA_CBL_PATA80;
  	return ATA_CBL_PATA40;
  }
e99846f18   Bartlomiej Zolnierkiewicz   [libata] pata_ati...
59
  static DEFINE_SPINLOCK(atiixp_lock);
669a5db41   Jeff Garzik   [libata] Add a bu...
60
  /**
46b9e7707   Bartlomiej Zolnierkiewicz   pata_atiixp: add ...
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
   *	atiixp_prereset	-	perform reset handling
   *	@link: ATA link
   *	@deadline: deadline jiffies for the operation
   *
   *	Reset sequence checking enable bits to see which ports are
   *	active.
   */
  
  static int atiixp_prereset(struct ata_link *link, unsigned long deadline)
  {
  	static const struct pci_bits atiixp_enable_bits[] = {
  		{ 0x48, 1, 0x01, 0x00 },
  		{ 0x48, 1, 0x08, 0x00 }
  	};
  
  	struct ata_port *ap = link->ap;
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  
  	if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
  		return -ENOENT;
  
  	return ata_sff_prereset(link, deadline);
  }
  
  /**
669a5db41   Jeff Garzik   [libata] Add a bu...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
   *	atiixp_set_pio_timing	-	set initial PIO mode data
   *	@ap: ATA interface
   *	@adev: ATA device
   *
   *	Called by both the pio and dma setup functions to set the controller
   *	timings for PIO transfers. We must load both the mode number and
   *	timing values into the controller.
   */
  
  static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev, int pio)
  {
  	static u8 pio_timings[5] = { 0x5D, 0x47, 0x34, 0x22, 0x20 };
  
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  	int dn = 2 * ap->port_no + adev->devno;
669a5db41   Jeff Garzik   [libata] Add a bu...
101
  	int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1);
1fd4bbec8   Bartlomiej Zolnierkiewicz   pata_atiixp: fix ...
102
103
  	u32 pio_timing_data;
  	u16 pio_mode_data;
669a5db41   Jeff Garzik   [libata] Add a bu...
104
105
106
107
108
  
  	pci_read_config_word(pdev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
  	pio_mode_data &= ~(0x7 << (4 * dn));
  	pio_mode_data |= pio << (4 * dn);
  	pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
1fd4bbec8   Bartlomiej Zolnierkiewicz   pata_atiixp: fix ...
109
  	pci_read_config_dword(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
d7b5a23fc   Jeff Garzik   [libata] pata_ati...
110
111
  	pio_timing_data &= ~(0xFF << timing_shift);
  	pio_timing_data |= (pio_timings[pio] << timing_shift);
1fd4bbec8   Bartlomiej Zolnierkiewicz   pata_atiixp: fix ...
112
  	pci_write_config_dword(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
669a5db41   Jeff Garzik   [libata] Add a bu...
113
114
115
116
117
118
119
120
121
122
123
124
125
  }
  
  /**
   *	atiixp_set_piomode	-	set initial PIO mode data
   *	@ap: ATA interface
   *	@adev: ATA device
   *
   *	Called to do the PIO mode setup. We use a shared helper for this
   *	as the DMA setup must also adjust the PIO timing information.
   */
  
  static void atiixp_set_piomode(struct ata_port *ap, struct ata_device *adev)
  {
e99846f18   Bartlomiej Zolnierkiewicz   [libata] pata_ati...
126
127
  	unsigned long flags;
  	spin_lock_irqsave(&atiixp_lock, flags);
669a5db41   Jeff Garzik   [libata] Add a bu...
128
  	atiixp_set_pio_timing(ap, adev, adev->pio_mode - XFER_PIO_0);
e99846f18   Bartlomiej Zolnierkiewicz   [libata] pata_ati...
129
  	spin_unlock_irqrestore(&atiixp_lock, flags);
669a5db41   Jeff Garzik   [libata] Add a bu...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  }
  
  /**
   *	atiixp_set_dmamode	-	set initial DMA mode data
   *	@ap: ATA interface
   *	@adev: ATA device
   *
   *	Called to do the DMA mode setup. We use timing tables for most
   *	modes but must tune an appropriate PIO mode to match.
   */
  
  static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
  {
  	static u8 mwdma_timings[5] = { 0x77, 0x21, 0x20 };
  
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  	int dma = adev->dma_mode;
  	int dn = 2 * ap->port_no + adev->devno;
  	int wanted_pio;
e99846f18   Bartlomiej Zolnierkiewicz   [libata] pata_ati...
149
150
151
  	unsigned long flags;
  
  	spin_lock_irqsave(&atiixp_lock, flags);
669a5db41   Jeff Garzik   [libata] Add a bu...
152
153
154
155
156
157
158
159
160
161
162
  
  	if (adev->dma_mode >= XFER_UDMA_0) {
  		u16 udma_mode_data;
  
  		dma -= XFER_UDMA_0;
  
  		pci_read_config_word(pdev, ATIIXP_IDE_UDMA_MODE, &udma_mode_data);
  		udma_mode_data &= ~(0x7 << (4 * dn));
  		udma_mode_data |= dma << (4 * dn);
  		pci_write_config_word(pdev, ATIIXP_IDE_UDMA_MODE, udma_mode_data);
  	} else {
669a5db41   Jeff Garzik   [libata] Add a bu...
163
  		int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1);
1fd4bbec8   Bartlomiej Zolnierkiewicz   pata_atiixp: fix ...
164
  		u32 mwdma_timing_data;
669a5db41   Jeff Garzik   [libata] Add a bu...
165
166
  
  		dma -= XFER_MW_DMA_0;
1fd4bbec8   Bartlomiej Zolnierkiewicz   pata_atiixp: fix ...
167
168
  		pci_read_config_dword(pdev, ATIIXP_IDE_MWDMA_TIMING,
  				      &mwdma_timing_data);
669a5db41   Jeff Garzik   [libata] Add a bu...
169
170
  		mwdma_timing_data &= ~(0xFF << timing_shift);
  		mwdma_timing_data |= (mwdma_timings[dma] << timing_shift);
1fd4bbec8   Bartlomiej Zolnierkiewicz   pata_atiixp: fix ...
171
172
  		pci_write_config_dword(pdev, ATIIXP_IDE_MWDMA_TIMING,
  				       mwdma_timing_data);
669a5db41   Jeff Garzik   [libata] Add a bu...
173
174
175
176
177
  	}
  	/*
  	 *	We must now look at the PIO mode situation. We may need to
  	 *	adjust the PIO mode to keep the timings acceptable
  	 */
273b542e7   Colin Ian King   pata_atiixp: fix ...
178
179
  	if (adev->dma_mode >= XFER_MW_DMA_2)
  		wanted_pio = 4;
669a5db41   Jeff Garzik   [libata] Add a bu...
180
181
182
183
184
185
186
187
  	else if (adev->dma_mode == XFER_MW_DMA_1)
  		wanted_pio = 3;
  	else if (adev->dma_mode == XFER_MW_DMA_0)
  		wanted_pio = 0;
  	else BUG();
  
  	if (adev->pio_mode != wanted_pio)
  		atiixp_set_pio_timing(ap, adev, wanted_pio);
e99846f18   Bartlomiej Zolnierkiewicz   [libata] pata_ati...
188
  	spin_unlock_irqrestore(&atiixp_lock, flags);
669a5db41   Jeff Garzik   [libata] Add a bu...
189
190
191
192
193
194
195
196
  }
  
  /**
   *	atiixp_bmdma_start	-	DMA start callback
   *	@qc: Command in progress
   *
   *	When DMA begins we need to ensure that the UDMA control
   *	register for the channel is correctly set.
21d2c925d   Alan Cox   pata_atiixp: Audi...
197
198
199
   *
   *	Note: The host lock held by the libata layer protects
   *	us from two channels both trying to set DMA bits at once
669a5db41   Jeff Garzik   [libata] Add a bu...
200
201
202
203
204
205
206
207
208
209
210
211
   */
  
  static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
  {
  	struct ata_port *ap = qc->ap;
  	struct ata_device *adev = qc->dev;
  
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  	int dn = (2 * ap->port_no) + adev->devno;
  	u16 tmp16;
  
  	pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
b15b3ebae   Alan Cox   libata: Fix a lar...
212
  	if (ata_using_udma(adev))
669a5db41   Jeff Garzik   [libata] Add a bu...
213
214
215
216
217
218
219
220
221
222
223
224
225
  		tmp16 |= (1 << dn);
  	else
  		tmp16 &= ~(1 << dn);
  	pci_write_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
  	ata_bmdma_start(qc);
  }
  
  /**
   *	atiixp_dma_stop	-	DMA stop callback
   *	@qc: Command in progress
   *
   *	DMA has completed. Clear the UDMA flag as the next operations will
   *	be PIO ones not UDMA data transfer.
21d2c925d   Alan Cox   pata_atiixp: Audi...
226
227
228
   *
   *	Note: The host lock held by the libata layer protects
   *	us from two channels both trying to set DMA bits at once
669a5db41   Jeff Garzik   [libata] Add a bu...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
   */
  
  static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
  {
  	struct ata_port *ap = qc->ap;
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  	int dn = (2 * ap->port_no) + qc->dev->devno;
  	u16 tmp16;
  
  	pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
  	tmp16 &= ~(1 << dn);
  	pci_write_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
  	ata_bmdma_stop(qc);
  }
  
  static struct scsi_host_template atiixp_sht = {
68d1d07b5   Tejun Heo   libata: implement...
245
  	ATA_BMDMA_SHT(DRV_NAME),
635adc280   Alan Cox   pata_atiixp: Use ...
246
  	.sg_tablesize		= LIBATA_DUMB_MAX_PRD,
669a5db41   Jeff Garzik   [libata] Add a bu...
247
248
249
  };
  
  static struct ata_port_operations atiixp_port_ops = {
029cfd6b7   Tejun Heo   libata: implement...
250
  	.inherits	= &ata_bmdma_port_ops,
669a5db41   Jeff Garzik   [libata] Add a bu...
251

f47451c45   Tejun Heo   libata-sff: ata_s...
252
  	.qc_prep 	= ata_bmdma_dumb_qc_prep,
669a5db41   Jeff Garzik   [libata] Add a bu...
253
254
  	.bmdma_start 	= atiixp_bmdma_start,
  	.bmdma_stop	= atiixp_bmdma_stop,
bda302881   Jeff Garzik   [libata] Don't us...
255

46b9e7707   Bartlomiej Zolnierkiewicz   pata_atiixp: add ...
256
  	.prereset	= atiixp_prereset,
029cfd6b7   Tejun Heo   libata: implement...
257
258
259
  	.cable_detect	= atiixp_cable_detect,
  	.set_piomode	= atiixp_set_piomode,
  	.set_dmamode	= atiixp_set_dmamode,
669a5db41   Jeff Garzik   [libata] Add a bu...
260
  };
16028232b   Tejun Heo   pata_atiixp: upda...
261
  static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
669a5db41   Jeff Garzik   [libata] Add a bu...
262
  {
1626aeb88   Tejun Heo   libata: clean up ...
263
  	static const struct ata_port_info info = {
1d2808fd3   Jeff Garzik   [libata] PATA dri...
264
  		.flags = ATA_FLAG_SLAVE_POSS,
14bdef982   Erik Inge Bolsø   [libata] convert ...
265
266
267
  		.pio_mask = ATA_PIO4,
  		.mwdma_mask = ATA_MWDMA12_ONLY,
  		.udma_mask = ATA_UDMA5,
669a5db41   Jeff Garzik   [libata] Add a bu...
268
269
  		.port_ops = &atiixp_port_ops
  	};
16028232b   Tejun Heo   pata_atiixp: upda...
270
  	const struct ata_port_info *ppi[] = { &info, &info };
16028232b   Tejun Heo   pata_atiixp: upda...
271

1c5afdf7a   Tejun Heo   libata-sff: separ...
272
273
  	return ata_pci_bmdma_init_one(pdev, ppi, &atiixp_sht, NULL,
  				      ATA_HOST_PARALLEL_SCAN);
669a5db41   Jeff Garzik   [libata] Add a bu...
274
  }
2d2744fc8   Jeff Garzik   [libata] PCI ID t...
275
276
277
278
279
  static const struct pci_device_id atiixp[] = {
  	{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
  	{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
  	{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
  	{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
1ca972c20   Jeff Garzik   [libata] pata_ati...
280
  	{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), },
5deab5366   Shane Huang   ahci / atiixp / p...
281
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), },
2d2744fc8   Jeff Garzik   [libata] PCI ID t...
282
283
  
  	{ },
669a5db41   Jeff Garzik   [libata] Add a bu...
284
285
286
287
288
289
  };
  
  static struct pci_driver atiixp_pci_driver = {
  	.name 		= DRV_NAME,
  	.id_table	= atiixp,
  	.probe 		= atiixp_init_one,
30ced0f0d   Alan Cox   [PATCH] PATA liba...
290
  	.remove		= ata_pci_remove_one,
58eb8cd56   Bartlomiej Zolnierkiewicz   ata: use CONFIG_P...
291
  #ifdef CONFIG_PM_SLEEP
30ced0f0d   Alan Cox   [PATCH] PATA liba...
292
293
  	.resume		= ata_pci_device_resume,
  	.suspend	= ata_pci_device_suspend,
438ac6d5e   Tejun Heo   libata: add missi...
294
  #endif
669a5db41   Jeff Garzik   [libata] Add a bu...
295
  };
2fc75da0c   Axel Lin   ata: use module_p...
296
  module_pci_driver(atiixp_pci_driver);
669a5db41   Jeff Garzik   [libata] Add a bu...
297

669a5db41   Jeff Garzik   [libata] Add a bu...
298
299
300
301
302
  MODULE_AUTHOR("Alan Cox");
  MODULE_DESCRIPTION("low-level driver for ATI IXP200/300/400");
  MODULE_LICENSE("GPL");
  MODULE_DEVICE_TABLE(pci, atiixp);
  MODULE_VERSION(DRV_VERSION);