diff options
Diffstat (limited to 'drivers/ide/umc8672.c')
-rw-r--r-- | drivers/ide/umc8672.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c new file mode 100644 index 000000000000..1da076e0c917 --- /dev/null +++ b/drivers/ide/umc8672.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1995-1996 Linus Torvalds & author (see below) | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * Principal Author/Maintainer: PODIEN@hml2.atlas.de (Wolfram Podien) | ||
7 | * | ||
8 | * This file provides support for the advanced features | ||
9 | * of the UMC 8672 IDE interface. | ||
10 | * | ||
11 | * Version 0.01 Initial version, hacked out of ide.c, | ||
12 | * and #include'd rather than compiled separately. | ||
13 | * This will get cleaned up in a subsequent release. | ||
14 | * | ||
15 | * Version 0.02 now configs/compiles separate from ide.c -ml | ||
16 | * Version 0.03 enhanced auto-tune, fix display bug | ||
17 | * Version 0.05 replace sti() with restore_flags() -ml | ||
18 | * add detection of possible race condition -ml | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * VLB Controller Support from | ||
23 | * Wolfram Podien | ||
24 | * Rohoefe 3 | ||
25 | * D28832 Achim | ||
26 | * Germany | ||
27 | * | ||
28 | * To enable UMC8672 support there must a lilo line like | ||
29 | * append="ide0=umc8672"... | ||
30 | * To set the speed according to the abilities of the hardware there must be a | ||
31 | * line like | ||
32 | * #define UMC_DRIVE0 11 | ||
33 | * in the beginning of the driver, which sets the speed of drive 0 to 11 (there | ||
34 | * are some lines present). 0 - 11 are allowed speed values. These values are | ||
35 | * the results from the DOS speed test program supplied from UMC. 11 is the | ||
36 | * highest speed (about PIO mode 3) | ||
37 | */ | ||
38 | #define REALLY_SLOW_IO /* some systems can safely undef this */ | ||
39 | |||
40 | #include <linux/module.h> | ||
41 | #include <linux/types.h> | ||
42 | #include <linux/kernel.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <linux/timer.h> | ||
45 | #include <linux/mm.h> | ||
46 | #include <linux/ioport.h> | ||
47 | #include <linux/blkdev.h> | ||
48 | #include <linux/ide.h> | ||
49 | #include <linux/init.h> | ||
50 | |||
51 | #include <asm/io.h> | ||
52 | |||
53 | #define DRV_NAME "umc8672" | ||
54 | |||
55 | /* | ||
56 | * Default speeds. These can be changed with "auto-tune" and/or hdparm. | ||
57 | */ | ||
58 | #define UMC_DRIVE0 1 /* DOS measured drive speeds */ | ||
59 | #define UMC_DRIVE1 1 /* 0 to 11 allowed */ | ||
60 | #define UMC_DRIVE2 1 /* 11 = Fastest Speed */ | ||
61 | #define UMC_DRIVE3 1 /* In case of crash reduce speed */ | ||
62 | |||
63 | static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3}; | ||
64 | static const u8 pio_to_umc [5] = {0, 3, 7, 10, 11}; /* rough guesses */ | ||
65 | |||
66 | /* 0 1 2 3 4 5 6 7 8 9 10 11 */ | ||
67 | static const u8 speedtab [3][12] = { | ||
68 | {0x0f, 0x0b, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1}, | ||
69 | {0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1}, | ||
70 | {0xff, 0xcb, 0xc0, 0x58, 0x36, 0x33, 0x23, 0x22, 0x21, 0x11, 0x10, 0x0} | ||
71 | }; | ||
72 | |||
73 | static void out_umc(char port, char wert) | ||
74 | { | ||
75 | outb_p(port, 0x108); | ||
76 | outb_p(wert, 0x109); | ||
77 | } | ||
78 | |||
79 | static inline u8 in_umc(char port) | ||
80 | { | ||
81 | outb_p(port, 0x108); | ||
82 | return inb_p(0x109); | ||
83 | } | ||
84 | |||
85 | static void umc_set_speeds(u8 speeds[]) | ||
86 | { | ||
87 | int i, tmp; | ||
88 | |||
89 | outb_p(0x5A, 0x108); /* enable umc */ | ||
90 | |||
91 | out_umc(0xd7, (speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4))); | ||
92 | out_umc(0xd6, (speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4))); | ||
93 | tmp = 0; | ||
94 | for (i = 3; i >= 0; i--) | ||
95 | tmp = (tmp << 2) | speedtab[1][speeds[i]]; | ||
96 | out_umc(0xdc, tmp); | ||
97 | for (i = 0; i < 4; i++) { | ||
98 | out_umc(0xd0 + i, speedtab[2][speeds[i]]); | ||
99 | out_umc(0xd8 + i, speedtab[2][speeds[i]]); | ||
100 | } | ||
101 | outb_p(0xa5, 0x108); /* disable umc */ | ||
102 | |||
103 | printk("umc8672: drive speeds [0 to 11]: %d %d %d %d\n", | ||
104 | speeds[0], speeds[1], speeds[2], speeds[3]); | ||
105 | } | ||
106 | |||
107 | static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio) | ||
108 | { | ||
109 | ide_hwif_t *hwif = drive->hwif; | ||
110 | unsigned long flags; | ||
111 | |||
112 | printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", | ||
113 | drive->name, pio, pio_to_umc[pio]); | ||
114 | spin_lock_irqsave(&ide_lock, flags); | ||
115 | if (hwif->mate && hwif->mate->hwgroup->handler) { | ||
116 | printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n"); | ||
117 | } else { | ||
118 | current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio]; | ||
119 | umc_set_speeds(current_speeds); | ||
120 | } | ||
121 | spin_unlock_irqrestore(&ide_lock, flags); | ||
122 | } | ||
123 | |||
124 | static const struct ide_port_ops umc8672_port_ops = { | ||
125 | .set_pio_mode = umc_set_pio_mode, | ||
126 | }; | ||
127 | |||
128 | static const struct ide_port_info umc8672_port_info __initdata = { | ||
129 | .name = DRV_NAME, | ||
130 | .chipset = ide_umc8672, | ||
131 | .port_ops = &umc8672_port_ops, | ||
132 | .host_flags = IDE_HFLAG_NO_DMA, | ||
133 | .pio_mask = ATA_PIO4, | ||
134 | }; | ||
135 | |||
136 | static int __init umc8672_probe(void) | ||
137 | { | ||
138 | unsigned long flags; | ||
139 | |||
140 | if (!request_region(0x108, 2, "umc8672")) { | ||
141 | printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n"); | ||
142 | return 1; | ||
143 | } | ||
144 | local_irq_save(flags); | ||
145 | outb_p(0x5A, 0x108); /* enable umc */ | ||
146 | if (in_umc (0xd5) != 0xa0) { | ||
147 | local_irq_restore(flags); | ||
148 | printk(KERN_ERR "umc8672: not found\n"); | ||
149 | release_region(0x108, 2); | ||
150 | return 1; | ||
151 | } | ||
152 | outb_p(0xa5, 0x108); /* disable umc */ | ||
153 | |||
154 | umc_set_speeds(current_speeds); | ||
155 | local_irq_restore(flags); | ||
156 | |||
157 | return ide_legacy_device_add(&umc8672_port_info, 0); | ||
158 | } | ||
159 | |||
160 | static int probe_umc8672; | ||
161 | |||
162 | module_param_named(probe, probe_umc8672, bool, 0); | ||
163 | MODULE_PARM_DESC(probe, "probe for UMC8672 chipset"); | ||
164 | |||
165 | static int __init umc8672_init(void) | ||
166 | { | ||
167 | if (probe_umc8672 == 0) | ||
168 | goto out; | ||
169 | |||
170 | if (umc8672_probe() == 0) | ||
171 | return 0;; | ||
172 | out: | ||
173 | return -ENODEV;; | ||
174 | } | ||
175 | |||
176 | module_init(umc8672_init); | ||
177 | |||
178 | MODULE_AUTHOR("Wolfram Podien"); | ||
179 | MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset"); | ||
180 | MODULE_LICENSE("GPL"); | ||