blob: 4350e33713600e4eb1ed4595d05e187c76f11bb4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01002 * linux/drivers/ide/pci/hpt366.c Version 1.00 Jun 25, 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
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +010063 * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used
64 * does not allow for this speed anyway
65 * - avoid touching disabled channels (e.g. HPT371/N are single channel chips,
66 * their primary channel is kind of virtual, it isn't tied to any pins)
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -080067 * - fix/remove bad/unused timing tables and use one set of tables for the whole
68 * HPT37x chip family; save space by introducing the separate transfer mode
69 * table in which the mode lookup is done
Sergei Shtylyov26c068d2006-12-13 00:35:52 -080070 * - use f_CNT value saved by the HighPoint BIOS as reading it directly gives
71 * the wrong PCI frequency since DPLL has already been calibrated by BIOS
Sergei Shtylyov33b18a62006-12-13 00:35:50 -080072 * - fix the hotswap code: it caused RESET- to glitch when tristating the bus,
73 * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -080074 * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
75 * they tamper with its fields
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +010076 * - pass to the init_setup handlers a copy of the ide_pci_device_t structure
77 * since they may tamper with its fields
Sergei Shtylyov90778572007-02-07 18:17:51 +010078 * - prefix the driver startup messages with the real chip name
79 * - claim the extra 240 bytes of I/O space for all chips
Sergei Shtylyove139b0b2007-02-07 18:17:37 +010080 * - optimize the rate masking/filtering and the drive list lookup code
Sergei Shtylyovb4586712007-02-07 18:17:54 +010081 * - use pci_get_slot() to get to the function 1 of HPT36x/374
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +010082 * - cache offset of the channel's misc. control registers (MCRs) being used
83 * throughout the driver
84 * - only touch the relevant MCR when detecting the cable type on HPT374's
85 * function 1
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +010086 * - rename all the register related variables consistently
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +010087 * - move all the interrupt twiddling code from the speedproc handlers into
88 * init_hwif_hpt366(), also grouping all the DMA related code together there
89 * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
90 * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
91 * when setting an UltraDMA mode
92 * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
93 * the best possible one
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +010094 * - clean up DMA timeout handling for HPT370
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +010095 * - switch to using the enumeration type to differ between the numerous chip
96 * variants, matching PCI device/revision ID with the chip type early, at the
97 * init_setup stage
98 * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
99 * stop duplicating it for each channel by storing the pointer in the pci_dev
100 * structure: first, at the init_setup stage, point it to a static "template"
101 * with only the chip type and its specific base DPLL frequency, the highest
102 * supported DMA mode, and the chip settings table pointer filled, then, at
103 * the init_chipset stage, allocate per-chip instance and fill it with the
104 * rest of the necessary information
105 * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
106 * switch to calculating PCI clock frequency based on the chip's base DPLL
107 * frequency
108 * - switch to using the DPLL clock and enable UltraATA/133 mode by default on
109 * anything newer than HPT370/A
110 * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366();
111 * unify HPT36x/37x timing setup code and the speedproc handlers by joining
112 * the register setting lists into the table indexed by the clock selected
113 * Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 */
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116#include <linux/types.h>
117#include <linux/module.h>
118#include <linux/kernel.h>
119#include <linux/delay.h>
120#include <linux/timer.h>
121#include <linux/mm.h>
122#include <linux/ioport.h>
123#include <linux/blkdev.h>
124#include <linux/hdreg.h>
125
126#include <linux/interrupt.h>
127#include <linux/pci.h>
128#include <linux/init.h>
129#include <linux/ide.h>
130
131#include <asm/uaccess.h>
132#include <asm/io.h>
133#include <asm/irq.h>
134
135/* various tuning parameters */
136#define HPT_RESET_STATE_ENGINE
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800137#undef HPT_DELAY_INTERRUPT
138#define HPT_SERIALIZE_IO 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140static const char *quirk_drives[] = {
141 "QUANTUM FIREBALLlct08 08",
142 "QUANTUM FIREBALLP KA6.4",
143 "QUANTUM FIREBALLP LM20.4",
144 "QUANTUM FIREBALLP LM20.5",
145 NULL
146};
147
148static const char *bad_ata100_5[] = {
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_4[] = {
168 "IBM-DTLA-307075",
169 "IBM-DTLA-307060",
170 "IBM-DTLA-307045",
171 "IBM-DTLA-307030",
172 "IBM-DTLA-307020",
173 "IBM-DTLA-307015",
174 "IBM-DTLA-305040",
175 "IBM-DTLA-305030",
176 "IBM-DTLA-305020",
177 "IC35L010AVER07-0",
178 "IC35L020AVER07-0",
179 "IC35L030AVER07-0",
180 "IC35L040AVER07-0",
181 "IC35L060AVER07-0",
182 "WDC AC310200R",
183 NULL
184};
185
186static const char *bad_ata66_3[] = {
187 "WDC AC310200R",
188 NULL
189};
190
191static const char *bad_ata33[] = {
192 "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
193 "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
194 "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
195 "Maxtor 90510D4",
196 "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
197 "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
198 "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
199 NULL
200};
201
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800202static u8 xfer_speeds[] = {
203 XFER_UDMA_6,
204 XFER_UDMA_5,
205 XFER_UDMA_4,
206 XFER_UDMA_3,
207 XFER_UDMA_2,
208 XFER_UDMA_1,
209 XFER_UDMA_0,
210
211 XFER_MW_DMA_2,
212 XFER_MW_DMA_1,
213 XFER_MW_DMA_0,
214
215 XFER_PIO_4,
216 XFER_PIO_3,
217 XFER_PIO_2,
218 XFER_PIO_1,
219 XFER_PIO_0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220};
221
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800222/* Key for bus clock timings
223 * 36x 37x
224 * bits bits
225 * 0:3 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
226 * cycles = value + 1
227 * 4:7 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
228 * cycles = value + 1
229 * 8:11 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
230 * register access.
231 * 12:15 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
232 * register access.
233 * 16:18 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
234 * - 21 CLK frequency: 0=ATA clock, 1=dual ATA clock.
235 * 19:21 22:24 pre_high_time. Time to initialize the 1st cycle for PIO and
236 * MW DMA xfer.
237 * 22:24 25:27 cmd_pre_high_time. Time to initialize the 1st PIO cycle for
238 * task file register access.
239 * 28 28 UDMA enable.
240 * 29 29 DMA enable.
241 * 30 30 PIO MST enable. If set, the chip is in bus master mode during
242 * PIO xfer.
243 * 31 31 FIFO enable.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800246static u32 forty_base_hpt36x[] = {
247 /* XFER_UDMA_6 */ 0x900fd943,
248 /* XFER_UDMA_5 */ 0x900fd943,
249 /* XFER_UDMA_4 */ 0x900fd943,
250 /* XFER_UDMA_3 */ 0x900ad943,
251 /* XFER_UDMA_2 */ 0x900bd943,
252 /* XFER_UDMA_1 */ 0x9008d943,
253 /* XFER_UDMA_0 */ 0x9008d943,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800255 /* XFER_MW_DMA_2 */ 0xa008d943,
256 /* XFER_MW_DMA_1 */ 0xa010d955,
257 /* XFER_MW_DMA_0 */ 0xa010d9fc,
258
259 /* XFER_PIO_4 */ 0xc008d963,
260 /* XFER_PIO_3 */ 0xc010d974,
261 /* XFER_PIO_2 */ 0xc010d997,
262 /* XFER_PIO_1 */ 0xc010d9c7,
263 /* XFER_PIO_0 */ 0xc018d9d9
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264};
265
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800266static u32 thirty_three_base_hpt36x[] = {
267 /* XFER_UDMA_6 */ 0x90c9a731,
268 /* XFER_UDMA_5 */ 0x90c9a731,
269 /* XFER_UDMA_4 */ 0x90c9a731,
270 /* XFER_UDMA_3 */ 0x90cfa731,
271 /* XFER_UDMA_2 */ 0x90caa731,
272 /* XFER_UDMA_1 */ 0x90cba731,
273 /* XFER_UDMA_0 */ 0x90c8a731,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800275 /* XFER_MW_DMA_2 */ 0xa0c8a731,
276 /* XFER_MW_DMA_1 */ 0xa0c8a732, /* 0xa0c8a733 */
277 /* XFER_MW_DMA_0 */ 0xa0c8a797,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800279 /* XFER_PIO_4 */ 0xc0c8a731,
280 /* XFER_PIO_3 */ 0xc0c8a742,
281 /* XFER_PIO_2 */ 0xc0d0a753,
282 /* XFER_PIO_1 */ 0xc0d0a7a3, /* 0xc0d0a793 */
283 /* XFER_PIO_0 */ 0xc0d0a7aa /* 0xc0d0a7a7 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284};
285
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800286static u32 twenty_five_base_hpt36x[] = {
287 /* XFER_UDMA_6 */ 0x90c98521,
288 /* XFER_UDMA_5 */ 0x90c98521,
289 /* XFER_UDMA_4 */ 0x90c98521,
290 /* XFER_UDMA_3 */ 0x90cf8521,
291 /* XFER_UDMA_2 */ 0x90cf8521,
292 /* XFER_UDMA_1 */ 0x90cb8521,
293 /* XFER_UDMA_0 */ 0x90cb8521,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800295 /* XFER_MW_DMA_2 */ 0xa0ca8521,
296 /* XFER_MW_DMA_1 */ 0xa0ca8532,
297 /* XFER_MW_DMA_0 */ 0xa0ca8575,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800299 /* XFER_PIO_4 */ 0xc0ca8521,
300 /* XFER_PIO_3 */ 0xc0ca8532,
301 /* XFER_PIO_2 */ 0xc0ca8542,
302 /* XFER_PIO_1 */ 0xc0d08572,
303 /* XFER_PIO_0 */ 0xc0d08585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304};
305
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800306static u32 thirty_three_base_hpt37x[] = {
307 /* XFER_UDMA_6 */ 0x12446231, /* 0x12646231 ?? */
308 /* XFER_UDMA_5 */ 0x12446231,
309 /* XFER_UDMA_4 */ 0x12446231,
310 /* XFER_UDMA_3 */ 0x126c6231,
311 /* XFER_UDMA_2 */ 0x12486231,
312 /* XFER_UDMA_1 */ 0x124c6233,
313 /* XFER_UDMA_0 */ 0x12506297,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800315 /* XFER_MW_DMA_2 */ 0x22406c31,
316 /* XFER_MW_DMA_1 */ 0x22406c33,
317 /* XFER_MW_DMA_0 */ 0x22406c97,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800319 /* XFER_PIO_4 */ 0x06414e31,
320 /* XFER_PIO_3 */ 0x06414e42,
321 /* XFER_PIO_2 */ 0x06414e53,
322 /* XFER_PIO_1 */ 0x06814e93,
323 /* XFER_PIO_0 */ 0x06814ea7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324};
325
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800326static u32 fifty_base_hpt37x[] = {
327 /* XFER_UDMA_6 */ 0x12848242,
328 /* XFER_UDMA_5 */ 0x12848242,
329 /* XFER_UDMA_4 */ 0x12ac8242,
330 /* XFER_UDMA_3 */ 0x128c8242,
331 /* XFER_UDMA_2 */ 0x120c8242,
332 /* XFER_UDMA_1 */ 0x12148254,
333 /* XFER_UDMA_0 */ 0x121882ea,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800335 /* XFER_MW_DMA_2 */ 0x22808242,
336 /* XFER_MW_DMA_1 */ 0x22808254,
337 /* XFER_MW_DMA_0 */ 0x228082ea,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800339 /* XFER_PIO_4 */ 0x0a81f442,
340 /* XFER_PIO_3 */ 0x0a81f443,
341 /* XFER_PIO_2 */ 0x0a81f454,
342 /* XFER_PIO_1 */ 0x0ac1f465,
343 /* XFER_PIO_0 */ 0x0ac1f48a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344};
345
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800346static u32 sixty_six_base_hpt37x[] = {
347 /* XFER_UDMA_6 */ 0x1c869c62,
348 /* XFER_UDMA_5 */ 0x1cae9c62, /* 0x1c8a9c62 */
349 /* XFER_UDMA_4 */ 0x1c8a9c62,
350 /* XFER_UDMA_3 */ 0x1c8e9c62,
351 /* XFER_UDMA_2 */ 0x1c929c62,
352 /* XFER_UDMA_1 */ 0x1c9a9c62,
353 /* XFER_UDMA_0 */ 0x1c829c62,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800355 /* XFER_MW_DMA_2 */ 0x2c829c62,
356 /* XFER_MW_DMA_1 */ 0x2c829c66,
357 /* XFER_MW_DMA_0 */ 0x2c829d2e,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800359 /* XFER_PIO_4 */ 0x0c829c62,
360 /* XFER_PIO_3 */ 0x0c829c84,
361 /* XFER_PIO_2 */ 0x0c829ca6,
362 /* XFER_PIO_1 */ 0x0d029d26,
363 /* XFER_PIO_0 */ 0x0d029d5e
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364};
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366#define HPT366_DEBUG_DRIVE_INFO 0
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100367#define HPT374_ALLOW_ATA133_6 1
368#define HPT371_ALLOW_ATA133_6 1
369#define HPT302_ALLOW_ATA133_6 1
370#define HPT372_ALLOW_ATA133_6 1
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100371#define HPT370_ALLOW_ATA100_5 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372#define HPT366_ALLOW_ATA66_4 1
373#define HPT366_ALLOW_ATA66_3 1
374#define HPT366_MAX_DEVS 8
375
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100376/* Supported ATA clock frequencies */
377enum ata_clock {
378 ATA_CLOCK_25MHZ,
379 ATA_CLOCK_33MHZ,
380 ATA_CLOCK_40MHZ,
381 ATA_CLOCK_50MHZ,
382 ATA_CLOCK_66MHZ,
383 NUM_ATA_CLOCKS
Alan Coxb39b01f2005-06-27 15:24:27 -0700384};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Alan Coxb39b01f2005-06-27 15:24:27 -0700386/*
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100387 * Hold all the HighPoint chip information in one place.
Alan Coxb39b01f2005-06-27 15:24:27 -0700388 */
389
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100390struct hpt_info {
391 u8 chip_type; /* Chip type */
392 u8 max_mode; /* Speeds allowed */
393 u8 dpll_clk; /* DPLL clock in MHz */
394 u8 pci_clk; /* PCI clock in MHz */
395 u32 **settings; /* Chipset settings table */
396};
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100397
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100398/* Supported HighPoint chips */
399enum {
400 HPT36x,
401 HPT370,
402 HPT370A,
403 HPT374,
404 HPT372,
405 HPT372A,
406 HPT302,
407 HPT371,
408 HPT372N,
409 HPT302N,
410 HPT371N
411};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100413static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
414 twenty_five_base_hpt36x,
415 thirty_three_base_hpt36x,
416 forty_base_hpt36x,
417 NULL,
418 NULL
419};
420
421static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
422 NULL,
423 thirty_three_base_hpt37x,
424 NULL,
425 fifty_base_hpt37x,
426 sixty_six_base_hpt37x
427};
428
429static struct hpt_info hpt36x __devinitdata = {
430 .chip_type = HPT36x,
431 .max_mode = (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1,
432 .dpll_clk = 0, /* no DPLL */
433 .settings = hpt36x_settings
434};
435
436static struct hpt_info hpt370 __devinitdata = {
437 .chip_type = HPT370,
438 .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2,
439 .dpll_clk = 48,
440 .settings = hpt37x_settings
441};
442
443static struct hpt_info hpt370a __devinitdata = {
444 .chip_type = HPT370A,
445 .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2,
446 .dpll_clk = 48,
447 .settings = hpt37x_settings
448};
449
450static struct hpt_info hpt374 __devinitdata = {
451 .chip_type = HPT374,
452 .max_mode = HPT374_ALLOW_ATA133_6 ? 4 : 3,
453 .dpll_clk = 48,
454 .settings = hpt37x_settings
455};
456
457static struct hpt_info hpt372 __devinitdata = {
458 .chip_type = HPT372,
459 .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
460 .dpll_clk = 55,
461 .settings = hpt37x_settings
462};
463
464static struct hpt_info hpt372a __devinitdata = {
465 .chip_type = HPT372A,
466 .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
467 .dpll_clk = 66,
468 .settings = hpt37x_settings
469};
470
471static struct hpt_info hpt302 __devinitdata = {
472 .chip_type = HPT302,
473 .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3,
474 .dpll_clk = 66,
475 .settings = hpt37x_settings
476};
477
478static struct hpt_info hpt371 __devinitdata = {
479 .chip_type = HPT371,
480 .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3,
481 .dpll_clk = 66,
482 .settings = hpt37x_settings
483};
484
485static struct hpt_info hpt372n __devinitdata = {
486 .chip_type = HPT372N,
487 .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
488 .dpll_clk = 77,
489 .settings = hpt37x_settings
490};
491
492static struct hpt_info hpt302n __devinitdata = {
493 .chip_type = HPT302N,
494 .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3,
495 .dpll_clk = 77,
496};
497
498static struct hpt_info hpt371n __devinitdata = {
499 .chip_type = HPT371N,
500 .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3,
501 .dpll_clk = 77,
502 .settings = hpt37x_settings
503};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100505static int check_in_drive_list(ide_drive_t *drive, const char **list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100507 struct hd_driveid *id = drive->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100509 while (*list)
510 if (!strcmp(*list++,id->model))
511 return 1;
512 return 0;
513}
Alan Coxb39b01f2005-06-27 15:24:27 -0700514
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100515static u8 hpt3xx_ratemask(ide_drive_t *drive)
516{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100517 struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev);
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100518 u8 mode = info->max_mode;
519
Alan Coxb39b01f2005-06-27 15:24:27 -0700520 if (!eighty_ninty_three(drive) && mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 mode = min(mode, (u8)1);
522 return mode;
523}
524
525/*
526 * Note for the future; the SATA hpt37x we must set
527 * either PIO or UDMA modes 0,4,5
528 */
529
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100530static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100532 struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev);
533 u8 chip_type = info->chip_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 u8 mode = hpt3xx_ratemask(drive);
535
536 if (drive->media != ide_disk)
537 return min(speed, (u8)XFER_PIO_4);
538
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100539 switch (mode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 case 0x04:
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100541 speed = min_t(u8, speed, XFER_UDMA_6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 break;
543 case 0x03:
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100544 speed = min_t(u8, speed, XFER_UDMA_5);
545 if (chip_type >= HPT374)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 break;
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100547 if (!check_in_drive_list(drive, bad_ata100_5))
548 goto check_bad_ata33;
549 /* fall thru */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 case 0x02:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100551 speed = min_t(u8, speed, XFER_UDMA_4);
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100552
553 /*
554 * CHECK ME, Does this need to be changed to HPT374 ??
555 */
556 if (chip_type >= HPT370)
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100557 goto check_bad_ata33;
558 if (HPT366_ALLOW_ATA66_4 &&
559 !check_in_drive_list(drive, bad_ata66_4))
560 goto check_bad_ata33;
561
Andrew Mortonf36702b2007-02-07 18:17:37 +0100562 speed = min_t(u8, speed, XFER_UDMA_3);
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100563 if (HPT366_ALLOW_ATA66_3 &&
564 !check_in_drive_list(drive, bad_ata66_3))
565 goto check_bad_ata33;
566 /* fall thru */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 case 0x01:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100568 speed = min_t(u8, speed, XFER_UDMA_2);
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100569
570 check_bad_ata33:
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100571 if (chip_type >= HPT370A)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 break;
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100573 if (!check_in_drive_list(drive, bad_ata33))
574 break;
575 /* fall thru */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 case 0x00:
577 default:
Andrew Mortonf36702b2007-02-07 18:17:37 +0100578 speed = min_t(u8, speed, XFER_MW_DMA_2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 break;
580 }
581 return speed;
582}
583
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100584static u32 get_speed_setting(u8 speed, struct hpt_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800586 int i;
587
588 /*
589 * Lookup the transfer mode table to get the index into
590 * the timing table.
591 *
592 * NOTE: For XFER_PIO_SLOW, PIO mode 0 timings will be used.
593 */
594 for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
595 if (xfer_speeds[i] == speed)
596 break;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100597 /*
598 * NOTE: info->settings only points to the pointer
599 * to the list of the actual register values
600 */
601 return (*info->settings)[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602}
603
604static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
605{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100606 ide_hwif_t *hwif = HWIF(drive);
607 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100608 struct hpt_info *info = pci_get_drvdata(dev);
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100609 u8 speed = hpt3xx_ratefilter(drive, xferspeed);
610 u8 itr_addr = drive->dn ? 0x44 : 0x40;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100611 u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
612 (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff);
613 u32 new_itr = get_speed_setting(speed, info);
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100614 u32 old_itr = 0;
Alan Coxb39b01f2005-06-27 15:24:27 -0700615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 /*
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100617 * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
618 * to avoid problems handling I/O errors later
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100620 pci_read_config_dword(dev, itr_addr, &old_itr);
621 new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
622 new_itr &= ~0xc0000000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100624 pci_write_config_dword(dev, itr_addr, new_itr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 return ide_config_drive_speed(drive, speed);
627}
628
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100629static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100631 ide_hwif_t *hwif = HWIF(drive);
632 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100633 struct hpt_info *info = pci_get_drvdata(dev);
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100634 u8 speed = hpt3xx_ratefilter(drive, xferspeed);
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100635 u8 itr_addr = 0x40 + (drive->dn * 4);
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100636 u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
637 (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff);
638 u32 new_itr = get_speed_setting(speed, info);
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100639 u32 old_itr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100641 pci_read_config_dword(dev, itr_addr, &old_itr);
642 new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Alan Coxb39b01f2005-06-27 15:24:27 -0700644 if (speed < XFER_MW_DMA_0)
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100645 new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
646 pci_write_config_dword(dev, itr_addr, new_itr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 return ide_config_drive_speed(drive, speed);
649}
650
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100651static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100653 ide_hwif_t *hwif = HWIF(drive);
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100654 struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100656 if (info->chip_type >= HPT370)
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100657 return hpt37x_tune_chipset(drive, speed);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 else /* hpt368: hpt_minimum_revision(dev, 2) */
659 return hpt36x_tune_chipset(drive, speed);
660}
661
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100662static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100664 pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
665 (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666}
667
668/*
669 * This allows the configuration of ide_pci chipset registers
670 * for cards that learn about the drive's UDMA, DMA, PIO capabilities
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100671 * after the drive is reported by the OS. Initially designed for
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
673 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 */
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100675static int config_chipset_for_dma(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676{
677 u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
678
Alan Coxb39b01f2005-06-27 15:24:27 -0700679 if (!speed)
680 return 0;
681
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 (void) hpt3xx_tune_chipset(drive, speed);
683 return ide_dma_enable(drive);
684}
685
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100686static int hpt3xx_quirkproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100688 struct hd_driveid *id = drive->id;
689 const char **list = quirk_drives;
690
691 while (*list)
692 if (strstr(id->model, *list++))
693 return 1;
694 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100697static void hpt3xx_intrproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100699 ide_hwif_t *hwif = HWIF(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
701 if (drive->quirk_list)
702 return;
703 /* drives in the quirk_list may not like intr setups/cleanups */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100704 hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705}
706
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100707static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100709 ide_hwif_t *hwif = HWIF(drive);
710 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100711 struct hpt_info *info = pci_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
713 if (drive->quirk_list) {
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100714 if (info->chip_type >= HPT370) {
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100715 u8 scr1 = 0;
716
717 pci_read_config_byte(dev, 0x5a, &scr1);
718 if (((scr1 & 0x10) >> 4) != mask) {
719 if (mask)
720 scr1 |= 0x10;
721 else
722 scr1 &= ~0x10;
723 pci_write_config_byte(dev, 0x5a, scr1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100725 } else {
726 if (mask)
727 disable_irq(hwif->irq);
728 else
729 enable_irq (hwif->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100731 } else
732 hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
733 IDE_CONTROL_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734}
735
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100736static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100738 ide_hwif_t *hwif = HWIF(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 struct hd_driveid *id = drive->id;
740
741 drive->init_speed = 0;
742
Alan Coxb39b01f2005-06-27 15:24:27 -0700743 if ((id->capability & 1) && drive->autodma) {
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100744 if (ide_use_dma(drive) && config_chipset_for_dma(drive))
745 return hwif->ide_dma_on(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
747 goto fast_ata_pio;
748
749 } else if ((id->capability & 8) || (id->field_valid & 2)) {
750fast_ata_pio:
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100751 hpt3xx_tune_drive(drive, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return hwif->ide_dma_off_quietly(drive);
753 }
754 /* IORDY not supported */
755 return 0;
756}
757
758/*
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100759 * This is specific to the HPT366 UDMA chipset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 * by HighPoint|Triones Technologies, Inc.
761 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100762static int hpt366_ide_dma_lostirq(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100764 struct pci_dev *dev = HWIF(drive)->pci_dev;
765 u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100767 pci_read_config_byte(dev, 0x50, &mcr1);
768 pci_read_config_byte(dev, 0x52, &mcr3);
769 pci_read_config_byte(dev, 0x5a, &scr1);
770 printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
771 drive->name, __FUNCTION__, mcr1, mcr3, scr1);
772 if (scr1 & 0x10)
773 pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return __ide_dma_lostirq(drive);
775}
776
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100777static void hpt370_clear_engine(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100779 ide_hwif_t *hwif = HWIF(drive);
780
781 pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 udelay(10);
783}
784
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100785static void hpt370_irq_timeout(ide_drive_t *drive)
786{
787 ide_hwif_t *hwif = HWIF(drive);
788 u16 bfifo = 0;
789 u8 dma_cmd;
790
791 pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
792 printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
793
794 /* get DMA command mode */
795 dma_cmd = hwif->INB(hwif->dma_command);
796 /* stop DMA */
797 hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
798 hpt370_clear_engine(drive);
799}
800
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801static void hpt370_ide_dma_start(ide_drive_t *drive)
802{
803#ifdef HPT_RESET_STATE_ENGINE
804 hpt370_clear_engine(drive);
805#endif
806 ide_dma_start(drive);
807}
808
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100809static int hpt370_ide_dma_end(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810{
811 ide_hwif_t *hwif = HWIF(drive);
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100812 u8 dma_stat = hwif->INB(hwif->dma_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
814 if (dma_stat & 0x01) {
815 /* wait a little */
816 udelay(20);
817 dma_stat = hwif->INB(hwif->dma_status);
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100818 if (dma_stat & 0x01)
819 hpt370_irq_timeout(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 return __ide_dma_end(drive);
822}
823
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100824static int hpt370_ide_dma_timeout(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825{
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100826 hpt370_irq_timeout(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 return __ide_dma_timeout(drive);
828}
829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830/* returns 1 if DMA IRQ issued, 0 otherwise */
831static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
832{
833 ide_hwif_t *hwif = HWIF(drive);
834 u16 bfifo = 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100835 u8 dma_stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100837 pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (bfifo & 0x1FF) {
839// printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
840 return 0;
841 }
842
843 dma_stat = hwif->INB(hwif->dma_status);
844 /* return 1 if INTR asserted */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100845 if (dma_stat & 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 return 1;
847
848 if (!drive->waiting_for_dma)
849 printk(KERN_WARNING "%s: (%s) called while not waiting\n",
850 drive->name, __FUNCTION__);
851 return 0;
852}
853
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100854static int hpt374_ide_dma_end(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 ide_hwif_t *hwif = HWIF(drive);
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100857 struct pci_dev *dev = hwif->pci_dev;
858 u8 mcr = 0, mcr_addr = hwif->select_data;
859 u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100861 pci_read_config_byte(dev, 0x6a, &bwsr);
862 pci_read_config_byte(dev, mcr_addr, &mcr);
863 if (bwsr & mask)
864 pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 return __ide_dma_end(drive);
866}
867
868/**
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800869 * hpt3xxn_set_clock - perform clock switching dance
870 * @hwif: hwif to switch
871 * @mode: clocking mode (0x21 for write, 0x23 otherwise)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 *
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800873 * Switch the DPLL clock on the HPT3xxN devices. This is a right mess.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800875
876static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100878 u8 scr2 = hwif->INB(hwif->dma_master + 0x7b);
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800879
880 if ((scr2 & 0x7f) == mode)
881 return;
882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 /* Tristate the bus */
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100884 hwif->OUTB(0x80, hwif->dma_master + 0x73);
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800885 hwif->OUTB(0x80, hwif->dma_master + 0x77);
886
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 /* Switch clock and reset channels */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800888 hwif->OUTB(mode, hwif->dma_master + 0x7b);
889 hwif->OUTB(0xc0, hwif->dma_master + 0x79);
890
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100891 /*
892 * Reset the state machines.
893 * NOTE: avoid accidentally enabling the disabled channels.
894 */
895 hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32,
896 hwif->dma_master + 0x70);
897 hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32,
898 hwif->dma_master + 0x74);
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 /* Complete reset */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800901 hwif->OUTB(0x00, hwif->dma_master + 0x79);
902
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 /* Reconnect channels to bus */
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100904 hwif->OUTB(0x00, hwif->dma_master + 0x73);
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800905 hwif->OUTB(0x00, hwif->dma_master + 0x77);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906}
907
908/**
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800909 * hpt3xxn_rw_disk - prepare for I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 * @drive: drive for command
911 * @rq: block request structure
912 *
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800913 * This is called when a disk I/O is issued to HPT3xxN.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 * We need it because of the clock switching.
915 */
916
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800917static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100919 hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920}
921
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922/*
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800923 * Set/get power state for a drive.
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100924 * NOTE: affects both drives on each channel.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 *
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800926 * When we turn the power back on, we need to re-initialize things.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 */
928#define TRISTATE_BIT 0x8000
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800929
930static int hpt3xx_busproc(ide_drive_t *drive, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100932 ide_hwif_t *hwif = HWIF(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100934 u8 mcr_addr = hwif->select_data + 2;
935 u8 resetmask = hwif->channel ? 0x80 : 0x40;
936 u8 bsr2 = 0;
937 u16 mcr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
939 hwif->bus_state = state;
940
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800941 /* Grab the status. */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100942 pci_read_config_word(dev, mcr_addr, &mcr);
943 pci_read_config_byte(dev, 0x59, &bsr2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800945 /*
946 * Set the state. We don't set it if we don't need to do so.
947 * Make sure that the drive knows that it has failed if it's off.
948 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 switch (state) {
950 case BUSSTATE_ON:
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100951 if (!(bsr2 & resetmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 return 0;
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800953 hwif->drives[0].failures = hwif->drives[1].failures = 0;
954
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100955 pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask);
956 pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT);
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800957 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 case BUSSTATE_OFF:
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100959 if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 return 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100961 mcr &= ~TRISTATE_BIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 break;
963 case BUSSTATE_TRISTATE:
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100964 if ((bsr2 & resetmask) && (mcr & TRISTATE_BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 return 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100966 mcr |= TRISTATE_BIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 break;
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800968 default:
969 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800972 hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
973 hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
974
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100975 pci_write_config_word(dev, mcr_addr, mcr);
976 pci_write_config_byte(dev, 0x59, bsr2 | resetmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 return 0;
978}
979
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100980/**
981 * hpt37x_calibrate_dpll - calibrate the DPLL
982 * @dev: PCI device
983 *
984 * Perform a calibration cycle on the DPLL.
985 * Returns 1 if this succeeds
986 */
987static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100989 u32 dpll = (f_high << 16) | f_low | 0x100;
990 u8 scr2;
991 int i;
Alan Coxb39b01f2005-06-27 15:24:27 -0700992
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100993 pci_write_config_dword(dev, 0x5c, dpll);
Alan Coxb39b01f2005-06-27 15:24:27 -0700994
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100995 /* Wait for oscillator ready */
996 for(i = 0; i < 0x5000; ++i) {
997 udelay(50);
998 pci_read_config_byte(dev, 0x5b, &scr2);
999 if (scr2 & 0x80)
Alan Coxb39b01f2005-06-27 15:24:27 -07001000 break;
1001 }
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001002 /* See if it stays ready (we'll just bail out if it's not yet) */
1003 for(i = 0; i < 0x1000; ++i) {
1004 pci_read_config_byte(dev, 0x5b, &scr2);
1005 /* DPLL destabilized? */
1006 if(!(scr2 & 0x80))
1007 return 0;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001008 }
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001009 /* Turn off tuning, we have the DPLL set */
1010 pci_read_config_dword (dev, 0x5c, &dpll);
1011 pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
1012 return 1;
Alan Coxb39b01f2005-06-27 15:24:27 -07001013}
1014
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
1016{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001017 struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
1018 unsigned long io_base = pci_resource_start(dev, 4);
1019 u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */
1020 enum ata_clock clock;
1021
1022 if (info == NULL) {
1023 printk(KERN_ERR "%s: out of memory!\n", name);
1024 return -ENOMEM;
1025 }
1026
1027 /*
1028 * Copy everything from a static "template" structure
1029 * to just allocated per-chip hpt_info structure.
1030 */
1031 *info = *(struct hpt_info *)pci_get_drvdata(dev);
1032
Linus Torvalds9ec4ff42005-09-11 09:22:50 -07001033 /*
1034 * FIXME: Not portable. Also, why do we enable the ROM in the first place?
1035 * We don't seem to be using it.
1036 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 if (dev->resource[PCI_ROM_RESOURCE].start)
Linus Torvalds9ec4ff42005-09-11 09:22:50 -07001038 pci_write_config_dword(dev, PCI_ROM_ADDRESS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
1040
Alan Coxb39b01f2005-06-27 15:24:27 -07001041 pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
1042 pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
1043 pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
1044 pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001046 /*
1047 * First, try to estimate the PCI clock frequency...
1048 */
1049 if (info->chip_type >= HPT370) {
1050 u8 scr1 = 0;
1051 u16 f_cnt = 0;
1052 u32 temp = 0;
Alan Coxb39b01f2005-06-27 15:24:27 -07001053
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001054 /* Interrupt force enable. */
1055 pci_read_config_byte(dev, 0x5a, &scr1);
1056 if (scr1 & 0x10)
1057 pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001058
1059 /*
1060 * HighPoint does this for HPT372A.
1061 * NOTE: This register is only writeable via I/O space.
1062 */
1063 if (info->chip_type == HPT372A)
1064 outb(0x0e, io_base + 0x9c);
1065
1066 /*
1067 * Default to PCI clock. Make sure MA15/16 are set to output
1068 * to prevent drives having problems with 40-pin cables.
1069 */
1070 pci_write_config_byte(dev, 0x5b, 0x23);
1071
1072 /*
1073 * We'll have to read f_CNT value in order to determine
1074 * the PCI clock frequency according to the following ratio:
1075 *
1076 * f_CNT = Fpci * 192 / Fdpll
1077 *
1078 * First try reading the register in which the HighPoint BIOS
1079 * saves f_CNT value before reprogramming the DPLL from its
1080 * default setting (which differs for the various chips).
1081 * NOTE: This register is only accessible via I/O space.
1082 *
1083 * In case the signature check fails, we'll have to resort to
1084 * reading the f_CNT register itself in hopes that nobody has
1085 * touched the DPLL yet...
1086 */
1087 temp = inl(io_base + 0x90);
1088 if ((temp & 0xFFFFF000) != 0xABCDE000) {
1089 int i;
1090
1091 printk(KERN_WARNING "%s: no clock data saved by BIOS\n",
1092 name);
1093
1094 /* Calculate the average value of f_CNT. */
1095 for (temp = i = 0; i < 128; i++) {
1096 pci_read_config_word(dev, 0x78, &f_cnt);
1097 temp += f_cnt & 0x1ff;
1098 mdelay(1);
1099 }
1100 f_cnt = temp / 128;
1101 } else
1102 f_cnt = temp & 0x1ff;
1103
1104 dpll_clk = info->dpll_clk;
1105 pci_clk = (f_cnt * dpll_clk) / 192;
1106
1107 /* Clamp PCI clock to bands. */
1108 if (pci_clk < 40)
1109 pci_clk = 33;
1110 else if(pci_clk < 45)
1111 pci_clk = 40;
1112 else if(pci_clk < 55)
1113 pci_clk = 50;
1114 else
1115 pci_clk = 66;
1116
1117 printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, "
1118 "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk);
1119 } else {
1120 u32 itr1 = 0;
1121
1122 pci_read_config_dword(dev, 0x40, &itr1);
1123
1124 /* Detect PCI clock by looking at cmd_high_time. */
1125 switch((itr1 >> 8) & 0x07) {
1126 case 0x09:
1127 pci_clk = 40;
1128 case 0x05:
1129 pci_clk = 25;
1130 case 0x07:
1131 default:
1132 pci_clk = 33;
1133 }
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001136 /* Let's assume we'll use PCI clock for the ATA clock... */
1137 switch (pci_clk) {
1138 case 25:
1139 clock = ATA_CLOCK_25MHZ;
1140 break;
1141 case 33:
1142 default:
1143 clock = ATA_CLOCK_33MHZ;
1144 break;
1145 case 40:
1146 clock = ATA_CLOCK_40MHZ;
1147 break;
1148 case 50:
1149 clock = ATA_CLOCK_50MHZ;
1150 break;
1151 case 66:
1152 clock = ATA_CLOCK_66MHZ;
1153 break;
1154 }
1155
1156 /*
1157 * Only try the DPLL if we don't have a table for the PCI clock that
1158 * we are running at for HPT370/A, always use it for anything newer...
1159 *
1160 * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
1161 * We also don't like using the DPLL because this causes glitches
1162 * on PRST-/SRST- when the state engine gets reset...
1163 */
1164 if (info->chip_type >= HPT374 || info->settings[clock] == NULL) {
1165 u16 f_low, delta = pci_clk < 50 ? 2 : 4;
1166 int adjust;
1167
1168 /*
1169 * Select 66 MHz DPLL clock only if UltraATA/133 mode is
1170 * supported/enabled, use 50 MHz DPLL clock otherwise...
1171 */
1172 if (info->max_mode == 0x04) {
1173 dpll_clk = 66;
1174 clock = ATA_CLOCK_66MHZ;
1175 } else if (dpll_clk) { /* HPT36x chips don't have DPLL */
1176 dpll_clk = 50;
1177 clock = ATA_CLOCK_50MHZ;
1178 }
1179
1180 if (info->settings[clock] == NULL) {
1181 printk(KERN_ERR "%s: unknown bus timing!\n", name);
1182 kfree(info);
1183 return -EIO;
1184 }
1185
1186 /* Select the DPLL clock. */
1187 pci_write_config_byte(dev, 0x5b, 0x21);
1188
1189 /*
1190 * Adjust the DPLL based upon PCI clock, enable it,
1191 * and wait for stabilization...
1192 */
1193 f_low = (pci_clk * 48) / dpll_clk;
1194
1195 for (adjust = 0; adjust < 8; adjust++) {
1196 if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
1197 break;
1198
1199 /*
1200 * See if it'll settle at a fractionally different clock
1201 */
1202 if (adjust & 1)
1203 f_low -= adjust >> 1;
1204 else
1205 f_low += adjust >> 1;
1206 }
1207 if (adjust == 8) {
1208 printk(KERN_ERR "%s: DPLL did not stabilize!\n", name);
1209 kfree(info);
1210 return -EIO;
1211 }
1212
1213 printk("%s: using %d MHz DPLL clock\n", name, dpll_clk);
1214 } else {
1215 /* Mark the fact that we're not using the DPLL. */
1216 dpll_clk = 0;
1217
1218 printk("%s: using %d MHz PCI clock\n", name, pci_clk);
1219 }
1220
1221 /*
1222 * Advance the table pointer to a slot which points to the list
1223 * of the register values settings matching the clock being used.
1224 */
1225 info->settings += clock;
1226
1227 /* Store the clock frequencies. */
1228 info->dpll_clk = dpll_clk;
1229 info->pci_clk = pci_clk;
1230
1231 /* Point to this chip's own instance of the hpt_info structure. */
1232 pci_set_drvdata(dev, info);
1233
1234 if (info->chip_type >= HPT370) {
1235 u8 mcr1, mcr4;
1236
1237 /*
1238 * Reset the state engines.
1239 * NOTE: Avoid accidentally enabling the disabled channels.
1240 */
1241 pci_read_config_byte (dev, 0x50, &mcr1);
1242 pci_read_config_byte (dev, 0x54, &mcr4);
1243 pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
1244 pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
1245 udelay(100);
1246 }
1247
1248 /*
1249 * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
1250 * the MISC. register to stretch the UltraDMA Tss timing.
1251 * NOTE: This register is only writeable via I/O space.
1252 */
1253 if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
1254
1255 outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
1256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 return dev->irq;
1258}
1259
1260static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
1261{
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001262 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001263 struct hpt_info *info = pci_get_drvdata(dev);
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001264 int serialize = HPT_SERIALIZE_IO;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001265 u8 scr1 = 0, ata66 = (hwif->channel) ? 0x01 : 0x02;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001266 u8 chip_type = info->chip_type;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001267 u8 new_mcr, old_mcr = 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001268
1269 /* Cache the channel's MISC. control registers' offset */
1270 hwif->select_data = hwif->channel ? 0x54 : 0x50;
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 hwif->tuneproc = &hpt3xx_tune_drive;
1273 hwif->speedproc = &hpt3xx_tune_chipset;
1274 hwif->quirkproc = &hpt3xx_quirkproc;
1275 hwif->intrproc = &hpt3xx_intrproc;
1276 hwif->maskproc = &hpt3xx_maskproc;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001277 hwif->busproc = &hpt3xx_busproc;
1278
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001279 /*
1280 * HPT3xxN chips have some complications:
1281 *
1282 * - on 33 MHz PCI we must clock switch
1283 * - on 66 MHz PCI we must NOT use the PCI clock
1284 */
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001285 if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001286 /*
1287 * Clock is shared between the channels,
1288 * so we'll have to serialize them... :-(
1289 */
1290 serialize = 1;
1291 hwif->rw_disk = &hpt3xxn_rw_disk;
1292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001294 /* Serialize access to this device if needed */
1295 if (serialize && hwif->mate)
1296 hwif->serialized = hwif->mate->serialized = 1;
1297
1298 /*
1299 * Disable the "fast interrupt" prediction. Don't hold off
1300 * on interrupts. (== 0x01 despite what the docs say)
1301 */
1302 pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
1303
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001304 if (info->chip_type >= HPT374)
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001305 new_mcr = old_mcr & ~0x07;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001306 else if (info->chip_type >= HPT370) {
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001307 new_mcr = old_mcr;
1308 new_mcr &= ~0x02;
1309
1310#ifdef HPT_DELAY_INTERRUPT
1311 new_mcr &= ~0x01;
1312#else
1313 new_mcr |= 0x01;
1314#endif
1315 } else /* HPT366 and HPT368 */
1316 new_mcr = old_mcr & ~0x80;
1317
1318 if (new_mcr != old_mcr)
1319 pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
1320
1321 if (!hwif->dma_base) {
1322 hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
1323 return;
1324 }
1325
1326 hwif->ultra_mask = 0x7f;
1327 hwif->mwdma_mask = 0x07;
1328
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 /*
1330 * The HPT37x uses the CBLID pins as outputs for MA15/MA16
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001331 * address lines to access an external EEPROM. To read valid
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 * cable detect state the pins must be enabled as inputs.
1333 */
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001334 if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 /*
1336 * HPT374 PCI function 1
1337 * - set bit 15 of reg 0x52 to enable TCBLID as input
1338 * - set bit 15 of reg 0x56 to enable FCBLID as input
1339 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001340 u8 mcr_addr = hwif->select_data + 2;
1341 u16 mcr;
1342
1343 pci_read_config_word (dev, mcr_addr, &mcr);
1344 pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 /* now read cable id register */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001346 pci_read_config_byte (dev, 0x5a, &scr1);
1347 pci_write_config_word(dev, mcr_addr, mcr);
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001348 } else if (chip_type >= HPT370) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 /*
1350 * HPT370/372 and 374 pcifn 0
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001351 * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001353 u8 scr2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001355 pci_read_config_byte (dev, 0x5b, &scr2);
1356 pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
1357 /* now read cable id register */
1358 pci_read_config_byte (dev, 0x5a, &scr1);
1359 pci_write_config_byte(dev, 0x5b, scr2);
1360 } else
1361 pci_read_config_byte (dev, 0x5a, &scr1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001363 if (!hwif->udma_four)
1364 hwif->udma_four = (scr1 & ata66) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001366 hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001368 if (chip_type >= HPT374) {
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001369 hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
1370 hwif->ide_dma_end = &hpt374_ide_dma_end;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001371 } else if (chip_type >= HPT370) {
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001372 hwif->dma_start = &hpt370_ide_dma_start;
1373 hwif->ide_dma_end = &hpt370_ide_dma_end;
1374 hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001375 } else
1376 hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
1378 if (!noautodma)
1379 hwif->autodma = 1;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001380 hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381}
1382
1383static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
1384{
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001385 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001386 u8 masterdma = 0, slavedma = 0;
1387 u8 dma_new = 0, dma_old = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 unsigned long flags;
1389
1390 if (!dmabase)
1391 return;
1392
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001393 dma_old = hwif->INB(dmabase + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
1395 local_irq_save(flags);
1396
1397 dma_new = dma_old;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001398 pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
1399 pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
1401 if (masterdma & 0x30) dma_new |= 0x20;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001402 if ( slavedma & 0x30) dma_new |= 0x40;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 if (dma_new != dma_old)
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001404 hwif->OUTB(dma_new, dmabase + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
1406 local_irq_restore(flags);
1407
1408 ide_setup_dma(hwif, dmabase, 8);
1409}
1410
1411static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
1412{
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001413 struct pci_dev *dev2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
1415 if (PCI_FUNC(dev->devfn) & 1)
1416 return -ENODEV;
1417
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001418 pci_set_drvdata(dev, &hpt374);
1419
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001420 if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
1421 int ret;
1422
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001423 pci_set_drvdata(dev2, &hpt374);
1424
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001425 if (dev2->irq != dev->irq) {
1426 /* FIXME: we need a core pci_set_interrupt() */
1427 dev2->irq = dev->irq;
1428 printk(KERN_WARNING "%s: PCI config space interrupt "
1429 "fixed.\n", d->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 }
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001431 ret = ide_setup_pci_devices(dev, dev2, d);
1432 if (ret < 0)
1433 pci_dev_put(dev2);
1434 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 }
1436 return ide_setup_pci_device(dev, d);
1437}
1438
Sergei Shtylyov90778572007-02-07 18:17:51 +01001439static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001441 pci_set_drvdata(dev, &hpt372n);
1442
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 return ide_setup_pci_device(dev, d);
1444}
1445
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001446static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
1447{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001448 struct hpt_info *info;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001449 u8 rev = 0, mcr1 = 0;
1450
1451 pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
1452
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001453 if (rev > 1) {
Sergei Shtylyov90778572007-02-07 18:17:51 +01001454 d->name = "HPT371N";
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001455
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001456 info = &hpt371n;
1457 } else
1458 info = &hpt371;
1459
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001460 /*
1461 * HPT371 chips physically have only one channel, the secondary one,
1462 * but the primary channel registers do exist! Go figure...
1463 * So, we manually disable the non-existing channel here
1464 * (if the BIOS hasn't done this already).
1465 */
1466 pci_read_config_byte(dev, 0x50, &mcr1);
1467 if (mcr1 & 0x04)
Sergei Shtylyov90778572007-02-07 18:17:51 +01001468 pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
1469
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001470 pci_set_drvdata(dev, info);
1471
Sergei Shtylyov90778572007-02-07 18:17:51 +01001472 return ide_setup_pci_device(dev, d);
1473}
1474
1475static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
1476{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001477 struct hpt_info *info;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001478 u8 rev = 0;
1479
1480 pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
1481
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001482 if (rev > 1) {
Sergei Shtylyov90778572007-02-07 18:17:51 +01001483 d->name = "HPT372N";
1484
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001485 info = &hpt372n;
1486 } else
1487 info = &hpt372a;
1488 pci_set_drvdata(dev, info);
1489
Sergei Shtylyov90778572007-02-07 18:17:51 +01001490 return ide_setup_pci_device(dev, d);
1491}
1492
1493static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
1494{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001495 struct hpt_info *info;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001496 u8 rev = 0;
1497
1498 pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
1499
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001500 if (rev > 1) {
Sergei Shtylyov90778572007-02-07 18:17:51 +01001501 d->name = "HPT302N";
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001502
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001503 info = &hpt302n;
1504 } else
1505 info = &hpt302;
1506 pci_set_drvdata(dev, info);
1507
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001508 return ide_setup_pci_device(dev, d);
1509}
1510
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
1512{
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001513 struct pci_dev *dev2;
1514 u8 rev = 0;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001515 static char *chipset_names[] = { "HPT366", "HPT366", "HPT368",
1516 "HPT370", "HPT370A", "HPT372",
1517 "HPT372N" };
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001518 static struct hpt_info *info[] = { &hpt36x, &hpt36x, &hpt36x,
1519 &hpt370, &hpt370a, &hpt372,
1520 &hpt372n };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
1522 if (PCI_FUNC(dev->devfn) & 1)
1523 return -ENODEV;
1524
Sergei Shtylyove139b0b2007-02-07 18:17:37 +01001525 pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
Sergei Shtylyov90778572007-02-07 18:17:51 +01001527 if (rev > 6)
Sergei Shtylyove139b0b2007-02-07 18:17:37 +01001528 rev = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
Sergei Shtylyov90778572007-02-07 18:17:51 +01001530 d->name = chipset_names[rev];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001532 pci_set_drvdata(dev, info[rev]);
1533
Sergei Shtylyov90778572007-02-07 18:17:51 +01001534 if (rev > 2)
1535 goto init_single;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 d->channels = 1;
1538
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001539 if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
1540 u8 pin1 = 0, pin2 = 0;
1541 int ret;
1542
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001543 pci_set_drvdata(dev2, info[rev]);
1544
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001545 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
1546 pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
1547 if (pin1 != pin2 && dev->irq == dev2->irq) {
1548 d->bootable = ON_BOARD;
1549 printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
1550 d->name, pin1, pin2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 }
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001552 ret = ide_setup_pci_devices(dev, dev2, d);
1553 if (ret < 0)
1554 pci_dev_put(dev2);
1555 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 }
1557init_single:
1558 return ide_setup_pci_device(dev, d);
1559}
1560
1561static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
1562 { /* 0 */
1563 .name = "HPT366",
1564 .init_setup = init_setup_hpt366,
1565 .init_chipset = init_chipset_hpt366,
1566 .init_hwif = init_hwif_hpt366,
1567 .init_dma = init_dma_hpt366,
1568 .channels = 2,
1569 .autodma = AUTODMA,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001570 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 .bootable = OFF_BOARD,
1572 .extra = 240
1573 },{ /* 1 */
1574 .name = "HPT372A",
Sergei Shtylyov90778572007-02-07 18:17:51 +01001575 .init_setup = init_setup_hpt372a,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 .init_chipset = init_chipset_hpt366,
1577 .init_hwif = init_hwif_hpt366,
1578 .init_dma = init_dma_hpt366,
1579 .channels = 2,
1580 .autodma = AUTODMA,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001581 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 .bootable = OFF_BOARD,
Sergei Shtylyov90778572007-02-07 18:17:51 +01001583 .extra = 240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 },{ /* 2 */
1585 .name = "HPT302",
Sergei Shtylyov90778572007-02-07 18:17:51 +01001586 .init_setup = init_setup_hpt302,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 .init_chipset = init_chipset_hpt366,
1588 .init_hwif = init_hwif_hpt366,
1589 .init_dma = init_dma_hpt366,
1590 .channels = 2,
1591 .autodma = AUTODMA,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001592 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 .bootable = OFF_BOARD,
Sergei Shtylyov90778572007-02-07 18:17:51 +01001594 .extra = 240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 },{ /* 3 */
1596 .name = "HPT371",
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001597 .init_setup = init_setup_hpt371,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 .init_chipset = init_chipset_hpt366,
1599 .init_hwif = init_hwif_hpt366,
1600 .init_dma = init_dma_hpt366,
1601 .channels = 2,
1602 .autodma = AUTODMA,
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001603 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 .bootable = OFF_BOARD,
Sergei Shtylyov90778572007-02-07 18:17:51 +01001605 .extra = 240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 },{ /* 4 */
1607 .name = "HPT374",
1608 .init_setup = init_setup_hpt374,
1609 .init_chipset = init_chipset_hpt366,
1610 .init_hwif = init_hwif_hpt366,
1611 .init_dma = init_dma_hpt366,
1612 .channels = 2, /* 4 */
1613 .autodma = AUTODMA,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001614 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 .bootable = OFF_BOARD,
Sergei Shtylyov90778572007-02-07 18:17:51 +01001616 .extra = 240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 },{ /* 5 */
1618 .name = "HPT372N",
Sergei Shtylyov90778572007-02-07 18:17:51 +01001619 .init_setup = init_setup_hpt372n,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 .init_chipset = init_chipset_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 .init_hwif = init_hwif_hpt366,
1622 .init_dma = init_dma_hpt366,
1623 .channels = 2, /* 4 */
1624 .autodma = AUTODMA,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001625 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 .bootable = OFF_BOARD,
Sergei Shtylyov90778572007-02-07 18:17:51 +01001627 .extra = 240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 }
1629};
1630
1631/**
1632 * hpt366_init_one - called when an HPT366 is found
1633 * @dev: the hpt366 device
1634 * @id: the matching pci id
1635 *
1636 * Called when the PCI registration layer (or the IDE initialization)
1637 * finds a device matching our IDE device tables.
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -08001638 *
1639 * NOTE: since we'll have to modify some fields of the ide_pci_device_t
1640 * structure depending on the chip's revision, we'd better pass a local
1641 * copy down the call chain...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
1644{
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -08001645 ide_pci_device_t d = hpt366_chipsets[id->driver_data];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -08001647 return d.init_setup(dev, &d);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648}
1649
1650static struct pci_device_id hpt366_pci_tbl[] = {
1651 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1652 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
1653 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
1654 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
1655 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
1656 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
1657 { 0, },
1658};
1659MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
1660
1661static struct pci_driver driver = {
1662 .name = "HPT366_IDE",
1663 .id_table = hpt366_pci_tbl,
1664 .probe = hpt366_init_one,
1665};
1666
Bartlomiej Zolnierkiewicz82ab1ee2007-01-27 13:46:56 +01001667static int __init hpt366_ide_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668{
1669 return ide_pci_register_driver(&driver);
1670}
1671
1672module_init(hpt366_ide_init);
1673
1674MODULE_AUTHOR("Andre Hedrick");
1675MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
1676MODULE_LICENSE("GPL");