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