diff options
Diffstat (limited to 'drivers/ata/pata_cs5536.c')
| -rw-r--r-- | drivers/ata/pata_cs5536.c | 163 |
1 files changed, 87 insertions, 76 deletions
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index 21ee23f89e8..6c15a554efb 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -1,6 +1,7 @@ /* * pata_cs5536.c - CS5536 PATA for new ATA layer * (C) 2007 Martin K. Petersen <mkp@mkp.net> + * (C) 2011 Bartlomiej Zolnierkiewicz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -32,35 +33,39 @@ #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 <linux/libata.h> #include <scsi/scsi_host.h> +#include <linux/dmi.h> + +#ifdef CONFIG_X86_32 #include <asm/msr.h> +static int use_msr; +module_param_named(msr, use_msr, int, 0644); +MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); +#else +#undef rdmsr /* avoid accidental MSR usage on, e.g. x86-64 */ +#undef wrmsr +#define rdmsr(x, y, z) do { } while (0) +#define wrmsr(x, y, z) do { } while (0) +#define use_msr 0 +#endif #define DRV_NAME "pata_cs5536" -#define DRV_VERSION "0.0.7" +#define DRV_VERSION "0.0.8" enum { - CFG = 0, - DTC = 1, - CAST = 2, - ETC = 3, - - MSR_IDE_BASE = 0x51300000, - MSR_IDE_CFG = (MSR_IDE_BASE + 0x10), - MSR_IDE_DTC = (MSR_IDE_BASE + 0x12), - MSR_IDE_CAST = (MSR_IDE_BASE + 0x13), - MSR_IDE_ETC = (MSR_IDE_BASE + 0x14), - + MSR_IDE_CFG = 0x51300010, PCI_IDE_CFG = 0x40, - PCI_IDE_DTC = 0x48, - PCI_IDE_CAST = 0x4c, - PCI_IDE_ETC = 0x50, - IDE_CFG_CHANEN = 0x2, - IDE_CFG_CABLE = 0x10000, + CFG = 0, + DTC = 2, + CAST = 3, + ETC = 4, + + IDE_CFG_CHANEN = (1 << 1), + IDE_CFG_CABLE = (1 << 17) | (1 << 16), IDE_D0_SHIFT = 24, IDE_D1_SHIFT = 16, @@ -72,47 +77,65 @@ enum { IDE_CAST_CMD_MASK = 0xff, IDE_CAST_CMD_SHIFT = 24, - IDE_ETC_NODMA = 0x03, + IDE_ETC_UDMA_MASK = 0xc0, }; -static int use_msr; - -static const u32 msr_reg[4] = { - MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC, -}; - -static const u8 pci_reg[4] = { - PCI_IDE_CFG, PCI_IDE_DTC, PCI_IDE_CAST, PCI_IDE_ETC, +/* Some Bachmann OT200 devices have a non working UDMA support due a + * missing resistor. + */ +static const struct dmi_system_id udma_quirk_dmi_table[] = { + { + .ident = "Bachmann electronic OT200", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Bachmann electronic"), + DMI_MATCH(DMI_PRODUCT_NAME, "OT200"), + DMI_MATCH(DMI_PRODUCT_VERSION, "1") + }, + }, + { } }; -static inline int cs5536_read(struct pci_dev *pdev, int reg, u32 *val) +static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val) { if (unlikely(use_msr)) { - u32 dummy; + u32 dummy __maybe_unused; - rdmsr(msr_reg[reg], *val, dummy); + rdmsr(MSR_IDE_CFG + reg, *val, dummy); return 0; } - return pci_read_config_dword(pdev, pci_reg[reg], val); + return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); } -static inline int cs5536_write(struct pci_dev *pdev, int reg, int val) +static int cs5536_write(struct pci_dev *pdev, int reg, int val) { if (unlikely(use_msr)) { - wrmsr(msr_reg[reg], val, 0); + wrmsr(MSR_IDE_CFG + reg, val, 0); return 0; } - return pci_write_config_dword(pdev, pci_reg[reg], val); + return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); +} + +static void cs5536_program_dtc(struct ata_device *adev, u8 tim) +{ + struct pci_dev *pdev = to_pci_dev(adev->link->ap->host->dev); + int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT; + u32 dtc; + + cs5536_read(pdev, DTC, &dtc); + dtc &= ~(IDE_DRV_MASK << dshift); + dtc |= tim << dshift; + cs5536_write(pdev, DTC, dtc); } /** * cs5536_cable_detect - detect cable type * @ap: Port to detect on * - * Perform cable detection for ATA66 capable cable. Return a libata - * cable type. + * Perform cable detection for ATA66 capable cable. + * + * Returns a cable type. */ static int cs5536_cable_detect(struct ata_port *ap) @@ -122,7 +145,7 @@ static int cs5536_cable_detect(struct ata_port *ap) cs5536_read(pdev, CFG, &cfg); - if (cfg & (IDE_CFG_CABLE << ap->port_no)) + if (cfg & IDE_CFG_CABLE) return ATA_CBL_PATA80; else return ATA_CBL_PATA40; @@ -152,19 +175,15 @@ static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev) struct ata_device *pair = ata_dev_pair(adev); int mode = adev->pio_mode - XFER_PIO_0; int cmdmode = mode; - int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT; int cshift = adev->devno ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; - u32 dtc, cast, etc; + u32 cast; if (pair) cmdmode = min(mode, pair->pio_mode - XFER_PIO_0); - cs5536_read(pdev, DTC, &dtc); - cs5536_read(pdev, CAST, &cast); - cs5536_read(pdev, ETC, &etc); + cs5536_program_dtc(adev, drv_timings[mode]); - dtc &= ~(IDE_DRV_MASK << dshift); - dtc |= drv_timings[mode] << dshift; + cs5536_read(pdev, CAST, &cast); cast &= ~(IDE_CAST_DRV_MASK << cshift); cast |= addr_timings[mode] << cshift; @@ -172,12 +191,7 @@ static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev) cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT); cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT; - etc &= ~(IDE_DRV_MASK << dshift); - etc |= IDE_ETC_NODMA << dshift; - - cs5536_write(pdev, DTC, dtc); cs5536_write(pdev, CAST, cast); - cs5536_write(pdev, ETC, etc); } /** @@ -198,25 +212,21 @@ static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev) }; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u32 dtc, etc; + u32 etc; int mode = adev->dma_mode; int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT; - if (mode >= XFER_UDMA_0) { - cs5536_read(pdev, ETC, &etc); + cs5536_read(pdev, ETC, &etc); + if (mode >= XFER_UDMA_0) { etc &= ~(IDE_DRV_MASK << dshift); etc |= udma_timings[mode - XFER_UDMA_0] << dshift; - - cs5536_write(pdev, ETC, etc); } else { /* MWDMA */ - cs5536_read(pdev, DTC, &dtc); - - dtc &= ~(IDE_DRV_MASK << dshift); - dtc |= mwdma_timings[mode - XFER_MW_DMA_0] << dshift; - - cs5536_write(pdev, DTC, dtc); + etc &= ~(IDE_ETC_UDMA_MASK << dshift); + cs5536_program_dtc(adev, mwdma_timings[mode - XFER_MW_DMA_0]); } + + cs5536_write(pdev, ETC, etc); } static struct scsi_host_template cs5536_sht = { @@ -247,9 +257,23 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) .port_ops = &cs5536_port_ops, }; - const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info }; + static const struct ata_port_info no_udma_info = { + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, + .port_ops = &cs5536_port_ops, + }; + + + const struct ata_port_info *ppi[2]; u32 cfg; + if (dmi_check_system(udma_quirk_dmi_table)) + ppi[0] = &no_udma_info; + else + ppi[0] = &info; + + ppi[1] = &ata_dummy_port_info; + if (use_msr) printk(KERN_ERR DRV_NAME ": Using MSR regs instead of PCI\n"); @@ -273,29 +297,16 @@ static struct pci_driver cs5536_pci_driver = { .id_table = cs5536, .probe = cs5536_init_one, .remove = ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, #endif }; -static int __init cs5536_init(void) -{ - return pci_register_driver(&cs5536_pci_driver); -} - -static void __exit cs5536_exit(void) -{ - pci_unregister_driver(&cs5536_pci_driver); -} +module_pci_driver(cs5536_pci_driver); MODULE_AUTHOR("Martin K. Petersen"); MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, cs5536); MODULE_VERSION(DRV_VERSION); -module_param_named(msr, use_msr, int, 0644); -MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); - -module_init(cs5536_init); -module_exit(cs5536_exit); |
