📄 hpt366.c
字号:
}static int hpt370_ide_dma_end (ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); u8 dma_stat = hwif->INB(hwif->dma_status); if (dma_stat & 0x01) { /* wait a little */ udelay(20); dma_stat = hwif->INB(hwif->dma_status); } if ((dma_stat & 0x01) != 0) /* fallthrough */ (void) HWIF(drive)->ide_dma_timeout(drive); return __ide_dma_end(drive);}static void hpt370_lostirq_timeout (ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); u8 bfifo = 0, reginfo = hwif->channel ? 0x56 : 0x52; u8 dma_stat = 0, dma_cmd = 0; pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo); printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo); hpt370_clear_engine(drive); /* get dma command mode */ dma_cmd = hwif->INB(hwif->dma_command); /* stop dma */ hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command); dma_stat = hwif->INB(hwif->dma_status); /* clear errors */ hwif->OUTB(dma_stat | 0x6, hwif->dma_status);}static int hpt370_ide_dma_timeout (ide_drive_t *drive){ hpt370_lostirq_timeout(drive); hpt370_clear_engine(drive); return __ide_dma_timeout(drive);}static int hpt370_ide_dma_lostirq (ide_drive_t *drive){ hpt370_lostirq_timeout(drive); hpt370_clear_engine(drive); return __ide_dma_lostirq(drive);}/* returns 1 if DMA IRQ issued, 0 otherwise */static int hpt374_ide_dma_test_irq(ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); u16 bfifo = 0; u8 reginfo = hwif->channel ? 0x56 : 0x52; u8 dma_stat; pci_read_config_word(hwif->pci_dev, reginfo, &bfifo); if (bfifo & 0x1FF) {// printk("%s: %d bytes in FIFO\n", drive->name, bfifo); return 0; } dma_stat = hwif->INB(hwif->dma_status); /* return 1 if INTR asserted */ if ((dma_stat & 4) == 4) return 1; if (!drive->waiting_for_dma) printk(KERN_WARNING "%s: (%s) called while not waiting\n", drive->name, __FUNCTION__); return 0;}static int hpt374_ide_dma_end (ide_drive_t *drive){ struct pci_dev *dev = HWIF(drive)->pci_dev; ide_hwif_t *hwif = HWIF(drive); u8 msc_stat = 0, mscreg = hwif->channel ? 0x54 : 0x50; u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01; pci_read_config_byte(dev, 0x6a, &bwsr_stat); pci_read_config_byte(dev, mscreg, &msc_stat); if ((bwsr_stat & bwsr_mask) == bwsr_mask) pci_write_config_byte(dev, mscreg, msc_stat|0x30); 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 - prepare for I/O * @drive: drive for command * @rq: block request structure * * This is called when a disk I/O is issued to the 372N. * We need it because of the clock switching. */static void hpt372n_rw_disk(ide_drive_t *drive, struct request *rq){ ide_hwif_t *hwif = drive->hwif; int wantclock; wantclock = rq_data_dir(rq) ? 0x23 : 0x21; if (hwif->config_data != wantclock) { hpt372n_set_clock(drive, wantclock); hwif->config_data = wantclock; }}/* * 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 * HOTSWAP ATA Infrastructure. */static void hpt3xx_reset (ide_drive_t *drive){}static int hpt3xx_tristate (ide_drive_t * drive, int state){ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 reg59h = 0, reset = (hwif->channel) ? 0x80 : 0x40; u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53; pci_read_config_byte(dev, 0x59, ®59h); pci_read_config_byte(dev, state_reg, ®XXh); if (state) { (void) ide_do_reset(drive); pci_write_config_byte(dev, state_reg, regXXh|0x80); pci_write_config_byte(dev, 0x59, reg59h|reset); } else { pci_write_config_byte(dev, 0x59, reg59h & ~(reset)); pci_write_config_byte(dev, state_reg, regXXh & ~(0x80)); (void) ide_do_reset(drive); } return 0;}/* * set/get power state for a drive. * turning the power off does the following things: * 1) soft-reset the drive * 2) tri-states the ide bus * * when we turn things back on, we need to re-initialize things. */#define TRISTATE_BIT 0x8000static int hpt370_busproc(ide_drive_t * drive, int state){ ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = hwif->pci_dev; u8 tristate = 0, resetmask = 0, bus_reg = 0; u16 tri_reg; hwif->bus_state = state; if (hwif->channel) { /* secondary channel */ tristate = 0x56; resetmask = 0x80; } else { /* primary channel */ tristate = 0x52; resetmask = 0x40; } /* grab status */ pci_read_config_word(dev, tristate, &tri_reg); pci_read_config_byte(dev, 0x59, &bus_reg); /* set the state. we don't set it if we don't need to do so. * make sure that the drive knows that it has failed if it's off */ switch (state) { case BUSSTATE_ON: hwif->drives[0].failures = 0; hwif->drives[1].failures = 0; if ((bus_reg & resetmask) == 0) return 0; tri_reg &= ~TRISTATE_BIT; bus_reg &= ~resetmask; break; case BUSSTATE_OFF: hwif->drives[0].failures = hwif->drives[0].max_failures + 1; hwif->drives[1].failures = hwif->drives[1].max_failures + 1; if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask)) return 0; tri_reg &= ~TRISTATE_BIT; bus_reg |= resetmask; break; case BUSSTATE_TRISTATE: hwif->drives[0].failures = hwif->drives[0].max_failures + 1; hwif->drives[1].failures = hwif->drives[1].max_failures + 1; if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask)) return 0; tri_reg |= TRISTATE_BIT; bus_reg |= resetmask; break; } pci_write_config_byte(dev, 0x59, bus_reg); pci_write_config_word(dev, tristate, tri_reg); return 0;}static void __devinit hpt366_clocking(ide_hwif_t *hwif){ u32 reg1 = 0; struct hpt_info *info = ide_get_hwifdata(hwif); pci_read_config_dword(hwif->pci_dev, 0x40, ®1); /* detect bus speed by looking at control reg timing: */ switch((reg1 >> 8) & 7) { case 5: info->speed = forty_base_hpt366; break; case 9: info->speed = twenty_five_base_hpt366; break; case 7: default: info->speed = thirty_three_base_hpt366; break; }}static void __devinit hpt37x_clocking(ide_hwif_t *hwif){ struct hpt_info *info = ide_get_hwifdata(hwif); struct pci_dev *dev = hwif->pci_dev; int adjust, i; u16 freq; u32 pll; u8 reg5bh; /* * default to pci clock. make sure MA15/16 are set to output * to prevent drives having problems with 40-pin cables. Needed * for some drives such as IBM-DTLA which will not enter ready * state on reset when PDIAG is a input. * * ToDo: should we set 0x21 when using PLL mode ? */ pci_write_config_byte(dev, 0x5b, 0x23); /* * 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; /* * 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 */ if(info->flags & 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 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 pll = F_LOW_PCI_66; if (pll == F_LOW_PCI_33) { if (info->revision >= 8) info->speed = thirty_three_base_hpt374; else if (info->revision >= 5) info->speed = thirty_three_base_hpt372; else if (info->revision >= 4) info->speed = thirty_three_base_hpt370a; else info->speed = thirty_three_base_hpt370; printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n"); } else if (pll == F_LOW_PCI_40) { /* Unsupported */ } else if (pll == F_LOW_PCI_50) { if (info->revision >= 8) info->speed = fifty_base_hpt370a; else if (info->revision >= 5) info->speed = fifty_base_hpt372; else if (info->revision >= 4) info->speed = fifty_base_hpt370a; else info->speed = fifty_base_hpt370a; printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n"); } else { if (info->revision >= 8) { printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n"); } else if (info->revision >= 5) info->speed = sixty_six_base_hpt372; else if (info->revision >= 4) info->speed = sixty_six_base_hpt370a; else info->speed = sixty_six_base_hpt370; printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n"); } } /* * only try the pll if we don't have a table for the clock * speed that we're running at. NOTE: the internal PLL will * result in slow reads when using a 33MHz PCI clock. we also * don't like to use the PLL because it will cause glitches * on PRST/SRST when the HPT state engine gets reset. * * ToDo: Use 66MHz PLL when ATA133 devices are present on a * 372 device so we can get ATA133 support */ if (info->speed) goto init_hpt37X_done; info->flags |= PLL_MODE; /* * FIXME: make this work correctly, esp with 372N as per * reference driver code. * * adjust PLL based upon PCI clock, enable it, and wait for * stabilization. */ adjust = 0; freq = (pll < F_LOW_PCI_50) ? 2 : 4; while (adjust++ < 6) { pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 | pll | 0x100); /* wait for clock stabilization */ for (i = 0; i < 0x50000; i++) { pci_read_config_byte(dev, 0x5b, ®5bh); if (reg5bh & 0x80) { /* spin looking for the clock to destabilize */ for (i = 0; i < 0x1000; ++i) { pci_read_config_byte(dev, 0x5b, ®5bh); if ((reg5bh & 0x80) == 0) goto pll_recal; } pci_read_config_dword(dev, 0x5c, &pll); pci_write_config_dword(dev, 0x5c, pll & ~0x100); pci_write_config_byte(dev, 0x5b, 0x21); if (info->revision >= 8) info->speed = fifty_base_hpt370a; else if (info->revision >= 5) info->speed = fifty_base_hpt372; else if (info->revision >= 4) info->speed = fifty_base_hpt370a; else info->speed = fifty_base_hpt370a; printk("HPT37X: using 50MHz internal PLL\n"); goto init_hpt37X_done; } }pll_recal: if (adjust & 1) pll -= (adjust >> 1); else pll += (adjust >> 1); } init_hpt37X_done: if (!info->speed) printk(KERN_ERR "HPT37X%s: unknown bus timing [%d %d].\n", (info->flags & IS_372N)?"N":"", pll, freq); /* reset state engine */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -