blob: 5cb2731047e918ed9bbb7fb323559c187fcb7155 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#define PDC202XX_DEBUG_DRIVE_INFO 0
24
25static const char *pdc_quirk_drives[] = {
26 "QUANTUM FIREBALLlct08 08",
27 "QUANTUM FIREBALLP KA6.4",
28 "QUANTUM FIREBALLP KA9.1",
29 "QUANTUM FIREBALLP LM20.4",
30 "QUANTUM FIREBALLP KX13.6",
31 "QUANTUM FIREBALLP KX20.5",
32 "QUANTUM FIREBALLP KX27.3",
33 "QUANTUM FIREBALLP LM20.5",
34 NULL
35};
36
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020037static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +020039static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -070040{
41 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +010042 struct pci_dev *dev = to_pci_dev(hwif->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 u8 drive_pci = 0x60 + (drive->dn << 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020045 u8 AP = 0, BP = 0, CP = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 u8 TA = 0, TB = 0, TC = 0;
47
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020048#if PDC202XX_DEBUG_DRIVE_INFO
49 u32 drive_conf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 pci_read_config_dword(dev, drive_pci, &drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020051#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020053 /*
54 * TODO: do this once per channel
55 */
56 if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
57 pdc_old_disable_66MHz_clock(hwif);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020059 pci_read_config_byte(dev, drive_pci, &AP);
60 pci_read_config_byte(dev, drive_pci + 1, &BP);
61 pci_read_config_byte(dev, drive_pci + 2, &CP);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63 switch(speed) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 case XFER_UDMA_5:
65 case XFER_UDMA_4: TB = 0x20; TC = 0x01; break;
66 case XFER_UDMA_2: TB = 0x20; TC = 0x01; break;
67 case XFER_UDMA_3:
68 case XFER_UDMA_1: TB = 0x40; TC = 0x02; break;
69 case XFER_UDMA_0:
70 case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break;
71 case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break;
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020072 case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 case XFER_PIO_4: TA = 0x01; TB = 0x04; break;
74 case XFER_PIO_3: TA = 0x02; TB = 0x06; break;
75 case XFER_PIO_2: TA = 0x03; TB = 0x08; break;
76 case XFER_PIO_1: TA = 0x05; TB = 0x0C; break;
77 case XFER_PIO_0:
78 default: TA = 0x09; TB = 0x13; break;
79 }
80
81 if (speed < XFER_SW_DMA_0) {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020082 /*
83 * preserve SYNC_INT / ERDDY_EN bits while clearing
84 * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
85 */
86 AP &= ~0x3f;
87 if (drive->id->capability & 4)
88 AP |= 0x20; /* set IORDY_EN bit */
89 if (drive->media == ide_disk)
90 AP |= 0x10; /* set Prefetch_EN bit */
91 /* clear PB[4:0] bits of register B */
92 BP &= ~0x1f;
93 pci_write_config_byte(dev, drive_pci, AP | TA);
94 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 } else {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020096 /* clear MB[2:0] bits of register B */
97 BP &= ~0xe0;
98 /* clear MC[3:0] bits of register C */
99 CP &= ~0x0f;
100 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
101 pci_write_config_byte(dev, drive_pci + 2, CP | TC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 }
103
104#if PDC202XX_DEBUG_DRIVE_INFO
105 printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
106 drive->name, ide_xfer_verbose(speed),
107 drive->dn, drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200108 pci_read_config_dword(dev, drive_pci, &drive_conf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 printk("0x%08x\n", drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200110#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200113static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200115 pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116}
117
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200118static u8 __devinit pdc2026x_cable_detect(ide_hwif_t *hwif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119{
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100120 struct pci_dev *dev = to_pci_dev(hwif->dev);
Alan Cox1bee4d12008-02-02 19:56:38 +0100121 u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200122
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100123 pci_read_config_word(dev, 0x50, &CIS);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200124
125 return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126}
127
128/*
129 * Set the control register to use the 66MHz system
130 * clock for UDMA 3/4/5 mode operation when necessary.
131 *
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200132 * FIXME: this register is shared by both channels, some locking is needed
133 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 * It may also be possible to leave the 66MHz clock on
135 * and readjust the timing parameters.
136 */
137static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
138{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100139 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100140 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100142 outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143}
144
145static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
146{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100147 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100148 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100150 outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151}
152
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100153static void pdc202xx_quirkproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
Sergei Shtylyovd24ec422007-02-07 18:18:39 +0100155 const char **list, *model = drive->id->model;
156
157 for (list = pdc_quirk_drives; *list != NULL; list++)
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100158 if (strstr(model, *list) != NULL) {
159 drive->quirk_list = 2;
160 return;
161 }
162
163 drive->quirk_list = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164}
165
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200166static void pdc202xx_dma_start(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167{
168 if (drive->current_speed > XFER_UDMA_2)
169 pdc_old_enable_66MHz_clock(drive->hwif);
Tobias Oedf3d5b342006-10-03 01:14:17 -0700170 if (drive->media != ide_disk || drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 struct request *rq = HWGROUP(drive)->rq;
172 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100173 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
175 u32 word_count = 0;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100176 u8 clock = inb(high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100178 outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 word_count = (rq->nr_sectors << 8);
180 word_count = (rq_data_dir(rq) == READ) ?
181 word_count | 0x05000000 :
182 word_count | 0x06000000;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100183 outl(word_count, atapi_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 }
185 ide_dma_start(drive);
186}
187
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200188static int pdc202xx_dma_end(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189{
Tobias Oedf3d5b342006-10-03 01:14:17 -0700190 if (drive->media != ide_disk || drive->addressing == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100192 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
194 u8 clock = 0;
195
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100196 outl(0, atapi_reg); /* zero out extra */
197 clock = inb(high_16 + 0x11);
198 outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 }
200 if (drive->current_speed > XFER_UDMA_2)
201 pdc_old_disable_66MHz_clock(drive->hwif);
202 return __ide_dma_end(drive);
203}
204
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200205static int pdc202xx_dma_test_irq(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
207 ide_hwif_t *hwif = HWIF(drive);
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100208 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewiczcab7f8e2008-07-23 19:55:51 +0200209 u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100210 u8 sc1d = inb(high_16 + 0x001d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
212 if (hwif->channel) {
213 /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */
214 if ((sc1d & 0x50) == 0x50)
215 goto somebody_else;
216 else if ((sc1d & 0x40) == 0x40)
217 return (dma_stat & 4) == 4;
218 } else {
219 /* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */
220 if ((sc1d & 0x05) == 0x05)
221 goto somebody_else;
222 else if ((sc1d & 0x04) == 0x04)
223 return (dma_stat & 4) == 4;
224 }
225somebody_else:
226 return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
227}
228
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229static void pdc202xx_reset_host (ide_hwif_t *hwif)
230{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100231 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100232 u8 udma_speed_flag = inb(high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100234 outb(udma_speed_flag | 0x10, high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 mdelay(100);
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(2000); /* 2 seconds ?! */
238
239 printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
240 hwif->channel ? "Secondary" : "Primary");
241}
242
243static void pdc202xx_reset (ide_drive_t *drive)
244{
245 ide_hwif_t *hwif = HWIF(drive);
246 ide_hwif_t *mate = hwif->mate;
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 pdc202xx_reset_host(hwif);
249 pdc202xx_reset_host(mate);
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200250
251 ide_set_max_pio(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252}
253
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200254static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
255{
256 pdc202xx_reset(drive);
257 ide_dma_lost_irq(drive);
258}
259
260static void pdc202xx_dma_timeout(ide_drive_t *drive)
261{
262 pdc202xx_reset(drive);
263 ide_dma_timeout(drive);
264}
265
Bartlomiej Zolnierkiewicz73369d22008-04-26 22:25:21 +0200266static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
267 const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
Bartlomiej Zolnierkiewicz73369d22008-04-26 22:25:21 +0200269 unsigned long dmabase = pci_resource_start(dev, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
271
Bartlomiej Zolnierkiewicz73369d22008-04-26 22:25:21 +0200272 if (dmabase == 0)
273 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100275 udma_speed_flag = inb(dmabase | 0x1f);
276 primary_mode = inb(dmabase | 0x1a);
277 secondary_mode = inb(dmabase | 0x1b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
279 "Primary %s Mode " \
Bartlomiej Zolnierkiewicz5e59c232008-04-26 22:25:20 +0200280 "Secondary %s Mode.\n", pci_name(dev),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 (udma_speed_flag & 1) ? "EN" : "DIS",
282 (primary_mode & 1) ? "MASTER" : "PCI",
283 (secondary_mode & 1) ? "MASTER" : "PCI" );
284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 if (!(udma_speed_flag & 1)) {
286 printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
Bartlomiej Zolnierkiewicz5e59c232008-04-26 22:25:20 +0200287 pci_name(dev), udma_speed_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 (udma_speed_flag|1));
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100289 outb(udma_speed_flag | 1, dmabase | 0x1f);
290 printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 }
Bartlomiej Zolnierkiewicz73369d22008-04-26 22:25:21 +0200292out:
293 return dev->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294}
295
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200296static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
297 const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
299 if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
300 u8 irq = 0, irq2 = 0;
301 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
302 /* 0xbc */
303 pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
304 if (irq != irq2) {
305 pci_write_config_byte(dev,
306 (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
Bartlomiej Zolnierkiewicz28cfd8a2008-07-24 22:53:31 +0200307 printk(KERN_INFO "%s %s: PCI config space interrupt "
308 "mirror fixed\n", name, pci_name(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 }
310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311}
312
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100313#define IDE_HFLAGS_PDC202XX \
314 (IDE_HFLAG_ERROR_STOPS_FIFO | \
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100315 IDE_HFLAG_OFF_BOARD)
316
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200317static const struct ide_port_ops pdc20246_port_ops = {
318 .set_pio_mode = pdc202xx_set_pio_mode,
319 .set_dma_mode = pdc202xx_set_mode,
320 .quirkproc = pdc202xx_quirkproc,
321};
322
323static const struct ide_port_ops pdc2026x_port_ops = {
324 .set_pio_mode = pdc202xx_set_pio_mode,
325 .set_dma_mode = pdc202xx_set_mode,
326 .quirkproc = pdc202xx_quirkproc,
327 .resetproc = pdc202xx_reset,
328 .cable_detect = pdc2026x_cable_detect,
329};
330
Bartlomiej Zolnierkiewiczf37afda2008-04-26 22:25:24 +0200331static const struct ide_dma_ops pdc20246_dma_ops = {
332 .dma_host_set = ide_dma_host_set,
333 .dma_setup = ide_dma_setup,
334 .dma_exec_cmd = ide_dma_exec_cmd,
335 .dma_start = ide_dma_start,
336 .dma_end = __ide_dma_end,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200337 .dma_test_irq = pdc202xx_dma_test_irq,
338 .dma_lost_irq = pdc202xx_dma_lost_irq,
339 .dma_timeout = pdc202xx_dma_timeout,
340};
341
Bartlomiej Zolnierkiewiczf37afda2008-04-26 22:25:24 +0200342static const struct ide_dma_ops pdc2026x_dma_ops = {
343 .dma_host_set = ide_dma_host_set,
344 .dma_setup = ide_dma_setup,
345 .dma_exec_cmd = ide_dma_exec_cmd,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200346 .dma_start = pdc202xx_dma_start,
347 .dma_end = pdc202xx_dma_end,
348 .dma_test_irq = pdc202xx_dma_test_irq,
349 .dma_lost_irq = pdc202xx_dma_lost_irq,
350 .dma_timeout = pdc202xx_dma_timeout,
351};
352
Bartlomiej Zolnierkiewicz272a3702007-10-20 00:32:30 +0200353#define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200354 { \
355 .name = name_str, \
356 .init_chipset = init_chipset_pdc202xx, \
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200357 .port_ops = &pdc2026x_port_ops, \
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200358 .dma_ops = &pdc2026x_dma_ops, \
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100359 .host_flags = IDE_HFLAGS_PDC202XX | extra_flags, \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200360 .pio_mask = ATA_PIO4, \
361 .mwdma_mask = ATA_MWDMA2, \
362 .udma_mask = udma, \
363 }
364
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200365static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 { /* 0 */
367 .name = "PDC20246",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 .init_chipset = init_chipset_pdc202xx,
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200369 .port_ops = &pdc20246_port_ops,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200370 .dma_ops = &pdc20246_dma_ops,
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100371 .host_flags = IDE_HFLAGS_PDC202XX,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +0200372 .pio_mask = ATA_PIO4,
Bartlomiej Zolnierkiewicz5f8b6c32007-10-19 00:30:07 +0200373 .mwdma_mask = ATA_MWDMA2,
374 .udma_mask = ATA_UDMA2,
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200375 },
376
Bartlomiej Zolnierkiewicz272a3702007-10-20 00:32:30 +0200377 /* 1 */ DECLARE_PDC2026X_DEV("PDC20262", ATA_UDMA4, 0),
378 /* 2 */ DECLARE_PDC2026X_DEV("PDC20263", ATA_UDMA4, 0),
379 /* 3 */ DECLARE_PDC2026X_DEV("PDC20265", ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
380 /* 4 */ DECLARE_PDC2026X_DEV("PDC20267", ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381};
382
383/**
384 * pdc202xx_init_one - called when a PDC202xx is found
385 * @dev: the pdc202xx device
386 * @id: the matching pci id
387 *
388 * Called when the PCI registration layer (or the IDE initialization)
389 * finds a device matching our IDE device tables.
390 */
391
392static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
393{
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200394 const struct ide_port_info *d;
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200395 u8 idx = id->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200397 d = &pdc202xx_chipsets[idx];
398
399 if (idx < 3)
400 pdc202ata4_fixup_irq(dev, d->name);
401
402 if (idx == 3) {
403 struct pci_dev *bridge = dev->bus->self;
404
405 if (bridge &&
406 bridge->vendor == PCI_VENDOR_ID_INTEL &&
407 (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
408 bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
Bartlomiej Zolnierkiewicz28cfd8a2008-07-24 22:53:31 +0200409 printk(KERN_INFO "pdc202xx_old %s: skipping Promise "
410 "PDC20265 attached to I2O RAID controller\n",
411 pci_name(dev));
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200412 return -ENODEV;
413 }
414 }
415
Bartlomiej Zolnierkiewicz6cdf6eb2008-07-24 22:53:14 +0200416 return ide_pci_init_one(dev, d, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
418
Bartlomiej Zolnierkiewicz9cbcc5e2007-10-16 22:29:56 +0200419static const struct pci_device_id pdc202xx_pci_tbl[] = {
420 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
421 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
422 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 2 },
423 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 3 },
424 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 { 0, },
426};
427MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
428
429static struct pci_driver driver = {
430 .name = "Promise_Old_IDE",
431 .id_table = pdc202xx_pci_tbl,
432 .probe = pdc202xx_init_one,
Bartlomiej Zolnierkiewicz574a1c22008-07-24 22:53:24 +0200433 .remove = ide_pci_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434};
435
Bartlomiej Zolnierkiewicz82ab1ee2007-01-27 13:46:56 +0100436static int __init pdc202xx_ide_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 return ide_pci_register_driver(&driver);
439}
440
Bartlomiej Zolnierkiewicz574a1c22008-07-24 22:53:24 +0200441static void __exit pdc202xx_ide_exit(void)
442{
443 pci_unregister_driver(&driver);
444}
445
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446module_init(pdc202xx_ide_init);
Bartlomiej Zolnierkiewicz574a1c22008-07-24 22:53:24 +0200447module_exit(pdc202xx_ide_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
450MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
451MODULE_LICENSE("GPL");