Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.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
220         if (CHECK_AX88796L_PORT(port)) {
221                 p = (volatile unsigned short *)port88796l(port, 0);
222                 while (count--) *((unsigned char *) addr)++ = *p & 0xff;
223         } else if (PXSEG(port))
224                 while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)port;
225         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
226                 bp = (__u8 *)PCI_IOMAP(port);
227                 while (count--) *((volatile unsigned char *) addr)++ = *bp;
228         } else {
229                 p = (volatile unsigned short *)port2adr(port);
230                 while (count--) *((unsigned char *) addr)++ = *p & 0xff;
231         }
232 }
233
234 void rts7751r2d_insw(unsigned long port, void *addr, unsigned long count)
235 {
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--) *((__u16 *) addr)++ = *p;
247 }
248
249 void rts7751r2d_insl(unsigned long port, void *addr, unsigned long count)
250 {
251         if (CHECK_AX88796L_PORT(port))
252                 maybebadio(insl, port);
253         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
254                 volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
255
256                 while (count--) *((__u32 *) addr)++ = *p;
257         } else
258                 maybebadio(insl, port);
259 }
260
261 void rts7751r2d_outsb(unsigned long port, const void *addr, unsigned long count)
262 {
263         volatile __u8 *bp;
264         volatile __u16 *p;
265
266         if (CHECK_AX88796L_PORT(port)) {
267                 p = (volatile unsigned short *)port88796l(port, 0);
268                 while (count--) *p = *((unsigned char *) addr)++;
269         } else if (PXSEG(port))
270                 while (count--) *(volatile unsigned char *)port = *((unsigned char *) addr)++;
271         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
272                 bp = (__u8 *)PCI_IOMAP(port);
273                 while (count--) *bp = *((volatile unsigned char *) addr)++;
274         } else {
275                 p = (volatile unsigned short *)port2adr(port);
276                 while (count--) *p = *((unsigned char *) addr)++;
277         }
278 }
279
280 void rts7751r2d_outsw(unsigned long port, const void *addr, unsigned long count)
281 {
282         volatile __u16 *p;
283
284         if (CHECK_AX88796L_PORT(port))
285                 p = (volatile unsigned short *)port88796l(port, 1);
286         else if (PXSEG(port))
287                 p = (volatile unsigned short *)port;
288         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
289                 p = (volatile unsigned short *)PCI_IOMAP(port);
290         else
291                 p = (volatile unsigned short *)port2adr(port);
292         while (count--) *p = *((__u16 *) addr)++;
293 }
294
295 void rts7751r2d_outsl(unsigned long port, const void *addr, unsigned long count)
296 {
297         if (CHECK_AX88796L_PORT(port))
298                 maybebadio(outsl, port);
299         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
300                 volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
301
302                 while (count--) *p = *((__u32 *) addr)++;
303         } else
304                 maybebadio(outsl, port);
305 }
306
307 void *rts7751r2d_ioremap(unsigned long offset, unsigned long size)
308 {
309         if (offset >= 0xfd000000)
310                 return (void *)offset;
311         else
312                 return (void *)P2SEGADDR(offset);
313 }
314 EXPORT_SYMBOL(rts7751r2d_ioremap);
315
316 unsigned long rts7751r2d_isa_port2addr(unsigned long offset)
317 {
318         return port2adr(offset);
319 }