1/*
2 *  linux/include/asm-arm/arch-rpc/io.h
3 *
4 *  Copyright (C) 1997 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Modifications:
11 *  06-Dec-1997	RMK	Created.
12 */
13#ifndef __ASM_ARM_ARCH_IO_H
14#define __ASM_ARM_ARCH_IO_H
15
16#define IO_SPACE_LIMIT 0xffffffff
17
18/*
19 * GCC is totally crap at loading/storing data.  We try to persuade it
20 * to do the right thing by using these whereever possible instead of
21 * the above.
22 */
23#define __arch_base_getb(b,o)			\
24 ({						\
25	unsigned int v, r = (b);		\
26	__asm__ __volatile__(			\
27		"ldrb	%0, [%1, %2]"		\
28		: "=r" (v)			\
29		: "r" (r), "Ir" (o));		\
30	v;					\
31 })
32
33#define __arch_base_getl(b,o)			\
34 ({						\
35	unsigned int v, r = (b);		\
36	__asm__ __volatile__(			\
37		"ldr	%0, [%1, %2]"		\
38		: "=r" (v)			\
39		: "r" (r), "Ir" (o));		\
40	v;					\
41 })
42
43#define __arch_base_putb(v,b,o)			\
44 ({						\
45	unsigned int r = (b);			\
46	__asm__ __volatile__(			\
47		"strb	%0, [%1, %2]"		\
48		:				\
49		: "r" (v), "r" (r), "Ir" (o));	\
50 })
51
52#define __arch_base_putl(v,b,o)			\
53 ({						\
54	unsigned int r = (b);			\
55	__asm__ __volatile__(			\
56		"str	%0, [%1, %2]"		\
57		:				\
58		: "r" (v), "r" (r), "Ir" (o));	\
59 })
60
61/*
62 * We use two different types of addressing - PC style addresses, and ARM
63 * addresses.  PC style accesses the PC hardware with the normal PC IO
64 * addresses, eg 0x3f8 for serial#1.  ARM addresses are 0x80000000+
65 * and are translated to the start of IO.  Note that all addresses are
66 * shifted left!
67 */
68#define __PORT_PCIO(x)	(!((x) & 0x80000000))
69
70/*
71 * Dynamic IO functions.
72 */
73static inline void __outb (unsigned int value, unsigned int port)
74{
75	unsigned long temp;
76	__asm__ __volatile__(
77	"tst	%2, #0x80000000\n\t"
78	"mov	%0, %4\n\t"
79	"addeq	%0, %0, %3\n\t"
80	"strb	%1, [%0, %2, lsl #2]	@ outb"
81	: "=&r" (temp)
82	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
83	: "cc");
84}
85
86static inline void __outw (unsigned int value, unsigned int port)
87{
88	unsigned long temp;
89	__asm__ __volatile__(
90	"tst	%2, #0x80000000\n\t"
91	"mov	%0, %4\n\t"
92	"addeq	%0, %0, %3\n\t"
93	"str	%1, [%0, %2, lsl #2]	@ outw"
94	: "=&r" (temp)
95	: "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
96	: "cc");
97}
98
99static inline void __outl (unsigned int value, unsigned int port)
100{
101	unsigned long temp;
102	__asm__ __volatile__(
103	"tst	%2, #0x80000000\n\t"
104	"mov	%0, %4\n\t"
105	"addeq	%0, %0, %3\n\t"
106	"str	%1, [%0, %2, lsl #2]	@ outl"
107	: "=&r" (temp)
108	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
109	: "cc");
110}
111
112#define DECLARE_DYN_IN(sz,fnsuffix,instr)					\
113static inline unsigned sz __in##fnsuffix (unsigned int port)		\
114{										\
115	unsigned long temp, value;						\
116	__asm__ __volatile__(							\
117	"tst	%2, #0x80000000\n\t"						\
118	"mov	%0, %4\n\t"							\
119	"addeq	%0, %0, %3\n\t"							\
120	"ldr" instr "	%1, [%0, %2, lsl #2]	@ in" #fnsuffix			\
121	: "=&r" (temp), "=r" (value)						\
122	: "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)		\
123	: "cc");								\
124	return (unsigned sz)value;						\
125}
126
127static inline unsigned int __ioaddr (unsigned int port)			\
128{										\
129	if (__PORT_PCIO(port))							\
130		return (unsigned int)(PCIO_BASE + (port << 2));			\
131	else									\
132		return (unsigned int)(IO_BASE + (port << 2));			\
133}
134
135#define DECLARE_IO(sz,fnsuffix,instr)	\
136	DECLARE_DYN_IN(sz,fnsuffix,instr)
137
138DECLARE_IO(char,b,"b")
139DECLARE_IO(short,w,"")
140DECLARE_IO(int,l,"")
141
142#undef DECLARE_IO
143#undef DECLARE_DYN_IN
144
145/*
146 * Constant address IO functions
147 *
148 * These have to be macros for the 'J' constraint to work -
149 * +/-4096 immediate operand.
150 */
151#define __outbc(value,port)							\
152({										\
153	if (__PORT_PCIO((port)))						\
154		__asm__ __volatile__(						\
155		"strb	%0, [%1, %2]	@ outbc"				\
156		: : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2));		\
157	else									\
158		__asm__ __volatile__(						\
159		"strb	%0, [%1, %2]	@ outbc"				\
160		: : "r" (value), "r" (IO_BASE), "r" ((port) << 2));		\
161})
162
163#define __inbc(port)								\
164({										\
165	unsigned char result;							\
166	if (__PORT_PCIO((port)))						\
167		__asm__ __volatile__(						\
168		"ldrb	%0, [%1, %2]	@ inbc"					\
169		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));		\
170	else									\
171		__asm__ __volatile__(						\
172		"ldrb	%0, [%1, %2]	@ inbc"					\
173		: "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));		\
174	result;									\
175})
176
177#define __outwc(value,port)							\
178({										\
179	unsigned long v = value;						\
180	if (__PORT_PCIO((port)))						\
181		__asm__ __volatile__(						\
182		"str	%0, [%1, %2]	@ outwc"				\
183		: : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2));	\
184	else									\
185		__asm__ __volatile__(						\
186		"str	%0, [%1, %2]	@ outwc"				\
187		: : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2));		\
188})
189
190#define __inwc(port)								\
191({										\
192	unsigned short result;							\
193	if (__PORT_PCIO((port)))						\
194		__asm__ __volatile__(						\
195		"ldr	%0, [%1, %2]	@ inwc"					\
196		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));		\
197	else									\
198		__asm__ __volatile__(						\
199		"ldr	%0, [%1, %2]	@ inwc"					\
200		: "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));		\
201	result & 0xffff;							\
202})
203
204#define __outlc(value,port)							\
205({										\
206	unsigned long v = value;						\
207	if (__PORT_PCIO((port)))						\
208		__asm__ __volatile__(						\
209		"str	%0, [%1, %2]	@ outlc"				\
210		: : "r" (v), "r" (PCIO_BASE), "Jr" ((port) << 2));		\
211	else									\
212		__asm__ __volatile__(						\
213		"str	%0, [%1, %2]	@ outlc"				\
214		: : "r" (v), "r" (IO_BASE), "r" ((port) << 2));			\
215})
216
217#define __inlc(port)								\
218({										\
219	unsigned long result;							\
220	if (__PORT_PCIO((port)))						\
221		__asm__ __volatile__(						\
222		"ldr	%0, [%1, %2]	@ inlc"					\
223		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));		\
224	else									\
225		__asm__ __volatile__(						\
226		"ldr	%0, [%1, %2]	@ inlc"					\
227		: "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));		\
228	result;									\
229})
230
231#define __ioaddrc(port)								\
232	(__PORT_PCIO((port)) ? PCIO_BASE + ((port) << 2) : IO_BASE + ((port) << 2))
233
234#define inb(p)	 	(__builtin_constant_p((p)) ? __inbc(p)    : __inb(p))
235#define inw(p)	 	(__builtin_constant_p((p)) ? __inwc(p)    : __inw(p))
236#define inl(p)	 	(__builtin_constant_p((p)) ? __inlc(p)    : __inl(p))
237#define outb(v,p)	(__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
238#define outw(v,p)	(__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
239#define outl(v,p)	(__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
240#define __ioaddr(p)	(__builtin_constant_p((p)) ? __ioaddr(p)  : __ioaddrc(p))
241/* the following macro is depreciated */
242#define ioaddr(port)			__ioaddr((port))
243
244#define insb(p,d,l)	__raw_readsb(__ioaddr(p),d,l)
245#define insw(p,d,l)	__raw_readsw(__ioaddr(p),d,l)
246
247#define outsb(p,d,l)	__raw_writesb(__ioaddr(p),d,l)
248#define outsw(p,d,l)	__raw_writesw(__ioaddr(p),d,l)
249
250#define iomem_valid_addr(o,s)	(1)
251#define iomem_to_phys(a)	(a)
252
253#endif
254