blob: df1c5fa44a7c38b375b2359bfae4efa331d1856e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Bartlomiej Zolnierkiewicz9adf7682007-10-19 00:30:07 +02002 * linux/drivers/ide/pci/pdc202xx_old.c Version 0.52 Aug 27, 2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
Sergei Shtylyovfed21642007-02-17 02:40:22 +01005 * Copyright (C) 2006-2007 MontaVista Software, Inc.
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +02006 * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
9 * compiled into the kernel if you have more than one card installed.
10 * Note that BIOS v1.29 is reported to fix the problem. Since this is
11 * safe chipset tuning, including this support is harmless
12 *
13 * Promise Ultra66 cards with BIOS v1.11 this
14 * compiled into the kernel if you have more than one card installed.
15 *
16 * Promise Ultra100 cards.
17 *
18 * The latest chipset code will support the following ::
19 * Three Ultra33 controllers and 12 drives.
20 * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
21 * The 8/4 ratio is a BIOS code limit by promise.
22 *
23 * UNLESS you enable "CONFIG_PDC202XX_BURST"
24 *
25 */
26
27/*
28 * Portions Copyright (C) 1999 Promise Technology, Inc.
29 * Author: Frank Tiernan (frankt@promise.com)
30 * Released under terms of General Public License
31 */
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/types.h>
34#include <linux/module.h>
35#include <linux/kernel.h>
36#include <linux/delay.h>
37#include <linux/timer.h>
38#include <linux/mm.h>
39#include <linux/ioport.h>
40#include <linux/blkdev.h>
41#include <linux/hdreg.h>
42#include <linux/interrupt.h>
43#include <linux/pci.h>
44#include <linux/init.h>
45#include <linux/ide.h>
46
47#include <asm/io.h>
48#include <asm/irq.h>
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#define PDC202XX_DEBUG_DRIVE_INFO 0
51
52static const char *pdc_quirk_drives[] = {
53 "QUANTUM FIREBALLlct08 08",
54 "QUANTUM FIREBALLP KA6.4",
55 "QUANTUM FIREBALLP KA9.1",
56 "QUANTUM FIREBALLP LM20.4",
57 "QUANTUM FIREBALLP KX13.6",
58 "QUANTUM FIREBALLP KX20.5",
59 "QUANTUM FIREBALLP KX27.3",
60 "QUANTUM FIREBALLP LM20.5",
61 NULL
62};
63
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020064static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +020066static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -070067{
68 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +010069 struct pci_dev *dev = to_pci_dev(hwif->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 u8 drive_pci = 0x60 + (drive->dn << 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020072 u8 AP = 0, BP = 0, CP = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 u8 TA = 0, TB = 0, TC = 0;
74
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020075#if PDC202XX_DEBUG_DRIVE_INFO
76 u32 drive_conf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 pci_read_config_dword(dev, drive_pci, &drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020078#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020080 /*
81 * TODO: do this once per channel
82 */
83 if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
84 pdc_old_disable_66MHz_clock(hwif);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020086 pci_read_config_byte(dev, drive_pci, &AP);
87 pci_read_config_byte(dev, drive_pci + 1, &BP);
88 pci_read_config_byte(dev, drive_pci + 2, &CP);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 switch(speed) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 case XFER_UDMA_5:
92 case XFER_UDMA_4: TB = 0x20; TC = 0x01; break;
93 case XFER_UDMA_2: TB = 0x20; TC = 0x01; break;
94 case XFER_UDMA_3:
95 case XFER_UDMA_1: TB = 0x40; TC = 0x02; break;
96 case XFER_UDMA_0:
97 case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break;
98 case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break;
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020099 case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 case XFER_PIO_4: TA = 0x01; TB = 0x04; break;
101 case XFER_PIO_3: TA = 0x02; TB = 0x06; break;
102 case XFER_PIO_2: TA = 0x03; TB = 0x08; break;
103 case XFER_PIO_1: TA = 0x05; TB = 0x0C; break;
104 case XFER_PIO_0:
105 default: TA = 0x09; TB = 0x13; break;
106 }
107
108 if (speed < XFER_SW_DMA_0) {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200109 /*
110 * preserve SYNC_INT / ERDDY_EN bits while clearing
111 * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
112 */
113 AP &= ~0x3f;
114 if (drive->id->capability & 4)
115 AP |= 0x20; /* set IORDY_EN bit */
116 if (drive->media == ide_disk)
117 AP |= 0x10; /* set Prefetch_EN bit */
118 /* clear PB[4:0] bits of register B */
119 BP &= ~0x1f;
120 pci_write_config_byte(dev, drive_pci, AP | TA);
121 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 } else {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200123 /* clear MB[2:0] bits of register B */
124 BP &= ~0xe0;
125 /* clear MC[3:0] bits of register C */
126 CP &= ~0x0f;
127 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
128 pci_write_config_byte(dev, drive_pci + 2, CP | TC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 }
130
131#if PDC202XX_DEBUG_DRIVE_INFO
132 printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
133 drive->name, ide_xfer_verbose(speed),
134 drive->dn, drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200135 pci_read_config_dword(dev, drive_pci, &drive_conf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 printk("0x%08x\n", drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200137#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138}
139
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200140static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200142 pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143}
144
145static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
146{
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100147 struct pci_dev *dev = to_pci_dev(hwif->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200149
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100150 pci_read_config_word(dev, 0x50, &CIS);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200151
152 return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153}
154
155/*
156 * Set the control register to use the 66MHz system
157 * clock for UDMA 3/4/5 mode operation when necessary.
158 *
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200159 * FIXME: this register is shared by both channels, some locking is needed
160 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 * It may also be possible to leave the 66MHz clock on
162 * and readjust the timing parameters.
163 */
164static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
165{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100166 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100167 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100169 outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170}
171
172static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
173{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100174 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100175 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100177 outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178}
179
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100180static void pdc202xx_quirkproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181{
Sergei Shtylyovd24ec422007-02-07 18:18:39 +0100182 const char **list, *model = drive->id->model;
183
184 for (list = pdc_quirk_drives; *list != NULL; list++)
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100185 if (strstr(model, *list) != NULL) {
186 drive->quirk_list = 2;
187 return;
188 }
189
190 drive->quirk_list = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191}
192
193static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
194{
195 if (drive->current_speed > XFER_UDMA_2)
196 pdc_old_enable_66MHz_clock(drive->hwif);
Tobias Oedf3d5b342006-10-03 01:14:17 -0700197 if (drive->media != ide_disk || drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 struct request *rq = HWGROUP(drive)->rq;
199 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100200 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
202 u32 word_count = 0;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100203 u8 clock = inb(high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100205 outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 word_count = (rq->nr_sectors << 8);
207 word_count = (rq_data_dir(rq) == READ) ?
208 word_count | 0x05000000 :
209 word_count | 0x06000000;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100210 outl(word_count, atapi_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 }
212 ide_dma_start(drive);
213}
214
215static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
216{
Tobias Oedf3d5b342006-10-03 01:14:17 -0700217 if (drive->media != ide_disk || drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100219 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
221 u8 clock = 0;
222
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100223 outl(0, atapi_reg); /* zero out extra */
224 clock = inb(high_16 + 0x11);
225 outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 }
227 if (drive->current_speed > XFER_UDMA_2)
228 pdc_old_disable_66MHz_clock(drive->hwif);
229 return __ide_dma_end(drive);
230}
231
232static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
233{
234 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100235 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100236 u8 dma_stat = inb(hwif->dma_status);
237 u8 sc1d = inb(high_16 + 0x001d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239 if (hwif->channel) {
240 /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */
241 if ((sc1d & 0x50) == 0x50)
242 goto somebody_else;
243 else if ((sc1d & 0x40) == 0x40)
244 return (dma_stat & 4) == 4;
245 } else {
246 /* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */
247 if ((sc1d & 0x05) == 0x05)
248 goto somebody_else;
249 else if ((sc1d & 0x04) == 0x04)
250 return (dma_stat & 4) == 4;
251 }
252somebody_else:
253 return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
254}
255
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200256static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200258 ide_hwif_t *hwif = HWIF(drive);
259
260 if (hwif->resetproc != NULL)
261 hwif->resetproc(drive);
262
263 ide_dma_lost_irq(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
265
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200266static void pdc202xx_dma_timeout(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200268 ide_hwif_t *hwif = HWIF(drive);
269
270 if (hwif->resetproc != NULL)
271 hwif->resetproc(drive);
272
273 ide_dma_timeout(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274}
275
276static void pdc202xx_reset_host (ide_hwif_t *hwif)
277{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100278 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100279 u8 udma_speed_flag = inb(high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100281 outb(udma_speed_flag | 0x10, high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 mdelay(100);
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100283 outb(udma_speed_flag & ~0x10, high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 mdelay(2000); /* 2 seconds ?! */
285
286 printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
287 hwif->channel ? "Secondary" : "Primary");
288}
289
290static void pdc202xx_reset (ide_drive_t *drive)
291{
292 ide_hwif_t *hwif = HWIF(drive);
293 ide_hwif_t *mate = hwif->mate;
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200294
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 pdc202xx_reset_host(hwif);
296 pdc202xx_reset_host(mate);
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200297
298 ide_set_max_pio(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299}
300
Alan Cox57e834e2006-06-28 04:27:03 -0700301static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
302 const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 return dev->irq;
305}
306
307static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
308{
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100309 struct pci_dev *dev = to_pci_dev(hwif->dev);
310
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200311 hwif->set_pio_mode = &pdc202xx_set_pio_mode;
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200312 hwif->set_dma_mode = &pdc202xx_set_mode;
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 hwif->quirkproc = &pdc202xx_quirkproc;
315
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100316 if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 hwif->resetproc = &pdc202xx_reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Bartlomiej Zolnierkiewicze98d6e52007-08-20 22:42:56 +0200319 if (hwif->dma_base == 0)
320 return;
321
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200322 hwif->dma_lost_irq = &pdc202xx_dma_lost_irq;
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200323 hwif->dma_timeout = &pdc202xx_dma_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100325 if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200326 if (hwif->cbl != ATA_CBL_PATA40_SHORT)
327 hwif->cbl = pdc202xx_old_cable_detect(hwif);
328
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 hwif->dma_start = &pdc202xx_old_ide_dma_start;
330 hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
331 }
332 hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333}
334
335static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
336{
337 u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
338
339 if (hwif->channel) {
Sergei Shtylyovecf327962008-02-01 23:09:30 +0100340 ide_setup_dma(hwif, dmabase);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 return;
342 }
343
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100344 udma_speed_flag = inb(dmabase | 0x1f);
345 primary_mode = inb(dmabase | 0x1a);
346 secondary_mode = inb(dmabase | 0x1b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
348 "Primary %s Mode " \
349 "Secondary %s Mode.\n", hwif->cds->name,
350 (udma_speed_flag & 1) ? "EN" : "DIS",
351 (primary_mode & 1) ? "MASTER" : "PCI",
352 (secondary_mode & 1) ? "MASTER" : "PCI" );
353
354#ifdef CONFIG_PDC202XX_BURST
355 if (!(udma_speed_flag & 1)) {
356 printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
357 hwif->cds->name, udma_speed_flag,
358 (udma_speed_flag|1));
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100359 outb(udma_speed_flag | 1, dmabase | 0x1f);
360 printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 }
362#endif /* CONFIG_PDC202XX_BURST */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Sergei Shtylyovecf327962008-02-01 23:09:30 +0100364 ide_setup_dma(hwif, dmabase);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365}
366
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200367static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
368 const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
370 if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
371 u8 irq = 0, irq2 = 0;
372 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
373 /* 0xbc */
374 pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
375 if (irq != irq2) {
376 pci_write_config_byte(dev,
377 (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200378 printk(KERN_INFO "%s: PCI config space interrupt "
379 "mirror fixed\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382}
383
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100384#define IDE_HFLAGS_PDC202XX \
385 (IDE_HFLAG_ERROR_STOPS_FIFO | \
386 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
387 IDE_HFLAG_OFF_BOARD)
388
Bartlomiej Zolnierkiewicz272a3702007-10-20 00:32:30 +0200389#define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200390 { \
391 .name = name_str, \
392 .init_chipset = init_chipset_pdc202xx, \
393 .init_hwif = init_hwif_pdc202xx, \
394 .init_dma = init_dma_pdc202xx, \
395 .extra = 48, \
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100396 .host_flags = IDE_HFLAGS_PDC202XX | extra_flags, \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200397 .pio_mask = ATA_PIO4, \
398 .mwdma_mask = ATA_MWDMA2, \
399 .udma_mask = udma, \
400 }
401
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200402static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 { /* 0 */
404 .name = "PDC20246",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 .init_chipset = init_chipset_pdc202xx,
406 .init_hwif = init_hwif_pdc202xx,
407 .init_dma = init_dma_pdc202xx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 .extra = 16,
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100409 .host_flags = IDE_HFLAGS_PDC202XX,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +0200410 .pio_mask = ATA_PIO4,
Bartlomiej Zolnierkiewicz5f8b6c32007-10-19 00:30:07 +0200411 .mwdma_mask = ATA_MWDMA2,
412 .udma_mask = ATA_UDMA2,
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200413 },
414
Bartlomiej Zolnierkiewicz272a3702007-10-20 00:32:30 +0200415 /* 1 */ DECLARE_PDC2026X_DEV("PDC20262", ATA_UDMA4, 0),
416 /* 2 */ DECLARE_PDC2026X_DEV("PDC20263", ATA_UDMA4, 0),
417 /* 3 */ DECLARE_PDC2026X_DEV("PDC20265", ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
418 /* 4 */ DECLARE_PDC2026X_DEV("PDC20267", ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419};
420
421/**
422 * pdc202xx_init_one - called when a PDC202xx is found
423 * @dev: the pdc202xx device
424 * @id: the matching pci id
425 *
426 * Called when the PCI registration layer (or the IDE initialization)
427 * finds a device matching our IDE device tables.
428 */
429
430static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
431{
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200432 const struct ide_port_info *d;
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200433 u8 idx = id->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200435 d = &pdc202xx_chipsets[idx];
436
437 if (idx < 3)
438 pdc202ata4_fixup_irq(dev, d->name);
439
440 if (idx == 3) {
441 struct pci_dev *bridge = dev->bus->self;
442
443 if (bridge &&
444 bridge->vendor == PCI_VENDOR_ID_INTEL &&
445 (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
446 bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
447 printk(KERN_INFO "ide: Skipping Promise PDC20265 "
448 "attached to I2O RAID controller\n");
449 return -ENODEV;
450 }
451 }
452
453 return ide_setup_pci_device(dev, d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454}
455
Bartlomiej Zolnierkiewicz9cbcc5e2007-10-16 22:29:56 +0200456static const struct pci_device_id pdc202xx_pci_tbl[] = {
457 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
458 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
459 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 2 },
460 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 3 },
461 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 { 0, },
463};
464MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
465
466static struct pci_driver driver = {
467 .name = "Promise_Old_IDE",
468 .id_table = pdc202xx_pci_tbl,
469 .probe = pdc202xx_init_one,
470};
471
Bartlomiej Zolnierkiewicz82ab1ee2007-01-27 13:46:56 +0100472static int __init pdc202xx_ide_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
474 return ide_pci_register_driver(&driver);
475}
476
477module_init(pdc202xx_ide_init);
478
479MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
480MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
481MODULE_LICENSE("GPL");