edecf107fc132d62f64e916048d6c61ab6403d15
[linux-2.6.git] / arch / sh / boards / renesas / hs7751rvoip / io.c
1 /*
2  * linux/arch/sh/kernel/io_hs7751rvoip.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 HS7751RVoIP
8  *
9  * Initial version only to support LAN access; some
10  * placeholder code from io_hs7751rvoip.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/hs7751rvoip/hs7751rvoip.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 extern void *area5_io8_base;    /* Area 5 8bit I/O Base address */
25 extern void *area6_io8_base;    /* Area 6 8bit I/O Base address */
26 extern void *area5_io16_base;   /* Area 5 16bit I/O Base address */
27 extern void *area6_io16_base;   /* Area 6 16bit I/O Base address */
28
29 /*
30  * The 7751R HS7751RVoIP uses the built-in PCI controller (PCIC)
31  * of the 7751R processor, and has a SuperIO accessible via the PCI.
32  * The board also includes a PCMCIA controller on its memory bus,
33  * like the other Solution Engine boards.
34  */
35
36 #define PCIIOBR         (volatile long *)PCI_REG(SH7751_PCIIOBR)
37 #define PCIMBR          (volatile long *)PCI_REG(SH7751_PCIMBR)
38 #define PCI_IO_AREA     SH7751_PCI_IO_BASE
39 #define PCI_MEM_AREA    SH7751_PCI_CONFIG_BASE
40
41 #define PCI_IOMAP(adr)  (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
42
43 #if defined(CONFIG_HS7751RVOIP_CODEC)
44 #define CODEC_IO_BASE   0x1000
45 #endif
46
47 #define maybebadio(name,port) \
48   printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
49          #name, (port), (__u32) __builtin_return_address(0))
50
51 static inline void delay(void)
52 {
53         ctrl_inw(0xa0000000);
54 }
55
56 static inline unsigned long port2adr(unsigned int port)
57 {
58         if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
59                 if (port == 0x3f6)
60                         return ((unsigned long)area5_io16_base + 0x0c);
61                 else
62                         return ((unsigned long)area5_io16_base + 0x800 + ((port-0x1f0) << 1));
63         else
64                 maybebadio(port2adr, (unsigned long)port);
65         return port;
66 }
67
68 /* The 7751R HS7751RVoIP seems to have everything hooked */
69 /* up pretty normally (nothing on high-bytes only...) so this */
70 /* shouldn't be needed */
71 static inline int shifted_port(unsigned long port)
72 {
73         /* For IDE registers, value is not shifted */
74         if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
75                 return 0;
76         else
77                 return 1;
78 }
79
80 #if defined(CONFIG_HS7751RVOIP_CODEC)
81 static inline int
82 codec_port(unsigned long port)
83 {
84         if (CODEC_IO_BASE <= port && port < (CODEC_IO_BASE+0x20))
85                 return 1;
86         else
87                 return 0;
88 }
89 #endif
90
91 /* In case someone configures the kernel w/o PCI support: in that */
92 /* scenario, don't ever bother to check for PCI-window addresses */
93
94 /* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
95 #if defined(CONFIG_PCI)
96 #define CHECK_SH7751_PCIIO(port) \
97   ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
98 #else
99 #define CHECK_SH7751_PCIIO(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 hs7751rvoip_inb(unsigned long port)
110 {
111         if (PXSEG(port))
112                 return *(volatile unsigned char *)port;
113 #if defined(CONFIG_HS7751RVOIP_CODEC)
114         else if (codec_port(port))
115                 return *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
116 #endif
117         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
118                 return *(volatile unsigned char *)PCI_IOMAP(port);
119         else
120                 return (*(volatile unsigned short *)port2adr(port) & 0xff);
121 }
122
123 unsigned char hs7751rvoip_inb_p(unsigned long port)
124 {
125         unsigned char v;
126
127         if (PXSEG(port))
128                 v = *(volatile unsigned char *)port;
129 #if defined(CONFIG_HS7751RVOIP_CODEC)
130         else if (codec_port(port))
131                 v = *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
132 #endif
133         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
134                 v = *(volatile unsigned char *)PCI_IOMAP(port);
135         else
136                 v = (*(volatile unsigned short *)port2adr(port) & 0xff);
137         delay();
138         return v;
139 }
140
141 unsigned short hs7751rvoip_inw(unsigned long port)
142 {
143         if (PXSEG(port))
144                 return *(volatile unsigned short *)port;
145         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
146                 return *(volatile unsigned short *)PCI_IOMAP(port);
147         else
148                 maybebadio(inw, port);
149         return 0;
150 }
151
152 unsigned int hs7751rvoip_inl(unsigned long port)
153 {
154         if (PXSEG(port))
155                 return *(volatile unsigned long *)port;
156         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
157                 return *(volatile unsigned long *)PCI_IOMAP(port);
158         else
159                 maybebadio(inl, port);
160         return 0;
161 }
162
163 void hs7751rvoip_outb(unsigned char value, unsigned long port)
164 {
165
166         if (PXSEG(port))
167                 *(volatile unsigned char *)port = value;
168 #if defined(CONFIG_HS7751RVOIP_CODEC)
169         else if (codec_port(port))
170                 *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = value;
171 #endif
172         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
173                 *(unsigned char *)PCI_IOMAP(port) = value;
174         else
175                 *(volatile unsigned short *)port2adr(port) = value;
176 }
177
178 void hs7751rvoip_outb_p(unsigned char value, unsigned long port)
179 {
180         if (PXSEG(port))
181                 *(volatile unsigned char *)port = value;
182 #if defined(CONFIG_HS7751RVOIP_CODEC)
183         else if (codec_port(port))
184                 *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = value;
185 #endif
186         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
187                 *(unsigned char *)PCI_IOMAP(port) = value;
188         else
189                 *(volatile unsigned short *)port2adr(port) = value;
190         delay();
191 }
192
193 void hs7751rvoip_outw(unsigned short value, unsigned long port)
194 {
195         if (PXSEG(port))
196                 *(volatile unsigned short *)port = value;
197         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
198                 *(unsigned short *)PCI_IOMAP(port) = value;
199         else
200                 maybebadio(outw, port);
201 }
202
203 void hs7751rvoip_outl(unsigned int value, unsigned long port)
204 {
205         if (PXSEG(port))
206                 *(volatile unsigned long *)port = value;
207         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
208                 *((unsigned long *)PCI_IOMAP(port)) = value;
209         else
210                 maybebadio(outl, port);
211 }
212
213 void hs7751rvoip_insb(unsigned long port, void *addr, unsigned long count)
214 {
215         if (PXSEG(port))
216                 while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)port;
217 #if defined(CONFIG_HS7751RVOIP_CODEC)
218         else if (codec_port(port))
219                 while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
220 #endif
221         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
222                 volatile __u8 *bp = (__u8 *)PCI_IOMAP(port);
223
224                 while (count--) *((volatile unsigned char *) addr)++ = *bp;
225         } else {
226                 volatile __u16 *p = (volatile unsigned short *)port2adr(port);
227
228                 while (count--) *((unsigned char *) addr)++ = *p & 0xff;
229         }
230 }
231
232 void hs7751rvoip_insw(unsigned long port, void *addr, unsigned long count)
233 {
234         volatile __u16 *p;
235
236         if (PXSEG(port))
237                 p = (volatile unsigned short *)port;
238         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
239                 p = (volatile unsigned short *)PCI_IOMAP(port);
240         else
241                 p = (volatile unsigned short *)port2adr(port);
242         while (count--) *((__u16 *) addr)++ = *p;
243 }
244
245 void hs7751rvoip_insl(unsigned long port, void *addr, unsigned long count)
246 {
247         if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
248                 volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
249
250                 while (count--) *((__u32 *) addr)++ = *p;
251         } else
252                 maybebadio(insl, port);
253 }
254
255 void hs7751rvoip_outsb(unsigned long port, const void *addr, unsigned long count)
256 {
257         if (PXSEG(port))
258                 while (count--) *(volatile unsigned char *)port = *((unsigned char *) addr)++;
259 #if defined(CONFIG_HS7751RVOIP_CODEC)
260         else if (codec_port(port))
261                 while (count--) *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = *((unsigned char *) addr)++;
262 #endif
263         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
264                 volatile __u8 *bp = (__u8 *)PCI_IOMAP(port);
265
266                 while (count--) *bp = *((volatile unsigned char *) addr)++;
267         } else {
268                 volatile __u16 *p = (volatile unsigned short *)port2adr(port);
269
270                 while (count--) *p = *((unsigned char *) addr)++;
271         }
272 }
273
274 void hs7751rvoip_outsw(unsigned long port, const void *addr, unsigned long count)
275 {
276         volatile __u16 *p;
277
278         if (PXSEG(port))
279                 p = (volatile unsigned short *)port;
280         else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
281                 p = (volatile unsigned short *)PCI_IOMAP(port);
282         else
283                 p = (volatile unsigned short *)port2adr(port);
284         while (count--) *p = *((__u16 *) addr)++;
285 }
286
287 void hs7751rvoip_outsl(unsigned long port, const void *addr, unsigned long count)
288 {
289         if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
290                 volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
291
292                 while (count--) *p = *((__u32 *) addr)++;
293         } else
294                 maybebadio(outsl, port);
295 }
296
297 unsigned long hs7751rvoip_isa_port2addr(unsigned long offset)
298 {
299         return port2adr(offset);
300 }