Blame view
drivers/ata/pata_cs5520.c
9.39 KB
669a5db41 [libata] Add a bu... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* * IDE tuning and bus mastering support for the CS5510/CS5520 * chipsets * * The CS5510/CS5520 are slightly unusual devices. Unlike the * typical IDE controllers they do bus mastering with the drive in * PIO mode and smarter silicon. * * The practical upshot of this is that we must always tune the * drive for the right PIO mode. We must also ignore all the blacklists * and the drive bus mastering DMA information. Also to confuse matters * further we can do DMA on PIO only drives. * * DMA on the 5510 also requires we disable_hlt() during DMA on early * revisions. * * *** This driver is strictly experimental *** * * (c) Copyright Red Hat Inc 2002 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * Documentation: * Not publically available. */ #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 <scsi/scsi_host.h> #include <linux/libata.h> #define DRV_NAME "pata_cs5520" |
2a3103ce4 [libata] Bump dri... |
44 |
#define DRV_VERSION "0.6.6" |
669a5db41 [libata] Add a bu... |
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
struct pio_clocks { int address; int assert; int recovery; }; static const struct pio_clocks cs5520_pio_clocks[]={ {3, 6, 11}, {2, 5, 6}, {1, 4, 3}, {1, 3, 2}, {1, 2, 1} }; /** * cs5520_set_timings - program PIO timings * @ap: ATA port * @adev: ATA device * * Program the PIO mode timings for the controller according to the pio * clocking table. */ static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int pio) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); int slave = adev->devno; pio -= XFER_PIO_0; /* Channel command timing */ pci_write_config_byte(pdev, 0x62 + ap->port_no, (cs5520_pio_clocks[pio].recovery << 4) | (cs5520_pio_clocks[pio].assert)); /* FIXME: should these use address ? */ /* Read command timing */ pci_write_config_byte(pdev, 0x64 + 4*ap->port_no + slave, (cs5520_pio_clocks[pio].recovery << 4) | (cs5520_pio_clocks[pio].assert)); /* Write command timing */ pci_write_config_byte(pdev, 0x66 + 4*ap->port_no + slave, (cs5520_pio_clocks[pio].recovery << 4) | (cs5520_pio_clocks[pio].assert)); } /** * cs5520_enable_dma - turn on DMA bits * * Turn on the DMA bits for this disk. Needed because the BIOS probably * has not done the work for us. Belongs in the core SATA code. */ static void cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev) { /* Set the DMA enable/disable flag */ |
0d5ff5667 libata: convert t... |
102 |
u8 reg = ioread8(ap->ioaddr.bmdma_addr + 0x02); |
669a5db41 [libata] Add a bu... |
103 |
reg |= 1<<(adev->devno + 5); |
0d5ff5667 libata: convert t... |
104 |
iowrite8(reg, ap->ioaddr.bmdma_addr + 0x02); |
669a5db41 [libata] Add a bu... |
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
} /** * cs5520_set_dmamode - program DMA timings * @ap: ATA port * @adev: ATA device * * Program the DMA mode timings for the controller according to the pio * clocking table. Note that this device sets the DMA timings to PIO * mode values. This may seem bizarre but the 5520 architecture talks * PIO mode to the disk and DMA mode to the controller so the underlying * transfers are PIO timed. */ static void cs5520_set_dmamode(struct ata_port *ap, struct ata_device *adev) { static const int dma_xlate[3] = { XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 }; cs5520_set_timings(ap, adev, dma_xlate[adev->dma_mode]); cs5520_enable_dma(ap, adev); } /** * cs5520_set_piomode - program PIO timings * @ap: ATA port * @adev: ATA device * * Program the PIO mode timings for the controller according to the pio * clocking table. We know pio_mode will equal dma_mode because of the * CS5520 architecture. At least once we turned DMA on and wrote a * mode setter. */ static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev) { cs5520_set_timings(ap, adev, adev->pio_mode); } |
669a5db41 [libata] Add a bu... |
141 |
static struct scsi_host_template cs5520_sht = { |
68d1d07b5 libata: implement... |
142 |
ATA_BMDMA_SHT(DRV_NAME), |
d26fc9551 libata: Support c... |
143 |
.sg_tablesize = LIBATA_DUMB_MAX_PRD, |
669a5db41 [libata] Add a bu... |
144 145 146 |
}; static struct ata_port_operations cs5520_port_ops = { |
029cfd6b7 libata: implement... |
147 |
.inherits = &ata_bmdma_port_ops, |
9363c3825 libata: rename SF... |
148 |
.qc_prep = ata_sff_dumb_qc_prep, |
029cfd6b7 libata: implement... |
149 |
.cable_detect = ata_cable_40wire, |
669a5db41 [libata] Add a bu... |
150 151 |
.set_piomode = cs5520_set_piomode, .set_dmamode = cs5520_set_dmamode, |
669a5db41 [libata] Add a bu... |
152 |
}; |
5d728824e libata: convert t... |
153 |
static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id) |
669a5db41 [libata] Add a bu... |
154 |
{ |
cbcdd8759 libata: implement... |
155 156 |
static const unsigned int cmd_port[] = { 0x1F0, 0x170 }; static const unsigned int ctl_port[] = { 0x3F6, 0x376 }; |
5d728824e libata: convert t... |
157 158 |
struct ata_port_info pi = { .flags = ATA_FLAG_SLAVE_POSS, |
14bdef982 [libata] convert ... |
159 |
.pio_mask = ATA_PIO4, |
5d728824e libata: convert t... |
160 161 162 |
.port_ops = &cs5520_port_ops, }; const struct ata_port_info *ppi[2]; |
669a5db41 [libata] Add a bu... |
163 |
u8 pcicfg; |
4ca4e4396 libata annotation... |
164 |
void __iomem *iomap[5]; |
5d728824e libata: convert t... |
165 166 167 |
struct ata_host *host; struct ata_ioports *ioaddr; int i, rc; |
669a5db41 [libata] Add a bu... |
168 |
|
f08048e94 libata: PCI devic... |
169 170 171 |
rc = pcim_enable_device(pdev); if (rc) return rc; |
669a5db41 [libata] Add a bu... |
172 |
/* IDE port enable bits */ |
5d728824e libata: convert t... |
173 |
pci_read_config_byte(pdev, 0x60, &pcicfg); |
669a5db41 [libata] Add a bu... |
174 175 176 177 |
/* Check if the ATA ports are enabled */ if ((pcicfg & 3) == 0) return -ENODEV; |
5d728824e libata: convert t... |
178 179 180 181 182 |
ppi[0] = ppi[1] = &ata_dummy_port_info; if (pcicfg & 1) ppi[0] = π if (pcicfg & 2) ppi[1] = π |
669a5db41 [libata] Add a bu... |
183 |
if ((pcicfg & 0x40) == 0) { |
5d728824e libata: convert t... |
184 185 186 187 |
dev_printk(KERN_WARNING, &pdev->dev, "DMA mode disabled. Enabling. "); pci_write_config_byte(pdev, 0x60, pcicfg | 0x40); |
669a5db41 [libata] Add a bu... |
188 |
} |
5d728824e libata: convert t... |
189 190 191 192 193 |
pi.mwdma_mask = id->driver_data; host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); if (!host) return -ENOMEM; |
669a5db41 [libata] Add a bu... |
194 |
/* Perform set up for DMA */ |
094839164 PCI: Remove users... |
195 |
if (pci_enable_device_io(pdev)) { |
669a5db41 [libata] Add a bu... |
196 197 198 199 |
printk(KERN_ERR DRV_NAME ": unable to configure BAR2. "); return -ENODEV; } |
5d728824e libata: convert t... |
200 201 |
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { |
669a5db41 [libata] Add a bu... |
202 203 204 205 |
printk(KERN_ERR DRV_NAME ": unable to configure DMA mask. "); return -ENODEV; } |
5d728824e libata: convert t... |
206 |
if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { |
669a5db41 [libata] Add a bu... |
207 208 209 210 |
printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask. "); return -ENODEV; } |
5d728824e libata: convert t... |
211 |
/* Map IO ports and initialize host accordingly */ |
cbcdd8759 libata: implement... |
212 213 214 215 |
iomap[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8); iomap[1] = devm_ioport_map(&pdev->dev, ctl_port[0], 1); iomap[2] = devm_ioport_map(&pdev->dev, cmd_port[1], 8); iomap[3] = devm_ioport_map(&pdev->dev, ctl_port[1], 1); |
5d728824e libata: convert t... |
216 |
iomap[4] = pcim_iomap(pdev, 2, 0); |
0d5ff5667 libata: convert t... |
217 218 219 |
if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4]) return -ENOMEM; |
5d728824e libata: convert t... |
220 221 222 223 224 |
ioaddr = &host->ports[0]->ioaddr; ioaddr->cmd_addr = iomap[0]; ioaddr->ctl_addr = iomap[1]; ioaddr->altstatus_addr = iomap[1]; ioaddr->bmdma_addr = iomap[4]; |
9363c3825 libata: rename SF... |
225 |
ata_sff_std_ports(ioaddr); |
5d728824e libata: convert t... |
226 |
|
cbcdd8759 libata: implement... |
227 228 229 |
ata_port_desc(host->ports[0], "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]); ata_port_pbar_desc(host->ports[0], 4, 0, "bmdma"); |
5d728824e libata: convert t... |
230 231 232 233 234 |
ioaddr = &host->ports[1]->ioaddr; ioaddr->cmd_addr = iomap[2]; ioaddr->ctl_addr = iomap[3]; ioaddr->altstatus_addr = iomap[3]; ioaddr->bmdma_addr = iomap[4] + 8; |
9363c3825 libata: rename SF... |
235 |
ata_sff_std_ports(ioaddr); |
5d728824e libata: convert t... |
236 |
|
cbcdd8759 libata: implement... |
237 238 239 |
ata_port_desc(host->ports[1], "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]); ata_port_pbar_desc(host->ports[1], 4, 8, "bmdma"); |
5d728824e libata: convert t... |
240 241 242 243 244 245 246 247 |
/* activate the host */ pci_set_master(pdev); rc = ata_host_start(host); if (rc) return rc; for (i = 0; i < 2; i++) { static const int irq[] = { 14, 15 }; |
8c6b065b7 pata_cs5520: Fix ... |
248 |
struct ata_port *ap = host->ports[i]; |
5d728824e libata: convert t... |
249 250 251 252 253 |
if (ata_port_is_dummy(ap)) continue; rc = devm_request_irq(&pdev->dev, irq[ap->port_no], |
9363c3825 libata: rename SF... |
254 |
ata_sff_interrupt, 0, DRV_NAME, host); |
5d728824e libata: convert t... |
255 256 |
if (rc) return rc; |
4031826b3 libata: fix assig... |
257 |
|
cbcdd8759 libata: implement... |
258 |
ata_port_desc(ap, "irq %d", irq[i]); |
5d728824e libata: convert t... |
259 260 261 |
} return ata_host_register(host, &cs5520_sht); |
669a5db41 [libata] Add a bu... |
262 |
} |
438ac6d5e libata: add missi... |
263 |
#ifdef CONFIG_PM |
8501120f1 [PATCH] pata_cs55... |
264 265 266 267 268 269 270 |
/** * cs5520_reinit_one - device resume * @pdev: PCI device * * Do any reconfiguration work needed by a resume from RAM. We need * to restore DMA mode support on BIOSen which disabled it */ |
f20b16ff7 [libata] trim tra... |
271 |
|
8501120f1 [PATCH] pata_cs55... |
272 273 |
static int cs5520_reinit_one(struct pci_dev *pdev) { |
f08048e94 libata: PCI devic... |
274 |
struct ata_host *host = dev_get_drvdata(&pdev->dev); |
8501120f1 [PATCH] pata_cs55... |
275 |
u8 pcicfg; |
f08048e94 libata: PCI devic... |
276 277 278 279 280 |
int rc; rc = ata_pci_device_do_resume(pdev); if (rc) return rc; |
8501120f1 [PATCH] pata_cs55... |
281 282 283 |
pci_read_config_byte(pdev, 0x60, &pcicfg); if ((pcicfg & 0x40) == 0) pci_write_config_byte(pdev, 0x60, pcicfg | 0x40); |
f08048e94 libata: PCI devic... |
284 285 286 |
ata_host_resume(host); return 0; |
8501120f1 [PATCH] pata_cs55... |
287 |
} |
aa6de4942 pata_cs5520: susp... |
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
/** * cs5520_pci_device_suspend - device suspend * @pdev: PCI device * * We have to cut and waste bits from the standard method because * the 5520 is a bit odd and not just a pure ATA device. As a result * we must not disable it. The needed code is short and this avoids * chip specific mess in the core code. */ static int cs5520_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) { struct ata_host *host = dev_get_drvdata(&pdev->dev); int rc = 0; rc = ata_host_suspend(host, mesg); if (rc) return rc; pci_save_state(pdev); return 0; } |
438ac6d5e libata: add missi... |
311 |
#endif /* CONFIG_PM */ |
a84471fe2 [libata] Trim tra... |
312 |
|
669a5db41 [libata] Add a bu... |
313 314 |
/* For now keep DMA off. We can set it for all but A rev CS5510 once the core ATA code can handle it */ |
2d2744fc8 [libata] PCI ID t... |
315 316 317 318 319 |
static const struct pci_device_id pata_cs5520[] = { { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), }, { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), }, { }, |
669a5db41 [libata] Add a bu... |
320 321 322 323 324 325 |
}; static struct pci_driver cs5520_pci_driver = { .name = DRV_NAME, .id_table = pata_cs5520, .probe = cs5520_init_one, |
2855568b1 [libata] struct p... |
326 |
.remove = ata_pci_remove_one, |
438ac6d5e libata: add missi... |
327 |
#ifdef CONFIG_PM |
aa6de4942 pata_cs5520: susp... |
328 |
.suspend = cs5520_pci_device_suspend, |
8501120f1 [PATCH] pata_cs55... |
329 |
.resume = cs5520_reinit_one, |
438ac6d5e libata: add missi... |
330 |
#endif |
669a5db41 [libata] Add a bu... |
331 |
}; |
669a5db41 [libata] Add a bu... |
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
static int __init cs5520_init(void) { return pci_register_driver(&cs5520_pci_driver); } static void __exit cs5520_exit(void) { pci_unregister_driver(&cs5520_pci_driver); } MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Cyrix CS5510/5520"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, pata_cs5520); MODULE_VERSION(DRV_VERSION); module_init(cs5520_init); module_exit(cs5520_exit); |