blob: da4329790387c6019ceaf7b24d7394840b25fb1d [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/blkdev.h>
36#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/pci.h>
38#include <linux/init.h>
39#include <linux/ide.h>
40
41#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#define PDC202XX_DEBUG_DRIVE_INFO 0
44
45static const char *pdc_quirk_drives[] = {
46 "QUANTUM FIREBALLlct08 08",
47 "QUANTUM FIREBALLP KA6.4",
48 "QUANTUM FIREBALLP KA9.1",
49 "QUANTUM FIREBALLP LM20.4",
50 "QUANTUM FIREBALLP KX13.6",
51 "QUANTUM FIREBALLP KX20.5",
52 "QUANTUM FIREBALLP KX27.3",
53 "QUANTUM FIREBALLP LM20.5",
54 NULL
55};
56
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020057static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +020059static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060{
61 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +010062 struct pci_dev *dev = to_pci_dev(hwif->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 u8 drive_pci = 0x60 + (drive->dn << 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020065 u8 AP = 0, BP = 0, CP = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 u8 TA = 0, TB = 0, TC = 0;
67
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020068#if PDC202XX_DEBUG_DRIVE_INFO
69 u32 drive_conf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 pci_read_config_dword(dev, drive_pci, &drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020071#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020073 /*
74 * TODO: do this once per channel
75 */
76 if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
77 pdc_old_disable_66MHz_clock(hwif);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020079 pci_read_config_byte(dev, drive_pci, &AP);
80 pci_read_config_byte(dev, drive_pci + 1, &BP);
81 pci_read_config_byte(dev, drive_pci + 2, &CP);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83 switch(speed) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 case XFER_UDMA_5:
85 case XFER_UDMA_4: TB = 0x20; TC = 0x01; break;
86 case XFER_UDMA_2: TB = 0x20; TC = 0x01; break;
87 case XFER_UDMA_3:
88 case XFER_UDMA_1: TB = 0x40; TC = 0x02; break;
89 case XFER_UDMA_0:
90 case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break;
91 case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break;
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020092 case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 case XFER_PIO_4: TA = 0x01; TB = 0x04; break;
94 case XFER_PIO_3: TA = 0x02; TB = 0x06; break;
95 case XFER_PIO_2: TA = 0x03; TB = 0x08; break;
96 case XFER_PIO_1: TA = 0x05; TB = 0x0C; break;
97 case XFER_PIO_0:
98 default: TA = 0x09; TB = 0x13; break;
99 }
100
101 if (speed < XFER_SW_DMA_0) {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200102 /*
103 * preserve SYNC_INT / ERDDY_EN bits while clearing
104 * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
105 */
106 AP &= ~0x3f;
107 if (drive->id->capability & 4)
108 AP |= 0x20; /* set IORDY_EN bit */
109 if (drive->media == ide_disk)
110 AP |= 0x10; /* set Prefetch_EN bit */
111 /* clear PB[4:0] bits of register B */
112 BP &= ~0x1f;
113 pci_write_config_byte(dev, drive_pci, AP | TA);
114 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 } else {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200116 /* clear MB[2:0] bits of register B */
117 BP &= ~0xe0;
118 /* clear MC[3:0] bits of register C */
119 CP &= ~0x0f;
120 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
121 pci_write_config_byte(dev, drive_pci + 2, CP | TC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 }
123
124#if PDC202XX_DEBUG_DRIVE_INFO
125 printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
126 drive->name, ide_xfer_verbose(speed),
127 drive->dn, drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200128 pci_read_config_dword(dev, drive_pci, &drive_conf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 printk("0x%08x\n", drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200130#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200133static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200135 pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Bartlomiej Zolnierkiewiczbfa14b42008-02-02 19:56:31 +0100138static u8 __devinit pdc2026x_old_cable_detect(ide_hwif_t *hwif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100140 struct pci_dev *dev = to_pci_dev(hwif->dev);
Alan Cox1bee4d12008-02-02 19:56:38 +0100141 u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200142
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100143 pci_read_config_word(dev, 0x50, &CIS);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200144
145 return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146}
147
148/*
149 * Set the control register to use the 66MHz system
150 * clock for UDMA 3/4/5 mode operation when necessary.
151 *
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200152 * FIXME: this register is shared by both channels, some locking is needed
153 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 * It may also be possible to leave the 66MHz clock on
155 * and readjust the timing parameters.
156 */
157static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
158{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100159 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100160 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100162 outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163}
164
165static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
166{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100167 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100168 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100170 outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100173static void pdc202xx_quirkproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
Sergei Shtylyovd24ec422007-02-07 18:18:39 +0100175 const char **list, *model = drive->id->model;
176
177 for (list = pdc_quirk_drives; *list != NULL; list++)
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100178 if (strstr(model, *list) != NULL) {
179 drive->quirk_list = 2;
180 return;
181 }
182
183 drive->quirk_list = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184}
185
186static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
187{
188 if (drive->current_speed > XFER_UDMA_2)
189 pdc_old_enable_66MHz_clock(drive->hwif);
Tobias Oedf3d5b342006-10-03 01:14:17 -0700190 if (drive->media != ide_disk || drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 struct request *rq = HWGROUP(drive)->rq;
192 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100193 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
195 u32 word_count = 0;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100196 u8 clock = inb(high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100198 outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 word_count = (rq->nr_sectors << 8);
200 word_count = (rq_data_dir(rq) == READ) ?
201 word_count | 0x05000000 :
202 word_count | 0x06000000;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100203 outl(word_count, atapi_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 }
205 ide_dma_start(drive);
206}
207
208static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
209{
Tobias Oedf3d5b342006-10-03 01:14:17 -0700210 if (drive->media != ide_disk || drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100212 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
214 u8 clock = 0;
215
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100216 outl(0, atapi_reg); /* zero out extra */
217 clock = inb(high_16 + 0x11);
218 outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 }
220 if (drive->current_speed > XFER_UDMA_2)
221 pdc_old_disable_66MHz_clock(drive->hwif);
222 return __ide_dma_end(drive);
223}
224
225static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
226{
227 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100228 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100229 u8 dma_stat = inb(hwif->dma_status);
230 u8 sc1d = inb(high_16 + 0x001d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232 if (hwif->channel) {
233 /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */
234 if ((sc1d & 0x50) == 0x50)
235 goto somebody_else;
236 else if ((sc1d & 0x40) == 0x40)
237 return (dma_stat & 4) == 4;
238 } else {
239 /* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */
240 if ((sc1d & 0x05) == 0x05)
241 goto somebody_else;
242 else if ((sc1d & 0x04) == 0x04)
243 return (dma_stat & 4) == 4;
244 }
245somebody_else:
246 return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
247}
248
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200249static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200251 ide_hwif_t *hwif = HWIF(drive);
252
253 if (hwif->resetproc != NULL)
254 hwif->resetproc(drive);
255
256 ide_dma_lost_irq(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257}
258
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200259static void pdc202xx_dma_timeout(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260{
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200261 ide_hwif_t *hwif = HWIF(drive);
262
263 if (hwif->resetproc != NULL)
264 hwif->resetproc(drive);
265
266 ide_dma_timeout(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267}
268
269static void pdc202xx_reset_host (ide_hwif_t *hwif)
270{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100271 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100272 u8 udma_speed_flag = inb(high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100274 outb(udma_speed_flag | 0x10, high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 mdelay(100);
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100276 outb(udma_speed_flag & ~0x10, high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 mdelay(2000); /* 2 seconds ?! */
278
279 printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
280 hwif->channel ? "Secondary" : "Primary");
281}
282
283static void pdc202xx_reset (ide_drive_t *drive)
284{
285 ide_hwif_t *hwif = HWIF(drive);
286 ide_hwif_t *mate = hwif->mate;
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 pdc202xx_reset_host(hwif);
289 pdc202xx_reset_host(mate);
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200290
291 ide_set_max_pio(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292}
293
Alan Cox57e834e2006-06-28 04:27:03 -0700294static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
295 const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 return dev->irq;
298}
299
300static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
301{
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100302 struct pci_dev *dev = to_pci_dev(hwif->dev);
303
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200304 hwif->set_pio_mode = &pdc202xx_set_pio_mode;
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200305 hwif->set_dma_mode = &pdc202xx_set_mode;
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 hwif->quirkproc = &pdc202xx_quirkproc;
308
Bartlomiej Zolnierkiewiczbfa14b42008-02-02 19:56:31 +0100309 if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 hwif->resetproc = &pdc202xx_reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Bartlomiej Zolnierkiewiczbfa14b42008-02-02 19:56:31 +0100312 hwif->cable_detect = pdc2026x_old_cable_detect;
313 }
314
Bartlomiej Zolnierkiewicze98d6e52007-08-20 22:42:56 +0200315 if (hwif->dma_base == 0)
316 return;
317
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200318 hwif->dma_lost_irq = &pdc202xx_dma_lost_irq;
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200319 hwif->dma_timeout = &pdc202xx_dma_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100321 if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 hwif->dma_start = &pdc202xx_old_ide_dma_start;
323 hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
324 }
325 hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
328static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
329{
330 u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
331
332 if (hwif->channel) {
Sergei Shtylyovecf327962008-02-01 23:09:30 +0100333 ide_setup_dma(hwif, dmabase);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 return;
335 }
336
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100337 udma_speed_flag = inb(dmabase | 0x1f);
338 primary_mode = inb(dmabase | 0x1a);
339 secondary_mode = inb(dmabase | 0x1b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
341 "Primary %s Mode " \
342 "Secondary %s Mode.\n", hwif->cds->name,
343 (udma_speed_flag & 1) ? "EN" : "DIS",
344 (primary_mode & 1) ? "MASTER" : "PCI",
345 (secondary_mode & 1) ? "MASTER" : "PCI" );
346
347#ifdef CONFIG_PDC202XX_BURST
348 if (!(udma_speed_flag & 1)) {
349 printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
350 hwif->cds->name, udma_speed_flag,
351 (udma_speed_flag|1));
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100352 outb(udma_speed_flag | 1, dmabase | 0x1f);
353 printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 }
355#endif /* CONFIG_PDC202XX_BURST */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Sergei Shtylyovecf327962008-02-01 23:09:30 +0100357 ide_setup_dma(hwif, dmabase);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358}
359
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200360static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
361 const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
363 if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
364 u8 irq = 0, irq2 = 0;
365 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
366 /* 0xbc */
367 pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
368 if (irq != irq2) {
369 pci_write_config_byte(dev,
370 (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200371 printk(KERN_INFO "%s: PCI config space interrupt "
372 "mirror fixed\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 }
374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375}
376
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100377#define IDE_HFLAGS_PDC202XX \
378 (IDE_HFLAG_ERROR_STOPS_FIFO | \
379 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
380 IDE_HFLAG_OFF_BOARD)
381
Bartlomiej Zolnierkiewicz272a3702007-10-20 00:32:30 +0200382#define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200383 { \
384 .name = name_str, \
385 .init_chipset = init_chipset_pdc202xx, \
386 .init_hwif = init_hwif_pdc202xx, \
387 .init_dma = init_dma_pdc202xx, \
388 .extra = 48, \
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100389 .host_flags = IDE_HFLAGS_PDC202XX | extra_flags, \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200390 .pio_mask = ATA_PIO4, \
391 .mwdma_mask = ATA_MWDMA2, \
392 .udma_mask = udma, \
393 }
394
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200395static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 { /* 0 */
397 .name = "PDC20246",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 .init_chipset = init_chipset_pdc202xx,
399 .init_hwif = init_hwif_pdc202xx,
400 .init_dma = init_dma_pdc202xx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 .extra = 16,
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100402 .host_flags = IDE_HFLAGS_PDC202XX,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +0200403 .pio_mask = ATA_PIO4,
Bartlomiej Zolnierkiewicz5f8b6c32007-10-19 00:30:07 +0200404 .mwdma_mask = ATA_MWDMA2,
405 .udma_mask = ATA_UDMA2,
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200406 },
407
Bartlomiej Zolnierkiewicz272a3702007-10-20 00:32:30 +0200408 /* 1 */ DECLARE_PDC2026X_DEV("PDC20262", ATA_UDMA4, 0),
409 /* 2 */ DECLARE_PDC2026X_DEV("PDC20263", ATA_UDMA4, 0),
410 /* 3 */ DECLARE_PDC2026X_DEV("PDC20265", ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
411 /* 4 */ DECLARE_PDC2026X_DEV("PDC20267", ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412};
413
414/**
415 * pdc202xx_init_one - called when a PDC202xx is found
416 * @dev: the pdc202xx device
417 * @id: the matching pci id
418 *
419 * Called when the PCI registration layer (or the IDE initialization)
420 * finds a device matching our IDE device tables.
421 */
422
423static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
424{
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200425 const struct ide_port_info *d;
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200426 u8 idx = id->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200428 d = &pdc202xx_chipsets[idx];
429
430 if (idx < 3)
431 pdc202ata4_fixup_irq(dev, d->name);
432
433 if (idx == 3) {
434 struct pci_dev *bridge = dev->bus->self;
435
436 if (bridge &&
437 bridge->vendor == PCI_VENDOR_ID_INTEL &&
438 (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
439 bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
440 printk(KERN_INFO "ide: Skipping Promise PDC20265 "
441 "attached to I2O RAID controller\n");
442 return -ENODEV;
443 }
444 }
445
446 return ide_setup_pci_device(dev, d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447}
448
Bartlomiej Zolnierkiewicz9cbcc5e2007-10-16 22:29:56 +0200449static const struct pci_device_id pdc202xx_pci_tbl[] = {
450 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
451 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
452 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 2 },
453 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 3 },
454 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 { 0, },
456};
457MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
458
459static struct pci_driver driver = {
460 .name = "Promise_Old_IDE",
461 .id_table = pdc202xx_pci_tbl,
462 .probe = pdc202xx_init_one,
463};
464
Bartlomiej Zolnierkiewicz82ab1ee2007-01-27 13:46:56 +0100465static int __init pdc202xx_ide_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
467 return ide_pci_register_driver(&driver);
468}
469
470module_init(pdc202xx_ide_init);
471
472MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
473MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
474MODULE_LICENSE("GPL");