1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/mm.h>
3 #include <asm/mmu_context.h>
4 #include <asm/cache_insns.h>
5 #include <asm/cacheflush.h>
6 #include <asm/traps.h>
7 
8 /*
9  * Write back the dirty D-caches, but not invalidate them.
10  *
11  * START: Virtual Address (U0, P1, or P3)
12  * SIZE: Size of the region.
13  */
sh4__flush_wback_region(void * start,int size)14 static void sh4__flush_wback_region(void *start, int size)
15 {
16 	reg_size_t aligned_start, v, cnt, end;
17 
18 	aligned_start = register_align(start);
19 	v = aligned_start & ~(L1_CACHE_BYTES-1);
20 	end = (aligned_start + size + L1_CACHE_BYTES-1)
21 		& ~(L1_CACHE_BYTES-1);
22 	cnt = (end - v) / L1_CACHE_BYTES;
23 
24 	while (cnt >= 8) {
25 		__ocbwb(v); v += L1_CACHE_BYTES;
26 		__ocbwb(v); v += L1_CACHE_BYTES;
27 		__ocbwb(v); v += L1_CACHE_BYTES;
28 		__ocbwb(v); v += L1_CACHE_BYTES;
29 		__ocbwb(v); v += L1_CACHE_BYTES;
30 		__ocbwb(v); v += L1_CACHE_BYTES;
31 		__ocbwb(v); v += L1_CACHE_BYTES;
32 		__ocbwb(v); v += L1_CACHE_BYTES;
33 		cnt -= 8;
34 	}
35 
36 	while (cnt) {
37 		__ocbwb(v); v += L1_CACHE_BYTES;
38 		cnt--;
39 	}
40 }
41 
42 /*
43  * Write back the dirty D-caches and invalidate them.
44  *
45  * START: Virtual Address (U0, P1, or P3)
46  * SIZE: Size of the region.
47  */
sh4__flush_purge_region(void * start,int size)48 static void sh4__flush_purge_region(void *start, int size)
49 {
50 	reg_size_t aligned_start, v, cnt, end;
51 
52 	aligned_start = register_align(start);
53 	v = aligned_start & ~(L1_CACHE_BYTES-1);
54 	end = (aligned_start + size + L1_CACHE_BYTES-1)
55 		& ~(L1_CACHE_BYTES-1);
56 	cnt = (end - v) / L1_CACHE_BYTES;
57 
58 	while (cnt >= 8) {
59 		__ocbp(v); v += L1_CACHE_BYTES;
60 		__ocbp(v); v += L1_CACHE_BYTES;
61 		__ocbp(v); v += L1_CACHE_BYTES;
62 		__ocbp(v); v += L1_CACHE_BYTES;
63 		__ocbp(v); v += L1_CACHE_BYTES;
64 		__ocbp(v); v += L1_CACHE_BYTES;
65 		__ocbp(v); v += L1_CACHE_BYTES;
66 		__ocbp(v); v += L1_CACHE_BYTES;
67 		cnt -= 8;
68 	}
69 	while (cnt) {
70 		__ocbp(v); v += L1_CACHE_BYTES;
71 		cnt--;
72 	}
73 }
74 
75 /*
76  * No write back please
77  */
sh4__flush_invalidate_region(void * start,int size)78 static void sh4__flush_invalidate_region(void *start, int size)
79 {
80 	reg_size_t aligned_start, v, cnt, end;
81 
82 	aligned_start = register_align(start);
83 	v = aligned_start & ~(L1_CACHE_BYTES-1);
84 	end = (aligned_start + size + L1_CACHE_BYTES-1)
85 		& ~(L1_CACHE_BYTES-1);
86 	cnt = (end - v) / L1_CACHE_BYTES;
87 
88 	while (cnt >= 8) {
89 		__ocbi(v); v += L1_CACHE_BYTES;
90 		__ocbi(v); v += L1_CACHE_BYTES;
91 		__ocbi(v); v += L1_CACHE_BYTES;
92 		__ocbi(v); v += L1_CACHE_BYTES;
93 		__ocbi(v); v += L1_CACHE_BYTES;
94 		__ocbi(v); v += L1_CACHE_BYTES;
95 		__ocbi(v); v += L1_CACHE_BYTES;
96 		__ocbi(v); v += L1_CACHE_BYTES;
97 		cnt -= 8;
98 	}
99 
100 	while (cnt) {
101 		__ocbi(v); v += L1_CACHE_BYTES;
102 		cnt--;
103 	}
104 }
105 
sh4__flush_region_init(void)106 void __init sh4__flush_region_init(void)
107 {
108 	__flush_wback_region		= sh4__flush_wback_region;
109 	__flush_invalidate_region	= sh4__flush_invalidate_region;
110 	__flush_purge_region		= sh4__flush_purge_region;
111 }
112