blob: 3d8d6b2ee41a35222c2c67d476607ba3243b3401 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Sergei Shtylyovb4e44362007-10-11 23:53:58 +02002 * linux/drivers/ide/pci/hpt366.c Version 1.13 Sep 29, 2007
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 Shtylyov38b66f82007-04-20 22:16:58 +02007 * Portions Copyright (C) 2005-2007 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
Sergei Shtylyov72931362007-09-11 22:28:35 +020071 * the wrong PCI frequency since DPLL has already been calibrated by BIOS;
72 * read it only from the function 0 of HPT374 chips
Sergei Shtylyov33b18a62006-12-13 00:35:50 -080073 * - fix the hotswap code: it caused RESET- to glitch when tristating the bus,
74 * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -080075 * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
76 * they tamper with its fields
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +010077 * - pass to the init_setup handlers a copy of the ide_pci_device_t structure
78 * since they may 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 Shtylyov2648e5d2007-07-09 23:17:55 +020081 * - optimize the UltraDMA 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 Shtylyov7b73ee02007-02-07 18:18:16 +010083 * - cache offset of the channel's misc. control registers (MCRs) being used
84 * throughout the driver
85 * - only touch the relevant MCR when detecting the cable type on HPT374's
86 * function 1
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +010087 * - rename all the register related variables consistently
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +010088 * - move all the interrupt twiddling code from the speedproc handlers into
89 * init_hwif_hpt366(), also grouping all the DMA related code together there
90 * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
91 * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
92 * when setting an UltraDMA mode
93 * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
94 * the best possible one
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +010095 * - clean up DMA timeout handling for HPT370
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +010096 * - switch to using the enumeration type to differ between the numerous chip
97 * variants, matching PCI device/revision ID with the chip type early, at the
98 * init_setup stage
99 * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
100 * stop duplicating it for each channel by storing the pointer in the pci_dev
101 * structure: first, at the init_setup stage, point it to a static "template"
102 * with only the chip type and its specific base DPLL frequency, the highest
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200103 * UltraDMA mode, and the chip settings table pointer filled, then, at the
104 * init_chipset stage, allocate per-chip instance and fill it with the rest
105 * of the necessary information
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100106 * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
107 * switch to calculating PCI clock frequency based on the chip's base DPLL
108 * frequency
109 * - switch to using the DPLL clock and enable UltraATA/133 mode by default on
Sergei Shtylyov278978e2007-06-08 15:14:32 +0200110 * anything newer than HPT370/A (except HPT374 that is not capable of this
111 * mode according to the manual)
Sergei Shtylyov6273d262007-02-07 18:18:20 +0100112 * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(),
113 * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100114 * unify HPT36x/37x timing setup code and the speedproc handlers by joining
115 * the register setting lists into the table indexed by the clock selected
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200116 * - set the correct hwif->ultra_mask for each individual chip
Sergei Shtylyovb4e44362007-10-11 23:53:58 +0200117 * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100118 * Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 */
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#include <linux/types.h>
122#include <linux/module.h>
123#include <linux/kernel.h>
124#include <linux/delay.h>
125#include <linux/timer.h>
126#include <linux/mm.h>
127#include <linux/ioport.h>
128#include <linux/blkdev.h>
129#include <linux/hdreg.h>
130
131#include <linux/interrupt.h>
132#include <linux/pci.h>
133#include <linux/init.h>
134#include <linux/ide.h>
135
136#include <asm/uaccess.h>
137#include <asm/io.h>
138#include <asm/irq.h>
139
140/* various tuning parameters */
141#define HPT_RESET_STATE_ENGINE
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800142#undef HPT_DELAY_INTERRUPT
143#define HPT_SERIALIZE_IO 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145static const char *quirk_drives[] = {
146 "QUANTUM FIREBALLlct08 08",
147 "QUANTUM FIREBALLP KA6.4",
148 "QUANTUM FIREBALLP LM20.4",
149 "QUANTUM FIREBALLP LM20.5",
150 NULL
151};
152
153static const char *bad_ata100_5[] = {
154 "IBM-DTLA-307075",
155 "IBM-DTLA-307060",
156 "IBM-DTLA-307045",
157 "IBM-DTLA-307030",
158 "IBM-DTLA-307020",
159 "IBM-DTLA-307015",
160 "IBM-DTLA-305040",
161 "IBM-DTLA-305030",
162 "IBM-DTLA-305020",
163 "IC35L010AVER07-0",
164 "IC35L020AVER07-0",
165 "IC35L030AVER07-0",
166 "IC35L040AVER07-0",
167 "IC35L060AVER07-0",
168 "WDC AC310200R",
169 NULL
170};
171
172static const char *bad_ata66_4[] = {
173 "IBM-DTLA-307075",
174 "IBM-DTLA-307060",
175 "IBM-DTLA-307045",
176 "IBM-DTLA-307030",
177 "IBM-DTLA-307020",
178 "IBM-DTLA-307015",
179 "IBM-DTLA-305040",
180 "IBM-DTLA-305030",
181 "IBM-DTLA-305020",
182 "IC35L010AVER07-0",
183 "IC35L020AVER07-0",
184 "IC35L030AVER07-0",
185 "IC35L040AVER07-0",
186 "IC35L060AVER07-0",
187 "WDC AC310200R",
Sergei Shtylyov783353b2007-07-03 22:28:35 +0200188 "MAXTOR STM3320620A",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 NULL
190};
191
192static const char *bad_ata66_3[] = {
193 "WDC AC310200R",
194 NULL
195};
196
197static const char *bad_ata33[] = {
198 "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
199 "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
200 "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
201 "Maxtor 90510D4",
202 "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
203 "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
204 "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
205 NULL
206};
207
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800208static u8 xfer_speeds[] = {
209 XFER_UDMA_6,
210 XFER_UDMA_5,
211 XFER_UDMA_4,
212 XFER_UDMA_3,
213 XFER_UDMA_2,
214 XFER_UDMA_1,
215 XFER_UDMA_0,
216
217 XFER_MW_DMA_2,
218 XFER_MW_DMA_1,
219 XFER_MW_DMA_0,
220
221 XFER_PIO_4,
222 XFER_PIO_3,
223 XFER_PIO_2,
224 XFER_PIO_1,
225 XFER_PIO_0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226};
227
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800228/* Key for bus clock timings
229 * 36x 37x
230 * bits bits
231 * 0:3 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
232 * cycles = value + 1
233 * 4:7 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
234 * cycles = value + 1
235 * 8:11 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
236 * register access.
237 * 12:15 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
238 * register access.
239 * 16:18 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
240 * - 21 CLK frequency: 0=ATA clock, 1=dual ATA clock.
241 * 19:21 22:24 pre_high_time. Time to initialize the 1st cycle for PIO and
242 * MW DMA xfer.
243 * 22:24 25:27 cmd_pre_high_time. Time to initialize the 1st PIO cycle for
244 * task file register access.
245 * 28 28 UDMA enable.
246 * 29 29 DMA enable.
247 * 30 30 PIO MST enable. If set, the chip is in bus master mode during
248 * PIO xfer.
249 * 31 31 FIFO enable.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800252static u32 forty_base_hpt36x[] = {
253 /* XFER_UDMA_6 */ 0x900fd943,
254 /* XFER_UDMA_5 */ 0x900fd943,
255 /* XFER_UDMA_4 */ 0x900fd943,
256 /* XFER_UDMA_3 */ 0x900ad943,
257 /* XFER_UDMA_2 */ 0x900bd943,
258 /* XFER_UDMA_1 */ 0x9008d943,
259 /* XFER_UDMA_0 */ 0x9008d943,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800261 /* XFER_MW_DMA_2 */ 0xa008d943,
262 /* XFER_MW_DMA_1 */ 0xa010d955,
263 /* XFER_MW_DMA_0 */ 0xa010d9fc,
264
265 /* XFER_PIO_4 */ 0xc008d963,
266 /* XFER_PIO_3 */ 0xc010d974,
267 /* XFER_PIO_2 */ 0xc010d997,
268 /* XFER_PIO_1 */ 0xc010d9c7,
269 /* XFER_PIO_0 */ 0xc018d9d9
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270};
271
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800272static u32 thirty_three_base_hpt36x[] = {
273 /* XFER_UDMA_6 */ 0x90c9a731,
274 /* XFER_UDMA_5 */ 0x90c9a731,
275 /* XFER_UDMA_4 */ 0x90c9a731,
276 /* XFER_UDMA_3 */ 0x90cfa731,
277 /* XFER_UDMA_2 */ 0x90caa731,
278 /* XFER_UDMA_1 */ 0x90cba731,
279 /* XFER_UDMA_0 */ 0x90c8a731,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800281 /* XFER_MW_DMA_2 */ 0xa0c8a731,
282 /* XFER_MW_DMA_1 */ 0xa0c8a732, /* 0xa0c8a733 */
283 /* XFER_MW_DMA_0 */ 0xa0c8a797,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800285 /* XFER_PIO_4 */ 0xc0c8a731,
286 /* XFER_PIO_3 */ 0xc0c8a742,
287 /* XFER_PIO_2 */ 0xc0d0a753,
288 /* XFER_PIO_1 */ 0xc0d0a7a3, /* 0xc0d0a793 */
289 /* XFER_PIO_0 */ 0xc0d0a7aa /* 0xc0d0a7a7 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290};
291
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800292static u32 twenty_five_base_hpt36x[] = {
293 /* XFER_UDMA_6 */ 0x90c98521,
294 /* XFER_UDMA_5 */ 0x90c98521,
295 /* XFER_UDMA_4 */ 0x90c98521,
296 /* XFER_UDMA_3 */ 0x90cf8521,
297 /* XFER_UDMA_2 */ 0x90cf8521,
298 /* XFER_UDMA_1 */ 0x90cb8521,
299 /* XFER_UDMA_0 */ 0x90cb8521,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800301 /* XFER_MW_DMA_2 */ 0xa0ca8521,
302 /* XFER_MW_DMA_1 */ 0xa0ca8532,
303 /* XFER_MW_DMA_0 */ 0xa0ca8575,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800305 /* XFER_PIO_4 */ 0xc0ca8521,
306 /* XFER_PIO_3 */ 0xc0ca8532,
307 /* XFER_PIO_2 */ 0xc0ca8542,
308 /* XFER_PIO_1 */ 0xc0d08572,
309 /* XFER_PIO_0 */ 0xc0d08585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310};
311
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800312static u32 thirty_three_base_hpt37x[] = {
313 /* XFER_UDMA_6 */ 0x12446231, /* 0x12646231 ?? */
314 /* XFER_UDMA_5 */ 0x12446231,
315 /* XFER_UDMA_4 */ 0x12446231,
316 /* XFER_UDMA_3 */ 0x126c6231,
317 /* XFER_UDMA_2 */ 0x12486231,
318 /* XFER_UDMA_1 */ 0x124c6233,
319 /* XFER_UDMA_0 */ 0x12506297,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800321 /* XFER_MW_DMA_2 */ 0x22406c31,
322 /* XFER_MW_DMA_1 */ 0x22406c33,
323 /* XFER_MW_DMA_0 */ 0x22406c97,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800325 /* XFER_PIO_4 */ 0x06414e31,
326 /* XFER_PIO_3 */ 0x06414e42,
327 /* XFER_PIO_2 */ 0x06414e53,
328 /* XFER_PIO_1 */ 0x06814e93,
329 /* XFER_PIO_0 */ 0x06814ea7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330};
331
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800332static u32 fifty_base_hpt37x[] = {
333 /* XFER_UDMA_6 */ 0x12848242,
334 /* XFER_UDMA_5 */ 0x12848242,
335 /* XFER_UDMA_4 */ 0x12ac8242,
336 /* XFER_UDMA_3 */ 0x128c8242,
337 /* XFER_UDMA_2 */ 0x120c8242,
338 /* XFER_UDMA_1 */ 0x12148254,
339 /* XFER_UDMA_0 */ 0x121882ea,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800341 /* XFER_MW_DMA_2 */ 0x22808242,
342 /* XFER_MW_DMA_1 */ 0x22808254,
343 /* XFER_MW_DMA_0 */ 0x228082ea,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800345 /* XFER_PIO_4 */ 0x0a81f442,
346 /* XFER_PIO_3 */ 0x0a81f443,
347 /* XFER_PIO_2 */ 0x0a81f454,
348 /* XFER_PIO_1 */ 0x0ac1f465,
349 /* XFER_PIO_0 */ 0x0ac1f48a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350};
351
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800352static u32 sixty_six_base_hpt37x[] = {
353 /* XFER_UDMA_6 */ 0x1c869c62,
354 /* XFER_UDMA_5 */ 0x1cae9c62, /* 0x1c8a9c62 */
355 /* XFER_UDMA_4 */ 0x1c8a9c62,
356 /* XFER_UDMA_3 */ 0x1c8e9c62,
357 /* XFER_UDMA_2 */ 0x1c929c62,
358 /* XFER_UDMA_1 */ 0x1c9a9c62,
359 /* XFER_UDMA_0 */ 0x1c829c62,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800361 /* XFER_MW_DMA_2 */ 0x2c829c62,
362 /* XFER_MW_DMA_1 */ 0x2c829c66,
363 /* XFER_MW_DMA_0 */ 0x2c829d2e,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800365 /* XFER_PIO_4 */ 0x0c829c62,
366 /* XFER_PIO_3 */ 0x0c829c84,
367 /* XFER_PIO_2 */ 0x0c829ca6,
368 /* XFER_PIO_1 */ 0x0d029d26,
369 /* XFER_PIO_0 */ 0x0d029d5e
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370};
371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372#define HPT366_DEBUG_DRIVE_INFO 0
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100373#define HPT371_ALLOW_ATA133_6 1
374#define HPT302_ALLOW_ATA133_6 1
375#define HPT372_ALLOW_ATA133_6 1
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100376#define HPT370_ALLOW_ATA100_5 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377#define HPT366_ALLOW_ATA66_4 1
378#define HPT366_ALLOW_ATA66_3 1
379#define HPT366_MAX_DEVS 8
380
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100381/* Supported ATA clock frequencies */
382enum ata_clock {
383 ATA_CLOCK_25MHZ,
384 ATA_CLOCK_33MHZ,
385 ATA_CLOCK_40MHZ,
386 ATA_CLOCK_50MHZ,
387 ATA_CLOCK_66MHZ,
388 NUM_ATA_CLOCKS
Alan Coxb39b01f2005-06-27 15:24:27 -0700389};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Alan Coxb39b01f2005-06-27 15:24:27 -0700391/*
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100392 * Hold all the HighPoint chip information in one place.
Alan Coxb39b01f2005-06-27 15:24:27 -0700393 */
394
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100395struct hpt_info {
396 u8 chip_type; /* Chip type */
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200397 u8 max_ultra; /* Max. UltraDMA mode allowed */
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100398 u8 dpll_clk; /* DPLL clock in MHz */
399 u8 pci_clk; /* PCI clock in MHz */
400 u32 **settings; /* Chipset settings table */
401};
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100402
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100403/* Supported HighPoint chips */
404enum {
405 HPT36x,
406 HPT370,
407 HPT370A,
408 HPT374,
409 HPT372,
410 HPT372A,
411 HPT302,
412 HPT371,
413 HPT372N,
414 HPT302N,
415 HPT371N
416};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100418static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
419 twenty_five_base_hpt36x,
420 thirty_three_base_hpt36x,
421 forty_base_hpt36x,
422 NULL,
423 NULL
424};
425
426static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
427 NULL,
428 thirty_three_base_hpt37x,
429 NULL,
430 fifty_base_hpt37x,
431 sixty_six_base_hpt37x
432};
433
434static struct hpt_info hpt36x __devinitdata = {
435 .chip_type = HPT36x,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200436 .max_ultra = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? 4 : 3) : 2,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100437 .dpll_clk = 0, /* no DPLL */
438 .settings = hpt36x_settings
439};
440
441static struct hpt_info hpt370 __devinitdata = {
442 .chip_type = HPT370,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200443 .max_ultra = HPT370_ALLOW_ATA100_5 ? 5 : 4,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100444 .dpll_clk = 48,
445 .settings = hpt37x_settings
446};
447
448static struct hpt_info hpt370a __devinitdata = {
449 .chip_type = HPT370A,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200450 .max_ultra = HPT370_ALLOW_ATA100_5 ? 5 : 4,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100451 .dpll_clk = 48,
452 .settings = hpt37x_settings
453};
454
455static struct hpt_info hpt374 __devinitdata = {
456 .chip_type = HPT374,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200457 .max_ultra = 5,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100458 .dpll_clk = 48,
459 .settings = hpt37x_settings
460};
461
462static struct hpt_info hpt372 __devinitdata = {
463 .chip_type = HPT372,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200464 .max_ultra = HPT372_ALLOW_ATA133_6 ? 6 : 5,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100465 .dpll_clk = 55,
466 .settings = hpt37x_settings
467};
468
469static struct hpt_info hpt372a __devinitdata = {
470 .chip_type = HPT372A,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200471 .max_ultra = HPT372_ALLOW_ATA133_6 ? 6 : 5,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100472 .dpll_clk = 66,
473 .settings = hpt37x_settings
474};
475
476static struct hpt_info hpt302 __devinitdata = {
477 .chip_type = HPT302,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200478 .max_ultra = HPT372_ALLOW_ATA133_6 ? 6 : 5,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100479 .dpll_clk = 66,
480 .settings = hpt37x_settings
481};
482
483static struct hpt_info hpt371 __devinitdata = {
484 .chip_type = HPT371,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200485 .max_ultra = HPT371_ALLOW_ATA133_6 ? 6 : 5,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100486 .dpll_clk = 66,
487 .settings = hpt37x_settings
488};
489
490static struct hpt_info hpt372n __devinitdata = {
491 .chip_type = HPT372N,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200492 .max_ultra = HPT372_ALLOW_ATA133_6 ? 6 : 5,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100493 .dpll_clk = 77,
494 .settings = hpt37x_settings
495};
496
497static struct hpt_info hpt302n __devinitdata = {
498 .chip_type = HPT302N,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200499 .max_ultra = HPT302_ALLOW_ATA133_6 ? 6 : 5,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100500 .dpll_clk = 77,
Sergei Shtylyov38b66f82007-04-20 22:16:58 +0200501 .settings = hpt37x_settings
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100502};
503
504static struct hpt_info hpt371n __devinitdata = {
505 .chip_type = HPT371N,
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200506 .max_ultra = HPT371_ALLOW_ATA133_6 ? 6 : 5,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100507 .dpll_clk = 77,
508 .settings = hpt37x_settings
509};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100511static int check_in_drive_list(ide_drive_t *drive, const char **list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100513 struct hd_driveid *id = drive->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100515 while (*list)
516 if (!strcmp(*list++,id->model))
517 return 1;
518 return 0;
519}
Alan Coxb39b01f2005-06-27 15:24:27 -0700520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521/*
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +0200522 * The Marvell bridge chips used on the HighPoint SATA cards do not seem
523 * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 */
Bartlomiej Zolnierkiewicz2d5eaa62007-05-10 00:01:08 +0200525
526static u8 hpt3xx_udma_filter(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +0200528 ide_hwif_t *hwif = HWIF(drive);
529 struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
530 u8 mask = hwif->ultra_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200532 switch (info->chip_type) {
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200533 case HPT36x:
534 if (!HPT366_ALLOW_ATA66_4 ||
535 check_in_drive_list(drive, bad_ata66_4))
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +0200536 mask = ATA_UDMA3;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100537
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200538 if (!HPT366_ALLOW_ATA66_3 ||
539 check_in_drive_list(drive, bad_ata66_3))
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +0200540 mask = ATA_UDMA2;
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200541 break;
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +0200542 case HPT370:
543 if (!HPT370_ALLOW_ATA100_5 ||
544 check_in_drive_list(drive, bad_ata100_5))
545 mask = ATA_UDMA4;
546 break;
547 case HPT370A:
548 if (!HPT370_ALLOW_ATA100_5 ||
549 check_in_drive_list(drive, bad_ata100_5))
550 return ATA_UDMA4;
551 case HPT372 :
552 case HPT372A:
553 case HPT372N:
554 case HPT374 :
555 if (ide_dev_is_sata(drive->id))
556 mask &= ~0x0e;
557 /* Fall thru */
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200558 default:
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +0200559 return mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 }
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +0200561
562 return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563}
564
Sergei Shtylyovb4e44362007-10-11 23:53:58 +0200565static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
566{
567 ide_hwif_t *hwif = HWIF(drive);
568 struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
569
570 switch (info->chip_type) {
571 case HPT372 :
572 case HPT372A:
573 case HPT372N:
574 case HPT374 :
575 if (ide_dev_is_sata(drive->id))
576 return 0x00;
577 /* Fall thru */
578 default:
579 return 0x07;
580 }
581}
582
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100583static u32 get_speed_setting(u8 speed, struct hpt_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
Sergei Shtylyov471a0bd2006-12-13 00:35:49 -0800585 int i;
586
587 /*
588 * Lookup the transfer mode table to get the index into
589 * the timing table.
590 *
591 * NOTE: For XFER_PIO_SLOW, PIO mode 0 timings will be used.
592 */
593 for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
594 if (xfer_speeds[i] == speed)
595 break;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100596 /*
597 * NOTE: info->settings only points to the pointer
598 * to the list of the actual register values
599 */
600 return (*info->settings)[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
603static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
604{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100605 ide_hwif_t *hwif = HWIF(drive);
606 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100607 struct hpt_info *info = pci_get_drvdata(dev);
Bartlomiej Zolnierkiewicz2d5eaa62007-05-10 00:01:08 +0200608 u8 speed = ide_rate_filter(drive, xferspeed);
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100609 u8 itr_addr = drive->dn ? 0x44 : 0x40;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100610 u32 old_itr = 0;
Bartlomiej Zolnierkiewicz2d5eaa62007-05-10 00:01:08 +0200611 u32 itr_mask, new_itr;
612
613 /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
614 if (drive->media != ide_disk)
615 speed = min_t(u8, speed, XFER_PIO_4);
616
617 itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
618 (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff);
619
620 new_itr = get_speed_setting(speed, info);
Alan Coxb39b01f2005-06-27 15:24:27 -0700621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 /*
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100623 * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
624 * to avoid problems handling I/O errors later
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100626 pci_read_config_dword(dev, itr_addr, &old_itr);
627 new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
628 new_itr &= ~0xc0000000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100630 pci_write_config_dword(dev, itr_addr, new_itr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
632 return ide_config_drive_speed(drive, speed);
633}
634
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100635static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100637 ide_hwif_t *hwif = HWIF(drive);
638 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100639 struct hpt_info *info = pci_get_drvdata(dev);
Bartlomiej Zolnierkiewicz2d5eaa62007-05-10 00:01:08 +0200640 u8 speed = ide_rate_filter(drive, xferspeed);
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100641 u8 itr_addr = 0x40 + (drive->dn * 4);
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100642 u32 old_itr = 0;
Bartlomiej Zolnierkiewicz2d5eaa62007-05-10 00:01:08 +0200643 u32 itr_mask, new_itr;
644
645 /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
646 if (drive->media != ide_disk)
647 speed = min_t(u8, speed, XFER_PIO_4);
648
649 itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
650 (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff);
651
652 new_itr = get_speed_setting(speed, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100654 pci_read_config_dword(dev, itr_addr, &old_itr);
655 new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Alan Coxb39b01f2005-06-27 15:24:27 -0700657 if (speed < XFER_MW_DMA_0)
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100658 new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
659 pci_write_config_dword(dev, itr_addr, new_itr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661 return ide_config_drive_speed(drive, speed);
662}
663
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100664static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100666 ide_hwif_t *hwif = HWIF(drive);
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100667 struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100669 if (info->chip_type >= HPT370)
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100670 return hpt37x_tune_chipset(drive, speed);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 else /* hpt368: hpt_minimum_revision(dev, 2) */
672 return hpt36x_tune_chipset(drive, speed);
673}
674
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100675static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676{
Bartlomiej Zolnierkiewicz21347582007-07-20 01:11:58 +0200677 pio = ide_get_best_pio_mode(drive, pio, 4);
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100678 (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679}
680
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100681static int hpt3xx_quirkproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
Sergei Shtylyove139b0b2007-02-07 18:17:37 +0100683 struct hd_driveid *id = drive->id;
684 const char **list = quirk_drives;
685
686 while (*list)
687 if (strstr(id->model, *list++))
688 return 1;
689 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690}
691
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100692static void hpt3xx_intrproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100694 ide_hwif_t *hwif = HWIF(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
696 if (drive->quirk_list)
697 return;
698 /* drives in the quirk_list may not like intr setups/cleanups */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100699 hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700}
701
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100702static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100704 ide_hwif_t *hwif = HWIF(drive);
705 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100706 struct hpt_info *info = pci_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 if (drive->quirk_list) {
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100709 if (info->chip_type >= HPT370) {
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100710 u8 scr1 = 0;
711
712 pci_read_config_byte(dev, 0x5a, &scr1);
713 if (((scr1 & 0x10) >> 4) != mask) {
714 if (mask)
715 scr1 |= 0x10;
716 else
717 scr1 &= ~0x10;
718 pci_write_config_byte(dev, 0x5a, scr1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 }
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100720 } else {
721 if (mask)
722 disable_irq(hwif->irq);
723 else
724 enable_irq (hwif->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 }
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100726 } else
727 hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
728 IDE_CONTROL_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729}
730
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100731static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 drive->init_speed = 0;
734
Bartlomiej Zolnierkiewicz29e744d2007-05-10 00:01:09 +0200735 if (ide_tune_dma(drive))
Bartlomiej Zolnierkiewicz3608b5d2007-02-17 02:40:26 +0100736 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Bartlomiej Zolnierkiewiczd8f44692007-02-17 02:40:25 +0100738 if (ide_use_fast_pio(drive))
Sergei Shtylyov26ccb802007-02-07 18:18:11 +0100739 hpt3xx_tune_drive(drive, 255);
Bartlomiej Zolnierkiewiczd8f44692007-02-17 02:40:25 +0100740
Bartlomiej Zolnierkiewicz3608b5d2007-02-17 02:40:26 +0100741 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
744/*
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100745 * This is specific to the HPT366 UDMA chipset
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 * by HighPoint|Triones Technologies, Inc.
747 */
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200748static void hpt366_dma_lost_irq(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100750 struct pci_dev *dev = HWIF(drive)->pci_dev;
751 u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100753 pci_read_config_byte(dev, 0x50, &mcr1);
754 pci_read_config_byte(dev, 0x52, &mcr3);
755 pci_read_config_byte(dev, 0x5a, &scr1);
756 printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
757 drive->name, __FUNCTION__, mcr1, mcr3, scr1);
758 if (scr1 & 0x10)
759 pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200760 ide_dma_lost_irq(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761}
762
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100763static void hpt370_clear_engine(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100765 ide_hwif_t *hwif = HWIF(drive);
766
767 pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 udelay(10);
769}
770
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100771static void hpt370_irq_timeout(ide_drive_t *drive)
772{
773 ide_hwif_t *hwif = HWIF(drive);
774 u16 bfifo = 0;
775 u8 dma_cmd;
776
777 pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
778 printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
779
780 /* get DMA command mode */
781 dma_cmd = hwif->INB(hwif->dma_command);
782 /* stop DMA */
783 hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
784 hpt370_clear_engine(drive);
785}
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787static void hpt370_ide_dma_start(ide_drive_t *drive)
788{
789#ifdef HPT_RESET_STATE_ENGINE
790 hpt370_clear_engine(drive);
791#endif
792 ide_dma_start(drive);
793}
794
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100795static int hpt370_ide_dma_end(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
797 ide_hwif_t *hwif = HWIF(drive);
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100798 u8 dma_stat = hwif->INB(hwif->dma_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 if (dma_stat & 0x01) {
801 /* wait a little */
802 udelay(20);
803 dma_stat = hwif->INB(hwif->dma_status);
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100804 if (dma_stat & 0x01)
805 hpt370_irq_timeout(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 return __ide_dma_end(drive);
808}
809
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200810static void hpt370_dma_timeout(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811{
Sergei Shtylyov4bf63de2007-02-07 18:18:13 +0100812 hpt370_irq_timeout(drive);
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200813 ide_dma_timeout(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814}
815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816/* returns 1 if DMA IRQ issued, 0 otherwise */
817static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
818{
819 ide_hwif_t *hwif = HWIF(drive);
820 u16 bfifo = 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100821 u8 dma_stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100823 pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 if (bfifo & 0x1FF) {
825// printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
826 return 0;
827 }
828
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100829 dma_stat = inb(hwif->dma_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 /* return 1 if INTR asserted */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100831 if (dma_stat & 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return 1;
833
834 if (!drive->waiting_for_dma)
835 printk(KERN_WARNING "%s: (%s) called while not waiting\n",
836 drive->name, __FUNCTION__);
837 return 0;
838}
839
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100840static int hpt374_ide_dma_end(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 ide_hwif_t *hwif = HWIF(drive);
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100843 struct pci_dev *dev = hwif->pci_dev;
844 u8 mcr = 0, mcr_addr = hwif->select_data;
845 u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100847 pci_read_config_byte(dev, 0x6a, &bwsr);
848 pci_read_config_byte(dev, mcr_addr, &mcr);
849 if (bwsr & mask)
850 pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 return __ide_dma_end(drive);
852}
853
854/**
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800855 * hpt3xxn_set_clock - perform clock switching dance
856 * @hwif: hwif to switch
857 * @mode: clocking mode (0x21 for write, 0x23 otherwise)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 *
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800859 * Switch the DPLL clock on the HPT3xxN devices. This is a right mess.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800861
862static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100864 u8 scr2 = hwif->INB(hwif->dma_master + 0x7b);
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800865
866 if ((scr2 & 0x7f) == mode)
867 return;
868
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 /* Tristate the bus */
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100870 hwif->OUTB(0x80, hwif->dma_master + 0x73);
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800871 hwif->OUTB(0x80, hwif->dma_master + 0x77);
872
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 /* Switch clock and reset channels */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800874 hwif->OUTB(mode, hwif->dma_master + 0x7b);
875 hwif->OUTB(0xc0, hwif->dma_master + 0x79);
876
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100877 /*
878 * Reset the state machines.
879 * NOTE: avoid accidentally enabling the disabled channels.
880 */
881 hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32,
882 hwif->dma_master + 0x70);
883 hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32,
884 hwif->dma_master + 0x74);
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 /* Complete reset */
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800887 hwif->OUTB(0x00, hwif->dma_master + 0x79);
888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 /* Reconnect channels to bus */
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100890 hwif->OUTB(0x00, hwif->dma_master + 0x73);
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800891 hwif->OUTB(0x00, hwif->dma_master + 0x77);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892}
893
894/**
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800895 * hpt3xxn_rw_disk - prepare for I/O
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 * @drive: drive for command
897 * @rq: block request structure
898 *
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800899 * This is called when a disk I/O is issued to HPT3xxN.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 * We need it because of the clock switching.
901 */
902
Sergei Shtylyov836c0062006-12-13 00:35:47 -0800903static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100905 hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906}
907
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908/*
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800909 * Set/get power state for a drive.
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100910 * NOTE: affects both drives on each channel.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 *
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800912 * When we turn the power back on, we need to re-initialize things.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 */
914#define TRISTATE_BIT 0x8000
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800915
916static int hpt3xx_busproc(ide_drive_t *drive, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917{
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100918 ide_hwif_t *hwif = HWIF(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100920 u8 mcr_addr = hwif->select_data + 2;
921 u8 resetmask = hwif->channel ? 0x80 : 0x40;
922 u8 bsr2 = 0;
923 u16 mcr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
925 hwif->bus_state = state;
926
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800927 /* Grab the status. */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100928 pci_read_config_word(dev, mcr_addr, &mcr);
929 pci_read_config_byte(dev, 0x59, &bsr2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800931 /*
932 * Set the state. We don't set it if we don't need to do so.
933 * Make sure that the drive knows that it has failed if it's off.
934 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 switch (state) {
936 case BUSSTATE_ON:
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100937 if (!(bsr2 & resetmask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 return 0;
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800939 hwif->drives[0].failures = hwif->drives[1].failures = 0;
940
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100941 pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask);
942 pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT);
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800943 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 case BUSSTATE_OFF:
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100945 if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 return 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100947 mcr &= ~TRISTATE_BIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 break;
949 case BUSSTATE_TRISTATE:
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100950 if ((bsr2 & resetmask) && (mcr & TRISTATE_BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 return 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100952 mcr |= TRISTATE_BIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 break;
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800954 default:
955 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Sergei Shtylyov33b18a62006-12-13 00:35:50 -0800958 hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
959 hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
960
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +0100961 pci_write_config_word(dev, mcr_addr, mcr);
962 pci_write_config_byte(dev, 0x59, bsr2 | resetmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 return 0;
964}
965
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100966/**
967 * hpt37x_calibrate_dpll - calibrate the DPLL
968 * @dev: PCI device
969 *
970 * Perform a calibration cycle on the DPLL.
971 * Returns 1 if this succeeds
972 */
973static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100975 u32 dpll = (f_high << 16) | f_low | 0x100;
976 u8 scr2;
977 int i;
Alan Coxb39b01f2005-06-27 15:24:27 -0700978
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100979 pci_write_config_dword(dev, 0x5c, dpll);
Alan Coxb39b01f2005-06-27 15:24:27 -0700980
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100981 /* Wait for oscillator ready */
982 for(i = 0; i < 0x5000; ++i) {
983 udelay(50);
984 pci_read_config_byte(dev, 0x5b, &scr2);
985 if (scr2 & 0x80)
Alan Coxb39b01f2005-06-27 15:24:27 -0700986 break;
987 }
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100988 /* See if it stays ready (we'll just bail out if it's not yet) */
989 for(i = 0; i < 0x1000; ++i) {
990 pci_read_config_byte(dev, 0x5b, &scr2);
991 /* DPLL destabilized? */
992 if(!(scr2 & 0x80))
993 return 0;
Sergei Shtylyov90778572007-02-07 18:17:51 +0100994 }
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +0100995 /* Turn off tuning, we have the DPLL set */
996 pci_read_config_dword (dev, 0x5c, &dpll);
997 pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
998 return 1;
Alan Coxb39b01f2005-06-27 15:24:27 -0700999}
1000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
1002{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001003 struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
1004 unsigned long io_base = pci_resource_start(dev, 4);
1005 u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */
Sergei Shtylyov72931362007-09-11 22:28:35 +02001006 u8 chip_type;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001007 enum ata_clock clock;
1008
1009 if (info == NULL) {
1010 printk(KERN_ERR "%s: out of memory!\n", name);
1011 return -ENOMEM;
1012 }
1013
1014 /*
1015 * Copy everything from a static "template" structure
1016 * to just allocated per-chip hpt_info structure.
1017 */
Sergei Shtylyov72931362007-09-11 22:28:35 +02001018 memcpy(info, pci_get_drvdata(dev), sizeof(struct hpt_info));
1019 chip_type = info->chip_type;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001020
Alan Coxb39b01f2005-06-27 15:24:27 -07001021 pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
1022 pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
1023 pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
1024 pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001026 /*
1027 * First, try to estimate the PCI clock frequency...
1028 */
Sergei Shtylyov72931362007-09-11 22:28:35 +02001029 if (chip_type >= HPT370) {
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001030 u8 scr1 = 0;
1031 u16 f_cnt = 0;
1032 u32 temp = 0;
Alan Coxb39b01f2005-06-27 15:24:27 -07001033
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001034 /* Interrupt force enable. */
1035 pci_read_config_byte(dev, 0x5a, &scr1);
1036 if (scr1 & 0x10)
1037 pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001038
1039 /*
1040 * HighPoint does this for HPT372A.
1041 * NOTE: This register is only writeable via I/O space.
1042 */
Sergei Shtylyov72931362007-09-11 22:28:35 +02001043 if (chip_type == HPT372A)
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001044 outb(0x0e, io_base + 0x9c);
1045
1046 /*
1047 * Default to PCI clock. Make sure MA15/16 are set to output
1048 * to prevent drives having problems with 40-pin cables.
1049 */
1050 pci_write_config_byte(dev, 0x5b, 0x23);
1051
1052 /*
1053 * We'll have to read f_CNT value in order to determine
1054 * the PCI clock frequency according to the following ratio:
1055 *
1056 * f_CNT = Fpci * 192 / Fdpll
1057 *
1058 * First try reading the register in which the HighPoint BIOS
1059 * saves f_CNT value before reprogramming the DPLL from its
1060 * default setting (which differs for the various chips).
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001061 *
Sergei Shtylyov72931362007-09-11 22:28:35 +02001062 * NOTE: This register is only accessible via I/O space;
1063 * HPT374 BIOS only saves it for the function 0, so we have to
1064 * always read it from there -- no need to check the result of
1065 * pci_get_slot() for the function 0 as the whole device has
1066 * been already "pinned" (via function 1) in init_setup_hpt374()
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001067 */
Sergei Shtylyov72931362007-09-11 22:28:35 +02001068 if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
1069 struct pci_dev *dev1 = pci_get_slot(dev->bus,
1070 dev->devfn - 1);
1071 unsigned long io_base = pci_resource_start(dev1, 4);
1072
1073 temp = inl(io_base + 0x90);
1074 pci_dev_put(dev1);
1075 } else
1076 temp = inl(io_base + 0x90);
1077
1078 /*
1079 * In case the signature check fails, we'll have to
1080 * resort to reading the f_CNT register itself in hopes
1081 * that nobody has touched the DPLL yet...
1082 */
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001083 if ((temp & 0xFFFFF000) != 0xABCDE000) {
1084 int i;
1085
1086 printk(KERN_WARNING "%s: no clock data saved by BIOS\n",
1087 name);
1088
1089 /* Calculate the average value of f_CNT. */
1090 for (temp = i = 0; i < 128; i++) {
1091 pci_read_config_word(dev, 0x78, &f_cnt);
1092 temp += f_cnt & 0x1ff;
1093 mdelay(1);
1094 }
1095 f_cnt = temp / 128;
1096 } else
1097 f_cnt = temp & 0x1ff;
1098
1099 dpll_clk = info->dpll_clk;
1100 pci_clk = (f_cnt * dpll_clk) / 192;
1101
1102 /* Clamp PCI clock to bands. */
1103 if (pci_clk < 40)
1104 pci_clk = 33;
1105 else if(pci_clk < 45)
1106 pci_clk = 40;
1107 else if(pci_clk < 55)
1108 pci_clk = 50;
1109 else
1110 pci_clk = 66;
1111
1112 printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, "
1113 "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk);
1114 } else {
1115 u32 itr1 = 0;
1116
1117 pci_read_config_dword(dev, 0x40, &itr1);
1118
1119 /* Detect PCI clock by looking at cmd_high_time. */
1120 switch((itr1 >> 8) & 0x07) {
1121 case 0x09:
1122 pci_clk = 40;
Sergei Shtylyov6273d262007-02-07 18:18:20 +01001123 break;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001124 case 0x05:
1125 pci_clk = 25;
Sergei Shtylyov6273d262007-02-07 18:18:20 +01001126 break;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001127 case 0x07:
1128 default:
1129 pci_clk = 33;
Sergei Shtylyov6273d262007-02-07 18:18:20 +01001130 break;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001131 }
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001134 /* Let's assume we'll use PCI clock for the ATA clock... */
1135 switch (pci_clk) {
1136 case 25:
1137 clock = ATA_CLOCK_25MHZ;
1138 break;
1139 case 33:
1140 default:
1141 clock = ATA_CLOCK_33MHZ;
1142 break;
1143 case 40:
1144 clock = ATA_CLOCK_40MHZ;
1145 break;
1146 case 50:
1147 clock = ATA_CLOCK_50MHZ;
1148 break;
1149 case 66:
1150 clock = ATA_CLOCK_66MHZ;
1151 break;
1152 }
1153
1154 /*
1155 * Only try the DPLL if we don't have a table for the PCI clock that
1156 * we are running at for HPT370/A, always use it for anything newer...
1157 *
1158 * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
1159 * We also don't like using the DPLL because this causes glitches
1160 * on PRST-/SRST- when the state engine gets reset...
1161 */
Sergei Shtylyov72931362007-09-11 22:28:35 +02001162 if (chip_type >= HPT374 || info->settings[clock] == NULL) {
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001163 u16 f_low, delta = pci_clk < 50 ? 2 : 4;
1164 int adjust;
1165
1166 /*
1167 * Select 66 MHz DPLL clock only if UltraATA/133 mode is
1168 * supported/enabled, use 50 MHz DPLL clock otherwise...
1169 */
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +02001170 if (info->max_ultra == 6) {
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001171 dpll_clk = 66;
1172 clock = ATA_CLOCK_66MHZ;
1173 } else if (dpll_clk) { /* HPT36x chips don't have DPLL */
1174 dpll_clk = 50;
1175 clock = ATA_CLOCK_50MHZ;
1176 }
1177
1178 if (info->settings[clock] == NULL) {
1179 printk(KERN_ERR "%s: unknown bus timing!\n", name);
1180 kfree(info);
1181 return -EIO;
1182 }
1183
1184 /* Select the DPLL clock. */
1185 pci_write_config_byte(dev, 0x5b, 0x21);
1186
1187 /*
1188 * Adjust the DPLL based upon PCI clock, enable it,
1189 * and wait for stabilization...
1190 */
1191 f_low = (pci_clk * 48) / dpll_clk;
1192
1193 for (adjust = 0; adjust < 8; adjust++) {
1194 if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
1195 break;
1196
1197 /*
1198 * See if it'll settle at a fractionally different clock
1199 */
1200 if (adjust & 1)
1201 f_low -= adjust >> 1;
1202 else
1203 f_low += adjust >> 1;
1204 }
1205 if (adjust == 8) {
1206 printk(KERN_ERR "%s: DPLL did not stabilize!\n", name);
1207 kfree(info);
1208 return -EIO;
1209 }
1210
1211 printk("%s: using %d MHz DPLL clock\n", name, dpll_clk);
1212 } else {
1213 /* Mark the fact that we're not using the DPLL. */
1214 dpll_clk = 0;
1215
1216 printk("%s: using %d MHz PCI clock\n", name, pci_clk);
1217 }
1218
1219 /*
1220 * Advance the table pointer to a slot which points to the list
1221 * of the register values settings matching the clock being used.
1222 */
1223 info->settings += clock;
1224
1225 /* Store the clock frequencies. */
1226 info->dpll_clk = dpll_clk;
1227 info->pci_clk = pci_clk;
1228
1229 /* Point to this chip's own instance of the hpt_info structure. */
1230 pci_set_drvdata(dev, info);
1231
Sergei Shtylyov72931362007-09-11 22:28:35 +02001232 if (chip_type >= HPT370) {
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001233 u8 mcr1, mcr4;
1234
1235 /*
1236 * Reset the state engines.
1237 * NOTE: Avoid accidentally enabling the disabled channels.
1238 */
1239 pci_read_config_byte (dev, 0x50, &mcr1);
1240 pci_read_config_byte (dev, 0x54, &mcr4);
1241 pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
1242 pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
1243 udelay(100);
1244 }
1245
1246 /*
1247 * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
1248 * the MISC. register to stretch the UltraDMA Tss timing.
1249 * NOTE: This register is only writeable via I/O space.
1250 */
Sergei Shtylyov72931362007-09-11 22:28:35 +02001251 if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001252
1253 outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
1254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 return dev->irq;
1256}
1257
1258static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
1259{
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001260 struct pci_dev *dev = hwif->pci_dev;
1261 struct hpt_info *info = pci_get_drvdata(dev);
1262 int serialize = HPT_SERIALIZE_IO;
1263 u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02;
1264 u8 chip_type = info->chip_type;
1265 u8 new_mcr, old_mcr = 0;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001266
1267 /* Cache the channel's MISC. control registers' offset */
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001268 hwif->select_data = hwif->channel ? 0x54 : 0x50;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001269
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001270 hwif->tuneproc = &hpt3xx_tune_drive;
1271 hwif->speedproc = &hpt3xx_tune_chipset;
1272 hwif->quirkproc = &hpt3xx_quirkproc;
1273 hwif->intrproc = &hpt3xx_intrproc;
1274 hwif->maskproc = &hpt3xx_maskproc;
1275 hwif->busproc = &hpt3xx_busproc;
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +02001276
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001277 hwif->udma_filter = &hpt3xx_udma_filter;
Sergei Shtylyovb4e44362007-10-11 23:53:58 +02001278 hwif->mdma_filter = &hpt3xx_mdma_filter;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001279
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001280 /*
1281 * HPT3xxN chips have some complications:
1282 *
1283 * - on 33 MHz PCI we must clock switch
1284 * - on 66 MHz PCI we must NOT use the PCI clock
1285 */
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001286 if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001287 /*
1288 * Clock is shared between the channels,
1289 * so we'll have to serialize them... :-(
1290 */
1291 serialize = 1;
1292 hwif->rw_disk = &hpt3xxn_rw_disk;
1293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001295 /* Serialize access to this device if needed */
1296 if (serialize && hwif->mate)
1297 hwif->serialized = hwif->mate->serialized = 1;
1298
1299 /*
1300 * Disable the "fast interrupt" prediction. Don't hold off
1301 * on interrupts. (== 0x01 despite what the docs say)
1302 */
1303 pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
1304
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001305 if (info->chip_type >= HPT374)
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001306 new_mcr = old_mcr & ~0x07;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001307 else if (info->chip_type >= HPT370) {
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001308 new_mcr = old_mcr;
1309 new_mcr &= ~0x02;
1310
1311#ifdef HPT_DELAY_INTERRUPT
1312 new_mcr &= ~0x01;
1313#else
1314 new_mcr |= 0x01;
1315#endif
1316 } else /* HPT366 and HPT368 */
1317 new_mcr = old_mcr & ~0x80;
1318
1319 if (new_mcr != old_mcr)
1320 pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
1321
1322 if (!hwif->dma_base) {
1323 hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
1324 return;
1325 }
1326
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +02001327 hwif->ultra_mask = hwif->cds->udma_mask;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001328 hwif->mwdma_mask = 0x07;
1329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 /*
1331 * The HPT37x uses the CBLID pins as outputs for MA15/MA16
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001332 * address lines to access an external EEPROM. To read valid
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 * cable detect state the pins must be enabled as inputs.
1334 */
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001335 if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 /*
1337 * HPT374 PCI function 1
1338 * - set bit 15 of reg 0x52 to enable TCBLID as input
1339 * - set bit 15 of reg 0x56 to enable FCBLID as input
1340 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001341 u8 mcr_addr = hwif->select_data + 2;
1342 u16 mcr;
1343
1344 pci_read_config_word (dev, mcr_addr, &mcr);
1345 pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 /* now read cable id register */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001347 pci_read_config_byte (dev, 0x5a, &scr1);
1348 pci_write_config_word(dev, mcr_addr, mcr);
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001349 } else if (chip_type >= HPT370) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 /*
1351 * HPT370/372 and 374 pcifn 0
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001352 * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 */
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001354 u8 scr2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001356 pci_read_config_byte (dev, 0x5b, &scr2);
1357 pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
1358 /* now read cable id register */
1359 pci_read_config_byte (dev, 0x5a, &scr1);
1360 pci_write_config_byte(dev, 0x5b, scr2);
1361 } else
1362 pci_read_config_byte (dev, 0x5a, &scr1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +02001364 if (hwif->cbl != ATA_CBL_PATA40_SHORT)
1365 hwif->cbl = (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001367 hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001369 if (chip_type >= HPT374) {
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001370 hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
1371 hwif->ide_dma_end = &hpt374_ide_dma_end;
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001372 } else if (chip_type >= HPT370) {
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001373 hwif->dma_start = &hpt370_ide_dma_start;
1374 hwif->ide_dma_end = &hpt370_ide_dma_end;
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +02001375 hwif->dma_timeout = &hpt370_dma_timeout;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001376 } else
Sergei Shtylyov841d2a92007-07-09 23:17:54 +02001377 hwif->dma_lost_irq = &hpt366_dma_lost_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
1379 if (!noautodma)
1380 hwif->autodma = 1;
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001381 hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382}
1383
1384static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
1385{
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001386 struct pci_dev *dev = hwif->pci_dev;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001387 u8 masterdma = 0, slavedma = 0;
1388 u8 dma_new = 0, dma_old = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 unsigned long flags;
1390
Sergei Shtylyov26ccb802007-02-07 18:18:11 +01001391 dma_old = hwif->INB(dmabase + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
1393 local_irq_save(flags);
1394
1395 dma_new = dma_old;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001396 pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
1397 pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
1399 if (masterdma & 0x30) dma_new |= 0x20;
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001400 if ( slavedma & 0x30) dma_new |= 0x40;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 if (dma_new != dma_old)
Sergei Shtylyovabc4ad42007-02-07 18:18:05 +01001402 hwif->OUTB(dma_new, dmabase + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
1404 local_irq_restore(flags);
1405
1406 ide_setup_dma(hwif, dmabase, 8);
1407}
1408
1409static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
1410{
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001411 struct pci_dev *dev2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
1413 if (PCI_FUNC(dev->devfn) & 1)
1414 return -ENODEV;
1415
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001416 pci_set_drvdata(dev, &hpt374);
1417
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001418 if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
1419 int ret;
1420
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001421 pci_set_drvdata(dev2, &hpt374);
1422
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001423 if (dev2->irq != dev->irq) {
1424 /* FIXME: we need a core pci_set_interrupt() */
1425 dev2->irq = dev->irq;
1426 printk(KERN_WARNING "%s: PCI config space interrupt "
1427 "fixed.\n", d->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 }
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001429 ret = ide_setup_pci_devices(dev, dev2, d);
1430 if (ret < 0)
1431 pci_dev_put(dev2);
1432 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 }
1434 return ide_setup_pci_device(dev, d);
1435}
1436
Sergei Shtylyov90778572007-02-07 18:17:51 +01001437static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001439 pci_set_drvdata(dev, &hpt372n);
1440
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 return ide_setup_pci_device(dev, d);
1442}
1443
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001444static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
1445{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001446 struct hpt_info *info;
Auke Kok44c10132007-06-08 15:46:36 -07001447 u8 mcr1 = 0;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001448
Auke Kok44c10132007-06-08 15:46:36 -07001449 if (dev->revision > 1) {
Sergei Shtylyov90778572007-02-07 18:17:51 +01001450 d->name = "HPT371N";
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001451
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001452 info = &hpt371n;
1453 } else
1454 info = &hpt371;
1455
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001456 /*
1457 * HPT371 chips physically have only one channel, the secondary one,
1458 * but the primary channel registers do exist! Go figure...
1459 * So, we manually disable the non-existing channel here
1460 * (if the BIOS hasn't done this already).
1461 */
1462 pci_read_config_byte(dev, 0x50, &mcr1);
1463 if (mcr1 & 0x04)
Sergei Shtylyov90778572007-02-07 18:17:51 +01001464 pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
1465
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001466 pci_set_drvdata(dev, info);
1467
Sergei Shtylyov90778572007-02-07 18:17:51 +01001468 return ide_setup_pci_device(dev, d);
1469}
1470
1471static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
1472{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001473 struct hpt_info *info;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001474
Auke Kok44c10132007-06-08 15:46:36 -07001475 if (dev->revision > 1) {
Sergei Shtylyov90778572007-02-07 18:17:51 +01001476 d->name = "HPT372N";
1477
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001478 info = &hpt372n;
1479 } else
1480 info = &hpt372a;
1481 pci_set_drvdata(dev, info);
1482
Sergei Shtylyov90778572007-02-07 18:17:51 +01001483 return ide_setup_pci_device(dev, d);
1484}
1485
1486static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
1487{
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001488 struct hpt_info *info;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001489
Auke Kok44c10132007-06-08 15:46:36 -07001490 if (dev->revision > 1) {
Sergei Shtylyov90778572007-02-07 18:17:51 +01001491 d->name = "HPT302N";
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001492
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001493 info = &hpt302n;
1494 } else
1495 info = &hpt302;
1496 pci_set_drvdata(dev, info);
1497
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001498 return ide_setup_pci_device(dev, d);
1499}
1500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
1502{
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001503 struct pci_dev *dev2;
Auke Kok44c10132007-06-08 15:46:36 -07001504 u8 rev = dev->revision;
Sergei Shtylyov90778572007-02-07 18:17:51 +01001505 static char *chipset_names[] = { "HPT366", "HPT366", "HPT368",
1506 "HPT370", "HPT370A", "HPT372",
1507 "HPT372N" };
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001508 static struct hpt_info *info[] = { &hpt36x, &hpt36x, &hpt36x,
1509 &hpt370, &hpt370a, &hpt372,
1510 &hpt372n };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
1512 if (PCI_FUNC(dev->devfn) & 1)
1513 return -ENODEV;
1514
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +02001515 switch (rev) {
1516 case 0:
1517 case 1:
1518 case 2:
1519 /*
1520 * HPT36x chips have one channel per function and have
1521 * both channel enable bits located differently and visible
1522 * to both functions -- really stupid design decision... :-(
1523 * Bit 4 is for the primary channel, bit 5 for the secondary.
1524 */
Bartlomiej Zolnierkiewicza5d8c5c2007-07-20 01:11:55 +02001525 d->host_flags |= IDE_HFLAG_SINGLE;
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +02001526 d->enablebits[0].mask = d->enablebits[0].val = 0x10;
1527
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001528 d->udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ?
1529 ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2;
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +02001530 break;
1531 case 3:
1532 case 4:
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001533 d->udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4;
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +02001534 break;
1535 default:
Sergei Shtylyove139b0b2007-02-07 18:17:37 +01001536 rev = 6;
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +02001537 /* fall thru */
1538 case 5:
1539 case 6:
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001540 d->udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5;
Sergei Shtylyov2648e5d2007-07-09 23:17:55 +02001541 break;
1542 }
1543
Sergei Shtylyov90778572007-02-07 18:17:51 +01001544 d->name = chipset_names[rev];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001546 pci_set_drvdata(dev, info[rev]);
1547
Sergei Shtylyov90778572007-02-07 18:17:51 +01001548 if (rev > 2)
1549 goto init_single;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001551 if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
Sergei Shtylyov96dcc082007-07-03 22:28:35 +02001552 u8 mcr1 = 0, pin1 = 0, pin2 = 0;
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001553 int ret;
1554
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001555 pci_set_drvdata(dev2, info[rev]);
1556
Sergei Shtylyov96dcc082007-07-03 22:28:35 +02001557 /*
1558 * Now we'll have to force both channels enabled if
1559 * at least one of them has been enabled by BIOS...
1560 */
1561 pci_read_config_byte(dev, 0x50, &mcr1);
1562 if (mcr1 & 0x30)
1563 pci_write_config_byte(dev, 0x50, mcr1 | 0x30);
1564
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001565 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
1566 pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
1567 if (pin1 != pin2 && dev->irq == dev2->irq) {
1568 d->bootable = ON_BOARD;
1569 printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
1570 d->name, pin1, pin2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 }
Sergei Shtylyovb4586712007-02-07 18:17:54 +01001572 ret = ide_setup_pci_devices(dev, dev2, d);
1573 if (ret < 0)
1574 pci_dev_put(dev2);
1575 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 }
1577init_single:
1578 return ide_setup_pci_device(dev, d);
1579}
1580
1581static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
1582 { /* 0 */
1583 .name = "HPT366",
1584 .init_setup = init_setup_hpt366,
1585 .init_chipset = init_chipset_hpt366,
1586 .init_hwif = init_hwif_hpt366,
1587 .init_dma = init_dma_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 .autodma = AUTODMA,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001589 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 .bootable = OFF_BOARD,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +02001591 .extra = 240,
1592 .pio_mask = ATA_PIO4,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 },{ /* 1 */
1594 .name = "HPT372A",
Sergei Shtylyov90778572007-02-07 18:17:51 +01001595 .init_setup = init_setup_hpt372a,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 .init_chipset = init_chipset_hpt366,
1597 .init_hwif = init_hwif_hpt366,
1598 .init_dma = init_dma_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 .autodma = AUTODMA,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001600 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001601 .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 .bootable = OFF_BOARD,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +02001603 .extra = 240,
1604 .pio_mask = ATA_PIO4,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 },{ /* 2 */
1606 .name = "HPT302",
Sergei Shtylyov90778572007-02-07 18:17:51 +01001607 .init_setup = init_setup_hpt302,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 .init_chipset = init_chipset_hpt366,
1609 .init_hwif = init_hwif_hpt366,
1610 .init_dma = init_dma_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 .autodma = AUTODMA,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001612 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001613 .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 .bootable = OFF_BOARD,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +02001615 .extra = 240,
1616 .pio_mask = ATA_PIO4,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 },{ /* 3 */
1618 .name = "HPT371",
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001619 .init_setup = init_setup_hpt371,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 .init_chipset = init_chipset_hpt366,
1621 .init_hwif = init_hwif_hpt366,
1622 .init_dma = init_dma_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 .autodma = AUTODMA,
Sergei Shtylyov836c0062006-12-13 00:35:47 -08001624 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001625 .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 .bootable = OFF_BOARD,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +02001627 .extra = 240,
1628 .pio_mask = ATA_PIO4,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 },{ /* 4 */
1630 .name = "HPT374",
1631 .init_setup = init_setup_hpt374,
1632 .init_chipset = init_chipset_hpt366,
1633 .init_hwif = init_hwif_hpt366,
1634 .init_dma = init_dma_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 .autodma = AUTODMA,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001636 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001637 .udma_mask = ATA_UDMA5,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 .bootable = OFF_BOARD,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +02001639 .extra = 240,
1640 .pio_mask = ATA_PIO4,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 },{ /* 5 */
1642 .name = "HPT372N",
Sergei Shtylyov90778572007-02-07 18:17:51 +01001643 .init_setup = init_setup_hpt372n,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 .init_chipset = init_chipset_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 .init_hwif = init_hwif_hpt366,
1646 .init_dma = init_dma_hpt366,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 .autodma = AUTODMA,
Sergei Shtylyov7b73ee02007-02-07 18:18:16 +01001648 .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
Sergei Shtylyov2808b0a2007-09-11 22:28:36 +02001649 .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 .bootable = OFF_BOARD,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +02001651 .extra = 240,
1652 .pio_mask = ATA_PIO4,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 }
1654};
1655
1656/**
1657 * hpt366_init_one - called when an HPT366 is found
1658 * @dev: the hpt366 device
1659 * @id: the matching pci id
1660 *
1661 * Called when the PCI registration layer (or the IDE initialization)
1662 * finds a device matching our IDE device tables.
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -08001663 *
1664 * NOTE: since we'll have to modify some fields of the ide_pci_device_t
1665 * structure depending on the chip's revision, we'd better pass a local
1666 * copy down the call chain...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
1669{
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -08001670 ide_pci_device_t d = hpt366_chipsets[id->driver_data];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
Sergei Shtylyov73d1dd92006-12-13 00:35:51 -08001672 return d.init_setup(dev, &d);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673}
1674
1675static struct pci_device_id hpt366_pci_tbl[] = {
1676 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1677 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
1678 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
1679 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
1680 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
1681 { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
1682 { 0, },
1683};
1684MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
1685
1686static struct pci_driver driver = {
1687 .name = "HPT366_IDE",
1688 .id_table = hpt366_pci_tbl,
1689 .probe = hpt366_init_one,
1690};
1691
Bartlomiej Zolnierkiewicz82ab1ee2007-01-27 13:46:56 +01001692static int __init hpt366_ide_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
1694 return ide_pci_register_driver(&driver);
1695}
1696
1697module_init(hpt366_ide_init);
1698
1699MODULE_AUTHOR("Andre Hedrick");
1700MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
1701MODULE_LICENSE("GPL");