1/*
2 * arch/sh/boards/se/7343/io.c
3 *
4 * I/O routine for SH-Mobile3AS 7343 SolutionEngine.
5 *
6 */
7#include <linux/kernel.h>
8#include <asm/io.h>
9#include <asm/mach/se7343.h>
10
11#define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a)
12
13struct iop {
14	unsigned long start, end;
15	unsigned long base;
16	struct iop *(*check) (struct iop * p, unsigned long port);
17	unsigned char (*inb) (struct iop * p, unsigned long port);
18	unsigned short (*inw) (struct iop * p, unsigned long port);
19	void (*outb) (struct iop * p, unsigned char value, unsigned long port);
20	void (*outw) (struct iop * p, unsigned short value, unsigned long port);
21};
22
23struct iop *
24simple_check(struct iop *p, unsigned long port)
25{
26	static int count;
27
28	if (count < 100)
29		count++;
30
31	port &= 0xFFFF;
32
33	if ((p->start <= port) && (port <= p->end))
34		return p;
35	else
36		badio(check, port);
37}
38
39struct iop *
40ide_check(struct iop *p, unsigned long port)
41{
42	if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7))
43		return p;
44	return NULL;
45}
46
47unsigned char
48simple_inb(struct iop *p, unsigned long port)
49{
50	return *(unsigned char *) (p->base + port);
51}
52
53unsigned short
54simple_inw(struct iop *p, unsigned long port)
55{
56	return *(unsigned short *) (p->base + port);
57}
58
59void
60simple_outb(struct iop *p, unsigned char value, unsigned long port)
61{
62	*(unsigned char *) (p->base + port) = value;
63}
64
65void
66simple_outw(struct iop *p, unsigned short value, unsigned long port)
67{
68	*(unsigned short *) (p->base + port) = value;
69}
70
71unsigned char
72pcc_inb(struct iop *p, unsigned long port)
73{
74	unsigned long addr = p->base + port + 0x40000;
75	unsigned long v;
76
77	if (port & 1)
78		addr += 0x00400000;
79	v = *(volatile unsigned char *) addr;
80	return v;
81}
82
83void
84pcc_outb(struct iop *p, unsigned char value, unsigned long port)
85{
86	unsigned long addr = p->base + port + 0x40000;
87
88	if (port & 1)
89		addr += 0x00400000;
90	*(volatile unsigned char *) addr = value;
91}
92
93unsigned char
94bad_inb(struct iop *p, unsigned long port)
95{
96	badio(inb, port);
97}
98
99void
100bad_outb(struct iop *p, unsigned char value, unsigned long port)
101{
102	badio(inw, port);
103}
104
105#ifdef CONFIG_SMC91X
106/* MSTLANEX01 LAN at 0xb400:0000 */
107static struct iop laniop = {
108	.start = 0x00,
109	.end = 0x0F,
110	.base = 0x04000000,
111	.check = simple_check,
112	.inb = simple_inb,
113	.inw = simple_inw,
114	.outb = simple_outb,
115	.outw = simple_outw,
116};
117#endif
118
119#ifdef CONFIG_NE2000
120/* NE2000 pc card NIC */
121static struct iop neiop = {
122	.start = 0x280,
123	.end = 0x29f,
124	.base = 0xb0600000 + 0x80,	/* soft 0x280 -> hard 0x300 */
125	.check = simple_check,
126	.inb = pcc_inb,
127	.inw = simple_inw,
128	.outb = pcc_outb,
129	.outw = simple_outw,
130};
131#endif
132
133#ifdef CONFIG_IDE
134/* CF in CF slot */
135static struct iop cfiop = {
136	.base = 0xb0600000,
137	.check = ide_check,
138	.inb = pcc_inb,
139	.inw = simple_inw,
140	.outb = pcc_outb,
141	.outw = simple_outw,
142};
143#endif
144
145static __inline__ struct iop *
146port2iop(unsigned long port)
147{
148	if (0) ;
149#if defined(CONFIG_SMC91X)
150	else if (laniop.check(&laniop, port))
151		return &laniop;
152#endif
153#if defined(CONFIG_NE2000)
154	else if (neiop.check(&neiop, port))
155		return &neiop;
156#endif
157#if defined(CONFIG_IDE)
158	else if (cfiop.check(&cfiop, port))
159		return &cfiop;
160#endif
161	else
162		return NULL;
163}
164
165static inline void
166delay(void)
167{
168	ctrl_inw(0xac000000);
169	ctrl_inw(0xac000000);
170}
171
172unsigned char
173sh7343se_inb(unsigned long port)
174{
175	struct iop *p = port2iop(port);
176	return (p->inb) (p, port);
177}
178
179unsigned char
180sh7343se_inb_p(unsigned long port)
181{
182	unsigned char v = sh7343se_inb(port);
183	delay();
184	return v;
185}
186
187unsigned short
188sh7343se_inw(unsigned long port)
189{
190	struct iop *p = port2iop(port);
191	return (p->inw) (p, port);
192}
193
194unsigned int
195sh7343se_inl(unsigned long port)
196{
197	badio(inl, port);
198}
199
200void
201sh7343se_outb(unsigned char value, unsigned long port)
202{
203	struct iop *p = port2iop(port);
204	(p->outb) (p, value, port);
205}
206
207void
208sh7343se_outb_p(unsigned char value, unsigned long port)
209{
210	sh7343se_outb(value, port);
211	delay();
212}
213
214void
215sh7343se_outw(unsigned short value, unsigned long port)
216{
217	struct iop *p = port2iop(port);
218	(p->outw) (p, value, port);
219}
220
221void
222sh7343se_outl(unsigned int value, unsigned long port)
223{
224	badio(outl, port);
225}
226
227void
228sh7343se_insb(unsigned long port, void *addr, unsigned long count)
229{
230	unsigned char *a = addr;
231	struct iop *p = port2iop(port);
232	while (count--)
233		*a++ = (p->inb) (p, port);
234}
235
236void
237sh7343se_insw(unsigned long port, void *addr, unsigned long count)
238{
239	unsigned short *a = addr;
240	struct iop *p = port2iop(port);
241	while (count--)
242		*a++ = (p->inw) (p, port);
243}
244
245void
246sh7343se_insl(unsigned long port, void *addr, unsigned long count)
247{
248	badio(insl, port);
249}
250
251void
252sh7343se_outsb(unsigned long port, const void *addr, unsigned long count)
253{
254	unsigned char *a = (unsigned char *) addr;
255	struct iop *p = port2iop(port);
256	while (count--)
257		(p->outb) (p, *a++, port);
258}
259
260void
261sh7343se_outsw(unsigned long port, const void *addr, unsigned long count)
262{
263	unsigned short *a = (unsigned short *) addr;
264	struct iop *p = port2iop(port);
265	while (count--)
266		(p->outw) (p, *a++, port);
267}
268
269void
270sh7343se_outsl(unsigned long port, const void *addr, unsigned long count)
271{
272	badio(outsw, port);
273}
274