1 /* cache.c - d-cache support for ARC CPUs */
2 
3 /*
4  * Copyright (c) 2016 Synopsys, Inc. All rights reserved.
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 /**
10  * @file
11  * @brief d-cache manipulation
12  *
13  * This module contains functions for manipulation of the d-cache.
14  */
15 
16 #include <zephyr/kernel.h>
17 #include <zephyr/arch/cpu.h>
18 #include <zephyr/sys/util.h>
19 #include <zephyr/toolchain.h>
20 #include <zephyr/cache.h>
21 #include <zephyr/linker/linker-defs.h>
22 #include <zephyr/arch/arc/v2/aux_regs.h>
23 #include <kernel_internal.h>
24 #include <zephyr/sys/__assert.h>
25 #include <zephyr/init.h>
26 #include <stdbool.h>
27 
28 #if defined(CONFIG_DCACHE_LINE_SIZE_DETECT)
29 size_t sys_cache_line_size;
30 #endif
31 
32 #define DC_CTRL_DC_ENABLE            0x0  /* enable d-cache */
33 #define DC_CTRL_DC_DISABLE           0x1  /* disable d-cache */
34 #define DC_CTRL_INVALID_ONLY         0x0  /* invalid d-cache only */
35 #define DC_CTRL_INVALID_FLUSH        0x40 /* invalid and flush d-cache */
36 #define DC_CTRL_ENABLE_FLUSH_LOCKED  0x80 /* locked d-cache can be flushed */
37 #define DC_CTRL_DISABLE_FLUSH_LOCKED 0x0  /* locked d-cache cannot be flushed */
38 #define DC_CTRL_FLUSH_STATUS         0x100/* flush status */
39 #define DC_CTRL_DIRECT_ACCESS        0x0  /* direct access mode  */
40 #define DC_CTRL_INDIRECT_ACCESS      0x20 /* indirect access mode */
41 #define DC_CTRL_OP_SUCCEEDED         0x4  /* d-cache operation succeeded */
42 
dcache_available(void)43 static bool dcache_available(void)
44 {
45 	unsigned long val = z_arc_v2_aux_reg_read(_ARC_V2_D_CACHE_BUILD);
46 
47 	val &= 0xff; /* extract version */
48 	return (val == 0) ? false : true;
49 }
50 
dcache_dc_ctrl(uint32_t dcache_en_mask)51 static void dcache_dc_ctrl(uint32_t dcache_en_mask)
52 {
53 	if (dcache_available()) {
54 		z_arc_v2_aux_reg_write(_ARC_V2_DC_CTRL, dcache_en_mask);
55 	}
56 }
57 
arch_dcache_enable(void)58 void arch_dcache_enable(void)
59 {
60 	dcache_dc_ctrl(DC_CTRL_DC_ENABLE);
61 }
62 
arch_dcache_disable(void)63 void arch_dcache_disable(void)
64 {
65 	/* nothing */
66 }
67 
arch_dcache_flush_range(void * start_addr_ptr,size_t size)68 int arch_dcache_flush_range(void *start_addr_ptr, size_t size)
69 {
70 	size_t line_size = sys_cache_data_line_size_get();
71 	uintptr_t start_addr = (uintptr_t)start_addr_ptr;
72 	uintptr_t end_addr;
73 	unsigned int key;
74 
75 	if (!dcache_available() || (size == 0U) || line_size == 0U) {
76 		return -ENOTSUP;
77 	}
78 
79 	end_addr = start_addr + size;
80 
81 	start_addr = ROUND_DOWN(start_addr, line_size);
82 
83 	key = arch_irq_lock(); /* --enter critical section-- */
84 
85 	do {
86 		z_arc_v2_aux_reg_write(_ARC_V2_DC_FLDL, start_addr);
87 		__builtin_arc_nop();
88 		__builtin_arc_nop();
89 		__builtin_arc_nop();
90 		/* wait for flush completion */
91 		do {
92 			if ((z_arc_v2_aux_reg_read(_ARC_V2_DC_CTRL) &
93 			     DC_CTRL_FLUSH_STATUS) == 0) {
94 				break;
95 			}
96 		} while (1);
97 		start_addr += line_size;
98 	} while (start_addr < end_addr);
99 
100 	arch_irq_unlock(key); /* --exit critical section-- */
101 
102 	return 0;
103 }
104 
arch_dcache_invd_range(void * start_addr_ptr,size_t size)105 int arch_dcache_invd_range(void *start_addr_ptr, size_t size)
106 {
107 	size_t line_size = sys_cache_data_line_size_get();
108 	uintptr_t start_addr = (uintptr_t)start_addr_ptr;
109 	uintptr_t end_addr;
110 	unsigned int key;
111 
112 	if (!dcache_available() || (size == 0U) || line_size == 0U) {
113 		return -ENOTSUP;
114 	}
115 	end_addr = start_addr + size;
116 	start_addr = ROUND_DOWN(start_addr, line_size);
117 
118 	key = arch_irq_lock(); /* -enter critical section- */
119 
120 	do {
121 		z_arc_v2_aux_reg_write(_ARC_V2_DC_IVDL, start_addr);
122 		__builtin_arc_nop();
123 		__builtin_arc_nop();
124 		__builtin_arc_nop();
125 		start_addr += line_size;
126 	} while (start_addr < end_addr);
127 	irq_unlock(key); /* -exit critical section- */
128 
129 	return 0;
130 }
131 
arch_dcache_flush_and_invd_range(void * start_addr_ptr,size_t size)132 int arch_dcache_flush_and_invd_range(void *start_addr_ptr, size_t size)
133 {
134 	return -ENOTSUP;
135 }
136 
arch_dcache_flush_all(void)137 int arch_dcache_flush_all(void)
138 {
139 	return -ENOTSUP;
140 }
141 
arch_dcache_invd_all(void)142 int arch_dcache_invd_all(void)
143 {
144 	return -ENOTSUP;
145 }
146 
arch_dcache_flush_and_invd_all(void)147 int arch_dcache_flush_and_invd_all(void)
148 {
149 	return -ENOTSUP;
150 }
151 
152 #if defined(CONFIG_DCACHE_LINE_SIZE_DETECT)
init_dcache_line_size(void)153 static void init_dcache_line_size(void)
154 {
155 	uint32_t val;
156 
157 	val = z_arc_v2_aux_reg_read(_ARC_V2_D_CACHE_BUILD);
158 	__ASSERT((val&0xff) != 0U, "d-cache is not present");
159 	val = ((val>>16) & 0xf) + 1;
160 	val *= 16U;
161 	sys_cache_line_size = (size_t) val;
162 }
163 
arch_dcache_line_size_get(void)164 size_t arch_dcache_line_size_get(void)
165 {
166 	return sys_cache_line_size;
167 }
168 #endif
169 
arch_icache_enable(void)170 void arch_icache_enable(void)
171 {
172 	/* nothing */
173 }
174 
arch_icache_disable(void)175 void arch_icache_disable(void)
176 {
177 	/* nothing */
178 }
179 
arch_icache_flush_all(void)180 int arch_icache_flush_all(void)
181 {
182 	return -ENOTSUP;
183 }
184 
arch_icache_invd_all(void)185 int arch_icache_invd_all(void)
186 {
187 	return -ENOTSUP;
188 }
189 
arch_icache_flush_and_invd_all(void)190 int arch_icache_flush_and_invd_all(void)
191 {
192 	return -ENOTSUP;
193 }
194 
arch_icache_flush_range(void * addr,size_t size)195 int arch_icache_flush_range(void *addr, size_t size)
196 {
197 	ARG_UNUSED(addr);
198 	ARG_UNUSED(size);
199 
200 	return -ENOTSUP;
201 }
202 
arch_icache_invd_range(void * addr,size_t size)203 int arch_icache_invd_range(void *addr, size_t size)
204 {
205 	ARG_UNUSED(addr);
206 	ARG_UNUSED(size);
207 
208 	return -ENOTSUP;
209 }
210 
arch_icache_flush_and_invd_range(void * addr,size_t size)211 int arch_icache_flush_and_invd_range(void *addr, size_t size)
212 {
213 	ARG_UNUSED(addr);
214 	ARG_UNUSED(size);
215 
216 	return -ENOTSUP;
217 }
218 
init_dcache(void)219 static int init_dcache(void)
220 {
221 
222 	arch_dcache_enable();
223 
224 #if defined(CONFIG_DCACHE_LINE_SIZE_DETECT)
225 	init_dcache_line_size();
226 #endif
227 
228 	return 0;
229 }
230 
231 SYS_INIT(init_dcache, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
232