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. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
23 #include "jtag/interface.h"
26 #include "armv7a_cache.h"
27 #include <helper/time_support.h>
28 #include "arm_opcodes.h"
30 static int armv7a_l1_d_cache_sanity_check(struct target *target)
32 struct armv7a_common *armv7a = target_to_armv7a(target);
34 if (target->state != TARGET_HALTED) {
35 LOG_ERROR("%s: target not halted", __func__);
36 return ERROR_TARGET_NOT_HALTED;
39 /* check that cache data is on at target halt */
40 if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
41 LOG_DEBUG("data cache is not enabled");
42 return ERROR_TARGET_INVALID;
48 static int armv7a_l1_i_cache_sanity_check(struct target *target)
50 struct armv7a_common *armv7a = target_to_armv7a(target);
52 if (target->state != TARGET_HALTED) {
53 LOG_ERROR("%s: target not halted", __func__);
54 return ERROR_TARGET_NOT_HALTED;
57 /* check that cache data is on at target halt */
58 if (!armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled) {
59 LOG_DEBUG("instruction cache is not enabled");
60 return ERROR_TARGET_INVALID;
66 static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl)
68 int retval = ERROR_OK;
69 int32_t c_way, c_index = size->index;
71 LOG_DEBUG("cl %" PRId32, cl);
75 uint32_t value = (c_index << size->index_shift)
76 | (c_way << size->way_shift) | (cl << 1);
78 * DCCISW - Clean and invalidate data cache
81 retval = dpm->instr_write_data_r0(dpm,
82 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
84 if (retval != ERROR_OK)
89 } while (c_index >= 0);
95 static int armv7a_l1_d_cache_clean_inval_all(struct target *target)
97 struct armv7a_common *armv7a = target_to_armv7a(target);
98 struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache);
99 struct arm_dpm *dpm = armv7a->arm.dpm;
103 retval = armv7a_l1_d_cache_sanity_check(target);
104 if (retval != ERROR_OK)
107 retval = dpm->prepare(dpm);
108 if (retval != ERROR_OK)
111 for (cl = 0; cl < cache->loc; cl++) {
112 /* skip i-only caches */
113 if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE)
116 armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, cl);
119 retval = dpm->finish(dpm);
123 LOG_ERROR("clean invalidate failed");
129 int armv7a_cache_auto_flush_all_data(struct target *target)
131 int retval = ERROR_FAIL;
132 struct armv7a_common *armv7a = target_to_armv7a(target);
134 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
138 struct target_list *head;
141 while (head != (struct target_list *)NULL) {
143 if (curr->state == TARGET_HALTED)
144 retval = armv7a_l1_d_cache_clean_inval_all(curr);
149 retval = armv7a_l1_d_cache_clean_inval_all(target);
151 /* do outer cache flushing after inner caches have been flushed */
152 retval = arm7a_l2x_flush_all_data(target);
158 int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
161 struct armv7a_common *armv7a = target_to_armv7a(target);
162 struct arm_dpm *dpm = armv7a->arm.dpm;
163 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
164 uint32_t linelen = armv7a_cache->dminline;
165 uint32_t va_line, va_end;
168 retval = armv7a_l1_d_cache_sanity_check(target);
169 if (retval != ERROR_OK)
172 retval = dpm->prepare(dpm);
173 if (retval != ERROR_OK)
176 va_line = virt & (-linelen);
177 va_end = virt + size;
179 /* handle unaligned start */
180 if (virt != va_line) {
182 retval = dpm->instr_write_data_r0(dpm,
183 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
184 if (retval != ERROR_OK)
189 /* handle unaligned end */
190 if ((va_end & (linelen-1)) != 0) {
191 va_end &= (-linelen);
193 retval = dpm->instr_write_data_r0(dpm,
194 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end);
195 if (retval != ERROR_OK)
199 while (va_line < va_end) {
200 /* DCIMVAC - Invalidate data cache line by VA to PoC. */
201 retval = dpm->instr_write_data_r0(dpm,
202 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
203 if (retval != ERROR_OK)
212 LOG_ERROR("d-cache invalidate failed");
218 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
221 struct armv7a_common *armv7a = target_to_armv7a(target);
222 struct arm_dpm *dpm = armv7a->arm.dpm;
223 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
224 uint32_t linelen = armv7a_cache->dminline;
225 uint32_t va_line, va_end;
228 retval = armv7a_l1_d_cache_sanity_check(target);
229 if (retval != ERROR_OK)
232 retval = dpm->prepare(dpm);
233 if (retval != ERROR_OK)
236 va_line = virt & (-linelen);
237 va_end = virt + size;
239 while (va_line < va_end) {
240 /* DCCMVAC - Data Cache Clean by MVA to PoC */
241 retval = dpm->instr_write_data_r0(dpm,
242 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line);
243 if (retval != ERROR_OK)
252 LOG_ERROR("d-cache invalidate failed");
258 int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
261 struct armv7a_common *armv7a = target_to_armv7a(target);
262 struct arm_dpm *dpm = armv7a->arm.dpm;
263 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
264 uint32_t linelen = armv7a_cache->dminline;
265 uint32_t va_line, va_end;
268 retval = armv7a_l1_d_cache_sanity_check(target);
269 if (retval != ERROR_OK)
272 retval = dpm->prepare(dpm);
273 if (retval != ERROR_OK)
276 va_line = virt & (-linelen);
277 va_end = virt + size;
279 while (va_line < va_end) {
281 retval = dpm->instr_write_data_r0(dpm,
282 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
283 if (retval != ERROR_OK)
292 LOG_ERROR("d-cache invalidate failed");
298 int armv7a_l1_i_cache_inval_all(struct target *target)
300 struct armv7a_common *armv7a = target_to_armv7a(target);
301 struct arm_dpm *dpm = armv7a->arm.dpm;
304 retval = armv7a_l1_i_cache_sanity_check(target);
305 if (retval != ERROR_OK)
308 retval = dpm->prepare(dpm);
309 if (retval != ERROR_OK)
314 retval = dpm->instr_write_data_r0(dpm,
315 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
318 retval = dpm->instr_write_data_r0(dpm,
319 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
322 if (retval != ERROR_OK)
329 LOG_ERROR("i-cache invalidate failed");
335 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
338 struct armv7a_common *armv7a = target_to_armv7a(target);
339 struct arm_dpm *dpm = armv7a->arm.dpm;
340 struct armv7a_cache_common *armv7a_cache =
341 &armv7a->armv7a_mmu.armv7a_cache;
342 uint32_t linelen = armv7a_cache->iminline;
343 uint32_t va_line, va_end;
346 retval = armv7a_l1_i_cache_sanity_check(target);
347 if (retval != ERROR_OK)
350 retval = dpm->prepare(dpm);
351 if (retval != ERROR_OK)
354 va_line = virt & (-linelen);
355 va_end = virt + size;
357 while (va_line < va_end) {
358 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
359 retval = dpm->instr_write_data_r0(dpm,
360 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
361 if (retval != ERROR_OK)
364 retval = dpm->instr_write_data_r0(dpm,
365 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line);
366 if (retval != ERROR_OK)
373 LOG_ERROR("i-cache invalidate failed");
379 int armv7a_cache_flush_virt(struct target *target, uint32_t virt,
382 armv7a_l1_d_cache_flush_virt(target, virt, size);
383 armv7a_l2x_cache_flush_virt(target, virt, size);
389 * We assume that target core was chosen correctly. It means if same data
390 * was handled by two cores, other core will loose the changes. Since it
391 * is impossible to know (FIXME) which core has correct data, keep in mind
392 * that some kind of data lost or korruption is possible.
394 * - core1 loaded and changed data on 0x12345678
395 * - we halted target and modified same data on core0
396 * - data on core1 will be lost.
398 int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt,
401 struct armv7a_common *armv7a = target_to_armv7a(target);
403 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
406 return armv7a_cache_flush_virt(target, virt, size);
409 COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
411 struct target *target = get_current_target(CMD_CTX);
412 struct armv7a_common *armv7a = target_to_armv7a(target);
414 return armv7a_handle_cache_info_command(CMD_CTX,
415 &armv7a->armv7a_mmu.armv7a_cache);
418 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd)
420 struct target *target = get_current_target(CMD_CTX);
422 armv7a_l1_d_cache_clean_inval_all(target);
427 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
429 struct target *target = get_current_target(CMD_CTX);
432 if (CMD_ARGC == 0 || CMD_ARGC > 2)
433 return ERROR_COMMAND_SYNTAX_ERROR;
436 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
440 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
442 return armv7a_l1_d_cache_inval_virt(target, virt, size);
445 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd)
447 struct target *target = get_current_target(CMD_CTX);
450 if (CMD_ARGC == 0 || CMD_ARGC > 2)
451 return ERROR_COMMAND_SYNTAX_ERROR;
454 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
458 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
460 return armv7a_l1_d_cache_clean_virt(target, virt, size);
463 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd)
465 struct target *target = get_current_target(CMD_CTX);
467 armv7a_l1_i_cache_inval_all(target);
472 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
474 struct target *target = get_current_target(CMD_CTX);
477 if (CMD_ARGC == 0 || CMD_ARGC > 2)
478 return ERROR_COMMAND_SYNTAX_ERROR;
481 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
485 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
487 return armv7a_l1_i_cache_inval_virt(target, virt, size);
490 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd)
492 struct target *target = get_current_target(CMD_CTX);
493 struct armv7a_common *armv7a = target_to_armv7a(target);
496 command_print(CMD_CTX, "auto cache is %s",
497 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled ? "enabled" : "disabled");
504 COMMAND_PARSE_ENABLE(CMD_ARGV[0], set);
505 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = !!set;
509 return ERROR_COMMAND_SYNTAX_ERROR;
512 static const struct command_registration arm7a_l1_d_cache_commands[] = {
515 .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
517 .help = "flush (clean and invalidate) complete l1 d-cache",
522 .handler = arm7a_l1_d_cache_inval_virt_cmd,
524 .help = "invalidate l1 d-cache by virtual address offset and range size",
525 .usage = "<virt_addr> [size]",
529 .handler = arm7a_l1_d_cache_clean_virt_cmd,
531 .help = "clean l1 d-cache by virtual address address offset and range size",
532 .usage = "<virt_addr> [size]",
534 COMMAND_REGISTRATION_DONE
537 static const struct command_registration arm7a_l1_i_cache_commands[] = {
540 .handler = armv7a_i_cache_clean_inval_all_cmd,
542 .help = "invalidate complete l1 i-cache",
547 .handler = arm7a_l1_i_cache_inval_virt_cmd,
549 .help = "invalidate l1 i-cache by virtual address offset and range size",
550 .usage = "<virt_addr> [size]",
552 COMMAND_REGISTRATION_DONE
555 const struct command_registration arm7a_l1_di_cache_group_handlers[] = {
558 .handler = arm7a_l1_cache_info_cmd,
560 .help = "print cache realted information",
566 .help = "l1 d-cache command group",
568 .chain = arm7a_l1_d_cache_commands,
573 .help = "l1 i-cache command group",
575 .chain = arm7a_l1_i_cache_commands,
577 COMMAND_REGISTRATION_DONE
580 const struct command_registration arm7a_cache_group_handlers[] = {
583 .handler = arm7a_cache_disable_auto_cmd,
585 .help = "disable or enable automatic cache handling.",
591 .help = "l1 cache command group",
593 .chain = arm7a_l1_di_cache_group_handlers,
596 .chain = arm7a_l2x_cache_command_handler,
598 COMMAND_REGISTRATION_DONE
601 const struct command_registration arm7a_cache_command_handlers[] = {
605 .help = "cache command group",
607 .chain = arm7a_cache_group_handlers,
609 COMMAND_REGISTRATION_DONE