common: Drop net.h from common header
[oweals/u-boot.git] / arch / arm / cpu / armv7m / cache.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
4  * Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics.
5  */
6
7 #include <common.h>
8 #include <cpu_func.h>
9 #include <errno.h>
10 #include <asm/armv7m.h>
11 #include <asm/cache.h>
12 #include <asm/io.h>
13
14 /* Cache maintenance operation registers */
15
16 #define V7M_CACHE_REG_ICIALLU           ((u32 *)(V7M_CACHE_MAINT_BASE + 0x00))
17 #define INVAL_ICACHE_POU                0
18 #define V7M_CACHE_REG_ICIMVALU          ((u32 *)(V7M_CACHE_MAINT_BASE + 0x08))
19 #define V7M_CACHE_REG_DCIMVAC           ((u32 *)(V7M_CACHE_MAINT_BASE + 0x0C))
20 #define V7M_CACHE_REG_DCISW             ((u32 *)(V7M_CACHE_MAINT_BASE + 0x10))
21 #define V7M_CACHE_REG_DCCMVAU           ((u32 *)(V7M_CACHE_MAINT_BASE + 0x14))
22 #define V7M_CACHE_REG_DCCMVAC           ((u32 *)(V7M_CACHE_MAINT_BASE + 0x18))
23 #define V7M_CACHE_REG_DCCSW             ((u32 *)(V7M_CACHE_MAINT_BASE + 0x1C))
24 #define V7M_CACHE_REG_DCCIMVAC          ((u32 *)(V7M_CACHE_MAINT_BASE + 0x20))
25 #define V7M_CACHE_REG_DCCISW            ((u32 *)(V7M_CACHE_MAINT_BASE + 0x24))
26 #define WAYS_SHIFT                      30
27 #define SETS_SHIFT                      5
28
29 /* armv7m processor feature registers */
30
31 #define V7M_PROC_REG_CLIDR              ((u32 *)(V7M_PROC_FTR_BASE + 0x00))
32 #define V7M_PROC_REG_CTR                ((u32 *)(V7M_PROC_FTR_BASE + 0x04))
33 #define V7M_PROC_REG_CCSIDR             ((u32 *)(V7M_PROC_FTR_BASE + 0x08))
34 #define MASK_NUM_WAYS                   GENMASK(12, 3)
35 #define MASK_NUM_SETS                   GENMASK(27, 13)
36 #define CLINE_SIZE_MASK                 GENMASK(2, 0)
37 #define NUM_WAYS_SHIFT                  3
38 #define NUM_SETS_SHIFT                  13
39 #define V7M_PROC_REG_CSSELR             ((u32 *)(V7M_PROC_FTR_BASE + 0x0C))
40 #define SEL_I_OR_D                      BIT(0)
41
42 enum cache_type {
43         DCACHE,
44         ICACHE,
45 };
46
47 /* PoU : Point of Unification, Poc: Point of Coherency */
48 enum cache_action {
49         INVALIDATE_POU,         /* i-cache invalidate by address */
50         INVALIDATE_POC,         /* d-cache invalidate by address */
51         INVALIDATE_SET_WAY,     /* d-cache invalidate by sets/ways */
52         FLUSH_POU,              /* d-cache clean by address to the PoU */
53         FLUSH_POC,              /* d-cache clean by address to the PoC */
54         FLUSH_SET_WAY,          /* d-cache clean by sets/ways */
55         FLUSH_INVAL_POC,        /* d-cache clean & invalidate by addr to PoC */
56         FLUSH_INVAL_SET_WAY,    /* d-cache clean & invalidate by set/ways */
57 };
58
59 #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
60 struct dcache_config {
61         u32 ways;
62         u32 sets;
63 };
64
65 static void get_cache_ways_sets(struct dcache_config *cache)
66 {
67         u32 cache_size_id = readl(V7M_PROC_REG_CCSIDR);
68
69         cache->ways = (cache_size_id & MASK_NUM_WAYS) >> NUM_WAYS_SHIFT;
70         cache->sets = (cache_size_id & MASK_NUM_SETS) >> NUM_SETS_SHIFT;
71 }
72
73 /*
74  * Return the io register to perform required cache action like clean or clean
75  * & invalidate by sets/ways.
76  */
77 static u32 *get_action_reg_set_ways(enum cache_action action)
78 {
79         switch (action) {
80         case INVALIDATE_SET_WAY:
81                 return V7M_CACHE_REG_DCISW;
82         case FLUSH_SET_WAY:
83                 return V7M_CACHE_REG_DCCSW;
84         case FLUSH_INVAL_SET_WAY:
85                 return V7M_CACHE_REG_DCCISW;
86         default:
87                 break;
88         };
89
90         return NULL;
91 }
92
93 /*
94  * Return the io register to perform required cache action like clean or clean
95  * & invalidate by adddress or range.
96  */
97 static u32 *get_action_reg_range(enum cache_action action)
98 {
99         switch (action) {
100         case INVALIDATE_POU:
101                 return V7M_CACHE_REG_ICIMVALU;
102         case INVALIDATE_POC:
103                 return V7M_CACHE_REG_DCIMVAC;
104         case FLUSH_POU:
105                 return V7M_CACHE_REG_DCCMVAU;
106         case FLUSH_POC:
107                 return V7M_CACHE_REG_DCCMVAC;
108         case FLUSH_INVAL_POC:
109                 return V7M_CACHE_REG_DCCIMVAC;
110         default:
111                 break;
112         }
113
114         return NULL;
115 }
116
117 static u32 get_cline_size(enum cache_type type)
118 {
119         u32 size;
120
121         if (type == DCACHE)
122                 clrbits_le32(V7M_PROC_REG_CSSELR, BIT(SEL_I_OR_D));
123         else if (type == ICACHE)
124                 setbits_le32(V7M_PROC_REG_CSSELR, BIT(SEL_I_OR_D));
125         /* Make sure cache selection is effective for next memory access */
126         dsb();
127
128         size = readl(V7M_PROC_REG_CCSIDR) & CLINE_SIZE_MASK;
129         /* Size enocoded as 2 less than log(no_of_words_in_cache_line) base 2 */
130         size = 1 << (size + 2);
131         debug("cache line size is %d\n", size);
132
133         return size;
134 }
135
136 /* Perform the action like invalidate/clean on a range of cache addresses */
137 static int action_cache_range(enum cache_action action, u32 start_addr,
138                               int64_t size)
139 {
140         u32 cline_size;
141         u32 *action_reg;
142         enum cache_type type;
143
144         action_reg = get_action_reg_range(action);
145         if (!action_reg)
146                 return -EINVAL;
147         if (action == INVALIDATE_POU)
148                 type = ICACHE;
149         else
150                 type = DCACHE;
151
152         /* Cache line size is minium size for the cache action */
153         cline_size = get_cline_size(type);
154         /* Align start address to cache line boundary */
155         start_addr &= ~(cline_size - 1);
156         debug("total size for cache action = %llx\n", size);
157         do {
158                 writel(start_addr, action_reg);
159                 size -= cline_size;
160                 start_addr += cline_size;
161         } while (size > cline_size);
162
163         /* Make sure cache action is effective for next memory access */
164         dsb();
165         isb();  /* Make sure instruction stream sees it */
166         debug("cache action on range done\n");
167
168         return 0;
169 }
170
171 /* Perform the action like invalidate/clean on all cached addresses */
172 static int action_dcache_all(enum cache_action action)
173 {
174         struct dcache_config cache;
175         u32 *action_reg;
176         int i, j;
177
178         action_reg = get_action_reg_set_ways(action);
179         if (!action_reg)
180                 return -EINVAL;
181
182         clrbits_le32(V7M_PROC_REG_CSSELR, BIT(SEL_I_OR_D));
183         /* Make sure cache selection is effective for next memory access */
184         dsb();
185
186         get_cache_ways_sets(&cache);    /* Get number of ways & sets */
187         debug("cache: ways= %d, sets= %d\n", cache.ways + 1, cache.sets + 1);
188         for (i = cache.sets; i >= 0; i--) {
189                 for (j = cache.ways; j >= 0; j--) {
190                         writel((j << WAYS_SHIFT) | (i << SETS_SHIFT),
191                                action_reg);
192                 }
193         }
194
195         /* Make sure cache action is effective for next memory access */
196         dsb();
197         isb();  /* Make sure instruction stream sees it */
198
199         return 0;
200 }
201
202 void dcache_enable(void)
203 {
204         if (dcache_status())    /* return if cache already enabled */
205                 return;
206
207         if (action_dcache_all(INVALIDATE_SET_WAY)) {
208                 printf("ERR: D-cache not enabled\n");
209                 return;
210         }
211
212         setbits_le32(&V7M_SCB->ccr, BIT(V7M_CCR_DCACHE));
213
214         /* Make sure cache action is effective for next memory access */
215         dsb();
216         isb();  /* Make sure instruction stream sees it */
217 }
218
219 void dcache_disable(void)
220 {
221         if (!dcache_status())
222                 return;
223
224         /* if dcache is enabled-> dcache disable & then flush */
225         if (action_dcache_all(FLUSH_SET_WAY)) {
226                 printf("ERR: D-cache not flushed\n");
227                 return;
228         }
229
230         clrbits_le32(&V7M_SCB->ccr, BIT(V7M_CCR_DCACHE));
231
232         /* Make sure cache action is effective for next memory access */
233         dsb();
234         isb();  /* Make sure instruction stream sees it */
235 }
236
237 int dcache_status(void)
238 {
239         return (readl(&V7M_SCB->ccr) & BIT(V7M_CCR_DCACHE)) != 0;
240 }
241
242 void invalidate_dcache_range(unsigned long start, unsigned long stop)
243 {
244         if (action_cache_range(INVALIDATE_POC, start, stop - start)) {
245                 printf("ERR: D-cache not invalidated\n");
246                 return;
247         }
248 }
249
250 void flush_dcache_range(unsigned long start, unsigned long stop)
251 {
252         if (action_cache_range(FLUSH_POC, start, stop - start)) {
253                 printf("ERR: D-cache not flushed\n");
254                 return;
255         }
256 }
257 void flush_dcache_all(void)
258 {
259         if (action_dcache_all(FLUSH_SET_WAY)) {
260                 printf("ERR: D-cache not flushed\n");
261                 return;
262         }
263 }
264
265 void invalidate_dcache_all(void)
266 {
267         if (action_dcache_all(INVALIDATE_SET_WAY)) {
268                 printf("ERR: D-cache not invalidated\n");
269                 return;
270         }
271 }
272 #else
273 void dcache_enable(void)
274 {
275         return;
276 }
277
278 void dcache_disable(void)
279 {
280         return;
281 }
282
283 int dcache_status(void)
284 {
285         return 0;
286 }
287
288 void flush_dcache_all(void)
289 {
290 }
291
292 void invalidate_dcache_all(void)
293 {
294 }
295
296 void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
297                                      enum dcache_option option)
298 {
299 }
300
301 #endif
302
303 #if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
304
305 void invalidate_icache_all(void)
306 {
307         writel(INVAL_ICACHE_POU, V7M_CACHE_REG_ICIALLU);
308
309         /* Make sure cache action is effective for next memory access */
310         dsb();
311         isb();  /* Make sure instruction stream sees it */
312 }
313
314 void icache_enable(void)
315 {
316         if (icache_status())
317                 return;
318
319         invalidate_icache_all();
320         setbits_le32(&V7M_SCB->ccr, BIT(V7M_CCR_ICACHE));
321
322         /* Make sure cache action is effective for next memory access */
323         dsb();
324         isb();  /* Make sure instruction stream sees it */
325 }
326
327 int icache_status(void)
328 {
329         return (readl(&V7M_SCB->ccr) & BIT(V7M_CCR_ICACHE)) != 0;
330 }
331
332 void icache_disable(void)
333 {
334         if (!icache_status())
335                 return;
336
337         isb();  /* flush pipeline */
338         clrbits_le32(&V7M_SCB->ccr, BIT(V7M_CCR_ICACHE));
339         isb();  /* subsequent instructions fetch see cache disable effect */
340 }
341 #else
342 void invalidate_icache_all(void)
343 {
344         return;
345 }
346
347 void icache_enable(void)
348 {
349         return;
350 }
351
352 void icache_disable(void)
353 {
354         return;
355 }
356
357 int icache_status(void)
358 {
359         return 0;
360 }
361 #endif
362
363 void enable_caches(void)
364 {
365 #if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
366         icache_enable();
367 #endif
368 #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
369         dcache_enable();
370 #endif
371 }