diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2012-03-05 06:49:29 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2012-09-17 08:42:04 -0400 |
commit | fc47897d2c65bc94b6868a5c914afbd33216e26f (patch) | |
tree | 0926daf682eba58fe67995d7b3c7c1bc65ea58e9 /arch/arm64 | |
parent | 6170a97460dbda12686bef0dec65ce2d59867f9e (diff) |
arm64: Device specific operations
This patch adds several definitions for device communication, including
I/O accessors and ioremap(). The __raw_* accessors are implemented as
inline asm to avoid compiler generation of post-indexed accesses (less
efficient to emulate in a virtualised environment).
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Tony Lindgren <tony@atomide.com>
Acked-by: Nicolas Pitre <nico@linaro.org>
Acked-by: Olof Johansson <olof@lixom.net>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Diffstat (limited to 'arch/arm64')
-rw-r--r-- | arch/arm64/include/asm/device.h | 26 | ||||
-rw-r--r-- | arch/arm64/include/asm/fb.h | 34 | ||||
-rw-r--r-- | arch/arm64/include/asm/io.h | 258 | ||||
-rw-r--r-- | arch/arm64/kernel/io.c | 64 | ||||
-rw-r--r-- | arch/arm64/mm/ioremap.c | 84 |
5 files changed, 466 insertions, 0 deletions
diff --git a/arch/arm64/include/asm/device.h b/arch/arm64/include/asm/device.h new file mode 100644 index 00000000000..0d8453c755a --- /dev/null +++ b/arch/arm64/include/asm/device.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ARM Ltd. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | #ifndef __ASM_DEVICE_H | ||
17 | #define __ASM_DEVICE_H | ||
18 | |||
19 | struct dev_archdata { | ||
20 | struct dma_map_ops *dma_ops; | ||
21 | }; | ||
22 | |||
23 | struct pdev_archdata { | ||
24 | }; | ||
25 | |||
26 | #endif | ||
diff --git a/arch/arm64/include/asm/fb.h b/arch/arm64/include/asm/fb.h new file mode 100644 index 00000000000..adb88a64b2f --- /dev/null +++ b/arch/arm64/include/asm/fb.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ARM Ltd. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | #ifndef __ASM_FB_H_ | ||
17 | #define __ASM_FB_H_ | ||
18 | |||
19 | #include <linux/fb.h> | ||
20 | #include <linux/fs.h> | ||
21 | #include <asm/page.h> | ||
22 | |||
23 | static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, | ||
24 | unsigned long off) | ||
25 | { | ||
26 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
27 | } | ||
28 | |||
29 | static inline int fb_is_primary_device(struct fb_info *info) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | #endif /* __ASM_FB_H_ */ | ||
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h new file mode 100644 index 00000000000..74a2a7d304a --- /dev/null +++ b/arch/arm64/include/asm/io.h | |||
@@ -0,0 +1,258 @@ | |||
1 | /* | ||
2 | * Based on arch/arm/include/asm/io.h | ||
3 | * | ||
4 | * Copyright (C) 1996-2000 Russell King | ||
5 | * Copyright (C) 2012 ARM Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #ifndef __ASM_IO_H | ||
20 | #define __ASM_IO_H | ||
21 | |||
22 | #ifdef __KERNEL__ | ||
23 | |||
24 | #include <linux/types.h> | ||
25 | |||
26 | #include <asm/byteorder.h> | ||
27 | #include <asm/barrier.h> | ||
28 | #include <asm/pgtable.h> | ||
29 | |||
30 | /* | ||
31 | * Generic IO read/write. These perform native-endian accesses. | ||
32 | */ | ||
33 | static inline void __raw_writeb(u8 val, volatile void __iomem *addr) | ||
34 | { | ||
35 | asm volatile("strb %w0, [%1]" : : "r" (val), "r" (addr)); | ||
36 | } | ||
37 | |||
38 | static inline void __raw_writew(u16 val, volatile void __iomem *addr) | ||
39 | { | ||
40 | asm volatile("strh %w0, [%1]" : : "r" (val), "r" (addr)); | ||
41 | } | ||
42 | |||
43 | static inline void __raw_writel(u32 val, volatile void __iomem *addr) | ||
44 | { | ||
45 | asm volatile("str %w0, [%1]" : : "r" (val), "r" (addr)); | ||
46 | } | ||
47 | |||
48 | static inline void __raw_writeq(u64 val, volatile void __iomem *addr) | ||
49 | { | ||
50 | asm volatile("str %0, [%1]" : : "r" (val), "r" (addr)); | ||
51 | } | ||
52 | |||
53 | static inline u8 __raw_readb(const volatile void __iomem *addr) | ||
54 | { | ||
55 | u8 val; | ||
56 | asm volatile("ldrb %w0, [%1]" : "=r" (val) : "r" (addr)); | ||
57 | return val; | ||
58 | } | ||
59 | |||
60 | static inline u16 __raw_readw(const volatile void __iomem *addr) | ||
61 | { | ||
62 | u16 val; | ||
63 | asm volatile("ldrh %w0, [%1]" : "=r" (val) : "r" (addr)); | ||
64 | return val; | ||
65 | } | ||
66 | |||
67 | static inline u32 __raw_readl(const volatile void __iomem *addr) | ||
68 | { | ||
69 | u32 val; | ||
70 | asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (addr)); | ||
71 | return val; | ||
72 | } | ||
73 | |||
74 | static inline u64 __raw_readq(const volatile void __iomem *addr) | ||
75 | { | ||
76 | u64 val; | ||
77 | asm volatile("ldr %0, [%1]" : "=r" (val) : "r" (addr)); | ||
78 | return val; | ||
79 | } | ||
80 | |||
81 | /* IO barriers */ | ||
82 | #define __iormb() rmb() | ||
83 | #define __iowmb() wmb() | ||
84 | |||
85 | #define mmiowb() do { } while (0) | ||
86 | |||
87 | /* | ||
88 | * Relaxed I/O memory access primitives. These follow the Device memory | ||
89 | * ordering rules but do not guarantee any ordering relative to Normal memory | ||
90 | * accesses. | ||
91 | */ | ||
92 | #define readb_relaxed(c) ({ u8 __v = __raw_readb(c); __v; }) | ||
93 | #define readw_relaxed(c) ({ u16 __v = le16_to_cpu((__force __le16)__raw_readw(c)); __v; }) | ||
94 | #define readl_relaxed(c) ({ u32 __v = le32_to_cpu((__force __le32)__raw_readl(c)); __v; }) | ||
95 | |||
96 | #define writeb_relaxed(v,c) ((void)__raw_writeb((v),(c))) | ||
97 | #define writew_relaxed(v,c) ((void)__raw_writew((__force u16)cpu_to_le16(v),(c))) | ||
98 | #define writel_relaxed(v,c) ((void)__raw_writel((__force u32)cpu_to_le32(v),(c))) | ||
99 | |||
100 | /* | ||
101 | * I/O memory access primitives. Reads are ordered relative to any | ||
102 | * following Normal memory access. Writes are ordered relative to any prior | ||
103 | * Normal memory access. | ||
104 | */ | ||
105 | #define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; }) | ||
106 | #define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; }) | ||
107 | #define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; }) | ||
108 | |||
109 | #define writeb(v,c) ({ __iowmb(); writeb_relaxed((v),(c)); }) | ||
110 | #define writew(v,c) ({ __iowmb(); writew_relaxed((v),(c)); }) | ||
111 | #define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); }) | ||
112 | |||
113 | /* | ||
114 | * I/O port access primitives. | ||
115 | */ | ||
116 | #define IO_SPACE_LIMIT 0xffff | ||
117 | #define PCI_IOBASE ((void __iomem *)0xffffffbbfffe0000UL) | ||
118 | |||
119 | static inline u8 inb(unsigned long addr) | ||
120 | { | ||
121 | return readb(addr + PCI_IOBASE); | ||
122 | } | ||
123 | |||
124 | static inline u16 inw(unsigned long addr) | ||
125 | { | ||
126 | return readw(addr + PCI_IOBASE); | ||
127 | } | ||
128 | |||
129 | static inline u32 inl(unsigned long addr) | ||
130 | { | ||
131 | return readl(addr + PCI_IOBASE); | ||
132 | } | ||
133 | |||
134 | static inline void outb(u8 b, unsigned long addr) | ||
135 | { | ||
136 | writeb(b, addr + PCI_IOBASE); | ||
137 | } | ||
138 | |||
139 | static inline void outw(u16 b, unsigned long addr) | ||
140 | { | ||
141 | writew(b, addr + PCI_IOBASE); | ||
142 | } | ||
143 | |||
144 | static inline void outl(u32 b, unsigned long addr) | ||
145 | { | ||
146 | writel(b, addr + PCI_IOBASE); | ||
147 | } | ||
148 | |||
149 | #define inb_p(addr) inb(addr) | ||
150 | #define inw_p(addr) inw(addr) | ||
151 | #define inl_p(addr) inl(addr) | ||
152 | |||
153 | #define outb_p(x, addr) outb((x), (addr)) | ||
154 | #define outw_p(x, addr) outw((x), (addr)) | ||
155 | #define outl_p(x, addr) outl((x), (addr)) | ||
156 | |||
157 | static inline void insb(unsigned long addr, void *buffer, int count) | ||
158 | { | ||
159 | u8 *buf = buffer; | ||
160 | while (count--) | ||
161 | *buf++ = __raw_readb(addr + PCI_IOBASE); | ||
162 | } | ||
163 | |||
164 | static inline void insw(unsigned long addr, void *buffer, int count) | ||
165 | { | ||
166 | u16 *buf = buffer; | ||
167 | while (count--) | ||
168 | *buf++ = __raw_readw(addr + PCI_IOBASE); | ||
169 | } | ||
170 | |||
171 | static inline void insl(unsigned long addr, void *buffer, int count) | ||
172 | { | ||
173 | u32 *buf = buffer; | ||
174 | while (count--) | ||
175 | *buf++ = __raw_readl(addr + PCI_IOBASE); | ||
176 | } | ||
177 | |||
178 | static inline void outsb(unsigned long addr, const void *buffer, int count) | ||
179 | { | ||
180 | const u8 *buf = buffer; | ||
181 | while (count--) | ||
182 | __raw_writeb(*buf++, addr + PCI_IOBASE); | ||
183 | } | ||
184 | |||
185 | static inline void outsw(unsigned long addr, const void *buffer, int count) | ||
186 | { | ||
187 | const u16 *buf = buffer; | ||
188 | while (count--) | ||
189 | __raw_writew(*buf++, addr + PCI_IOBASE); | ||
190 | } | ||
191 | |||
192 | static inline void outsl(unsigned long addr, const void *buffer, int count) | ||
193 | { | ||
194 | const u32 *buf = buffer; | ||
195 | while (count--) | ||
196 | __raw_writel(*buf++, addr + PCI_IOBASE); | ||
197 | } | ||
198 | |||
199 | #define insb_p(port,to,len) insb(port,to,len) | ||
200 | #define insw_p(port,to,len) insw(port,to,len) | ||
201 | #define insl_p(port,to,len) insl(port,to,len) | ||
202 | |||
203 | #define outsb_p(port,from,len) outsb(port,from,len) | ||
204 | #define outsw_p(port,from,len) outsw(port,from,len) | ||
205 | #define outsl_p(port,from,len) outsl(port,from,len) | ||
206 | |||
207 | /* | ||
208 | * String version of I/O memory access operations. | ||
209 | */ | ||
210 | extern void __memcpy_fromio(void *, const volatile void __iomem *, size_t); | ||
211 | extern void __memcpy_toio(volatile void __iomem *, const void *, size_t); | ||
212 | extern void __memset_io(volatile void __iomem *, int, size_t); | ||
213 | |||
214 | #define memset_io(c,v,l) __memset_io((c),(v),(l)) | ||
215 | #define memcpy_fromio(a,c,l) __memcpy_fromio((a),(c),(l)) | ||
216 | #define memcpy_toio(c,a,l) __memcpy_toio((c),(a),(l)) | ||
217 | |||
218 | /* | ||
219 | * I/O memory mapping functions. | ||
220 | */ | ||
221 | extern void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot); | ||
222 | extern void __iounmap(volatile void __iomem *addr); | ||
223 | |||
224 | #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_DIRTY) | ||
225 | #define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_XN | PTE_ATTRINDX(MT_DEVICE_nGnRE)) | ||
226 | #define PROT_NORMAL_NC (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL_NC)) | ||
227 | |||
228 | #define ioremap(addr, size) __ioremap((addr), (size), PROT_DEVICE_nGnRE) | ||
229 | #define ioremap_nocache(addr, size) __ioremap((addr), (size), PROT_DEVICE_nGnRE) | ||
230 | #define ioremap_wc(addr, size) __ioremap((addr), (size), PROT_NORMAL_NC) | ||
231 | #define iounmap __iounmap | ||
232 | |||
233 | #define ARCH_HAS_IOREMAP_WC | ||
234 | #include <asm-generic/iomap.h> | ||
235 | |||
236 | /* | ||
237 | * More restrictive address range checking than the default implementation | ||
238 | * (PHYS_OFFSET and PHYS_MASK taken into account). | ||
239 | */ | ||
240 | #define ARCH_HAS_VALID_PHYS_ADDR_RANGE | ||
241 | extern int valid_phys_addr_range(unsigned long addr, size_t size); | ||
242 | extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); | ||
243 | |||
244 | extern int devmem_is_allowed(unsigned long pfn); | ||
245 | |||
246 | /* | ||
247 | * Convert a physical pointer to a virtual kernel pointer for /dev/mem | ||
248 | * access | ||
249 | */ | ||
250 | #define xlate_dev_mem_ptr(p) __va(p) | ||
251 | |||
252 | /* | ||
253 | * Convert a virtual cached pointer to an uncached pointer | ||
254 | */ | ||
255 | #define xlate_dev_kmem_ptr(p) p | ||
256 | |||
257 | #endif /* __KERNEL__ */ | ||
258 | #endif /* __ASM_IO_H */ | ||
diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c new file mode 100644 index 00000000000..7d37ead4d19 --- /dev/null +++ b/arch/arm64/kernel/io.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Based on arch/arm/kernel/io.c | ||
3 | * | ||
4 | * Copyright (C) 2012 ARM Ltd. | ||
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 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/export.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/io.h> | ||
22 | |||
23 | /* | ||
24 | * Copy data from IO memory space to "real" memory space. | ||
25 | */ | ||
26 | void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) | ||
27 | { | ||
28 | unsigned char *t = to; | ||
29 | while (count) { | ||
30 | count--; | ||
31 | *t = readb(from); | ||
32 | t++; | ||
33 | from++; | ||
34 | } | ||
35 | } | ||
36 | EXPORT_SYMBOL(__memcpy_fromio); | ||
37 | |||
38 | /* | ||
39 | * Copy data from "real" memory space to IO memory space. | ||
40 | */ | ||
41 | void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) | ||
42 | { | ||
43 | const unsigned char *f = from; | ||
44 | while (count) { | ||
45 | count--; | ||
46 | writeb(*f, to); | ||
47 | f++; | ||
48 | to++; | ||
49 | } | ||
50 | } | ||
51 | EXPORT_SYMBOL(__memcpy_toio); | ||
52 | |||
53 | /* | ||
54 | * "memset" on IO memory space. | ||
55 | */ | ||
56 | void __memset_io(volatile void __iomem *dst, int c, size_t count) | ||
57 | { | ||
58 | while (count) { | ||
59 | count--; | ||
60 | writeb(c, dst); | ||
61 | dst++; | ||
62 | } | ||
63 | } | ||
64 | EXPORT_SYMBOL(__memset_io); | ||
diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c new file mode 100644 index 00000000000..1725cd6db37 --- /dev/null +++ b/arch/arm64/mm/ioremap.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * Based on arch/arm/mm/ioremap.c | ||
3 | * | ||
4 | * (C) Copyright 1995 1996 Linus Torvalds | ||
5 | * Hacked for ARM by Phil Blundell <philb@gnu.org> | ||
6 | * Hacked to allow all architectures to build, and various cleanups | ||
7 | * by Russell King | ||
8 | * Copyright (C) 2012 ARM Ltd. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | */ | ||
22 | |||
23 | #include <linux/export.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/vmalloc.h> | ||
26 | #include <linux/io.h> | ||
27 | |||
28 | static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size, | ||
29 | pgprot_t prot, void *caller) | ||
30 | { | ||
31 | unsigned long last_addr; | ||
32 | unsigned long offset = phys_addr & ~PAGE_MASK; | ||
33 | int err; | ||
34 | unsigned long addr; | ||
35 | struct vm_struct *area; | ||
36 | |||
37 | /* | ||
38 | * Page align the mapping address and size, taking account of any | ||
39 | * offset. | ||
40 | */ | ||
41 | phys_addr &= PAGE_MASK; | ||
42 | size = PAGE_ALIGN(size + offset); | ||
43 | |||
44 | /* | ||
45 | * Don't allow wraparound, zero size or outside PHYS_MASK. | ||
46 | */ | ||
47 | last_addr = phys_addr + size - 1; | ||
48 | if (!size || last_addr < phys_addr || (last_addr & ~PHYS_MASK)) | ||
49 | return NULL; | ||
50 | |||
51 | /* | ||
52 | * Don't allow RAM to be mapped. | ||
53 | */ | ||
54 | if (WARN_ON(pfn_valid(__phys_to_pfn(phys_addr)))) | ||
55 | return NULL; | ||
56 | |||
57 | area = get_vm_area_caller(size, VM_IOREMAP, caller); | ||
58 | if (!area) | ||
59 | return NULL; | ||
60 | addr = (unsigned long)area->addr; | ||
61 | |||
62 | err = ioremap_page_range(addr, addr + size, phys_addr, prot); | ||
63 | if (err) { | ||
64 | vunmap((void *)addr); | ||
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | return (void __iomem *)(offset + addr); | ||
69 | } | ||
70 | |||
71 | void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot) | ||
72 | { | ||
73 | return __ioremap_caller(phys_addr, size, prot, | ||
74 | __builtin_return_address(0)); | ||
75 | } | ||
76 | EXPORT_SYMBOL(__ioremap); | ||
77 | |||
78 | void __iounmap(volatile void __iomem *io_addr) | ||
79 | { | ||
80 | void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr); | ||
81 | |||
82 | vunmap(addr); | ||
83 | } | ||
84 | EXPORT_SYMBOL(__iounmap); | ||