diff options
author | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2007-02-12 10:28:56 -0500 |
---|---|---|
committer | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2007-04-27 07:44:14 -0400 |
commit | e3e7d8d4ea37b8372ee417452d03171c5dc55125 (patch) | |
tree | 247a899f472e5cf1a3f7467dda88a017bee134a6 /include/asm-avr32/io.h | |
parent | 92b728c147adb8c690b520304f4c9ee3eee43c21 (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>
Diffstat (limited to 'include/asm-avr32/io.h')
-rw-r--r-- | include/asm-avr32/io.h | 335 |
1 files changed, 183 insertions, 152 deletions
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 */ |
12 | static __inline__ unsigned long virt_to_phys(volatile void *address) | 14 | static __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); | |||
36 | extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen); | 38 | extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen); |
37 | extern void __raw_readsl(const void __iomem *addr, void *data, int longlen); | 39 | extern void __raw_readsl(const void __iomem *addr, void *data, int longlen); |
38 | 40 | ||
39 | static inline void writeb(unsigned char b, volatile void __iomem *addr) | 41 | static 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 | } |
43 | static inline void writew(unsigned short b, volatile void __iomem *addr) | 45 | static 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 | } |
47 | static inline void writel(unsigned int b, volatile void __iomem *addr) | 49 | static 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 | ||
55 | static inline unsigned char readb(const volatile void __iomem *addr) | 54 | static 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 | } |
59 | static inline unsigned short readw(const volatile void __iomem *addr) | 58 | static 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 | } |
63 | static inline unsigned int readl(const volatile void __iomem *addr) | 62 | static 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) \ | ||
79 | static inline void \ | ||
80 | pfx##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 | \ | ||
93 | static 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) \ | ||
107 | static 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 | \ | ||
121 | static 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 | |||
151 | BUILDIO_MEM(b, u8) | ||
152 | BUILDIO_MEM(w, u16) | ||
153 | BUILDIO_MEM(l, u32) | ||
154 | |||
155 | BUILDIO_IOPORT(b, u8) | ||
156 | BUILDIO_IOPORT(w, u16) | ||
157 | BUILDIO_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) \ | ||
164 | static 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 | \ | ||
173 | static 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) \ | ||
183 | static 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 | \ | ||
192 | static 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 | ||
205 | BUILDSTRING(b, u8) | ||
206 | BUILDSTRING(w, u16) | ||
207 | BUILDSTRING(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 | */ | ||
115 | static inline void memcpy_fromio(void * to, const volatile void __iomem *from, | 240 | static 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 | ||
127 | static inline void memcpy_toio(volatile void __iomem *to, const void * from, | 250 | static 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 | ||
139 | static inline void memset_io(volatile void __iomem *addr, unsigned char val, | 260 | static 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 | */ | ||
148 | extern 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 | |||
183 | static 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 | ||
191 | static 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 | ||
199 | static 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 | |||
207 | static 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 | |||
215 | static 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 | |||
223 | static 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 | ||
238 | extern void __iomem *__ioremap(unsigned long offset, size_t size, | 271 | extern 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 */ |