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