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