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