diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/ide/pci/opti621.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/ide/pci/opti621.c')
-rw-r--r-- | drivers/ide/pci/opti621.c | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c new file mode 100644 index 000000000000..cf4fd91d396a --- /dev/null +++ b/drivers/ide/pci/opti621.c | |||
@@ -0,0 +1,394 @@ | |||
1 | /* | ||
2 | * linux/drivers/ide/pci/opti621.c Version 0.7 Sept 10, 2002 | ||
3 | * | ||
4 | * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Authors: | ||
9 | * Jaromir Koutek <miri@punknet.cz>, | ||
10 | * Jan Harkes <jaharkes@cwi.nl>, | ||
11 | * Mark Lord <mlord@pobox.com> | ||
12 | * Some parts of code are from ali14xx.c and from rz1000.c. | ||
13 | * | ||
14 | * OPTi is trademark of OPTi, Octek is trademark of Octek. | ||
15 | * | ||
16 | * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps | ||
17 | * and disassembled/traced setupvic.exe (DOS program). | ||
18 | * It increases kernel code about 2 kB. | ||
19 | * I don't have this card no more, but I hope I can get some in case | ||
20 | * of needed development. | ||
21 | * My card is Octek PIDE 1.01 (on card) or OPTiViC (program). | ||
22 | * It has a place for a secondary connector in circuit, but nothing | ||
23 | * is there. Also BIOS says no address for | ||
24 | * secondary controller (see bellow in ide_init_opti621). | ||
25 | * I've only tested this on my system, which only has one disk. | ||
26 | * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus | ||
27 | * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random | ||
28 | * lockups). I tried the OCTEK double speed CD-ROM and | ||
29 | * it does not work! But I can't boot DOS also, so it's probably | ||
30 | * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no | ||
31 | * problems) and Seagate 1GB (as slave, WD as master). My experiences | ||
32 | * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes | ||
33 | * it slows to about 100kB/s! I don't know why and I have | ||
34 | * not this drive now, so I can't try it again. | ||
35 | * I write this driver because I lost the paper ("manual") with | ||
36 | * settings of jumpers on the card and I have to boot Linux with | ||
37 | * Loadlin except LILO, cause I have to run the setupvic.exe program | ||
38 | * already or I get disk errors (my test: rpm -Vf | ||
39 | * /usr/X11R6/bin/XF86_SVGA - or any big file). | ||
40 | * Some numbers from hdparm -t /dev/hda: | ||
41 | * Timing buffer-cache reads: 32 MB in 3.02 seconds =10.60 MB/sec | ||
42 | * Timing buffered disk reads: 16 MB in 5.52 seconds = 2.90 MB/sec | ||
43 | * I have 4 Megs/s before, but I don't know why (maybe changes | ||
44 | * in hdparm test). | ||
45 | * After release of 0.1, I got some successful reports, so it might work. | ||
46 | * | ||
47 | * The main problem with OPTi is that some timings for master | ||
48 | * and slave must be the same. For example, if you have master | ||
49 | * PIO 3 and slave PIO 0, driver have to set some timings of | ||
50 | * master for PIO 0. Second problem is that opti621_tune_drive | ||
51 | * got only one drive to set, but have to set both drives. | ||
52 | * This is solved in compute_pios. If you don't set | ||
53 | * the second drive, compute_pios use ide_get_best_pio_mode | ||
54 | * for autoselect mode (you can change it to PIO 0, if you want). | ||
55 | * If you then set the second drive to another PIO, the old value | ||
56 | * (automatically selected) will be overrided by yours. | ||
57 | * There is a 25/33MHz switch in configuration | ||
58 | * register, but driver is written for use at any frequency which get | ||
59 | * (use idebus=xx to select PCI bus speed). | ||
60 | * Use ide0=autotune for automatical tune of the PIO modes. | ||
61 | * If you get strange results, do not use this and set PIO manually | ||
62 | * by hdparm. | ||
63 | * | ||
64 | * Version 0.1, Nov 8, 1996 | ||
65 | * by Jaromir Koutek, for 2.1.8. | ||
66 | * Initial version of driver. | ||
67 | * | ||
68 | * Version 0.2 | ||
69 | * Number 0.2 skipped. | ||
70 | * | ||
71 | * Version 0.3, Nov 29, 1997 | ||
72 | * by Mark Lord (probably), for 2.1.68 | ||
73 | * Updates for use with new IDE block driver. | ||
74 | * | ||
75 | * Version 0.4, Dec 14, 1997 | ||
76 | * by Jan Harkes | ||
77 | * Fixed some errors and cleaned the code. | ||
78 | * | ||
79 | * Version 0.5, Jan 2, 1998 | ||
80 | * by Jaromir Koutek | ||
81 | * Updates for use with (again) new IDE block driver. | ||
82 | * Update of documentation. | ||
83 | * | ||
84 | * Version 0.6, Jan 2, 1999 | ||
85 | * by Jaromir Koutek | ||
86 | * Reversed to version 0.3 of the driver, because | ||
87 | * 0.5 doesn't work. | ||
88 | */ | ||
89 | |||
90 | #undef REALLY_SLOW_IO /* most systems can safely undef this */ | ||
91 | #define OPTI621_DEBUG /* define for debug messages */ | ||
92 | |||
93 | #include <linux/types.h> | ||
94 | #include <linux/module.h> | ||
95 | #include <linux/kernel.h> | ||
96 | #include <linux/delay.h> | ||
97 | #include <linux/timer.h> | ||
98 | #include <linux/mm.h> | ||
99 | #include <linux/ioport.h> | ||
100 | #include <linux/blkdev.h> | ||
101 | #include <linux/pci.h> | ||
102 | #include <linux/hdreg.h> | ||
103 | #include <linux/ide.h> | ||
104 | |||
105 | #include <asm/io.h> | ||
106 | |||
107 | #define OPTI621_MAX_PIO 3 | ||
108 | /* In fact, I do not have any PIO 4 drive | ||
109 | * (address: 25 ns, data: 70 ns, recovery: 35 ns), | ||
110 | * but OPTi 82C621 is programmable and it can do (minimal values): | ||
111 | * on 40MHz PCI bus (pulse 25 ns): | ||
112 | * address: 25 ns, data: 25 ns, recovery: 50 ns; | ||
113 | * on 20MHz PCI bus (pulse 50 ns): | ||
114 | * address: 50 ns, data: 50 ns, recovery: 100 ns. | ||
115 | */ | ||
116 | |||
117 | /* #define READ_PREFETCH 0 */ | ||
118 | /* Uncomment for disable read prefetch. | ||
119 | * There is some readprefetch capatibility in hdparm, | ||
120 | * but when I type hdparm -P 1 /dev/hda, I got errors | ||
121 | * and till reset drive is inaccessible. | ||
122 | * This (hw) read prefetch is safe on my drive. | ||
123 | */ | ||
124 | |||
125 | #ifndef READ_PREFETCH | ||
126 | #define READ_PREFETCH 0x40 /* read prefetch is enabled */ | ||
127 | #endif /* else read prefetch is disabled */ | ||
128 | |||
129 | #define READ_REG 0 /* index of Read cycle timing register */ | ||
130 | #define WRITE_REG 1 /* index of Write cycle timing register */ | ||
131 | #define CNTRL_REG 3 /* index of Control register */ | ||
132 | #define STRAP_REG 5 /* index of Strap register */ | ||
133 | #define MISC_REG 6 /* index of Miscellaneous register */ | ||
134 | |||
135 | static int reg_base; | ||
136 | |||
137 | #define PIO_NOT_EXIST 254 | ||
138 | #define PIO_DONT_KNOW 255 | ||
139 | |||
140 | /* there are stored pio numbers from other calls of opti621_tune_drive */ | ||
141 | static void compute_pios(ide_drive_t *drive, u8 pio) | ||
142 | /* Store values into drive->drive_data | ||
143 | * second_contr - 0 for primary controller, 1 for secondary | ||
144 | * slave_drive - 0 -> pio is for master, 1 -> pio is for slave | ||
145 | * pio - PIO mode for selected drive (for other we don't know) | ||
146 | */ | ||
147 | { | ||
148 | int d; | ||
149 | ide_hwif_t *hwif = HWIF(drive); | ||
150 | |||
151 | drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL); | ||
152 | for (d = 0; d < 2; ++d) { | ||
153 | drive = &hwif->drives[d]; | ||
154 | if (drive->present) { | ||
155 | if (drive->drive_data == PIO_DONT_KNOW) | ||
156 | drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL); | ||
157 | #ifdef OPTI621_DEBUG | ||
158 | printk("%s: Selected PIO mode %d\n", | ||
159 | drive->name, drive->drive_data); | ||
160 | #endif | ||
161 | } else { | ||
162 | drive->drive_data = PIO_NOT_EXIST; | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | |||
167 | static int cmpt_clk(int time, int bus_speed) | ||
168 | /* Returns (rounded up) time in clocks for time in ns, | ||
169 | * with bus_speed in MHz. | ||
170 | * Example: bus_speed = 40 MHz, time = 80 ns | ||
171 | * 1000/40 = 25 ns (clk value), | ||
172 | * 80/25 = 3.2, rounded up to 4 (I hope ;-)). | ||
173 | * Use idebus=xx to select right frequency. | ||
174 | */ | ||
175 | { | ||
176 | return ((time*bus_speed+999)/1000); | ||
177 | } | ||
178 | |||
179 | static void write_reg(ide_hwif_t *hwif, u8 value, int reg) | ||
180 | /* Write value to register reg, base of register | ||
181 | * is at reg_base (0x1f0 primary, 0x170 secondary, | ||
182 | * if not changed by PCI configuration). | ||
183 | * This is from setupvic.exe program. | ||
184 | */ | ||
185 | { | ||
186 | hwif->INW(reg_base+1); | ||
187 | hwif->INW(reg_base+1); | ||
188 | hwif->OUTB(3, reg_base+2); | ||
189 | hwif->OUTB(value, reg_base+reg); | ||
190 | hwif->OUTB(0x83, reg_base+2); | ||
191 | } | ||
192 | |||
193 | static u8 read_reg(ide_hwif_t *hwif, int reg) | ||
194 | /* Read value from register reg, base of register | ||
195 | * is at reg_base (0x1f0 primary, 0x170 secondary, | ||
196 | * if not changed by PCI configuration). | ||
197 | * This is from setupvic.exe program. | ||
198 | */ | ||
199 | { | ||
200 | u8 ret = 0; | ||
201 | |||
202 | hwif->INW(reg_base+1); | ||
203 | hwif->INW(reg_base+1); | ||
204 | hwif->OUTB(3, reg_base+2); | ||
205 | ret = hwif->INB(reg_base+reg); | ||
206 | hwif->OUTB(0x83, reg_base+2); | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | typedef struct pio_clocks_s { | ||
211 | int address_time; /* Address setup (clocks) */ | ||
212 | int data_time; /* Active/data pulse (clocks) */ | ||
213 | int recovery_time; /* Recovery time (clocks) */ | ||
214 | } pio_clocks_t; | ||
215 | |||
216 | static void compute_clocks(int pio, pio_clocks_t *clks) | ||
217 | { | ||
218 | if (pio != PIO_NOT_EXIST) { | ||
219 | int adr_setup, data_pls; | ||
220 | int bus_speed = system_bus_clock(); | ||
221 | |||
222 | adr_setup = ide_pio_timings[pio].setup_time; | ||
223 | data_pls = ide_pio_timings[pio].active_time; | ||
224 | clks->address_time = cmpt_clk(adr_setup, bus_speed); | ||
225 | clks->data_time = cmpt_clk(data_pls, bus_speed); | ||
226 | clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time | ||
227 | - adr_setup-data_pls, bus_speed); | ||
228 | if (clks->address_time<1) clks->address_time = 1; | ||
229 | if (clks->address_time>4) clks->address_time = 4; | ||
230 | if (clks->data_time<1) clks->data_time = 1; | ||
231 | if (clks->data_time>16) clks->data_time = 16; | ||
232 | if (clks->recovery_time<2) clks->recovery_time = 2; | ||
233 | if (clks->recovery_time>17) clks->recovery_time = 17; | ||
234 | } else { | ||
235 | clks->address_time = 1; | ||
236 | clks->data_time = 1; | ||
237 | clks->recovery_time = 2; | ||
238 | /* minimal values */ | ||
239 | } | ||
240 | |||
241 | } | ||
242 | |||
243 | /* Main tune procedure, called from tuneproc. */ | ||
244 | static void opti621_tune_drive (ide_drive_t *drive, u8 pio) | ||
245 | { | ||
246 | /* primary and secondary drives share some registers, | ||
247 | * so we have to program both drives | ||
248 | */ | ||
249 | unsigned long flags; | ||
250 | u8 pio1 = 0, pio2 = 0; | ||
251 | pio_clocks_t first, second; | ||
252 | int ax, drdy; | ||
253 | u8 cycle1, cycle2, misc; | ||
254 | ide_hwif_t *hwif = HWIF(drive); | ||
255 | |||
256 | /* sets drive->drive_data for both drives */ | ||
257 | compute_pios(drive, pio); | ||
258 | pio1 = hwif->drives[0].drive_data; | ||
259 | pio2 = hwif->drives[1].drive_data; | ||
260 | |||
261 | compute_clocks(pio1, &first); | ||
262 | compute_clocks(pio2, &second); | ||
263 | |||
264 | /* ax = max(a1,a2) */ | ||
265 | ax = (first.address_time < second.address_time) ? second.address_time : first.address_time; | ||
266 | |||
267 | drdy = 2; /* DRDY is default 2 (by OPTi Databook) */ | ||
268 | |||
269 | cycle1 = ((first.data_time-1)<<4) | (first.recovery_time-2); | ||
270 | cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2); | ||
271 | misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1); | ||
272 | |||
273 | #ifdef OPTI621_DEBUG | ||
274 | printk("%s: master: address: %d, data: %d, " | ||
275 | "recovery: %d, drdy: %d [clk]\n", | ||
276 | hwif->name, ax, first.data_time, | ||
277 | first.recovery_time, drdy); | ||
278 | printk("%s: slave: address: %d, data: %d, " | ||
279 | "recovery: %d, drdy: %d [clk]\n", | ||
280 | hwif->name, ax, second.data_time, | ||
281 | second.recovery_time, drdy); | ||
282 | #endif | ||
283 | |||
284 | spin_lock_irqsave(&ide_lock, flags); | ||
285 | |||
286 | reg_base = hwif->io_ports[IDE_DATA_OFFSET]; | ||
287 | |||
288 | /* allow Register-B */ | ||
289 | hwif->OUTB(0xc0, reg_base+CNTRL_REG); | ||
290 | /* hmm, setupvic.exe does this ;-) */ | ||
291 | hwif->OUTB(0xff, reg_base+5); | ||
292 | /* if reads 0xff, adapter not exist? */ | ||
293 | (void) hwif->INB(reg_base+CNTRL_REG); | ||
294 | /* if reads 0xc0, no interface exist? */ | ||
295 | read_reg(hwif, CNTRL_REG); | ||
296 | /* read version, probably 0 */ | ||
297 | read_reg(hwif, STRAP_REG); | ||
298 | |||
299 | /* program primary drive */ | ||
300 | /* select Index-0 for Register-A */ | ||
301 | write_reg(hwif, 0, MISC_REG); | ||
302 | /* set read cycle timings */ | ||
303 | write_reg(hwif, cycle1, READ_REG); | ||
304 | /* set write cycle timings */ | ||
305 | write_reg(hwif, cycle1, WRITE_REG); | ||
306 | |||
307 | /* program secondary drive */ | ||
308 | /* select Index-1 for Register-B */ | ||
309 | write_reg(hwif, 1, MISC_REG); | ||
310 | /* set read cycle timings */ | ||
311 | write_reg(hwif, cycle2, READ_REG); | ||
312 | /* set write cycle timings */ | ||
313 | write_reg(hwif, cycle2, WRITE_REG); | ||
314 | |||
315 | /* use Register-A for drive 0 */ | ||
316 | /* use Register-B for drive 1 */ | ||
317 | write_reg(hwif, 0x85, CNTRL_REG); | ||
318 | |||
319 | /* set address setup, DRDY timings, */ | ||
320 | /* and read prefetch for both drives */ | ||
321 | write_reg(hwif, misc, MISC_REG); | ||
322 | |||
323 | spin_unlock_irqrestore(&ide_lock, flags); | ||
324 | } | ||
325 | |||
326 | /* | ||
327 | * init_hwif_opti621() is called once for each hwif found at boot. | ||
328 | */ | ||
329 | static void __init init_hwif_opti621 (ide_hwif_t *hwif) | ||
330 | { | ||
331 | hwif->autodma = 0; | ||
332 | hwif->drives[0].drive_data = PIO_DONT_KNOW; | ||
333 | hwif->drives[1].drive_data = PIO_DONT_KNOW; | ||
334 | hwif->tuneproc = &opti621_tune_drive; | ||
335 | |||
336 | if (!(hwif->dma_base)) | ||
337 | return; | ||
338 | |||
339 | hwif->atapi_dma = 1; | ||
340 | hwif->mwdma_mask = 0x07; | ||
341 | hwif->swdma_mask = 0x07; | ||
342 | |||
343 | if (!noautodma) | ||
344 | hwif->autodma = 1; | ||
345 | hwif->drives[0].autodma = hwif->autodma; | ||
346 | hwif->drives[1].autodma = hwif->autodma; | ||
347 | } | ||
348 | |||
349 | static ide_pci_device_t opti621_chipsets[] __devinitdata = { | ||
350 | { /* 0 */ | ||
351 | .name = "OPTI621", | ||
352 | .init_hwif = init_hwif_opti621, | ||
353 | .channels = 2, | ||
354 | .autodma = AUTODMA, | ||
355 | .enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, | ||
356 | .bootable = ON_BOARD, | ||
357 | },{ /* 1 */ | ||
358 | .name = "OPTI621X", | ||
359 | .init_hwif = init_hwif_opti621, | ||
360 | .channels = 2, | ||
361 | .autodma = AUTODMA, | ||
362 | .enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, | ||
363 | .bootable = ON_BOARD, | ||
364 | } | ||
365 | }; | ||
366 | |||
367 | static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id) | ||
368 | { | ||
369 | return ide_setup_pci_device(dev, &opti621_chipsets[id->driver_data]); | ||
370 | } | ||
371 | |||
372 | static struct pci_device_id opti621_pci_tbl[] = { | ||
373 | { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
374 | { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, | ||
375 | { 0, }, | ||
376 | }; | ||
377 | MODULE_DEVICE_TABLE(pci, opti621_pci_tbl); | ||
378 | |||
379 | static struct pci_driver driver = { | ||
380 | .name = "Opti621_IDE", | ||
381 | .id_table = opti621_pci_tbl, | ||
382 | .probe = opti621_init_one, | ||
383 | }; | ||
384 | |||
385 | static int opti621_ide_init(void) | ||
386 | { | ||
387 | return ide_pci_register_driver(&driver); | ||
388 | } | ||
389 | |||
390 | module_init(opti621_ide_init); | ||
391 | |||
392 | MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord"); | ||
393 | MODULE_DESCRIPTION("PCI driver module for Opti621 IDE"); | ||
394 | MODULE_LICENSE("GPL"); | ||