• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  linux/arch/arm/mach-ebsa110/isamem.c
4  *
5  *  Copyright (C) 2001 Russell King
6  *
7  * Perform "ISA" memory and IO accesses.  The EBSA110 has some "peculiarities"
8  * in the way it handles accesses to odd IO ports on 16-bit devices.  These
9  * devices have their D0-D15 lines connected to the processors D0-D15 lines.
10  * Since they expect all byte IO operations to be performed on D0-D7, and the
11  * StrongARM expects to transfer the byte to these odd addresses on D8-D15,
12  * we must use a trick to get the required behaviour.
13  *
14  * The trick employed here is to use long word stores to odd address -1.  The
15  * glue logic picks this up as a "trick" access, and asserts the LSB of the
16  * peripherals address bus, thereby accessing the odd IO port.  Meanwhile, the
17  * StrongARM transfers its data on D0-D7 as expected.
18  *
19  * Things get more interesting on the pass-1 EBSA110 - the PCMCIA controller
20  * wiring was screwed in such a way that it had limited memory space access.
21  * Luckily, the work-around for this is not too horrible.  See
22  * __isamem_convert_addr for the details.
23  */
24 #include <linux/module.h>
25 #include <linux/kernel.h>
26 #include <linux/types.h>
27 #include <linux/io.h>
28 
29 #include <mach/hardware.h>
30 #include <asm/page.h>
31 
__isamem_convert_addr(const volatile void __iomem * addr)32 static void __iomem *__isamem_convert_addr(const volatile void __iomem *addr)
33 {
34 	u32 ret, a = (u32 __force) addr;
35 
36 	/*
37 	 * The PCMCIA controller is wired up as follows:
38 	 *        +---------+---------+---------+---------+---------+---------+
39 	 * PCMCIA | 2 2 2 2 | 1 1 1 1 | 1 1 1 1 | 1 1     |         |         |
40 	 *        | 3 2 1 0 | 9 8 7 6 | 5 4 3 2 | 1 0 9 8 | 7 6 5 4 | 3 2 1 0 |
41 	 *        +---------+---------+---------+---------+---------+---------+
42 	 *  CPU   | 2 2 2 2 | 2 1 1 1 | 1 1 1 1 | 1 1 1   |         |         |
43 	 *        | 4 3 2 1 | 0 9 9 8 | 7 6 5 4 | 3 2 0 9 | 8 7 6 5 | 4 3 2 x |
44 	 *        +---------+---------+---------+---------+---------+---------+
45 	 *
46 	 * This means that we can access PCMCIA regions as follows:
47 	 *	0x*10000 -> 0x*1ffff
48 	 *	0x*70000 -> 0x*7ffff
49 	 *	0x*90000 -> 0x*9ffff
50 	 *	0x*f0000 -> 0x*fffff
51 	 */
52 	ret  = (a & 0xf803fe) << 1;
53 	ret |= (a & 0x03fc00) << 2;
54 
55 	ret += 0xe8000000;
56 
57 	if ((a & 0x20000) == (a & 0x40000) >> 1)
58 		return (void __iomem *)ret;
59 
60 	BUG();
61 	return NULL;
62 }
63 
64 /*
65  * read[bwl] and write[bwl]
66  */
__readb(const volatile void __iomem * addr)67 u8 __readb(const volatile void __iomem *addr)
68 {
69 	void __iomem *a = __isamem_convert_addr(addr);
70 	u32 ret;
71 
72 	if ((unsigned long)addr & 1)
73 		ret = __raw_readl(a);
74 	else
75 		ret = __raw_readb(a);
76 	return ret;
77 }
78 
__readw(const volatile void __iomem * addr)79 u16 __readw(const volatile void __iomem *addr)
80 {
81 	void __iomem *a = __isamem_convert_addr(addr);
82 
83 	if ((unsigned long)addr & 1)
84 		BUG();
85 
86 	return __raw_readw(a);
87 }
88 
__readl(const volatile void __iomem * addr)89 u32 __readl(const volatile void __iomem *addr)
90 {
91 	void __iomem *a = __isamem_convert_addr(addr);
92 	u32 ret;
93 
94 	if ((unsigned long)addr & 3)
95 		BUG();
96 
97 	ret = __raw_readw(a);
98 	ret |= __raw_readw(a + 4) << 16;
99 	return ret;
100 }
101 
102 EXPORT_SYMBOL(__readb);
103 EXPORT_SYMBOL(__readw);
104 EXPORT_SYMBOL(__readl);
105 
readsw(const volatile void __iomem * addr,void * data,int len)106 void readsw(const volatile void __iomem *addr, void *data, int len)
107 {
108 	void __iomem *a = __isamem_convert_addr(addr);
109 
110 	BUG_ON((unsigned long)addr & 1);
111 
112 	__raw_readsw(a, data, len);
113 }
114 EXPORT_SYMBOL(readsw);
115 
readsl(const volatile void __iomem * addr,void * data,int len)116 void readsl(const volatile void __iomem *addr, void *data, int len)
117 {
118 	void __iomem *a = __isamem_convert_addr(addr);
119 
120 	BUG_ON((unsigned long)addr & 3);
121 
122 	__raw_readsl(a, data, len);
123 }
124 EXPORT_SYMBOL(readsl);
125 
__writeb(u8 val,volatile void __iomem * addr)126 void __writeb(u8 val, volatile void __iomem *addr)
127 {
128 	void __iomem *a = __isamem_convert_addr(addr);
129 
130 	if ((unsigned long)addr & 1)
131 		__raw_writel(val, a);
132 	else
133 		__raw_writeb(val, a);
134 }
135 
__writew(u16 val,volatile void __iomem * addr)136 void __writew(u16 val, volatile void __iomem *addr)
137 {
138 	void __iomem *a = __isamem_convert_addr(addr);
139 
140 	if ((unsigned long)addr & 1)
141 		BUG();
142 
143 	__raw_writew(val, a);
144 }
145 
__writel(u32 val,volatile void __iomem * addr)146 void __writel(u32 val, volatile void __iomem *addr)
147 {
148 	void __iomem *a = __isamem_convert_addr(addr);
149 
150 	if ((unsigned long)addr & 3)
151 		BUG();
152 
153 	__raw_writew(val, a);
154 	__raw_writew(val >> 16, a + 4);
155 }
156 
157 EXPORT_SYMBOL(__writeb);
158 EXPORT_SYMBOL(__writew);
159 EXPORT_SYMBOL(__writel);
160 
writesw(volatile void __iomem * addr,const void * data,int len)161 void writesw(volatile void __iomem *addr, const void *data, int len)
162 {
163 	void __iomem *a = __isamem_convert_addr(addr);
164 
165 	BUG_ON((unsigned long)addr & 1);
166 
167 	__raw_writesw(a, data, len);
168 }
169 EXPORT_SYMBOL(writesw);
170 
writesl(volatile void __iomem * addr,const void * data,int len)171 void writesl(volatile void __iomem *addr, const void *data, int len)
172 {
173 	void __iomem *a = __isamem_convert_addr(addr);
174 
175 	BUG_ON((unsigned long)addr & 3);
176 
177 	__raw_writesl(a, data, len);
178 }
179 EXPORT_SYMBOL(writesl);
180 
181 /*
182  * The EBSA110 has a weird "ISA IO" region:
183  *
184  * Region 0 (addr = 0xf0000000 + io << 2)
185  * --------------------------------------------------------
186  * Physical region	IO region
187  * f0000fe0 - f0000ffc	3f8 - 3ff  ttyS0
188  * f0000e60 - f0000e64	398 - 399
189  * f0000de0 - f0000dfc	378 - 37f  lp0
190  * f0000be0 - f0000bfc	2f8 - 2ff  ttyS1
191  *
192  * Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1))
193  * --------------------------------------------------------
194  * Physical region	IO region
195  * f00014f1             a79        pnp write data
196  * f00007c0 - f00007c1	3e0 - 3e1  pcmcia
197  * f00004f1		279        pnp address
198  * f0000440 - f000046c  220 - 236  eth0
199  * f0000405		203        pnp read data
200  */
201 #define SUPERIO_PORT(p) \
202 	(((p) >> 3) == (0x3f8 >> 3) || \
203 	 ((p) >> 3) == (0x2f8 >> 3) || \
204 	 ((p) >> 3) == (0x378 >> 3))
205 
206 /*
207  * We're addressing an 8 or 16-bit peripheral which tranfers
208  * odd addresses on the low ISA byte lane.
209  */
__inb8(unsigned int port)210 u8 __inb8(unsigned int port)
211 {
212 	u32 ret;
213 
214 	/*
215 	 * The SuperIO registers use sane addressing techniques...
216 	 */
217 	if (SUPERIO_PORT(port))
218 		ret = __raw_readb((void __iomem *)ISAIO_BASE + (port << 2));
219 	else {
220 		void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);
221 
222 		/*
223 		 * Shame nothing else does
224 		 */
225 		if (port & 1)
226 			ret = __raw_readl(a);
227 		else
228 			ret = __raw_readb(a);
229 	}
230 	return ret;
231 }
232 
233 /*
234  * We're addressing a 16-bit peripheral which transfers odd
235  * addresses on the high ISA byte lane.
236  */
__inb16(unsigned int port)237 u8 __inb16(unsigned int port)
238 {
239 	unsigned int offset;
240 
241 	/*
242 	 * The SuperIO registers use sane addressing techniques...
243 	 */
244 	if (SUPERIO_PORT(port))
245 		offset = port << 2;
246 	else
247 		offset = (port & ~1) << 1 | (port & 1);
248 
249 	return __raw_readb((void __iomem *)ISAIO_BASE + offset);
250 }
251 
__inw(unsigned int port)252 u16 __inw(unsigned int port)
253 {
254 	unsigned int offset;
255 
256 	/*
257 	 * The SuperIO registers use sane addressing techniques...
258 	 */
259 	if (SUPERIO_PORT(port))
260 		offset = port << 2;
261 	else {
262 		offset = port << 1;
263 		BUG_ON(port & 1);
264 	}
265 	return __raw_readw((void __iomem *)ISAIO_BASE + offset);
266 }
267 
268 /*
269  * Fake a 32-bit read with two 16-bit reads.  Needed for 3c589.
270  */
__inl(unsigned int port)271 u32 __inl(unsigned int port)
272 {
273 	void __iomem *a;
274 
275 	if (SUPERIO_PORT(port) || port & 3)
276 		BUG();
277 
278 	a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);
279 
280 	return __raw_readw(a) | __raw_readw(a + 4) << 16;
281 }
282 
283 EXPORT_SYMBOL(__inb8);
284 EXPORT_SYMBOL(__inb16);
285 EXPORT_SYMBOL(__inw);
286 EXPORT_SYMBOL(__inl);
287 
__outb8(u8 val,unsigned int port)288 void __outb8(u8 val, unsigned int port)
289 {
290 	/*
291 	 * The SuperIO registers use sane addressing techniques...
292 	 */
293 	if (SUPERIO_PORT(port))
294 		__raw_writeb(val, (void __iomem *)ISAIO_BASE + (port << 2));
295 	else {
296 		void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1);
297 
298 		/*
299 		 * Shame nothing else does
300 		 */
301 		if (port & 1)
302 			__raw_writel(val, a);
303 		else
304 			__raw_writeb(val, a);
305 	}
306 }
307 
__outb16(u8 val,unsigned int port)308 void __outb16(u8 val, unsigned int port)
309 {
310 	unsigned int offset;
311 
312 	/*
313 	 * The SuperIO registers use sane addressing techniques...
314 	 */
315 	if (SUPERIO_PORT(port))
316 		offset = port << 2;
317 	else
318 		offset = (port & ~1) << 1 | (port & 1);
319 
320 	__raw_writeb(val, (void __iomem *)ISAIO_BASE + offset);
321 }
322 
__outw(u16 val,unsigned int port)323 void __outw(u16 val, unsigned int port)
324 {
325 	unsigned int offset;
326 
327 	/*
328 	 * The SuperIO registers use sane addressing techniques...
329 	 */
330 	if (SUPERIO_PORT(port))
331 		offset = port << 2;
332 	else {
333 		offset = port << 1;
334 		BUG_ON(port & 1);
335 	}
336 	__raw_writew(val, (void __iomem *)ISAIO_BASE + offset);
337 }
338 
__outl(u32 val,unsigned int port)339 void __outl(u32 val, unsigned int port)
340 {
341 	BUG();
342 }
343 
344 EXPORT_SYMBOL(__outb8);
345 EXPORT_SYMBOL(__outb16);
346 EXPORT_SYMBOL(__outw);
347 EXPORT_SYMBOL(__outl);
348 
outsb(unsigned int port,const void * from,int len)349 void outsb(unsigned int port, const void *from, int len)
350 {
351 	u32 off;
352 
353 	if (SUPERIO_PORT(port))
354 		off = port << 2;
355 	else {
356 		off = (port & ~1) << 1;
357 		if (port & 1)
358 			BUG();
359 	}
360 
361 	__raw_writesb((void __iomem *)ISAIO_BASE + off, from, len);
362 }
363 
insb(unsigned int port,void * from,int len)364 void insb(unsigned int port, void *from, int len)
365 {
366 	u32 off;
367 
368 	if (SUPERIO_PORT(port))
369 		off = port << 2;
370 	else {
371 		off = (port & ~1) << 1;
372 		if (port & 1)
373 			BUG();
374 	}
375 
376 	__raw_readsb((void __iomem *)ISAIO_BASE + off, from, len);
377 }
378 
379 EXPORT_SYMBOL(outsb);
380 EXPORT_SYMBOL(insb);
381 
outsw(unsigned int port,const void * from,int len)382 void outsw(unsigned int port, const void *from, int len)
383 {
384 	u32 off;
385 
386 	if (SUPERIO_PORT(port))
387 		off = port << 2;
388 	else {
389 		off = (port & ~1) << 1;
390 		if (port & 1)
391 			BUG();
392 	}
393 
394 	__raw_writesw((void __iomem *)ISAIO_BASE + off, from, len);
395 }
396 
insw(unsigned int port,void * from,int len)397 void insw(unsigned int port, void *from, int len)
398 {
399 	u32 off;
400 
401 	if (SUPERIO_PORT(port))
402 		off = port << 2;
403 	else {
404 		off = (port & ~1) << 1;
405 		if (port & 1)
406 			BUG();
407 	}
408 
409 	__raw_readsw((void __iomem *)ISAIO_BASE + off, from, len);
410 }
411 
412 EXPORT_SYMBOL(outsw);
413 EXPORT_SYMBOL(insw);
414 
415 /*
416  * We implement these as 16-bit insw/outsw, mainly for
417  * 3c589 cards.
418  */
outsl(unsigned int port,const void * from,int len)419 void outsl(unsigned int port, const void *from, int len)
420 {
421 	u32 off = port << 1;
422 
423 	if (SUPERIO_PORT(port) || port & 3)
424 		BUG();
425 
426 	__raw_writesw((void __iomem *)ISAIO_BASE + off, from, len << 1);
427 }
428 
insl(unsigned int port,void * from,int len)429 void insl(unsigned int port, void *from, int len)
430 {
431 	u32 off = port << 1;
432 
433 	if (SUPERIO_PORT(port) || port & 3)
434 		BUG();
435 
436 	__raw_readsw((void __iomem *)ISAIO_BASE + off, from, len << 1);
437 }
438 
439 EXPORT_SYMBOL(outsl);
440 EXPORT_SYMBOL(insl);
441