blob: 9a39ee963143fa4169bae4e9bb46abaabcf27a68 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $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. */
17int sh_pcic_io_wbase = 0xb8400000;
18int sh_pcic_io_start;
19int sh_pcic_io_stop;
20int sh_pcic_io_type;
21int sh_pcic_io_dummy;
22
23static 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
32static inline volatile __u16 *
33port2adr(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
45static inline int
46shifted_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
59unsigned 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
69unsigned 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
83unsigned 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
93unsigned int se_inl(unsigned long port)
94{
95 maybebadio(inl, port);
96 return 0;
97}
98
99void 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
109void 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
120void 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
129void se_outl(unsigned int value, unsigned long port)
130{
131 maybebadio(outl, port);
132}
133
134void 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
152void 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
160void se_insl(unsigned long port, void *addr, unsigned long count)
161{
162 maybebadio(insl, port);
163}
164
165void 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
183void 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
191void 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. */
199static __u32 sh_isa_memmap[256];
200
201static int
202sh_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
218unsigned long
219se_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}