xref: /openbmc/u-boot/arch/arc/lib/cache.c (revision 5d7a24d6)
1660d5f0dSAlexey Brodkin /*
2660d5f0dSAlexey Brodkin  * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved.
3660d5f0dSAlexey Brodkin  *
4660d5f0dSAlexey Brodkin  * SPDX-License-Identifier:	GPL-2.0+
5660d5f0dSAlexey Brodkin  */
6660d5f0dSAlexey Brodkin 
7660d5f0dSAlexey Brodkin #include <config.h>
8379b3280SAlexey Brodkin #include <common.h>
9ef639e6fSAlexey Brodkin #include <linux/compiler.h>
10ef639e6fSAlexey Brodkin #include <linux/kernel.h>
1197a63144SAlexey Brodkin #include <linux/log2.h>
12660d5f0dSAlexey Brodkin #include <asm/arcregs.h>
13205e7a7bSAlexey Brodkin #include <asm/cache.h>
14660d5f0dSAlexey Brodkin 
15660d5f0dSAlexey Brodkin /* Bit values in IC_CTRL */
1619b10a42SEugeniy Paltsev #define IC_CTRL_CACHE_DISABLE	BIT(0)
17660d5f0dSAlexey Brodkin 
18660d5f0dSAlexey Brodkin /* Bit values in DC_CTRL */
1919b10a42SEugeniy Paltsev #define DC_CTRL_CACHE_DISABLE	BIT(0)
2019b10a42SEugeniy Paltsev #define DC_CTRL_INV_MODE_FLUSH	BIT(6)
2119b10a42SEugeniy Paltsev #define DC_CTRL_FLUSH_STATUS	BIT(8)
22660d5f0dSAlexey Brodkin #define CACHE_VER_NUM_MASK	0xF
23660d5f0dSAlexey Brodkin 
24*5d7a24d6SEugeniy Paltsev #define OP_INV			BIT(0)
25*5d7a24d6SEugeniy Paltsev #define OP_FLUSH		BIT(1)
26*5d7a24d6SEugeniy Paltsev #define OP_FLUSH_N_INV		(OP_FLUSH | OP_INV)
27ef639e6fSAlexey Brodkin 
2841cada4dSEugeniy Paltsev /* Bit val in SLC_CONTROL */
2941cada4dSEugeniy Paltsev #define SLC_CTRL_DIS		0x001
3041cada4dSEugeniy Paltsev #define SLC_CTRL_IM		0x040
3141cada4dSEugeniy Paltsev #define SLC_CTRL_BUSY		0x100
3241cada4dSEugeniy Paltsev #define SLC_CTRL_RGN_OP_INV	0x200
3341cada4dSEugeniy Paltsev 
34ef639e6fSAlexey Brodkin /*
35ef639e6fSAlexey Brodkin  * By default that variable will fall into .bss section.
36ef639e6fSAlexey Brodkin  * But .bss section is not relocated and so it will be initilized before
37ef639e6fSAlexey Brodkin  * relocation but will be used after being zeroed.
38ef639e6fSAlexey Brodkin  */
39379b3280SAlexey Brodkin int l1_line_sz __section(".data");
403cf23939SEugeniy Paltsev bool dcache_exists __section(".data") = false;
413cf23939SEugeniy Paltsev bool icache_exists __section(".data") = false;
42379b3280SAlexey Brodkin 
43379b3280SAlexey Brodkin #define CACHE_LINE_MASK		(~(l1_line_sz - 1))
44379b3280SAlexey Brodkin 
45379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
46ef639e6fSAlexey Brodkin int slc_line_sz __section(".data");
473cf23939SEugeniy Paltsev bool slc_exists __section(".data") = false;
483cf23939SEugeniy Paltsev bool ioc_exists __section(".data") = false;
4941cada4dSEugeniy Paltsev bool pae_exists __section(".data") = false;
50ef639e6fSAlexey Brodkin 
51b0146f9eSEugeniy Paltsev /* To force enable IOC set ioc_enable to 'true' */
52b0146f9eSEugeniy Paltsev bool ioc_enable __section(".data") = false;
53b0146f9eSEugeniy Paltsev 
5441cada4dSEugeniy Paltsev void read_decode_mmu_bcr(void)
55ef639e6fSAlexey Brodkin {
5641cada4dSEugeniy Paltsev 	/* TODO: should we compare mmu version from BCR and from CONFIG? */
5741cada4dSEugeniy Paltsev #if (CONFIG_ARC_MMU_VER >= 4)
5841cada4dSEugeniy Paltsev 	u32 tmp;
59ef639e6fSAlexey Brodkin 
6041cada4dSEugeniy Paltsev 	tmp = read_aux_reg(ARC_AUX_MMU_BCR);
61ef639e6fSAlexey Brodkin 
6241cada4dSEugeniy Paltsev 	struct bcr_mmu_4 {
6341cada4dSEugeniy Paltsev #ifdef CONFIG_CPU_BIG_ENDIAN
6441cada4dSEugeniy Paltsev 	unsigned int ver:8, sasid:1, sz1:4, sz0:4, res:2, pae:1,
6541cada4dSEugeniy Paltsev 		     n_ways:2, n_entry:2, n_super:2, u_itlb:3, u_dtlb:3;
66ef639e6fSAlexey Brodkin #else
6741cada4dSEugeniy Paltsev 	/*           DTLB      ITLB      JES        JE         JA      */
6841cada4dSEugeniy Paltsev 	unsigned int u_dtlb:3, u_itlb:3, n_super:2, n_entry:2, n_ways:2,
6941cada4dSEugeniy Paltsev 		     pae:1, res:2, sz0:4, sz1:4, sasid:1, ver:8;
7041cada4dSEugeniy Paltsev #endif /* CONFIG_CPU_BIG_ENDIAN */
7141cada4dSEugeniy Paltsev 	} *mmu4;
7241cada4dSEugeniy Paltsev 
7341cada4dSEugeniy Paltsev 	mmu4 = (struct bcr_mmu_4 *)&tmp;
7441cada4dSEugeniy Paltsev 
7541cada4dSEugeniy Paltsev 	pae_exists = !!mmu4->pae;
7641cada4dSEugeniy Paltsev #endif /* (CONFIG_ARC_MMU_VER >= 4) */
7741cada4dSEugeniy Paltsev }
7841cada4dSEugeniy Paltsev 
7941cada4dSEugeniy Paltsev static void __slc_entire_op(const int op)
8041cada4dSEugeniy Paltsev {
8141cada4dSEugeniy Paltsev 	unsigned int ctrl;
8241cada4dSEugeniy Paltsev 
8341cada4dSEugeniy Paltsev 	ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
8441cada4dSEugeniy Paltsev 
8541cada4dSEugeniy Paltsev 	if (!(op & OP_FLUSH))		/* i.e. OP_INV */
8641cada4dSEugeniy Paltsev 		ctrl &= ~SLC_CTRL_IM;	/* clear IM: Disable flush before Inv */
8741cada4dSEugeniy Paltsev 	else
8841cada4dSEugeniy Paltsev 		ctrl |= SLC_CTRL_IM;
8941cada4dSEugeniy Paltsev 
9041cada4dSEugeniy Paltsev 	write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
9141cada4dSEugeniy Paltsev 
9241cada4dSEugeniy Paltsev 	if (op & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
9341cada4dSEugeniy Paltsev 		write_aux_reg(ARC_AUX_SLC_INVALIDATE, 0x1);
9441cada4dSEugeniy Paltsev 	else
9541cada4dSEugeniy Paltsev 		write_aux_reg(ARC_AUX_SLC_FLUSH, 0x1);
9641cada4dSEugeniy Paltsev 
9741cada4dSEugeniy Paltsev 	/* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */
9841cada4dSEugeniy Paltsev 	read_aux_reg(ARC_AUX_SLC_CTRL);
9941cada4dSEugeniy Paltsev 
10041cada4dSEugeniy Paltsev 	/* Important to wait for flush to complete */
10141cada4dSEugeniy Paltsev 	while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY);
10241cada4dSEugeniy Paltsev }
10341cada4dSEugeniy Paltsev 
10441cada4dSEugeniy Paltsev static void slc_upper_region_init(void)
10541cada4dSEugeniy Paltsev {
10641cada4dSEugeniy Paltsev 	/*
10741cada4dSEugeniy Paltsev 	 * ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1 are always == 0
10841cada4dSEugeniy Paltsev 	 * as we don't use PAE40.
10941cada4dSEugeniy Paltsev 	 */
11041cada4dSEugeniy Paltsev 	write_aux_reg(ARC_AUX_SLC_RGN_END1, 0);
11141cada4dSEugeniy Paltsev 	write_aux_reg(ARC_AUX_SLC_RGN_START1, 0);
11241cada4dSEugeniy Paltsev }
11341cada4dSEugeniy Paltsev 
11441cada4dSEugeniy Paltsev static void __slc_rgn_op(unsigned long paddr, unsigned long sz, const int op)
11541cada4dSEugeniy Paltsev {
11641cada4dSEugeniy Paltsev 	unsigned int ctrl;
11741cada4dSEugeniy Paltsev 	unsigned long end;
11841cada4dSEugeniy Paltsev 
11941cada4dSEugeniy Paltsev 	/*
12041cada4dSEugeniy Paltsev 	 * The Region Flush operation is specified by CTRL.RGN_OP[11..9]
12141cada4dSEugeniy Paltsev 	 *  - b'000 (default) is Flush,
12241cada4dSEugeniy Paltsev 	 *  - b'001 is Invalidate if CTRL.IM == 0
12341cada4dSEugeniy Paltsev 	 *  - b'001 is Flush-n-Invalidate if CTRL.IM == 1
12441cada4dSEugeniy Paltsev 	 */
12541cada4dSEugeniy Paltsev 	ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
12641cada4dSEugeniy Paltsev 
12741cada4dSEugeniy Paltsev 	/* Don't rely on default value of IM bit */
12841cada4dSEugeniy Paltsev 	if (!(op & OP_FLUSH))		/* i.e. OP_INV */
12941cada4dSEugeniy Paltsev 		ctrl &= ~SLC_CTRL_IM;	/* clear IM: Disable flush before Inv */
13041cada4dSEugeniy Paltsev 	else
13141cada4dSEugeniy Paltsev 		ctrl |= SLC_CTRL_IM;
13241cada4dSEugeniy Paltsev 
13341cada4dSEugeniy Paltsev 	if (op & OP_INV)
13441cada4dSEugeniy Paltsev 		ctrl |= SLC_CTRL_RGN_OP_INV;	/* Inv or flush-n-inv */
13541cada4dSEugeniy Paltsev 	else
13641cada4dSEugeniy Paltsev 		ctrl &= ~SLC_CTRL_RGN_OP_INV;
13741cada4dSEugeniy Paltsev 
13841cada4dSEugeniy Paltsev 	write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
13941cada4dSEugeniy Paltsev 
14041cada4dSEugeniy Paltsev 	/*
14141cada4dSEugeniy Paltsev 	 * Lower bits are ignored, no need to clip
14241cada4dSEugeniy Paltsev 	 * END needs to be setup before START (latter triggers the operation)
14341cada4dSEugeniy Paltsev 	 * END can't be same as START, so add (l2_line_sz - 1) to sz
14441cada4dSEugeniy Paltsev 	 */
14541cada4dSEugeniy Paltsev 	end = paddr + sz + slc_line_sz - 1;
14641cada4dSEugeniy Paltsev 
14741cada4dSEugeniy Paltsev 	/*
14841cada4dSEugeniy Paltsev 	 * Upper addresses (ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1)
14941cada4dSEugeniy Paltsev 	 * are always == 0 as we don't use PAE40, so we only setup lower ones
15041cada4dSEugeniy Paltsev 	 * (ARC_AUX_SLC_RGN_END and ARC_AUX_SLC_RGN_START)
15141cada4dSEugeniy Paltsev 	 */
15241cada4dSEugeniy Paltsev 	write_aux_reg(ARC_AUX_SLC_RGN_END, end);
15341cada4dSEugeniy Paltsev 	write_aux_reg(ARC_AUX_SLC_RGN_START, paddr);
15441cada4dSEugeniy Paltsev 
15541cada4dSEugeniy Paltsev 	/* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */
15641cada4dSEugeniy Paltsev 	read_aux_reg(ARC_AUX_SLC_CTRL);
15741cada4dSEugeniy Paltsev 
15841cada4dSEugeniy Paltsev 	while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY);
15941cada4dSEugeniy Paltsev }
16041cada4dSEugeniy Paltsev #endif /* CONFIG_ISA_ARCV2 */
161ef639e6fSAlexey Brodkin 
162379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
163379b3280SAlexey Brodkin static void read_decode_cache_bcr_arcv2(void)
164ef639e6fSAlexey Brodkin {
165379b3280SAlexey Brodkin 	union {
166379b3280SAlexey Brodkin 		struct {
167379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
168379b3280SAlexey Brodkin 			unsigned int pad:24, way:2, lsz:2, sz:4;
169379b3280SAlexey Brodkin #else
170379b3280SAlexey Brodkin 			unsigned int sz:4, lsz:2, way:2, pad:24;
171379b3280SAlexey Brodkin #endif
172379b3280SAlexey Brodkin 		} fields;
173379b3280SAlexey Brodkin 		unsigned int word;
174379b3280SAlexey Brodkin 	} slc_cfg;
175379b3280SAlexey Brodkin 
176379b3280SAlexey Brodkin 	union {
177379b3280SAlexey Brodkin 		struct {
178379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
179379b3280SAlexey Brodkin 			unsigned int pad:24, ver:8;
180379b3280SAlexey Brodkin #else
181379b3280SAlexey Brodkin 			unsigned int ver:8, pad:24;
182379b3280SAlexey Brodkin #endif
183379b3280SAlexey Brodkin 		} fields;
184379b3280SAlexey Brodkin 		unsigned int word;
185379b3280SAlexey Brodkin 	} sbcr;
186379b3280SAlexey Brodkin 
187379b3280SAlexey Brodkin 	sbcr.word = read_aux_reg(ARC_BCR_SLC);
188379b3280SAlexey Brodkin 	if (sbcr.fields.ver) {
189379b3280SAlexey Brodkin 		slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG);
1903cf23939SEugeniy Paltsev 		slc_exists = true;
191379b3280SAlexey Brodkin 		slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64;
192379b3280SAlexey Brodkin 	}
193db6ce231SAlexey Brodkin 
194db6ce231SAlexey Brodkin 	union {
195db6ce231SAlexey Brodkin 		struct bcr_clust_cfg {
196db6ce231SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
197db6ce231SAlexey Brodkin 			unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8;
198db6ce231SAlexey Brodkin #else
199db6ce231SAlexey Brodkin 			unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7;
200db6ce231SAlexey Brodkin #endif
201db6ce231SAlexey Brodkin 		} fields;
202db6ce231SAlexey Brodkin 		unsigned int word;
203db6ce231SAlexey Brodkin 	} cbcr;
204db6ce231SAlexey Brodkin 
205db6ce231SAlexey Brodkin 	cbcr.word = read_aux_reg(ARC_BCR_CLUSTER);
206b0146f9eSEugeniy Paltsev 	if (cbcr.fields.c && ioc_enable)
2073cf23939SEugeniy Paltsev 		ioc_exists = true;
208379b3280SAlexey Brodkin }
209379b3280SAlexey Brodkin #endif
210379b3280SAlexey Brodkin 
211379b3280SAlexey Brodkin void read_decode_cache_bcr(void)
212379b3280SAlexey Brodkin {
213379b3280SAlexey Brodkin 	int dc_line_sz = 0, ic_line_sz = 0;
214379b3280SAlexey Brodkin 
215379b3280SAlexey Brodkin 	union {
216379b3280SAlexey Brodkin 		struct {
217379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
218379b3280SAlexey Brodkin 			unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
219379b3280SAlexey Brodkin #else
220379b3280SAlexey Brodkin 			unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
221379b3280SAlexey Brodkin #endif
222379b3280SAlexey Brodkin 		} fields;
223379b3280SAlexey Brodkin 		unsigned int word;
224379b3280SAlexey Brodkin 	} ibcr, dbcr;
225379b3280SAlexey Brodkin 
226379b3280SAlexey Brodkin 	ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD);
227379b3280SAlexey Brodkin 	if (ibcr.fields.ver) {
2283cf23939SEugeniy Paltsev 		icache_exists = true;
229379b3280SAlexey Brodkin 		l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len;
230379b3280SAlexey Brodkin 		if (!ic_line_sz)
231379b3280SAlexey Brodkin 			panic("Instruction exists but line length is 0\n");
232ef639e6fSAlexey Brodkin 	}
233ef639e6fSAlexey Brodkin 
234379b3280SAlexey Brodkin 	dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD);
235379b3280SAlexey Brodkin 	if (dbcr.fields.ver) {
2363cf23939SEugeniy Paltsev 		dcache_exists = true;
237379b3280SAlexey Brodkin 		l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len;
238379b3280SAlexey Brodkin 		if (!dc_line_sz)
239379b3280SAlexey Brodkin 			panic("Data cache exists but line length is 0\n");
240379b3280SAlexey Brodkin 	}
241379b3280SAlexey Brodkin 
242379b3280SAlexey Brodkin 	if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz))
243379b3280SAlexey Brodkin 		panic("Instruction and data cache line lengths differ\n");
244ef639e6fSAlexey Brodkin }
245ef639e6fSAlexey Brodkin 
246ef639e6fSAlexey Brodkin void cache_init(void)
247ef639e6fSAlexey Brodkin {
248379b3280SAlexey Brodkin 	read_decode_cache_bcr();
249379b3280SAlexey Brodkin 
250ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
251379b3280SAlexey Brodkin 	read_decode_cache_bcr_arcv2();
252db6ce231SAlexey Brodkin 
253db6ce231SAlexey Brodkin 	if (ioc_exists) {
25497a63144SAlexey Brodkin 		/* IOC Aperture start is equal to DDR start */
25597a63144SAlexey Brodkin 		unsigned int ap_base = CONFIG_SYS_SDRAM_BASE;
25697a63144SAlexey Brodkin 		/* IOC Aperture size is equal to DDR size */
25797a63144SAlexey Brodkin 		long ap_size = CONFIG_SYS_SDRAM_SIZE;
25897a63144SAlexey Brodkin 
259a4a43fcfSAlexey Brodkin 		flush_dcache_all();
260a4a43fcfSAlexey Brodkin 		invalidate_dcache_all();
261a4a43fcfSAlexey Brodkin 
26297a63144SAlexey Brodkin 		if (!is_power_of_2(ap_size) || ap_size < 4096)
26397a63144SAlexey Brodkin 			panic("IOC Aperture size must be power of 2 and bigger 4Kib");
26497a63144SAlexey Brodkin 
26597a63144SAlexey Brodkin 		/*
26697a63144SAlexey Brodkin 		 * IOC Aperture size decoded as 2 ^ (SIZE + 2) KB,
26797a63144SAlexey Brodkin 		 * so setting 0x11 implies 512M, 0x12 implies 1G...
26897a63144SAlexey Brodkin 		 */
26997a63144SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE,
27097a63144SAlexey Brodkin 			      order_base_2(ap_size / 1024) - 2);
27197a63144SAlexey Brodkin 
27297a63144SAlexey Brodkin 		/* IOC Aperture start must be aligned to the size of the aperture */
27397a63144SAlexey Brodkin 		if (ap_base % ap_size != 0)
27497a63144SAlexey Brodkin 			panic("IOC Aperture start must be aligned to the size of the aperture");
27597a63144SAlexey Brodkin 
27697a63144SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, ap_base >> 12);
277db6ce231SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1);
278db6ce231SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1);
279db6ce231SAlexey Brodkin 	}
28041cada4dSEugeniy Paltsev 
28141cada4dSEugeniy Paltsev 	read_decode_mmu_bcr();
28241cada4dSEugeniy Paltsev 
28341cada4dSEugeniy Paltsev 	/*
28441cada4dSEugeniy Paltsev 	 * ARC_AUX_SLC_RGN_START1 and ARC_AUX_SLC_RGN_END1 register exist
28541cada4dSEugeniy Paltsev 	 * only if PAE exists in current HW. So we had to check pae_exist
28641cada4dSEugeniy Paltsev 	 * before using them.
28741cada4dSEugeniy Paltsev 	 */
28841cada4dSEugeniy Paltsev 	if (slc_exists && pae_exists)
28941cada4dSEugeniy Paltsev 		slc_upper_region_init();
29041cada4dSEugeniy Paltsev #endif /* CONFIG_ISA_ARCV2 */
291ef639e6fSAlexey Brodkin }
292ef639e6fSAlexey Brodkin 
293660d5f0dSAlexey Brodkin int icache_status(void)
294660d5f0dSAlexey Brodkin {
295379b3280SAlexey Brodkin 	if (!icache_exists)
296660d5f0dSAlexey Brodkin 		return 0;
297660d5f0dSAlexey Brodkin 
298ef639e6fSAlexey Brodkin 	if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE)
299ef639e6fSAlexey Brodkin 		return 0;
300ef639e6fSAlexey Brodkin 	else
301ef639e6fSAlexey Brodkin 		return 1;
302660d5f0dSAlexey Brodkin }
303660d5f0dSAlexey Brodkin 
304660d5f0dSAlexey Brodkin void icache_enable(void)
305660d5f0dSAlexey Brodkin {
306379b3280SAlexey Brodkin 	if (icache_exists)
307660d5f0dSAlexey Brodkin 		write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) &
308660d5f0dSAlexey Brodkin 			      ~IC_CTRL_CACHE_DISABLE);
309660d5f0dSAlexey Brodkin }
310660d5f0dSAlexey Brodkin 
311660d5f0dSAlexey Brodkin void icache_disable(void)
312660d5f0dSAlexey Brodkin {
313379b3280SAlexey Brodkin 	if (icache_exists)
314660d5f0dSAlexey Brodkin 		write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) |
315660d5f0dSAlexey Brodkin 			      IC_CTRL_CACHE_DISABLE);
316660d5f0dSAlexey Brodkin }
317660d5f0dSAlexey Brodkin 
31816aeee81SEugeniy Paltsev /* IC supports only invalidation */
31916aeee81SEugeniy Paltsev static inline void __ic_entire_invalidate(void)
320660d5f0dSAlexey Brodkin {
32116aeee81SEugeniy Paltsev 	if (!icache_status())
32216aeee81SEugeniy Paltsev 		return;
32316aeee81SEugeniy Paltsev 
324660d5f0dSAlexey Brodkin 	/* Any write to IC_IVIC register triggers invalidation of entire I$ */
325660d5f0dSAlexey Brodkin 	write_aux_reg(ARC_AUX_IC_IVIC, 1);
326f2a22678SAlexey Brodkin 	/*
327f2a22678SAlexey Brodkin 	 * As per ARC HS databook (see chapter 5.3.3.2)
328f2a22678SAlexey Brodkin 	 * it is required to add 3 NOPs after each write to IC_IVIC.
329f2a22678SAlexey Brodkin 	 */
330f2a22678SAlexey Brodkin 	__builtin_arc_nop();
331f2a22678SAlexey Brodkin 	__builtin_arc_nop();
332f2a22678SAlexey Brodkin 	__builtin_arc_nop();
333ef639e6fSAlexey Brodkin 	read_aux_reg(ARC_AUX_IC_CTRL);  /* blocks */
334660d5f0dSAlexey Brodkin }
33541cada4dSEugeniy Paltsev 
33616aeee81SEugeniy Paltsev void invalidate_icache_all(void)
33716aeee81SEugeniy Paltsev {
33816aeee81SEugeniy Paltsev 	__ic_entire_invalidate();
33916aeee81SEugeniy Paltsev 
34041cada4dSEugeniy Paltsev #ifdef CONFIG_ISA_ARCV2
34141cada4dSEugeniy Paltsev 	if (slc_exists)
34241cada4dSEugeniy Paltsev 		__slc_entire_op(OP_INV);
343ef639e6fSAlexey Brodkin #endif
34441cada4dSEugeniy Paltsev }
345660d5f0dSAlexey Brodkin 
346660d5f0dSAlexey Brodkin int dcache_status(void)
347660d5f0dSAlexey Brodkin {
348379b3280SAlexey Brodkin 	if (!dcache_exists)
349660d5f0dSAlexey Brodkin 		return 0;
350660d5f0dSAlexey Brodkin 
351ef639e6fSAlexey Brodkin 	if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE)
352ef639e6fSAlexey Brodkin 		return 0;
353ef639e6fSAlexey Brodkin 	else
354ef639e6fSAlexey Brodkin 		return 1;
355660d5f0dSAlexey Brodkin }
356660d5f0dSAlexey Brodkin 
357660d5f0dSAlexey Brodkin void dcache_enable(void)
358660d5f0dSAlexey Brodkin {
359379b3280SAlexey Brodkin 	if (!dcache_exists)
360660d5f0dSAlexey Brodkin 		return;
361660d5f0dSAlexey Brodkin 
362660d5f0dSAlexey Brodkin 	write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) &
363660d5f0dSAlexey Brodkin 		      ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE));
364660d5f0dSAlexey Brodkin }
365660d5f0dSAlexey Brodkin 
366660d5f0dSAlexey Brodkin void dcache_disable(void)
367660d5f0dSAlexey Brodkin {
368379b3280SAlexey Brodkin 	if (!dcache_exists)
369660d5f0dSAlexey Brodkin 		return;
370660d5f0dSAlexey Brodkin 
371660d5f0dSAlexey Brodkin 	write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) |
372660d5f0dSAlexey Brodkin 		      DC_CTRL_CACHE_DISABLE);
373660d5f0dSAlexey Brodkin }
374660d5f0dSAlexey Brodkin 
375660d5f0dSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF
376c4ef14d2SEugeniy Paltsev /* Common Helper for Line Operations on D-cache */
377c4ef14d2SEugeniy Paltsev static inline void __dcache_line_loop(unsigned long paddr, unsigned long sz,
378ef639e6fSAlexey Brodkin 				      const int cacheop)
379660d5f0dSAlexey Brodkin {
380ef639e6fSAlexey Brodkin 	unsigned int aux_cmd;
381ef639e6fSAlexey Brodkin 	int num_lines;
382660d5f0dSAlexey Brodkin 
383ef639e6fSAlexey Brodkin 	/* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
384ef639e6fSAlexey Brodkin 	aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL;
385660d5f0dSAlexey Brodkin 
386ef639e6fSAlexey Brodkin 	sz += paddr & ~CACHE_LINE_MASK;
387ef639e6fSAlexey Brodkin 	paddr &= CACHE_LINE_MASK;
388ef639e6fSAlexey Brodkin 
389379b3280SAlexey Brodkin 	num_lines = DIV_ROUND_UP(sz, l1_line_sz);
390ef639e6fSAlexey Brodkin 
391ef639e6fSAlexey Brodkin 	while (num_lines-- > 0) {
392ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3)
393c4ef14d2SEugeniy Paltsev 		write_aux_reg(ARC_AUX_DC_PTAG, paddr);
394ef639e6fSAlexey Brodkin #endif
395ef639e6fSAlexey Brodkin 		write_aux_reg(aux_cmd, paddr);
396379b3280SAlexey Brodkin 		paddr += l1_line_sz;
397ef639e6fSAlexey Brodkin 	}
398ef639e6fSAlexey Brodkin }
399ef639e6fSAlexey Brodkin 
400*5d7a24d6SEugeniy Paltsev static void __before_dc_op(const int op)
401ef639e6fSAlexey Brodkin {
402*5d7a24d6SEugeniy Paltsev 	unsigned int ctrl;
403ef639e6fSAlexey Brodkin 
404*5d7a24d6SEugeniy Paltsev 	ctrl = read_aux_reg(ARC_AUX_DC_CTRL);
405*5d7a24d6SEugeniy Paltsev 
406*5d7a24d6SEugeniy Paltsev 	/* IM bit implies flush-n-inv, instead of vanilla inv */
407*5d7a24d6SEugeniy Paltsev 	if (op == OP_INV)
408*5d7a24d6SEugeniy Paltsev 		ctrl &= ~DC_CTRL_INV_MODE_FLUSH;
409*5d7a24d6SEugeniy Paltsev 	else
410*5d7a24d6SEugeniy Paltsev 		ctrl |= DC_CTRL_INV_MODE_FLUSH;
411*5d7a24d6SEugeniy Paltsev 
412*5d7a24d6SEugeniy Paltsev 	write_aux_reg(ARC_AUX_DC_CTRL, ctrl);
413ef639e6fSAlexey Brodkin }
414ef639e6fSAlexey Brodkin 
415*5d7a24d6SEugeniy Paltsev static void __after_dc_op(const int op)
416ef639e6fSAlexey Brodkin {
417ef639e6fSAlexey Brodkin 	if (op & OP_FLUSH)	/* flush / flush-n-inv both wait */
41819b10a42SEugeniy Paltsev 		while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS);
419ef639e6fSAlexey Brodkin }
420ef639e6fSAlexey Brodkin 
421ef639e6fSAlexey Brodkin static inline void __dc_entire_op(const int cacheop)
422ef639e6fSAlexey Brodkin {
423ef639e6fSAlexey Brodkin 	int aux;
424*5d7a24d6SEugeniy Paltsev 
425*5d7a24d6SEugeniy Paltsev 	__before_dc_op(cacheop);
426ef639e6fSAlexey Brodkin 
427ef639e6fSAlexey Brodkin 	if (cacheop & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
428ef639e6fSAlexey Brodkin 		aux = ARC_AUX_DC_IVDC;
429ef639e6fSAlexey Brodkin 	else
430ef639e6fSAlexey Brodkin 		aux = ARC_AUX_DC_FLSH;
431ef639e6fSAlexey Brodkin 
432ef639e6fSAlexey Brodkin 	write_aux_reg(aux, 0x1);
433ef639e6fSAlexey Brodkin 
434*5d7a24d6SEugeniy Paltsev 	__after_dc_op(cacheop);
435ef639e6fSAlexey Brodkin }
436ef639e6fSAlexey Brodkin 
437ef639e6fSAlexey Brodkin static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
438ef639e6fSAlexey Brodkin 				const int cacheop)
439ef639e6fSAlexey Brodkin {
440*5d7a24d6SEugeniy Paltsev 	__before_dc_op(cacheop);
441c4ef14d2SEugeniy Paltsev 	__dcache_line_loop(paddr, sz, cacheop);
442*5d7a24d6SEugeniy Paltsev 	__after_dc_op(cacheop);
443ef639e6fSAlexey Brodkin }
444ef639e6fSAlexey Brodkin #else
445ef639e6fSAlexey Brodkin #define __dc_entire_op(cacheop)
446ef639e6fSAlexey Brodkin #define __dc_line_op(paddr, sz, cacheop)
447ef639e6fSAlexey Brodkin #endif /* !CONFIG_SYS_DCACHE_OFF */
448ef639e6fSAlexey Brodkin 
449660d5f0dSAlexey Brodkin void invalidate_dcache_range(unsigned long start, unsigned long end)
450660d5f0dSAlexey Brodkin {
45141cada4dSEugeniy Paltsev 	if (start >= end)
45241cada4dSEugeniy Paltsev 		return;
45341cada4dSEugeniy Paltsev 
454ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
455db6ce231SAlexey Brodkin 	if (!ioc_exists)
456db6ce231SAlexey Brodkin #endif
457db6ce231SAlexey Brodkin 		__dc_line_op(start, end - start, OP_INV);
458db6ce231SAlexey Brodkin 
459db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
460db6ce231SAlexey Brodkin 	if (slc_exists && !ioc_exists)
46141cada4dSEugeniy Paltsev 		__slc_rgn_op(start, end - start, OP_INV);
462660d5f0dSAlexey Brodkin #endif
463660d5f0dSAlexey Brodkin }
464660d5f0dSAlexey Brodkin 
465ef639e6fSAlexey Brodkin void flush_dcache_range(unsigned long start, unsigned long end)
466660d5f0dSAlexey Brodkin {
46741cada4dSEugeniy Paltsev 	if (start >= end)
46841cada4dSEugeniy Paltsev 		return;
46941cada4dSEugeniy Paltsev 
470ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
471db6ce231SAlexey Brodkin 	if (!ioc_exists)
472db6ce231SAlexey Brodkin #endif
473db6ce231SAlexey Brodkin 		__dc_line_op(start, end - start, OP_FLUSH);
474db6ce231SAlexey Brodkin 
475db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
476db6ce231SAlexey Brodkin 	if (slc_exists && !ioc_exists)
47741cada4dSEugeniy Paltsev 		__slc_rgn_op(start, end - start, OP_FLUSH);
478ef639e6fSAlexey Brodkin #endif
479660d5f0dSAlexey Brodkin }
480660d5f0dSAlexey Brodkin 
481660d5f0dSAlexey Brodkin void flush_cache(unsigned long start, unsigned long size)
482660d5f0dSAlexey Brodkin {
483660d5f0dSAlexey Brodkin 	flush_dcache_range(start, start + size);
484660d5f0dSAlexey Brodkin }
4856eb15e50SAlexey Brodkin 
486ef639e6fSAlexey Brodkin void invalidate_dcache_all(void)
487ef639e6fSAlexey Brodkin {
488db6ce231SAlexey Brodkin 	__dc_entire_op(OP_INV);
489db6ce231SAlexey Brodkin 
490db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
491bd91508bSAlexey Brodkin 	if (slc_exists)
492ef639e6fSAlexey Brodkin 		__slc_entire_op(OP_INV);
493ef639e6fSAlexey Brodkin #endif
4946eb15e50SAlexey Brodkin }
4956eb15e50SAlexey Brodkin 
496ef639e6fSAlexey Brodkin void flush_dcache_all(void)
4976eb15e50SAlexey Brodkin {
498db6ce231SAlexey Brodkin 	__dc_entire_op(OP_FLUSH);
499db6ce231SAlexey Brodkin 
500db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
5012a8382c6SAlexey Brodkin 	if (slc_exists)
502ef639e6fSAlexey Brodkin 		__slc_entire_op(OP_FLUSH);
503ef639e6fSAlexey Brodkin #endif
5046eb15e50SAlexey Brodkin }
505