?? pata_via.c
字號:
/* * pata_via.c - VIA PATA for new ATA layer * (C) 2005-2006 Red Hat Inc * Alan Cox <alan@redhat.com> * * Documentation * Most chipset documentation available under NDA only * * VIA version guide * VIA VT82C561 - early design, uses ata_generic currently * VIA VT82C576 - MWDMA, 33Mhz * VIA VT82C586 - MWDMA, 33Mhz * VIA VT82C586a - Added UDMA to 33Mhz * VIA VT82C586b - UDMA33 * VIA VT82C596a - Nonfunctional UDMA66 * VIA VT82C596b - Working UDMA66 * VIA VT82C686 - Nonfunctional UDMA66 * VIA VT82C686a - Working UDMA66 * VIA VT82C686b - Updated to UDMA100 * VIA VT8231 - UDMA100 * VIA VT8233 - UDMA100 * VIA VT8233a - UDMA133 * VIA VT8233c - UDMA100 * VIA VT8235 - UDMA133 * VIA VT8237 - UDMA133 * VIA VT8237S - UDMA133 * VIA VT8251 - UDMA133 * * Most registers remain compatible across chips. Others start reserved * and acquire sensible semantics if set to 1 (eg cable detect). A few * exceptions exist, notably around the FIFO settings. * * One additional quirk of the VIA design is that like ALi they use few * PCI IDs for a lot of chips. * * Based heavily on: * * Version 3.38 * * VIA IDE driver for Linux. Supported southbridges: * * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a, * vt8235, vt8237 * * Copyright (c) 2000-2002 Vojtech Pavlik * * Based on the work of: * Michel Aubry * Jeff Garzik * Andre Hedrick */#include <linux/kernel.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <scsi/scsi_host.h>#include <linux/libata.h>#include <linux/dmi.h>#define DRV_NAME "pata_via"#define DRV_VERSION "0.3.3"/* * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx * driver. */enum { VIA_UDMA = 0x007, VIA_UDMA_NONE = 0x000, VIA_UDMA_33 = 0x001, VIA_UDMA_66 = 0x002, VIA_UDMA_100 = 0x003, VIA_UDMA_133 = 0x004, VIA_BAD_PREQ = 0x010, /* Crashes if PREQ# till DDACK# set */ VIA_BAD_CLK66 = 0x020, /* 66 MHz clock doesn't work correctly */ VIA_SET_FIFO = 0x040, /* Needs to have FIFO split set */ VIA_NO_UNMASK = 0x080, /* Doesn't work with IRQ unmasking on */ VIA_BAD_ID = 0x100, /* Has wrong vendor ID (0x1107) */ VIA_BAD_AST = 0x200, /* Don't touch Address Setup Timing */ VIA_NO_ENABLES = 0x400, /* Has no enablebits */ VIA_SATA_PATA = 0x800, /* SATA/PATA combined configuration */};/* * VIA SouthBridge chips. */static const struct via_isa_bridge { const char *name; u16 id; u8 rev_min; u8 rev_max; u16 flags;} via_isa_bridges[] = { { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA }, { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES}, { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 }, { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 }, { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 }, { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 }, { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 }, { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 }, { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 }, { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 }, { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO }, { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ }, { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO }, { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO }, { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO }, { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK }, { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID }, { NULL }};/* * Cable special cases */static const struct dmi_system_id cable_dmi_table[] = { { .ident = "Acer Ferrari 3400", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Acer,Inc."), DMI_MATCH(DMI_BOARD_NAME, "Ferrari 3400"), }, }, { }};static int via_cable_override(struct pci_dev *pdev){ /* Systems by DMI */ if (dmi_check_system(cable_dmi_table)) return 1; /* Arima W730-K8/Targa Visionary 811/... */ if (pdev->subsystem_vendor == 0x161F && pdev->subsystem_device == 0x2032) return 1; return 0;}/** * via_cable_detect - cable detection * @ap: ATA port * * Perform cable detection. Actually for the VIA case the BIOS * already did this for us. We read the values provided by the * BIOS. If you are using an 8235 in a non-PC configuration you * may need to update this code. * * Hotplug also impacts on this. */static int via_cable_detect(struct ata_port *ap) { const struct via_isa_bridge *config = ap->host->private_data; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 ata66; if (via_cable_override(pdev)) return ATA_CBL_PATA40_SHORT; if ((config->flags & VIA_SATA_PATA) && ap->port_no == 0) return ATA_CBL_SATA; /* Early chips are 40 wire */ if ((config->flags & VIA_UDMA) < VIA_UDMA_66) return ATA_CBL_PATA40; /* UDMA 66 chips have only drive side logic */ else if ((config->flags & VIA_UDMA) < VIA_UDMA_100) return ATA_CBL_PATA_UNK; /* UDMA 100 or later */ pci_read_config_dword(pdev, 0x50, &ata66); /* Check both the drive cable reporting bits, we might not have two drives */ if (ata66 & (0x10100000 >> (16 * ap->port_no))) return ATA_CBL_PATA80; /* Check with ACPI so we can spot BIOS reported SATA bridges */ if (ata_acpi_init_gtm(ap) && ata_acpi_cbl_80wire(ap, ata_acpi_init_gtm(ap))) return ATA_CBL_PATA80; return ATA_CBL_PATA40;}static int via_pre_reset(struct ata_link *link, unsigned long deadline){ struct ata_port *ap = link->ap; const struct via_isa_bridge *config = ap->host->private_data; if (!(config->flags & VIA_NO_ENABLES)) { static const struct pci_bits via_enable_bits[] = { { 0x40, 1, 0x02, 0x02 }, { 0x40, 1, 0x01, 0x01 } }; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &via_enable_bits[ap->port_no])) return -ENOENT; } return ata_sff_prereset(link, deadline);}/** * via_do_set_mode - set initial PIO mode data * @ap: ATA interface * @adev: ATA device * @mode: ATA mode being programmed * @tdiv: Clocks per PCI clock * @set_ast: Set to program address setup * @udma_type: UDMA mode/format of registers * * Program the VIA registers for DMA and PIO modes. Uses the ata timing * support in order to compute modes. * * FIXME: Hotplug will require we serialize multiple mode changes * on the two channels. */static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mode, int tdiv, int set_ast, int udma_type){ struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct ata_device *peer = ata_dev_pair(adev); struct ata_timing t, p; static int via_clock = 33333; /* Bus clock in kHZ - ought to be tunable one day */ unsigned long T = 1000000000 / via_clock; unsigned long UT = T/tdiv; int ut; int offset = 3 - (2*ap->port_no) - adev->devno; /* Calculate the timing values we require */ ata_timing_compute(adev, mode, &t, T, UT); /* We share 8bit timing so we must merge the constraints */ if (peer) { if (peer->pio_mode) { ata_timing_compute(peer, peer->pio_mode, &p, T, UT); ata_timing_merge(&p, &t, &t, ATA_TIMING_8BIT); } } /* Address setup is programmable but breaks on UDMA133 setups */ if (set_ast) { u8 setup; /* 2 bits per drive */ int shift = 2 * offset; pci_read_config_byte(pdev, 0x4C, &setup); setup &= ~(3 << shift); setup |= clamp_val(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */ pci_write_config_byte(pdev, 0x4C, setup); } /* Load the PIO mode bits */ pci_write_config_byte(pdev, 0x4F - ap->port_no, ((clamp_val(t.act8b, 1, 16) - 1) << 4) | (clamp_val(t.rec8b, 1, 16) - 1)); pci_write_config_byte(pdev, 0x48 + offset, ((clamp_val(t.active, 1, 16) - 1) << 4) | (clamp_val(t.recover, 1, 16) - 1)); /* Load the UDMA bits according to type */ switch(udma_type) { default: /* BUG() ? */ /* fall through */ case 33: ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 5) - 2)) : 0x03; break; case 66: ut = t.udma ? (0xe8 | (clamp_val(t.udma, 2, 9) - 2)) : 0x0f; break; case 100: ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07; break; case 133: ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07; break; } /* Set UDMA unless device is not UDMA capable */ if (udma_type && t.udma) { u8 cable80_status; /* Get 80-wire cable detection bit */ pci_read_config_byte(pdev, 0x50 + offset, &cable80_status); cable80_status &= 0x10; pci_write_config_byte(pdev, 0x50 + offset, ut | cable80_status); }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -