blob: 9ad1531b60349bc5d11742372ee9fa943f2a6b00 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +01002 * linux/drivers/ide/pci/hpt366.c Version 0.52 Jun 07, 2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
5 * Portions Copyright (C) 2001 Sun Microsystems, Inc.
6 * Portions Copyright (C) 2003 Red Hat Inc
Sergei Shtylyov836c0062006-12-13 00:35:47 -08007 * Portions Copyright (C) 2005-2006 MontaVista Software, Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
9 * Thanks to HighPoint Technologies for their assistance, and hardware.
10 * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
11 * donation of an ABit BP6 mainboard, processor, and memory acellerated
12 * development and support.
13 *
Alan Coxb39b01f2005-06-27 15:24:27 -070014 *
Sergei Shtylyov836c0062006-12-13 00:35:47 -080015 * HighPoint has its own drivers (open source except for the RAID part)
16 * available from http://www.highpoint-tech.com/BIOS%20+%20Driver/.
17 * This may be useful to anyone wanting to work on this driver, however do not
18 * trust them too much since the code tends to become less and less meaningful
19 * as the time passes... :-/
Alan Coxb39b01f2005-06-27 15:24:27 -070020 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 * Note that final HPT370 support was done by force extraction of GPL.
22 *
23 * - add function for getting/setting power status of drive
24 * - the HPT370's state machine can get confused. reset it before each dma
25 * xfer to prevent that from happening.
26 * - reset state engine whenever we get an error.
27 * - check for busmaster state at end of dma.
28 * - use new highpoint timings.
29 * - detect bus speed using highpoint register.
30 * - use pll if we don't have a clock table. added a 66MHz table that's
31 * just 2x the 33MHz table.
32 * - removed turnaround. NOTE: we never want to switch between pll and
33 * pci clocks as the chip can glitch in those cases. the highpoint
34 * approved workaround slows everything down too much to be useful. in
35 * addition, we would have to serialize access to each chip.
36 * Adrian Sun <a.sun@sun.com>
37 *
38 * add drive timings for 66MHz PCI bus,
39 * fix ATA Cable signal detection, fix incorrect /proc info
40 * add /proc display for per-drive PIO/DMA/UDMA mode and
41 * per-channel ATA-33/66 Cable detect.
42 * Duncan Laurie <void@sun.com>
43 *
44 * fixup /proc output for multiple controllers
45 * Tim Hockin <thockin@sun.com>
46 *
47 * On hpt366:
48 * Reset the hpt366 on error, reset on dma
49 * Fix disabling Fast Interrupt hpt366.
50 * Mike Waychison <crlf@sun.com>
51 *
52 * Added support for 372N clocking and clock switching. The 372N needs
53 * different clocks on read/write. This requires overloading rw_disk and
54 * other deeply crazy things. Thanks to <http://www.hoerstreich.de> for
55 * keeping me sane.
56 * Alan Cox <alan@redhat.com>
57 *
Sergei Shtylyov836c0062006-12-13 00:35:47 -080058 * - fix the clock turnaround code: it was writing to the wrong ports when
59 * called for the secondary channel, caching the current clock mode per-
60 * channel caused the cached register value to get out of sync with the
61 * actual one, the channels weren't serialized, the turnaround shouldn't
62 * be done on 66 MHz PCI bus
63 * - avoid calibrating PLL twice as the second time results in a wrong PCI
64 * frequency and thus in the wrong timings for the secondary channel
Sergei Shtylyove139b0b2007-02-07 18:17:37 +010065 * - disable UltraATA/133 for HPT372 and UltraATA/100 for HPT370 by default
66 * as the ATA clock being used does not allow for this speed anyway
Sergei Shtylyov836c0062006-12-13 00:35:47 -080067 * - add support for HPT302N and HPT371N clocking (the same as for HPT372N)
68 * - HPT371/N are single channel chips, so avoid touching the primary channel
69 * which exists only virtually (there's no pins for it)
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -080070 * - fix/remove bad/unused timing tables and use one set of tables for the whole
71 * HPT37x chip family; save space by introducing the separate transfer mode
72 * table in which the mode lookup is done
Sergei Shtylyov26c068d2006-12-13 00:35:52 -080073 * - use f_CNT value saved by the HighPoint BIOS as reading it directly gives
74 * the wrong PCI frequency since DPLL has already been calibrated by BIOS
Sergei Shtylyov33b18a62006-12-13 00:35:50 -080075 * - fix the hotswap code: it caused RESET- to glitch when tristating the bus,
76 * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -080077 * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
78 * they tamper with its fields
Sergei Shtylyov90778572007-02-07 18:17:51 +010079 * - prefix the driver startup messages with the real chip name
80 * - claim the extra 240 bytes of I/O space for all chips
Sergei Shtylyove139b0b2007-02-07 18:17:37 +010081 * - optimize the rate masking/filtering and the drive list lookup code
Sergei Shtylyovb4586712007-02-07 18:17:54 +010082 * - use pci_get_slot() to get to the function 1 of HPT36x/374
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +010083 * - cache the channel's MCRs' offset; only touch the relevant MCR when detecting
84 * the cable type on HPT374's function 1
85 * - rename all the register related variables consistently
Sergei Shtylyov26ccb802007-02-07 18:18:11 +010086 * - move the interrupt twiddling code from the speedproc handlers into the
87 * init_hwif handler, also grouping all the DMA related code together there;
88 * simplify the init_chipset handler
89 * - merge two HPT37x speedproc handlers and fix the PIO timing register mask
90 * there; make HPT36x speedproc handler look the same way as the HPT37x one
91 * - fix the tuneproc handler to always set the PIO mode requested, not the
92 * best possible one
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +010093 * - clean up DMA timeout handling for HPT370
Sergei Shtylyov836c0062006-12-13 00:35:47 -080094 * <source@mvista.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 */
96
Linus Torvalds1da177e2005-04-16 15:20:36 -070097#include <linux/types.h>
98#include <linux/module.h>
99#include <linux/kernel.h>
100#include <linux/delay.h>
101#include <linux/timer.h>
102#include <linux/mm.h>
103#include <linux/ioport.h>
104#include <linux/blkdev.h>
105#include <linux/hdreg.h>
106
107#include <linux/interrupt.h>
108#include <linux/pci.h>
109#include <linux/init.h>
110#include <linux/ide.h>
111
112#include <asm/uaccess.h>
113#include <asm/io.h>
114#include <asm/irq.h>
115
116/* various tuning parameters */
117#define HPT_RESET_STATE_ENGINE
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800118#undef HPT_DELAY_INTERRUPT
119#define HPT_SERIALIZE_IO 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
121static const char *quirk_drives[] = {
122 "QUANTUM FIREBALLlct08 08",
123 "QUANTUM FIREBALLP KA6.4",
124 "QUANTUM FIREBALLP LM20.4",
125 "QUANTUM FIREBALLP LM20.5",
126 NULL
127};
128
129static const char *bad_ata100_5[] = {
130 "IBM-DTLA-307075",
131 "IBM-DTLA-307060",
132 "IBM-DTLA-307045",
133 "IBM-DTLA-307030",
134 "IBM-DTLA-307020",
135 "IBM-DTLA-307015",
136 "IBM-DTLA-305040",
137 "IBM-DTLA-305030",
138 "IBM-DTLA-305020",
139 "IC35L010AVER07-0",
140 "IC35L020AVER07-0",
141 "IC35L030AVER07-0",
142 "IC35L040AVER07-0",
143 "IC35L060AVER07-0",
144 "WDC AC310200R",
145 NULL
146};
147
148static const char *bad_ata66_4[] = {
149 "IBM-DTLA-307075",
150 "IBM-DTLA-307060",
151 "IBM-DTLA-307045",
152 "IBM-DTLA-307030",
153 "IBM-DTLA-307020",
154 "IBM-DTLA-307015",
155 "IBM-DTLA-305040",
156 "IBM-DTLA-305030",
157 "IBM-DTLA-305020",
158 "IC35L010AVER07-0",
159 "IC35L020AVER07-0",
160 "IC35L030AVER07-0",
161 "IC35L040AVER07-0",
162 "IC35L060AVER07-0",
163 "WDC AC310200R",
164 NULL
165};
166
167static const char *bad_ata66_3[] = {
168 "WDC AC310200R",
169 NULL
170};
171
172static const char *bad_ata33[] = {
173 "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
174 "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
175 "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
176 "Maxtor 90510D4",
177 "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
178 "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
179 "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
180 NULL
181};
182
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800183static u8 xfer_speeds[] = {
184 XFER_UDMA_6,
185 XFER_UDMA_5,
186 XFER_UDMA_4,
187 XFER_UDMA_3,
188 XFER_UDMA_2,
189 XFER_UDMA_1,
190 XFER_UDMA_0,
191
192 XFER_MW_DMA_2,
193 XFER_MW_DMA_1,
194 XFER_MW_DMA_0,
195
196 XFER_PIO_4,
197 XFER_PIO_3,
198 XFER_PIO_2,
199 XFER_PIO_1,
200 XFER_PIO_0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201};
202
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800203/* Key for bus clock timings
204 * 36x 37x
205 * bits bits
206 * 0:3 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
207 * cycles = value + 1
208 * 4:7 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
209 * cycles = value + 1
210 * 8:11 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
211 * register access.
212 * 12:15 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
213 * register access.
214 * 16:18 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
215 * - 21 CLK frequency: 0=ATA clock, 1=dual ATA clock.
216 * 19:21 22:24 pre_high_time. Time to initialize the 1st cycle for PIO and
217 * MW DMA xfer.
218 * 22:24 25:27 cmd_pre_high_time. Time to initialize the 1st PIO cycle for
219 * task file register access.
220 * 28 28 UDMA enable.
221 * 29 29 DMA enable.
222 * 30 30 PIO MST enable. If set, the chip is in bus master mode during
223 * PIO xfer.
224 * 31 31 FIFO enable.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800227static u32 forty_base_hpt36x[] = {
228 /* XFER_UDMA_6 */ 0x900fd943,
229 /* XFER_UDMA_5 */ 0x900fd943,
230 /* XFER_UDMA_4 */ 0x900fd943,
231 /* XFER_UDMA_3 */ 0x900ad943,
232 /* XFER_UDMA_2 */ 0x900bd943,
233 /* XFER_UDMA_1 */ 0x9008d943,
234 /* XFER_UDMA_0 */ 0x9008d943,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800236 /* XFER_MW_DMA_2 */ 0xa008d943,
237 /* XFER_MW_DMA_1 */ 0xa010d955,
238 /* XFER_MW_DMA_0 */ 0xa010d9fc,
239
240 /* XFER_PIO_4 */ 0xc008d963,
241 /* XFER_PIO_3 */ 0xc010d974,
242 /* XFER_PIO_2 */ 0xc010d997,
243 /* XFER_PIO_1 */ 0xc010d9c7,
244 /* XFER_PIO_0 */ 0xc018d9d9
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245};
246
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800247static u32 thirty_three_base_hpt36x[] = {
248 /* XFER_UDMA_6 */ 0x90c9a731,
249 /* XFER_UDMA_5 */ 0x90c9a731,
250 /* XFER_UDMA_4 */ 0x90c9a731,
251 /* XFER_UDMA_3 */ 0x90cfa731,
252 /* XFER_UDMA_2 */ 0x90caa731,
253 /* XFER_UDMA_1 */ 0x90cba731,
254 /* XFER_UDMA_0 */ 0x90c8a731,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800256 /* XFER_MW_DMA_2 */ 0xa0c8a731,
257 /* XFER_MW_DMA_1 */ 0xa0c8a732, /* 0xa0c8a733 */
258 /* XFER_MW_DMA_0 */ 0xa0c8a797,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800260 /* XFER_PIO_4 */ 0xc0c8a731,
261 /* XFER_PIO_3 */ 0xc0c8a742,
262 /* XFER_PIO_2 */ 0xc0d0a753,
263 /* XFER_PIO_1 */ 0xc0d0a7a3, /* 0xc0d0a793 */
264 /* XFER_PIO_0 */ 0xc0d0a7aa /* 0xc0d0a7a7 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265};
266
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800267static u32 twenty_five_base_hpt36x[] = {
268 /* XFER_UDMA_6 */ 0x90c98521,
269 /* XFER_UDMA_5 */ 0x90c98521,
270 /* XFER_UDMA_4 */ 0x90c98521,
271 /* XFER_UDMA_3 */ 0x90cf8521,
272 /* XFER_UDMA_2 */ 0x90cf8521,
273 /* XFER_UDMA_1 */ 0x90cb8521,
274 /* XFER_UDMA_0 */ 0x90cb8521,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800276 /* XFER_MW_DMA_2 */ 0xa0ca8521,
277 /* XFER_MW_DMA_1 */ 0xa0ca8532,
278 /* XFER_MW_DMA_0 */ 0xa0ca8575,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800280 /* XFER_PIO_4 */ 0xc0ca8521,
281 /* XFER_PIO_3 */ 0xc0ca8532,
282 /* XFER_PIO_2 */ 0xc0ca8542,
283 /* XFER_PIO_1 */ 0xc0d08572,
284 /* XFER_PIO_0 */ 0xc0d08585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285};
286
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800287static u32 thirty_three_base_hpt37x[] = {
288 /* XFER_UDMA_6 */ 0x12446231, /* 0x12646231 ?? */
289 /* XFER_UDMA_5 */ 0x12446231,
290 /* XFER_UDMA_4 */ 0x12446231,
291 /* XFER_UDMA_3 */ 0x126c6231,
292 /* XFER_UDMA_2 */ 0x12486231,
293 /* XFER_UDMA_1 */ 0x124c6233,
294 /* XFER_UDMA_0 */ 0x12506297,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800296 /* XFER_MW_DMA_2 */ 0x22406c31,
297 /* XFER_MW_DMA_1 */ 0x22406c33,
298 /* XFER_MW_DMA_0 */ 0x22406c97,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800300 /* XFER_PIO_4 */ 0x06414e31,
301 /* XFER_PIO_3 */ 0x06414e42,
302 /* XFER_PIO_2 */ 0x06414e53,
303 /* XFER_PIO_1 */ 0x06814e93,
304 /* XFER_PIO_0 */ 0x06814ea7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305};
306
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800307static u32 fifty_base_hpt37x[] = {
308 /* XFER_UDMA_6 */ 0x12848242,
309 /* XFER_UDMA_5 */ 0x12848242,
310 /* XFER_UDMA_4 */ 0x12ac8242,
311 /* XFER_UDMA_3 */ 0x128c8242,
312 /* XFER_UDMA_2 */ 0x120c8242,
313 /* XFER_UDMA_1 */ 0x12148254,
314 /* XFER_UDMA_0 */ 0x121882ea,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800316 /* XFER_MW_DMA_2 */ 0x22808242,
317 /* XFER_MW_DMA_1 */ 0x22808254,
318 /* XFER_MW_DMA_0 */ 0x228082ea,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800320 /* XFER_PIO_4 */ 0x0a81f442,
321 /* XFER_PIO_3 */ 0x0a81f443,
322 /* XFER_PIO_2 */ 0x0a81f454,
323 /* XFER_PIO_1 */ 0x0ac1f465,
324 /* XFER_PIO_0 */ 0x0ac1f48a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325};
326
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800327static u32 sixty_six_base_hpt37x[] = {
328 /* XFER_UDMA_6 */ 0x1c869c62,
329 /* XFER_UDMA_5 */ 0x1cae9c62, /* 0x1c8a9c62 */
330 /* XFER_UDMA_4 */ 0x1c8a9c62,
331 /* XFER_UDMA_3 */ 0x1c8e9c62,
332 /* XFER_UDMA_2 */ 0x1c929c62,
333 /* XFER_UDMA_1 */ 0x1c9a9c62,
334 /* XFER_UDMA_0 */ 0x1c829c62,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800336 /* XFER_MW_DMA_2 */ 0x2c829c62,
337 /* XFER_MW_DMA_1 */ 0x2c829c66,
338 /* XFER_MW_DMA_0 */ 0x2c829d2e,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800340 /* XFER_PIO_4 */ 0x0c829c62,
341 /* XFER_PIO_3 */ 0x0c829c84,
342 /* XFER_PIO_2 */ 0x0c829ca6,
343 /* XFER_PIO_1 */ 0x0d029d26,
344 /* XFER_PIO_0 */ 0x0d029d5e
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345};
346
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347#define HPT366_DEBUG_DRIVE_INFO 0
348#define HPT374_ALLOW_ATA133_6 0
349#define HPT371_ALLOW_ATA133_6 0
350#define HPT302_ALLOW_ATA133_6 0
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800351#define HPT372_ALLOW_ATA133_6 0
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100352#define HPT370_ALLOW_ATA100_5 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353#define HPT366_ALLOW_ATA66_4 1
354#define HPT366_ALLOW_ATA66_3 1
355#define HPT366_MAX_DEVS 8
356
357#define F_LOW_PCI_33 0x23
358#define F_LOW_PCI_40 0x29
359#define F_LOW_PCI_50 0x2d
360#define F_LOW_PCI_66 0x42
361
Alan Coxb39b01f2005-06-27 15:24:27 -0700362/*
363 * Hold all the highpoint quirks and revision information in one
364 * place.
365 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Alan Coxb39b01f2005-06-27 15:24:27 -0700367struct hpt_info
368{
369 u8 max_mode; /* Speeds allowed */
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100370 u8 revision; /* Chipset revision */
371 u8 flags; /* Chipset properties */
Alan Coxb39b01f2005-06-27 15:24:27 -0700372#define PLL_MODE 1
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800373#define IS_3xxN 2
374#define PCI_66MHZ 4
Alan Coxb39b01f2005-06-27 15:24:27 -0700375 /* Speed table */
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800376 u32 *speed;
Alan Coxb39b01f2005-06-27 15:24:27 -0700377};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Alan Coxb39b01f2005-06-27 15:24:27 -0700379/*
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100380 * This wants fixing so that we do everything not by revision
Alan Coxb39b01f2005-06-27 15:24:27 -0700381 * (which breaks on the newest chips) but by creating an
382 * enumeration of chip variants and using that
383 */
384
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100385static __devinit u8 hpt_revision(struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100387 u8 rev = 0;
388
389 pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
391 switch(dev->device) {
392 /* Remap new 372N onto 372 */
393 case PCI_DEVICE_ID_TTI_HPT372N:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100394 rev = PCI_DEVICE_ID_TTI_HPT372;
395 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 case PCI_DEVICE_ID_TTI_HPT374:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100397 rev = PCI_DEVICE_ID_TTI_HPT374;
398 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 case PCI_DEVICE_ID_TTI_HPT371:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100400 rev = PCI_DEVICE_ID_TTI_HPT371;
401 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 case PCI_DEVICE_ID_TTI_HPT302:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100403 rev = PCI_DEVICE_ID_TTI_HPT302;
404 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 case PCI_DEVICE_ID_TTI_HPT372:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100406 rev = PCI_DEVICE_ID_TTI_HPT372;
407 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 default:
409 break;
410 }
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100411 return rev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100414static int check_in_drive_list(ide_drive_t *drive, const char **list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100416 struct hd_driveid *id = drive->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100418 while (*list)
419 if (!strcmp(*list++,id->model))
420 return 1;
421 return 0;
422}
Alan Coxb39b01f2005-06-27 15:24:27 -0700423
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100424static u8 hpt3xx_ratemask(ide_drive_t *drive)
425{
426 struct hpt_info *info = ide_get_hwifdata(HWIF(drive));
427 u8 mode = info->max_mode;
428
Alan Coxb39b01f2005-06-27 15:24:27 -0700429 if (!eighty_ninty_three(drive) && mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 mode = min(mode, (u8)1);
431 return mode;
432}
433
434/*
435 * Note for the future; the SATA hpt37x we must set
436 * either PIO or UDMA modes 0,4,5
437 */
438
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100439static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100441 struct hpt_info *info = ide_get_hwifdata(HWIF(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 u8 mode = hpt3xx_ratemask(drive);
443
444 if (drive->media != ide_disk)
445 return min(speed, (u8)XFER_PIO_4);
446
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100447 switch (mode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 case 0x04:
449 speed = min(speed, (u8)XFER_UDMA_6);
450 break;
451 case 0x03:
452 speed = min(speed, (u8)XFER_UDMA_5);
Alan Coxb39b01f2005-06-27 15:24:27 -0700453 if (info->revision >= 5)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 break;
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100455 if (!check_in_drive_list(drive, bad_ata100_5))
456 goto check_bad_ata33;
457 /* fall thru */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 case 0x02:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100459 speed = min_t(u8, speed, XFER_UDMA_4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 /*
461 * CHECK ME, Does this need to be set to 5 ??
462 */
Alan Coxb39b01f2005-06-27 15:24:27 -0700463 if (info->revision >= 3)
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100464 goto check_bad_ata33;
465 if (HPT366_ALLOW_ATA66_4 &&
466 !check_in_drive_list(drive, bad_ata66_4))
467 goto check_bad_ata33;
468
Andrew Mortonf36702b2007-02-07 18:17:37 +0100469 speed = min_t(u8, speed, XFER_UDMA_3);
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100470 if (HPT366_ALLOW_ATA66_3 &&
471 !check_in_drive_list(drive, bad_ata66_3))
472 goto check_bad_ata33;
473 /* fall thru */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 case 0x01:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100475 speed = min_t(u8, speed, XFER_UDMA_2);
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100476
477 check_bad_ata33:
478 if (info->revision >= 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 break;
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100480 if (!check_in_drive_list(drive, bad_ata33))
481 break;
482 /* fall thru */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 case 0x00:
484 default:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100485 speed = min_t(u8, speed, XFER_MW_DMA_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 break;
487 }
488 return speed;
489}
490
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800491static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800493 int i;
494
495 /*
496 * Lookup the transfer mode table to get the index into
497 * the timing table.
498 *
499 * NOTE: For XFER_PIO_SLOW, PIO mode 0 timings will be used.
500 */
501 for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
502 if (xfer_speeds[i] == speed)
503 break;
504 return chipset_table[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505}
506
507static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
508{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100509 ide_hwif_t *hwif = HWIF(drive);
510 struct pci_dev *dev = hwif->pci_dev;
511 struct hpt_info *info = ide_get_hwifdata (hwif);
512 u8 speed = hpt3xx_ratefilter(drive, xferspeed);
513 u8 itr_addr = drive->dn ? 0x44 : 0x40;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100514 u32 itr_mask = (speed < XFER_MW_DMA_0) ? 0x30070000 : 0xc0000000;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100515 u32 new_itr = pci_bus_clock_list(speed, info->speed);
516 u32 old_itr = 0;
Alan Coxb39b01f2005-06-27 15:24:27 -0700517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 /*
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100519 * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
520 * to avoid problems handling I/O errors later
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100522 pci_read_config_dword(dev, itr_addr, &old_itr);
523 new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
524 new_itr &= ~0xc0000000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100526 pci_write_config_dword(dev, itr_addr, new_itr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
528 return ide_config_drive_speed(drive, speed);
529}
530
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100531static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100533 ide_hwif_t *hwif = HWIF(drive);
534 struct pci_dev *dev = hwif->pci_dev;
535 struct hpt_info *info = ide_get_hwifdata (hwif);
536 u8 speed = hpt3xx_ratefilter(drive, xferspeed);
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100537 u8 itr_addr = 0x40 + (drive->dn * 4);
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100538 u32 itr_mask = (speed < XFER_MW_DMA_0) ? 0x303c0000 : 0xc0000000;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100539 u32 new_itr = pci_bus_clock_list(speed, info->speed);
540 u32 old_itr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100542 pci_read_config_dword(dev, itr_addr, &old_itr);
543 new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Alan Coxb39b01f2005-06-27 15:24:27 -0700545 if (speed < XFER_MW_DMA_0)
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100546 new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
547 pci_write_config_dword(dev, itr_addr, new_itr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 return ide_config_drive_speed(drive, speed);
550}
551
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100552static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100554 ide_hwif_t *hwif = HWIF(drive);
Alan Coxb39b01f2005-06-27 15:24:27 -0700555 struct hpt_info *info = ide_get_hwifdata(hwif);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100557 if (info->revision >= 3)
558 return hpt37x_tune_chipset(drive, speed);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 else /* hpt368: hpt_minimum_revision(dev, 2) */
560 return hpt36x_tune_chipset(drive, speed);
561}
562
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100563static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100565 pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
566 (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567}
568
569/*
570 * This allows the configuration of ide_pci chipset registers
571 * for cards that learn about the drive's UDMA, DMA, PIO capabilities
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100572 * after the drive is reported by the OS. Initially designed for
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
574 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 */
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100576static int config_chipset_for_dma(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100579 ide_hwif_t *hwif = HWIF(drive);
Alan Coxb39b01f2005-06-27 15:24:27 -0700580 struct hpt_info *info = ide_get_hwifdata(hwif);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Alan Coxb39b01f2005-06-27 15:24:27 -0700582 if (!speed)
583 return 0;
584
585 /* If we don't have any timings we can't do a lot */
586 if (info->speed == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 return 0;
588
589 (void) hpt3xx_tune_chipset(drive, speed);
590 return ide_dma_enable(drive);
591}
592
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100593static int hpt3xx_quirkproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100595 struct hd_driveid *id = drive->id;
596 const char **list = quirk_drives;
597
598 while (*list)
599 if (strstr(id->model, *list++))
600 return 1;
601 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602}
603
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100604static void hpt3xx_intrproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100606 ide_hwif_t *hwif = HWIF(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 if (drive->quirk_list)
609 return;
610 /* drives in the quirk_list may not like intr setups/cleanups */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100611 hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612}
613
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100614static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100616 ide_hwif_t *hwif = HWIF(drive);
617 struct pci_dev *dev = hwif->pci_dev;
618 struct hpt_info *info = ide_get_hwifdata(hwif);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
620 if (drive->quirk_list) {
Alan Coxb39b01f2005-06-27 15:24:27 -0700621 if (info->revision >= 3) {
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100622 u8 scr1 = 0;
623
624 pci_read_config_byte(dev, 0x5a, &scr1);
625 if (((scr1 & 0x10) >> 4) != mask) {
626 if (mask)
627 scr1 |= 0x10;
628 else
629 scr1 &= ~0x10;
630 pci_write_config_byte(dev, 0x5a, scr1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 }
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100632 } else {
633 if (mask)
634 disable_irq(hwif->irq);
635 else
636 enable_irq (hwif->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 }
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100638 } else
639 hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
640 IDE_CONTROL_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641}
642
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100643static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100645 ide_hwif_t *hwif = HWIF(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 struct hd_driveid *id = drive->id;
647
648 drive->init_speed = 0;
649
Alan Coxb39b01f2005-06-27 15:24:27 -0700650 if ((id->capability & 1) && drive->autodma) {
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100651 if (ide_use_dma(drive) && config_chipset_for_dma(drive))
652 return hwif->ide_dma_on(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 goto fast_ata_pio;
655
656 } else if ((id->capability & 8) || (id->field_valid & 2)) {
657fast_ata_pio:
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100658 hpt3xx_tune_drive(drive, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 return hwif->ide_dma_off_quietly(drive);
660 }
661 /* IORDY not supported */
662 return 0;
663}
664
665/*
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100666 * This is specific to the HPT366 UDMA chipset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 * by HighPoint|Triones Technologies, Inc.
668 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100669static int hpt366_ide_dma_lostirq(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100671 struct pci_dev *dev = HWIF(drive)->pci_dev;
672 u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100674 pci_read_config_byte(dev, 0x50, &mcr1);
675 pci_read_config_byte(dev, 0x52, &mcr3);
676 pci_read_config_byte(dev, 0x5a, &scr1);
677 printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
678 drive->name, __FUNCTION__, mcr1, mcr3, scr1);
679 if (scr1 & 0x10)
680 pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return __ide_dma_lostirq(drive);
682}
683
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100684static void hpt370_clear_engine(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100686 ide_hwif_t *hwif = HWIF(drive);
687
688 pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 udelay(10);
690}
691
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100692static void hpt370_irq_timeout(ide_drive_t *drive)
693{
694 ide_hwif_t *hwif = HWIF(drive);
695 u16 bfifo = 0;
696 u8 dma_cmd;
697
698 pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
699 printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
700
701 /* get DMA command mode */
702 dma_cmd = hwif->INB(hwif->dma_command);
703 /* stop DMA */
704 hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
705 hpt370_clear_engine(drive);
706}
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708static void hpt370_ide_dma_start(ide_drive_t *drive)
709{
710#ifdef HPT_RESET_STATE_ENGINE
711 hpt370_clear_engine(drive);
712#endif
713 ide_dma_start(drive);
714}
715
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100716static int hpt370_ide_dma_end(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
718 ide_hwif_t *hwif = HWIF(drive);
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100719 u8 dma_stat = hwif->INB(hwif->dma_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 if (dma_stat & 0x01) {
722 /* wait a little */
723 udelay(20);
724 dma_stat = hwif->INB(hwif->dma_status);
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100725 if (dma_stat & 0x01)
726 hpt370_irq_timeout(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return __ide_dma_end(drive);
729}
730
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100731static int hpt370_ide_dma_timeout(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732{
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100733 hpt370_irq_timeout(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 return __ide_dma_timeout(drive);
735}
736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737/* returns 1 if DMA IRQ issued, 0 otherwise */
738static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
739{
740 ide_hwif_t *hwif = HWIF(drive);
741 u16 bfifo = 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100742 u8 dma_stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100744 pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if (bfifo & 0x1FF) {
746// printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
747 return 0;
748 }
749
750 dma_stat = hwif->INB(hwif->dma_status);
751 /* return 1 if INTR asserted */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100752 if (dma_stat & 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return 1;
754
755 if (!drive->waiting_for_dma)
756 printk(KERN_WARNING "%s: (%s) called while not waiting\n",
757 drive->name, __FUNCTION__);
758 return 0;
759}
760
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100761static int hpt374_ide_dma_end(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 ide_hwif_t *hwif = HWIF(drive);
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100764 struct pci_dev *dev = hwif->pci_dev;
765 u8 mcr = 0, mcr_addr = hwif->select_data;
766 u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100768 pci_read_config_byte(dev, 0x6a, &bwsr);
769 pci_read_config_byte(dev, mcr_addr, &mcr);
770 if (bwsr & mask)
771 pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 return __ide_dma_end(drive);
773}
774
775/**
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800776 * hpt3xxn_set_clock - perform clock switching dance
777 * @hwif: hwif to switch
778 * @mode: clocking mode (0x21 for write, 0x23 otherwise)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 *
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800780 * Switch the DPLL clock on the HPT3xxN devices. This is a right mess.
781 * NOTE: avoid touching the disabled primary channel on HPT371N -- it
782 * doesn't physically exist anyway...
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800784
785static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800787 u8 mcr1, scr2 = hwif->INB(hwif->dma_master + 0x7b);
788
789 if ((scr2 & 0x7f) == mode)
790 return;
791
792 /* MISC. control register 1 has the channel enable bit... */
793 mcr1 = hwif->INB(hwif->dma_master + 0x70);
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 /* Tristate the bus */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800796 if (mcr1 & 0x04)
797 hwif->OUTB(0x80, hwif->dma_master + 0x73);
798 hwif->OUTB(0x80, hwif->dma_master + 0x77);
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 /* Switch clock and reset channels */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800801 hwif->OUTB(mode, hwif->dma_master + 0x7b);
802 hwif->OUTB(0xc0, hwif->dma_master + 0x79);
803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 /* Reset state machines */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800805 if (mcr1 & 0x04)
806 hwif->OUTB(0x37, hwif->dma_master + 0x70);
807 hwif->OUTB(0x37, hwif->dma_master + 0x74);
808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 /* Complete reset */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800810 hwif->OUTB(0x00, hwif->dma_master + 0x79);
811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 /* Reconnect channels to bus */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800813 if (mcr1 & 0x04)
814 hwif->OUTB(0x00, hwif->dma_master + 0x73);
815 hwif->OUTB(0x00, hwif->dma_master + 0x77);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816}
817
818/**
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800819 * hpt3xxn_rw_disk - prepare for I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 * @drive: drive for command
821 * @rq: block request structure
822 *
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800823 * This is called when a disk I/O is issued to HPT3xxN.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 * We need it because of the clock switching.
825 */
826
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800827static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828{
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800829 ide_hwif_t *hwif = HWIF(drive);
830 u8 wantclock = rq_data_dir(rq) ? 0x23 : 0x21;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800832 hpt3xxn_set_clock(hwif, wantclock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833}
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835/*
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800836 * Set/get power state for a drive.
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100837 * NOTE: affects both drives on each channel.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 *
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800839 * When we turn the power back on, we need to re-initialize things.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 */
841#define TRISTATE_BIT 0x8000
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800842
843static int hpt3xx_busproc(ide_drive_t *drive, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100845 ide_hwif_t *hwif = HWIF(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100847 u8 mcr_addr = hwif->select_data + 2;
848 u8 resetmask = hwif->channel ? 0x80 : 0x40;
849 u8 bsr2 = 0;
850 u16 mcr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
852 hwif->bus_state = state;
853
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800854 /* Grab the status. */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100855 pci_read_config_word(dev, mcr_addr, &mcr);
856 pci_read_config_byte(dev, 0x59, &bsr2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800858 /*
859 * Set the state. We don't set it if we don't need to do so.
860 * Make sure that the drive knows that it has failed if it's off.
861 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 switch (state) {
863 case BUSSTATE_ON:
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100864 if (!(bsr2 & resetmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 return 0;
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800866 hwif->drives[0].failures = hwif->drives[1].failures = 0;
867
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100868 pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask);
869 pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT);
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800870 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 case BUSSTATE_OFF:
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100872 if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 return 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100874 mcr &= ~TRISTATE_BIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 break;
876 case BUSSTATE_TRISTATE:
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100877 if ((bsr2 & resetmask) && (mcr & TRISTATE_BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 return 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100879 mcr |= TRISTATE_BIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 break;
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800881 default:
882 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800885 hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
886 hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
887
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100888 pci_write_config_word(dev, mcr_addr, mcr);
889 pci_write_config_byte(dev, 0x59, bsr2 | resetmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 return 0;
891}
892
Alan Coxb39b01f2005-06-27 15:24:27 -0700893static void __devinit hpt366_clocking(ide_hwif_t *hwif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100895 u32 itr1 = 0;
Alan Coxb39b01f2005-06-27 15:24:27 -0700896 struct hpt_info *info = ide_get_hwifdata(hwif);
897
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100898 pci_read_config_dword(hwif->pci_dev, 0x40, &itr1);
Alan Coxb39b01f2005-06-27 15:24:27 -0700899
900 /* detect bus speed by looking at control reg timing: */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100901 switch((itr1 >> 8) & 7) {
Alan Coxb39b01f2005-06-27 15:24:27 -0700902 case 5:
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800903 info->speed = forty_base_hpt36x;
Alan Coxb39b01f2005-06-27 15:24:27 -0700904 break;
905 case 9:
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800906 info->speed = twenty_five_base_hpt36x;
Alan Coxb39b01f2005-06-27 15:24:27 -0700907 break;
908 case 7:
909 default:
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800910 info->speed = thirty_three_base_hpt36x;
Alan Coxb39b01f2005-06-27 15:24:27 -0700911 break;
912 }
913}
914
915static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
916{
Sergei Shtylyov90778572007-02-07 18:17:51 +0100917 struct hpt_info *info = ide_get_hwifdata(hwif);
918 struct pci_dev *dev = hwif->pci_dev;
919 char *name = hwif->cds->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 int adjust, i;
Sergei Shtylyov26c068d2006-12-13 00:35:52 -0800921 u16 freq = 0;
922 u32 pll, temp = 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100923 u8 scr2 = 0, mcr1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 /*
926 * default to pci clock. make sure MA15/16 are set to output
Alan Coxb39b01f2005-06-27 15:24:27 -0700927 * to prevent drives having problems with 40-pin cables. Needed
928 * for some drives such as IBM-DTLA which will not enter ready
929 * state on reset when PDIAG is a input.
930 *
931 * ToDo: should we set 0x21 when using PLL mode ?
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 */
933 pci_write_config_byte(dev, 0x5b, 0x23);
934
935 /*
Sergei Shtylyov26c068d2006-12-13 00:35:52 -0800936 * We'll have to read f_CNT value in order to determine
937 * the PCI clock frequency according to the following ratio:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 *
Sergei Shtylyov26c068d2006-12-13 00:35:52 -0800939 * f_CNT = Fpci * 192 / Fdpll
940 *
941 * First try reading the register in which the HighPoint BIOS
942 * saves f_CNT value before reprogramming the DPLL from its
943 * default setting (which differs for the various chips).
Sergei Shtylyovf13c1522006-12-13 00:35:53 -0800944 * NOTE: This register is only accessible via I/O space.
945 *
Sergei Shtylyov26c068d2006-12-13 00:35:52 -0800946 * In case the signature check fails, we'll have to resort to
947 * reading the f_CNT register itself in hopes that nobody has
948 * touched the DPLL yet...
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 */
Sergei Shtylyovf13c1522006-12-13 00:35:53 -0800950 temp = inl(pci_resource_start(dev, 4) + 0x90);
Sergei Shtylyov26c068d2006-12-13 00:35:52 -0800951 if ((temp & 0xFFFFF000) != 0xABCDE000) {
Sergei Shtylyov90778572007-02-07 18:17:51 +0100952 printk(KERN_WARNING "%s: no clock data saved by BIOS\n", name);
Sergei Shtylyov26c068d2006-12-13 00:35:52 -0800953
954 /* Calculate the average value of f_CNT */
955 for (temp = i = 0; i < 128; i++) {
956 pci_read_config_word(dev, 0x78, &freq);
957 temp += freq & 0x1ff;
958 mdelay(1);
959 }
960 freq = temp / 128;
961 } else
962 freq = temp & 0x1ff;
963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 /*
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800965 * HPT3xxN chips use different PCI clock information.
966 * Currently we always set up the PLL for them.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800968
969 if (info->flags & IS_3xxN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 if(freq < 0x55)
971 pll = F_LOW_PCI_33;
972 else if(freq < 0x70)
973 pll = F_LOW_PCI_40;
974 else if(freq < 0x7F)
975 pll = F_LOW_PCI_50;
976 else
977 pll = F_LOW_PCI_66;
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800978
Sergei Shtylyov90778572007-02-07 18:17:51 +0100979 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if(freq < 0x9C)
981 pll = F_LOW_PCI_33;
982 else if(freq < 0xb0)
983 pll = F_LOW_PCI_40;
984 else if(freq <0xc8)
985 pll = F_LOW_PCI_50;
986 else
987 pll = F_LOW_PCI_66;
Sergei Shtylyov90778572007-02-07 18:17:51 +0100988 }
989 printk(KERN_INFO "%s: FREQ: %d, PLL: %d\n", name, freq, pll);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
Sergei Shtylyov90778572007-02-07 18:17:51 +0100991 if (!(info->flags & IS_3xxN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 if (pll == F_LOW_PCI_33) {
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800993 info->speed = thirty_three_base_hpt37x;
Sergei Shtylyov90778572007-02-07 18:17:51 +0100994 printk(KERN_DEBUG "%s: using 33MHz PCI clock\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 } else if (pll == F_LOW_PCI_40) {
996 /* Unsupported */
997 } else if (pll == F_LOW_PCI_50) {
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800998 info->speed = fifty_base_hpt37x;
Sergei Shtylyov90778572007-02-07 18:17:51 +0100999 printk(KERN_DEBUG "%s: using 50MHz PCI clock\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 } else {
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -08001001 info->speed = sixty_six_base_hpt37x;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001002 printk(KERN_DEBUG "%s: using 66MHz PCI clock\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 }
1004 }
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001005
1006 if (pll == F_LOW_PCI_66)
1007 info->flags |= PCI_66MHZ;
1008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 /*
1010 * only try the pll if we don't have a table for the clock
1011 * speed that we're running at. NOTE: the internal PLL will
1012 * result in slow reads when using a 33MHz PCI clock. we also
1013 * don't like to use the PLL because it will cause glitches
1014 * on PRST/SRST when the HPT state engine gets reset.
Alan Coxb39b01f2005-06-27 15:24:27 -07001015 *
1016 * ToDo: Use 66MHz PLL when ATA133 devices are present on a
1017 * 372 device so we can get ATA133 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 */
Alan Coxb39b01f2005-06-27 15:24:27 -07001019 if (info->speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 goto init_hpt37X_done;
Alan Coxb39b01f2005-06-27 15:24:27 -07001021
1022 info->flags |= PLL_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 /*
Sergei Shtylyov26c068d2006-12-13 00:35:52 -08001025 * Adjust the PLL based upon the PCI clock, enable it, and
1026 * wait for stabilization...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 */
1028 adjust = 0;
1029 freq = (pll < F_LOW_PCI_50) ? 2 : 4;
1030 while (adjust++ < 6) {
1031 pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
1032 pll | 0x100);
1033
1034 /* wait for clock stabilization */
1035 for (i = 0; i < 0x50000; i++) {
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001036 pci_read_config_byte(dev, 0x5b, &scr2);
1037 if (scr2 & 0x80) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 /* spin looking for the clock to destabilize */
1039 for (i = 0; i < 0x1000; ++i) {
1040 pci_read_config_byte(dev, 0x5b,
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001041 &scr2);
1042 if ((scr2 & 0x80) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 goto pll_recal;
1044 }
1045 pci_read_config_dword(dev, 0x5c, &pll);
1046 pci_write_config_dword(dev, 0x5c,
1047 pll & ~0x100);
1048 pci_write_config_byte(dev, 0x5b, 0x21);
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -08001049
1050 info->speed = fifty_base_hpt37x;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001051 printk("%s: using 50MHz internal PLL\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 goto init_hpt37X_done;
1053 }
1054 }
1055pll_recal:
1056 if (adjust & 1)
1057 pll -= (adjust >> 1);
1058 else
1059 pll += (adjust >> 1);
1060 }
1061
1062init_hpt37X_done:
Alan Coxb39b01f2005-06-27 15:24:27 -07001063 if (!info->speed)
Sergei Shtylyov90778572007-02-07 18:17:51 +01001064 printk(KERN_ERR "%s: unknown bus timing [%d %d].\n",
1065 name, pll, freq);
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001066 /*
1067 * Reset the state engines.
1068 * NOTE: avoid accidentally enabling the primary channel on HPT371N.
1069 */
1070 pci_read_config_byte(dev, 0x50, &mcr1);
1071 if (mcr1 & 0x04)
1072 pci_write_config_byte(dev, 0x50, 0x37);
1073 pci_write_config_byte(dev, 0x54, 0x37);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 udelay(100);
Alan Coxb39b01f2005-06-27 15:24:27 -07001075}
1076
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
1078{
Linus Torvalds9ec4ff42005-09-11 09:22:50 -07001079 /*
1080 * FIXME: Not portable. Also, why do we enable the ROM in the first place?
1081 * We don't seem to be using it.
1082 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 if (dev->resource[PCI_ROM_RESOURCE].start)
Linus Torvalds9ec4ff42005-09-11 09:22:50 -07001084 pci_write_config_dword(dev, PCI_ROM_ADDRESS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
1086
Alan Coxb39b01f2005-06-27 15:24:27 -07001087 pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
1088 pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
1089 pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
1090 pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001092 if (hpt_revision(dev) >= 3) {
1093 u8 scr1 = 0;
Alan Coxb39b01f2005-06-27 15:24:27 -07001094
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001095 /* Interrupt force enable. */
1096 pci_read_config_byte(dev, 0x5a, &scr1);
1097 if (scr1 & 0x10)
1098 pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
1099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101 return dev->irq;
1102}
1103
1104static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
1105{
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001106 struct pci_dev *dev = hwif->pci_dev;
Alan Coxb39b01f2005-06-27 15:24:27 -07001107 struct hpt_info *info = ide_get_hwifdata(hwif);
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001108 int serialize = HPT_SERIALIZE_IO;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001109 u8 scr1 = 0, ata66 = (hwif->channel) ? 0x01 : 0x02;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001110 u8 new_mcr, old_mcr = 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001111
1112 /* Cache the channel's MISC. control registers' offset */
1113 hwif->select_data = hwif->channel ? 0x54 : 0x50;
1114
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 hwif->tuneproc = &hpt3xx_tune_drive;
1116 hwif->speedproc = &hpt3xx_tune_chipset;
1117 hwif->quirkproc = &hpt3xx_quirkproc;
1118 hwif->intrproc = &hpt3xx_intrproc;
1119 hwif->maskproc = &hpt3xx_maskproc;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001120 hwif->busproc = &hpt3xx_busproc;
1121
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001122 /*
1123 * HPT3xxN chips have some complications:
1124 *
1125 * - on 33 MHz PCI we must clock switch
1126 * - on 66 MHz PCI we must NOT use the PCI clock
1127 */
1128 if ((info->flags & (IS_3xxN | PCI_66MHZ)) == IS_3xxN) {
1129 /*
1130 * Clock is shared between the channels,
1131 * so we'll have to serialize them... :-(
1132 */
1133 serialize = 1;
1134 hwif->rw_disk = &hpt3xxn_rw_disk;
1135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001137 /* Serialize access to this device if needed */
1138 if (serialize && hwif->mate)
1139 hwif->serialized = hwif->mate->serialized = 1;
1140
1141 /*
1142 * Disable the "fast interrupt" prediction. Don't hold off
1143 * on interrupts. (== 0x01 despite what the docs say)
1144 */
1145 pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
1146
1147 if (info->revision >= 5) /* HPT372 and newer */
1148 new_mcr = old_mcr & ~0x07;
1149 else if (info->revision >= 3) { /* HPT370 and HPT370A */
1150 new_mcr = old_mcr;
1151 new_mcr &= ~0x02;
1152
1153#ifdef HPT_DELAY_INTERRUPT
1154 new_mcr &= ~0x01;
1155#else
1156 new_mcr |= 0x01;
1157#endif
1158 } else /* HPT366 and HPT368 */
1159 new_mcr = old_mcr & ~0x80;
1160
1161 if (new_mcr != old_mcr)
1162 pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
1163
1164 if (!hwif->dma_base) {
1165 hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
1166 return;
1167 }
1168
1169 hwif->ultra_mask = 0x7f;
1170 hwif->mwdma_mask = 0x07;
1171
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 /*
1173 * The HPT37x uses the CBLID pins as outputs for MA15/MA16
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001174 * address lines to access an external EEPROM. To read valid
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 * cable detect state the pins must be enabled as inputs.
1176 */
Alan Coxb39b01f2005-06-27 15:24:27 -07001177 if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 /*
1179 * HPT374 PCI function 1
1180 * - set bit 15 of reg 0x52 to enable TCBLID as input
1181 * - set bit 15 of reg 0x56 to enable FCBLID as input
1182 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001183 u8 mcr_addr = hwif->select_data + 2;
1184 u16 mcr;
1185
1186 pci_read_config_word (dev, mcr_addr, &mcr);
1187 pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 /* now read cable id register */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001189 pci_read_config_byte (dev, 0x5a, &scr1);
1190 pci_write_config_word(dev, mcr_addr, mcr);
Alan Coxb39b01f2005-06-27 15:24:27 -07001191 } else if (info->revision >= 3) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 /*
1193 * HPT370/372 and 374 pcifn 0
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001194 * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001196 u8 scr2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001198 pci_read_config_byte (dev, 0x5b, &scr2);
1199 pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
1200 /* now read cable id register */
1201 pci_read_config_byte (dev, 0x5a, &scr1);
1202 pci_write_config_byte(dev, 0x5b, scr2);
1203 } else
1204 pci_read_config_byte (dev, 0x5a, &scr1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001206 if (!hwif->udma_four)
1207 hwif->udma_four = (scr1 & ata66) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001209 hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001211 if (info->revision >= 5) {
1212 hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
1213 hwif->ide_dma_end = &hpt374_ide_dma_end;
Alan Coxb39b01f2005-06-27 15:24:27 -07001214 } else if (info->revision >= 3) {
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001215 hwif->dma_start = &hpt370_ide_dma_start;
1216 hwif->ide_dma_end = &hpt370_ide_dma_end;
1217 hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001218 } else
1219 hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221 if (!noautodma)
1222 hwif->autodma = 1;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001223 hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224}
1225
1226static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
1227{
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001228 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001229 struct hpt_info *info = ide_get_hwifdata(hwif);
1230 u8 masterdma = 0, slavedma = 0;
1231 u8 dma_new = 0, dma_old = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 unsigned long flags;
1233
1234 if (!dmabase)
1235 return;
1236
Alan Coxb39b01f2005-06-27 15:24:27 -07001237 if(info->speed == NULL) {
Sergei Shtylyov90778572007-02-07 18:17:51 +01001238 printk(KERN_WARNING "%s: no known IDE timings, disabling DMA.\n",
1239 hwif->cds->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 return;
1241 }
1242
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001243 dma_old = hwif->INB(dmabase + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
1245 local_irq_save(flags);
1246
1247 dma_new = dma_old;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001248 pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
1249 pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
1251 if (masterdma & 0x30) dma_new |= 0x20;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001252 if ( slavedma & 0x30) dma_new |= 0x40;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 if (dma_new != dma_old)
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001254 hwif->OUTB(dma_new, dmabase + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
1256 local_irq_restore(flags);
1257
1258 ide_setup_dma(hwif, dmabase, 8);
1259}
1260
Alan Coxb39b01f2005-06-27 15:24:27 -07001261/*
1262 * We "borrow" this hook in order to set the data structures
1263 * up early enough before dma or init_hwif calls are made.
1264 */
1265
1266static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
1267{
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001268 struct hpt_info *info = kzalloc(sizeof(struct hpt_info), GFP_KERNEL);
1269 struct pci_dev *dev = hwif->pci_dev;
1270 u16 did = dev->device;
Sergei Shtylyove139b0b2007-02-07 18:17:37 +01001271 u8 mode, rid = 0;
Alan Coxb39b01f2005-06-27 15:24:27 -07001272
1273 if(info == NULL) {
Sergei Shtylyov90778572007-02-07 18:17:51 +01001274 printk(KERN_WARNING "%s: out of memory.\n", hwif->cds->name);
Alan Coxb39b01f2005-06-27 15:24:27 -07001275 return;
1276 }
Alan Coxb39b01f2005-06-27 15:24:27 -07001277 ide_set_hwifdata(hwif, info);
1278
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001279 /* Avoid doing the same thing twice. */
1280 if (hwif->channel && hwif->mate) {
1281 memcpy(info, ide_get_hwifdata(hwif->mate), sizeof(struct hpt_info));
1282 return;
Alan Coxb39b01f2005-06-27 15:24:27 -07001283 }
1284
Sergei Shtylyove139b0b2007-02-07 18:17:37 +01001285 pci_read_config_byte(dev, PCI_REVISION_ID, &rid);
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001286
1287 if (( did == PCI_DEVICE_ID_TTI_HPT366 && rid == 6) ||
1288 ((did == PCI_DEVICE_ID_TTI_HPT372 ||
1289 did == PCI_DEVICE_ID_TTI_HPT302 ||
1290 did == PCI_DEVICE_ID_TTI_HPT371) && rid > 1) ||
1291 did == PCI_DEVICE_ID_TTI_HPT372N)
1292 info->flags |= IS_3xxN;
1293
Sergei Shtylyove139b0b2007-02-07 18:17:37 +01001294 rid = info->revision = hpt_revision(dev);
1295 if (rid >= 8) /* HPT374 */
1296 mode = HPT374_ALLOW_ATA133_6 ? 4 : 3;
1297 else if (rid >= 7) /* HPT371 and HPT371N */
1298 mode = HPT371_ALLOW_ATA133_6 ? 4 : 3;
1299 else if (rid >= 6) /* HPT302 and HPT302N */
1300 mode = HPT302_ALLOW_ATA133_6 ? 4 : 3;
1301 else if (rid >= 5) /* HPT372, HPT372A, and HPT372N */
1302 mode = HPT372_ALLOW_ATA133_6 ? 4 : 3;
1303 else if (rid >= 3) /* HPT370 and HPT370A */
1304 mode = HPT370_ALLOW_ATA100_5 ? 3 : 2;
1305 else /* HPT366 and HPT368 */
1306 mode = (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1;
1307 info->max_mode = mode;
Alan Coxb39b01f2005-06-27 15:24:27 -07001308
Sergei Shtylyove139b0b2007-02-07 18:17:37 +01001309 if (rid >= 3)
Alan Coxb39b01f2005-06-27 15:24:27 -07001310 hpt37x_clocking(hwif);
1311 else
1312 hpt366_clocking(hwif);
1313}
1314
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
1316{
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001317 struct pci_dev *dev2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
1319 if (PCI_FUNC(dev->devfn) & 1)
1320 return -ENODEV;
1321
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001322 if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
1323 int ret;
1324
1325 if (dev2->irq != dev->irq) {
1326 /* FIXME: we need a core pci_set_interrupt() */
1327 dev2->irq = dev->irq;
1328 printk(KERN_WARNING "%s: PCI config space interrupt "
1329 "fixed.\n", d->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 }
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001331 ret = ide_setup_pci_devices(dev, dev2, d);
1332 if (ret < 0)
1333 pci_dev_put(dev2);
1334 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 }
1336 return ide_setup_pci_device(dev, d);
1337}
1338
Sergei Shtylyov90778572007-02-07 18:17:51 +01001339static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340{
1341 return ide_setup_pci_device(dev, d);
1342}
1343
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001344static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
1345{
Sergei Shtylyov90778572007-02-07 18:17:51 +01001346 u8 rev = 0, mcr1 = 0;
1347
1348 pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
1349
1350 if (rev > 1)
1351 d->name = "HPT371N";
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001352
1353 /*
1354 * HPT371 chips physically have only one channel, the secondary one,
1355 * but the primary channel registers do exist! Go figure...
1356 * So, we manually disable the non-existing channel here
1357 * (if the BIOS hasn't done this already).
1358 */
1359 pci_read_config_byte(dev, 0x50, &mcr1);
1360 if (mcr1 & 0x04)
Sergei Shtylyov90778572007-02-07 18:17:51 +01001361 pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
1362
1363 return ide_setup_pci_device(dev, d);
1364}
1365
1366static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
1367{
1368 u8 rev = 0;
1369
1370 pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
1371
1372 if (rev > 1)
1373 d->name = "HPT372N";
1374
1375 return ide_setup_pci_device(dev, d);
1376}
1377
1378static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
1379{
1380 u8 rev = 0;
1381
1382 pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
1383
1384 if (rev > 1)
1385 d->name = "HPT302N";
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001386
1387 return ide_setup_pci_device(dev, d);
1388}
1389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
1391{
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001392 struct pci_dev *dev2;
1393 u8 rev = 0;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001394 static char *chipset_names[] = { "HPT366", "HPT366", "HPT368",
1395 "HPT370", "HPT370A", "HPT372",
1396 "HPT372N" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
1398 if (PCI_FUNC(dev->devfn) & 1)
1399 return -ENODEV;
1400
Sergei Shtylyove139b0b2007-02-07 18:17:37 +01001401 pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Sergei Shtylyov90778572007-02-07 18:17:51 +01001403 if (rev > 6)
Sergei Shtylyove139b0b2007-02-07 18:17:37 +01001404 rev = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
Sergei Shtylyov90778572007-02-07 18:17:51 +01001406 d->name = chipset_names[rev];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
Sergei Shtylyov90778572007-02-07 18:17:51 +01001408 if (rev > 2)
1409 goto init_single;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
1411 d->channels = 1;
1412
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001413 if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
1414 u8 pin1 = 0, pin2 = 0;
1415 int ret;
1416
1417 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
1418 pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
1419 if (pin1 != pin2 && dev->irq == dev2->irq) {
1420 d->bootable = ON_BOARD;
1421 printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
1422 d->name, pin1, pin2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 }
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001424 ret = ide_setup_pci_devices(dev, dev2, d);
1425 if (ret < 0)
1426 pci_dev_put(dev2);
1427 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 }
1429init_single:
1430 return ide_setup_pci_device(dev, d);
1431}
1432
1433static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
1434 { /* 0 */
1435 .name = "HPT366",
1436 .init_setup = init_setup_hpt366,
1437 .init_chipset = init_chipset_hpt366,
Alan Coxb39b01f2005-06-27 15:24:27 -07001438 .init_iops = init_iops_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 .init_hwif = init_hwif_hpt366,
1440 .init_dma = init_dma_hpt366,
1441 .channels = 2,
1442 .autodma = AUTODMA,
1443 .bootable = OFF_BOARD,
1444 .extra = 240
1445 },{ /* 1 */
1446 .name = "HPT372A",
Sergei Shtylyov90778572007-02-07 18:17:51 +01001447 .init_setup = init_setup_hpt372a,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 .init_chipset = init_chipset_hpt366,
Alan Coxb39b01f2005-06-27 15:24:27 -07001449 .init_iops = init_iops_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 .init_hwif = init_hwif_hpt366,
1451 .init_dma = init_dma_hpt366,
1452 .channels = 2,
1453 .autodma = AUTODMA,
1454 .bootable = OFF_BOARD,
Sergei Shtylyov90778572007-02-07 18:17:51 +01001455 .extra = 240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 },{ /* 2 */
1457 .name = "HPT302",
Sergei Shtylyov90778572007-02-07 18:17:51 +01001458 .init_setup = init_setup_hpt302,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 .init_chipset = init_chipset_hpt366,
Alan Coxb39b01f2005-06-27 15:24:27 -07001460 .init_iops = init_iops_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 .init_hwif = init_hwif_hpt366,
1462 .init_dma = init_dma_hpt366,
1463 .channels = 2,
1464 .autodma = AUTODMA,
1465 .bootable = OFF_BOARD,
Sergei Shtylyov90778572007-02-07 18:17:51 +01001466 .extra = 240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 },{ /* 3 */
1468 .name = "HPT371",
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001469 .init_setup = init_setup_hpt371,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 .init_chipset = init_chipset_hpt366,
Alan Coxb39b01f2005-06-27 15:24:27 -07001471 .init_iops = init_iops_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 .init_hwif = init_hwif_hpt366,
1473 .init_dma = init_dma_hpt366,
1474 .channels = 2,
1475 .autodma = AUTODMA,
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001476 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 .bootable = OFF_BOARD,
Sergei Shtylyov90778572007-02-07 18:17:51 +01001478 .extra = 240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 },{ /* 4 */
1480 .name = "HPT374",
1481 .init_setup = init_setup_hpt374,
1482 .init_chipset = init_chipset_hpt366,
Alan Coxb39b01f2005-06-27 15:24:27 -07001483 .init_iops = init_iops_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 .init_hwif = init_hwif_hpt366,
1485 .init_dma = init_dma_hpt366,
1486 .channels = 2, /* 4 */
1487 .autodma = AUTODMA,
1488 .bootable = OFF_BOARD,
Sergei Shtylyov90778572007-02-07 18:17:51 +01001489 .extra = 240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 },{ /* 5 */
1491 .name = "HPT372N",
Sergei Shtylyov90778572007-02-07 18:17:51 +01001492 .init_setup = init_setup_hpt372n,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 .init_chipset = init_chipset_hpt366,
Alan Coxb39b01f2005-06-27 15:24:27 -07001494 .init_iops = init_iops_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 .init_hwif = init_hwif_hpt366,
1496 .init_dma = init_dma_hpt366,
1497 .channels = 2, /* 4 */
1498 .autodma = AUTODMA,
1499 .bootable = OFF_BOARD,
Sergei Shtylyov90778572007-02-07 18:17:51 +01001500 .extra = 240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 }
1502};
1503
1504/**
1505 * hpt366_init_one - called when an HPT366 is found
1506 * @dev: the hpt366 device
1507 * @id: the matching pci id
1508 *
1509 * Called when the PCI registration layer (or the IDE initialization)
1510 * finds a device matching our IDE device tables.
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -08001511 *
1512 * NOTE: since we'll have to modify some fields of the ide_pci_device_t
1513 * structure depending on the chip's revision, we'd better pass a local
1514 * copy down the call chain...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
1517{
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -08001518 ide_pci_device_t d = hpt366_chipsets[id->driver_data];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -08001520 return d.init_setup(dev, &d);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521}
1522
1523static struct pci_device_id hpt366_pci_tbl[] = {
1524 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1525 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
1526 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
1527 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
1528 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
1529 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
1530 { 0, },
1531};
1532MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
1533
1534static struct pci_driver driver = {
1535 .name = "HPT366_IDE",
1536 .id_table = hpt366_pci_tbl,
1537 .probe = hpt366_init_one,
1538};
1539
Bartlomiej Zolnierkiewicz82ab1ee2007-01-27 13:46:56 +01001540static int __init hpt366_ide_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541{
1542 return ide_pci_register_driver(&driver);
1543}
1544
1545module_init(hpt366_ide_init);
1546
1547MODULE_AUTHOR("Andre Hedrick");
1548MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
1549MODULE_LICENSE("GPL");