1/* 2 * IDE tuning and bus mastering support for the CS5510/CS5520 3 * chipsets 4 * 5 * The CS5510/CS5520 are slightly unusual devices. Unlike the 6 * typical IDE controllers they do bus mastering with the drive in 7 * PIO mode and smarter silicon. 8 * 9 * The practical upshot of this is that we must always tune the 10 * drive for the right PIO mode. We must also ignore all the blacklists 11 * and the drive bus mastering DMA information. 12 * 13 * *** This driver is strictly experimental *** 14 * 15 * (c) Copyright Red Hat Inc 2002 16 * 17 * This program is free software; you can redistribute it and/or modify it 18 * under the terms of the GNU General Public License as published by the 19 * Free Software Foundation; either version 2, or (at your option) any 20 * later version. 21 * 22 * This program is distributed in the hope that it will be useful, but 23 * WITHOUT ANY WARRANTY; without even the implied warranty of 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 25 * General Public License for more details. 26 * 27 * For the avoidance of doubt the "preferred form" of this code is one which 28 * is in an open non patent encumbered format. Where cryptographic key signing 29 * forms part of the process of creating an executable the information 30 * including keys needed to generate an equivalently functional executable 31 * are deemed to be part of the source code. 32 * 33 */ 34 35#include <linux/module.h> 36#include <linux/types.h> 37#include <linux/kernel.h> 38#include <linux/delay.h> 39#include <linux/timer.h> 40#include <linux/mm.h> 41#include <linux/ioport.h> 42#include <linux/blkdev.h> 43#include <linux/hdreg.h> 44 45#include <linux/interrupt.h> 46#include <linux/init.h> 47#include <linux/pci.h> 48#include <linux/ide.h> 49#include <linux/dma-mapping.h> 50 51#include <asm/io.h> 52#include <asm/irq.h> 53 54struct pio_clocks 55{ 56 int address; 57 int assert; 58 int recovery; 59}; 60 61static struct pio_clocks cs5520_pio_clocks[]={ 62 {3, 6, 11}, 63 {2, 5, 6}, 64 {1, 4, 3}, 65 {1, 3, 2}, 66 {1, 2, 1} 67}; 68 69static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed) 70{ 71 ide_hwif_t *hwif = HWIF(drive); 72 struct pci_dev *pdev = hwif->pci_dev; 73 u8 speed = min((u8)XFER_PIO_4, xferspeed); 74 int pio = speed; 75 u8 reg; 76 int controller = drive->dn > 1 ? 1 : 0; 77 int error; 78 79 switch(speed) 80 { 81 case XFER_PIO_4: 82 case XFER_PIO_3: 83 case XFER_PIO_2: 84 case XFER_PIO_1: 85 case XFER_PIO_0: 86 pio -= XFER_PIO_0; 87 break; 88 default: 89 pio = 0; 90 printk(KERN_ERR "cs55x0: bad ide timing.\n"); 91 } 92 93 printk("PIO clocking = %d\n", pio); 94 95 96 /* 8bit CAT/CRT - 8bit command timing for channel */ 97 pci_write_config_byte(pdev, 0x62 + controller, 98 (cs5520_pio_clocks[pio].recovery << 4) | 99 (cs5520_pio_clocks[pio].assert)); 100 101 /* 0x64 - 16bit Primary, 0x68 - 16bit Secondary */ 102 103 /* Data read timing */ 104 pci_write_config_byte(pdev, 0x64 + 4*controller + (drive->dn&1), 105 (cs5520_pio_clocks[pio].recovery << 4) | 106 (cs5520_pio_clocks[pio].assert)); 107 /* Write command timing */ 108 pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1), 109 (cs5520_pio_clocks[pio].recovery << 4) | 110 (cs5520_pio_clocks[pio].assert)); 111 112 /* Set the DMA enable/disable flag */ 113 reg = inb(hwif->dma_base + 0x02 + 8*controller); 114 reg |= 1<<((drive->dn&1)+5); 115 outb(reg, hwif->dma_base + 0x02 + 8*controller); 116 117 error = ide_config_drive_speed(drive, speed); 118 /* ATAPI is harder so leave it for now */ 119 if(!error && drive->media == ide_disk) 120 error = hwif->ide_dma_on(drive); 121 122 return error; 123} 124 125static void cs5520_tune_drive(ide_drive_t *drive, u8 pio) 126{ 127 pio = ide_get_best_pio_mode(drive, pio, 4, NULL); 128 cs5520_tune_chipset(drive, (XFER_PIO_0 + pio)); 129} 130 131static int cs5520_config_drive_xfer_rate(ide_drive_t *drive) 132{ 133 /* Tune the drive for PIO modes up to PIO 4 */ 134 cs5520_tune_drive(drive, 4); 135 136 /* Then tell the core to use DMA operations */ 137 return 0; 138} 139 140/* 141 * We provide a callback for our nonstandard DMA location 142 */ 143 144static void __devinit cs5520_init_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif) 145{ 146 unsigned long bmide = pci_resource_start(dev, 2); /* Not the usual 4 */ 147 if(hwif->mate && hwif->mate->dma_base) /* Second channel at primary + 8 */ 148 bmide += 8; 149 ide_setup_dma(hwif, bmide, 8); 150} 151 152/* 153 * We wrap the DMA activate to set the vdma flag. This is needed 154 * so that the IDE DMA layer issues PIO not DMA commands over the 155 * DMA channel 156 */ 157 158static int cs5520_dma_on(ide_drive_t *drive) 159{ 160 drive->vdma = 1; 161 return 0; 162} 163 164static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) 165{ 166 hwif->tuneproc = &cs5520_tune_drive; 167 hwif->speedproc = &cs5520_tune_chipset; 168 hwif->ide_dma_check = &cs5520_config_drive_xfer_rate; 169 hwif->ide_dma_on = &cs5520_dma_on; 170 171 if(!noautodma) 172 hwif->autodma = 1; 173 174 if(!hwif->dma_base) 175 { 176 hwif->drives[0].autotune = 1; 177 hwif->drives[1].autotune = 1; 178 return; 179 } 180 181 hwif->atapi_dma = 0; 182 hwif->ultra_mask = 0; 183 hwif->swdma_mask = 0; 184 hwif->mwdma_mask = 0; 185 186 hwif->drives[0].autodma = hwif->autodma; 187 hwif->drives[1].autodma = hwif->autodma; 188} 189 190#define DECLARE_CS_DEV(name_str) \ 191 { \ 192 .name = name_str, \ 193 .init_setup_dma = cs5520_init_setup_dma, \ 194 .init_hwif = init_hwif_cs5520, \ 195 .channels = 2, \ 196 .autodma = AUTODMA, \ 197 .bootable = ON_BOARD, \ 198 .flags = IDEPCI_FLAG_ISA_PORTS, \ 199 } 200 201static ide_pci_device_t cyrix_chipsets[] __devinitdata = { 202 /* 0 */ DECLARE_CS_DEV("Cyrix 5510"), 203 /* 1 */ DECLARE_CS_DEV("Cyrix 5520") 204}; 205 206/* 207 * The 5510/5520 are a bit weird. They don't quite set up the way 208 * the PCI helper layer expects so we must do much of the set up 209 * work longhand. 210 */ 211 212static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id) 213{ 214 ide_hwif_t *hwif = NULL, *mate = NULL; 215 ata_index_t index; 216 ide_pci_device_t *d = &cyrix_chipsets[id->driver_data]; 217 218 ide_setup_pci_noise(dev, d); 219 220 /* We must not grab the entire device, it has 'ISA' space in its 221 BARS too and we will freak out other bits of the kernel */ 222 if (pci_enable_device_bars(dev, 1<<2)) { 223 printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name); 224 return -ENODEV; 225 } 226 pci_set_master(dev); 227 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) { 228 printk(KERN_WARNING "cs5520: No suitable DMA available.\n"); 229 return -ENODEV; 230 } 231 232 index.all = 0xf0f0; 233 234 /* 235 * Now the chipset is configured we can let the core 236 * do all the device setup for us 237 */ 238 239 ide_pci_setup_ports(dev, d, 14, &index); 240 241 if ((index.b.low & 0xf0) != 0xf0) 242 hwif = &ide_hwifs[index.b.low]; 243 if ((index.b.high & 0xf0) != 0xf0) 244 mate = &ide_hwifs[index.b.high]; 245 246 if (hwif) 247 probe_hwif_init(hwif); 248 if (mate) 249 probe_hwif_init(mate); 250 251 if (hwif) 252 ide_proc_register_port(hwif); 253 if (mate) 254 ide_proc_register_port(mate); 255 256 return 0; 257} 258 259static struct pci_device_id cs5520_pci_tbl[] = { 260 { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 261 { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, 262 { 0, }, 263}; 264MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl); 265 266static struct pci_driver driver = { 267 .name = "Cyrix_IDE", 268 .id_table = cs5520_pci_tbl, 269 .probe = cs5520_init_one, 270}; 271 272static int __init cs5520_ide_init(void) 273{ 274 return ide_pci_register_driver(&driver); 275} 276 277module_init(cs5520_ide_init); 278 279MODULE_AUTHOR("Alan Cox"); 280MODULE_DESCRIPTION("PCI driver module for Cyrix 5510/5520 IDE"); 281MODULE_LICENSE("GPL"); 282