v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / arch / arm / mach-ebsa110 / io.c
1 /*
2  *  linux/arch/arm/mach-ebsa110/isamem.c
3  *
4  *  Copyright (C) 2001 Russell King
5  *
6  * Perform "ISA" memory and IO accesses.  The EBSA110 has some "peculiarities"
7  * in the way it handles accesses to odd IO ports on 16-bit devices.  These
8  * devices have their D0-D15 lines connected to the processors D0-D15 lines.
9  * Since they expect all byte IO operations to be performed on D0-D7, and the
10  * StrongARM expects to transfer the byte to these odd addresses on D8-D15,
11  * we must use a trick to get the required behaviour.
12  *
13  * The trick employed here is to use long word stores to odd address -1.  The
14  * glue logic picks this up as a "trick" access, and asserts the LSB of the
15  * peripherals address bus, thereby accessing the odd IO port.  Meanwhile, the
16  * StrongARM transfers its data on D0-D7 as expected.
17  *
18  * Things get more interesting on the pass-1 EBSA110 - the PCMCIA controller
19  * wiring was screwed in such a way that it had limited memory space access.
20  * Luckily, the work-around for this is not too horrible.  See
21  * __isamem_convert_addr for the details.
22  */
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/types.h>
26
27 #include <asm/io.h>
28 #include <asm/page.h>
29
30 static u32 __isamem_convert_addr(void *addr)
31 {
32         u32 ret, a = (u32) addr;
33
34         /*
35          * The PCMCIA controller is wired up as follows:
36          *        +---------+---------+---------+---------+---------+---------+
37          * PCMCIA | 2 2 2 2 | 1 1 1 1 | 1 1 1 1 | 1 1     |         |         |
38          *        | 3 2 1 0 | 9 8 7 6 | 5 4 3 2 | 1 0 9 8 | 7 6 5 4 | 3 2 1 0 |
39          *        +---------+---------+---------+---------+---------+---------+
40          *  CPU   | 2 2 2 2 | 2 1 1 1 | 1 1 1 1 | 1 1 1   |         |         |
41          *        | 4 3 2 1 | 0 9 9 8 | 7 6 5 4 | 3 2 0 9 | 8 7 6 5 | 4 3 2 x |
42          *        +---------+---------+---------+---------+---------+---------+
43          *
44          * This means that we can access PCMCIA regions as follows:
45          *      0x*10000 -> 0x*1ffff
46          *      0x*70000 -> 0x*7ffff
47          *      0x*90000 -> 0x*9ffff
48          *      0x*f0000 -> 0x*fffff
49          */
50         ret  = (a & 0xf803fe) << 1;
51         ret |= (a & 0x03fc00) << 2;
52
53         ret += 0xe8000000;
54
55         if ((a & 0x20000) == (a & 0x40000) >> 1)
56                 return ret;
57
58         BUG();
59         return 0;
60 }
61
62 /*
63  * read[bwl] and write[bwl]
64  */
65 u8 __readb(void *addr)
66 {
67         u32 ret, a = __isamem_convert_addr(addr);
68
69         if ((int)addr & 1)
70                 ret = __arch_getl(a);
71         else
72                 ret = __arch_getb(a);
73         return ret;
74 }
75
76 u16 __readw(void *addr)
77 {
78         u32 a = __isamem_convert_addr(addr);
79
80         if ((int)addr & 1)
81                 BUG();
82
83         return __arch_getw(a);
84 }
85
86 u32 __readl(void *addr)
87 {
88         u32 ret, a = __isamem_convert_addr(addr);
89
90         if ((int)addr & 3)
91                 BUG();
92
93         ret = __arch_getw(a);
94         ret |= __arch_getw(a + 4) << 16;
95         return ret;
96 }
97
98 EXPORT_SYMBOL(__readb);
99 EXPORT_SYMBOL(__readw);
100 EXPORT_SYMBOL(__readl);
101
102 void __writeb(u8 val, void *addr)
103 {
104         u32 a = __isamem_convert_addr(addr);
105
106         if ((int)addr & 1)
107                 __arch_putl(val, a);
108         else
109                 __arch_putb(val, a);
110 }
111
112 void __writew(u16 val, void *addr)
113 {
114         u32 a = __isamem_convert_addr(addr);
115
116         if ((int)addr & 1)
117                 BUG();
118
119         __arch_putw(val, a);
120 }
121
122 void __writel(u32 val, void *addr)
123 {
124         u32 a = __isamem_convert_addr(addr);
125
126         if ((int)addr & 3)
127                 BUG();
128
129         __arch_putw(val, a);
130         __arch_putw(val >> 16, a + 4);
131 }
132
133 EXPORT_SYMBOL(__writeb);
134 EXPORT_SYMBOL(__writew);
135 EXPORT_SYMBOL(__writel);
136
137 #define SUPERIO_PORT(p) \
138         (((p) >> 3) == (0x3f8 >> 3) || \
139          ((p) >> 3) == (0x2f8 >> 3) || \
140          ((p) >> 3) == (0x378 >> 3))
141
142 u8 __inb(int port)
143 {
144         u32 ret;
145
146         /*
147          * The SuperIO registers use sane addressing techniques...
148          */
149         if (SUPERIO_PORT(port))
150                 ret = __arch_getb(ISAIO_BASE + (port << 2));
151         else {
152                 u32 a = ISAIO_BASE + ((port & ~1) << 1);
153
154                 /*
155                  * Shame nothing else does
156                  */
157                 if (port & 1)
158                         ret = __arch_getl(a);
159                 else
160                         ret = __arch_getb(a);
161         }
162         return ret;
163 }
164
165 u16 __inw(int port)
166 {
167         u32 ret;
168
169         /*
170          * The SuperIO registers use sane addressing techniques...
171          */
172         if (SUPERIO_PORT(port))
173                 ret = __arch_getw(ISAIO_BASE + (port << 2));
174         else {
175                 u32 a = ISAIO_BASE + ((port & ~1) << 1);
176
177                 /*
178                  * Shame nothing else does
179                  */
180                 if (port & 1)
181                         BUG();
182
183                 ret = __arch_getw(a);
184         }
185         return ret;
186 }
187
188 u32 __inl(int port)
189 {
190         BUG();
191         return 0;
192 }
193
194 EXPORT_SYMBOL(__inb);
195 EXPORT_SYMBOL(__inw);
196 EXPORT_SYMBOL(__inl);
197
198 void __outb(u8 val, int port)
199 {
200         /*
201          * The SuperIO registers use sane addressing techniques...
202          */
203         if (SUPERIO_PORT(port))
204                 __arch_putb(val, ISAIO_BASE + (port << 2));
205         else {
206                 u32 a = ISAIO_BASE + ((port & ~1) << 1);
207
208                 /*
209                  * Shame nothing else does
210                  */
211                 if (port & 1)
212                         __arch_putl(val, a);
213                 else
214                         __arch_putb(val, a);
215         }
216 }
217
218 void __outw(u16 val, int port)
219 {
220         u32 off;
221
222         /*
223          * The SuperIO registers use sane addressing techniques...
224          */
225         if (SUPERIO_PORT(port))
226                 off = port << 2;
227         else {
228                 off = (port & ~1) << 1;
229                 if (port & 1)
230                         BUG();
231
232         }
233         __arch_putw(val, ISAIO_BASE + off);
234 }
235
236 void __outl(u32 val, int port)
237 {
238         BUG();
239 }
240
241 EXPORT_SYMBOL(__outb);
242 EXPORT_SYMBOL(__outw);
243 EXPORT_SYMBOL(__outl);
244
245 extern void __arch_writesb(unsigned long virt, const void *from, int len);
246 extern void __arch_writesw(unsigned long virt, const void *from, int len);
247 extern void __arch_writesl(unsigned long virt, const void *from, int len);
248 extern void __arch_readsb(unsigned long virt, void *from, int len);
249 extern void __arch_readsw(unsigned long virt, void *from, int len);
250 extern void __arch_readsl(unsigned long virt, void *from, int len);
251
252 void outsb(unsigned int port, const void *from, int len)
253 {
254         u32 off;
255
256         if (SUPERIO_PORT(port))
257                 off = port << 2;
258         else {
259                 off = (port & ~1) << 1;
260                 if (port & 1)
261                         BUG();
262         }
263
264         __raw_writesb(ISAIO_BASE + off, from, len);
265 }
266
267 void insb(unsigned int port, void *from, int len)
268 {
269         u32 off;
270
271         if (SUPERIO_PORT(port))
272                 off = port << 2;
273         else {
274                 off = (port & ~1) << 1;
275                 if (port & 1)
276                         BUG();
277         }
278
279         __raw_readsb(ISAIO_BASE + off, from, len);
280 }
281
282 void outsw(unsigned int port, const void *from, int len)
283 {
284         u32 off;
285
286         if (SUPERIO_PORT(port))
287                 off = port << 2;
288         else {
289                 off = (port & ~1) << 1;
290                 if (port & 1)
291                         BUG();
292         }
293
294         __raw_writesw(ISAIO_BASE + off, from, len);
295 }
296
297 void insw(unsigned int port, void *from, int len)
298 {
299         u32 off;
300
301         if (SUPERIO_PORT(port))
302                 off = port << 2;
303         else {
304                 off = (port & ~1) << 1;
305                 if (port & 1)
306                         BUG();
307         }
308
309         __raw_readsw(ISAIO_BASE + off, from, len);
310 }
311
312 void outsl(unsigned int port, const void *from, int len)
313 {
314         panic("outsl not supported on this architecture");
315 }
316
317 void insl(unsigned int port, void *from, int len)
318 {
319         panic("insl not supported on this architecture");
320 }