summaryrefslogtreecommitdiffstats
path: root/include/asm-arm/arch-ixp2000/io.h
blob: 7fbcdf9931eecfd7ac2d7e088a5fd56befee8616 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/*
 * linux/include/asm-arm/arch-ixp2000/io.h
 *
 * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
 * Maintainer: Deepak Saxena <dsaxena@plexity.net>
 *
 * Copyright (C) 2002  Intel Corp.
 * Copyrgiht (C) 2003-2004 MontaVista Software, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H

#include <asm/hardware.h>

#define IO_SPACE_LIMIT		0xffffffff
#define __mem_pci(a)		(a)

/*
 * The A? revisions of the IXP2000s assert byte lanes for PCI I/O
 * transactions the other way round (MEM transactions don't have this
 * issue), so if we want to support those models, we need to override
 * the standard I/O functions.
 *
 * B0 and later have a bit that can be set to 1 to get the proper
 * behavior for I/O transactions, which then allows us to use the
 * standard I/O functions.  This is what we do if the user does not
 * explicitly ask for support for pre-B0.
 */
#ifdef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
#define ___io(p)		((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))

#define alignb(addr)		(void __iomem *)((unsigned long)(addr) ^ 3)
#define alignw(addr)		(void __iomem *)((unsigned long)(addr) ^ 2)

#define outb(v,p)		__raw_writeb((v),alignb(___io(p)))
#define outw(v,p)		__raw_writew((v),alignw(___io(p)))
#define outl(v,p)		__raw_writel((v),___io(p))

#define inb(p)		({ unsigned int __v = __raw_readb(alignb(___io(p))); __v; })
#define inw(p)		\
	({ unsigned int __v = (__raw_readw(alignw(___io(p)))); __v; })
#define inl(p)		\
	({ unsigned int __v = (__raw_readl(___io(p))); __v; })

#define outsb(p,d,l)		__raw_writesb(alignb(___io(p)),d,l)
#define outsw(p,d,l)		__raw_writesw(alignw(___io(p)),d,l)
#define outsl(p,d,l)		__raw_writesl(___io(p),d,l)

#define insb(p,d,l)		__raw_readsb(alignb(___io(p)),d,l)
#define insw(p,d,l)		__raw_readsw(alignw(___io(p)),d,l)
#define insl(p,d,l)		__raw_readsl(___io(p),d,l)

#define __is_io_address(p)	((((unsigned long)(p)) & ~(IXP2000_PCI_IO_SIZE - 1)) == IXP2000_PCI_IO_VIRT_BASE)

#define ioread8(p)						\
	({							\
		unsigned int __v;				\
								\
		if (__is_io_address(p)) {			\
			__v = __raw_readb(alignb(p));		\
		} else {					\
			__v = __raw_readb(p);			\
		}						\
								\
		__v;						\
	})							\

#define ioread16(p)						\
	({							\
		unsigned int __v;				\
								\
		if (__is_io_address(p)) {			\
			__v = __raw_readw(alignw(p));		\
		} else {					\
			__v = le16_to_cpu(__raw_readw(p));	\
		}						\
								\
		__v;						\
	})

#define ioread32(p)						\
	({							\
		unsigned int __v;				\
								\
		if (__is_io_address(p)) {			\
			__v = __raw_readl(p);			\
		} else {					\
			__v = le32_to_cpu(__raw_readl(p));	\
		}						\
								\
		 __v;						\
	})

#define iowrite8(v,p)						\
	({							\
		if (__is_io_address(p)) {			\
			__raw_writeb((v), alignb(p));		\
		} else {					\
			__raw_writeb((v), p);			\
		}						\
	})

#define iowrite16(v,p)						\
	({							\
		if (__is_io_address(p)) {			\
			__raw_writew((v), alignw(p));		\
		} else {					\
			__raw_writew(cpu_to_le16(v), p);	\
		}						\
	})

#define iowrite32(v,p)						\
	({							\
		if (__is_io_address(p)) {			\
			__raw_writel((v), p);			\
		} else {					\
			__raw_writel(cpu_to_le32(v), p);	\
		}						\
	})

#define ioport_map(port, nr)	___io(port)

#define ioport_unmap(addr)
#else
#define __io(p)			((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
#endif


#ifdef CONFIG_ARCH_IXDP2X01
/*
 * This is an ugly hack but the CS8900 on the 2x01's does not sit in any sort
 * of "I/O space" and is just direct mapped into a 32-bit-only addressable
 * bus. The address space for this bus is such that we can't really easily
 * make it contiguous to the PCI I/O address range, and it also does not
 * need swapping like PCI addresses do (IXDP2x01 is a BE platform).
 * B/C of this we can't use the standard in/out functions and need to
 * runtime check if the incoming address is a PCI address or for
 * the CS89x0.
 */
#undef inw
#undef outw
#undef insw
#undef outsw

#include <asm/mach-types.h>

static inline void insw(u32 ptr, void *buf, int length)
{
	register volatile u32 *port = (volatile u32 *)ptr;

	/*
	 * Is this cycle meant for the CS8900?
	 */
	if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
		(((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) &&
		 ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) {
		u8 *buf8 = (u8*)buf;
		register u32 tmp32;

		do {
			tmp32 = *port;
			*buf8++ = (u8)tmp32;
			*buf8++ = (u8)(tmp32 >> 8);
		} while(--length);

		return;
	}

	__raw_readsw(alignw(___io(ptr)),buf,length);
}

static inline void outsw(u32 ptr, void *buf, int length)
{
	register volatile u32 *port = (volatile u32 *)ptr;

	/*
	 * Is this cycle meant for the CS8900?
	 */
	if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
		(((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) &&
		 ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) {
		register u32 tmp32;
		u8 *buf8 = (u8*)buf;
		do {
			tmp32 = *buf8++;
			tmp32 |= (*buf8++) << 8;
			*port = tmp32;
		} while(--length);
		return;
	}

	__raw_writesw(alignw(___io(ptr)),buf,length);
}


static inline u16 inw(u32 ptr)
{
	register volatile u32 *port = (volatile u32 *)ptr;

	/*
	 * Is this cycle meant for the CS8900?
	 */
	if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
		(((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) &&
		 ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) {
		return (u16)(*port);  
	}

	return __raw_readw(alignw(___io(ptr)));
}

static inline void outw(u16 value, u32 ptr)
{
	register volatile u32 *port = (volatile u32 *)ptr;

	if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
		(((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) &&
		 ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) {
		*port = value;  
		return;
	}

	__raw_writew((value),alignw(___io(ptr)));
}
#endif	/* IXDP2x01 */

#endif