pdc202xx_new.c
来自「linux 内核源代码」· C语言 代码 · 共 602 行 · 第 1/2 页
C
602 行
/* * Promise TX2/TX4/TX2000/133 IDE driver * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Split from: * linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002 * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2005-2007 MontaVista Software, Inc. * Portions Copyright (C) 1999 Promise Technology, Inc. * Author: Frank Tiernan (frankt@promise.com) * Released under terms of General Public License */#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/blkdev.h>#include <linux/hdreg.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/ide.h>#include <asm/io.h>#include <asm/irq.h>#ifdef CONFIG_PPC_PMAC#include <asm/prom.h>#include <asm/pci-bridge.h>#endif#undef DEBUG#ifdef DEBUG#define DBG(fmt, args...) printk("%s: " fmt, __FUNCTION__, ## args)#else#define DBG(fmt, args...)#endifstatic const char *pdc_quirk_drives[] = { "QUANTUM FIREBALLlct08 08", "QUANTUM FIREBALLP KA6.4", "QUANTUM FIREBALLP KA9.1", "QUANTUM FIREBALLP LM20.4", "QUANTUM FIREBALLP KX13.6", "QUANTUM FIREBALLP KX20.5", "QUANTUM FIREBALLP KX27.3", "QUANTUM FIREBALLP LM20.5", NULL};static u8 max_dma_rate(struct pci_dev *pdev){ u8 mode; switch(pdev->device) { case PCI_DEVICE_ID_PROMISE_20277: case PCI_DEVICE_ID_PROMISE_20276: case PCI_DEVICE_ID_PROMISE_20275: case PCI_DEVICE_ID_PROMISE_20271: case PCI_DEVICE_ID_PROMISE_20269: mode = 4; break; case PCI_DEVICE_ID_PROMISE_20270: case PCI_DEVICE_ID_PROMISE_20268: mode = 3; break; default: return 0; } return mode;}/** * get_indexed_reg - Get indexed register * @hwif: for the port address * @index: index of the indexed register */static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index){ u8 value; outb(index, hwif->dma_vendor1); value = inb(hwif->dma_vendor3); DBG("index[%02X] value[%02X]\n", index, value); return value;}/** * set_indexed_reg - Set indexed register * @hwif: for the port address * @index: index of the indexed register */static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value){ outb(index, hwif->dma_vendor1); outb(value, hwif->dma_vendor3); DBG("index[%02X] value[%02X]\n", index, value);}/* * ATA Timing Tables based on 133 MHz PLL output clock. * * If the PLL outputs 100 MHz clock, the ASIC hardware will set * the timing registers automatically when "set features" command is * issued to the device. However, if the PLL output clock is 133 MHz, * the following tables must be used. */static struct pio_timing { u8 reg0c, reg0d, reg13;} pio_timings [] = { { 0xfb, 0x2b, 0xac }, /* PIO mode 0, IORDY off, Prefetch off */ { 0x46, 0x29, 0xa4 }, /* PIO mode 1, IORDY off, Prefetch off */ { 0x23, 0x26, 0x64 }, /* PIO mode 2, IORDY off, Prefetch off */ { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */ { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */};static struct mwdma_timing { u8 reg0e, reg0f;} mwdma_timings [] = { { 0xdf, 0x5f }, /* MWDMA mode 0 */ { 0x6b, 0x27 }, /* MWDMA mode 1 */ { 0x69, 0x25 }, /* MWDMA mode 2 */};static struct udma_timing { u8 reg10, reg11, reg12;} udma_timings [] = { { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */ { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */ { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */ { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */ { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */ { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */ { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */};static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed){ ide_hwif_t *hwif = HWIF(drive); u8 adj = (drive->dn & 1) ? 0x08 : 0x00; /* * IDE core issues SETFEATURES_XFER to the drive first (thanks to * IDE_HFLAG_POST_SET_MODE in ->host_flags). PDC202xx hardware will * automatically set the timing registers based on 100 MHz PLL output. * * As we set up the PLL to output 133 MHz for UltraDMA/133 capable * chips, we must override the default register settings... */ if (max_dma_rate(hwif->pci_dev) == 4) { u8 mode = speed & 0x07; switch (speed) { case XFER_UDMA_6: case XFER_UDMA_5: case XFER_UDMA_4: case XFER_UDMA_3: case XFER_UDMA_2: case XFER_UDMA_1: case XFER_UDMA_0: set_indexed_reg(hwif, 0x10 + adj, udma_timings[mode].reg10); set_indexed_reg(hwif, 0x11 + adj, udma_timings[mode].reg11); set_indexed_reg(hwif, 0x12 + adj, udma_timings[mode].reg12); break; case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: set_indexed_reg(hwif, 0x0e + adj, mwdma_timings[mode].reg0e); set_indexed_reg(hwif, 0x0f + adj, mwdma_timings[mode].reg0f); break; case XFER_PIO_4: case XFER_PIO_3: case XFER_PIO_2: case XFER_PIO_1: case XFER_PIO_0: set_indexed_reg(hwif, 0x0c + adj, pio_timings[mode].reg0c); set_indexed_reg(hwif, 0x0d + adj, pio_timings[mode].reg0d); set_indexed_reg(hwif, 0x13 + adj, pio_timings[mode].reg13); break; default: printk(KERN_ERR "pdc202xx_new: " "Unknown speed %d ignored\n", speed); } } else if (speed == XFER_UDMA_2) { /* Set tHOLD bit to 0 if using UDMA mode 2 */ u8 tmp = get_indexed_reg(hwif, 0x10 + adj); set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f); }}static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio){ pdcnew_set_mode(drive, XFER_PIO_0 + pio);}static u8 pdcnew_cable_detect(ide_hwif_t *hwif){ if (get_indexed_reg(hwif, 0x0b) & 0x04) return ATA_CBL_PATA40; else return ATA_CBL_PATA80;}static int pdcnew_quirkproc(ide_drive_t *drive){ const char **list, *model = drive->id->model; for (list = pdc_quirk_drives; *list != NULL; list++) if (strstr(model, *list) != NULL) return 2; return 0;}static void pdcnew_reset(ide_drive_t *drive){ /* * Deleted this because it is redundant from the caller. */ printk(KERN_WARNING "pdc202xx_new: %s channel reset.\n", HWIF(drive)->channel ? "Secondary" : "Primary");}/** * read_counter - Read the byte count registers * @dma_base: for the port address */static long __devinit read_counter(u32 dma_base){ u32 pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08; u8 cnt0, cnt1, cnt2, cnt3; long count = 0, last; int retry = 3; do { last = count; /* Read the current count */ outb(0x20, pri_dma_base + 0x01); cnt0 = inb(pri_dma_base + 0x03); outb(0x21, pri_dma_base + 0x01); cnt1 = inb(pri_dma_base + 0x03); outb(0x20, sec_dma_base + 0x01); cnt2 = inb(sec_dma_base + 0x03); outb(0x21, sec_dma_base + 0x01); cnt3 = inb(sec_dma_base + 0x03); count = (cnt3 << 23) | (cnt2 << 15) | (cnt1 << 8) | cnt0; /* * The 30-bit decrementing counter is read in 4 pieces. * Incorrect value may be read when the most significant bytes * are changing... */ } while (retry-- && (((last ^ count) & 0x3fff8000) || last < count)); DBG("cnt0[%02X] cnt1[%02X] cnt2[%02X] cnt3[%02X]\n", cnt0, cnt1, cnt2, cnt3); return count;}/** * detect_pll_input_clock - Detect the PLL input clock in Hz. * @dma_base: for the port address * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock. */static long __devinit detect_pll_input_clock(unsigned long dma_base){ struct timeval start_time, end_time; long start_count, end_count; long pll_input, usec_elapsed; u8 scr1; start_count = read_counter(dma_base); do_gettimeofday(&start_time); /* Start the test mode */ outb(0x01, dma_base + 0x01); scr1 = inb(dma_base + 0x03);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?