1 /***************************************************************************
2 * Copyright (C) 2015 by Oleksij Rempel *
3 * linux@rempel-privat.de *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 ***************************************************************************/
20 #include "jtag/interface.h"
23 #include "armv7a_cache.h"
24 #include <helper/time_support.h>
25 #include "arm_opcodes.h"
27 static int armv7a_l1_d_cache_sanity_check(struct target *target)
29 struct armv7a_common *armv7a = target_to_armv7a(target);
31 if (target->state != TARGET_HALTED) {
32 LOG_ERROR("%s: target not halted", __func__);
33 return ERROR_TARGET_NOT_HALTED;
36 /* check that cache data is on at target halt */
37 if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
38 LOG_DEBUG("data cache is not enabled");
39 return ERROR_TARGET_INVALID;
45 static int armv7a_l1_i_cache_sanity_check(struct target *target)
47 struct armv7a_common *armv7a = target_to_armv7a(target);
49 if (target->state != TARGET_HALTED) {
50 LOG_ERROR("%s: target not halted", __func__);
51 return ERROR_TARGET_NOT_HALTED;
54 /* check that cache data is on at target halt */
55 if (!armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled) {
56 LOG_DEBUG("instruction cache is not enabled");
57 return ERROR_TARGET_INVALID;
63 static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl)
65 int retval = ERROR_OK;
66 int32_t c_way, c_index = size->index;
68 LOG_DEBUG("cl %" PRId32, cl);
72 uint32_t value = (c_index << size->index_shift)
73 | (c_way << size->way_shift) | (cl << 1);
75 * DCCISW - Clean and invalidate data cache
78 retval = dpm->instr_write_data_r0(dpm,
79 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
81 if (retval != ERROR_OK)
86 } while (c_index >= 0);
92 static int armv7a_l1_d_cache_clean_inval_all(struct target *target)
94 struct armv7a_common *armv7a = target_to_armv7a(target);
95 struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache);
96 struct arm_dpm *dpm = armv7a->arm.dpm;
100 retval = armv7a_l1_d_cache_sanity_check(target);
101 if (retval != ERROR_OK)
104 retval = dpm->prepare(dpm);
105 if (retval != ERROR_OK)
108 for (cl = 0; cl < cache->loc; cl++) {
109 /* skip i-only caches */
110 if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE)
113 armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, cl);
116 retval = dpm->finish(dpm);
120 LOG_ERROR("clean invalidate failed");
126 int armv7a_cache_auto_flush_all_data(struct target *target)
128 int retval = ERROR_FAIL;
129 struct armv7a_common *armv7a = target_to_armv7a(target);
131 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
135 struct target_list *head;
138 while (head != (struct target_list *)NULL) {
140 if (curr->state == TARGET_HALTED)
141 retval = armv7a_l1_d_cache_clean_inval_all(curr);
146 retval = armv7a_l1_d_cache_clean_inval_all(target);
148 /* do outer cache flushing after inner caches have been flushed */
149 retval = arm7a_l2x_flush_all_data(target);
155 int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
158 struct armv7a_common *armv7a = target_to_armv7a(target);
159 struct arm_dpm *dpm = armv7a->arm.dpm;
160 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
161 uint32_t linelen = armv7a_cache->dminline;
162 uint32_t va_line, va_end;
165 retval = armv7a_l1_d_cache_sanity_check(target);
166 if (retval != ERROR_OK)
169 retval = dpm->prepare(dpm);
170 if (retval != ERROR_OK)
173 va_line = virt & (-linelen);
174 va_end = virt + size;
176 /* handle unaligned start */
177 if (virt != va_line) {
179 retval = dpm->instr_write_data_r0(dpm,
180 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
181 if (retval != ERROR_OK)
186 /* handle unaligned end */
187 if ((va_end & (linelen-1)) != 0) {
188 va_end &= (-linelen);
190 retval = dpm->instr_write_data_r0(dpm,
191 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end);
192 if (retval != ERROR_OK)
196 while (va_line < va_end) {
197 /* DCIMVAC - Invalidate data cache line by VA to PoC. */
198 retval = dpm->instr_write_data_r0(dpm,
199 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
200 if (retval != ERROR_OK)
209 LOG_ERROR("d-cache invalidate failed");
215 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
218 struct armv7a_common *armv7a = target_to_armv7a(target);
219 struct arm_dpm *dpm = armv7a->arm.dpm;
220 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
221 uint32_t i, linelen = armv7a_cache->dminline;
224 retval = armv7a_l1_d_cache_sanity_check(target);
225 if (retval != ERROR_OK)
228 retval = dpm->prepare(dpm);
229 if (retval != ERROR_OK)
232 for (i = 0; i < size; i += linelen) {
233 uint32_t offs = virt + i;
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), offs);
238 if (retval != ERROR_OK)
244 LOG_ERROR("d-cache invalidate failed");
250 int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
253 struct armv7a_common *armv7a = target_to_armv7a(target);
254 struct arm_dpm *dpm = armv7a->arm.dpm;
255 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
256 uint32_t i, linelen = armv7a_cache->dminline;
259 retval = armv7a_l1_d_cache_sanity_check(target);
260 if (retval != ERROR_OK)
263 retval = dpm->prepare(dpm);
264 if (retval != ERROR_OK)
267 for (i = 0; i < size; i += linelen) {
268 uint32_t offs = virt + i;
271 retval = dpm->instr_write_data_r0(dpm,
272 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), offs);
273 if (retval != ERROR_OK)
279 LOG_ERROR("d-cache invalidate failed");
285 int armv7a_l1_i_cache_inval_all(struct target *target)
287 struct armv7a_common *armv7a = target_to_armv7a(target);
288 struct arm_dpm *dpm = armv7a->arm.dpm;
291 retval = armv7a_l1_i_cache_sanity_check(target);
292 if (retval != ERROR_OK)
295 retval = dpm->prepare(dpm);
296 if (retval != ERROR_OK)
301 retval = dpm->instr_write_data_r0(dpm,
302 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
305 retval = dpm->instr_write_data_r0(dpm,
306 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
309 if (retval != ERROR_OK)
316 LOG_ERROR("i-cache invalidate failed");
322 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
325 struct armv7a_common *armv7a = target_to_armv7a(target);
326 struct arm_dpm *dpm = armv7a->arm.dpm;
327 struct armv7a_cache_common *armv7a_cache =
328 &armv7a->armv7a_mmu.armv7a_cache;
329 uint32_t linelen = armv7a_cache->iminline;
330 uint32_t va_line, va_end;
333 retval = armv7a_l1_i_cache_sanity_check(target);
334 if (retval != ERROR_OK)
337 retval = dpm->prepare(dpm);
338 if (retval != ERROR_OK)
341 va_line = virt & (-linelen);
342 va_end = virt + size;
344 while (va_line < va_end) {
345 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
346 retval = dpm->instr_write_data_r0(dpm,
347 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
348 if (retval != ERROR_OK)
351 retval = dpm->instr_write_data_r0(dpm,
352 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line);
353 if (retval != ERROR_OK)
360 LOG_ERROR("i-cache invalidate failed");
366 int armv7a_cache_flush_virt(struct target *target, uint32_t virt,
369 armv7a_l1_d_cache_flush_virt(target, virt, size);
370 armv7a_l2x_cache_flush_virt(target, virt, size);
376 * We assume that target core was chosen correctly. It means if same data
377 * was handled by two cores, other core will loose the changes. Since it
378 * is impossible to know (FIXME) which core has correct data, keep in mind
379 * that some kind of data lost or korruption is possible.
381 * - core1 loaded and changed data on 0x12345678
382 * - we halted target and modified same data on core0
383 * - data on core1 will be lost.
385 int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt,
388 struct armv7a_common *armv7a = target_to_armv7a(target);
390 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
393 return armv7a_cache_flush_virt(target, virt, size);
396 COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
398 struct target *target = get_current_target(CMD_CTX);
399 struct armv7a_common *armv7a = target_to_armv7a(target);
401 return armv7a_handle_cache_info_command(CMD_CTX,
402 &armv7a->armv7a_mmu.armv7a_cache);
405 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd)
407 struct target *target = get_current_target(CMD_CTX);
409 armv7a_l1_d_cache_clean_inval_all(target);
414 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
416 struct target *target = get_current_target(CMD_CTX);
419 if (CMD_ARGC == 0 || CMD_ARGC > 2)
420 return ERROR_COMMAND_SYNTAX_ERROR;
423 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
427 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
429 return armv7a_l1_d_cache_inval_virt(target, virt, size);
432 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd)
434 struct target *target = get_current_target(CMD_CTX);
437 if (CMD_ARGC == 0 || CMD_ARGC > 2)
438 return ERROR_COMMAND_SYNTAX_ERROR;
441 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
445 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
447 return armv7a_l1_d_cache_clean_virt(target, virt, size);
450 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd)
452 struct target *target = get_current_target(CMD_CTX);
454 armv7a_l1_i_cache_inval_all(target);
459 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
461 struct target *target = get_current_target(CMD_CTX);
464 if (CMD_ARGC == 0 || CMD_ARGC > 2)
465 return ERROR_COMMAND_SYNTAX_ERROR;
468 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
472 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
474 return armv7a_l1_i_cache_inval_virt(target, virt, size);
477 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd)
479 struct target *target = get_current_target(CMD_CTX);
480 struct armv7a_common *armv7a = target_to_armv7a(target);
483 command_print(CMD_CTX, "auto cache is %s",
484 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled ? "enabled" : "disabled");
491 COMMAND_PARSE_ENABLE(CMD_ARGV[0], set);
492 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = !!set;
496 return ERROR_COMMAND_SYNTAX_ERROR;
499 static const struct command_registration arm7a_l1_d_cache_commands[] = {
502 .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
504 .help = "flush (clean and invalidate) complete l1 d-cache",
509 .handler = arm7a_l1_d_cache_inval_virt_cmd,
511 .help = "invalidate l1 d-cache by virtual address offset and range size",
512 .usage = "<virt_addr> [size]",
516 .handler = arm7a_l1_d_cache_clean_virt_cmd,
518 .help = "clean l1 d-cache by virtual address address offset and range size",
519 .usage = "<virt_addr> [size]",
521 COMMAND_REGISTRATION_DONE
524 static const struct command_registration arm7a_l1_i_cache_commands[] = {
527 .handler = armv7a_i_cache_clean_inval_all_cmd,
529 .help = "invalidate complete l1 i-cache",
534 .handler = arm7a_l1_i_cache_inval_virt_cmd,
536 .help = "invalidate l1 i-cache by virtual address offset and range size",
537 .usage = "<virt_addr> [size]",
539 COMMAND_REGISTRATION_DONE
542 const struct command_registration arm7a_l1_di_cache_group_handlers[] = {
545 .handler = arm7a_l1_cache_info_cmd,
547 .help = "print cache realted information",
553 .help = "l1 d-cache command group",
555 .chain = arm7a_l1_d_cache_commands,
560 .help = "l1 i-cache command group",
562 .chain = arm7a_l1_i_cache_commands,
564 COMMAND_REGISTRATION_DONE
567 const struct command_registration arm7a_cache_group_handlers[] = {
570 .handler = arm7a_cache_disable_auto_cmd,
572 .help = "disable or enable automatic cache handling.",
578 .help = "l1 cache command group",
580 .chain = arm7a_l1_di_cache_group_handlers,
583 .chain = arm7a_l2x_cache_command_handler,
585 COMMAND_REGISTRATION_DONE
588 const struct command_registration arm7a_cache_command_handlers[] = {
592 .help = "cache command group",
594 .chain = arm7a_cache_group_handlers,
596 COMMAND_REGISTRATION_DONE