http://www.usr.com/support/gpl/USR9107_release1.1.tar.gz
[bcm963xx.git] / kernel / linux / arch / sh / boards / se / 770x / io.c
1 /* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $
2  *
3  * linux/arch/sh/kernel/io_se.c
4  *
5  * Copyright (C) 2000  Kazumoto Kojima
6  *
7  * I/O routine for Hitachi SolutionEngine.
8  *
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/types.h>
13 #include <asm/io.h>
14 #include <asm/se/se.h>
15
16 /* SH pcmcia io window base, start and end.  */
17 int sh_pcic_io_wbase = 0xb8400000;
18 int sh_pcic_io_start;
19 int sh_pcic_io_stop;
20 int sh_pcic_io_type;
21 int sh_pcic_io_dummy;
22
23 static inline void delay(void)
24 {
25         ctrl_inw(0xa0000000);
26 }
27
28 /* MS7750 requires special versions of in*, out* routines, since
29    PC-like io ports are located at upper half byte of 16-bit word which
30    can be accessed only with 16-bit wide.  */
31
32 static inline volatile __u16 *
33 port2adr(unsigned int port)
34 {
35         if (port >= 0x2000)
36                 return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
37         else if (port >= 0x1000)
38                 return (volatile __u16 *) (PA_83902 + (port << 1));
39         else if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
40                 return (volatile __u16 *) (sh_pcic_io_wbase + (port &~ 1));
41         else
42                 return (volatile __u16 *) (PA_SUPERIO + (port << 1));
43 }
44
45 static inline int
46 shifted_port(unsigned long port)
47 {
48         /* For IDE registers, value is not shifted */
49         if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
50                 return 0;
51         else
52                 return 1;
53 }
54
55 #define maybebadio(name,port) \
56   printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
57          #name, (port), (__u32) __builtin_return_address(0))
58
59 unsigned char se_inb(unsigned long port)
60 {
61         if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
62                 return *(__u8 *) (sh_pcic_io_wbase + 0x40000 + port); 
63         else if (shifted_port(port))
64                 return (*port2adr(port) >> 8); 
65         else
66                 return (*port2adr(port))&0xff; 
67 }
68
69 unsigned char se_inb_p(unsigned long port)
70 {
71         unsigned long v;
72
73         if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
74                 v = *(__u8 *) (sh_pcic_io_wbase + 0x40000 + port); 
75         else if (shifted_port(port))
76                 v = (*port2adr(port) >> 8); 
77         else
78                 v = (*port2adr(port))&0xff; 
79         delay();
80         return v;
81 }
82
83 unsigned short se_inw(unsigned long port)
84 {
85         if (port >= 0x2000 ||
86             (sh_pcic_io_start <= port && port <= sh_pcic_io_stop))
87                 return *port2adr(port);
88         else
89                 maybebadio(inw, port);
90         return 0;
91 }
92
93 unsigned int se_inl(unsigned long port)
94 {
95         maybebadio(inl, port);
96         return 0;
97 }
98
99 void se_outb(unsigned char value, unsigned long port)
100 {
101         if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
102                 *(__u8 *)(sh_pcic_io_wbase + port) = value; 
103         else if (shifted_port(port))
104                 *(port2adr(port)) = value << 8;
105         else
106                 *(port2adr(port)) = value;
107 }
108
109 void se_outb_p(unsigned char value, unsigned long port)
110 {
111         if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
112                 *(__u8 *)(sh_pcic_io_wbase + port) = value; 
113         else if (shifted_port(port))
114                 *(port2adr(port)) = value << 8;
115         else
116                 *(port2adr(port)) = value;
117         delay();
118 }
119
120 void se_outw(unsigned short value, unsigned long port)
121 {
122         if (port >= 0x2000 ||
123             (sh_pcic_io_start <= port && port <= sh_pcic_io_stop))
124                 *port2adr(port) = value;
125         else
126                 maybebadio(outw, port);
127 }
128
129 void se_outl(unsigned int value, unsigned long port)
130 {
131         maybebadio(outl, port);
132 }
133
134 void se_insb(unsigned long port, void *addr, unsigned long count)
135 {
136         volatile __u16 *p = port2adr(port);
137         __u8 *ap = addr;
138
139         if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) {
140                 volatile __u8 *bp = (__u8 *) (sh_pcic_io_wbase + 0x40000 + port); 
141                 while (count--)
142                         *ap++ = *bp;
143         } else if (shifted_port(port)) {
144                 while (count--)
145                         *ap++ = *p >> 8;
146         } else {
147                 while (count--)
148                         *ap++ = *p;
149         }
150 }
151
152 void se_insw(unsigned long port, void *addr, unsigned long count)
153 {
154         volatile __u16 *p = port2adr(port);
155         __u16 *ap = addr;
156         while (count--)
157                 *ap++ = *p;
158 }
159
160 void se_insl(unsigned long port, void *addr, unsigned long count)
161 {
162         maybebadio(insl, port);
163 }
164
165 void se_outsb(unsigned long port, const void *addr, unsigned long count)
166 {
167         volatile __u16 *p = port2adr(port);
168         const __u8 *ap = addr;
169
170         if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) {
171                 volatile __u8 *bp = (__u8 *) (sh_pcic_io_wbase + port); 
172                 while (count--)
173                         *bp = *ap++;
174         } else if (shifted_port(port)) {
175                 while (count--)
176                         *p = *ap++ << 8;
177         } else {
178                 while (count--)
179                         *p = *ap++;
180         }
181 }
182
183 void se_outsw(unsigned long port, const void *addr, unsigned long count)
184 {
185         volatile __u16 *p = port2adr(port);
186         const __u16 *ap = addr;
187         while (count--)
188                 *p = *ap++;
189 }
190
191 void se_outsl(unsigned long port, const void *addr, unsigned long count)
192 {
193         maybebadio(outsw, port);
194 }
195
196 /* Map ISA bus address to the real address. Only for PCMCIA.  */
197
198 /* ISA page descriptor.  */
199 static __u32 sh_isa_memmap[256];
200
201 static int
202 sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
203 {
204         int idx;
205
206         if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
207                 return -1;
208
209         idx = start >> 12;
210         sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
211 #if 0
212         printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
213                start, length, offset, idx, sh_isa_memmap[idx]);
214 #endif
215         return 0;
216 }
217
218 unsigned long
219 se_isa_port2addr(unsigned long offset)
220 {
221         int idx;
222
223         idx = (offset >> 12) & 0xff;
224         offset &= 0xfff;
225         return sh_isa_memmap[idx] + offset;
226 }