1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2015 by Oleksij Rempel *
5 * linux@rempel-privat.de *
6 ***************************************************************************/
12 #include "jtag/interface.h"
15 #include "armv7a_cache.h"
16 #include <helper/time_support.h>
17 #include "arm_opcodes.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_ERROR("%s: target not halted", __func__);
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;
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_ERROR("%s: target not halted", __func__);
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;
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);
66 uint32_t value = (c_index << size->index_shift)
67 | (c_way << size->way_shift) | (cl << 1);
69 * DCCISW - Clean and invalidate data cache
72 retval = dpm->instr_write_data_r0(dpm,
73 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
75 if (retval != ERROR_OK)
80 } while (c_index >= 0);
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;
95 retval = armv7a_l1_d_cache_sanity_check(target);
96 if (retval != ERROR_OK)
99 retval = dpm->prepare(dpm);
100 if (retval != ERROR_OK)
103 for (cl = 0; cl < cache->loc; cl++) {
104 /* skip i-only caches */
105 if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE)
108 armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, cl);
111 retval = dpm->finish(dpm);
115 LOG_ERROR("clean invalidate failed");
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)
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);
137 retval = armv7a_l1_d_cache_clean_inval_all(target);
139 if (retval != ERROR_OK)
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,
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;
157 retval = armv7a_l1_d_cache_sanity_check(target);
158 if (retval != ERROR_OK)
161 retval = dpm->prepare(dpm);
162 if (retval != ERROR_OK)
165 va_line = virt & (-linelen);
166 va_end = virt + size;
168 /* handle unaligned start */
169 if (virt != va_line) {
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)
178 /* handle unaligned end */
179 if ((va_end & (linelen-1)) != 0) {
180 va_end &= (-linelen);
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)
188 while (va_line < va_end) {
189 if ((i++ & 0x3f) == 0)
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)
204 LOG_ERROR("d-cache invalidate failed");
211 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
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;
221 retval = armv7a_l1_d_cache_sanity_check(target);
222 if (retval != ERROR_OK)
225 retval = dpm->prepare(dpm);
226 if (retval != ERROR_OK)
229 va_line = virt & (-linelen);
230 va_end = virt + size;
232 while (va_line < va_end) {
233 if ((i++ & 0x3f) == 0)
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)
248 LOG_ERROR("d-cache invalidate failed");
255 int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
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;
265 retval = armv7a_l1_d_cache_sanity_check(target);
266 if (retval != ERROR_OK)
269 retval = dpm->prepare(dpm);
270 if (retval != ERROR_OK)
273 va_line = virt & (-linelen);
274 va_end = virt + size;
276 while (va_line < va_end) {
277 if ((i++ & 0x3f) == 0)
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)
292 LOG_ERROR("d-cache invalidate failed");
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;
305 retval = armv7a_l1_i_cache_sanity_check(target);
306 if (retval != ERROR_OK)
309 retval = dpm->prepare(dpm);
310 if (retval != ERROR_OK)
315 retval = dpm->instr_write_data_r0(dpm,
316 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
319 retval = dpm->instr_write_data_r0(dpm,
320 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
323 if (retval != ERROR_OK)
330 LOG_ERROR("i-cache invalidate failed");
336 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
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;
347 retval = armv7a_l1_i_cache_sanity_check(target);
348 if (retval != ERROR_OK)
351 retval = dpm->prepare(dpm);
352 if (retval != ERROR_OK)
355 va_line = virt & (-linelen);
356 va_end = virt + size;
358 while (va_line < va_end) {
359 if ((i++ & 0x3f) == 0)
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)
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)
378 LOG_ERROR("i-cache invalidate failed");
385 int armv7a_cache_flush_virt(struct target *target, uint32_t virt,
388 armv7a_l1_d_cache_flush_virt(target, virt, size);
389 armv7a_l2x_cache_flush_virt(target, virt, size);
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.
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,
407 struct armv7a_common *armv7a = target_to_armv7a(target);
409 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
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);
433 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
435 struct target *target = get_current_target(CMD_CTX);
438 if (CMD_ARGC == 0 || CMD_ARGC > 2)
439 return ERROR_COMMAND_SYNTAX_ERROR;
442 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
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);
456 if (CMD_ARGC == 0 || CMD_ARGC > 2)
457 return ERROR_COMMAND_SYNTAX_ERROR;
460 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
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);
478 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
480 struct target *target = get_current_target(CMD_CTX);
483 if (CMD_ARGC == 0 || CMD_ARGC > 2)
484 return ERROR_COMMAND_SYNTAX_ERROR;
487 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
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);
502 command_print(CMD, "auto cache is %s",
503 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled ? "enabled" : "disabled");
510 COMMAND_PARSE_ENABLE(CMD_ARGV[0], set);
511 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = !!set;
515 return ERROR_COMMAND_SYNTAX_ERROR;
518 static const struct command_registration arm7a_l1_d_cache_commands[] = {
521 .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
523 .help = "flush (clean and invalidate) complete l1 d-cache",
528 .handler = arm7a_l1_d_cache_inval_virt_cmd,
530 .help = "invalidate l1 d-cache by virtual address offset and range size",
531 .usage = "<virt_addr> [size]",
535 .handler = arm7a_l1_d_cache_clean_virt_cmd,
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[] = {
546 .handler = armv7a_i_cache_clean_inval_all_cmd,
548 .help = "invalidate complete l1 i-cache",
553 .handler = arm7a_l1_i_cache_inval_virt_cmd,
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[] = {
564 .handler = arm7a_l1_cache_info_cmd,
566 .help = "print cache related information",
572 .help = "l1 d-cache command group",
574 .chain = arm7a_l1_d_cache_commands,
579 .help = "l1 i-cache command group",
581 .chain = arm7a_l1_i_cache_commands,
583 COMMAND_REGISTRATION_DONE
586 static const struct command_registration arm7a_cache_group_handlers[] = {
589 .handler = arm7a_cache_disable_auto_cmd,
591 .help = "disable or enable automatic cache handling.",
597 .help = "l1 cache command group",
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[] = {
611 .help = "cache command group",
613 .chain = arm7a_cache_group_handlers,
615 COMMAND_REGISTRATION_DONE