blob: 41853a1bc913f19aaff5beae08f01dc63a70b9a4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
Sergei Shtylyovfed21642007-02-17 02:40:22 +01003 * Copyright (C) 2006-2007 MontaVista Software, Inc.
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +02004 * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
6 * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
7 * compiled into the kernel if you have more than one card installed.
8 * Note that BIOS v1.29 is reported to fix the problem. Since this is
9 * safe chipset tuning, including this support is harmless
10 *
11 * Promise Ultra66 cards with BIOS v1.11 this
12 * compiled into the kernel if you have more than one card installed.
13 *
14 * Promise Ultra100 cards.
15 *
16 * The latest chipset code will support the following ::
17 * Three Ultra33 controllers and 12 drives.
18 * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
19 * The 8/4 ratio is a BIOS code limit by promise.
20 *
21 * UNLESS you enable "CONFIG_PDC202XX_BURST"
22 *
23 */
24
25/*
26 * Portions Copyright (C) 1999 Promise Technology, Inc.
27 * Author: Frank Tiernan (frankt@promise.com)
28 * Released under terms of General Public License
29 */
30
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/types.h>
32#include <linux/module.h>
33#include <linux/kernel.h>
34#include <linux/delay.h>
35#include <linux/timer.h>
36#include <linux/mm.h>
37#include <linux/ioport.h>
38#include <linux/blkdev.h>
39#include <linux/hdreg.h>
40#include <linux/interrupt.h>
41#include <linux/pci.h>
42#include <linux/init.h>
43#include <linux/ide.h>
44
45#include <asm/io.h>
46#include <asm/irq.h>
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#define PDC202XX_DEBUG_DRIVE_INFO 0
49
50static const char *pdc_quirk_drives[] = {
51 "QUANTUM FIREBALLlct08 08",
52 "QUANTUM FIREBALLP KA6.4",
53 "QUANTUM FIREBALLP KA9.1",
54 "QUANTUM FIREBALLP LM20.4",
55 "QUANTUM FIREBALLP KX13.6",
56 "QUANTUM FIREBALLP KX20.5",
57 "QUANTUM FIREBALLP KX27.3",
58 "QUANTUM FIREBALLP LM20.5",
59 NULL
60};
61
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020062static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +020064static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065{
66 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +010067 struct pci_dev *dev = to_pci_dev(hwif->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 u8 drive_pci = 0x60 + (drive->dn << 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020070 u8 AP = 0, BP = 0, CP = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 u8 TA = 0, TB = 0, TC = 0;
72
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020073#if PDC202XX_DEBUG_DRIVE_INFO
74 u32 drive_conf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 pci_read_config_dword(dev, drive_pci, &drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020076#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020078 /*
79 * TODO: do this once per channel
80 */
81 if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
82 pdc_old_disable_66MHz_clock(hwif);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020084 pci_read_config_byte(dev, drive_pci, &AP);
85 pci_read_config_byte(dev, drive_pci + 1, &BP);
86 pci_read_config_byte(dev, drive_pci + 2, &CP);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
88 switch(speed) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 case XFER_UDMA_5:
90 case XFER_UDMA_4: TB = 0x20; TC = 0x01; break;
91 case XFER_UDMA_2: TB = 0x20; TC = 0x01; break;
92 case XFER_UDMA_3:
93 case XFER_UDMA_1: TB = 0x40; TC = 0x02; break;
94 case XFER_UDMA_0:
95 case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break;
96 case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break;
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020097 case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 case XFER_PIO_4: TA = 0x01; TB = 0x04; break;
99 case XFER_PIO_3: TA = 0x02; TB = 0x06; break;
100 case XFER_PIO_2: TA = 0x03; TB = 0x08; break;
101 case XFER_PIO_1: TA = 0x05; TB = 0x0C; break;
102 case XFER_PIO_0:
103 default: TA = 0x09; TB = 0x13; break;
104 }
105
106 if (speed < XFER_SW_DMA_0) {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200107 /*
108 * preserve SYNC_INT / ERDDY_EN bits while clearing
109 * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
110 */
111 AP &= ~0x3f;
112 if (drive->id->capability & 4)
113 AP |= 0x20; /* set IORDY_EN bit */
114 if (drive->media == ide_disk)
115 AP |= 0x10; /* set Prefetch_EN bit */
116 /* clear PB[4:0] bits of register B */
117 BP &= ~0x1f;
118 pci_write_config_byte(dev, drive_pci, AP | TA);
119 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 } else {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200121 /* clear MB[2:0] bits of register B */
122 BP &= ~0xe0;
123 /* clear MC[3:0] bits of register C */
124 CP &= ~0x0f;
125 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
126 pci_write_config_byte(dev, drive_pci + 2, CP | TC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 }
128
129#if PDC202XX_DEBUG_DRIVE_INFO
130 printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
131 drive->name, ide_xfer_verbose(speed),
132 drive->dn, drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200133 pci_read_config_dword(dev, drive_pci, &drive_conf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 printk("0x%08x\n", drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200135#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200138static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200140 pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141}
142
Bartlomiej Zolnierkiewiczbfa14b42008-02-02 19:56:31 +0100143static u8 __devinit pdc2026x_old_cable_detect(ide_hwif_t *hwif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100145 struct pci_dev *dev = to_pci_dev(hwif->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200147
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100148 pci_read_config_word(dev, 0x50, &CIS);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200149
150 return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151}
152
153/*
154 * Set the control register to use the 66MHz system
155 * clock for UDMA 3/4/5 mode operation when necessary.
156 *
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200157 * FIXME: this register is shared by both channels, some locking is needed
158 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 * It may also be possible to leave the 66MHz clock on
160 * and readjust the timing parameters.
161 */
162static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
163{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100164 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100165 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100167 outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169
170static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
171{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100172 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100173 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100175 outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176}
177
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100178static void pdc202xx_quirkproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179{
Sergei Shtylyovd24ec422007-02-07 18:18:39 +0100180 const char **list, *model = drive->id->model;
181
182 for (list = pdc_quirk_drives; *list != NULL; list++)
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100183 if (strstr(model, *list) != NULL) {
184 drive->quirk_list = 2;
185 return;
186 }
187
188 drive->quirk_list = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189}
190
191static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
192{
193 if (drive->current_speed > XFER_UDMA_2)
194 pdc_old_enable_66MHz_clock(drive->hwif);
Tobias Oedf3d5b342006-10-03 01:14:17 -0700195 if (drive->media != ide_disk || drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 struct request *rq = HWGROUP(drive)->rq;
197 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100198 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
200 u32 word_count = 0;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100201 u8 clock = inb(high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100203 outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 word_count = (rq->nr_sectors << 8);
205 word_count = (rq_data_dir(rq) == READ) ?
206 word_count | 0x05000000 :
207 word_count | 0x06000000;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100208 outl(word_count, atapi_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 }
210 ide_dma_start(drive);
211}
212
213static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
214{
Tobias Oedf3d5b342006-10-03 01:14:17 -0700215 if (drive->media != ide_disk || drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100217 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
219 u8 clock = 0;
220
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100221 outl(0, atapi_reg); /* zero out extra */
222 clock = inb(high_16 + 0x11);
223 outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 }
225 if (drive->current_speed > XFER_UDMA_2)
226 pdc_old_disable_66MHz_clock(drive->hwif);
227 return __ide_dma_end(drive);
228}
229
230static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
231{
232 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100233 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100234 u8 dma_stat = inb(hwif->dma_status);
235 u8 sc1d = inb(high_16 + 0x001d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237 if (hwif->channel) {
238 /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */
239 if ((sc1d & 0x50) == 0x50)
240 goto somebody_else;
241 else if ((sc1d & 0x40) == 0x40)
242 return (dma_stat & 4) == 4;
243 } else {
244 /* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */
245 if ((sc1d & 0x05) == 0x05)
246 goto somebody_else;
247 else if ((sc1d & 0x04) == 0x04)
248 return (dma_stat & 4) == 4;
249 }
250somebody_else:
251 return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
252}
253
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200254static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200256 ide_hwif_t *hwif = HWIF(drive);
257
258 if (hwif->resetproc != NULL)
259 hwif->resetproc(drive);
260
261 ide_dma_lost_irq(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262}
263
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200264static void pdc202xx_dma_timeout(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200266 ide_hwif_t *hwif = HWIF(drive);
267
268 if (hwif->resetproc != NULL)
269 hwif->resetproc(drive);
270
271 ide_dma_timeout(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272}
273
274static void pdc202xx_reset_host (ide_hwif_t *hwif)
275{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100276 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100277 u8 udma_speed_flag = inb(high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100279 outb(udma_speed_flag | 0x10, high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 mdelay(100);
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(2000); /* 2 seconds ?! */
283
284 printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
285 hwif->channel ? "Secondary" : "Primary");
286}
287
288static void pdc202xx_reset (ide_drive_t *drive)
289{
290 ide_hwif_t *hwif = HWIF(drive);
291 ide_hwif_t *mate = hwif->mate;
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 pdc202xx_reset_host(hwif);
294 pdc202xx_reset_host(mate);
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200295
296 ide_set_max_pio(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297}
298
Alan Cox57e834e2006-06-28 04:27:03 -0700299static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
300 const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 return dev->irq;
303}
304
305static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
306{
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100307 struct pci_dev *dev = to_pci_dev(hwif->dev);
308
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200309 hwif->set_pio_mode = &pdc202xx_set_pio_mode;
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200310 hwif->set_dma_mode = &pdc202xx_set_mode;
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 hwif->quirkproc = &pdc202xx_quirkproc;
313
Bartlomiej Zolnierkiewiczbfa14b42008-02-02 19:56:31 +0100314 if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 hwif->resetproc = &pdc202xx_reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Bartlomiej Zolnierkiewiczbfa14b42008-02-02 19:56:31 +0100317 hwif->cable_detect = pdc2026x_old_cable_detect;
318 }
319
Bartlomiej Zolnierkiewicze98d6e52007-08-20 22:42:56 +0200320 if (hwif->dma_base == 0)
321 return;
322
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200323 hwif->dma_lost_irq = &pdc202xx_dma_lost_irq;
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200324 hwif->dma_timeout = &pdc202xx_dma_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100326 if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 hwif->dma_start = &pdc202xx_old_ide_dma_start;
328 hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
329 }
330 hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
332
333static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
334{
335 u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
336
337 if (hwif->channel) {
Sergei Shtylyovecf327962008-02-01 23:09:30 +0100338 ide_setup_dma(hwif, dmabase);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 return;
340 }
341
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100342 udma_speed_flag = inb(dmabase | 0x1f);
343 primary_mode = inb(dmabase | 0x1a);
344 secondary_mode = inb(dmabase | 0x1b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
346 "Primary %s Mode " \
347 "Secondary %s Mode.\n", hwif->cds->name,
348 (udma_speed_flag & 1) ? "EN" : "DIS",
349 (primary_mode & 1) ? "MASTER" : "PCI",
350 (secondary_mode & 1) ? "MASTER" : "PCI" );
351
352#ifdef CONFIG_PDC202XX_BURST
353 if (!(udma_speed_flag & 1)) {
354 printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
355 hwif->cds->name, udma_speed_flag,
356 (udma_speed_flag|1));
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100357 outb(udma_speed_flag | 1, dmabase | 0x1f);
358 printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 }
360#endif /* CONFIG_PDC202XX_BURST */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Sergei Shtylyovecf327962008-02-01 23:09:30 +0100362 ide_setup_dma(hwif, dmabase);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
364
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200365static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
366 const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
368 if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
369 u8 irq = 0, irq2 = 0;
370 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
371 /* 0xbc */
372 pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
373 if (irq != irq2) {
374 pci_write_config_byte(dev,
375 (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200376 printk(KERN_INFO "%s: PCI config space interrupt "
377 "mirror fixed\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100382#define IDE_HFLAGS_PDC202XX \
383 (IDE_HFLAG_ERROR_STOPS_FIFO | \
384 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
385 IDE_HFLAG_OFF_BOARD)
386
Bartlomiej Zolnierkiewicz272a3702007-10-20 00:32:30 +0200387#define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200388 { \
389 .name = name_str, \
390 .init_chipset = init_chipset_pdc202xx, \
391 .init_hwif = init_hwif_pdc202xx, \
392 .init_dma = init_dma_pdc202xx, \
393 .extra = 48, \
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100394 .host_flags = IDE_HFLAGS_PDC202XX | extra_flags, \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200395 .pio_mask = ATA_PIO4, \
396 .mwdma_mask = ATA_MWDMA2, \
397 .udma_mask = udma, \
398 }
399
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200400static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 { /* 0 */
402 .name = "PDC20246",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 .init_chipset = init_chipset_pdc202xx,
404 .init_hwif = init_hwif_pdc202xx,
405 .init_dma = init_dma_pdc202xx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 .extra = 16,
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100407 .host_flags = IDE_HFLAGS_PDC202XX,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +0200408 .pio_mask = ATA_PIO4,
Bartlomiej Zolnierkiewicz5f8b6c32007-10-19 00:30:07 +0200409 .mwdma_mask = ATA_MWDMA2,
410 .udma_mask = ATA_UDMA2,
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200411 },
412
Bartlomiej Zolnierkiewicz272a3702007-10-20 00:32:30 +0200413 /* 1 */ DECLARE_PDC2026X_DEV("PDC20262", ATA_UDMA4, 0),
414 /* 2 */ DECLARE_PDC2026X_DEV("PDC20263", ATA_UDMA4, 0),
415 /* 3 */ DECLARE_PDC2026X_DEV("PDC20265", ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
416 /* 4 */ DECLARE_PDC2026X_DEV("PDC20267", ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417};
418
419/**
420 * pdc202xx_init_one - called when a PDC202xx is found
421 * @dev: the pdc202xx device
422 * @id: the matching pci id
423 *
424 * Called when the PCI registration layer (or the IDE initialization)
425 * finds a device matching our IDE device tables.
426 */
427
428static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
429{
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200430 const struct ide_port_info *d;
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200431 u8 idx = id->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200433 d = &pdc202xx_chipsets[idx];
434
435 if (idx < 3)
436 pdc202ata4_fixup_irq(dev, d->name);
437
438 if (idx == 3) {
439 struct pci_dev *bridge = dev->bus->self;
440
441 if (bridge &&
442 bridge->vendor == PCI_VENDOR_ID_INTEL &&
443 (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
444 bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
445 printk(KERN_INFO "ide: Skipping Promise PDC20265 "
446 "attached to I2O RAID controller\n");
447 return -ENODEV;
448 }
449 }
450
451 return ide_setup_pci_device(dev, d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452}
453
Bartlomiej Zolnierkiewicz9cbcc5e2007-10-16 22:29:56 +0200454static const struct pci_device_id pdc202xx_pci_tbl[] = {
455 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
456 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
457 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 2 },
458 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 3 },
459 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 { 0, },
461};
462MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
463
464static struct pci_driver driver = {
465 .name = "Promise_Old_IDE",
466 .id_table = pdc202xx_pci_tbl,
467 .probe = pdc202xx_init_one,
468};
469
Bartlomiej Zolnierkiewicz82ab1ee2007-01-27 13:46:56 +0100470static int __init pdc202xx_ide_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
472 return ide_pci_register_driver(&driver);
473}
474
475module_init(pdc202xx_ide_init);
476
477MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
478MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
479MODULE_LICENSE("GPL");