85511576d414c3baf909323439aa1797a111b2ef
[linux-2.6.git] / arch / sh / boards / renesas / systemh / io.c
1 /*
2  * linux/arch/sh/boards/systemh/io.c
3  *
4  * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
5  * Based largely on io_se.c.
6  *
7  * I/O routine for Hitachi 7751 Systemh.
8  *
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/types.h>
13 #include <asm/systemh/7751systemh.h>
14 #include <asm/addrspace.h>
15 #include <asm/io.h>
16
17 #include <linux/pci.h>
18 #include "../../../drivers/pci/pci-sh7751.h"
19
20 /*
21  * The 7751 SystemH Engine uses the built-in PCI controller (PCIC)
22  * of the 7751 processor, and has a SuperIO accessible on its memory
23  * bus.
24  */
25
26 #define PCIIOBR         (volatile long *)PCI_REG(SH7751_PCIIOBR)
27 #define PCIMBR          (volatile long *)PCI_REG(SH7751_PCIMBR)
28 #define PCI_IO_AREA     SH7751_PCI_IO_BASE
29 #define PCI_MEM_AREA    SH7751_PCI_CONFIG_BASE
30
31 #define PCI_IOMAP(adr)  (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
32 #define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area
33                                                 of smc lan chip*/
34
35 #define maybebadio(name,port) \
36   printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
37          #name, (port), (__u32) __builtin_return_address(0))
38
39 static inline void delay(void)
40 {
41         ctrl_inw(0xa0000000);
42 }
43
44 static inline volatile __u16 *
45 port2adr(unsigned int port)
46 {
47         if (port >= 0x2000)
48                 return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
49 #if 0
50         else
51                 return (volatile __u16 *) (PA_SUPERIO + (port << 1));
52 #endif
53         maybebadio(name,(unsigned long)port);
54         return (volatile __u16*)port;
55 }
56
57 /* In case someone configures the kernel w/o PCI support: in that */
58 /* scenario, don't ever bother to check for PCI-window addresses */
59
60 /* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
61 #if defined(CONFIG_PCI)
62 #define CHECK_SH7751_PCIIO(port) \
63   ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
64 #else
65 #define CHECK_SH7751_PCIIO(port) (0)
66 #endif
67
68 /*
69  * General outline: remap really low stuff [eventually] to SuperIO,
70  * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
71  * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
72  * should be way beyond the window, and is used  w/o translation for
73  * compatibility.
74  */
75 unsigned char sh7751systemh_inb(unsigned long port)
76 {
77         if (PXSEG(port))
78                 return *(volatile unsigned char *)port;
79         else if (CHECK_SH7751_PCIIO(port))
80                 return *(volatile unsigned char *)PCI_IOMAP(port);
81         else if (port <= 0x3F1)
82                 return *(volatile unsigned char *)ETHER_IOMAP(port);
83         else
84                 return (*port2adr(port))&0xff;
85 }
86
87 unsigned char sh7751systemh_inb_p(unsigned long port)
88 {
89         unsigned char v;
90
91         if (PXSEG(port))
92                 v = *(volatile unsigned char *)port;
93         else if (CHECK_SH7751_PCIIO(port))
94                 v = *(volatile unsigned char *)PCI_IOMAP(port);
95         else if (port <= 0x3F1)
96                 v = *(volatile unsigned char *)ETHER_IOMAP(port);
97         else
98                 v = (*port2adr(port))&0xff;
99         delay();
100         return v;
101 }
102
103 unsigned short sh7751systemh_inw(unsigned long port)
104 {
105         if (PXSEG(port))
106                 return *(volatile unsigned short *)port;
107         else if (CHECK_SH7751_PCIIO(port))
108                 return *(volatile unsigned short *)PCI_IOMAP(port);
109         else if (port >= 0x2000)
110                 return *port2adr(port);
111         else if (port <= 0x3F1)
112                 return *(volatile unsigned int *)ETHER_IOMAP(port);
113         else
114                 maybebadio(inw, port);
115         return 0;
116 }
117
118 unsigned int sh7751systemh_inl(unsigned long port)
119 {
120         if (PXSEG(port))
121                 return *(volatile unsigned long *)port;
122         else if (CHECK_SH7751_PCIIO(port))
123                 return *(volatile unsigned int *)PCI_IOMAP(port);
124         else if (port >= 0x2000)
125                 return *port2adr(port);
126         else if (port <= 0x3F1)
127                 return *(volatile unsigned int *)ETHER_IOMAP(port);
128         else
129                 maybebadio(inl, port);
130         return 0;
131 }
132
133 void sh7751systemh_outb(unsigned char value, unsigned long port)
134 {
135
136         if (PXSEG(port))
137                 *(volatile unsigned char *)port = value;
138         else if (CHECK_SH7751_PCIIO(port))
139                 *((unsigned char*)PCI_IOMAP(port)) = value;
140         else if (port <= 0x3F1)
141                 *(volatile unsigned char *)ETHER_IOMAP(port) = value;
142         else
143                 *(port2adr(port)) = value;
144 }
145
146 void sh7751systemh_outb_p(unsigned char value, unsigned long port)
147 {
148         if (PXSEG(port))
149                 *(volatile unsigned char *)port = value;
150         else if (CHECK_SH7751_PCIIO(port))
151                 *((unsigned char*)PCI_IOMAP(port)) = value;
152         else if (port <= 0x3F1)
153                 *(volatile unsigned char *)ETHER_IOMAP(port) = value;
154         else
155                 *(port2adr(port)) = value;
156         delay();
157 }
158
159 void sh7751systemh_outw(unsigned short value, unsigned long port)
160 {
161         if (PXSEG(port))
162                 *(volatile unsigned short *)port = value;
163         else if (CHECK_SH7751_PCIIO(port))
164                 *((unsigned short *)PCI_IOMAP(port)) = value;
165         else if (port >= 0x2000)
166                 *port2adr(port) = value;
167         else if (port <= 0x3F1)
168                 *(volatile unsigned short *)ETHER_IOMAP(port) = value;
169         else
170                 maybebadio(outw, port);
171 }
172
173 void sh7751systemh_outl(unsigned int value, unsigned long port)
174 {
175         if (PXSEG(port))
176                 *(volatile unsigned long *)port = value;
177         else if (CHECK_SH7751_PCIIO(port))
178                 *((unsigned long*)PCI_IOMAP(port)) = value;
179         else
180                 maybebadio(outl, port);
181 }
182
183 void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count)
184 {
185         unsigned char *p = addr;
186         while (count--) *p++ = sh7751systemh_inb(port);
187 }
188
189 void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count)
190 {
191         unsigned short *p = addr;
192         while (count--) *p++ = sh7751systemh_inw(port);
193 }
194
195 void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count)
196 {
197         maybebadio(insl, port);
198 }
199
200 void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count)
201 {
202         unsigned char *p = (unsigned char*)addr;
203         while (count--) sh7751systemh_outb(*p++, port);
204 }
205
206 void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count)
207 {
208         unsigned short *p = (unsigned short*)addr;
209         while (count--) sh7751systemh_outw(*p++, port);
210 }
211
212 void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count)
213 {
214         maybebadio(outsw, port);
215 }
216
217 /* For read/write calls, just copy generic (pass-thru); PCIMBR is  */
218 /* already set up.  For a larger memory space, these would need to */
219 /* reset PCIMBR as needed on a per-call basis...                   */
220
221 unsigned char sh7751systemh_readb(unsigned long addr)
222 {
223         return *(volatile unsigned char*)addr;
224 }
225
226 unsigned short sh7751systemh_readw(unsigned long addr)
227 {
228         return *(volatile unsigned short*)addr;
229 }
230
231 unsigned int sh7751systemh_readl(unsigned long addr)
232 {
233         return *(volatile unsigned long*)addr;
234 }
235
236 void sh7751systemh_writeb(unsigned char b, unsigned long addr)
237 {
238         *(volatile unsigned char*)addr = b;
239 }
240
241 void sh7751systemh_writew(unsigned short b, unsigned long addr)
242 {
243         *(volatile unsigned short*)addr = b;
244 }
245
246 void sh7751systemh_writel(unsigned int b, unsigned long addr)
247 {
248         *(volatile unsigned long*)addr = b;
249 }
250
251 \f
252
253 /* Map ISA bus address to the real address. Only for PCMCIA.  */
254
255 /* ISA page descriptor.  */
256 static __u32 sh_isa_memmap[256];
257
258 #if 0
259 static int
260 sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
261 {
262         int idx;
263
264         if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
265                 return -1;
266
267         idx = start >> 12;
268         sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
269         printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
270                start, length, offset, idx, sh_isa_memmap[idx]);
271         return 0;
272 }
273 #endif
274
275 unsigned long
276 sh7751systemh_isa_port2addr(unsigned long offset)
277 {
278         int idx;
279
280         idx = (offset >> 12) & 0xff;
281         offset &= 0xfff;
282         return sh_isa_memmap[idx] + offset;
283 }