blob: 248a54bd2386f346e155c19a74f1c635215170a3 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/pci.h>
17#include <linux/init.h>
18#include <linux/ide.h>
19
20#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +020022#define DRV_NAME "pdc202xx_old"
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#define PDC202XX_DEBUG_DRIVE_INFO 0
25
26static const char *pdc_quirk_drives[] = {
27 "QUANTUM FIREBALLlct08 08",
28 "QUANTUM FIREBALLP KA6.4",
29 "QUANTUM FIREBALLP KA9.1",
30 "QUANTUM FIREBALLP LM20.4",
31 "QUANTUM FIREBALLP KX13.6",
32 "QUANTUM FIREBALLP KX20.5",
33 "QUANTUM FIREBALLP KX27.3",
34 "QUANTUM FIREBALLP LM20.5",
35 NULL
36};
37
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020038static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +020040static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041{
Bartlomiej Zolnierkiewicz898ec222009-01-06 17:20:52 +010042 ide_hwif_t *hwif = drive->hwif;
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +010043 struct pci_dev *dev = to_pci_dev(hwif->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 u8 drive_pci = 0x60 + (drive->dn << 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020046 u8 AP = 0, BP = 0, CP = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 u8 TA = 0, TB = 0, TC = 0;
48
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020049#if PDC202XX_DEBUG_DRIVE_INFO
50 u32 drive_conf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 pci_read_config_dword(dev, drive_pci, &drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020052#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020054 /*
55 * TODO: do this once per channel
56 */
57 if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
58 pdc_old_disable_66MHz_clock(hwif);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020060 pci_read_config_byte(dev, drive_pci, &AP);
61 pci_read_config_byte(dev, drive_pci + 1, &BP);
62 pci_read_config_byte(dev, drive_pci + 2, &CP);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64 switch(speed) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 case XFER_UDMA_5:
66 case XFER_UDMA_4: TB = 0x20; TC = 0x01; break;
67 case XFER_UDMA_2: TB = 0x20; TC = 0x01; break;
68 case XFER_UDMA_3:
69 case XFER_UDMA_1: TB = 0x40; TC = 0x02; break;
70 case XFER_UDMA_0:
71 case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break;
72 case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break;
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020073 case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 case XFER_PIO_4: TA = 0x01; TB = 0x04; break;
75 case XFER_PIO_3: TA = 0x02; TB = 0x06; break;
76 case XFER_PIO_2: TA = 0x03; TB = 0x08; break;
77 case XFER_PIO_1: TA = 0x05; TB = 0x0C; break;
78 case XFER_PIO_0:
79 default: TA = 0x09; TB = 0x13; break;
80 }
81
82 if (speed < XFER_SW_DMA_0) {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020083 /*
84 * preserve SYNC_INT / ERDDY_EN bits while clearing
85 * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
86 */
87 AP &= ~0x3f;
Bartlomiej Zolnierkiewicz48fb2682008-10-10 22:39:19 +020088 if (ata_id_iordy_disable(drive->id))
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020089 AP |= 0x20; /* set IORDY_EN bit */
90 if (drive->media == ide_disk)
91 AP |= 0x10; /* set Prefetch_EN bit */
92 /* clear PB[4:0] bits of register B */
93 BP &= ~0x1f;
94 pci_write_config_byte(dev, drive_pci, AP | TA);
95 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 } else {
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +020097 /* clear MB[2:0] bits of register B */
98 BP &= ~0xe0;
99 /* clear MC[3:0] bits of register C */
100 CP &= ~0x0f;
101 pci_write_config_byte(dev, drive_pci + 1, BP | TB);
102 pci_write_config_byte(dev, drive_pci + 2, CP | TC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 }
104
105#if PDC202XX_DEBUG_DRIVE_INFO
106 printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
107 drive->name, ide_xfer_verbose(speed),
108 drive->dn, drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200109 pci_read_config_dword(dev, drive_pci, &drive_conf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 printk("0x%08x\n", drive_conf);
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200111#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200114static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200116 pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117}
118
Bartlomiej Zolnierkiewiczf454cbe2008-08-05 18:17:04 +0200119static u8 pdc2026x_cable_detect(ide_hwif_t *hwif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120{
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100121 struct pci_dev *dev = to_pci_dev(hwif->dev);
Alan Cox1bee4d12008-02-02 19:56:38 +0100122 u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200123
Bartlomiej Zolnierkiewicz36501652008-02-01 23:09:31 +0100124 pci_read_config_word(dev, 0x50, &CIS);
Bartlomiej Zolnierkiewicz49521f92007-07-09 23:17:58 +0200125
126 return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
128
129/*
130 * Set the control register to use the 66MHz system
131 * clock for UDMA 3/4/5 mode operation when necessary.
132 *
Bartlomiej Zolnierkiewicz4fce3162007-05-16 00:51:41 +0200133 * FIXME: this register is shared by both channels, some locking is needed
134 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 * It may also be possible to leave the 66MHz clock on
136 * and readjust the timing parameters.
137 */
138static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
139{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100140 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100141 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100143 outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144}
145
146static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
147{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100148 unsigned long clock_reg = hwif->extra_base + 0x01;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100149 u8 clock = inb(clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100151 outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152}
153
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100154static void pdc202xx_quirkproc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200156 const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
Sergei Shtylyovd24ec422007-02-07 18:18:39 +0100157
158 for (list = pdc_quirk_drives; *list != NULL; list++)
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200159 if (strstr(m, *list) != NULL) {
Bartlomiej Zolnierkiewiczf01393e2008-01-26 20:13:03 +0100160 drive->quirk_list = 2;
161 return;
162 }
163
164 drive->quirk_list = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165}
166
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200167static void pdc202xx_dma_start(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168{
169 if (drive->current_speed > XFER_UDMA_2)
170 pdc_old_enable_66MHz_clock(drive->hwif);
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200171 if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
Bartlomiej Zolnierkiewicz898ec222009-01-06 17:20:52 +0100172 ide_hwif_t *hwif = drive->hwif;
Bartlomiej Zolnierkiewiczb65fac32009-01-06 17:20:50 +0100173 struct request *rq = hwif->rq;
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100174 unsigned long high_16 = hwif->extra_base - 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
176 u32 word_count = 0;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100177 u8 clock = inb(high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100179 outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 word_count = (rq->nr_sectors << 8);
181 word_count = (rq_data_dir(rq) == READ) ?
182 word_count | 0x05000000 :
183 word_count | 0x06000000;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100184 outl(word_count, atapi_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 }
186 ide_dma_start(drive);
187}
188
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200189static int pdc202xx_dma_end(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190{
Bartlomiej Zolnierkiewicz97100fc2008-10-13 21:39:36 +0200191 if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
Bartlomiej Zolnierkiewicz898ec222009-01-06 17:20:52 +0100192 ide_hwif_t *hwif = drive->hwif;
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 u8 clock = 0;
196
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100197 outl(0, atapi_reg); /* zero out extra */
198 clock = inb(high_16 + 0x11);
199 outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
201 if (drive->current_speed > XFER_UDMA_2)
202 pdc_old_disable_66MHz_clock(drive->hwif);
Bartlomiej Zolnierkiewicz653bcf52008-10-13 21:39:46 +0200203 return ide_dma_end(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204}
205
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200206static int pdc202xx_dma_test_irq(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
Bartlomiej Zolnierkiewicz898ec222009-01-06 17:20:52 +0100208 ide_hwif_t *hwif = drive->hwif;
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100209 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewiczcab7f8e2008-07-23 19:55:51 +0200210 u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100211 u8 sc1d = inb(high_16 + 0x001d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 if (hwif->channel) {
214 /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */
215 if ((sc1d & 0x50) == 0x50)
216 goto somebody_else;
217 else if ((sc1d & 0x40) == 0x40)
218 return (dma_stat & 4) == 4;
219 } else {
220 /* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */
221 if ((sc1d & 0x05) == 0x05)
222 goto somebody_else;
223 else if ((sc1d & 0x04) == 0x04)
224 return (dma_stat & 4) == 4;
225 }
226somebody_else:
227 return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
228}
229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230static void pdc202xx_reset_host (ide_hwif_t *hwif)
231{
Bartlomiej Zolnierkiewicz1c029fd2008-01-25 22:17:05 +0100232 unsigned long high_16 = hwif->extra_base - 16;
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100233 u8 udma_speed_flag = inb(high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100235 outb(udma_speed_flag | 0x10, high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 mdelay(100);
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100237 outb(udma_speed_flag & ~0x10, high_16 | 0x001f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 mdelay(2000); /* 2 seconds ?! */
239
240 printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
241 hwif->channel ? "Secondary" : "Primary");
242}
243
244static void pdc202xx_reset (ide_drive_t *drive)
245{
Bartlomiej Zolnierkiewicz898ec222009-01-06 17:20:52 +0100246 ide_hwif_t *hwif = drive->hwif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 ide_hwif_t *mate = hwif->mate;
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 pdc202xx_reset_host(hwif);
250 pdc202xx_reset_host(mate);
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200251
252 ide_set_max_pio(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253}
254
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200255static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
256{
257 pdc202xx_reset(drive);
258 ide_dma_lost_irq(drive);
259}
260
Bartlomiej Zolnierkiewicz2ed0ef52009-03-24 23:22:53 +0100261static int init_chipset_pdc202xx(struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262{
Bartlomiej Zolnierkiewicz73369d22008-04-26 22:25:21 +0200263 unsigned long dmabase = pci_resource_start(dev, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
265
Bartlomiej Zolnierkiewicz73369d22008-04-26 22:25:21 +0200266 if (dmabase == 0)
267 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100269 udma_speed_flag = inb(dmabase | 0x1f);
270 primary_mode = inb(dmabase | 0x1a);
271 secondary_mode = inb(dmabase | 0x1b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
273 "Primary %s Mode " \
Bartlomiej Zolnierkiewicz5e59c232008-04-26 22:25:20 +0200274 "Secondary %s Mode.\n", pci_name(dev),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 (udma_speed_flag & 1) ? "EN" : "DIS",
276 (primary_mode & 1) ? "MASTER" : "PCI",
277 (secondary_mode & 1) ? "MASTER" : "PCI" );
278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 if (!(udma_speed_flag & 1)) {
280 printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
Bartlomiej Zolnierkiewicz5e59c232008-04-26 22:25:20 +0200281 pci_name(dev), udma_speed_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 (udma_speed_flag|1));
Bartlomiej Zolnierkiewicz0ecdca22007-02-17 02:40:25 +0100283 outb(udma_speed_flag | 1, dmabase | 0x1f);
284 printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 }
Bartlomiej Zolnierkiewicz73369d22008-04-26 22:25:21 +0200286out:
Bartlomiej Zolnierkiewicz2ed0ef52009-03-24 23:22:53 +0100287 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288}
289
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200290static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
291 const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
293 if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
294 u8 irq = 0, irq2 = 0;
295 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
296 /* 0xbc */
297 pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
298 if (irq != irq2) {
299 pci_write_config_byte(dev,
300 (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
Bartlomiej Zolnierkiewicz28cfd8a2008-07-24 22:53:31 +0200301 printk(KERN_INFO "%s %s: PCI config space interrupt "
302 "mirror fixed\n", name, pci_name(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305}
306
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100307#define IDE_HFLAGS_PDC202XX \
308 (IDE_HFLAG_ERROR_STOPS_FIFO | \
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100309 IDE_HFLAG_OFF_BOARD)
310
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200311static const struct ide_port_ops pdc20246_port_ops = {
312 .set_pio_mode = pdc202xx_set_pio_mode,
313 .set_dma_mode = pdc202xx_set_mode,
314 .quirkproc = pdc202xx_quirkproc,
315};
316
317static const struct ide_port_ops pdc2026x_port_ops = {
318 .set_pio_mode = pdc202xx_set_pio_mode,
319 .set_dma_mode = pdc202xx_set_mode,
320 .quirkproc = pdc202xx_quirkproc,
321 .resetproc = pdc202xx_reset,
322 .cable_detect = pdc2026x_cable_detect,
323};
324
Bartlomiej Zolnierkiewiczf37afda2008-04-26 22:25:24 +0200325static const struct ide_dma_ops pdc20246_dma_ops = {
326 .dma_host_set = ide_dma_host_set,
327 .dma_setup = ide_dma_setup,
Bartlomiej Zolnierkiewiczf37afda2008-04-26 22:25:24 +0200328 .dma_start = ide_dma_start,
Bartlomiej Zolnierkiewicz653bcf52008-10-13 21:39:46 +0200329 .dma_end = ide_dma_end,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200330 .dma_test_irq = pdc202xx_dma_test_irq,
331 .dma_lost_irq = pdc202xx_dma_lost_irq,
Bartlomiej Zolnierkiewicz22117d62009-03-27 12:46:47 +0100332 .dma_timer_expiry = ide_dma_sff_timer_expiry,
Bartlomiej Zolnierkiewicz35c9b4d2009-03-31 20:15:19 +0200333 .dma_clear = pdc202xx_reset,
Sergei Shtylyov592b5312009-01-06 17:21:02 +0100334 .dma_sff_read_status = ide_dma_sff_read_status,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200335};
336
Bartlomiej Zolnierkiewiczf37afda2008-04-26 22:25:24 +0200337static const struct ide_dma_ops pdc2026x_dma_ops = {
338 .dma_host_set = ide_dma_host_set,
339 .dma_setup = ide_dma_setup,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200340 .dma_start = pdc202xx_dma_start,
341 .dma_end = pdc202xx_dma_end,
342 .dma_test_irq = pdc202xx_dma_test_irq,
343 .dma_lost_irq = pdc202xx_dma_lost_irq,
Bartlomiej Zolnierkiewicz22117d62009-03-27 12:46:47 +0100344 .dma_timer_expiry = ide_dma_sff_timer_expiry,
Bartlomiej Zolnierkiewicz35c9b4d2009-03-31 20:15:19 +0200345 .dma_clear = pdc202xx_reset,
Sergei Shtylyov592b5312009-01-06 17:21:02 +0100346 .dma_sff_read_status = ide_dma_sff_read_status,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200347};
348
Bartlomiej Zolnierkiewicz6b492492008-12-29 20:27:34 +0100349#define DECLARE_PDC2026X_DEV(udma, sectors) \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200350 { \
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200351 .name = DRV_NAME, \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200352 .init_chipset = init_chipset_pdc202xx, \
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200353 .port_ops = &pdc2026x_port_ops, \
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200354 .dma_ops = &pdc2026x_dma_ops, \
Bartlomiej Zolnierkiewicz6b492492008-12-29 20:27:34 +0100355 .host_flags = IDE_HFLAGS_PDC202XX, \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200356 .pio_mask = ATA_PIO4, \
357 .mwdma_mask = ATA_MWDMA2, \
358 .udma_mask = udma, \
Bartlomiej Zolnierkiewicz6b492492008-12-29 20:27:34 +0100359 .max_sectors = sectors, \
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200360 }
361
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200362static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200363 { /* 0: PDC20246 */
364 .name = DRV_NAME,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 .init_chipset = init_chipset_pdc202xx,
Bartlomiej Zolnierkiewiczac95bee2008-04-26 22:25:14 +0200366 .port_ops = &pdc20246_port_ops,
Bartlomiej Zolnierkiewicz5e37bdc2008-04-26 22:25:24 +0200367 .dma_ops = &pdc20246_dma_ops,
Bartlomiej Zolnierkiewicz4db90a12008-01-25 22:17:18 +0100368 .host_flags = IDE_HFLAGS_PDC202XX,
Bartlomiej Zolnierkiewicz4099d142007-07-20 01:11:59 +0200369 .pio_mask = ATA_PIO4,
Bartlomiej Zolnierkiewicz5f8b6c32007-10-19 00:30:07 +0200370 .mwdma_mask = ATA_MWDMA2,
371 .udma_mask = ATA_UDMA2,
Bartlomiej Zolnierkiewicz5ef8cb52007-10-19 00:30:10 +0200372 },
373
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200374 /* 1: PDC2026{2,3} */
375 DECLARE_PDC2026X_DEV(ATA_UDMA4, 0),
Bartlomiej Zolnierkiewicz6b492492008-12-29 20:27:34 +0100376 /* 2: PDC2026{5,7}: UDMA5, limit LBA48 requests to 256 sectors */
377 DECLARE_PDC2026X_DEV(ATA_UDMA5, 256),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378};
379
380/**
381 * pdc202xx_init_one - called when a PDC202xx is found
382 * @dev: the pdc202xx device
383 * @id: the matching pci id
384 *
385 * Called when the PCI registration layer (or the IDE initialization)
386 * finds a device matching our IDE device tables.
387 */
388
389static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
390{
Bartlomiej Zolnierkiewicz85620432007-10-20 00:32:34 +0200391 const struct ide_port_info *d;
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200392 u8 idx = id->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200394 d = &pdc202xx_chipsets[idx];
395
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200396 if (idx < 2)
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200397 pdc202ata4_fixup_irq(dev, d->name);
398
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200399 if (dev->vendor == PCI_DEVICE_ID_PROMISE_20265) {
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200400 struct pci_dev *bridge = dev->bus->self;
401
402 if (bridge &&
403 bridge->vendor == PCI_VENDOR_ID_INTEL &&
404 (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
405 bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200406 printk(KERN_INFO DRV_NAME " %s: skipping Promise "
Bartlomiej Zolnierkiewicz28cfd8a2008-07-24 22:53:31 +0200407 "PDC20265 attached to I2O RAID controller\n",
408 pci_name(dev));
Bartlomiej Zolnierkiewicz97f84ba2007-10-19 00:30:09 +0200409 return -ENODEV;
410 }
411 }
412
Bartlomiej Zolnierkiewicz6cdf6eb2008-07-24 22:53:14 +0200413 return ide_pci_init_one(dev, d, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
Bartlomiej Zolnierkiewicz9cbcc5e2007-10-16 22:29:56 +0200416static const struct pci_device_id pdc202xx_pci_tbl[] = {
417 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
418 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
Bartlomiej Zolnierkiewiczced3ec82008-07-24 22:53:32 +0200419 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 },
420 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 },
421 { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 { 0, },
423};
424MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
425
Bartlomiej Zolnierkiewicza9ab09e22008-10-13 21:39:41 +0200426static struct pci_driver pdc202xx_pci_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 .name = "Promise_Old_IDE",
428 .id_table = pdc202xx_pci_tbl,
429 .probe = pdc202xx_init_one,
Bartlomiej Zolnierkiewicz574a1c22008-07-24 22:53:24 +0200430 .remove = ide_pci_remove,
Bartlomiej Zolnierkiewiczfeb22b72008-10-10 22:39:32 +0200431 .suspend = ide_pci_suspend,
432 .resume = ide_pci_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433};
434
Bartlomiej Zolnierkiewicz82ab1ee2007-01-27 13:46:56 +0100435static int __init pdc202xx_ide_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436{
Bartlomiej Zolnierkiewicza9ab09e22008-10-13 21:39:41 +0200437 return ide_pci_register_driver(&pdc202xx_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438}
439
Bartlomiej Zolnierkiewicz574a1c22008-07-24 22:53:24 +0200440static void __exit pdc202xx_ide_exit(void)
441{
Bartlomiej Zolnierkiewicza9ab09e22008-10-13 21:39:41 +0200442 pci_unregister_driver(&pdc202xx_pci_driver);
Bartlomiej Zolnierkiewicz574a1c22008-07-24 22:53:24 +0200443}
444
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445module_init(pdc202xx_ide_init);
Bartlomiej Zolnierkiewicz574a1c22008-07-24 22:53:24 +0200446module_exit(pdc202xx_ide_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
449MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
450MODULE_LICENSE("GPL");