1 2 3#include <linux/kernel.h> 4#include <linux/module.h> 5#include <linux/pci.h> 6#include <linux/init.h> 7#include <linux/ide.h> 8#include <asm/msr.h> 9 10#define DRV_NAME "cs5536" 11 12enum { 13 MSR_IDE_CFG = 0x51300010, 14 PCI_IDE_CFG = 0x40, 15 16 CFG = 0, 17 DTC = 2, 18 CAST = 3, 19 ETC = 4, 20 21 IDE_CFG_CHANEN = (1 << 1), 22 IDE_CFG_CABLE = (1 << 17) | (1 << 16), 23 24 IDE_D0_SHIFT = 24, 25 IDE_D1_SHIFT = 16, 26 IDE_DRV_MASK = 0xff, 27 28 IDE_CAST_D0_SHIFT = 6, 29 IDE_CAST_D1_SHIFT = 4, 30 IDE_CAST_DRV_MASK = 0x3, 31 32 IDE_CAST_CMD_SHIFT = 24, 33 IDE_CAST_CMD_MASK = 0xff, 34 35 IDE_ETC_UDMA_MASK = 0xc0, 36}; 37 38static int use_msr; 39 40static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val) 41{ 42 if (unlikely(use_msr)) { 43 u32 dummy; 44 45 rdmsr(MSR_IDE_CFG + reg, *val, dummy); 46 return 0; 47 } 48 49 return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); 50} 51 52static int cs5536_write(struct pci_dev *pdev, int reg, int val) 53{ 54 if (unlikely(use_msr)) { 55 wrmsr(MSR_IDE_CFG + reg, val, 0); 56 return 0; 57 } 58 59 return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); 60} 61 62static void cs5536_program_dtc(ide_drive_t *drive, u8 tim) 63{ 64 struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); 65 int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; 66 u32 dtc; 67 68 cs5536_read(pdev, DTC, &dtc); 69 dtc &= ~(IDE_DRV_MASK << dshift); 70 dtc |= tim << dshift; 71 cs5536_write(pdev, DTC, dtc); 72} 73 74/** 75 * cs5536_cable_detect - detect cable type 76 * @hwif: Port to detect on 77 * 78 * Perform cable detection for ATA66 capable cable. 79 * 80 * Returns a cable type. 81 */ 82 83static u8 cs5536_cable_detect(ide_hwif_t *hwif) 84{ 85 struct pci_dev *pdev = to_pci_dev(hwif->dev); 86 u32 cfg; 87 88 cs5536_read(pdev, CFG, &cfg); 89 90 if (cfg & IDE_CFG_CABLE) 91 return ATA_CBL_PATA80; 92 else 93 return ATA_CBL_PATA40; 94} 95 96/** 97 * cs5536_set_pio_mode - PIO timing setup 98 * @hwif: ATA port 99 * @drive: ATA device 100 */ 101 102static void cs5536_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) 103{ 104 static const u8 drv_timings[5] = { 105 0x98, 0x55, 0x32, 0x21, 0x20, 106 }; 107 108 static const u8 addr_timings[5] = { 109 0x2, 0x1, 0x0, 0x0, 0x0, 110 }; 111 112 static const u8 cmd_timings[5] = { 113 0x99, 0x92, 0x90, 0x22, 0x20, 114 }; 115 116 struct pci_dev *pdev = to_pci_dev(hwif->dev); 117 ide_drive_t *pair = ide_get_pair_dev(drive); 118 int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; 119 unsigned long timings = (unsigned long)ide_get_drivedata(drive); 120 u32 cast; 121 const u8 pio = drive->pio_mode - XFER_PIO_0; 122 u8 cmd_pio = pio; 123 124 if (pair) 125 cmd_pio = min_t(u8, pio, pair->pio_mode - XFER_PIO_0); 126 127 timings &= (IDE_DRV_MASK << 8); 128 timings |= drv_timings[pio]; 129 ide_set_drivedata(drive, (void *)timings); 130 131 cs5536_program_dtc(drive, drv_timings[pio]); 132 133 cs5536_read(pdev, CAST, &cast); 134 135 cast &= ~(IDE_CAST_DRV_MASK << cshift); 136 cast |= addr_timings[pio] << cshift; 137 138 cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT); 139 cast |= cmd_timings[cmd_pio] << IDE_CAST_CMD_SHIFT; 140 141 cs5536_write(pdev, CAST, cast); 142} 143 144/** 145 * cs5536_set_dma_mode - DMA timing setup 146 * @hwif: ATA port 147 * @drive: ATA device 148 */ 149 150static void cs5536_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) 151{ 152 static const u8 udma_timings[6] = { 153 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, 154 }; 155 156 static const u8 mwdma_timings[3] = { 157 0x67, 0x21, 0x20, 158 }; 159 160 struct pci_dev *pdev = to_pci_dev(hwif->dev); 161 int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; 162 unsigned long timings = (unsigned long)ide_get_drivedata(drive); 163 u32 etc; 164 const u8 mode = drive->dma_mode; 165 166 cs5536_read(pdev, ETC, &etc); 167 168 if (mode >= XFER_UDMA_0) { 169 etc &= ~(IDE_DRV_MASK << dshift); 170 etc |= udma_timings[mode - XFER_UDMA_0] << dshift; 171 } else { /* MWDMA */ 172 etc &= ~(IDE_ETC_UDMA_MASK << dshift); 173 timings &= IDE_DRV_MASK; 174 timings |= mwdma_timings[mode - XFER_MW_DMA_0] << 8; 175 ide_set_drivedata(drive, (void *)timings); 176 } 177 178 cs5536_write(pdev, ETC, etc); 179} 180 181static void cs5536_dma_start(ide_drive_t *drive) 182{ 183 unsigned long timings = (unsigned long)ide_get_drivedata(drive); 184 185 if (drive->current_speed < XFER_UDMA_0 && 186 (timings >> 8) != (timings & IDE_DRV_MASK)) 187 cs5536_program_dtc(drive, timings >> 8); 188 189 ide_dma_start(drive); 190} 191 192static int cs5536_dma_end(ide_drive_t *drive) 193{ 194 int ret = ide_dma_end(drive); 195 unsigned long timings = (unsigned long)ide_get_drivedata(drive); 196 197 if (drive->current_speed < XFER_UDMA_0 && 198 (timings >> 8) != (timings & IDE_DRV_MASK)) 199 cs5536_program_dtc(drive, timings & IDE_DRV_MASK); 200 201 return ret; 202} 203 204static const struct ide_port_ops cs5536_port_ops = { 205 .set_pio_mode = cs5536_set_pio_mode, 206 .set_dma_mode = cs5536_set_dma_mode, 207 .cable_detect = cs5536_cable_detect, 208}; 209 210static const struct ide_dma_ops cs5536_dma_ops = { 211 .dma_host_set = ide_dma_host_set, 212 .dma_setup = ide_dma_setup, 213 .dma_start = cs5536_dma_start, 214 .dma_end = cs5536_dma_end, 215 .dma_test_irq = ide_dma_test_irq, 216 .dma_lost_irq = ide_dma_lost_irq, 217 .dma_timer_expiry = ide_dma_sff_timer_expiry, 218 .dma_sff_read_status = ide_dma_sff_read_status, 219}; 220 221static const struct ide_port_info cs5536_info = { 222 .name = DRV_NAME, 223 .port_ops = &cs5536_port_ops, 224 .dma_ops = &cs5536_dma_ops, 225 .host_flags = IDE_HFLAG_SINGLE, 226 .pio_mask = ATA_PIO4, 227 .mwdma_mask = ATA_MWDMA2, 228 .udma_mask = ATA_UDMA5, 229}; 230 231/** 232 * cs5536_init_one 233 * @dev: PCI device 234 * @id: Entry in match table 235 */ 236 237static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) 238{ 239 u32 cfg; 240 241 if (use_msr) 242 printk(KERN_INFO DRV_NAME ": Using MSR regs instead of PCI\n"); 243 244 cs5536_read(dev, CFG, &cfg); 245 246 if ((cfg & IDE_CFG_CHANEN) == 0) { 247 printk(KERN_ERR DRV_NAME ": disabled by BIOS\n"); 248 return -ENODEV; 249 } 250 251 return ide_pci_init_one(dev, &cs5536_info, NULL); 252} 253 254static const struct pci_device_id cs5536_pci_tbl[] = { 255 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), }, 256 { }, 257}; 258 259static struct pci_driver cs5536_pci_driver = { 260 .name = DRV_NAME, 261 .id_table = cs5536_pci_tbl, 262 .probe = cs5536_init_one, 263 .remove = ide_pci_remove, 264 .suspend = ide_pci_suspend, 265 .resume = ide_pci_resume, 266}; 267 268static int __init cs5536_init(void) 269{ 270 return pci_register_driver(&cs5536_pci_driver); 271} 272 273static void __exit cs5536_exit(void) 274{ 275 pci_unregister_driver(&cs5536_pci_driver); 276} 277 278MODULE_AUTHOR("Martin K. Petersen, Bartlomiej Zolnierkiewicz"); 279MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller"); 280MODULE_LICENSE("GPL"); 281MODULE_DEVICE_TABLE(pci, cs5536_pci_tbl); 282 283module_param_named(msr, use_msr, int, 0644); 284MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); 285 286module_init(cs5536_init); 287module_exit(cs5536_exit); 288