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