blob: 5d4436f3efd4c3292027f7ec3e4130284eafd2a0 [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 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * Portions Copyright (C) 1999 Promise Technology, Inc.
7 * Author: Frank Tiernan (frankt@promise.com)
8 * Released under terms of General Public License
9 */
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/types.h>
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/blkdev.h>
16#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/pci.h>
18#include <linux/init.h>
19#include <linux/ide.h>
20
21#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +020023#define DRV_NAME "pdc202xx_old"
24
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#define PDC202XX_DEBUG_DRIVE_INFO 0
26
27static const char *pdc_quirk_drives[] = {
28 "QUANTUM FIREBALLlct08 08",
29 "QUANTUM FIREBALLP KA6.4",
30 "QUANTUM FIREBALLP KA9.1",
31 "QUANTUM FIREBALLP LM20.4",
32 "QUANTUM FIREBALLP KX13.6",
33 "QUANTUM FIREBALLP KX20.5",
34 "QUANTUM FIREBALLP KX27.3",
35 "QUANTUM FIREBALLP LM20.5",
36 NULL
37};
38
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020039static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +020041static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -070042{
43 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +010044 struct pci_dev *dev = to_pci_dev(hwif->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 u8 drive_pci = 0x60 + (drive->dn << 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020047 u8 AP = 0, BP = 0, CP = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 u8 TA = 0, TB = 0, TC = 0;
49
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020050#if PDC202XX_DEBUG_DRIVE_INFO
51 u32 drive_conf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 pci_read_config_dword(dev, drive_pci, &drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020053#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020055 /*
56 * TODO: do this once per channel
57 */
58 if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
59 pdc_old_disable_66MHz_clock(hwif);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020061 pci_read_config_byte(dev, drive_pci, &AP);
62 pci_read_config_byte(dev, drive_pci + 1, &BP);
63 pci_read_config_byte(dev, drive_pci + 2, &CP);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65 switch(speed) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 case XFER_UDMA_5:
67 case XFER_UDMA_4: TB = 0x20; TC = 0x01; break;
68 case XFER_UDMA_2: TB = 0x20; TC = 0x01; break;
69 case XFER_UDMA_3:
70 case XFER_UDMA_1: TB = 0x40; TC = 0x02; break;
71 case XFER_UDMA_0:
72 case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break;
73 case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break;
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020074 case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 case XFER_PIO_4: TA = 0x01; TB = 0x04; break;
76 case XFER_PIO_3: TA = 0x02; TB = 0x06; break;
77 case XFER_PIO_2: TA = 0x03; TB = 0x08; break;
78 case XFER_PIO_1: TA = 0x05; TB = 0x0C; break;
79 case XFER_PIO_0:
80 default: TA = 0x09; TB = 0x13; break;
81 }
82
83 if (speed < XFER_SW_DMA_0) {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020084 /*
85 * preserve SYNC_INT / ERDDY_EN bits while clearing
86 * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
87 */
88 AP &= ~0x3f;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +020089 if (ata_id_iordy_disable(drive->id))
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020090 AP |= 0x20; /* set IORDY_EN bit */
91 if (drive->media == ide_disk)
92 AP |= 0x10; /* set Prefetch_EN bit */
93 /* clear PB[4:0] bits of register B */
94 BP &= ~0x1f;
95 pci_write_config_byte(dev, drive_pci, AP | TA);
96 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 } else {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020098 /* clear MB[2:0] bits of register B */
99 BP &= ~0xe0;
100 /* clear MC[3:0] bits of register C */
101 CP &= ~0x0f;
102 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
103 pci_write_config_byte(dev, drive_pci + 2, CP | TC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 }
105
106#if PDC202XX_DEBUG_DRIVE_INFO
107 printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
108 drive->name, ide_xfer_verbose(speed),
109 drive->dn, drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200110 pci_read_config_dword(dev, drive_pci, &drive_conf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 printk("0x%08x\n", drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200112#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113}
114
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200115static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200117 pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118}
119
Bartlomiej Zolnierkiewiczf454cbe2008-08-05 18:17:04 +0200120static u8 pdc2026x_cable_detect(ide_hwif_t *hwif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100122 struct pci_dev *dev = to_pci_dev(hwif->dev);
Alan Cox1bee4d12008-02-02 19:56:38 +0100123 u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200124
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100125 pci_read_config_word(dev, 0x50, &CIS);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200126
127 return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128}
129
130/*
131 * Set the control register to use the 66MHz system
132 * clock for UDMA 3/4/5 mode operation when necessary.
133 *
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200134 * FIXME: this register is shared by both channels, some locking is needed
135 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 * It may also be possible to leave the 66MHz clock on
137 * and readjust the timing parameters.
138 */
139static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
140{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100141 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100142 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100144 outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145}
146
147static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
148{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100149 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100150 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100152 outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153}
154
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100155static void pdc202xx_quirkproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200157 const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
Sergei Shtylyovd24ec422007-02-07 18:18:39 +0100158
159 for (list = pdc_quirk_drives; *list != NULL; list++)
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200160 if (strstr(m, *list) != NULL) {
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100161 drive->quirk_list = 2;
162 return;
163 }
164
165 drive->quirk_list = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166}
167
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200168static void pdc202xx_dma_start(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169{
170 if (drive->current_speed > XFER_UDMA_2)
171 pdc_old_enable_66MHz_clock(drive->hwif);
Tobias Oedf3d5b342006-10-03 01:14:17 -0700172 if (drive->media != ide_disk || drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 struct request *rq = HWGROUP(drive)->rq;
174 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100175 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
177 u32 word_count = 0;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100178 u8 clock = inb(high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100180 outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 word_count = (rq->nr_sectors << 8);
182 word_count = (rq_data_dir(rq) == READ) ?
183 word_count | 0x05000000 :
184 word_count | 0x06000000;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100185 outl(word_count, atapi_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 }
187 ide_dma_start(drive);
188}
189
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200190static int pdc202xx_dma_end(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191{
Tobias Oedf3d5b342006-10-03 01:14:17 -0700192 if (drive->media != ide_disk || drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100194 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
196 u8 clock = 0;
197
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100198 outl(0, atapi_reg); /* zero out extra */
199 clock = inb(high_16 + 0x11);
200 outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 }
202 if (drive->current_speed > XFER_UDMA_2)
203 pdc_old_disable_66MHz_clock(drive->hwif);
204 return __ide_dma_end(drive);
205}
206
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200207static int pdc202xx_dma_test_irq(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100210 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewiczcab7f8e2008-07-23 19:55:51 +0200211 u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100212 u8 sc1d = inb(high_16 + 0x001d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
214 if (hwif->channel) {
215 /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */
216 if ((sc1d & 0x50) == 0x50)
217 goto somebody_else;
218 else if ((sc1d & 0x40) == 0x40)
219 return (dma_stat & 4) == 4;
220 } else {
221 /* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */
222 if ((sc1d & 0x05) == 0x05)
223 goto somebody_else;
224 else if ((sc1d & 0x04) == 0x04)
225 return (dma_stat & 4) == 4;
226 }
227somebody_else:
228 return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
229}
230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231static void pdc202xx_reset_host (ide_hwif_t *hwif)
232{
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 udma_speed_flag = inb(high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100236 outb(udma_speed_flag | 0x10, high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 mdelay(100);
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100238 outb(udma_speed_flag & ~0x10, high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 mdelay(2000); /* 2 seconds ?! */
240
241 printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
242 hwif->channel ? "Secondary" : "Primary");
243}
244
245static void pdc202xx_reset (ide_drive_t *drive)
246{
247 ide_hwif_t *hwif = HWIF(drive);
248 ide_hwif_t *mate = hwif->mate;
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 pdc202xx_reset_host(hwif);
251 pdc202xx_reset_host(mate);
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200252
253 ide_set_max_pio(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254}
255
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200256static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
257{
258 pdc202xx_reset(drive);
259 ide_dma_lost_irq(drive);
260}
261
262static void pdc202xx_dma_timeout(ide_drive_t *drive)
263{
264 pdc202xx_reset(drive);
265 ide_dma_timeout(drive);
266}
267
Bartlomiej Zolnierkiewicza326b022008-07-24 22:53:33 +0200268static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
Bartlomiej Zolnierkiewicz73369d22008-04-26 22:25:21 +0200270 unsigned long dmabase = pci_resource_start(dev, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
272
Bartlomiej Zolnierkiewicz73369d22008-04-26 22:25:21 +0200273 if (dmabase == 0)
274 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100276 udma_speed_flag = inb(dmabase | 0x1f);
277 primary_mode = inb(dmabase | 0x1a);
278 secondary_mode = inb(dmabase | 0x1b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
280 "Primary %s Mode " \
Bartlomiej Zolnierkiewicz5e59c232008-04-26 22:25:20 +0200281 "Secondary %s Mode.\n", pci_name(dev),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 (udma_speed_flag & 1) ? "EN" : "DIS",
283 (primary_mode & 1) ? "MASTER" : "PCI",
284 (secondary_mode & 1) ? "MASTER" : "PCI" );
285
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 if (!(udma_speed_flag & 1)) {
287 printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
Bartlomiej Zolnierkiewicz5e59c232008-04-26 22:25:20 +0200288 pci_name(dev), udma_speed_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 (udma_speed_flag|1));
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100290 outb(udma_speed_flag | 1, dmabase | 0x1f);
291 printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 }
Bartlomiej Zolnierkiewicz73369d22008-04-26 22:25:21 +0200293out:
294 return dev->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295}
296
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200297static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
298 const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
301 u8 irq = 0, irq2 = 0;
302 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
303 /* 0xbc */
304 pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
305 if (irq != irq2) {
306 pci_write_config_byte(dev,
307 (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
Bartlomiej Zolnierkiewicz28cfd8a2008-07-24 22:53:31 +0200308 printk(KERN_INFO "%s %s: PCI config space interrupt "
309 "mirror fixed\n", name, pci_name(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 }
311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100314#define IDE_HFLAGS_PDC202XX \
315 (IDE_HFLAG_ERROR_STOPS_FIFO | \
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100316 IDE_HFLAG_OFF_BOARD)
317
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200318static const struct ide_port_ops pdc20246_port_ops = {
319 .set_pio_mode = pdc202xx_set_pio_mode,
320 .set_dma_mode = pdc202xx_set_mode,
321 .quirkproc = pdc202xx_quirkproc,
322};
323
324static const struct ide_port_ops pdc2026x_port_ops = {
325 .set_pio_mode = pdc202xx_set_pio_mode,
326 .set_dma_mode = pdc202xx_set_mode,
327 .quirkproc = pdc202xx_quirkproc,
328 .resetproc = pdc202xx_reset,
329 .cable_detect = pdc2026x_cable_detect,
330};
331
Bartlomiej Zolnierkiewiczf37afda2008-04-26 22:25:24 +0200332static const struct ide_dma_ops pdc20246_dma_ops = {
333 .dma_host_set = ide_dma_host_set,
334 .dma_setup = ide_dma_setup,
335 .dma_exec_cmd = ide_dma_exec_cmd,
336 .dma_start = ide_dma_start,
337 .dma_end = __ide_dma_end,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200338 .dma_test_irq = pdc202xx_dma_test_irq,
339 .dma_lost_irq = pdc202xx_dma_lost_irq,
340 .dma_timeout = pdc202xx_dma_timeout,
341};
342
Bartlomiej Zolnierkiewiczf37afda2008-04-26 22:25:24 +0200343static const struct ide_dma_ops pdc2026x_dma_ops = {
344 .dma_host_set = ide_dma_host_set,
345 .dma_setup = ide_dma_setup,
346 .dma_exec_cmd = ide_dma_exec_cmd,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200347 .dma_start = pdc202xx_dma_start,
348 .dma_end = pdc202xx_dma_end,
349 .dma_test_irq = pdc202xx_dma_test_irq,
350 .dma_lost_irq = pdc202xx_dma_lost_irq,
351 .dma_timeout = pdc202xx_dma_timeout,
352};
353
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200354#define DECLARE_PDC2026X_DEV(udma, extra_flags) \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200355 { \
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200356 .name = DRV_NAME, \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200357 .init_chipset = init_chipset_pdc202xx, \
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200358 .port_ops = &pdc2026x_port_ops, \
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200359 .dma_ops = &pdc2026x_dma_ops, \
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100360 .host_flags = IDE_HFLAGS_PDC202XX | extra_flags, \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200361 .pio_mask = ATA_PIO4, \
362 .mwdma_mask = ATA_MWDMA2, \
363 .udma_mask = udma, \
364 }
365
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200366static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200367 { /* 0: PDC20246 */
368 .name = DRV_NAME,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 .init_chipset = init_chipset_pdc202xx,
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200370 .port_ops = &pdc20246_port_ops,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200371 .dma_ops = &pdc20246_dma_ops,
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100372 .host_flags = IDE_HFLAGS_PDC202XX,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +0200373 .pio_mask = ATA_PIO4,
Bartlomiej Zolnierkiewicz5f8b6c32007-10-19 00:30:07 +0200374 .mwdma_mask = ATA_MWDMA2,
375 .udma_mask = ATA_UDMA2,
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200376 },
377
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200378 /* 1: PDC2026{2,3} */
379 DECLARE_PDC2026X_DEV(ATA_UDMA4, 0),
380 /* 2: PDC2026{5,7} */
381 DECLARE_PDC2026X_DEV(ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382};
383
384/**
385 * pdc202xx_init_one - called when a PDC202xx is found
386 * @dev: the pdc202xx device
387 * @id: the matching pci id
388 *
389 * Called when the PCI registration layer (or the IDE initialization)
390 * finds a device matching our IDE device tables.
391 */
392
393static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
394{
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200395 const struct ide_port_info *d;
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200396 u8 idx = id->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200398 d = &pdc202xx_chipsets[idx];
399
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200400 if (idx < 2)
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200401 pdc202ata4_fixup_irq(dev, d->name);
402
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200403 if (dev->vendor == PCI_DEVICE_ID_PROMISE_20265) {
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200404 struct pci_dev *bridge = dev->bus->self;
405
406 if (bridge &&
407 bridge->vendor == PCI_VENDOR_ID_INTEL &&
408 (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
409 bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200410 printk(KERN_INFO DRV_NAME " %s: skipping Promise "
Bartlomiej Zolnierkiewicz28cfd8a2008-07-24 22:53:31 +0200411 "PDC20265 attached to I2O RAID controller\n",
412 pci_name(dev));
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200413 return -ENODEV;
414 }
415 }
416
Bartlomiej Zolnierkiewicz6cdf6eb2008-07-24 22:53:14 +0200417 return ide_pci_init_one(dev, d, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418}
419
Bartlomiej Zolnierkiewicz9cbcc5e2007-10-16 22:29:56 +0200420static const struct pci_device_id pdc202xx_pci_tbl[] = {
421 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
422 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200423 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 },
424 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 },
425 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 { 0, },
427};
428MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
429
430static struct pci_driver driver = {
431 .name = "Promise_Old_IDE",
432 .id_table = pdc202xx_pci_tbl,
433 .probe = pdc202xx_init_one,
Bartlomiej Zolnierkiewicz574a1c22008-07-24 22:53:24 +0200434 .remove = ide_pci_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435};
436
Bartlomiej Zolnierkiewicz82ab1ee2007-01-27 13:46:56 +0100437static int __init pdc202xx_ide_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
439 return ide_pci_register_driver(&driver);
440}
441
Bartlomiej Zolnierkiewicz574a1c22008-07-24 22:53:24 +0200442static void __exit pdc202xx_ide_exit(void)
443{
444 pci_unregister_driver(&driver);
445}
446
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447module_init(pdc202xx_ide_init);
Bartlomiej Zolnierkiewicz574a1c22008-07-24 22:53:24 +0200448module_exit(pdc202xx_ide_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
450MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
451MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
452MODULE_LICENSE("GPL");