1/* 2 * CS5536 PATA support 3 * (C) 2007 Martin K. Petersen <mkp@mkp.net> 4 * (C) 2009 Bartlomiej Zolnierkiewicz 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 * Documentation: 20 * Available from AMD web site. 21 * 22 * The IDE timing registers for the CS5536 live in the Geode Machine 23 * Specific Register file and not PCI config space. Most BIOSes 24 * virtualize the PCI registers so the chip looks like a standard IDE 25 * controller. Unfortunately not all implementations get this right. 26 * In particular some have problems with unaligned accesses to the 27 * virtualized PCI registers. This driver always does full dword 28 * writes to work around the issue. Also, in case of a bad BIOS this 29 * driver can be loaded with the "msr=1" parameter which forces using 30 * the Machine Specific Registers to configure the device. 31 */ 32 33#include <linux/kernel.h> 34#include <linux/module.h> 35#include <linux/pci.h> 36#include <linux/init.h> 37#include <linux/ide.h> 38#include <asm/msr.h> 39 40#define DRV_NAME "cs5536" 41 42enum { 43 MSR_IDE_CFG = 0x51300010, 44 PCI_IDE_CFG = 0x40, 45 46 CFG = 0, 47 DTC = 2, 48 CAST = 3, 49 ETC = 4, 50 51 IDE_CFG_CHANEN = (1 << 1), 52 IDE_CFG_CABLE = (1 << 17) | (1 << 16), 53 54 IDE_D0_SHIFT = 24, 55 IDE_D1_SHIFT = 16, 56 IDE_DRV_MASK = 0xff, 57 58 IDE_CAST_D0_SHIFT = 6, 59 IDE_CAST_D1_SHIFT = 4, 60 IDE_CAST_DRV_MASK = 0x3, 61 62 IDE_CAST_CMD_SHIFT = 24, 63 IDE_CAST_CMD_MASK = 0xff, 64 65 IDE_ETC_UDMA_MASK = 0xc0, 66}; 67 68static int use_msr; 69 70static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val) 71{ 72 if (unlikely(use_msr)) { 73 u32 dummy; 74 75 rdmsr(MSR_IDE_CFG + reg, *val, dummy); 76 return 0; 77 } 78 79 return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); 80} 81 82static int cs5536_write(struct pci_dev *pdev, int reg, int val) 83{ 84 if (unlikely(use_msr)) { 85 wrmsr(MSR_IDE_CFG + reg, val, 0); 86 return 0; 87 } 88 89 return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); 90} 91 92static void cs5536_program_dtc(ide_drive_t *drive, u8 tim) 93{ 94 struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); 95 int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; 96 u32 dtc; 97 98 cs5536_read(pdev, DTC, &dtc); 99 dtc &= ~(IDE_DRV_MASK << dshift); 100 dtc |= tim << dshift; 101 cs5536_write(pdev, DTC, dtc); 102} 103 104/** 105 * cs5536_cable_detect - detect cable type 106 * @hwif: Port to detect on 107 * 108 * Perform cable detection for ATA66 capable cable. 109 * 110 * Returns a cable type. 111 */ 112 113static u8 cs5536_cable_detect(ide_hwif_t *hwif) 114{ 115 struct pci_dev *pdev = to_pci_dev(hwif->dev); 116 u32 cfg; 117 118 cs5536_read(pdev, CFG, &cfg); 119 120 if (cfg & IDE_CFG_CABLE) 121 return ATA_CBL_PATA80; 122 else 123 return ATA_CBL_PATA40; 124} 125 126/** 127 * cs5536_set_pio_mode - PIO timing setup 128 * @hwif: ATA port 129 * @drive: ATA device 130 */ 131 132static void cs5536_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) 133{ 134 static const u8 drv_timings[5] = { 135 0x98, 0x55, 0x32, 0x21, 0x20, 136 }; 137 138 static const u8 addr_timings[5] = { 139 0x2, 0x1, 0x0, 0x0, 0x0, 140 }; 141 142 static const u8 cmd_timings[5] = { 143 0x99, 0x92, 0x90, 0x22, 0x20, 144 }; 145 146 struct pci_dev *pdev = to_pci_dev(hwif->dev); 147 ide_drive_t *pair = ide_get_pair_dev(drive); 148 int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; 149 unsigned long timings = (unsigned long)ide_get_drivedata(drive); 150 u32 cast; 151 const u8 pio = drive->pio_mode - XFER_PIO_0; 152 u8 cmd_pio = pio; 153 154 if (pair) 155 cmd_pio = min_t(u8, pio, pair->pio_mode - XFER_PIO_0); 156 157 timings &= (IDE_DRV_MASK << 8); 158 timings |= drv_timings[pio]; 159 ide_set_drivedata(drive, (void *)timings); 160 161 cs5536_program_dtc(drive, drv_timings[pio]); 162 163 cs5536_read(pdev, CAST, &cast); 164 165 cast &= ~(IDE_CAST_DRV_MASK << cshift); 166 cast |= addr_timings[pio] << cshift; 167 168 cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT); 169 cast |= cmd_timings[cmd_pio] << IDE_CAST_CMD_SHIFT; 170 171 cs5536_write(pdev, CAST, cast); 172} 173 174/** 175 * cs5536_set_dma_mode - DMA timing setup 176 * @hwif: ATA port 177 * @drive: ATA device 178 */ 179 180static void cs5536_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) 181{ 182 static const u8 udma_timings[6] = { 183 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, 184 }; 185 186 static const u8 mwdma_timings[3] = { 187 0x67, 0x21, 0x20, 188 }; 189 190 struct pci_dev *pdev = to_pci_dev(hwif->dev); 191 int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; 192 unsigned long timings = (unsigned long)ide_get_drivedata(drive); 193 u32 etc; 194 const u8 mode = drive->dma_mode; 195 196 cs5536_read(pdev, ETC, &etc); 197 198 if (mode >= XFER_UDMA_0) { 199 etc &= ~(IDE_DRV_MASK << dshift); 200 etc |= udma_timings[mode - XFER_UDMA_0] << dshift; 201 } else { /* MWDMA */ 202 etc &= ~(IDE_ETC_UDMA_MASK << dshift); 203 timings &= IDE_DRV_MASK; 204 timings |= mwdma_timings[mode - XFER_MW_DMA_0] << 8; 205 ide_set_drivedata(drive, (void *)timings); 206 } 207 208 cs5536_write(pdev, ETC, etc); 209} 210 211static void cs5536_dma_start(ide_drive_t *drive) 212{ 213 unsigned long timings = (unsigned long)ide_get_drivedata(drive); 214 215 if (drive->current_speed < XFER_UDMA_0 && 216 (timings >> 8) != (timings & IDE_DRV_MASK)) 217 cs5536_program_dtc(drive, timings >> 8); 218 219 ide_dma_start(drive); 220} 221 222static int cs5536_dma_end(ide_drive_t *drive) 223{ 224 int ret = ide_dma_end(drive); 225 unsigned long timings = (unsigned long)ide_get_drivedata(drive); 226 227 if (drive->current_speed < XFER_UDMA_0 && 228 (timings >> 8) != (timings & IDE_DRV_MASK)) 229 cs5536_program_dtc(drive, timings & IDE_DRV_MASK); 230 231 return ret; 232} 233 234static const struct ide_port_ops cs5536_port_ops = { 235 .set_pio_mode = cs5536_set_pio_mode, 236 .set_dma_mode = cs5536_set_dma_mode, 237 .cable_detect = cs5536_cable_detect, 238}; 239 240static const struct ide_dma_ops cs5536_dma_ops = { 241 .dma_host_set = ide_dma_host_set, 242 .dma_setup = ide_dma_setup, 243 .dma_start = cs5536_dma_start, 244 .dma_end = cs5536_dma_end, 245 .dma_test_irq = ide_dma_test_irq, 246 .dma_lost_irq = ide_dma_lost_irq, 247 .dma_timer_expiry = ide_dma_sff_timer_expiry, 248 .dma_sff_read_status = ide_dma_sff_read_status, 249}; 250 251static const struct ide_port_info cs5536_info = { 252 .name = DRV_NAME, 253 .port_ops = &cs5536_port_ops, 254 .dma_ops = &cs5536_dma_ops, 255 .host_flags = IDE_HFLAG_SINGLE, 256 .pio_mask = ATA_PIO4, 257 .mwdma_mask = ATA_MWDMA2, 258 .udma_mask = ATA_UDMA5, 259}; 260 261/** 262 * cs5536_init_one 263 * @dev: PCI device 264 * @id: Entry in match table 265 */ 266 267static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) 268{ 269 u32 cfg; 270 271 if (use_msr) 272 printk(KERN_INFO DRV_NAME ": Using MSR regs instead of PCI\n"); 273 274 cs5536_read(dev, CFG, &cfg); 275 276 if ((cfg & IDE_CFG_CHANEN) == 0) { 277 printk(KERN_ERR DRV_NAME ": disabled by BIOS\n"); 278 return -ENODEV; 279 } 280 281 return ide_pci_init_one(dev, &cs5536_info, NULL); 282} 283 284static const struct pci_device_id cs5536_pci_tbl[] = { 285 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), }, 286 { }, 287}; 288 289static struct pci_driver cs5536_pci_driver = { 290 .name = DRV_NAME, 291 .id_table = cs5536_pci_tbl, 292 .probe = cs5536_init_one, 293 .remove = ide_pci_remove, 294 .suspend = ide_pci_suspend, 295 .resume = ide_pci_resume, 296}; 297 298module_pci_driver(cs5536_pci_driver); 299 300MODULE_AUTHOR("Martin K. Petersen, Bartlomiej Zolnierkiewicz"); 301MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller"); 302MODULE_LICENSE("GPL"); 303MODULE_DEVICE_TABLE(pci, cs5536_pci_tbl); 304 305module_param_named(msr, use_msr, int, 0644); 306MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); 307