aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/Kconfig18
-rw-r--r--arch/arm/mm/Makefile2
-rw-r--r--arch/arm/mm/cache-feroceon-l2.c54
-rw-r--r--arch/arm/mm/cache-xsc3l2.c107
-rw-r--r--arch/arm/mm/dma-mapping.c72
-rw-r--r--arch/arm/mm/flush.c2
-rw-r--r--arch/arm/mm/highmem.c116
-rw-r--r--arch/arm/mm/init.c21
-rw-r--r--arch/arm/mm/mm.h3
-rw-r--r--arch/arm/mm/mmu.c41
-rw-r--r--arch/arm/mm/proc-mohawk.S416
11 files changed, 798 insertions, 54 deletions
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index bc3331863d9d..20979564e7ee 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -358,6 +358,17 @@ config CPU_XSC3
358 select CPU_TLB_V4WBI if MMU 358 select CPU_TLB_V4WBI if MMU
359 select IO_36 359 select IO_36
360 360
361# Marvell PJ1 (Mohawk)
362config CPU_MOHAWK
363 bool
364 select CPU_32v5
365 select CPU_ABRT_EV5T
366 select CPU_PABRT_NOIFAR
367 select CPU_CACHE_VIVT
368 select CPU_CP15_MMU
369 select CPU_TLB_V4WBI if MMU
370 select CPU_COPY_V4WB if MMU
371
361# Feroceon 372# Feroceon
362config CPU_FEROCEON 373config CPU_FEROCEON
363 bool 374 bool
@@ -600,7 +611,7 @@ comment "Processor Features"
600 611
601config ARM_THUMB 612config ARM_THUMB
602 bool "Support Thumb user binaries" 613 bool "Support Thumb user binaries"
603 depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7 || CPU_FEROCEON 614 depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V7 || CPU_FEROCEON
604 default y 615 default y
605 help 616 help
606 Say Y if you want to include kernel support for running user space 617 Say Y if you want to include kernel support for running user space
@@ -684,7 +695,7 @@ config CPU_CACHE_ROUND_ROBIN
684 695
685config CPU_BPREDICT_DISABLE 696config CPU_BPREDICT_DISABLE
686 bool "Disable branch prediction" 697 bool "Disable branch prediction"
687 depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7 || CPU_FA526 698 depends on CPU_ARM1020 || CPU_V6 || CPU_MOHAWK || CPU_XSC3 || CPU_V7 || CPU_FA526
688 help 699 help
689 Say Y here to disable branch prediction. If unsure, say N. 700 Say Y here to disable branch prediction. If unsure, say N.
690 701
@@ -735,7 +746,8 @@ config CACHE_FEROCEON_L2_WRITETHROUGH
735 746
736config CACHE_L2X0 747config CACHE_L2X0
737 bool "Enable the L2x0 outer cache controller" 748 bool "Enable the L2x0 outer cache controller"
738 depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || REALVIEW_EB_A9MP 749 depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \
750 REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31
739 default y 751 default y
740 select OUTER_CACHE 752 select OUTER_CACHE
741 help 753 help
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 40f941c2245c..63e3f6dd0e21 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MODULES) += proc-syms.o
16 16
17obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o 17obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
18obj-$(CONFIG_DISCONTIGMEM) += discontig.o 18obj-$(CONFIG_DISCONTIGMEM) += discontig.o
19obj-$(CONFIG_HIGHMEM) += highmem.o
19 20
20obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o 21obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o
21obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o 22obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o
@@ -74,6 +75,7 @@ obj-$(CONFIG_CPU_SA110) += proc-sa110.o
74obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o 75obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o
75obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o 76obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o
76obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o 77obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o
78obj-$(CONFIG_CPU_MOHAWK) += proc-mohawk.o
77obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o 79obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o
78obj-$(CONFIG_CPU_V6) += proc-v6.o 80obj-$(CONFIG_CPU_V6) += proc-v6.o
79obj-$(CONFIG_CPU_V7) += proc-v7.o 81obj-$(CONFIG_CPU_V7) += proc-v7.o
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
index 80cd207cbaea..d6dd83826f8a 100644
--- a/arch/arm/mm/cache-feroceon-l2.c
+++ b/arch/arm/mm/cache-feroceon-l2.c
@@ -14,8 +14,12 @@
14 14
15#include <linux/init.h> 15#include <linux/init.h>
16#include <asm/cacheflush.h> 16#include <asm/cacheflush.h>
17#include <asm/kmap_types.h>
18#include <asm/fixmap.h>
19#include <asm/pgtable.h>
20#include <asm/tlbflush.h>
17#include <plat/cache-feroceon-l2.h> 21#include <plat/cache-feroceon-l2.h>
18 22#include "mm.h"
19 23
20/* 24/*
21 * Low-level cache maintenance operations. 25 * Low-level cache maintenance operations.
@@ -34,14 +38,36 @@
34 * The range operations require two successive cp15 writes, in 38 * The range operations require two successive cp15 writes, in
35 * between which we don't want to be preempted. 39 * between which we don't want to be preempted.
36 */ 40 */
41
42static inline unsigned long l2_start_va(unsigned long paddr)
43{
44#ifdef CONFIG_HIGHMEM
45 /*
46 * Let's do our own fixmap stuff in a minimal way here.
47 * Because range ops can't be done on physical addresses,
48 * we simply install a virtual mapping for it only for the
49 * TLB lookup to occur, hence no need to flush the untouched
50 * memory mapping. This is protected with the disabling of
51 * interrupts by the caller.
52 */
53 unsigned long idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
54 unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
55 set_pte_ext(TOP_PTE(vaddr), pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL), 0);
56 local_flush_tlb_kernel_page(vaddr);
57 return vaddr + (paddr & ~PAGE_MASK);
58#else
59 return __phys_to_virt(paddr);
60#endif
61}
62
37static inline void l2_clean_pa(unsigned long addr) 63static inline void l2_clean_pa(unsigned long addr)
38{ 64{
39 __asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr)); 65 __asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr));
40} 66}
41 67
42static inline void l2_clean_mva_range(unsigned long start, unsigned long end) 68static inline void l2_clean_pa_range(unsigned long start, unsigned long end)
43{ 69{
44 unsigned long flags; 70 unsigned long va_start, va_end, flags;
45 71
46 /* 72 /*
47 * Make sure 'start' and 'end' reference the same page, as 73 * Make sure 'start' and 'end' reference the same page, as
@@ -51,17 +77,14 @@ static inline void l2_clean_mva_range(unsigned long start, unsigned long end)
51 BUG_ON((start ^ end) >> PAGE_SHIFT); 77 BUG_ON((start ^ end) >> PAGE_SHIFT);
52 78
53 raw_local_irq_save(flags); 79 raw_local_irq_save(flags);
80 va_start = l2_start_va(start);
81 va_end = va_start + (end - start);
54 __asm__("mcr p15, 1, %0, c15, c9, 4\n\t" 82 __asm__("mcr p15, 1, %0, c15, c9, 4\n\t"
55 "mcr p15, 1, %1, c15, c9, 5" 83 "mcr p15, 1, %1, c15, c9, 5"
56 : : "r" (start), "r" (end)); 84 : : "r" (va_start), "r" (va_end));
57 raw_local_irq_restore(flags); 85 raw_local_irq_restore(flags);
58} 86}
59 87
60static inline void l2_clean_pa_range(unsigned long start, unsigned long end)
61{
62 l2_clean_mva_range(__phys_to_virt(start), __phys_to_virt(end));
63}
64
65static inline void l2_clean_inv_pa(unsigned long addr) 88static inline void l2_clean_inv_pa(unsigned long addr)
66{ 89{
67 __asm__("mcr p15, 1, %0, c15, c10, 3" : : "r" (addr)); 90 __asm__("mcr p15, 1, %0, c15, c10, 3" : : "r" (addr));
@@ -72,9 +95,9 @@ static inline void l2_inv_pa(unsigned long addr)
72 __asm__("mcr p15, 1, %0, c15, c11, 3" : : "r" (addr)); 95 __asm__("mcr p15, 1, %0, c15, c11, 3" : : "r" (addr));
73} 96}
74 97
75static inline void l2_inv_mva_range(unsigned long start, unsigned long end) 98static inline void l2_inv_pa_range(unsigned long start, unsigned long end)
76{ 99{
77 unsigned long flags; 100 unsigned long va_start, va_end, flags;
78 101
79 /* 102 /*
80 * Make sure 'start' and 'end' reference the same page, as 103 * Make sure 'start' and 'end' reference the same page, as
@@ -84,17 +107,14 @@ static inline void l2_inv_mva_range(unsigned long start, unsigned long end)
84 BUG_ON((start ^ end) >> PAGE_SHIFT); 107 BUG_ON((start ^ end) >> PAGE_SHIFT);
85 108
86 raw_local_irq_save(flags); 109 raw_local_irq_save(flags);
110 va_start = l2_start_va(start);
111 va_end = va_start + (end - start);
87 __asm__("mcr p15, 1, %0, c15, c11, 4\n\t" 112 __asm__("mcr p15, 1, %0, c15, c11, 4\n\t"
88 "mcr p15, 1, %1, c15, c11, 5" 113 "mcr p15, 1, %1, c15, c11, 5"
89 : : "r" (start), "r" (end)); 114 : : "r" (va_start), "r" (va_end));
90 raw_local_irq_restore(flags); 115 raw_local_irq_restore(flags);
91} 116}
92 117
93static inline void l2_inv_pa_range(unsigned long start, unsigned long end)
94{
95 l2_inv_mva_range(__phys_to_virt(start), __phys_to_virt(end));
96}
97
98 118
99/* 119/*
100 * Linux primitives. 120 * Linux primitives.
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
index 464de893a988..5d180cb0bd94 100644
--- a/arch/arm/mm/cache-xsc3l2.c
+++ b/arch/arm/mm/cache-xsc3l2.c
@@ -17,12 +17,14 @@
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */ 18 */
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/spinlock.h>
21#include <linux/io.h>
22
23#include <asm/system.h> 20#include <asm/system.h>
24#include <asm/cputype.h> 21#include <asm/cputype.h>
25#include <asm/cacheflush.h> 22#include <asm/cacheflush.h>
23#include <asm/kmap_types.h>
24#include <asm/fixmap.h>
25#include <asm/pgtable.h>
26#include <asm/tlbflush.h>
27#include "mm.h"
26 28
27#define CR_L2 (1 << 26) 29#define CR_L2 (1 << 26)
28 30
@@ -47,21 +49,11 @@ static inline void xsc3_l2_clean_mva(unsigned long addr)
47 __asm__("mcr p15, 1, %0, c7, c11, 1" : : "r" (addr)); 49 __asm__("mcr p15, 1, %0, c7, c11, 1" : : "r" (addr));
48} 50}
49 51
50static inline void xsc3_l2_clean_pa(unsigned long addr)
51{
52 xsc3_l2_clean_mva(__phys_to_virt(addr));
53}
54
55static inline void xsc3_l2_inv_mva(unsigned long addr) 52static inline void xsc3_l2_inv_mva(unsigned long addr)
56{ 53{
57 __asm__("mcr p15, 1, %0, c7, c7, 1" : : "r" (addr)); 54 __asm__("mcr p15, 1, %0, c7, c7, 1" : : "r" (addr));
58} 55}
59 56
60static inline void xsc3_l2_inv_pa(unsigned long addr)
61{
62 xsc3_l2_inv_mva(__phys_to_virt(addr));
63}
64
65static inline void xsc3_l2_inv_all(void) 57static inline void xsc3_l2_inv_all(void)
66{ 58{
67 unsigned long l2ctype, set_way; 59 unsigned long l2ctype, set_way;
@@ -79,50 +71,103 @@ static inline void xsc3_l2_inv_all(void)
79 dsb(); 71 dsb();
80} 72}
81 73
74#ifdef CONFIG_HIGHMEM
75#define l2_map_save_flags(x) raw_local_save_flags(x)
76#define l2_map_restore_flags(x) raw_local_irq_restore(x)
77#else
78#define l2_map_save_flags(x) ((x) = 0)
79#define l2_map_restore_flags(x) ((void)(x))
80#endif
81
82static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va,
83 unsigned long flags)
84{
85#ifdef CONFIG_HIGHMEM
86 unsigned long va = prev_va & PAGE_MASK;
87 unsigned long pa_offset = pa << (32 - PAGE_SHIFT);
88 if (unlikely(pa_offset < (prev_va << (32 - PAGE_SHIFT)))) {
89 /*
90 * Switching to a new page. Because cache ops are
91 * using virtual addresses only, we must put a mapping
92 * in place for it. We also enable interrupts for a
93 * short while and disable them again to protect this
94 * mapping.
95 */
96 unsigned long idx;
97 raw_local_irq_restore(flags);
98 idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
99 va = __fix_to_virt(FIX_KMAP_BEGIN + idx);
100 raw_local_irq_restore(flags | PSR_I_BIT);
101 set_pte_ext(TOP_PTE(va), pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL), 0);
102 local_flush_tlb_kernel_page(va);
103 }
104 return va + (pa_offset >> (32 - PAGE_SHIFT));
105#else
106 return __phys_to_virt(pa);
107#endif
108}
109
82static void xsc3_l2_inv_range(unsigned long start, unsigned long end) 110static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
83{ 111{
112 unsigned long vaddr, flags;
113
84 if (start == 0 && end == -1ul) { 114 if (start == 0 && end == -1ul) {
85 xsc3_l2_inv_all(); 115 xsc3_l2_inv_all();
86 return; 116 return;
87 } 117 }
88 118
119 vaddr = -1; /* to force the first mapping */
120 l2_map_save_flags(flags);
121
89 /* 122 /*
90 * Clean and invalidate partial first cache line. 123 * Clean and invalidate partial first cache line.
91 */ 124 */
92 if (start & (CACHE_LINE_SIZE - 1)) { 125 if (start & (CACHE_LINE_SIZE - 1)) {
93 xsc3_l2_clean_pa(start & ~(CACHE_LINE_SIZE - 1)); 126 vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr, flags);
94 xsc3_l2_inv_pa(start & ~(CACHE_LINE_SIZE - 1)); 127 xsc3_l2_clean_mva(vaddr);
128 xsc3_l2_inv_mva(vaddr);
95 start = (start | (CACHE_LINE_SIZE - 1)) + 1; 129 start = (start | (CACHE_LINE_SIZE - 1)) + 1;
96 } 130 }
97 131
98 /* 132 /*
99 * Clean and invalidate partial last cache line. 133 * Invalidate all full cache lines between 'start' and 'end'.
100 */ 134 */
101 if (start < end && (end & (CACHE_LINE_SIZE - 1))) { 135 while (start < (end & ~(CACHE_LINE_SIZE - 1))) {
102 xsc3_l2_clean_pa(end & ~(CACHE_LINE_SIZE - 1)); 136 vaddr = l2_map_va(start, vaddr, flags);
103 xsc3_l2_inv_pa(end & ~(CACHE_LINE_SIZE - 1)); 137 xsc3_l2_inv_mva(vaddr);
104 end &= ~(CACHE_LINE_SIZE - 1); 138 start += CACHE_LINE_SIZE;
105 } 139 }
106 140
107 /* 141 /*
108 * Invalidate all full cache lines between 'start' and 'end'. 142 * Clean and invalidate partial last cache line.
109 */ 143 */
110 while (start < end) { 144 if (start < end) {
111 xsc3_l2_inv_pa(start); 145 vaddr = l2_map_va(start, vaddr, flags);
112 start += CACHE_LINE_SIZE; 146 xsc3_l2_clean_mva(vaddr);
147 xsc3_l2_inv_mva(vaddr);
113 } 148 }
114 149
150 l2_map_restore_flags(flags);
151
115 dsb(); 152 dsb();
116} 153}
117 154
118static void xsc3_l2_clean_range(unsigned long start, unsigned long end) 155static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
119{ 156{
157 unsigned long vaddr, flags;
158
159 vaddr = -1; /* to force the first mapping */
160 l2_map_save_flags(flags);
161
120 start &= ~(CACHE_LINE_SIZE - 1); 162 start &= ~(CACHE_LINE_SIZE - 1);
121 while (start < end) { 163 while (start < end) {
122 xsc3_l2_clean_pa(start); 164 vaddr = l2_map_va(start, vaddr, flags);
165 xsc3_l2_clean_mva(vaddr);
123 start += CACHE_LINE_SIZE; 166 start += CACHE_LINE_SIZE;
124 } 167 }
125 168
169 l2_map_restore_flags(flags);
170
126 dsb(); 171 dsb();
127} 172}
128 173
@@ -148,18 +193,26 @@ static inline void xsc3_l2_flush_all(void)
148 193
149static void xsc3_l2_flush_range(unsigned long start, unsigned long end) 194static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
150{ 195{
196 unsigned long vaddr, flags;
197
151 if (start == 0 && end == -1ul) { 198 if (start == 0 && end == -1ul) {
152 xsc3_l2_flush_all(); 199 xsc3_l2_flush_all();
153 return; 200 return;
154 } 201 }
155 202
203 vaddr = -1; /* to force the first mapping */
204 l2_map_save_flags(flags);
205
156 start &= ~(CACHE_LINE_SIZE - 1); 206 start &= ~(CACHE_LINE_SIZE - 1);
157 while (start < end) { 207 while (start < end) {
158 xsc3_l2_clean_pa(start); 208 vaddr = l2_map_va(start, vaddr, flags);
159 xsc3_l2_inv_pa(start); 209 xsc3_l2_clean_mva(vaddr);
210 xsc3_l2_inv_mva(vaddr);
160 start += CACHE_LINE_SIZE; 211 start += CACHE_LINE_SIZE;
161 } 212 }
162 213
214 l2_map_restore_flags(flags);
215
163 dsb(); 216 dsb();
164} 217}
165 218
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index f1ef5613ccd4..510c179b0ac8 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -19,6 +19,7 @@
19#include <linux/dma-mapping.h> 19#include <linux/dma-mapping.h>
20 20
21#include <asm/memory.h> 21#include <asm/memory.h>
22#include <asm/highmem.h>
22#include <asm/cacheflush.h> 23#include <asm/cacheflush.h>
23#include <asm/tlbflush.h> 24#include <asm/tlbflush.h>
24#include <asm/sizes.h> 25#include <asm/sizes.h>
@@ -517,6 +518,74 @@ void dma_cache_maint(const void *start, size_t size, int direction)
517} 518}
518EXPORT_SYMBOL(dma_cache_maint); 519EXPORT_SYMBOL(dma_cache_maint);
519 520
521static void dma_cache_maint_contiguous(struct page *page, unsigned long offset,
522 size_t size, int direction)
523{
524 void *vaddr;
525 unsigned long paddr;
526 void (*inner_op)(const void *, const void *);
527 void (*outer_op)(unsigned long, unsigned long);
528
529 switch (direction) {
530 case DMA_FROM_DEVICE: /* invalidate only */
531 inner_op = dmac_inv_range;
532 outer_op = outer_inv_range;
533 break;
534 case DMA_TO_DEVICE: /* writeback only */
535 inner_op = dmac_clean_range;
536 outer_op = outer_clean_range;
537 break;
538 case DMA_BIDIRECTIONAL: /* writeback and invalidate */
539 inner_op = dmac_flush_range;
540 outer_op = outer_flush_range;
541 break;
542 default:
543 BUG();
544 }
545
546 if (!PageHighMem(page)) {
547 vaddr = page_address(page) + offset;
548 inner_op(vaddr, vaddr + size);
549 } else {
550 vaddr = kmap_high_get(page);
551 if (vaddr) {
552 vaddr += offset;
553 inner_op(vaddr, vaddr + size);
554 kunmap_high(page);
555 }
556 }
557
558 paddr = page_to_phys(page) + offset;
559 outer_op(paddr, paddr + size);
560}
561
562void dma_cache_maint_page(struct page *page, unsigned long offset,
563 size_t size, int dir)
564{
565 /*
566 * A single sg entry may refer to multiple physically contiguous
567 * pages. But we still need to process highmem pages individually.
568 * If highmem is not configured then the bulk of this loop gets
569 * optimized out.
570 */
571 size_t left = size;
572 do {
573 size_t len = left;
574 if (PageHighMem(page) && len + offset > PAGE_SIZE) {
575 if (offset >= PAGE_SIZE) {
576 page += offset / PAGE_SIZE;
577 offset %= PAGE_SIZE;
578 }
579 len = PAGE_SIZE - offset;
580 }
581 dma_cache_maint_contiguous(page, offset, len, dir);
582 offset = 0;
583 page++;
584 left -= len;
585 } while (left);
586}
587EXPORT_SYMBOL(dma_cache_maint_page);
588
520/** 589/**
521 * dma_map_sg - map a set of SG buffers for streaming mode DMA 590 * dma_map_sg - map a set of SG buffers for streaming mode DMA
522 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices 591 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
@@ -614,7 +683,8 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
614 continue; 683 continue;
615 684
616 if (!arch_is_coherent()) 685 if (!arch_is_coherent())
617 dma_cache_maint(sg_virt(s), s->length, dir); 686 dma_cache_maint_page(sg_page(s), s->offset,
687 s->length, dir);
618 } 688 }
619} 689}
620EXPORT_SYMBOL(dma_sync_sg_for_device); 690EXPORT_SYMBOL(dma_sync_sg_for_device);
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 0fa9bf388f0b..4e283481cee1 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -192,7 +192,7 @@ void flush_dcache_page(struct page *page)
192 struct address_space *mapping = page_mapping(page); 192 struct address_space *mapping = page_mapping(page);
193 193
194#ifndef CONFIG_SMP 194#ifndef CONFIG_SMP
195 if (mapping && !mapping_mapped(mapping)) 195 if (!PageHighMem(page) && mapping && !mapping_mapped(mapping))
196 set_bit(PG_dcache_dirty, &page->flags); 196 set_bit(PG_dcache_dirty, &page->flags);
197 else 197 else
198#endif 198#endif
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
new file mode 100644
index 000000000000..a34954d9df7d
--- /dev/null
+++ b/arch/arm/mm/highmem.c
@@ -0,0 +1,116 @@
1/*
2 * arch/arm/mm/highmem.c -- ARM highmem support
3 *
4 * Author: Nicolas Pitre
5 * Created: september 8, 2008
6 * Copyright: Marvell Semiconductors Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/highmem.h>
15#include <linux/interrupt.h>
16#include <asm/fixmap.h>
17#include <asm/cacheflush.h>
18#include <asm/tlbflush.h>
19#include "mm.h"
20
21void *kmap(struct page *page)
22{
23 might_sleep();
24 if (!PageHighMem(page))
25 return page_address(page);
26 return kmap_high(page);
27}
28EXPORT_SYMBOL(kmap);
29
30void kunmap(struct page *page)
31{
32 BUG_ON(in_interrupt());
33 if (!PageHighMem(page))
34 return;
35 kunmap_high(page);
36}
37EXPORT_SYMBOL(kunmap);
38
39void *kmap_atomic(struct page *page, enum km_type type)
40{
41 unsigned int idx;
42 unsigned long vaddr;
43
44 pagefault_disable();
45 if (!PageHighMem(page))
46 return page_address(page);
47
48 idx = type + KM_TYPE_NR * smp_processor_id();
49 vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
50#ifdef CONFIG_DEBUG_HIGHMEM
51 /*
52 * With debugging enabled, kunmap_atomic forces that entry to 0.
53 * Make sure it was indeed properly unmapped.
54 */
55 BUG_ON(!pte_none(*(TOP_PTE(vaddr))));
56#endif
57 set_pte_ext(TOP_PTE(vaddr), mk_pte(page, kmap_prot), 0);
58 /*
59 * When debugging is off, kunmap_atomic leaves the previous mapping
60 * in place, so this TLB flush ensures the TLB is updated with the
61 * new mapping.
62 */
63 local_flush_tlb_kernel_page(vaddr);
64
65 return (void *)vaddr;
66}
67EXPORT_SYMBOL(kmap_atomic);
68
69void kunmap_atomic(void *kvaddr, enum km_type type)
70{
71 unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
72 unsigned int idx = type + KM_TYPE_NR * smp_processor_id();
73
74 if (kvaddr >= (void *)FIXADDR_START) {
75 __cpuc_flush_dcache_page((void *)vaddr);
76#ifdef CONFIG_DEBUG_HIGHMEM
77 BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
78 set_pte_ext(TOP_PTE(vaddr), __pte(0), 0);
79 local_flush_tlb_kernel_page(vaddr);
80#else
81 (void) idx; /* to kill a warning */
82#endif
83 }
84 pagefault_enable();
85}
86EXPORT_SYMBOL(kunmap_atomic);
87
88void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
89{
90 unsigned int idx;
91 unsigned long vaddr;
92
93 pagefault_disable();
94
95 idx = type + KM_TYPE_NR * smp_processor_id();
96 vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
97#ifdef CONFIG_DEBUG_HIGHMEM
98 BUG_ON(!pte_none(*(TOP_PTE(vaddr))));
99#endif
100 set_pte_ext(TOP_PTE(vaddr), pfn_pte(pfn, kmap_prot), 0);
101 local_flush_tlb_kernel_page(vaddr);
102
103 return (void *)vaddr;
104}
105
106struct page *kmap_atomic_to_page(const void *ptr)
107{
108 unsigned long vaddr = (unsigned long)ptr;
109 pte_t *pte;
110
111 if (vaddr < FIXADDR_START)
112 return virt_to_page(ptr);
113
114 pte = TOP_PTE(vaddr);
115 return pte_page(*pte);
116}
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 80fd3b69ae1f..8277802ec859 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -15,6 +15,7 @@
15#include <linux/mman.h> 15#include <linux/mman.h>
16#include <linux/nodemask.h> 16#include <linux/nodemask.h>
17#include <linux/initrd.h> 17#include <linux/initrd.h>
18#include <linux/highmem.h>
18 19
19#include <asm/mach-types.h> 20#include <asm/mach-types.h>
20#include <asm/sections.h> 21#include <asm/sections.h>
@@ -485,7 +486,7 @@ void __init mem_init(void)
485 int i, node; 486 int i, node;
486 487
487#ifndef CONFIG_DISCONTIGMEM 488#ifndef CONFIG_DISCONTIGMEM
488 max_mapnr = virt_to_page(high_memory) - mem_map; 489 max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
489#endif 490#endif
490 491
491 /* this will put all unused low memory onto the freelists */ 492 /* this will put all unused low memory onto the freelists */
@@ -504,6 +505,19 @@ void __init mem_init(void)
504 __phys_to_pfn(__pa(swapper_pg_dir)), NULL); 505 __phys_to_pfn(__pa(swapper_pg_dir)), NULL);
505#endif 506#endif
506 507
508#ifdef CONFIG_HIGHMEM
509 /* set highmem page free */
510 for_each_online_node(node) {
511 for_each_nodebank (i, &meminfo, node) {
512 unsigned long start = bank_pfn_start(&meminfo.bank[i]);
513 unsigned long end = bank_pfn_end(&meminfo.bank[i]);
514 if (start >= max_low_pfn + PHYS_PFN_OFFSET)
515 totalhigh_pages += free_area(start, end, NULL);
516 }
517 }
518 totalram_pages += totalhigh_pages;
519#endif
520
507 /* 521 /*
508 * Since our memory may not be contiguous, calculate the 522 * Since our memory may not be contiguous, calculate the
509 * real number of pages we have in this system 523 * real number of pages we have in this system
@@ -521,9 +535,10 @@ void __init mem_init(void)
521 initsize = __init_end - __init_begin; 535 initsize = __init_end - __init_begin;
522 536
523 printk(KERN_NOTICE "Memory: %luKB available (%dK code, " 537 printk(KERN_NOTICE "Memory: %luKB available (%dK code, "
524 "%dK data, %dK init)\n", 538 "%dK data, %dK init, %luK highmem)\n",
525 (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), 539 (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
526 codesize >> 10, datasize >> 10, initsize >> 10); 540 codesize >> 10, datasize >> 10, initsize >> 10,
541 (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
527 542
528 if (PAGE_SIZE >= 16384 && num_physpages <= 128) { 543 if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
529 extern int sysctl_overcommit_memory; 544 extern int sysctl_overcommit_memory;
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index 95bbe112965e..c4f6f05198e0 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -1,7 +1,6 @@
1/* the upper-most page table pointer */
2
3#ifdef CONFIG_MMU 1#ifdef CONFIG_MMU
4 2
3/* the upper-most page table pointer */
5extern pmd_t *top_pmd; 4extern pmd_t *top_pmd;
6 5
7#define TOP_PTE(x) pte_offset_kernel(top_pmd, x) 6#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index d4d082c5c2d4..1585814f8414 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -18,9 +18,11 @@
18#include <asm/cputype.h> 18#include <asm/cputype.h>
19#include <asm/mach-types.h> 19#include <asm/mach-types.h>
20#include <asm/sections.h> 20#include <asm/sections.h>
21#include <asm/cachetype.h>
21#include <asm/setup.h> 22#include <asm/setup.h>
22#include <asm/sizes.h> 23#include <asm/sizes.h>
23#include <asm/tlb.h> 24#include <asm/tlb.h>
25#include <asm/highmem.h>
24 26
25#include <asm/mach/arch.h> 27#include <asm/mach/arch.h>
26#include <asm/mach/map.h> 28#include <asm/mach/map.h>
@@ -243,6 +245,10 @@ static struct mem_type mem_types[] = {
243 .prot_sect = PMD_TYPE_SECT, 245 .prot_sect = PMD_TYPE_SECT,
244 .domain = DOMAIN_KERNEL, 246 .domain = DOMAIN_KERNEL,
245 }, 247 },
248 [MT_MEMORY_NONCACHED] = {
249 .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
250 .domain = DOMAIN_KERNEL,
251 },
246}; 252};
247 253
248const struct mem_type *get_mem_type(unsigned int type) 254const struct mem_type *get_mem_type(unsigned int type)
@@ -406,9 +412,28 @@ static void __init build_mem_type_table(void)
406 kern_pgprot |= L_PTE_SHARED; 412 kern_pgprot |= L_PTE_SHARED;
407 vecs_pgprot |= L_PTE_SHARED; 413 vecs_pgprot |= L_PTE_SHARED;
408 mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; 414 mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
415 mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S;
409#endif 416#endif
410 } 417 }
411 418
419 /*
420 * Non-cacheable Normal - intended for memory areas that must
421 * not cause dirty cache line writebacks when used
422 */
423 if (cpu_arch >= CPU_ARCH_ARMv6) {
424 if (cpu_arch >= CPU_ARCH_ARMv7 && (cr & CR_TRE)) {
425 /* Non-cacheable Normal is XCB = 001 */
426 mem_types[MT_MEMORY_NONCACHED].prot_sect |=
427 PMD_SECT_BUFFERED;
428 } else {
429 /* For both ARMv6 and non-TEX-remapping ARMv7 */
430 mem_types[MT_MEMORY_NONCACHED].prot_sect |=
431 PMD_SECT_TEX(1);
432 }
433 } else {
434 mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE;
435 }
436
412 for (i = 0; i < 16; i++) { 437 for (i = 0; i < 16; i++) {
413 unsigned long v = pgprot_val(protection_map[i]); 438 unsigned long v = pgprot_val(protection_map[i]);
414 protection_map[i] = __pgprot(v | user_pgprot); 439 protection_map[i] = __pgprot(v | user_pgprot);
@@ -677,6 +702,10 @@ static void __init sanity_check_meminfo(void)
677 if (meminfo.nr_banks >= NR_BANKS) { 702 if (meminfo.nr_banks >= NR_BANKS) {
678 printk(KERN_CRIT "NR_BANKS too low, " 703 printk(KERN_CRIT "NR_BANKS too low, "
679 "ignoring high memory\n"); 704 "ignoring high memory\n");
705 } else if (cache_is_vipt_aliasing()) {
706 printk(KERN_CRIT "HIGHMEM is not yet supported "
707 "with VIPT aliasing cache, "
708 "ignoring high memory\n");
680 } else { 709 } else {
681 memmove(bank + 1, bank, 710 memmove(bank + 1, bank,
682 (meminfo.nr_banks - i) * sizeof(*bank)); 711 (meminfo.nr_banks - i) * sizeof(*bank));
@@ -895,6 +924,17 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
895 flush_cache_all(); 924 flush_cache_all();
896} 925}
897 926
927static void __init kmap_init(void)
928{
929#ifdef CONFIG_HIGHMEM
930 pmd_t *pmd = pmd_off_k(PKMAP_BASE);
931 pte_t *pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
932 BUG_ON(!pmd_none(*pmd) || !pte);
933 __pmd_populate(pmd, __pa(pte) | _PAGE_KERNEL_TABLE);
934 pkmap_page_table = pte + PTRS_PER_PTE;
935#endif
936}
937
898/* 938/*
899 * paging_init() sets up the page tables, initialises the zone memory 939 * paging_init() sets up the page tables, initialises the zone memory
900 * maps, and sets up the zero page, bad page and bad page tables. 940 * maps, and sets up the zero page, bad page and bad page tables.
@@ -908,6 +948,7 @@ void __init paging_init(struct machine_desc *mdesc)
908 prepare_page_table(); 948 prepare_page_table();
909 bootmem_init(); 949 bootmem_init();
910 devicemaps_init(mdesc); 950 devicemaps_init(mdesc);
951 kmap_init();
911 952
912 top_pmd = pmd_off_k(0xffff0000); 953 top_pmd = pmd_off_k(0xffff0000);
913 954
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
new file mode 100644
index 000000000000..540f5078496b
--- /dev/null
+++ b/arch/arm/mm/proc-mohawk.S
@@ -0,0 +1,416 @@
1/*
2 * linux/arch/arm/mm/proc-mohawk.S: MMU functions for Marvell PJ1 core
3 *
4 * PJ1 (codename Mohawk) is a hybrid of the xscale3 and Marvell's own core.
5 *
6 * Heavily based on proc-arm926.S and proc-xsc3.S
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <linux/linkage.h>
24#include <linux/init.h>
25#include <asm/assembler.h>
26#include <asm/hwcap.h>
27#include <asm/pgtable-hwdef.h>
28#include <asm/pgtable.h>
29#include <asm/page.h>
30#include <asm/ptrace.h>
31#include "proc-macros.S"
32
33/*
34 * This is the maximum size of an area which will be flushed. If the
35 * area is larger than this, then we flush the whole cache.
36 */
37#define CACHE_DLIMIT 32768
38
39/*
40 * The cache line size of the L1 D cache.
41 */
42#define CACHE_DLINESIZE 32
43
44/*
45 * cpu_mohawk_proc_init()
46 */
47ENTRY(cpu_mohawk_proc_init)
48 mov pc, lr
49
50/*
51 * cpu_mohawk_proc_fin()
52 */
53ENTRY(cpu_mohawk_proc_fin)
54 stmfd sp!, {lr}
55 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
56 msr cpsr_c, ip
57 bl mohawk_flush_kern_cache_all
58 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
59 bic r0, r0, #0x1800 @ ...iz...........
60 bic r0, r0, #0x0006 @ .............ca.
61 mcr p15, 0, r0, c1, c0, 0 @ disable caches
62 ldmfd sp!, {pc}
63
64/*
65 * cpu_mohawk_reset(loc)
66 *
67 * Perform a soft reset of the system. Put the CPU into the
68 * same state as it would be if it had been reset, and branch
69 * to what would be the reset vector.
70 *
71 * loc: location to jump to for soft reset
72 *
73 * (same as arm926)
74 */
75 .align 5
76ENTRY(cpu_mohawk_reset)
77 mov ip, #0
78 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
79 mcr p15, 0, ip, c7, c10, 4 @ drain WB
80 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
81 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
82 bic ip, ip, #0x0007 @ .............cam
83 bic ip, ip, #0x1100 @ ...i...s........
84 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
85 mov pc, r0
86
87/*
88 * cpu_mohawk_do_idle()
89 *
90 * Called with IRQs disabled
91 */
92 .align 5
93ENTRY(cpu_mohawk_do_idle)
94 mov r0, #0
95 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
96 mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
97 mov pc, lr
98
99/*
100 * flush_user_cache_all()
101 *
102 * Clean and invalidate all cache entries in a particular
103 * address space.
104 */
105ENTRY(mohawk_flush_user_cache_all)
106 /* FALLTHROUGH */
107
108/*
109 * flush_kern_cache_all()
110 *
111 * Clean and invalidate the entire cache.
112 */
113ENTRY(mohawk_flush_kern_cache_all)
114 mov r2, #VM_EXEC
115 mov ip, #0
116__flush_whole_cache:
117 mcr p15, 0, ip, c7, c14, 0 @ clean & invalidate all D cache
118 tst r2, #VM_EXEC
119 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
120 mcrne p15, 0, ip, c7, c10, 0 @ drain write buffer
121 mov pc, lr
122
123/*
124 * flush_user_cache_range(start, end, flags)
125 *
126 * Clean and invalidate a range of cache entries in the
127 * specified address range.
128 *
129 * - start - start address (inclusive)
130 * - end - end address (exclusive)
131 * - flags - vm_flags describing address space
132 *
133 * (same as arm926)
134 */
135ENTRY(mohawk_flush_user_cache_range)
136 mov ip, #0
137 sub r3, r1, r0 @ calculate total size
138 cmp r3, #CACHE_DLIMIT
139 bgt __flush_whole_cache
1401: tst r2, #VM_EXEC
141 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
142 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
143 add r0, r0, #CACHE_DLINESIZE
144 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
145 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
146 add r0, r0, #CACHE_DLINESIZE
147 cmp r0, r1
148 blo 1b
149 tst r2, #VM_EXEC
150 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
151 mov pc, lr
152
153/*
154 * coherent_kern_range(start, end)
155 *
156 * Ensure coherency between the Icache and the Dcache in the
157 * region described by start, end. If you have non-snooping
158 * Harvard caches, you need to implement this function.
159 *
160 * - start - virtual start address
161 * - end - virtual end address
162 */
163ENTRY(mohawk_coherent_kern_range)
164 /* FALLTHROUGH */
165
166/*
167 * coherent_user_range(start, end)
168 *
169 * Ensure coherency between the Icache and the Dcache in the
170 * region described by start, end. If you have non-snooping
171 * Harvard caches, you need to implement this function.
172 *
173 * - start - virtual start address
174 * - end - virtual end address
175 *
176 * (same as arm926)
177 */
178ENTRY(mohawk_coherent_user_range)
179 bic r0, r0, #CACHE_DLINESIZE - 1
1801: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
181 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
182 add r0, r0, #CACHE_DLINESIZE
183 cmp r0, r1
184 blo 1b
185 mcr p15, 0, r0, c7, c10, 4 @ drain WB
186 mov pc, lr
187
188/*
189 * flush_kern_dcache_page(void *page)
190 *
191 * Ensure no D cache aliasing occurs, either with itself or
192 * the I cache
193 *
194 * - addr - page aligned address
195 */
196ENTRY(mohawk_flush_kern_dcache_page)
197 add r1, r0, #PAGE_SZ
1981: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
199 add r0, r0, #CACHE_DLINESIZE
200 cmp r0, r1
201 blo 1b
202 mov r0, #0
203 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
204 mcr p15, 0, r0, c7, c10, 4 @ drain WB
205 mov pc, lr
206
207/*
208 * dma_inv_range(start, end)
209 *
210 * Invalidate (discard) the specified virtual address range.
211 * May not write back any entries. If 'start' or 'end'
212 * are not cache line aligned, those lines must be written
213 * back.
214 *
215 * - start - virtual start address
216 * - end - virtual end address
217 *
218 * (same as v4wb)
219 */
220ENTRY(mohawk_dma_inv_range)
221 tst r0, #CACHE_DLINESIZE - 1
222 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
223 tst r1, #CACHE_DLINESIZE - 1
224 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
225 bic r0, r0, #CACHE_DLINESIZE - 1
2261: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
227 add r0, r0, #CACHE_DLINESIZE
228 cmp r0, r1
229 blo 1b
230 mcr p15, 0, r0, c7, c10, 4 @ drain WB
231 mov pc, lr
232
233/*
234 * dma_clean_range(start, end)
235 *
236 * Clean the specified virtual address range.
237 *
238 * - start - virtual start address
239 * - end - virtual end address
240 *
241 * (same as v4wb)
242 */
243ENTRY(mohawk_dma_clean_range)
244 bic r0, r0, #CACHE_DLINESIZE - 1
2451: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
246 add r0, r0, #CACHE_DLINESIZE
247 cmp r0, r1
248 blo 1b
249 mcr p15, 0, r0, c7, c10, 4 @ drain WB
250 mov pc, lr
251
252/*
253 * dma_flush_range(start, end)
254 *
255 * Clean and invalidate the specified virtual address range.
256 *
257 * - start - virtual start address
258 * - end - virtual end address
259 */
260ENTRY(mohawk_dma_flush_range)
261 bic r0, r0, #CACHE_DLINESIZE - 1
2621:
263 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
264 add r0, r0, #CACHE_DLINESIZE
265 cmp r0, r1
266 blo 1b
267 mcr p15, 0, r0, c7, c10, 4 @ drain WB
268 mov pc, lr
269
270ENTRY(mohawk_cache_fns)
271 .long mohawk_flush_kern_cache_all
272 .long mohawk_flush_user_cache_all
273 .long mohawk_flush_user_cache_range
274 .long mohawk_coherent_kern_range
275 .long mohawk_coherent_user_range
276 .long mohawk_flush_kern_dcache_page
277 .long mohawk_dma_inv_range
278 .long mohawk_dma_clean_range
279 .long mohawk_dma_flush_range
280
281ENTRY(cpu_mohawk_dcache_clean_area)
2821: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
283 add r0, r0, #CACHE_DLINESIZE
284 subs r1, r1, #CACHE_DLINESIZE
285 bhi 1b
286 mcr p15, 0, r0, c7, c10, 4 @ drain WB
287 mov pc, lr
288
289/*
290 * cpu_mohawk_switch_mm(pgd)
291 *
292 * Set the translation base pointer to be as described by pgd.
293 *
294 * pgd: new page tables
295 */
296 .align 5
297ENTRY(cpu_mohawk_switch_mm)
298 mov ip, #0
299 mcr p15, 0, ip, c7, c14, 0 @ clean & invalidate all D cache
300 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
301 mcr p15, 0, ip, c7, c10, 4 @ drain WB
302 orr r0, r0, #0x18 @ cache the page table in L2
303 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
304 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
305 mov pc, lr
306
307/*
308 * cpu_mohawk_set_pte_ext(ptep, pte, ext)
309 *
310 * Set a PTE and flush it out
311 */
312 .align 5
313ENTRY(cpu_mohawk_set_pte_ext)
314 armv3_set_pte_ext
315 mov r0, r0
316 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
317 mcr p15, 0, r0, c7, c10, 4 @ drain WB
318 mov pc, lr
319
320 __INIT
321
322 .type __mohawk_setup, #function
323__mohawk_setup:
324 mov r0, #0
325 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches
326 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
327 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs
328 orr r4, r4, #0x18 @ cache the page table in L2
329 mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
330
331 mov r0, #0 @ don't allow CP access
332 mcr p15, 0, r0, c15, c1, 0 @ write CP access register
333
334 adr r5, mohawk_crval
335 ldmia r5, {r5, r6}
336 mrc p15, 0, r0, c1, c0 @ get control register
337 bic r0, r0, r5
338 orr r0, r0, r6
339 mov pc, lr
340
341 .size __mohawk_setup, . - __mohawk_setup
342
343 /*
344 * R
345 * .RVI ZFRS BLDP WCAM
346 * .011 1001 ..00 0101
347 *
348 */
349 .type mohawk_crval, #object
350mohawk_crval:
351 crval clear=0x00007f3f, mmuset=0x00003905, ucset=0x00001134
352
353 __INITDATA
354
355/*
356 * Purpose : Function pointers used to access above functions - all calls
357 * come through these
358 */
359 .type mohawk_processor_functions, #object
360mohawk_processor_functions:
361 .word v5t_early_abort
362 .word pabort_noifar
363 .word cpu_mohawk_proc_init
364 .word cpu_mohawk_proc_fin
365 .word cpu_mohawk_reset
366 .word cpu_mohawk_do_idle
367 .word cpu_mohawk_dcache_clean_area
368 .word cpu_mohawk_switch_mm
369 .word cpu_mohawk_set_pte_ext
370 .size mohawk_processor_functions, . - mohawk_processor_functions
371
372 .section ".rodata"
373
374 .type cpu_arch_name, #object
375cpu_arch_name:
376 .asciz "armv5te"
377 .size cpu_arch_name, . - cpu_arch_name
378
379 .type cpu_elf_name, #object
380cpu_elf_name:
381 .asciz "v5"
382 .size cpu_elf_name, . - cpu_elf_name
383
384 .type cpu_mohawk_name, #object
385cpu_mohawk_name:
386 .asciz "Marvell 88SV331x"
387 .size cpu_mohawk_name, . - cpu_mohawk_name
388
389 .align
390
391 .section ".proc.info.init", #alloc, #execinstr
392
393 .type __88sv331x_proc_info,#object
394__88sv331x_proc_info:
395 .long 0x56158000 @ Marvell 88SV331x (MOHAWK)
396 .long 0xfffff000
397 .long PMD_TYPE_SECT | \
398 PMD_SECT_BUFFERABLE | \
399 PMD_SECT_CACHEABLE | \
400 PMD_BIT4 | \
401 PMD_SECT_AP_WRITE | \
402 PMD_SECT_AP_READ
403 .long PMD_TYPE_SECT | \
404 PMD_BIT4 | \
405 PMD_SECT_AP_WRITE | \
406 PMD_SECT_AP_READ
407 b __mohawk_setup
408 .long cpu_arch_name
409 .long cpu_elf_name
410 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
411 .long cpu_mohawk_name
412 .long mohawk_processor_functions
413 .long v4wbi_tlb_fns
414 .long v4wb_user_fns
415 .long mohawk_cache_fns
416 .size __88sv331x_proc_info, . - __88sv331x_proc_info