aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/Kconfig21
-rw-r--r--arch/arm/mm/Makefile2
-rw-r--r--arch/arm/mm/cache-feroceon-l2.c318
-rw-r--r--arch/arm/mm/fault-armv.c4
-rw-r--r--arch/arm/mm/flush.c2
-rw-r--r--arch/arm/mm/proc-arm925.S2
-rw-r--r--arch/arm/mm/proc-arm926.S2
-rw-r--r--arch/arm/mm/proc-arm940.S2
-rw-r--r--arch/arm/mm/proc-arm946.S2
-rw-r--r--arch/arm/mm/proc-feroceon.S242
10 files changed, 563 insertions, 34 deletions
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 33ed048502a3..a2c8b006d710 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -180,8 +180,8 @@ config CPU_ARM925T
180# ARM926T 180# ARM926T
181config CPU_ARM926T 181config CPU_ARM926T
182 bool "Support ARM926T processor" 182 bool "Support ARM926T processor"
183 depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || ARCH_NS9XXX || ARCH_DAVINCI 183 depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G20 || ARCH_AT91CAP9 || ARCH_NS9XXX || ARCH_DAVINCI
184 default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || ARCH_NS9XXX || ARCH_DAVINCI 184 default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G20 || ARCH_AT91CAP9 || ARCH_NS9XXX || ARCH_DAVINCI
185 select CPU_32v5 185 select CPU_32v5
186 select CPU_ABRT_EV5TJ 186 select CPU_ABRT_EV5TJ
187 select CPU_PABRT_NOIFAR 187 select CPU_PABRT_NOIFAR
@@ -365,7 +365,7 @@ config CPU_XSC3
365# Feroceon 365# Feroceon
366config CPU_FEROCEON 366config CPU_FEROCEON
367 bool 367 bool
368 depends on ARCH_ORION5X 368 depends on ARCH_ORION5X || ARCH_LOKI || ARCH_KIRKWOOD || ARCH_MV78XX0
369 default y 369 default y
370 select CPU_32v5 370 select CPU_32v5
371 select CPU_ABRT_EV5T 371 select CPU_ABRT_EV5T
@@ -373,7 +373,7 @@ config CPU_FEROCEON
373 select CPU_CACHE_VIVT 373 select CPU_CACHE_VIVT
374 select CPU_CP15_MMU 374 select CPU_CP15_MMU
375 select CPU_COPY_FEROCEON if MMU 375 select CPU_COPY_FEROCEON if MMU
376 select CPU_TLB_V4WBI if MMU 376 select CPU_TLB_FEROCEON if MMU
377 377
378config CPU_FEROCEON_OLD_ID 378config CPU_FEROCEON_OLD_ID
379 bool "Accept early Feroceon cores with an ARM926 ID" 379 bool "Accept early Feroceon cores with an ARM926 ID"
@@ -551,6 +551,11 @@ config CPU_TLB_V4WBI
551 ARM Architecture Version 4 TLB with writeback cache and invalidate 551 ARM Architecture Version 4 TLB with writeback cache and invalidate
552 instruction cache entry. 552 instruction cache entry.
553 553
554config CPU_TLB_FEROCEON
555 bool
556 help
557 Feroceon TLB (v4wbi with non-outer-cachable page table walks).
558
554config CPU_TLB_V6 559config CPU_TLB_V6
555 bool 560 bool
556 561
@@ -709,6 +714,14 @@ config OUTER_CACHE
709 bool 714 bool
710 default n 715 default n
711 716
717config CACHE_FEROCEON_L2
718 bool "Enable the Feroceon L2 cache controller"
719 depends on ARCH_KIRKWOOD || ARCH_MV78XX0
720 default y
721 select OUTER_CACHE
722 help
723 This option enables the Feroceon L2 cache controller.
724
712config CACHE_L2X0 725config CACHE_L2X0
713 bool "Enable the L2x0 outer cache controller" 726 bool "Enable the L2x0 outer cache controller"
714 depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 727 depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 32b2d2d213a6..f64b92557b11 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_CPU_TLB_V3) += tlb-v3.o
46obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o 46obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o
47obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o 47obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o
48obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o 48obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o
49obj-$(CONFIG_CPU_TLB_FEROCEON) += tlb-v4wbi.o # reuse v4wbi TLB functions
49obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o 50obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o
50obj-$(CONFIG_CPU_TLB_V7) += tlb-v7.o 51obj-$(CONFIG_CPU_TLB_V7) += tlb-v7.o
51 52
@@ -73,4 +74,5 @@ obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o
73obj-$(CONFIG_CPU_V6) += proc-v6.o 74obj-$(CONFIG_CPU_V6) += proc-v6.o
74obj-$(CONFIG_CPU_V7) += proc-v7.o 75obj-$(CONFIG_CPU_V7) += proc-v7.o
75 76
77obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o
76obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o 78obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
new file mode 100644
index 000000000000..20eec4ba173f
--- /dev/null
+++ b/arch/arm/mm/cache-feroceon-l2.c
@@ -0,0 +1,318 @@
1/*
2 * arch/arm/mm/cache-feroceon-l2.c - Feroceon L2 cache controller support
3 *
4 * Copyright (C) 2008 Marvell Semiconductor
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 *
10 * References:
11 * - Unified Layer 2 Cache for Feroceon CPU Cores,
12 * Document ID MV-S104858-00, Rev. A, October 23 2007.
13 */
14
15#include <linux/init.h>
16#include <asm/cacheflush.h>
17#include <asm/plat-orion/cache-feroceon-l2.h>
18
19
20/*
21 * Low-level cache maintenance operations.
22 *
23 * As well as the regular 'clean/invalidate/flush L2 cache line by
24 * MVA' instructions, the Feroceon L2 cache controller also features
25 * 'clean/invalidate L2 range by MVA' operations.
26 *
27 * Cache range operations are initiated by writing the start and
28 * end addresses to successive cp15 registers, and process every
29 * cache line whose first byte address lies in the inclusive range
30 * [start:end].
31 *
32 * The cache range operations stall the CPU pipeline until completion.
33 *
34 * The range operations require two successive cp15 writes, in
35 * between which we don't want to be preempted.
36 */
37static inline void l2_clean_pa(unsigned long addr)
38{
39 __asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr));
40}
41
42static inline void l2_clean_mva_range(unsigned long start, unsigned long end)
43{
44 unsigned long flags;
45
46 /*
47 * Make sure 'start' and 'end' reference the same page, as
48 * L2 is PIPT and range operations only do a TLB lookup on
49 * the start address.
50 */
51 BUG_ON((start ^ end) & ~(PAGE_SIZE - 1));
52
53 raw_local_irq_save(flags);
54 __asm__("mcr p15, 1, %0, c15, c9, 4" : : "r" (start));
55 __asm__("mcr p15, 1, %0, c15, c9, 5" : : "r" (end));
56 raw_local_irq_restore(flags);
57}
58
59static inline void l2_clean_pa_range(unsigned long start, unsigned long end)
60{
61 l2_clean_mva_range(__phys_to_virt(start), __phys_to_virt(end));
62}
63
64static inline void l2_clean_inv_pa(unsigned long addr)
65{
66 __asm__("mcr p15, 1, %0, c15, c10, 3" : : "r" (addr));
67}
68
69static inline void l2_inv_pa(unsigned long addr)
70{
71 __asm__("mcr p15, 1, %0, c15, c11, 3" : : "r" (addr));
72}
73
74static inline void l2_inv_mva_range(unsigned long start, unsigned long end)
75{
76 unsigned long flags;
77
78 /*
79 * Make sure 'start' and 'end' reference the same page, as
80 * L2 is PIPT and range operations only do a TLB lookup on
81 * the start address.
82 */
83 BUG_ON((start ^ end) & ~(PAGE_SIZE - 1));
84
85 raw_local_irq_save(flags);
86 __asm__("mcr p15, 1, %0, c15, c11, 4" : : "r" (start));
87 __asm__("mcr p15, 1, %0, c15, c11, 5" : : "r" (end));
88 raw_local_irq_restore(flags);
89}
90
91static inline void l2_inv_pa_range(unsigned long start, unsigned long end)
92{
93 l2_inv_mva_range(__phys_to_virt(start), __phys_to_virt(end));
94}
95
96
97/*
98 * Linux primitives.
99 *
100 * Note that the end addresses passed to Linux primitives are
101 * noninclusive, while the hardware cache range operations use
102 * inclusive start and end addresses.
103 */
104#define CACHE_LINE_SIZE 32
105#define MAX_RANGE_SIZE 1024
106
107static int l2_wt_override;
108
109static unsigned long calc_range_end(unsigned long start, unsigned long end)
110{
111 unsigned long range_end;
112
113 BUG_ON(start & (CACHE_LINE_SIZE - 1));
114 BUG_ON(end & (CACHE_LINE_SIZE - 1));
115
116 /*
117 * Try to process all cache lines between 'start' and 'end'.
118 */
119 range_end = end;
120
121 /*
122 * Limit the number of cache lines processed at once,
123 * since cache range operations stall the CPU pipeline
124 * until completion.
125 */
126 if (range_end > start + MAX_RANGE_SIZE)
127 range_end = start + MAX_RANGE_SIZE;
128
129 /*
130 * Cache range operations can't straddle a page boundary.
131 */
132 if (range_end > (start | (PAGE_SIZE - 1)) + 1)
133 range_end = (start | (PAGE_SIZE - 1)) + 1;
134
135 return range_end;
136}
137
138static void feroceon_l2_inv_range(unsigned long start, unsigned long end)
139{
140 /*
141 * Clean and invalidate partial first cache line.
142 */
143 if (start & (CACHE_LINE_SIZE - 1)) {
144 l2_clean_inv_pa(start & ~(CACHE_LINE_SIZE - 1));
145 start = (start | (CACHE_LINE_SIZE - 1)) + 1;
146 }
147
148 /*
149 * Clean and invalidate partial last cache line.
150 */
151 if (end & (CACHE_LINE_SIZE - 1)) {
152 l2_clean_inv_pa(end & ~(CACHE_LINE_SIZE - 1));
153 end &= ~(CACHE_LINE_SIZE - 1);
154 }
155
156 /*
157 * Invalidate all full cache lines between 'start' and 'end'.
158 */
159 while (start != end) {
160 unsigned long range_end = calc_range_end(start, end);
161 l2_inv_pa_range(start, range_end - CACHE_LINE_SIZE);
162 start = range_end;
163 }
164
165 dsb();
166}
167
168static void feroceon_l2_clean_range(unsigned long start, unsigned long end)
169{
170 /*
171 * If L2 is forced to WT, the L2 will always be clean and we
172 * don't need to do anything here.
173 */
174 if (!l2_wt_override) {
175 start &= ~(CACHE_LINE_SIZE - 1);
176 end = (end + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1);
177 while (start != end) {
178 unsigned long range_end = calc_range_end(start, end);
179 l2_clean_pa_range(start, range_end - CACHE_LINE_SIZE);
180 start = range_end;
181 }
182 }
183
184 dsb();
185}
186
187static void feroceon_l2_flush_range(unsigned long start, unsigned long end)
188{
189 start &= ~(CACHE_LINE_SIZE - 1);
190 end = (end + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1);
191 while (start != end) {
192 unsigned long range_end = calc_range_end(start, end);
193 if (!l2_wt_override)
194 l2_clean_pa_range(start, range_end - CACHE_LINE_SIZE);
195 l2_inv_pa_range(start, range_end - CACHE_LINE_SIZE);
196 start = range_end;
197 }
198
199 dsb();
200}
201
202
203/*
204 * Routines to disable and re-enable the D-cache and I-cache at run
205 * time. These are necessary because the L2 cache can only be enabled
206 * or disabled while the L1 Dcache and Icache are both disabled.
207 */
208static void __init invalidate_and_disable_dcache(void)
209{
210 u32 cr;
211
212 cr = get_cr();
213 if (cr & CR_C) {
214 unsigned long flags;
215
216 raw_local_irq_save(flags);
217 flush_cache_all();
218 set_cr(cr & ~CR_C);
219 raw_local_irq_restore(flags);
220 }
221}
222
223static void __init enable_dcache(void)
224{
225 u32 cr;
226
227 cr = get_cr();
228 if (!(cr & CR_C))
229 set_cr(cr | CR_C);
230}
231
232static void __init __invalidate_icache(void)
233{
234 int dummy;
235
236 __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 0\n" : "=r" (dummy));
237}
238
239static void __init invalidate_and_disable_icache(void)
240{
241 u32 cr;
242
243 cr = get_cr();
244 if (cr & CR_I) {
245 set_cr(cr & ~CR_I);
246 __invalidate_icache();
247 }
248}
249
250static void __init enable_icache(void)
251{
252 u32 cr;
253
254 cr = get_cr();
255 if (!(cr & CR_I))
256 set_cr(cr | CR_I);
257}
258
259static inline u32 read_extra_features(void)
260{
261 u32 u;
262
263 __asm__("mrc p15, 1, %0, c15, c1, 0" : "=r" (u));
264
265 return u;
266}
267
268static inline void write_extra_features(u32 u)
269{
270 __asm__("mcr p15, 1, %0, c15, c1, 0" : : "r" (u));
271}
272
273static void __init disable_l2_prefetch(void)
274{
275 u32 u;
276
277 /*
278 * Read the CPU Extra Features register and verify that the
279 * Disable L2 Prefetch bit is set.
280 */
281 u = read_extra_features();
282 if (!(u & 0x01000000)) {
283 printk(KERN_INFO "Feroceon L2: Disabling L2 prefetch.\n");
284 write_extra_features(u | 0x01000000);
285 }
286}
287
288static void __init enable_l2(void)
289{
290 u32 u;
291
292 u = read_extra_features();
293 if (!(u & 0x00400000)) {
294 printk(KERN_INFO "Feroceon L2: Enabling L2\n");
295
296 invalidate_and_disable_dcache();
297 invalidate_and_disable_icache();
298 write_extra_features(u | 0x00400000);
299 enable_icache();
300 enable_dcache();
301 }
302}
303
304void __init feroceon_l2_init(int __l2_wt_override)
305{
306 l2_wt_override = __l2_wt_override;
307
308 disable_l2_prefetch();
309
310 outer_cache.inv_range = feroceon_l2_inv_range;
311 outer_cache.clean_range = feroceon_l2_clean_range;
312 outer_cache.flush_range = feroceon_l2_flush_range;
313
314 enable_l2();
315
316 printk(KERN_INFO "Feroceon L2: Cache support initialised%s.\n",
317 l2_wt_override ? ", in WT override mode" : "");
318}
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index 44558d5f9313..fbfa26058442 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -144,13 +144,17 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
144 page = pfn_to_page(pfn); 144 page = pfn_to_page(pfn);
145 mapping = page_mapping(page); 145 mapping = page_mapping(page);
146 if (mapping) { 146 if (mapping) {
147#ifndef CONFIG_SMP
147 int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); 148 int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
148 149
149 if (dirty) 150 if (dirty)
150 __flush_dcache_page(mapping, page); 151 __flush_dcache_page(mapping, page);
152#endif
151 153
152 if (cache_is_vivt()) 154 if (cache_is_vivt())
153 make_coherent(mapping, vma, addr, pfn); 155 make_coherent(mapping, vma, addr, pfn);
156 else if (vma->vm_flags & VM_EXEC)
157 __flush_icache_all();
154 } 158 }
155} 159}
156 160
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 9df507d36e0b..029ee65fda2b 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -199,6 +199,8 @@ void flush_dcache_page(struct page *page)
199 __flush_dcache_page(mapping, page); 199 __flush_dcache_page(mapping, page);
200 if (mapping && cache_is_vivt()) 200 if (mapping && cache_is_vivt())
201 __flush_dcache_aliases(mapping, page); 201 __flush_dcache_aliases(mapping, page);
202 else if (mapping)
203 __flush_icache_all();
202 } 204 }
203} 205}
204EXPORT_SYMBOL(flush_dcache_page); 206EXPORT_SYMBOL(flush_dcache_page);
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
index 065087afb772..d045812f3399 100644
--- a/arch/arm/mm/proc-arm925.S
+++ b/arch/arm/mm/proc-arm925.S
@@ -332,7 +332,7 @@ ENTRY(arm925_dma_flush_range)
332#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 332#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
333 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 333 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
334#else 334#else
335 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 335 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
336#endif 336#endif
337 add r0, r0, #CACHE_DLINESIZE 337 add r0, r0, #CACHE_DLINESIZE
338 cmp r0, r1 338 cmp r0, r1
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 997db8472b5c..4cd33169a7c9 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -295,7 +295,7 @@ ENTRY(arm926_dma_flush_range)
295#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 295#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
296 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 296 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
297#else 297#else
298 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 298 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
299#endif 299#endif
300 add r0, r0, #CACHE_DLINESIZE 300 add r0, r0, #CACHE_DLINESIZE
301 cmp r0, r1 301 cmp r0, r1
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
index 44ead902bd54..1a3d63df8e90 100644
--- a/arch/arm/mm/proc-arm940.S
+++ b/arch/arm/mm/proc-arm940.S
@@ -222,7 +222,7 @@ ENTRY(arm940_dma_flush_range)
222#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 222#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
223 mcr p15, 0, r3, c7, c14, 2 @ clean/flush D entry 223 mcr p15, 0, r3, c7, c14, 2 @ clean/flush D entry
224#else 224#else
225 mcr p15, 0, r3, c7, c10, 2 @ clean D entry 225 mcr p15, 0, r3, c7, c6, 2 @ invalidate D entry
226#endif 226#endif
227 subs r3, r3, #1 << 26 227 subs r3, r3, #1 << 26
228 bcs 2b @ entries 63 to 0 228 bcs 2b @ entries 63 to 0
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
index 2218b0c01330..82d579ac9b98 100644
--- a/arch/arm/mm/proc-arm946.S
+++ b/arch/arm/mm/proc-arm946.S
@@ -265,7 +265,7 @@ ENTRY(arm946_dma_flush_range)
265#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 265#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
266 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 266 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
267#else 267#else
268 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 268 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
269#endif 269#endif
270 add r0, r0, #CACHE_DLINESIZE 270 add r0, r0, #CACHE_DLINESIZE
271 cmp r0, r1 271 cmp r0, r1
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
index a02c1712b52d..f2e5884c513a 100644
--- a/arch/arm/mm/proc-feroceon.S
+++ b/arch/arm/mm/proc-feroceon.S
@@ -44,11 +44,31 @@
44 */ 44 */
45#define CACHE_DLINESIZE 32 45#define CACHE_DLINESIZE 32
46 46
47 .bss
48 .align 3
49__cache_params_loc:
50 .space 8
51
47 .text 52 .text
53__cache_params:
54 .word __cache_params_loc
55
48/* 56/*
49 * cpu_feroceon_proc_init() 57 * cpu_feroceon_proc_init()
50 */ 58 */
51ENTRY(cpu_feroceon_proc_init) 59ENTRY(cpu_feroceon_proc_init)
60 mrc p15, 0, r0, c0, c0, 1 @ read cache type register
61 ldr r1, __cache_params
62 mov r2, #(16 << 5)
63 tst r0, #(1 << 16) @ get way
64 mov r0, r0, lsr #18 @ get cache size order
65 movne r3, #((4 - 1) << 30) @ 4-way
66 and r0, r0, #0xf
67 moveq r3, #0 @ 1-way
68 mov r2, r2, lsl r0 @ actual cache size
69 movne r2, r2, lsr #2 @ turned into # of sets
70 sub r2, r2, #(1 << 5)
71 stmia r1, {r2, r3}
52 mov pc, lr 72 mov pc, lr
53 73
54/* 74/*
@@ -59,6 +79,13 @@ ENTRY(cpu_feroceon_proc_fin)
59 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE 79 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
60 msr cpsr_c, ip 80 msr cpsr_c, ip
61 bl feroceon_flush_kern_cache_all 81 bl feroceon_flush_kern_cache_all
82
83#if defined(CONFIG_CACHE_FEROCEON_L2) && !defined(CONFIG_L2_CACHE_WRITETHROUGH)
84 mov r0, #0
85 mcr p15, 1, r0, c15, c9, 0 @ clean L2
86 mcr p15, 0, r0, c7, c10, 4 @ drain WB
87#endif
88
62 mrc p15, 0, r0, c1, c0, 0 @ ctrl register 89 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
63 bic r0, r0, #0x1000 @ ...i............ 90 bic r0, r0, #0x1000 @ ...i............
64 bic r0, r0, #0x000e @ ............wca. 91 bic r0, r0, #0x000e @ ............wca.
@@ -117,11 +144,19 @@ ENTRY(feroceon_flush_user_cache_all)
117 */ 144 */
118ENTRY(feroceon_flush_kern_cache_all) 145ENTRY(feroceon_flush_kern_cache_all)
119 mov r2, #VM_EXEC 146 mov r2, #VM_EXEC
120 mov ip, #0 147
121__flush_whole_cache: 148__flush_whole_cache:
1221: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate 149 ldr r1, __cache_params
123 bne 1b 150 ldmia r1, {r1, r3}
1511: orr ip, r1, r3
1522: mcr p15, 0, ip, c7, c14, 2 @ clean + invalidate D set/way
153 subs ip, ip, #(1 << 30) @ next way
154 bcs 2b
155 subs r1, r1, #(1 << 5) @ next set
156 bcs 1b
157
124 tst r2, #VM_EXEC 158 tst r2, #VM_EXEC
159 mov ip, #0
125 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache 160 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
126 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 161 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
127 mov pc, lr 162 mov pc, lr
@@ -138,7 +173,6 @@ __flush_whole_cache:
138 */ 173 */
139 .align 5 174 .align 5
140ENTRY(feroceon_flush_user_cache_range) 175ENTRY(feroceon_flush_user_cache_range)
141 mov ip, #0
142 sub r3, r1, r0 @ calculate total size 176 sub r3, r1, r0 @ calculate total size
143 cmp r3, #CACHE_DLIMIT 177 cmp r3, #CACHE_DLIMIT
144 bgt __flush_whole_cache 178 bgt __flush_whole_cache
@@ -152,6 +186,7 @@ ENTRY(feroceon_flush_user_cache_range)
152 cmp r0, r1 186 cmp r0, r1
153 blo 1b 187 blo 1b
154 tst r2, #VM_EXEC 188 tst r2, #VM_EXEC
189 mov ip, #0
155 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 190 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
156 mov pc, lr 191 mov pc, lr
157 192
@@ -209,6 +244,20 @@ ENTRY(feroceon_flush_kern_dcache_page)
209 mcr p15, 0, r0, c7, c10, 4 @ drain WB 244 mcr p15, 0, r0, c7, c10, 4 @ drain WB
210 mov pc, lr 245 mov pc, lr
211 246
247 .align 5
248ENTRY(feroceon_range_flush_kern_dcache_page)
249 mrs r2, cpsr
250 add r1, r0, #PAGE_SZ - CACHE_DLINESIZE @ top addr is inclusive
251 orr r3, r2, #PSR_I_BIT
252 msr cpsr_c, r3 @ disable interrupts
253 mcr p15, 5, r0, c15, c15, 0 @ D clean/inv range start
254 mcr p15, 5, r1, c15, c15, 1 @ D clean/inv range top
255 msr cpsr_c, r2 @ restore interrupts
256 mov r0, #0
257 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
258 mcr p15, 0, r0, c7, c10, 4 @ drain WB
259 mov pc, lr
260
212/* 261/*
213 * dma_inv_range(start, end) 262 * dma_inv_range(start, end)
214 * 263 *
@@ -225,10 +274,10 @@ ENTRY(feroceon_flush_kern_dcache_page)
225 .align 5 274 .align 5
226ENTRY(feroceon_dma_inv_range) 275ENTRY(feroceon_dma_inv_range)
227 tst r0, #CACHE_DLINESIZE - 1 276 tst r0, #CACHE_DLINESIZE - 1
277 bic r0, r0, #CACHE_DLINESIZE - 1
228 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 278 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
229 tst r1, #CACHE_DLINESIZE - 1 279 tst r1, #CACHE_DLINESIZE - 1
230 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 280 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
231 bic r0, r0, #CACHE_DLINESIZE - 1
2321: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 2811: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
233 add r0, r0, #CACHE_DLINESIZE 282 add r0, r0, #CACHE_DLINESIZE
234 cmp r0, r1 283 cmp r0, r1
@@ -236,6 +285,22 @@ ENTRY(feroceon_dma_inv_range)
236 mcr p15, 0, r0, c7, c10, 4 @ drain WB 285 mcr p15, 0, r0, c7, c10, 4 @ drain WB
237 mov pc, lr 286 mov pc, lr
238 287
288 .align 5
289ENTRY(feroceon_range_dma_inv_range)
290 mrs r2, cpsr
291 tst r0, #CACHE_DLINESIZE - 1
292 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
293 tst r1, #CACHE_DLINESIZE - 1
294 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
295 cmp r1, r0
296 subne r1, r1, #1 @ top address is inclusive
297 orr r3, r2, #PSR_I_BIT
298 msr cpsr_c, r3 @ disable interrupts
299 mcr p15, 5, r0, c15, c14, 0 @ D inv range start
300 mcr p15, 5, r1, c15, c14, 1 @ D inv range top
301 msr cpsr_c, r2 @ restore interrupts
302 mov pc, lr
303
239/* 304/*
240 * dma_clean_range(start, end) 305 * dma_clean_range(start, end)
241 * 306 *
@@ -256,6 +321,19 @@ ENTRY(feroceon_dma_clean_range)
256 mcr p15, 0, r0, c7, c10, 4 @ drain WB 321 mcr p15, 0, r0, c7, c10, 4 @ drain WB
257 mov pc, lr 322 mov pc, lr
258 323
324 .align 5
325ENTRY(feroceon_range_dma_clean_range)
326 mrs r2, cpsr
327 cmp r1, r0
328 subne r1, r1, #1 @ top address is inclusive
329 orr r3, r2, #PSR_I_BIT
330 msr cpsr_c, r3 @ disable interrupts
331 mcr p15, 5, r0, c15, c13, 0 @ D clean range start
332 mcr p15, 5, r1, c15, c13, 1 @ D clean range top
333 msr cpsr_c, r2 @ restore interrupts
334 mcr p15, 0, r0, c7, c10, 4 @ drain WB
335 mov pc, lr
336
259/* 337/*
260 * dma_flush_range(start, end) 338 * dma_flush_range(start, end)
261 * 339 *
@@ -274,6 +352,19 @@ ENTRY(feroceon_dma_flush_range)
274 mcr p15, 0, r0, c7, c10, 4 @ drain WB 352 mcr p15, 0, r0, c7, c10, 4 @ drain WB
275 mov pc, lr 353 mov pc, lr
276 354
355 .align 5
356ENTRY(feroceon_range_dma_flush_range)
357 mrs r2, cpsr
358 cmp r1, r0
359 subne r1, r1, #1 @ top address is inclusive
360 orr r3, r2, #PSR_I_BIT
361 msr cpsr_c, r3 @ disable interrupts
362 mcr p15, 5, r0, c15, c15, 0 @ D clean/inv range start
363 mcr p15, 5, r1, c15, c15, 1 @ D clean/inv range top
364 msr cpsr_c, r2 @ restore interrupts
365 mcr p15, 0, r0, c7, c10, 4 @ drain WB
366 mov pc, lr
367
277ENTRY(feroceon_cache_fns) 368ENTRY(feroceon_cache_fns)
278 .long feroceon_flush_kern_cache_all 369 .long feroceon_flush_kern_cache_all
279 .long feroceon_flush_user_cache_all 370 .long feroceon_flush_user_cache_all
@@ -285,12 +376,33 @@ ENTRY(feroceon_cache_fns)
285 .long feroceon_dma_clean_range 376 .long feroceon_dma_clean_range
286 .long feroceon_dma_flush_range 377 .long feroceon_dma_flush_range
287 378
379ENTRY(feroceon_range_cache_fns)
380 .long feroceon_flush_kern_cache_all
381 .long feroceon_flush_user_cache_all
382 .long feroceon_flush_user_cache_range
383 .long feroceon_coherent_kern_range
384 .long feroceon_coherent_user_range
385 .long feroceon_range_flush_kern_dcache_page
386 .long feroceon_range_dma_inv_range
387 .long feroceon_range_dma_clean_range
388 .long feroceon_range_dma_flush_range
389
288 .align 5 390 .align 5
289ENTRY(cpu_feroceon_dcache_clean_area) 391ENTRY(cpu_feroceon_dcache_clean_area)
392#if defined(CONFIG_CACHE_FEROCEON_L2) && !defined(CONFIG_L2_CACHE_WRITETHROUGH)
393 mov r2, r0
394 mov r3, r1
395#endif
2901: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 3961: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
291 add r0, r0, #CACHE_DLINESIZE 397 add r0, r0, #CACHE_DLINESIZE
292 subs r1, r1, #CACHE_DLINESIZE 398 subs r1, r1, #CACHE_DLINESIZE
293 bhi 1b 399 bhi 1b
400#if defined(CONFIG_CACHE_FEROCEON_L2) && !defined(CONFIG_L2_CACHE_WRITETHROUGH)
4011: mcr p15, 1, r2, c15, c9, 1 @ clean L2 entry
402 add r2, r2, #CACHE_DLINESIZE
403 subs r3, r3, #CACHE_DLINESIZE
404 bhi 1b
405#endif
294 mcr p15, 0, r0, c7, c10, 4 @ drain WB 406 mcr p15, 0, r0, c7, c10, 4 @ drain WB
295 mov pc, lr 407 mov pc, lr
296 408
@@ -306,16 +418,25 @@ ENTRY(cpu_feroceon_dcache_clean_area)
306 .align 5 418 .align 5
307ENTRY(cpu_feroceon_switch_mm) 419ENTRY(cpu_feroceon_switch_mm)
308#ifdef CONFIG_MMU 420#ifdef CONFIG_MMU
309 mov ip, #0 421 /*
310@ && 'Clean & Invalidate whole DCache' 422 * Note: we wish to call __flush_whole_cache but we need to preserve
3111: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate 423 * lr to do so. The only way without touching main memory is to
312 bne 1b 424 * use r2 which is normally used to test the VM_EXEC flag, and
313 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache 425 * compensate locally for the skipped ops if it is not set.
314 mcr p15, 0, ip, c7, c10, 4 @ drain WB 426 */
427 mov r2, lr @ abuse r2 to preserve lr
428 bl __flush_whole_cache
429 @ if r2 contains the VM_EXEC bit then the next 2 ops are done already
430 tst r2, #VM_EXEC
431 mcreq p15, 0, ip, c7, c5, 0 @ invalidate I cache
432 mcreq p15, 0, ip, c7, c10, 4 @ drain WB
433
315 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer 434 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
316 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 435 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
317#endif 436 mov pc, r2
437#else
318 mov pc, lr 438 mov pc, lr
439#endif
319 440
320/* 441/*
321 * cpu_feroceon_set_pte_ext(ptep, pte, ext) 442 * cpu_feroceon_set_pte_ext(ptep, pte, ext)
@@ -345,6 +466,9 @@ ENTRY(cpu_feroceon_set_pte_ext)
345 str r2, [r0] @ hardware version 466 str r2, [r0] @ hardware version
346 mov r0, r0 467 mov r0, r0
347 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 468 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
469#if defined(CONFIG_CACHE_FEROCEON_L2) && !defined(CONFIG_L2_CACHE_WRITETHROUGH)
470 mcr p15, 1, r0, c15, c9, 1 @ clean L2 entry
471#endif
348 mcr p15, 0, r0, c7, c10, 4 @ drain WB 472 mcr p15, 0, r0, c7, c10, 4 @ drain WB
349#endif 473#endif
350 mov pc, lr 474 mov pc, lr
@@ -369,14 +493,15 @@ __feroceon_setup:
369 .size __feroceon_setup, . - __feroceon_setup 493 .size __feroceon_setup, . - __feroceon_setup
370 494
371 /* 495 /*
372 * R 496 * B
373 * .RVI ZFRS BLDP WCAM 497 * R P
374 * .011 0001 ..11 0101 498 * .RVI UFRS BLDP WCAM
499 * .011 .001 ..11 0101
375 * 500 *
376 */ 501 */
377 .type feroceon_crval, #object 502 .type feroceon_crval, #object
378feroceon_crval: 503feroceon_crval:
379 crval clear=0x00007f3f, mmuset=0x00003135, ucset=0x00001134 504 crval clear=0x0000773f, mmuset=0x00003135, ucset=0x00001134
380 505
381 __INITDATA 506 __INITDATA
382 507
@@ -414,6 +539,21 @@ cpu_feroceon_name:
414 .asciz "Feroceon" 539 .asciz "Feroceon"
415 .size cpu_feroceon_name, . - cpu_feroceon_name 540 .size cpu_feroceon_name, . - cpu_feroceon_name
416 541
542 .type cpu_88fr531_name, #object
543cpu_88fr531_name:
544 .asciz "Feroceon 88FR531-vd"
545 .size cpu_88fr531_name, . - cpu_88fr531_name
546
547 .type cpu_88fr571_name, #object
548cpu_88fr571_name:
549 .asciz "Feroceon 88FR571-vd"
550 .size cpu_88fr571_name, . - cpu_88fr571_name
551
552 .type cpu_88fr131_name, #object
553cpu_88fr131_name:
554 .asciz "Feroceon 88FR131"
555 .size cpu_88fr131_name, . - cpu_88fr131_name
556
417 .align 557 .align
418 558
419 .section ".proc.info.init", #alloc, #execinstr 559 .section ".proc.info.init", #alloc, #execinstr
@@ -421,15 +561,15 @@ cpu_feroceon_name:
421#ifdef CONFIG_CPU_FEROCEON_OLD_ID 561#ifdef CONFIG_CPU_FEROCEON_OLD_ID
422 .type __feroceon_old_id_proc_info,#object 562 .type __feroceon_old_id_proc_info,#object
423__feroceon_old_id_proc_info: 563__feroceon_old_id_proc_info:
424 .long 0x41069260 564 .long 0x41009260
425 .long 0xfffffff0 565 .long 0xff00fff0
426 .long PMD_TYPE_SECT | \ 566 .long PMD_TYPE_SECT | \
427 PMD_SECT_BUFFERABLE | \ 567 PMD_SECT_BUFFERABLE | \
428 PMD_SECT_CACHEABLE | \ 568 PMD_SECT_CACHEABLE | \
429 PMD_BIT4 | \ 569 PMD_BIT4 | \
430 PMD_SECT_AP_WRITE | \ 570 PMD_SECT_AP_WRITE | \
431 PMD_SECT_AP_READ 571 PMD_SECT_AP_READ
432 .long PMD_TYPE_SECT | \ 572 .long PMD_TYPE_SECT | \
433 PMD_BIT4 | \ 573 PMD_BIT4 | \
434 PMD_SECT_AP_WRITE | \ 574 PMD_SECT_AP_WRITE | \
435 PMD_SECT_AP_READ 575 PMD_SECT_AP_READ
@@ -445,17 +585,17 @@ __feroceon_old_id_proc_info:
445 .size __feroceon_old_id_proc_info, . - __feroceon_old_id_proc_info 585 .size __feroceon_old_id_proc_info, . - __feroceon_old_id_proc_info
446#endif 586#endif
447 587
448 .type __feroceon_proc_info,#object 588 .type __88fr531_proc_info,#object
449__feroceon_proc_info: 589__88fr531_proc_info:
450 .long 0x56055310 590 .long 0x56055310
451 .long 0xfffffff0 591 .long 0xfffffff0
452 .long PMD_TYPE_SECT | \ 592 .long PMD_TYPE_SECT | \
453 PMD_SECT_BUFFERABLE | \ 593 PMD_SECT_BUFFERABLE | \
454 PMD_SECT_CACHEABLE | \ 594 PMD_SECT_CACHEABLE | \
455 PMD_BIT4 | \ 595 PMD_BIT4 | \
456 PMD_SECT_AP_WRITE | \ 596 PMD_SECT_AP_WRITE | \
457 PMD_SECT_AP_READ 597 PMD_SECT_AP_READ
458 .long PMD_TYPE_SECT | \ 598 .long PMD_TYPE_SECT | \
459 PMD_BIT4 | \ 599 PMD_BIT4 | \
460 PMD_SECT_AP_WRITE | \ 600 PMD_SECT_AP_WRITE | \
461 PMD_SECT_AP_READ 601 PMD_SECT_AP_READ
@@ -463,9 +603,59 @@ __feroceon_proc_info:
463 .long cpu_arch_name 603 .long cpu_arch_name
464 .long cpu_elf_name 604 .long cpu_elf_name
465 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP 605 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
466 .long cpu_feroceon_name 606 .long cpu_88fr531_name
467 .long feroceon_processor_functions 607 .long feroceon_processor_functions
468 .long v4wbi_tlb_fns 608 .long v4wbi_tlb_fns
469 .long feroceon_user_fns 609 .long feroceon_user_fns
470 .long feroceon_cache_fns 610 .long feroceon_cache_fns
471 .size __feroceon_proc_info, . - __feroceon_proc_info 611 .size __88fr531_proc_info, . - __88fr531_proc_info
612
613 .type __88fr571_proc_info,#object
614__88fr571_proc_info:
615 .long 0x56155710
616 .long 0xfffffff0
617 .long PMD_TYPE_SECT | \
618 PMD_SECT_BUFFERABLE | \
619 PMD_SECT_CACHEABLE | \
620 PMD_BIT4 | \
621 PMD_SECT_AP_WRITE | \
622 PMD_SECT_AP_READ
623 .long PMD_TYPE_SECT | \
624 PMD_BIT4 | \
625 PMD_SECT_AP_WRITE | \
626 PMD_SECT_AP_READ
627 b __feroceon_setup
628 .long cpu_arch_name
629 .long cpu_elf_name
630 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
631 .long cpu_88fr571_name
632 .long feroceon_processor_functions
633 .long v4wbi_tlb_fns
634 .long feroceon_user_fns
635 .long feroceon_range_cache_fns
636 .size __88fr571_proc_info, . - __88fr571_proc_info
637
638 .type __88fr131_proc_info,#object
639__88fr131_proc_info:
640 .long 0x56251310
641 .long 0xfffffff0
642 .long PMD_TYPE_SECT | \
643 PMD_SECT_BUFFERABLE | \
644 PMD_SECT_CACHEABLE | \
645 PMD_BIT4 | \
646 PMD_SECT_AP_WRITE | \
647 PMD_SECT_AP_READ
648 .long PMD_TYPE_SECT | \
649 PMD_BIT4 | \
650 PMD_SECT_AP_WRITE | \
651 PMD_SECT_AP_READ
652 b __feroceon_setup
653 .long cpu_arch_name
654 .long cpu_elf_name
655 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
656 .long cpu_88fr131_name
657 .long feroceon_processor_functions
658 .long v4wbi_tlb_fns
659 .long feroceon_user_fns
660 .long feroceon_range_cache_fns
661 .size __88fr131_proc_info, . - __88fr131_proc_info