target: fix messages and return values of failed op because not halted
[openocd.git] / src / target / armv7a_cache.c
blobe1f0dfafb0bdd4bc25c65e2ef349ffd6fd3544c5
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2015 by Oleksij Rempel *
5 * linux@rempel-privat.de *
6 ***************************************************************************/
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
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 "arm_opcodes.h"
18 #include "smp.h"
20 static int armv7a_l1_d_cache_sanity_check(struct target *target)
22 struct armv7a_common *armv7a = target_to_armv7a(target);
24 if (target->state != TARGET_HALTED) {
25 LOG_TARGET_ERROR(target, "not halted");
26 return ERROR_TARGET_NOT_HALTED;
29 /* check that cache data is on at target halt */
30 if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
31 LOG_DEBUG("data cache is not enabled");
32 return ERROR_TARGET_INVALID;
35 return ERROR_OK;
38 static int armv7a_l1_i_cache_sanity_check(struct target *target)
40 struct armv7a_common *armv7a = target_to_armv7a(target);
42 if (target->state != TARGET_HALTED) {
43 LOG_TARGET_ERROR(target, "not halted");
44 return ERROR_TARGET_NOT_HALTED;
47 /* check that cache data is on at target halt */
48 if (!armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled) {
49 LOG_DEBUG("instruction cache is not enabled");
50 return ERROR_TARGET_INVALID;
53 return ERROR_OK;
56 static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl)
58 int retval = ERROR_OK;
59 int32_t c_way, c_index = size->index;
61 LOG_DEBUG("cl %" PRId32, cl);
62 do {
63 keep_alive();
64 c_way = size->way;
65 do {
66 uint32_t value = (c_index << size->index_shift)
67 | (c_way << size->way_shift) | (cl << 1);
69 * DCCISW - Clean and invalidate data cache
70 * line by Set/Way.
72 retval = dpm->instr_write_data_r0(dpm,
73 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
74 value);
75 if (retval != ERROR_OK)
76 goto done;
77 c_way -= 1;
78 } while (c_way >= 0);
79 c_index -= 1;
80 } while (c_index >= 0);
82 done:
83 keep_alive();
84 return retval;
87 static int armv7a_l1_d_cache_clean_inval_all(struct target *target)
89 struct armv7a_common *armv7a = target_to_armv7a(target);
90 struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache);
91 struct arm_dpm *dpm = armv7a->arm.dpm;
92 int cl;
93 int retval;
95 retval = armv7a_l1_d_cache_sanity_check(target);
96 if (retval != ERROR_OK)
97 return retval;
99 retval = dpm->prepare(dpm);
100 if (retval != ERROR_OK)
101 goto done;
103 for (cl = 0; cl < cache->loc; cl++) {
104 /* skip i-only caches */
105 if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE)
106 continue;
108 armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, cl);
111 retval = dpm->finish(dpm);
112 return retval;
114 done:
115 LOG_ERROR("clean invalidate failed");
116 dpm->finish(dpm);
118 return retval;
121 int armv7a_cache_auto_flush_all_data(struct target *target)
123 int retval = ERROR_FAIL;
124 struct armv7a_common *armv7a = target_to_armv7a(target);
126 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
127 return ERROR_OK;
129 if (target->smp) {
130 struct target_list *head;
131 foreach_smp_target(head, target->smp_targets) {
132 struct target *curr = head->target;
133 if (curr->state == TARGET_HALTED)
134 retval = armv7a_l1_d_cache_clean_inval_all(curr);
136 } else
137 retval = armv7a_l1_d_cache_clean_inval_all(target);
139 if (retval != ERROR_OK)
140 return retval;
142 /* do outer cache flushing after inner caches have been flushed */
143 return arm7a_l2x_flush_all_data(target);
147 int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
148 uint32_t size)
150 struct armv7a_common *armv7a = target_to_armv7a(target);
151 struct arm_dpm *dpm = armv7a->arm.dpm;
152 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
153 uint32_t linelen = armv7a_cache->dminline;
154 uint32_t va_line, va_end;
155 int retval, i = 0;
157 retval = armv7a_l1_d_cache_sanity_check(target);
158 if (retval != ERROR_OK)
159 return retval;
161 retval = dpm->prepare(dpm);
162 if (retval != ERROR_OK)
163 goto done;
165 va_line = virt & (-linelen);
166 va_end = virt + size;
168 /* handle unaligned start */
169 if (virt != va_line) {
170 /* DCCIMVAC */
171 retval = dpm->instr_write_data_r0(dpm,
172 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
173 if (retval != ERROR_OK)
174 goto done;
175 va_line += linelen;
178 /* handle unaligned end */
179 if ((va_end & (linelen-1)) != 0) {
180 va_end &= (-linelen);
181 /* DCCIMVAC */
182 retval = dpm->instr_write_data_r0(dpm,
183 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end);
184 if (retval != ERROR_OK)
185 goto done;
188 while (va_line < va_end) {
189 if ((i++ & 0x3f) == 0)
190 keep_alive();
191 /* DCIMVAC - Invalidate data cache line by VA to PoC. */
192 retval = dpm->instr_write_data_r0(dpm,
193 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
194 if (retval != ERROR_OK)
195 goto done;
196 va_line += linelen;
199 keep_alive();
200 dpm->finish(dpm);
201 return retval;
203 done:
204 LOG_ERROR("d-cache invalidate failed");
205 keep_alive();
206 dpm->finish(dpm);
208 return retval;
211 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
212 unsigned int size)
214 struct armv7a_common *armv7a = target_to_armv7a(target);
215 struct arm_dpm *dpm = armv7a->arm.dpm;
216 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
217 uint32_t linelen = armv7a_cache->dminline;
218 uint32_t va_line, va_end;
219 int retval, i = 0;
221 retval = armv7a_l1_d_cache_sanity_check(target);
222 if (retval != ERROR_OK)
223 return retval;
225 retval = dpm->prepare(dpm);
226 if (retval != ERROR_OK)
227 goto done;
229 va_line = virt & (-linelen);
230 va_end = virt + size;
232 while (va_line < va_end) {
233 if ((i++ & 0x3f) == 0)
234 keep_alive();
235 /* DCCMVAC - Data Cache Clean by MVA to PoC */
236 retval = dpm->instr_write_data_r0(dpm,
237 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line);
238 if (retval != ERROR_OK)
239 goto done;
240 va_line += linelen;
243 keep_alive();
244 dpm->finish(dpm);
245 return retval;
247 done:
248 LOG_ERROR("d-cache invalidate failed");
249 keep_alive();
250 dpm->finish(dpm);
252 return retval;
255 int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
256 unsigned int size)
258 struct armv7a_common *armv7a = target_to_armv7a(target);
259 struct arm_dpm *dpm = armv7a->arm.dpm;
260 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
261 uint32_t linelen = armv7a_cache->dminline;
262 uint32_t va_line, va_end;
263 int retval, i = 0;
265 retval = armv7a_l1_d_cache_sanity_check(target);
266 if (retval != ERROR_OK)
267 return retval;
269 retval = dpm->prepare(dpm);
270 if (retval != ERROR_OK)
271 goto done;
273 va_line = virt & (-linelen);
274 va_end = virt + size;
276 while (va_line < va_end) {
277 if ((i++ & 0x3f) == 0)
278 keep_alive();
279 /* DCCIMVAC */
280 retval = dpm->instr_write_data_r0(dpm,
281 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
282 if (retval != ERROR_OK)
283 goto done;
284 va_line += linelen;
287 keep_alive();
288 dpm->finish(dpm);
289 return retval;
291 done:
292 LOG_ERROR("d-cache invalidate failed");
293 keep_alive();
294 dpm->finish(dpm);
296 return retval;
299 int armv7a_l1_i_cache_inval_all(struct target *target)
301 struct armv7a_common *armv7a = target_to_armv7a(target);
302 struct arm_dpm *dpm = armv7a->arm.dpm;
303 int retval;
305 retval = armv7a_l1_i_cache_sanity_check(target);
306 if (retval != ERROR_OK)
307 return retval;
309 retval = dpm->prepare(dpm);
310 if (retval != ERROR_OK)
311 goto done;
313 if (target->smp) {
314 /* ICIALLUIS */
315 retval = dpm->instr_write_data_r0(dpm,
316 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
317 } else {
318 /* ICIALLU */
319 retval = dpm->instr_write_data_r0(dpm,
320 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
323 if (retval != ERROR_OK)
324 goto done;
326 dpm->finish(dpm);
327 return retval;
329 done:
330 LOG_ERROR("i-cache invalidate failed");
331 dpm->finish(dpm);
333 return retval;
336 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
337 uint32_t size)
339 struct armv7a_common *armv7a = target_to_armv7a(target);
340 struct arm_dpm *dpm = armv7a->arm.dpm;
341 struct armv7a_cache_common *armv7a_cache =
342 &armv7a->armv7a_mmu.armv7a_cache;
343 uint32_t linelen = armv7a_cache->iminline;
344 uint32_t va_line, va_end;
345 int retval, i = 0;
347 retval = armv7a_l1_i_cache_sanity_check(target);
348 if (retval != ERROR_OK)
349 return retval;
351 retval = dpm->prepare(dpm);
352 if (retval != ERROR_OK)
353 goto done;
355 va_line = virt & (-linelen);
356 va_end = virt + size;
358 while (va_line < va_end) {
359 if ((i++ & 0x3f) == 0)
360 keep_alive();
361 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
362 retval = dpm->instr_write_data_r0(dpm,
363 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
364 if (retval != ERROR_OK)
365 goto done;
366 /* BPIMVA */
367 retval = dpm->instr_write_data_r0(dpm,
368 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line);
369 if (retval != ERROR_OK)
370 goto done;
371 va_line += linelen;
373 keep_alive();
374 dpm->finish(dpm);
375 return retval;
377 done:
378 LOG_ERROR("i-cache invalidate failed");
379 keep_alive();
380 dpm->finish(dpm);
382 return retval;
385 int armv7a_cache_flush_virt(struct target *target, uint32_t virt,
386 uint32_t size)
388 armv7a_l1_d_cache_flush_virt(target, virt, size);
389 armv7a_l2x_cache_flush_virt(target, virt, size);
391 return ERROR_OK;
395 * We assume that target core was chosen correctly. It means if same data
396 * was handled by two cores, other core will loose the changes. Since it
397 * is impossible to know (FIXME) which core has correct data, keep in mind
398 * that some kind of data lost or corruption is possible.
399 * Possible scenario:
400 * - core1 loaded and changed data on 0x12345678
401 * - we halted target and modified same data on core0
402 * - data on core1 will be lost.
404 int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt,
405 uint32_t size)
407 struct armv7a_common *armv7a = target_to_armv7a(target);
409 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
410 return ERROR_OK;
412 return armv7a_cache_flush_virt(target, virt, size);
415 COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
417 struct target *target = get_current_target(CMD_CTX);
418 struct armv7a_common *armv7a = target_to_armv7a(target);
420 return armv7a_handle_cache_info_command(CMD,
421 &armv7a->armv7a_mmu.armv7a_cache);
424 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd)
426 struct target *target = get_current_target(CMD_CTX);
428 armv7a_l1_d_cache_clean_inval_all(target);
430 return 0;
433 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
435 struct target *target = get_current_target(CMD_CTX);
436 uint32_t virt, size;
438 if (CMD_ARGC == 0 || CMD_ARGC > 2)
439 return ERROR_COMMAND_SYNTAX_ERROR;
441 if (CMD_ARGC == 2)
442 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
443 else
444 size = 1;
446 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
448 return armv7a_l1_d_cache_inval_virt(target, virt, size);
451 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd)
453 struct target *target = get_current_target(CMD_CTX);
454 uint32_t virt, size;
456 if (CMD_ARGC == 0 || CMD_ARGC > 2)
457 return ERROR_COMMAND_SYNTAX_ERROR;
459 if (CMD_ARGC == 2)
460 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
461 else
462 size = 1;
464 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
466 return armv7a_l1_d_cache_clean_virt(target, virt, size);
469 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd)
471 struct target *target = get_current_target(CMD_CTX);
473 armv7a_l1_i_cache_inval_all(target);
475 return 0;
478 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
480 struct target *target = get_current_target(CMD_CTX);
481 uint32_t virt, size;
483 if (CMD_ARGC == 0 || CMD_ARGC > 2)
484 return ERROR_COMMAND_SYNTAX_ERROR;
486 if (CMD_ARGC == 2)
487 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
488 else
489 size = 1;
491 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
493 return armv7a_l1_i_cache_inval_virt(target, virt, size);
496 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd)
498 struct target *target = get_current_target(CMD_CTX);
499 struct armv7a_common *armv7a = target_to_armv7a(target);
501 if (CMD_ARGC == 0) {
502 command_print(CMD, "auto cache is %s",
503 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled ? "enabled" : "disabled");
504 return ERROR_OK;
507 if (CMD_ARGC == 1) {
508 uint32_t set;
510 COMMAND_PARSE_ENABLE(CMD_ARGV[0], set);
511 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = !!set;
512 return ERROR_OK;
515 return ERROR_COMMAND_SYNTAX_ERROR;
518 static const struct command_registration arm7a_l1_d_cache_commands[] = {
520 .name = "flush_all",
521 .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
522 .mode = COMMAND_ANY,
523 .help = "flush (clean and invalidate) complete l1 d-cache",
524 .usage = "",
527 .name = "inval",
528 .handler = arm7a_l1_d_cache_inval_virt_cmd,
529 .mode = COMMAND_ANY,
530 .help = "invalidate l1 d-cache by virtual address offset and range size",
531 .usage = "<virt_addr> [size]",
534 .name = "clean",
535 .handler = arm7a_l1_d_cache_clean_virt_cmd,
536 .mode = COMMAND_ANY,
537 .help = "clean l1 d-cache by virtual address address offset and range size",
538 .usage = "<virt_addr> [size]",
540 COMMAND_REGISTRATION_DONE
543 static const struct command_registration arm7a_l1_i_cache_commands[] = {
545 .name = "inval_all",
546 .handler = armv7a_i_cache_clean_inval_all_cmd,
547 .mode = COMMAND_ANY,
548 .help = "invalidate complete l1 i-cache",
549 .usage = "",
552 .name = "inval",
553 .handler = arm7a_l1_i_cache_inval_virt_cmd,
554 .mode = COMMAND_ANY,
555 .help = "invalidate l1 i-cache by virtual address offset and range size",
556 .usage = "<virt_addr> [size]",
558 COMMAND_REGISTRATION_DONE
561 static const struct command_registration arm7a_l1_di_cache_group_handlers[] = {
563 .name = "info",
564 .handler = arm7a_l1_cache_info_cmd,
565 .mode = COMMAND_ANY,
566 .help = "print cache related information",
567 .usage = "",
570 .name = "d",
571 .mode = COMMAND_ANY,
572 .help = "l1 d-cache command group",
573 .usage = "",
574 .chain = arm7a_l1_d_cache_commands,
577 .name = "i",
578 .mode = COMMAND_ANY,
579 .help = "l1 i-cache command group",
580 .usage = "",
581 .chain = arm7a_l1_i_cache_commands,
583 COMMAND_REGISTRATION_DONE
586 static const struct command_registration arm7a_cache_group_handlers[] = {
588 .name = "auto",
589 .handler = arm7a_cache_disable_auto_cmd,
590 .mode = COMMAND_ANY,
591 .help = "disable or enable automatic cache handling.",
592 .usage = "(1|0)",
595 .name = "l1",
596 .mode = COMMAND_ANY,
597 .help = "l1 cache command group",
598 .usage = "",
599 .chain = arm7a_l1_di_cache_group_handlers,
602 .chain = arm7a_l2x_cache_command_handler,
604 COMMAND_REGISTRATION_DONE
607 const struct command_registration arm7a_cache_command_handlers[] = {
609 .name = "cache",
610 .mode = COMMAND_ANY,
611 .help = "cache command group",
612 .usage = "",
613 .chain = arm7a_cache_group_handlers,
615 COMMAND_REGISTRATION_DONE