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