Blame view
drivers/ide/cs5530.c
8.14 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
1da177e4c Linux-2.6.12-rc2 |
2 |
* Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> |
1da177e4c Linux-2.6.12-rc2 |
3 |
* Copyright (C) 2000 Mark Lord <mlord@pobox.com> |
5fd216bbb cs5530/sc1200: ad... |
4 5 |
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz * |
1da177e4c Linux-2.6.12-rc2 |
6 7 8 9 10 11 12 13 |
* May be copied or modified under the terms of the GNU General Public License * * Development of this chipset driver was funded * by the nice folks at National Semiconductor. * * Documentation: * CS5530 documentation available from National Semiconductor. */ |
1da177e4c Linux-2.6.12-rc2 |
14 15 16 |
#include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
17 18 19 |
#include <linux/pci.h> #include <linux/init.h> #include <linux/ide.h> |
78829dd92 ide: remove needl... |
20 |
|
1da177e4c Linux-2.6.12-rc2 |
21 |
#include <asm/io.h> |
1da177e4c Linux-2.6.12-rc2 |
22 |
|
ced3ec8aa ide: prefix messa... |
23 |
#define DRV_NAME "cs5530" |
1da177e4c Linux-2.6.12-rc2 |
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/* * Here are the standard PIO mode 0-4 timings for each "format". * Format-0 uses fast data reg timings, with slower command reg timings. * Format-1 uses fast timings for all registers, but won't work with all drives. */ static unsigned int cs5530_pio_timings[2][5] = { {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010} }; /* * After chip reset, the PIO timings are set to 0x0000e132, which is not valid. */ #define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132) #define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20)) /** |
88b2b32ba ide: move ide_con... |
41 |
* cs5530_set_pio_mode - set host controller for PIO mode |
e085b3cae ide: change ->set... |
42 |
* @hwif: port |
26bcb879c ide: add ide_set{... |
43 |
* @drive: drive |
1da177e4c Linux-2.6.12-rc2 |
44 |
* |
88b2b32ba ide: move ide_con... |
45 |
* Handles setting of PIO mode for the chipset. |
1da177e4c Linux-2.6.12-rc2 |
46 |
* |
26bcb879c ide: add ide_set{... |
47 |
* The init_hwif_cs5530() routine guarantees that all drives |
1da177e4c Linux-2.6.12-rc2 |
48 49 |
* will have valid default PIO timings set up before we get here. */ |
e085b3cae ide: change ->set... |
50 |
static void cs5530_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) |
1da177e4c Linux-2.6.12-rc2 |
51 |
{ |
e085b3cae ide: change ->set... |
52 |
unsigned long basereg = CS5530_BASEREG(hwif); |
88b2b32ba ide: move ide_con... |
53 |
unsigned int format = (inl(basereg + 4) >> 31) & 1; |
e085b3cae ide: change ->set... |
54 |
const u8 pio = drive->pio_mode - XFER_PIO_0; |
88b2b32ba ide: move ide_con... |
55 56 |
outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3)); |
1da177e4c Linux-2.6.12-rc2 |
57 58 59 |
} /** |
5fd216bbb cs5530/sc1200: ad... |
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
* cs5530_udma_filter - UDMA filter * @drive: drive * * cs5530_udma_filter() does UDMA mask filtering for the given drive * taking into the consideration capabilities of the mate device. * * The CS5530 specifies that two drives sharing a cable cannot mix * UDMA/MDMA. It has to be one or the other, for the pair, though * different timings can still be chosen for each drive. We could * set the appropriate timing bits on the fly, but that might be * a bit confusing. So, for now we statically handle this requirement * by looking at our mate drive to see what it is capable of, before * choosing a mode for our own drive. * * Note: This relies on the fact we never fail from UDMA to MWDMA2 * but instead drop to PIO. */ static u8 cs5530_udma_filter(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; |
7e59ea21a ide: check drive-... |
81 |
ide_drive_t *mate = ide_get_pair_dev(drive); |
9ecab6e5b drivers/ide/{cs55... |
82 |
u16 *mateid; |
5fd216bbb cs5530/sc1200: ad... |
83 |
u8 mask = hwif->ultra_mask; |
7e59ea21a ide: check drive-... |
84 |
if (mate == NULL) |
5fd216bbb cs5530/sc1200: ad... |
85 |
goto out; |
9ecab6e5b drivers/ide/{cs55... |
86 |
mateid = mate->id; |
5fd216bbb cs5530/sc1200: ad... |
87 |
|
48fb2688a ide: remove drive... |
88 |
if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) { |
4dde4492d ide: make drive->... |
89 90 |
if ((mateid[ATA_ID_FIELD_VALID] & 4) && (mateid[ATA_ID_UDMA_MODES] & 7)) |
5fd216bbb cs5530/sc1200: ad... |
91 |
goto out; |
8d64fcd93 ide: identify dat... |
92 |
if (mateid[ATA_ID_MWDMA_MODES] & 7) |
5fd216bbb cs5530/sc1200: ad... |
93 94 95 96 97 |
mask = 0; } out: return mask; } |
8776168ca ide: change ->set... |
98 |
static void cs5530_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) |
3c3f5d2c9 cs5530/sc1200: ad... |
99 |
{ |
5fd216bbb cs5530/sc1200: ad... |
100 |
unsigned long basereg; |
3c3f5d2c9 cs5530/sc1200: ad... |
101 |
unsigned int reg, timings = 0; |
1da177e4c Linux-2.6.12-rc2 |
102 |
|
8776168ca ide: change ->set... |
103 |
switch (drive->dma_mode) { |
1da177e4c Linux-2.6.12-rc2 |
104 105 106 107 108 109 |
case XFER_UDMA_0: timings = 0x00921250; break; case XFER_UDMA_1: timings = 0x00911140; break; case XFER_UDMA_2: timings = 0x00911030; break; case XFER_MW_DMA_0: timings = 0x00077771; break; case XFER_MW_DMA_1: timings = 0x00012121; break; case XFER_MW_DMA_2: timings = 0x00002020; break; |
1da177e4c Linux-2.6.12-rc2 |
110 |
} |
8776168ca ide: change ->set... |
111 |
basereg = CS5530_BASEREG(hwif); |
0ecdca26e ide: use PIO/MMIO... |
112 |
reg = inl(basereg + 4); /* get drive0 config register */ |
1da177e4c Linux-2.6.12-rc2 |
113 |
timings |= reg & 0x80000000; /* preserve PIO format bit */ |
3c3f5d2c9 cs5530/sc1200: ad... |
114 |
if ((drive-> dn & 1) == 0) { /* are we configuring drive0? */ |
0ecdca26e ide: use PIO/MMIO... |
115 |
outl(timings, basereg + 4); /* write drive0 config register */ |
1da177e4c Linux-2.6.12-rc2 |
116 117 118 119 120 |
} else { if (timings & 0x00100000) reg |= 0x00100000; /* enable UDMA timings for both drives */ else reg &= ~0x00100000; /* disable UDMA timings for both drives */ |
0ecdca26e ide: use PIO/MMIO... |
121 122 |
outl(reg, basereg + 4); /* write drive0 config register */ outl(timings, basereg + 12); /* write drive1 config register */ |
1da177e4c Linux-2.6.12-rc2 |
123 |
} |
1da177e4c Linux-2.6.12-rc2 |
124 125 126 127 128 |
} /** * init_chipset_5530 - set up 5530 bridge * @dev: PCI device |
1da177e4c Linux-2.6.12-rc2 |
129 130 131 |
* * Initialize the cs5530 bridge for reliable IDE DMA operation. */ |
2ed0ef543 ide: fix ->init_c... |
132 |
static int init_chipset_cs5530(struct pci_dev *dev) |
1da177e4c Linux-2.6.12-rc2 |
133 134 |
{ struct pci_dev *master_0 = NULL, *cs5530_0 = NULL; |
1da177e4c Linux-2.6.12-rc2 |
135 |
|
f7b0d2df2 cs5530: add missi... |
136 137 |
if (pci_resource_start(dev, 4) == 0) return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
138 |
dev = NULL; |
652aa1629 [PATCH] IDE: more... |
139 |
while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) { |
1da177e4c Linux-2.6.12-rc2 |
140 141 |
switch (dev->device) { case PCI_DEVICE_ID_CYRIX_PCI_MASTER: |
652aa1629 [PATCH] IDE: more... |
142 |
master_0 = pci_dev_get(dev); |
1da177e4c Linux-2.6.12-rc2 |
143 144 |
break; case PCI_DEVICE_ID_CYRIX_5530_LEGACY: |
652aa1629 [PATCH] IDE: more... |
145 |
cs5530_0 = pci_dev_get(dev); |
1da177e4c Linux-2.6.12-rc2 |
146 147 148 149 |
break; } } if (!master_0) { |
a326b02b0 ide: drop 'name' ... |
150 151 |
printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function "); |
652aa1629 [PATCH] IDE: more... |
152 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
153 154 |
} if (!cs5530_0) { |
a326b02b0 ide: drop 'name' ... |
155 156 |
printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function "); |
652aa1629 [PATCH] IDE: more... |
157 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
158 |
} |
1da177e4c Linux-2.6.12-rc2 |
159 160 161 162 163 164 |
/* * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530: * --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530 */ pci_set_master(cs5530_0); |
694625c0b PCI: add pci_try_... |
165 |
pci_try_set_mwi(cs5530_0); |
1da177e4c Linux-2.6.12-rc2 |
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
/* * Set PCI CacheLineSize to 16-bytes: * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530 */ pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04); /* * Disable trapping of UDMA register accesses (Win98 hack): * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530 */ pci_write_config_word(cs5530_0, 0xd0, 0x5006); /* * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus: * The other settings are what is necessary to get the register * into a sane state for IDE DMA operation. */ pci_write_config_byte(master_0, 0x40, 0x1e); /* * Set max PCI burst size (16-bytes seems to work best): * 16bytes: set bit-1 at 0x41 (reg value of 0x16) * all others: clear bit-1 at 0x41, and do: * 128bytes: OR 0x00 at 0x41 * 256bytes: OR 0x04 at 0x41 * 512bytes: OR 0x08 at 0x41 * 1024bytes: OR 0x0c at 0x41 */ pci_write_config_byte(master_0, 0x41, 0x14); /* * These settings are necessary to get the chip * into a sane state for IDE DMA operation. */ pci_write_config_byte(master_0, 0x42, 0x00); pci_write_config_byte(master_0, 0x43, 0xc1); |
652aa1629 [PATCH] IDE: more... |
208 209 210 |
out: pci_dev_put(master_0); pci_dev_put(cs5530_0); |
1da177e4c Linux-2.6.12-rc2 |
211 212 213 214 215 216 217 218 219 220 |
return 0; } /** * init_hwif_cs5530 - initialise an IDE channel * @hwif: IDE to initialize * * This gets invoked by the IDE driver once for each channel. It * performs channel-specific pre-initialization before drive probing. */ |
fe31edc8a Drivers: ide: rem... |
221 |
static void init_hwif_cs5530 (ide_hwif_t *hwif) |
1da177e4c Linux-2.6.12-rc2 |
222 223 224 |
{ unsigned long basereg; u32 d0_timings; |
1da177e4c Linux-2.6.12-rc2 |
225 |
|
1da177e4c Linux-2.6.12-rc2 |
226 |
basereg = CS5530_BASEREG(hwif); |
0ecdca26e ide: use PIO/MMIO... |
227 |
d0_timings = inl(basereg + 0); |
93104654c cs5530: always tu... |
228 |
if (CS5530_BAD_PIO(d0_timings)) |
0ecdca26e ide: use PIO/MMIO... |
229 |
outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0); |
93104654c cs5530: always tu... |
230 |
if (CS5530_BAD_PIO(inl(basereg + 8))) |
0ecdca26e ide: use PIO/MMIO... |
231 |
outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8); |
1da177e4c Linux-2.6.12-rc2 |
232 |
} |
ac95beedf ide: add struct i... |
233 234 235 236 237 |
static const struct ide_port_ops cs5530_port_ops = { .set_pio_mode = cs5530_set_pio_mode, .set_dma_mode = cs5530_set_dma_mode, .udma_filter = cs5530_udma_filter, }; |
fe31edc8a Drivers: ide: rem... |
238 |
static const struct ide_port_info cs5530_chipset = { |
ced3ec8aa ide: prefix messa... |
239 |
.name = DRV_NAME, |
1da177e4c Linux-2.6.12-rc2 |
240 241 |
.init_chipset = init_chipset_cs5530, .init_hwif = init_hwif_cs5530, |
ac95beedf ide: add struct i... |
242 |
.port_ops = &cs5530_port_ops, |
1c51361a9 ide: add IDE_HFLA... |
243 |
.host_flags = IDE_HFLAG_SERIALIZE | |
5e71d9c5a ide: IDE_HFLAG_BO... |
244 |
IDE_HFLAG_POST_SET_MODE, |
4099d1432 ide: add PIO masks |
245 |
.pio_mask = ATA_PIO4, |
5f8b6c348 ide: add ->mwdma_... |
246 247 |
.mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA2, |
1da177e4c Linux-2.6.12-rc2 |
248 |
}; |
fe31edc8a Drivers: ide: rem... |
249 |
static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) |
1da177e4c Linux-2.6.12-rc2 |
250 |
{ |
6cdf6eb35 ide: add ->dev an... |
251 |
return ide_pci_init_one(dev, &cs5530_chipset, NULL); |
1da177e4c Linux-2.6.12-rc2 |
252 |
} |
9cbcc5e3c ide: use PCI_VDEV... |
253 254 |
static const struct pci_device_id cs5530_pci_tbl[] = { { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), 0 }, |
1da177e4c Linux-2.6.12-rc2 |
255 256 257 |
{ 0, }, }; MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl); |
a9ab09e26 ide: use unique n... |
258 |
static struct pci_driver cs5530_pci_driver = { |
1da177e4c Linux-2.6.12-rc2 |
259 260 261 |
.name = "CS5530 IDE", .id_table = cs5530_pci_tbl, .probe = cs5530_init_one, |
d16492a97 cs5530: add ->rem... |
262 |
.remove = ide_pci_remove, |
feb22b7f8 ide: add proper P... |
263 264 |
.suspend = ide_pci_suspend, .resume = ide_pci_resume, |
1da177e4c Linux-2.6.12-rc2 |
265 |
}; |
82ab1eece ide: add missing ... |
266 |
static int __init cs5530_ide_init(void) |
1da177e4c Linux-2.6.12-rc2 |
267 |
{ |
a9ab09e26 ide: use unique n... |
268 |
return ide_pci_register_driver(&cs5530_pci_driver); |
1da177e4c Linux-2.6.12-rc2 |
269 |
} |
d16492a97 cs5530: add ->rem... |
270 271 |
static void __exit cs5530_ide_exit(void) { |
a9ab09e26 ide: use unique n... |
272 |
pci_unregister_driver(&cs5530_pci_driver); |
d16492a97 cs5530: add ->rem... |
273 |
} |
1da177e4c Linux-2.6.12-rc2 |
274 |
module_init(cs5530_ide_init); |
d16492a97 cs5530: add ->rem... |
275 |
module_exit(cs5530_ide_exit); |
1da177e4c Linux-2.6.12-rc2 |
276 277 278 279 |
MODULE_AUTHOR("Mark Lord"); MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE"); MODULE_LICENSE("GPL"); |