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