openocd: src/target: replace the GPL-2.0-or-later license tag
[openocd.git] / src / target / armv7a_cache_l2x.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4 * Copyright (C) 2015 by Oleksij Rempel *
5 * linux@rempel-privat.de *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "jtag/interface.h"
13 #include "arm.h"
14 #include "armv7a.h"
15 #include "armv7a_cache.h"
16 #include <helper/time_support.h>
17 #include "target.h"
18 #include "target_type.h"
19 #include "smp.h"
20
21 static int arm7a_l2x_sanity_check(struct target *target)
22 {
23 struct armv7a_common *armv7a = target_to_armv7a(target);
24 struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
25 (armv7a->armv7a_mmu.armv7a_cache.outer_cache);
26
27 if (target->state != TARGET_HALTED) {
28 LOG_ERROR("%s: target not halted", __func__);
29 return ERROR_TARGET_NOT_HALTED;
30 }
31
32 if (!l2x_cache || !l2x_cache->base) {
33 LOG_DEBUG("l2x is not configured!");
34 return ERROR_FAIL;
35 }
36
37 return ERROR_OK;
38 }
39 /*
40 * clean and invalidate complete l2x cache
41 */
42 int arm7a_l2x_flush_all_data(struct target *target)
43 {
44 struct armv7a_common *armv7a = target_to_armv7a(target);
45 struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
46 (armv7a->armv7a_mmu.armv7a_cache.outer_cache);
47 uint32_t l2_way_val;
48 int retval;
49
50 retval = arm7a_l2x_sanity_check(target);
51 if (retval)
52 return retval;
53
54 l2_way_val = (1 << l2x_cache->way) - 1;
55
56 return target_write_phys_u32(target,
57 l2x_cache->base + L2X0_CLEAN_INV_WAY,
58 l2_way_val);
59 }
60
61 int armv7a_l2x_cache_flush_virt(struct target *target, target_addr_t virt,
62 uint32_t size)
63 {
64 struct armv7a_common *armv7a = target_to_armv7a(target);
65 struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
66 (armv7a->armv7a_mmu.armv7a_cache.outer_cache);
67 /* FIXME: different controllers have different linelen? */
68 uint32_t i, linelen = 32;
69 int retval;
70
71 retval = arm7a_l2x_sanity_check(target);
72 if (retval)
73 return retval;
74
75 for (i = 0; i < size; i += linelen) {
76 target_addr_t pa, offs = virt + i;
77
78 /* FIXME: use less verbose virt2phys? */
79 retval = target->type->virt2phys(target, offs, &pa);
80 if (retval != ERROR_OK)
81 goto done;
82
83 retval = target_write_phys_u32(target,
84 l2x_cache->base + L2X0_CLEAN_INV_LINE_PA, pa);
85 if (retval != ERROR_OK)
86 goto done;
87 }
88 return retval;
89
90 done:
91 LOG_ERROR("d-cache invalidate failed");
92
93 return retval;
94 }
95
96 static int armv7a_l2x_cache_inval_virt(struct target *target, target_addr_t virt,
97 uint32_t size)
98 {
99 struct armv7a_common *armv7a = target_to_armv7a(target);
100 struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
101 (armv7a->armv7a_mmu.armv7a_cache.outer_cache);
102 /* FIXME: different controllers have different linelen */
103 uint32_t i, linelen = 32;
104 int retval;
105
106 retval = arm7a_l2x_sanity_check(target);
107 if (retval)
108 return retval;
109
110 for (i = 0; i < size; i += linelen) {
111 target_addr_t pa, offs = virt + i;
112
113 /* FIXME: use less verbose virt2phys? */
114 retval = target->type->virt2phys(target, offs, &pa);
115 if (retval != ERROR_OK)
116 goto done;
117
118 retval = target_write_phys_u32(target,
119 l2x_cache->base + L2X0_INV_LINE_PA, pa);
120 if (retval != ERROR_OK)
121 goto done;
122 }
123 return retval;
124
125 done:
126 LOG_ERROR("d-cache invalidate failed");
127
128 return retval;
129 }
130
131 static int armv7a_l2x_cache_clean_virt(struct target *target, target_addr_t virt,
132 unsigned int size)
133 {
134 struct armv7a_common *armv7a = target_to_armv7a(target);
135 struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
136 (armv7a->armv7a_mmu.armv7a_cache.outer_cache);
137 /* FIXME: different controllers have different linelen */
138 uint32_t i, linelen = 32;
139 int retval;
140
141 retval = arm7a_l2x_sanity_check(target);
142 if (retval)
143 return retval;
144
145 for (i = 0; i < size; i += linelen) {
146 target_addr_t pa, offs = virt + i;
147
148 /* FIXME: use less verbose virt2phys? */
149 retval = target->type->virt2phys(target, offs, &pa);
150 if (retval != ERROR_OK)
151 goto done;
152
153 retval = target_write_phys_u32(target,
154 l2x_cache->base + L2X0_CLEAN_LINE_PA, pa);
155 if (retval != ERROR_OK)
156 goto done;
157 }
158 return retval;
159
160 done:
161 LOG_ERROR("d-cache invalidate failed");
162
163 return retval;
164 }
165
166 static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd,
167 struct armv7a_cache_common *armv7a_cache)
168 {
169 struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
170 (armv7a_cache->outer_cache);
171
172 if (armv7a_cache->info == -1) {
173 command_print(cmd, "cache not yet identified");
174 return ERROR_OK;
175 }
176
177 command_print(cmd,
178 "L2 unified cache Base Address 0x%" PRIx32 ", %" PRIu32 " ways",
179 l2x_cache->base, l2x_cache->way);
180
181 return ERROR_OK;
182 }
183
184 static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
185 {
186 struct armv7a_l2x_cache *l2x_cache;
187 struct target_list *head;
188
189 struct armv7a_common *armv7a = target_to_armv7a(target);
190 if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) {
191 LOG_ERROR("L2 cache was already initialised\n");
192 return ERROR_FAIL;
193 }
194
195 l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache));
196 l2x_cache->base = base;
197 l2x_cache->way = way;
198 armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
199
200 /* initialize all targets in this cluster (smp target)
201 * l2 cache must be configured after smp declaration */
202 foreach_smp_target(head, target->smp_targets) {
203 struct target *curr = head->target;
204 if (curr != target) {
205 armv7a = target_to_armv7a(curr);
206 if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) {
207 LOG_ERROR("smp target : cache l2 already initialized\n");
208 return ERROR_FAIL;
209 }
210 armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
211 }
212 }
213 return ERROR_OK;
214 }
215
216 COMMAND_HANDLER(arm7a_l2x_cache_info_command)
217 {
218 struct target *target = get_current_target(CMD_CTX);
219 struct armv7a_common *armv7a = target_to_armv7a(target);
220 int retval;
221
222 retval = arm7a_l2x_sanity_check(target);
223 if (retval)
224 return retval;
225
226 return arm7a_handle_l2x_cache_info_command(CMD,
227 &armv7a->armv7a_mmu.armv7a_cache);
228 }
229
230 COMMAND_HANDLER(arm7a_l2x_cache_flush_all_command)
231 {
232 struct target *target = get_current_target(CMD_CTX);
233
234 return arm7a_l2x_flush_all_data(target);
235 }
236
237 COMMAND_HANDLER(arm7a_l2x_cache_flush_virt_cmd)
238 {
239 struct target *target = get_current_target(CMD_CTX);
240 target_addr_t virt;
241 uint32_t size;
242
243 if (CMD_ARGC == 0 || CMD_ARGC > 2)
244 return ERROR_COMMAND_SYNTAX_ERROR;
245
246 if (CMD_ARGC == 2)
247 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
248 else
249 size = 1;
250
251 COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt);
252
253 return armv7a_l2x_cache_flush_virt(target, virt, size);
254 }
255
256 COMMAND_HANDLER(arm7a_l2x_cache_inval_virt_cmd)
257 {
258 struct target *target = get_current_target(CMD_CTX);
259 target_addr_t virt;
260 uint32_t size;
261
262 if (CMD_ARGC == 0 || CMD_ARGC > 2)
263 return ERROR_COMMAND_SYNTAX_ERROR;
264
265 if (CMD_ARGC == 2)
266 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
267 else
268 size = 1;
269
270 COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt);
271
272 return armv7a_l2x_cache_inval_virt(target, virt, size);
273 }
274
275 COMMAND_HANDLER(arm7a_l2x_cache_clean_virt_cmd)
276 {
277 struct target *target = get_current_target(CMD_CTX);
278 target_addr_t virt;
279 uint32_t size;
280
281 if (CMD_ARGC == 0 || CMD_ARGC > 2)
282 return ERROR_COMMAND_SYNTAX_ERROR;
283
284 if (CMD_ARGC == 2)
285 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
286 else
287 size = 1;
288
289 COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt);
290
291 return armv7a_l2x_cache_clean_virt(target, virt, size);
292 }
293
294 /* FIXME: should we configure way size? or controller type? */
295 COMMAND_HANDLER(armv7a_l2x_cache_conf_cmd)
296 {
297 struct target *target = get_current_target(CMD_CTX);
298 uint32_t base, way;
299
300 if (CMD_ARGC != 2)
301 return ERROR_COMMAND_SYNTAX_ERROR;
302
303 /* command_print(CMD, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
304 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base);
305 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way);
306
307 /* AP address is in bits 31:24 of DP_SELECT */
308 return armv7a_l2x_cache_init(target, base, way);
309 }
310
311 static const struct command_registration arm7a_l2x_cache_commands[] = {
312 {
313 .name = "conf",
314 .handler = armv7a_l2x_cache_conf_cmd,
315 .mode = COMMAND_ANY,
316 .help = "configure l2x cache",
317 .usage = "<base_addr> <number_of_way>",
318 },
319 {
320 .name = "info",
321 .handler = arm7a_l2x_cache_info_command,
322 .mode = COMMAND_ANY,
323 .help = "print cache related information",
324 .usage = "",
325 },
326 {
327 .name = "flush_all",
328 .handler = arm7a_l2x_cache_flush_all_command,
329 .mode = COMMAND_ANY,
330 .help = "flush complete l2x cache",
331 .usage = "",
332 },
333 {
334 .name = "flush",
335 .handler = arm7a_l2x_cache_flush_virt_cmd,
336 .mode = COMMAND_ANY,
337 .help = "flush (clean and invalidate) l2x cache by virtual address offset and range size",
338 .usage = "<virt_addr> [size]",
339 },
340 {
341 .name = "inval",
342 .handler = arm7a_l2x_cache_inval_virt_cmd,
343 .mode = COMMAND_ANY,
344 .help = "invalidate l2x cache by virtual address offset and range size",
345 .usage = "<virt_addr> [size]",
346 },
347 {
348 .name = "clean",
349 .handler = arm7a_l2x_cache_clean_virt_cmd,
350 .mode = COMMAND_ANY,
351 .help = "clean l2x cache by virtual address address offset and range size",
352 .usage = "<virt_addr> [size]",
353 },
354 COMMAND_REGISTRATION_DONE
355 };
356
357 const struct command_registration arm7a_l2x_cache_command_handler[] = {
358 {
359 .name = "l2x",
360 .mode = COMMAND_ANY,
361 .help = "l2x cache command group",
362 .usage = "",
363 .chain = arm7a_l2x_cache_commands,
364 },
365 COMMAND_REGISTRATION_DONE
366 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)