1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _M68K_CACHEFLUSH_H
3 #define _M68K_CACHEFLUSH_H
4 
5 #include <linux/mm.h>
6 #ifdef CONFIG_COLDFIRE
7 #include <asm/mcfsim.h>
8 #endif
9 
10 /* cache code */
11 #define FLUSH_I_AND_D	(0x00000808)
12 #define FLUSH_I		(0x00000008)
13 
14 #ifndef ICACHE_MAX_ADDR
15 #define ICACHE_MAX_ADDR	0
16 #define ICACHE_SET_MASK	0
17 #define DCACHE_MAX_ADDR	0
18 #define DCACHE_SETMASK	0
19 #endif
20 #ifndef CACHE_MODE
21 #define	CACHE_MODE	0
22 #define	CACR_ICINVA	0
23 #define	CACR_DCINVA	0
24 #define	CACR_BCINVA	0
25 #endif
26 
27 /*
28  * ColdFire architecture has no way to clear individual cache lines, so we
29  * are stuck invalidating all the cache entries when we want a clear operation.
30  */
31 static inline void clear_cf_icache(unsigned long start, unsigned long end)
32 {
33 	__asm__ __volatile__ (
34 		"movec	%0,%%cacr\n\t"
35 		"nop"
36 		:
37 		: "r" (CACHE_MODE | CACR_ICINVA | CACR_BCINVA));
38 }
39 
40 static inline void clear_cf_dcache(unsigned long start, unsigned long end)
41 {
42 	__asm__ __volatile__ (
43 		"movec	%0,%%cacr\n\t"
44 		"nop"
45 		:
46 		: "r" (CACHE_MODE | CACR_DCINVA));
47 }
48 
49 static inline void clear_cf_bcache(unsigned long start, unsigned long end)
50 {
51 	__asm__ __volatile__ (
52 		"movec	%0,%%cacr\n\t"
53 		"nop"
54 		:
55 		: "r" (CACHE_MODE | CACR_ICINVA | CACR_BCINVA | CACR_DCINVA));
56 }
57 
58 /*
59  * Use the ColdFire cpushl instruction to push (and invalidate) cache lines.
60  * The start and end addresses are cache line numbers not memory addresses.
61  */
62 static inline void flush_cf_icache(unsigned long start, unsigned long end)
63 {
64 	unsigned long set;
65 
66 	for (set = start; set <= end; set += (0x10 - 3)) {
67 		__asm__ __volatile__ (
68 			"cpushl %%ic,(%0)\n\t"
69 			"addq%.l #1,%0\n\t"
70 			"cpushl %%ic,(%0)\n\t"
71 			"addq%.l #1,%0\n\t"
72 			"cpushl %%ic,(%0)\n\t"
73 			"addq%.l #1,%0\n\t"
74 			"cpushl %%ic,(%0)"
75 			: "=a" (set)
76 			: "a" (set));
77 	}
78 }
79 
80 static inline void flush_cf_dcache(unsigned long start, unsigned long end)
81 {
82 	unsigned long set;
83 
84 	for (set = start; set <= end; set += (0x10 - 3)) {
85 		__asm__ __volatile__ (
86 			"cpushl %%dc,(%0)\n\t"
87 			"addq%.l #1,%0\n\t"
88 			"cpushl %%dc,(%0)\n\t"
89 			"addq%.l #1,%0\n\t"
90 			"cpushl %%dc,(%0)\n\t"
91 			"addq%.l #1,%0\n\t"
92 			"cpushl %%dc,(%0)"
93 			: "=a" (set)
94 			: "a" (set));
95 	}
96 }
97 
98 static inline void flush_cf_bcache(unsigned long start, unsigned long end)
99 {
100 	unsigned long set;
101 
102 	for (set = start; set <= end; set += (0x10 - 3)) {
103 		__asm__ __volatile__ (
104 			"cpushl %%bc,(%0)\n\t"
105 			"addq%.l #1,%0\n\t"
106 			"cpushl %%bc,(%0)\n\t"
107 			"addq%.l #1,%0\n\t"
108 			"cpushl %%bc,(%0)\n\t"
109 			"addq%.l #1,%0\n\t"
110 			"cpushl %%bc,(%0)"
111 			: "=a" (set)
112 			: "a" (set));
113 	}
114 }
115 
116 /*
117  * Cache handling functions
118  */
119 
120 static inline void flush_icache(void)
121 {
122 	if (CPU_IS_COLDFIRE) {
123 		flush_cf_icache(0, ICACHE_MAX_ADDR);
124 	} else if (CPU_IS_040_OR_060) {
125 		asm volatile (	"nop\n"
126 			"	.chip	68040\n"
127 			"	cpusha	%bc\n"
128 			"	.chip	68k");
129 	} else {
130 		unsigned long tmp;
131 		asm volatile (	"movec	%%cacr,%0\n"
132 			"	or.w	%1,%0\n"
133 			"	movec	%0,%%cacr"
134 			: "=&d" (tmp)
135 			: "id" (FLUSH_I));
136 	}
137 }
138 
139 /*
140  * invalidate the cache for the specified memory range.
141  * It starts at the physical address specified for
142  * the given number of bytes.
143  */
144 extern void cache_clear(unsigned long paddr, int len);
145 /*
146  * push any dirty cache in the specified memory range.
147  * It starts at the physical address specified for
148  * the given number of bytes.
149  */
150 extern void cache_push(unsigned long paddr, int len);
151 
152 /*
153  * push and invalidate pages in the specified user virtual
154  * memory range.
155  */
156 extern void cache_push_v(unsigned long vaddr, int len);
157 
158 /* This is needed whenever the virtual mapping of the current
159    process changes.  */
160 #define __flush_cache_all()					\
161 ({								\
162 	if (CPU_IS_COLDFIRE) {					\
163 		flush_cf_dcache(0, DCACHE_MAX_ADDR);		\
164 	} else if (CPU_IS_040_OR_060) {				\
165 		__asm__ __volatile__("nop\n\t"			\
166 				     ".chip 68040\n\t"		\
167 				     "cpusha %dc\n\t"		\
168 				     ".chip 68k");		\
169 	} else {						\
170 		unsigned long _tmp;				\
171 		__asm__ __volatile__("movec %%cacr,%0\n\t"	\
172 				     "orw %1,%0\n\t"		\
173 				     "movec %0,%%cacr"		\
174 				     : "=&d" (_tmp)		\
175 				     : "di" (FLUSH_I_AND_D));	\
176 	}							\
177 })
178 
179 #define __flush_cache_030()					\
180 ({								\
181 	if (CPU_IS_020_OR_030) {				\
182 		unsigned long _tmp;				\
183 		__asm__ __volatile__("movec %%cacr,%0\n\t"	\
184 				     "orw %1,%0\n\t"		\
185 				     "movec %0,%%cacr"		\
186 				     : "=&d" (_tmp)		\
187 				     : "di" (FLUSH_I_AND_D));	\
188 	}							\
189 })
190 
191 #define flush_cache_all() __flush_cache_all()
192 
193 #define flush_cache_vmap(start, end)		flush_cache_all()
194 #define flush_cache_vunmap(start, end)		flush_cache_all()
195 
196 static inline void flush_cache_mm(struct mm_struct *mm)
197 {
198 	if (mm == current->mm)
199 		__flush_cache_030();
200 }
201 
202 #define flush_cache_dup_mm(mm)			flush_cache_mm(mm)
203 
204 /* flush_cache_range/flush_cache_page must be macros to avoid
205    a dependency on linux/mm.h, which includes this file... */
206 static inline void flush_cache_range(struct vm_area_struct *vma,
207 				     unsigned long start,
208 				     unsigned long end)
209 {
210 	if (vma->vm_mm == current->mm)
211 	        __flush_cache_030();
212 }
213 
214 static inline void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn)
215 {
216 	if (vma->vm_mm == current->mm)
217 	        __flush_cache_030();
218 }
219 
220 
221 /* Push the page at kernel virtual address and clear the icache */
222 /* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
223 static inline void __flush_page_to_ram(void *vaddr)
224 {
225 	if (CPU_IS_COLDFIRE) {
226 		unsigned long addr, start, end;
227 		addr = ((unsigned long) vaddr) & ~(PAGE_SIZE - 1);
228 		start = addr & ICACHE_SET_MASK;
229 		end = (addr + PAGE_SIZE - 1) & ICACHE_SET_MASK;
230 		if (start > end) {
231 			flush_cf_bcache(0, end);
232 			end = ICACHE_MAX_ADDR;
233 		}
234 		flush_cf_bcache(start, end);
235 	} else if (CPU_IS_040_OR_060) {
236 		__asm__ __volatile__("nop\n\t"
237 				     ".chip 68040\n\t"
238 				     "cpushp %%bc,(%0)\n\t"
239 				     ".chip 68k"
240 				     : : "a" (__pa(vaddr)));
241 	} else {
242 		unsigned long _tmp;
243 		__asm__ __volatile__("movec %%cacr,%0\n\t"
244 				     "orw %1,%0\n\t"
245 				     "movec %0,%%cacr"
246 				     : "=&d" (_tmp)
247 				     : "di" (FLUSH_I));
248 	}
249 }
250 
251 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
252 #define flush_dcache_page(page)		__flush_page_to_ram(page_address(page))
253 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
254 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
255 #define flush_icache_page(vma, page)	__flush_page_to_ram(page_address(page))
256 
257 extern void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
258 				    unsigned long addr, int len);
259 extern void flush_icache_range(unsigned long address, unsigned long endaddr);
260 
261 static inline void copy_to_user_page(struct vm_area_struct *vma,
262 				     struct page *page, unsigned long vaddr,
263 				     void *dst, void *src, int len)
264 {
265 	flush_cache_page(vma, vaddr, page_to_pfn(page));
266 	memcpy(dst, src, len);
267 	flush_icache_user_range(vma, page, vaddr, len);
268 }
269 static inline void copy_from_user_page(struct vm_area_struct *vma,
270 				       struct page *page, unsigned long vaddr,
271 				       void *dst, void *src, int len)
272 {
273 	flush_cache_page(vma, vaddr, page_to_pfn(page));
274 	memcpy(dst, src, len);
275 }
276 
277 #endif /* _M68K_CACHEFLUSH_H */
278