Blame view

drivers/ata/pata_triflex.c 6.43 KB
669a5db41   Jeff Garzik   [libata] Add a bu...
1
2
3
  /*
   * pata_triflex.c 	- Compaq PATA for new ATA layer
   *			  (C) 2005 Red Hat Inc
ab7716300   Alan Cox   ata: Switch all m...
4
   *			  Alan Cox <alan@lxorguk.ukuu.org.uk>
669a5db41   Jeff Garzik   [libata] Add a bu...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
   *
   * based upon
   *
   * triflex.c
   *
   * IDE Chipset driver for the Compaq TriFlex IDE controller.
   *
   * Known to work with the Compaq Workstation 5x00 series.
   *
   * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
   * Author: Torben Mathiasen <torben.mathiasen@hp.com>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   *
   * Loosely based on the piix & svwks drivers.
   *
   * Documentation:
25985edce   Lucas De Marchi   Fix common misspe...
33
   *	Not publicly available.
669a5db41   Jeff Garzik   [libata] Add a bu...
34
35
36
37
38
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/pci.h>
669a5db41   Jeff Garzik   [libata] Add a bu...
39
40
41
42
43
44
  #include <linux/blkdev.h>
  #include <linux/delay.h>
  #include <scsi/scsi_host.h>
  #include <linux/libata.h>
  
  #define DRV_NAME "pata_triflex"
a0fcdc025   Jeff Garzik   [libata] Update s...
45
  #define DRV_VERSION "0.2.8"
669a5db41   Jeff Garzik   [libata] Add a bu...
46
47
  
  /**
c961922b7   Alan Cox   [PATCH] libata-eh...
48
   *	triflex_prereset		-	probe begin
cc0680a58   Tejun Heo   libata-link: link...
49
   *	@link: ATA link
d4b2bab4f   Tejun Heo   libata: add deadl...
50
   *	@deadline: deadline jiffies for the operation
669a5db41   Jeff Garzik   [libata] Add a bu...
51
52
53
   *
   *	Set up cable type and use generic probe init
   */
cc0680a58   Tejun Heo   libata-link: link...
54
  static int triflex_prereset(struct ata_link *link, unsigned long deadline)
669a5db41   Jeff Garzik   [libata] Add a bu...
55
56
57
58
59
  {
  	static const struct pci_bits triflex_enable_bits[] = {
  		{ 0x80, 1, 0x01, 0x01 },
  		{ 0x80, 1, 0x02, 0x02 }
  	};
cc0680a58   Tejun Heo   libata-link: link...
60
  	struct ata_port *ap = link->ap;
669a5db41   Jeff Garzik   [libata] Add a bu...
61
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
85cd7251b   Jeff Garzik   [libata #pata-dri...
62

c961922b7   Alan Cox   [PATCH] libata-eh...
63
64
  	if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
  		return -ENOENT;
d4b2bab4f   Tejun Heo   libata: add deadl...
65

9363c3825   Tejun Heo   libata: rename SF...
66
  	return ata_sff_prereset(link, deadline);
669a5db41   Jeff Garzik   [libata] Add a bu...
67
  }
669a5db41   Jeff Garzik   [libata] Add a bu...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  /**
   *	triflex_load_timing		-	timing configuration
   *	@ap: ATA interface
   *	@adev: Device on the bus
   *	@speed: speed to configure
   *
   *	The Triflex has one set of timings per device per channel. This
   *	means we must do some switching. As the PIO and DMA timings don't
   *	match we have to do some reloading unlike PIIX devices where tuning
   *	tricks can avoid it.
   */
  
  static void triflex_load_timing(struct ata_port *ap, struct ata_device *adev, int speed)
  {
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  	u32 timing = 0;
  	u32 triflex_timing, old_triflex_timing;
  	int channel_offset = ap->port_no ? 0x74: 0x70;
  	unsigned int is_slave	= (adev->devno != 0);
  
  
  	pci_read_config_dword(pdev, channel_offset, &old_triflex_timing);
  	triflex_timing = old_triflex_timing;
  
  	switch(speed)
  	{
  		case XFER_MW_DMA_2:
  			timing = 0x0103;break;
  		case XFER_MW_DMA_1:
  			timing = 0x0203;break;
  		case XFER_MW_DMA_0:
  			timing = 0x0808;break;
  		case XFER_SW_DMA_2:
  		case XFER_SW_DMA_1:
  		case XFER_SW_DMA_0:
  			timing = 0x0F0F;break;
  		case XFER_PIO_4:
  			timing = 0x0202;break;
  		case XFER_PIO_3:
  			timing = 0x0204;break;
  		case XFER_PIO_2:
  			timing = 0x0404;break;
  		case XFER_PIO_1:
  			timing = 0x0508;break;
  		case XFER_PIO_0:
  			timing = 0x0808;break;
  		default:
  			BUG();
  	}
  	triflex_timing &= ~ (0xFFFF << (16 * is_slave));
  	triflex_timing |= (timing << (16 * is_slave));
  
  	if (triflex_timing != old_triflex_timing)
  		pci_write_config_dword(pdev, channel_offset, triflex_timing);
  }
  
  /**
   *	triflex_set_piomode	-	set initial PIO mode data
   *	@ap: ATA interface
   *	@adev: ATA device
   *
   *	Use the timing loader to set up the PIO mode. We have to do this
   *	because DMA start/stop will only be called once DMA occurs. If there
   *	has been no DMA then the PIO timings are still needed.
   */
  static void triflex_set_piomode(struct ata_port *ap, struct ata_device *adev)
  {
  	triflex_load_timing(ap, adev, adev->pio_mode);
  }
  
  /**
   *	triflex_dma_start	-	DMA start callback
   *	@qc: Command in progress
   *
   *	Usually drivers set the DMA timing at the point the set_dmamode call
   *	is made. Triflex however requires we load new timings on the
   *	transition or keep matching PIO/DMA pairs (ie MWDMA2/PIO4 etc).
   *	We load the DMA timings just before starting DMA and then restore
   *	the PIO timing when the DMA is finished.
   */
  
  static void triflex_bmdma_start(struct ata_queued_cmd *qc)
  {
  	triflex_load_timing(qc->ap, qc->dev, qc->dev->dma_mode);
  	ata_bmdma_start(qc);
  }
  
  /**
   *	triflex_dma_stop	-	DMA stop callback
   *	@ap: ATA interface
   *	@adev: ATA device
   *
   *	We loaded new timings in dma_start, as a result we need to restore
   *	the PIO timings in dma_stop so that the next command issue gets the
   *	right clock values.
   */
  
  static void triflex_bmdma_stop(struct ata_queued_cmd *qc)
  {
  	ata_bmdma_stop(qc);
  	triflex_load_timing(qc->ap, qc->dev, qc->dev->pio_mode);
  }
  
  static struct scsi_host_template triflex_sht = {
68d1d07b5   Tejun Heo   libata: implement...
172
  	ATA_BMDMA_SHT(DRV_NAME),
669a5db41   Jeff Garzik   [libata] Add a bu...
173
174
175
  };
  
  static struct ata_port_operations triflex_port_ops = {
029cfd6b7   Tejun Heo   libata: implement...
176
  	.inherits	= &ata_bmdma_port_ops,
669a5db41   Jeff Garzik   [libata] Add a bu...
177
178
  	.bmdma_start 	= triflex_bmdma_start,
  	.bmdma_stop	= triflex_bmdma_stop,
029cfd6b7   Tejun Heo   libata: implement...
179
180
  	.cable_detect	= ata_cable_40wire,
  	.set_piomode	= triflex_set_piomode,
a1efdaba2   Tejun Heo   libata: make rese...
181
  	.prereset	= triflex_prereset,
669a5db41   Jeff Garzik   [libata] Add a bu...
182
183
184
185
  };
  
  static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
  {
1626aeb88   Tejun Heo   libata: clean up ...
186
  	static const struct ata_port_info info = {
1d2808fd3   Jeff Garzik   [libata] PATA dri...
187
  		.flags = ATA_FLAG_SLAVE_POSS,
14bdef982   Erik Inge Bolsø   [libata] convert ...
188
189
  		.pio_mask = ATA_PIO4,
  		.mwdma_mask = ATA_MWDMA2,
669a5db41   Jeff Garzik   [libata] Add a bu...
190
191
  		.port_ops = &triflex_port_ops
  	};
1626aeb88   Tejun Heo   libata: clean up ...
192
  	const struct ata_port_info *ppi[] = { &info, NULL };
669a5db41   Jeff Garzik   [libata] Add a bu...
193

06296a1e6   Joe Perches   ata: Add and use ...
194
  	ata_print_version_once(&dev->dev, DRV_VERSION);
669a5db41   Jeff Garzik   [libata] Add a bu...
195

1c5afdf7a   Tejun Heo   libata-sff: separ...
196
  	return ata_pci_bmdma_init_one(dev, ppi, &triflex_sht, NULL, 0);
669a5db41   Jeff Garzik   [libata] Add a bu...
197
198
199
  }
  
  static const struct pci_device_id triflex[] = {
2d2744fc8   Jeff Garzik   [libata] PCI ID t...
200
201
202
  	{ PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), },
  
  	{ },
669a5db41   Jeff Garzik   [libata] Add a bu...
203
  };
58eb8cd56   Bartlomiej Zolnierkiewicz   ata: use CONFIG_P...
204
  #ifdef CONFIG_PM_SLEEP
bfeec8ca1   Mikulas Patocka   ATA: Don't powerd...
205
206
  static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
  {
0a86e1c85   Jingoo Han   ata: use pci_get_...
207
  	struct ata_host *host = pci_get_drvdata(pdev);
bfeec8ca1   Mikulas Patocka   ATA: Don't powerd...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  	int rc = 0;
  
  	rc = ata_host_suspend(host, mesg);
  	if (rc)
  		return rc;
  
  	/*
  	 * We must not disable or powerdown the device.
  	 * APM bios refuses to suspend if IDE is not accessible.
  	 */
  	pci_save_state(pdev);
  
  	return 0;
  }
  
  #endif
669a5db41   Jeff Garzik   [libata] Add a bu...
224
  static struct pci_driver triflex_pci_driver = {
2d2744fc8   Jeff Garzik   [libata] PCI ID t...
225
  	.name 		= DRV_NAME,
669a5db41   Jeff Garzik   [libata] Add a bu...
226
227
  	.id_table	= triflex,
  	.probe 		= triflex_init_one,
30ced0f0d   Alan Cox   [PATCH] PATA liba...
228
  	.remove		= ata_pci_remove_one,
58eb8cd56   Bartlomiej Zolnierkiewicz   ata: use CONFIG_P...
229
  #ifdef CONFIG_PM_SLEEP
bfeec8ca1   Mikulas Patocka   ATA: Don't powerd...
230
  	.suspend	= triflex_ata_pci_device_suspend,
30ced0f0d   Alan Cox   [PATCH] PATA liba...
231
  	.resume		= ata_pci_device_resume,
438ac6d5e   Tejun Heo   libata: add missi...
232
  #endif
669a5db41   Jeff Garzik   [libata] Add a bu...
233
  };
2fc75da0c   Axel Lin   ata: use module_p...
234
  module_pci_driver(triflex_pci_driver);
669a5db41   Jeff Garzik   [libata] Add a bu...
235

669a5db41   Jeff Garzik   [libata] Add a bu...
236
237
238
239
240
  MODULE_AUTHOR("Alan Cox");
  MODULE_DESCRIPTION("low-level driver for Compaq Triflex");
  MODULE_LICENSE("GPL");
  MODULE_DEVICE_TABLE(pci, triflex);
  MODULE_VERSION(DRV_VERSION);