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