X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fide%2Fpci%2Fhpt366.c;h=5f5bc3b6e8bc5907495531dddb0599f75e3c60d4;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=77bc20861dd13375fa4ce4f258244919dd8a7e22;hpb=db216c3d5e4c040e557a50f8f5d35d5c415e8c1c;p=linux-2.6.git diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 77bc20861..5f5bc3b6e 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1,8 +1,9 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 0.34 Sept 17, 2002 + * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003 * * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. + * Portions Copyright (C) 2003 Red Hat Inc * * Thanks to HighPoint Technologies for their assistance, and hardware. * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his @@ -39,6 +40,13 @@ * Reset the hpt366 on error, reset on dma * Fix disabling Fast Interrupt hpt366. * Mike Waychison + * + * Added support for 372N clocking and clock switching. The 372N needs + * different clocks on read/write. This requires overloading rw_disk and + * other deeply crazy things. Thanks to for + * keeping me sane. + * Alan Cox + * */ @@ -168,6 +176,9 @@ static u32 hpt_revision (struct pci_dev *dev) class_rev &= 0xff; switch(dev->device) { + /* Remap new 372N onto 372 */ + case PCI_DEVICE_ID_TTI_HPT372N: + class_rev = PCI_DEVICE_ID_TTI_HPT372; break; case PCI_DEVICE_ID_TTI_HPT374: class_rev = PCI_DEVICE_ID_TTI_HPT374; break; case PCI_DEVICE_ID_TTI_HPT371: @@ -217,6 +228,11 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive) return mode; } +/* + * Note for the future; the SATA hpt37x we must set + * either PIO or UDMA modes 0,4,5 + */ + static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed) { struct pci_dev *dev = HWIF(drive)->pci_dev; @@ -292,7 +308,7 @@ static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_ return chipset_table->chipset_settings; } -static void hpt366_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) { struct pci_dev *dev = HWIF(drive)->pci_dev; u8 speed = hpt3xx_ratefilter(drive, xferspeed); @@ -329,14 +345,11 @@ static void hpt366_tune_chipset (ide_drive_t *drive, u8 xferspeed) reg2 &= ~0x80000000; pci_write_config_dword(dev, regtime, reg2); -} -static void hpt368_tune_chipset (ide_drive_t *drive, u8 speed) -{ - hpt366_tune_chipset(drive, speed); + return ide_config_drive_speed(drive, speed); } -static void hpt370_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed) { struct pci_dev *dev = HWIF(drive)->pci_dev; u8 speed = hpt3xx_ratefilter(drive, xferspeed); @@ -378,9 +391,11 @@ static void hpt370_tune_chipset (ide_drive_t *drive, u8 xferspeed) } pci_write_config_dword(dev, drive_pci, list_conf); + + return ide_config_drive_speed(drive, speed); } -static void hpt372_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed) { struct pci_dev *dev = HWIF(drive)->pci_dev; u8 speed = hpt3xx_ratefilter(drive, xferspeed); @@ -406,11 +421,8 @@ static void hpt372_tune_chipset (ide_drive_t *drive, u8 xferspeed) if (speed < XFER_MW_DMA_0) list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ pci_write_config_dword(dev, drive_pci, list_conf); -} -static void hpt374_tune_chipset (ide_drive_t *drive, u8 speed) -{ - hpt372_tune_chipset(drive, speed); + return ide_config_drive_speed(drive, speed); } static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed) @@ -418,7 +430,7 @@ static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed) struct pci_dev *dev = HWIF(drive)->pci_dev; if (hpt_minimum_revision(dev, 8)) - hpt374_tune_chipset(drive, speed); + return hpt372_tune_chipset(drive, speed); /* not a typo */ #if 0 else if (hpt_minimum_revision(dev, 7)) hpt371_tune_chipset(drive, speed); @@ -426,15 +438,11 @@ static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed) hpt302_tune_chipset(drive, speed); #endif else if (hpt_minimum_revision(dev, 5)) - hpt372_tune_chipset(drive, speed); + return hpt372_tune_chipset(drive, speed); else if (hpt_minimum_revision(dev, 3)) - hpt370_tune_chipset(drive, speed); - else if (hpt_minimum_revision(dev, 2)) - hpt368_tune_chipset(drive, speed); - else - hpt366_tune_chipset(drive, speed); - - return ((int) ide_config_drive_speed(drive, speed)); + return hpt370_tune_chipset(drive, speed); + else /* hpt368: hpt_minimum_revision(dev, 2) */ + return hpt36x_tune_chipset(drive, speed); } static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio) @@ -680,6 +688,69 @@ static int hpt374_ide_dma_end (ide_drive_t *drive) return __ide_dma_end(drive); } +/** + * hpt372n_set_clock - perform clock switching dance + * @drive: Drive to switch + * @mode: Switching mode (0x21 for write, 0x23 otherwise) + * + * Switch the DPLL clock on the HPT372N devices. This is a + * right mess. + */ + +static void hpt372n_set_clock(ide_drive_t *drive, int mode) +{ + ide_hwif_t *hwif = HWIF(drive); + + /* FIXME: should we check for DMA active and BUG() */ + /* Tristate the bus */ + outb(0x80, hwif->dma_base+0x73); + outb(0x80, hwif->dma_base+0x77); + + /* Switch clock and reset channels */ + outb(mode, hwif->dma_base+0x7B); + outb(0xC0, hwif->dma_base+0x79); + + /* Reset state machines */ + outb(0x37, hwif->dma_base+0x70); + outb(0x37, hwif->dma_base+0x74); + + /* Complete reset */ + outb(0x00, hwif->dma_base+0x79); + + /* Reconnect channels to bus */ + outb(0x00, hwif->dma_base+0x73); + outb(0x00, hwif->dma_base+0x77); +} + +/** + * hpt372n_rw_disk - wrapper for I/O + * @drive: drive for command + * @rq: block request structure + * @block: block number + * + * This is called when a disk I/O is issued to the 372N instead + * of the default functionality. We need it because of the clock + * switching + * + */ + +static ide_startstop_t hpt372n_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block) +{ + int wantclock; + + if(rq_data_dir(rq) == READ) + wantclock = 0x21; + else + wantclock = 0x23; + + if(HWIF(drive)->config_data != wantclock) + { + hpt372n_set_clock(drive, wantclock); + HWIF(drive)->config_data = wantclock; + } + return __ide_do_rw_disk(drive, rq, block); +} + /* * Since SUN Cobalt is attempting to do this operation, I should disclose * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date @@ -801,13 +872,23 @@ static int __devinit init_hpt37x(struct pci_dev *dev) u16 freq; u32 pll; u8 reg5bh; - -#if 1 u8 reg5ah = 0; + unsigned long dmabase = pci_resource_start(dev, 4); + u8 did, rid; + int is_372n = 0; + pci_read_config_byte(dev, 0x5a, ®5ah); /* interrupt force enable */ pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10)); -#endif + + if(dmabase) + { + did = inb(dmabase + 0x22); + rid = inb(dmabase + 0x28); + + if((did == 4 && rid == 6) || (did == 5 && rid > 1)) + is_372n = 1; + } /* * default to pci clock. make sure MA15/16 are set to output @@ -818,47 +899,86 @@ static int __devinit init_hpt37x(struct pci_dev *dev) /* * set up the PLL. we need to adjust it so that it's stable. * freq = Tpll * 192 / Tpci + * + * Todo. For non x86 should probably check the dword is + * set to 0xABCDExxx indicating the BIOS saved f_CNT */ pci_read_config_word(dev, 0x78, &freq); freq &= 0x1FF; - if (freq < 0xa0) { - pll = F_LOW_PCI_33; - if (hpt_minimum_revision(dev,8)) - pci_set_drvdata(dev, (void *) thirty_three_base_hpt374); - else if (hpt_minimum_revision(dev,5)) - pci_set_drvdata(dev, (void *) thirty_three_base_hpt372); - else if (hpt_minimum_revision(dev,4)) - pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a); + + /* + * The 372N uses different PCI clock information and has + * some other complications + * On PCI33 timing we must clock switch + * On PCI66 timing we must NOT use the PCI clock + * + * Currently we always set up the PLL for the 372N + */ + + pci_set_drvdata(dev, NULL); + + if(is_372n) + { + printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n"); + if(freq < 0x55) + pll = F_LOW_PCI_33; + else if(freq < 0x70) + pll = F_LOW_PCI_40; + else if(freq < 0x7F) + pll = F_LOW_PCI_50; else - pci_set_drvdata(dev, (void *) thirty_three_base_hpt370); - printk("HPT37X: using 33MHz PCI clock\n"); - } else if (freq < 0xb0) { - pll = F_LOW_PCI_40; - } else if (freq < 0xc8) { - pll = F_LOW_PCI_50; - if (hpt_minimum_revision(dev,8)) - pci_set_drvdata(dev, NULL); - else if (hpt_minimum_revision(dev,5)) - pci_set_drvdata(dev, (void *) fifty_base_hpt372); - else if (hpt_minimum_revision(dev,4)) - pci_set_drvdata(dev, (void *) fifty_base_hpt370a); + pll = F_LOW_PCI_66; + + printk(KERN_INFO "FREQ: %d PLL: %d\n", freq, pll); + + /* We always use the pll not the PCI clock on 372N */ + } + else + { + if(freq < 0x9C) + pll = F_LOW_PCI_33; + else if(freq < 0xb0) + pll = F_LOW_PCI_40; + else if(freq <0xc8) + pll = F_LOW_PCI_50; else - pci_set_drvdata(dev, (void *) fifty_base_hpt370a); - printk("HPT37X: using 50MHz PCI clock\n"); - } else { - pll = F_LOW_PCI_66; - if (hpt_minimum_revision(dev,8)) - { - printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n"); - pci_set_drvdata(dev, NULL); + pll = F_LOW_PCI_66; + + if (pll == F_LOW_PCI_33) { + if (hpt_minimum_revision(dev,8)) + pci_set_drvdata(dev, (void *) thirty_three_base_hpt374); + else if (hpt_minimum_revision(dev,5)) + pci_set_drvdata(dev, (void *) thirty_three_base_hpt372); + else if (hpt_minimum_revision(dev,4)) + pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a); + else + pci_set_drvdata(dev, (void *) thirty_three_base_hpt370); + printk("HPT37X: using 33MHz PCI clock\n"); + } else if (pll == F_LOW_PCI_40) { + /* Unsupported */ + } else if (pll == F_LOW_PCI_50) { + if (hpt_minimum_revision(dev,8)) + pci_set_drvdata(dev, NULL); + else if (hpt_minimum_revision(dev,5)) + pci_set_drvdata(dev, (void *) fifty_base_hpt372); + else if (hpt_minimum_revision(dev,4)) + pci_set_drvdata(dev, (void *) fifty_base_hpt370a); + else + pci_set_drvdata(dev, (void *) fifty_base_hpt370a); + printk("HPT37X: using 50MHz PCI clock\n"); + } else { + if (hpt_minimum_revision(dev,8)) + { + printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n"); + } + else if (hpt_minimum_revision(dev,5)) + pci_set_drvdata(dev, (void *) sixty_six_base_hpt372); + else if (hpt_minimum_revision(dev,4)) + pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a); + else + pci_set_drvdata(dev, (void *) sixty_six_base_hpt370); + printk("HPT37X: using 66MHz PCI clock\n"); } - else if (hpt_minimum_revision(dev,5)) - pci_set_drvdata(dev, (void *) sixty_six_base_hpt372); - else if (hpt_minimum_revision(dev,4)) - pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a); - else - pci_set_drvdata(dev, (void *) sixty_six_base_hpt370); - printk("HPT37X: using 66MHz PCI clock\n"); } /* @@ -871,6 +991,11 @@ static int __devinit init_hpt37x(struct pci_dev *dev) if (pci_get_drvdata(dev)) goto init_hpt37X_done; + if (hpt_minimum_revision(dev,8)) + { + printk(KERN_ERR "HPT374: Only 33MHz PCI timings are supported.\n"); + return -EOPNOTSUPP; + } /* * adjust PLL based upon PCI clock, enable it, and wait for * stabilization. @@ -1008,12 +1133,27 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02; - + u8 did, rid; + unsigned long dmabase = hwif->dma_base; + int is_372n = 0; + + if(dmabase) + { + did = inb(dmabase + 0x22); + rid = inb(dmabase + 0x28); + + if((did == 4 && rid == 6) || (did == 5 && rid > 1)) + is_372n = 1; + } + hwif->tuneproc = &hpt3xx_tune_drive; hwif->speedproc = &hpt3xx_tune_chipset; hwif->quirkproc = &hpt3xx_quirkproc; hwif->intrproc = &hpt3xx_intrproc; hwif->maskproc = &hpt3xx_maskproc; + + if(is_372n) + hwif->rw_disk = &hpt372n_rw_disk; /* * The HPT37x uses the CBLID pins as outputs for MA15/MA16 @@ -1187,7 +1327,8 @@ static void __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d u8 pin1 = 0, pin2 = 0; unsigned int class_rev; char *chipset_names[] = {"HPT366", "HPT366", "HPT368", - "HPT370", "HPT370A", "HPT372"}; + "HPT370", "HPT370A", "HPT372", + "HPT372N" }; if (PCI_FUNC(dev->devfn) & 1) return; @@ -1195,9 +1336,14 @@ static void __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - strcpy(d->name, chipset_names[class_rev]); + if(dev->device == PCI_DEVICE_ID_TTI_HPT372N) + class_rev = 6; + + if(class_rev <= 6) + d->name = chipset_names[class_rev]; switch(class_rev) { + case 6: case 5: case 4: case 3: ide_setup_pci_device(dev, d); @@ -1251,6 +1397,7 @@ static struct pci_device_id hpt366_pci_tbl[] = { { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, + { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, { 0, }, }; MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);