aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2007-02-12 10:28:56 -0500
committerHaavard Skinnemoen <hskinnemoen@atmel.com>2007-04-27 07:44:14 -0400
commite3e7d8d4ea37b8372ee417452d03171c5dc55125 (patch)
tree247a899f472e5cf1a3f7467dda88a017bee134a6
parent92b728c147adb8c690b520304f4c9ee3eee43c21 (diff)
[AVR32] Make I/O access macros work with external devices
Fix the I/O access macros so that they work with externally connected devices accessed in little-endian mode over any bus width: * Use a set of macros to define I/O port- and memory operations borrowed from MIPS. * Allow subarchitecture to specify address- and data-mangling * Implement at32ap-specific port mangling (with build-time configurable bus width. Only one bus width at a time supported for now.) * Rewrite iowriteN and friends to use write[bwl] and friends (not the __raw counterparts.) This has been tested using pata_pcmcia to access a CompactFlash card connected to the EBI (16-bit bus width.) Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
-rw-r--r--arch/avr32/mach-at32ap/Kconfig26
-rw-r--r--include/asm-avr32/arch-at32ap/io.h39
-rw-r--r--include/asm-avr32/io.h335
3 files changed, 247 insertions, 153 deletions
diff --git a/arch/avr32/mach-at32ap/Kconfig b/arch/avr32/mach-at32ap/Kconfig
index d7497715cc02..eb307838457b 100644
--- a/arch/avr32/mach-at32ap/Kconfig
+++ b/arch/avr32/mach-at32ap/Kconfig
@@ -2,6 +2,30 @@ if PLATFORM_AT32AP
2 2
3menu "Atmel AVR32 AP options" 3menu "Atmel AVR32 AP options"
4 4
5choice
6 prompt "AT32AP7000 static memory bus width"
7 depends on CPU_AT32AP7000
8 default AP7000_16_BIT_SMC
9 help
10 Define the width of the AP7000 external static memory interface.
11 This is used to determine how to mangle the address and/or data
12 when doing little-endian port access.
13
14 The current code can only support a single external memory bus
15 width for all chip selects, excluding the flash (which is using
16 raw access and is thus not affected by any of this.)
17
18config AP7000_32_BIT_SMC
19 bool "32 bit"
20
21config AP7000_16_BIT_SMC
22 bool "16 bit"
23
24config AP7000_8_BIT_SMC
25 bool "8 bit"
26
27endchoice
28
5endmenu 29endmenu
6 30
7endif 31endif # PLATFORM_AT32AP
diff --git a/include/asm-avr32/arch-at32ap/io.h b/include/asm-avr32/arch-at32ap/io.h
new file mode 100644
index 000000000000..ee59e401f041
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/io.h
@@ -0,0 +1,39 @@
1#ifndef __ASM_AVR32_ARCH_AT32AP_IO_H
2#define __ASM_AVR32_ARCH_AT32AP_IO_H
3
4/* For "bizarre" halfword swapping */
5#include <linux/byteorder/swabb.h>
6
7#if defined(CONFIG_AP7000_32_BIT_SMC)
8# define __swizzle_addr_b(addr) (addr ^ 3UL)
9# define __swizzle_addr_w(addr) (addr ^ 2UL)
10# define __swizzle_addr_l(addr) (addr)
11# define ioswabb(a, x) (x)
12# define ioswabw(a, x) (x)
13# define ioswabl(a, x) (x)
14# define __mem_ioswabb(a, x) (x)
15# define __mem_ioswabw(a, x) swab16(x)
16# define __mem_ioswabl(a, x) swab32(x)
17#elif defined(CONFIG_AP7000_16_BIT_SMC)
18# define __swizzle_addr_b(addr) (addr ^ 1UL)
19# define __swizzle_addr_w(addr) (addr)
20# define __swizzle_addr_l(addr) (addr)
21# define ioswabb(a, x) (x)
22# define ioswabw(a, x) (x)
23# define ioswabl(a, x) swahw32(x)
24# define __mem_ioswabb(a, x) (x)
25# define __mem_ioswabw(a, x) swab16(x)
26# define __mem_ioswabl(a, x) swahb32(x)
27#else
28# define __swizzle_addr_b(addr) (addr)
29# define __swizzle_addr_w(addr) (addr)
30# define __swizzle_addr_l(addr) (addr)
31# define ioswabb(a, x) (x)
32# define ioswabw(a, x) swab16(x)
33# define ioswabl(a, x) swab32(x)
34# define __mem_ioswabb(a, x) (x)
35# define __mem_ioswabw(a, x) (x)
36# define __mem_ioswabl(a, x) (x)
37#endif
38
39#endif /* __ASM_AVR32_ARCH_AT32AP_IO_H */
diff --git a/include/asm-avr32/io.h b/include/asm-avr32/io.h
index c08e81048393..27b1523d42e0 100644
--- a/include/asm-avr32/io.h
+++ b/include/asm-avr32/io.h
@@ -1,13 +1,15 @@
1#ifndef __ASM_AVR32_IO_H 1#ifndef __ASM_AVR32_IO_H
2#define __ASM_AVR32_IO_H 2#define __ASM_AVR32_IO_H
3 3
4#include <linux/kernel.h>
4#include <linux/string.h> 5#include <linux/string.h>
5 6#include <linux/types.h>
6#ifdef __KERNEL__
7 7
8#include <asm/addrspace.h> 8#include <asm/addrspace.h>
9#include <asm/byteorder.h> 9#include <asm/byteorder.h>
10 10
11#include <asm/arch/io.h>
12
11/* virt_to_phys will only work when address is in P1 or P2 */ 13/* virt_to_phys will only work when address is in P1 or P2 */
12static __inline__ unsigned long virt_to_phys(volatile void *address) 14static __inline__ unsigned long virt_to_phys(volatile void *address)
13{ 15{
@@ -36,204 +38,235 @@ extern void __raw_readsb(const void __iomem *addr, void *data, int bytelen);
36extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen); 38extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen);
37extern void __raw_readsl(const void __iomem *addr, void *data, int longlen); 39extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
38 40
39static inline void writeb(unsigned char b, volatile void __iomem *addr) 41static inline void __raw_writeb(u8 v, volatile void __iomem *addr)
40{ 42{
41 *(volatile unsigned char __force *)addr = b; 43 *(volatile u8 __force *)addr = v;
42} 44}
43static inline void writew(unsigned short b, volatile void __iomem *addr) 45static inline void __raw_writew(u16 v, volatile void __iomem *addr)
44{ 46{
45 *(volatile unsigned short __force *)addr = b; 47 *(volatile u16 __force *)addr = v;
46} 48}
47static inline void writel(unsigned int b, volatile void __iomem *addr) 49static inline void __raw_writel(u32 v, volatile void __iomem *addr)
48{ 50{
49 *(volatile unsigned int __force *)addr = b; 51 *(volatile u32 __force *)addr = v;
50} 52}
51#define __raw_writeb writeb
52#define __raw_writew writew
53#define __raw_writel writel
54 53
55static inline unsigned char readb(const volatile void __iomem *addr) 54static inline u8 __raw_readb(const volatile void __iomem *addr)
56{ 55{
57 return *(const volatile unsigned char __force *)addr; 56 return *(const volatile u8 __force *)addr;
58} 57}
59static inline unsigned short readw(const volatile void __iomem *addr) 58static inline u16 __raw_readw(const volatile void __iomem *addr)
60{ 59{
61 return *(const volatile unsigned short __force *)addr; 60 return *(const volatile u16 __force *)addr;
62} 61}
63static inline unsigned int readl(const volatile void __iomem *addr) 62static inline u32 __raw_readl(const volatile void __iomem *addr)
64{ 63{
65 return *(const volatile unsigned int __force *)addr; 64 return *(const volatile u32 __force *)addr;
65}
66
67/* Convert I/O port address to virtual address */
68#ifndef __io
69# define __io(p) ((void *)phys_to_uncached(p))
70#endif
71
72/*
73 * Not really sure about the best way to slow down I/O on
74 * AVR32. Defining it as a no-op until we have an actual test case.
75 */
76#define SLOW_DOWN_IO do { } while (0)
77
78#define __BUILD_MEMORY_SINGLE(pfx, bwl, type) \
79static inline void \
80pfx##write##bwl(type val, volatile void __iomem *addr) \
81{ \
82 volatile type *__addr; \
83 type __val; \
84 \
85 __addr = (void *)__swizzle_addr_##bwl((unsigned long)(addr)); \
86 __val = pfx##ioswab##bwl(__addr, val); \
87 \
88 BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \
89 \
90 *__addr = __val; \
91} \
92 \
93static inline type pfx##read##bwl(const volatile void __iomem *addr) \
94{ \
95 volatile type *__addr; \
96 type __val; \
97 \
98 __addr = (void *)__swizzle_addr_##bwl((unsigned long)(addr)); \
99 \
100 BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \
101 \
102 __val = *__addr; \
103 return pfx##ioswab##bwl(__addr, __val); \
104}
105
106#define __BUILD_IOPORT_SINGLE(pfx, bwl, type, p, slow) \
107static inline void pfx##out##bwl##p(type val, unsigned long port) \
108{ \
109 volatile type *__addr; \
110 type __val; \
111 \
112 __addr = __io(__swizzle_addr_##bwl(port)); \
113 __val = pfx##ioswab##bwl(__addr, val); \
114 \
115 BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \
116 \
117 *__addr = __val; \
118 slow; \
119} \
120 \
121static inline type pfx##in##bwl##p(unsigned long port) \
122{ \
123 volatile type *__addr; \
124 type __val; \
125 \
126 __addr = __io(__swizzle_addr_##bwl(port)); \
127 \
128 BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \
129 \
130 __val = *__addr; \
131 slow; \
132 \
133 return pfx##ioswab##bwl(__addr, __val); \
66} 134}
67#define __raw_readb readb
68#define __raw_readw readw
69#define __raw_readl readl
70 135
71#define writesb(p, d, l) __raw_writesb((unsigned int)p, d, l) 136#define __BUILD_MEMORY_PFX(bus, bwl, type) \
72#define writesw(p, d, l) __raw_writesw((unsigned int)p, d, l) 137 __BUILD_MEMORY_SINGLE(bus, bwl, type)
73#define writesl(p, d, l) __raw_writesl((unsigned int)p, d, l) 138
139#define BUILDIO_MEM(bwl, type) \
140 __BUILD_MEMORY_PFX(, bwl, type) \
141 __BUILD_MEMORY_PFX(__mem_, bwl, type)
142
143#define __BUILD_IOPORT_PFX(bus, bwl, type) \
144 __BUILD_IOPORT_SINGLE(bus, bwl, type, ,) \
145 __BUILD_IOPORT_SINGLE(bus, bwl, type, _p, SLOW_DOWN_IO)
146
147#define BUILDIO_IOPORT(bwl, type) \
148 __BUILD_IOPORT_PFX(, bwl, type) \
149 __BUILD_IOPORT_PFX(__mem_, bwl, type)
150
151BUILDIO_MEM(b, u8)
152BUILDIO_MEM(w, u16)
153BUILDIO_MEM(l, u32)
154
155BUILDIO_IOPORT(b, u8)
156BUILDIO_IOPORT(w, u16)
157BUILDIO_IOPORT(l, u32)
158
159#define readb_relaxed readb
160#define readw_relaxed readw
161#define readl_relaxed readl
162
163#define __BUILD_MEMORY_STRING(bwl, type) \
164static inline void writes##bwl(volatile void __iomem *addr, \
165 const void *data, unsigned int count) \
166{ \
167 const type *__data = data; \
168 \
169 while (count--) \
170 __mem_write##bwl(*__data++, addr); \
171} \
172 \
173static inline void reads##bwl(const volatile void __iomem *addr, \
174 void *data, unsigned int count) \
175{ \
176 type *__data = data; \
177 \
178 while (count--) \
179 *__data++ = __mem_read##bwl(addr); \
180}
181
182#define __BUILD_IOPORT_STRING(bwl, type) \
183static inline void outs##bwl(unsigned long port, const void *data, \
184 unsigned int count) \
185{ \
186 const type *__data = data; \
187 \
188 while (count--) \
189 __mem_out##bwl(*__data++, port); \
190} \
191 \
192static inline void ins##bwl(unsigned long port, void *data, \
193 unsigned int count) \
194{ \
195 type *__data = data; \
196 \
197 while (count--) \
198 *__data++ = __mem_in##bwl(port); \
199}
74 200
75#define readsb(p, d, l) __raw_readsb((unsigned int)p, d, l) 201#define BUILDSTRING(bwl, type) \
76#define readsw(p, d, l) __raw_readsw((unsigned int)p, d, l) 202 __BUILD_MEMORY_STRING(bwl, type) \
77#define readsl(p, d, l) __raw_readsl((unsigned int)p, d, l) 203 __BUILD_IOPORT_STRING(bwl, type)
78 204
205BUILDSTRING(b, u8)
206BUILDSTRING(w, u16)
207BUILDSTRING(l, u32)
79 208
80/* 209/*
81 * io{read,write}{8,16,32} macros in both le (for PCI style consumers) and native be 210 * io{read,write}{8,16,32} macros in both le (for PCI style consumers) and native be
82 */ 211 */
83#ifndef ioread8 212#ifndef ioread8
84 213
85#define ioread8(p) ({ unsigned int __v = __raw_readb(p); __v; }) 214#define ioread8(p) ((unsigned int)readb(p))
86 215
87#define ioread16(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(p)); __v; }) 216#define ioread16(p) ((unsigned int)readw(p))
88#define ioread16be(p) ({ unsigned int __v = be16_to_cpu(__raw_readw(p)); __v; }) 217#define ioread16be(p) ((unsigned int)__raw_readw(p))
89 218
90#define ioread32(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(p)); __v; }) 219#define ioread32(p) ((unsigned int)readl(p))
91#define ioread32be(p) ({ unsigned int __v = be32_to_cpu(__raw_readl(p)); __v; }) 220#define ioread32be(p) ((unsigned int)__raw_readl(p))
92 221
93#define iowrite8(v,p) __raw_writeb(v, p) 222#define iowrite8(v,p) writeb(v, p)
94 223
95#define iowrite16(v,p) __raw_writew(cpu_to_le16(v), p) 224#define iowrite16(v,p) writew(v, p)
96#define iowrite16be(v,p) __raw_writew(cpu_to_be16(v), p) 225#define iowrite16be(v,p) __raw_writew(v, p)
97 226
98#define iowrite32(v,p) __raw_writel(cpu_to_le32(v), p) 227#define iowrite32(v,p) writel(v, p)
99#define iowrite32be(v,p) __raw_writel(cpu_to_be32(v), p) 228#define iowrite32be(v,p) __raw_writel(v, p)
100 229
101#define ioread8_rep(p,d,c) __raw_readsb(p,d,c) 230#define ioread8_rep(p,d,c) readsb(p,d,c)
102#define ioread16_rep(p,d,c) __raw_readsw(p,d,c) 231#define ioread16_rep(p,d,c) readsw(p,d,c)
103#define ioread32_rep(p,d,c) __raw_readsl(p,d,c) 232#define ioread32_rep(p,d,c) readsl(p,d,c)
104 233
105#define iowrite8_rep(p,s,c) __raw_writesb(p,s,c) 234#define iowrite8_rep(p,s,c) writesb(p,s,c)
106#define iowrite16_rep(p,s,c) __raw_writesw(p,s,c) 235#define iowrite16_rep(p,s,c) writesw(p,s,c)
107#define iowrite32_rep(p,s,c) __raw_writesl(p,s,c) 236#define iowrite32_rep(p,s,c) writesl(p,s,c)
108 237
109#endif 238#endif
110 239
111
112/*
113 * These two are only here because ALSA _thinks_ it needs them...
114 */
115static inline void memcpy_fromio(void * to, const volatile void __iomem *from, 240static inline void memcpy_fromio(void * to, const volatile void __iomem *from,
116 unsigned long count) 241 unsigned long count)
117{ 242{
118 char *p = to; 243 char *p = to;
119 while (count) { 244 volatile const char __iomem *addr = from;
120 count--; 245
121 *p = readb(from); 246 while (count--)
122 p++; 247 *p++ = readb(addr++);
123 from++;
124 }
125} 248}
126 249
127static inline void memcpy_toio(volatile void __iomem *to, const void * from, 250static inline void memcpy_toio(volatile void __iomem *to, const void * from,
128 unsigned long count) 251 unsigned long count)
129{ 252{
130 const char *p = from; 253 const char *p = from;
131 while (count) { 254 volatile char __iomem *addr = to;
132 count--; 255
133 writeb(*p, to); 256 while (count--)
134 p++; 257 writeb(*p++, addr++);
135 to++;
136 }
137} 258}
138 259
139static inline void memset_io(volatile void __iomem *addr, unsigned char val, 260static inline void memset_io(volatile void __iomem *addr, unsigned char val,
140 unsigned long count) 261 unsigned long count)
141{ 262{
142 memset((void __force *)addr, val, count); 263 volatile char __iomem *p = addr;
143}
144
145/*
146 * Bad read/write accesses...
147 */
148extern void __readwrite_bug(const char *fn);
149
150#define IO_SPACE_LIMIT 0xffffffff
151
152/* Convert I/O port address to virtual address */
153#define __io(p) ((void __iomem *)phys_to_uncached(p))
154
155/*
156 * IO port access primitives
157 * -------------------------
158 *
159 * The AVR32 doesn't have special IO access instructions; all IO is memory
160 * mapped. Note that these are defined to perform little endian accesses
161 * only. Their primary purpose is to access PCI and ISA peripherals.
162 *
163 * Note that for a big endian machine, this implies that the following
164 * big endian mode connectivity is in place.
165 *
166 * The machine specific io.h include defines __io to translate an "IO"
167 * address to a memory address.
168 *
169 * Note that we prevent GCC re-ordering or caching values in expressions
170 * by introducing sequence points into the in*() definitions. Note that
171 * __raw_* do not guarantee this behaviour.
172 *
173 * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space.
174 */
175#define outb(v, p) __raw_writeb(v, __io(p))
176#define outw(v, p) __raw_writew(cpu_to_le16(v), __io(p))
177#define outl(v, p) __raw_writel(cpu_to_le32(v), __io(p))
178
179#define inb(p) __raw_readb(__io(p))
180#define inw(p) le16_to_cpu(__raw_readw(__io(p)))
181#define inl(p) le32_to_cpu(__raw_readl(__io(p)))
182
183static inline void __outsb(unsigned long port, void *addr, unsigned int count)
184{
185 while (count--) {
186 outb(*(u8 *)addr, port);
187 addr++;
188 }
189}
190 264
191static inline void __insb(unsigned long port, void *addr, unsigned int count) 265 while (count--)
192{ 266 writeb(val, p++);
193 while (count--) {
194 *(u8 *)addr = inb(port);
195 addr++;
196 }
197} 267}
198 268
199static inline void __outsw(unsigned long port, void *addr, unsigned int count) 269#define IO_SPACE_LIMIT 0xffffffff
200{
201 while (count--) {
202 outw(*(u16 *)addr, port);
203 addr += 2;
204 }
205}
206
207static inline void __insw(unsigned long port, void *addr, unsigned int count)
208{
209 while (count--) {
210 *(u16 *)addr = inw(port);
211 addr += 2;
212 }
213}
214
215static inline void __outsl(unsigned long port, void *addr, unsigned int count)
216{
217 while (count--) {
218 outl(*(u32 *)addr, port);
219 addr += 4;
220 }
221}
222
223static inline void __insl(unsigned long port, void *addr, unsigned int count)
224{
225 while (count--) {
226 *(u32 *)addr = inl(port);
227 addr += 4;
228 }
229}
230
231#define outsb(port, addr, count) __outsb(port, addr, count)
232#define insb(port, addr, count) __insb(port, addr, count)
233#define outsw(port, addr, count) __outsw(port, addr, count)
234#define insw(port, addr, count) __insw(port, addr, count)
235#define outsl(port, addr, count) __outsl(port, addr, count)
236#define insl(port, addr, count) __insl(port, addr, count)
237 270
238extern void __iomem *__ioremap(unsigned long offset, size_t size, 271extern void __iomem *__ioremap(unsigned long offset, size_t size,
239 unsigned long flags); 272 unsigned long flags);
@@ -292,6 +325,4 @@ extern void __iounmap(void __iomem *addr);
292 */ 325 */
293#define xlate_dev_kmem_ptr(p) p 326#define xlate_dev_kmem_ptr(p) p
294 327
295#endif /* __KERNEL__ */
296
297#endif /* __ASM_AVR32_IO_H */ 328#endif /* __ASM_AVR32_IO_H */