root/drivers/ata/pata_cs5536.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cs5536_read
  2. cs5536_write
  3. cs5536_program_dtc
  4. cs5536_cable_detect
  5. cs5536_set_piomode
  6. cs5536_set_dmamode
  7. cs5536_init_one

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * pata_cs5536.c        - CS5536 PATA for new ATA layer
   4  *                        (C) 2007 Martin K. Petersen <mkp@mkp.net>
   5  *                        (C) 2011 Bartlomiej Zolnierkiewicz
   6  *
   7  * Documentation:
   8  *      Available from AMD web site.
   9  *
  10  * The IDE timing registers for the CS5536 live in the Geode Machine
  11  * Specific Register file and not PCI config space.  Most BIOSes
  12  * virtualize the PCI registers so the chip looks like a standard IDE
  13  * controller.  Unfortunately not all implementations get this right.
  14  * In particular some have problems with unaligned accesses to the
  15  * virtualized PCI registers.  This driver always does full dword
  16  * writes to work around the issue.  Also, in case of a bad BIOS this
  17  * driver can be loaded with the "msr=1" parameter which forces using
  18  * the Machine Specific Registers to configure the device.
  19  */
  20 
  21 #include <linux/kernel.h>
  22 #include <linux/module.h>
  23 #include <linux/pci.h>
  24 #include <linux/blkdev.h>
  25 #include <linux/delay.h>
  26 #include <linux/libata.h>
  27 #include <scsi/scsi_host.h>
  28 #include <linux/dmi.h>
  29 
  30 #ifdef CONFIG_X86_32
  31 #include <asm/msr.h>
  32 static int use_msr;
  33 module_param_named(msr, use_msr, int, 0644);
  34 MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
  35 #else
  36 #undef rdmsr    /* avoid accidental MSR usage on, e.g. x86-64 */
  37 #undef wrmsr
  38 #define rdmsr(x, y, z) do { } while (0)
  39 #define wrmsr(x, y, z) do { } while (0)
  40 #define use_msr 0
  41 #endif
  42 
  43 #define DRV_NAME        "pata_cs5536"
  44 #define DRV_VERSION     "0.0.8"
  45 
  46 enum {
  47         MSR_IDE_CFG             = 0x51300010,
  48         PCI_IDE_CFG             = 0x40,
  49 
  50         CFG                     = 0,
  51         DTC                     = 2,
  52         CAST                    = 3,
  53         ETC                     = 4,
  54 
  55         IDE_CFG_CHANEN          = (1 << 1),
  56         IDE_CFG_CABLE           = (1 << 17) | (1 << 16),
  57 
  58         IDE_D0_SHIFT            = 24,
  59         IDE_D1_SHIFT            = 16,
  60         IDE_DRV_MASK            = 0xff,
  61 
  62         IDE_CAST_D0_SHIFT       = 6,
  63         IDE_CAST_D1_SHIFT       = 4,
  64         IDE_CAST_DRV_MASK       = 0x3,
  65         IDE_CAST_CMD_MASK       = 0xff,
  66         IDE_CAST_CMD_SHIFT      = 24,
  67 
  68         IDE_ETC_UDMA_MASK       = 0xc0,
  69 };
  70 
  71 /* Some Bachmann OT200 devices have a non working UDMA support due a
  72  * missing resistor.
  73  */
  74 static const struct dmi_system_id udma_quirk_dmi_table[] = {
  75         {
  76                 .ident = "Bachmann electronic OT200",
  77                 .matches = {
  78                         DMI_MATCH(DMI_SYS_VENDOR, "Bachmann electronic"),
  79                         DMI_MATCH(DMI_PRODUCT_NAME, "OT200"),
  80                         DMI_MATCH(DMI_PRODUCT_VERSION, "1")
  81                 },
  82         },
  83         { }
  84 };
  85 
  86 static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
  87 {
  88         if (unlikely(use_msr)) {
  89                 u32 dummy __maybe_unused;
  90 
  91                 rdmsr(MSR_IDE_CFG + reg, *val, dummy);
  92                 return 0;
  93         }
  94 
  95         return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
  96 }
  97 
  98 static int cs5536_write(struct pci_dev *pdev, int reg, int val)
  99 {
 100         if (unlikely(use_msr)) {
 101                 wrmsr(MSR_IDE_CFG + reg, val, 0);
 102                 return 0;
 103         }
 104 
 105         return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
 106 }
 107 
 108 static void cs5536_program_dtc(struct ata_device *adev, u8 tim)
 109 {
 110         struct pci_dev *pdev = to_pci_dev(adev->link->ap->host->dev);
 111         int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
 112         u32 dtc;
 113 
 114         cs5536_read(pdev, DTC, &dtc);
 115         dtc &= ~(IDE_DRV_MASK << dshift);
 116         dtc |= tim << dshift;
 117         cs5536_write(pdev, DTC, dtc);
 118 }
 119 
 120 /**
 121  *      cs5536_cable_detect     -       detect cable type
 122  *      @ap: Port to detect on
 123  *
 124  *      Perform cable detection for ATA66 capable cable.
 125  *
 126  *      Returns a cable type.
 127  */
 128 
 129 static int cs5536_cable_detect(struct ata_port *ap)
 130 {
 131         struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 132         u32 cfg;
 133 
 134         cs5536_read(pdev, CFG, &cfg);
 135 
 136         if (cfg & IDE_CFG_CABLE)
 137                 return ATA_CBL_PATA80;
 138         else
 139                 return ATA_CBL_PATA40;
 140 }
 141 
 142 /**
 143  *      cs5536_set_piomode              -       PIO setup
 144  *      @ap: ATA interface
 145  *      @adev: device on the interface
 146  */
 147 
 148 static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev)
 149 {
 150         static const u8 drv_timings[5] = {
 151                 0x98, 0x55, 0x32, 0x21, 0x20,
 152         };
 153 
 154         static const u8 addr_timings[5] = {
 155                 0x2, 0x1, 0x0, 0x0, 0x0,
 156         };
 157 
 158         static const u8 cmd_timings[5] = {
 159                 0x99, 0x92, 0x90, 0x22, 0x20,
 160         };
 161 
 162         struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 163         struct ata_device *pair = ata_dev_pair(adev);
 164         int mode = adev->pio_mode - XFER_PIO_0;
 165         int cmdmode = mode;
 166         int cshift = adev->devno ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
 167         u32 cast;
 168 
 169         if (pair)
 170                 cmdmode = min(mode, pair->pio_mode - XFER_PIO_0);
 171 
 172         cs5536_program_dtc(adev, drv_timings[mode]);
 173 
 174         cs5536_read(pdev, CAST, &cast);
 175 
 176         cast &= ~(IDE_CAST_DRV_MASK << cshift);
 177         cast |= addr_timings[mode] << cshift;
 178 
 179         cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);
 180         cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT;
 181 
 182         cs5536_write(pdev, CAST, cast);
 183 }
 184 
 185 /**
 186  *      cs5536_set_dmamode              -       DMA timing setup
 187  *      @ap: ATA interface
 188  *      @adev: Device being configured
 189  *
 190  */
 191 
 192 static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 193 {
 194         static const u8 udma_timings[6] = {
 195                 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6,
 196         };
 197 
 198         static const u8 mwdma_timings[3] = {
 199                 0x67, 0x21, 0x20,
 200         };
 201 
 202         struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 203         u32 etc;
 204         int mode = adev->dma_mode;
 205         int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
 206 
 207         cs5536_read(pdev, ETC, &etc);
 208 
 209         if (mode >= XFER_UDMA_0) {
 210                 etc &= ~(IDE_DRV_MASK << dshift);
 211                 etc |= udma_timings[mode - XFER_UDMA_0] << dshift;
 212         } else { /* MWDMA */
 213                 etc &= ~(IDE_ETC_UDMA_MASK << dshift);
 214                 cs5536_program_dtc(adev, mwdma_timings[mode - XFER_MW_DMA_0]);
 215         }
 216 
 217         cs5536_write(pdev, ETC, etc);
 218 }
 219 
 220 static struct scsi_host_template cs5536_sht = {
 221         ATA_BMDMA_SHT(DRV_NAME),
 222 };
 223 
 224 static struct ata_port_operations cs5536_port_ops = {
 225         .inherits               = &ata_bmdma32_port_ops,
 226         .cable_detect           = cs5536_cable_detect,
 227         .set_piomode            = cs5536_set_piomode,
 228         .set_dmamode            = cs5536_set_dmamode,
 229 };
 230 
 231 /**
 232  *      cs5536_init_one
 233  *      @dev: PCI device
 234  *      @id: Entry in match table
 235  *
 236  */
 237 
 238 static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 239 {
 240         static const struct ata_port_info info = {
 241                 .flags = ATA_FLAG_SLAVE_POSS,
 242                 .pio_mask = ATA_PIO4,
 243                 .mwdma_mask = ATA_MWDMA2,
 244                 .udma_mask = ATA_UDMA5,
 245                 .port_ops = &cs5536_port_ops,
 246         };
 247 
 248         static const struct ata_port_info no_udma_info = {
 249                 .flags = ATA_FLAG_SLAVE_POSS,
 250                 .pio_mask = ATA_PIO4,
 251                 .port_ops = &cs5536_port_ops,
 252         };
 253 
 254 
 255         const struct ata_port_info *ppi[2];
 256         u32 cfg;
 257 
 258         if (dmi_check_system(udma_quirk_dmi_table))
 259                 ppi[0] = &no_udma_info;
 260         else
 261                 ppi[0] = &info;
 262 
 263         ppi[1] = &ata_dummy_port_info;
 264 
 265         if (use_msr)
 266                 printk(KERN_ERR DRV_NAME ": Using MSR regs instead of PCI\n");
 267 
 268         cs5536_read(dev, CFG, &cfg);
 269 
 270         if ((cfg & IDE_CFG_CHANEN) == 0) {
 271                 printk(KERN_ERR DRV_NAME ": disabled by BIOS\n");
 272                 return -ENODEV;
 273         }
 274 
 275         return ata_pci_bmdma_init_one(dev, ppi, &cs5536_sht, NULL, 0);
 276 }
 277 
 278 static const struct pci_device_id cs5536[] = {
 279         { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_CS5536_IDE), },
 280         { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), },
 281         { },
 282 };
 283 
 284 static struct pci_driver cs5536_pci_driver = {
 285         .name           = DRV_NAME,
 286         .id_table       = cs5536,
 287         .probe          = cs5536_init_one,
 288         .remove         = ata_pci_remove_one,
 289 #ifdef CONFIG_PM_SLEEP
 290         .suspend        = ata_pci_device_suspend,
 291         .resume         = ata_pci_device_resume,
 292 #endif
 293 };
 294 
 295 module_pci_driver(cs5536_pci_driver);
 296 
 297 MODULE_AUTHOR("Martin K. Petersen");
 298 MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller");
 299 MODULE_LICENSE("GPL");
 300 MODULE_DEVICE_TABLE(pci, cs5536);
 301 MODULE_VERSION(DRV_VERSION);

/* [<][>][^][v][top][bottom][index][help] */