8dc2a2e2e5df8eb10d89c045bda44254c0ff1288
[linux-2.6.git] / arch / sh / boards / renesas / rts7751r2d / io.c
1 /*
2  * linux/arch/sh/kernel/io_rts7751r2d.c
3  *
4  * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
5  * Based largely on io_se.c.
6  *
7  * I/O routine for Renesas Technology sales RTS7751R2D.
8  *
9  * Initial version only to support LAN access; some
10  * placeholder code from io_rts7751r2d.c left in with the
11  * expectation of later SuperIO and PCMCIA access.
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/types.h>
16 #include <linux/pci.h>
17 #include "../../../drivers/pci/pci-sh7751.h"
18 #include <asm/rts7751r2d/rts7751r2d.h>
19 #include <asm/io.h>
20 #include <asm/addrspace.h>
21
22 /*
23  * The 7751R RTS7751R2D uses the built-in PCI controller (PCIC)
24  * of the 7751R processor, and has a SuperIO accessible via the PCI.
25  * The board also includes a PCMCIA controller on its memory bus,
26  * like the other Solution Engine boards.
27  */
28
29 #define PCIIOBR         (volatile long *)PCI_REG(SH7751_PCIIOBR)
30 #define PCIMBR          (volatile long *)PCI_REG(SH7751_PCIMBR)
31 #define PCI_IO_AREA     SH7751_PCI_IO_BASE
32 #define PCI_MEM_AREA    SH7751_PCI_CONFIG_BASE
33
34 #define PCI_IOMAP(adr)  (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
35
36 static inline void delay(void)
37 {
38         ctrl_inw(0xa0000000);
39 }
40
41 static inline unsigned long port2adr(unsigned int port)
42 {
43         if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
44                 if (port == 0x3f6)
45                         return (PA_AREA5_IO + 0x80c);
46                 else
47                         return (PA_AREA5_IO + 0x1000 + ((port-0x1f0) << 1));
48         else
49                 maybebadio((unsigned long)port);
50
51         return port;
52 }
53
54 static inline unsigned long port88796l(unsigned int port, int flag)
55 {
56         unsigned long addr;
57
58         if (flag)
59                 addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1);
60         else
61                 addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1) + 0x1000;
62
63         return addr;
64 }
65
66 /* The 7751R RTS7751R2D seems to have everything hooked */
67 /* up pretty normally (nothing on high-bytes only...) so this */
68 /* shouldn't be needed */
69 static inline int shifted_port(unsigned long port)
70 {
71         /* For IDE registers, value is not shifted */
72         if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
73                 return 0;
74         else
75                 return 1;
76 }
77
78 /* In case someone configures the kernel w/o PCI support: in that */
79 /* scenario, don't ever bother to check for PCI-window addresses */
80
81 /* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
82 #if defined(CONFIG_PCI)
83 #define CHECK_SH7751_PCIIO(port) \
84   ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
85 #else
86 #define CHECK_SH7751_PCIIO(port) (0)
87 #endif
88
89 #if defined(CONFIG_NE2000) || defined(CONFIG_NE2000_MODULE)
90 #define CHECK_AX88796L_PORT(port) \
91   ((port >= AX88796L_IO_BASE) && (port < (AX88796L_IO_BASE+0x20)))
92 #else
93 #define CHECK_AX88796L_PORT(port) (0)
94 #endif
95
96 /*
97  * General outline: remap really low stuff [eventually] to SuperIO,
98  * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
99  * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
100  * should be way beyond the window, and is used  w/o translation for
101  * compatibility.
102  */
103 unsigned char rts7751r2d_inb(unsigned long port)
104 {
105         if (CHECK_AX88796L_PORT(port))
106                 return (*(volatile unsigned short *)port88796l(port, 0)) & 0xff;
107         else if (PXSEG(port))
108                 return *(volatile unsigned char *)port;
109         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
110                 return *(volatile unsigned char *)PCI_IOMAP(port);
111         else
112                 return (*(volatile unsigned short *)port2adr(port) & 0xff);
113 }
114
115 unsigned char rts7751r2d_inb_p(unsigned long port)
116 {
117         unsigned char v;
118
119         if (CHECK_AX88796L_PORT(port))
120                 v = (*(volatile unsigned short *)port88796l(port, 0)) & 0xff;
121         else if (PXSEG(port))
122                 v = *(volatile unsigned char *)port;
123         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
124                 v = *(volatile unsigned char *)PCI_IOMAP(port);
125         else
126                 v = (*(volatile unsigned short *)port2adr(port) & 0xff);
127         delay();
128
129         return v;
130 }
131
132 unsigned short rts7751r2d_inw(unsigned long port)
133 {
134         if (CHECK_AX88796L_PORT(port))
135                 maybebadio(port);
136         else if (PXSEG(port))
137                 return *(volatile unsigned short *)port;
138         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
139                 return *(volatile unsigned short *)PCI_IOMAP(port);
140         else
141                 maybebadio(port);
142
143         return 0;
144 }
145
146 unsigned int rts7751r2d_inl(unsigned long port)
147 {
148         if (CHECK_AX88796L_PORT(port))
149                 maybebadio(port);
150         else if (PXSEG(port))
151                 return *(volatile unsigned long *)port;
152         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
153                 return *(volatile unsigned long *)PCI_IOMAP(port);
154         else
155                 maybebadio(port);
156
157         return 0;
158 }
159
160 void rts7751r2d_outb(unsigned char value, unsigned long port)
161 {
162         if (CHECK_AX88796L_PORT(port))
163                 *((volatile unsigned short *)port88796l(port, 0)) = value;
164         else if (PXSEG(port))
165                 *(volatile unsigned char *)port = value;
166         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
167                 *(volatile unsigned char *)PCI_IOMAP(port) = value;
168         else
169                 *(volatile unsigned short *)port2adr(port) = value;
170 }
171
172 void rts7751r2d_outb_p(unsigned char value, unsigned long port)
173 {
174         if (CHECK_AX88796L_PORT(port))
175                 *((volatile unsigned short *)port88796l(port, 0)) = value;
176         else if (PXSEG(port))
177                 *(volatile unsigned char *)port = value;
178         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
179                 *(volatile unsigned char *)PCI_IOMAP(port) = value;
180         else
181                 *(volatile unsigned short *)port2adr(port) = value;
182         delay();
183 }
184
185 void rts7751r2d_outw(unsigned short value, unsigned long port)
186 {
187         if (CHECK_AX88796L_PORT(port))
188                 maybebadio(port);
189         else if (PXSEG(port))
190                 *(volatile unsigned short *)port = value;
191         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
192                 *(volatile unsigned short *)PCI_IOMAP(port) = value;
193         else
194                 maybebadio(port);
195 }
196
197 void rts7751r2d_outl(unsigned int value, unsigned long port)
198 {
199         if (CHECK_AX88796L_PORT(port))
200                 maybebadio(port);
201         else if (PXSEG(port))
202                 *(volatile unsigned long *)port = value;
203         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
204                 *(volatile unsigned long *)PCI_IOMAP(port) = value;
205         else
206                 maybebadio(port);
207 }
208
209 void rts7751r2d_insb(unsigned long port, void *addr, unsigned long count)
210 {
211         unsigned long a = (unsigned long)addr;
212         volatile __u8 *bp;
213         volatile __u16 *p;
214
215         if (CHECK_AX88796L_PORT(port)) {
216                 p = (volatile unsigned short *)port88796l(port, 0);
217                 while (count--)
218                         ctrl_outb(*p & 0xff, a++);
219         } else if (PXSEG(port))
220                 while (count--)
221                         ctrl_outb(ctrl_inb(port), a++);
222         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
223                 bp = (__u8 *)PCI_IOMAP(port);
224                 while (count--)
225                         ctrl_outb(*bp, a++);
226         } else {
227                 p = (volatile unsigned short *)port2adr(port);
228                 while (count--)
229                         ctrl_outb(*p & 0xff, a++);
230         }
231 }
232
233 void rts7751r2d_insw(unsigned long port, void *addr, unsigned long count)
234 {
235         unsigned long a = (unsigned long)addr;
236         volatile __u16 *p;
237
238         if (CHECK_AX88796L_PORT(port))
239                 p = (volatile unsigned short *)port88796l(port, 1);
240         else if (PXSEG(port))
241                 p = (volatile unsigned short *)port;
242         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
243                 p = (volatile unsigned short *)PCI_IOMAP(port);
244         else
245                 p = (volatile unsigned short *)port2adr(port);
246         while (count--)
247                 ctrl_outw(*p, a++);
248 }
249
250 void rts7751r2d_insl(unsigned long port, void *addr, unsigned long count)
251 {
252         if (CHECK_AX88796L_PORT(port))
253                 maybebadio(port);
254         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
255                 unsigned long a = (unsigned long)addr;
256
257                 while (count--) {
258                         ctrl_outl(ctrl_inl(PCI_IOMAP(port)), a);
259                         a += 4;
260                 }
261         } else
262                 maybebadio(port);
263 }
264
265 void rts7751r2d_outsb(unsigned long port, const void *addr, unsigned long count)
266 {
267         unsigned long a = (unsigned long)addr;
268         volatile __u8 *bp;
269         volatile __u16 *p;
270
271         if (CHECK_AX88796L_PORT(port)) {
272                 p = (volatile unsigned short *)port88796l(port, 0);
273                 while (count--)
274                         *p = ctrl_inb(a++);
275         } else if (PXSEG(port))
276                 while (count--)
277                         ctrl_outb(a++, port);
278         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
279                 bp = (__u8 *)PCI_IOMAP(port);
280                 while (count--)
281                         *bp = ctrl_inb(a++);
282         } else {
283                 p = (volatile unsigned short *)port2adr(port);
284                 while (count--)
285                         *p = ctrl_inb(a++);
286         }
287 }
288
289 void rts7751r2d_outsw(unsigned long port, const void *addr, unsigned long count)
290 {
291         unsigned long a = (unsigned long)addr;
292         volatile __u16 *p;
293
294         if (CHECK_AX88796L_PORT(port))
295                 p = (volatile unsigned short *)port88796l(port, 1);
296         else if (PXSEG(port))
297                 p = (volatile unsigned short *)port;
298         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
299                 p = (volatile unsigned short *)PCI_IOMAP(port);
300         else
301                 p = (volatile unsigned short *)port2adr(port);
302
303         while (count--) {
304                 ctrl_outw(*p, a);
305                 a += 2;
306         }
307 }
308
309 void rts7751r2d_outsl(unsigned long port, const void *addr, unsigned long count)
310 {
311         if (CHECK_AX88796L_PORT(port))
312                 maybebadio(port);
313         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
314                 unsigned long a = (unsigned long)addr;
315
316                 while (count--) {
317                         ctrl_outl(ctrl_inl(a), PCI_IOMAP(port));
318                         a += 4;
319                 }
320         } else
321                 maybebadio(port);
322 }
323
324 unsigned long rts7751r2d_isa_port2addr(unsigned long offset)
325 {
326         return port2adr(offset);
327 }