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 if (retval
!= ERROR_OK
)
154 /* do outer cache flushing after inner caches have been flushed */
155 return arm7a_l2x_flush_all_data(target
);
159 int armv7a_l1_d_cache_inval_virt(struct target
*target
, uint32_t virt
,
162 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
163 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
164 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
165 uint32_t linelen
= armv7a_cache
->dminline
;
166 uint32_t va_line
, va_end
;
169 retval
= armv7a_l1_d_cache_sanity_check(target
);
170 if (retval
!= ERROR_OK
)
173 retval
= dpm
->prepare(dpm
);
174 if (retval
!= ERROR_OK
)
177 va_line
= virt
& (-linelen
);
178 va_end
= virt
+ size
;
180 /* handle unaligned start */
181 if (virt
!= va_line
) {
183 retval
= dpm
->instr_write_data_r0(dpm
,
184 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line
);
185 if (retval
!= ERROR_OK
)
190 /* handle unaligned end */
191 if ((va_end
& (linelen
-1)) != 0) {
192 va_end
&= (-linelen
);
194 retval
= dpm
->instr_write_data_r0(dpm
,
195 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end
);
196 if (retval
!= ERROR_OK
)
200 while (va_line
< va_end
) {
201 /* DCIMVAC - Invalidate data cache line by VA to PoC. */
202 retval
= dpm
->instr_write_data_r0(dpm
,
203 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line
);
204 if (retval
!= ERROR_OK
)
213 LOG_ERROR("d-cache invalidate failed");
219 int armv7a_l1_d_cache_clean_virt(struct target
*target
, uint32_t virt
,
222 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
223 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
224 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
225 uint32_t linelen
= armv7a_cache
->dminline
;
226 uint32_t va_line
, va_end
;
229 retval
= armv7a_l1_d_cache_sanity_check(target
);
230 if (retval
!= ERROR_OK
)
233 retval
= dpm
->prepare(dpm
);
234 if (retval
!= ERROR_OK
)
237 va_line
= virt
& (-linelen
);
238 va_end
= virt
+ size
;
240 while (va_line
< va_end
) {
241 /* DCCMVAC - Data Cache Clean by MVA to PoC */
242 retval
= dpm
->instr_write_data_r0(dpm
,
243 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line
);
244 if (retval
!= ERROR_OK
)
253 LOG_ERROR("d-cache invalidate failed");
259 int armv7a_l1_d_cache_flush_virt(struct target
*target
, uint32_t virt
,
262 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
263 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
264 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
265 uint32_t linelen
= armv7a_cache
->dminline
;
266 uint32_t va_line
, va_end
;
269 retval
= armv7a_l1_d_cache_sanity_check(target
);
270 if (retval
!= ERROR_OK
)
273 retval
= dpm
->prepare(dpm
);
274 if (retval
!= ERROR_OK
)
277 va_line
= virt
& (-linelen
);
278 va_end
= virt
+ size
;
280 while (va_line
< va_end
) {
282 retval
= dpm
->instr_write_data_r0(dpm
,
283 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line
);
284 if (retval
!= ERROR_OK
)
293 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 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
360 retval
= dpm
->instr_write_data_r0(dpm
,
361 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
362 if (retval
!= ERROR_OK
)
365 retval
= dpm
->instr_write_data_r0(dpm
,
366 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
367 if (retval
!= ERROR_OK
)
374 LOG_ERROR("i-cache invalidate failed");
380 int armv7a_cache_flush_virt(struct target
*target
, uint32_t virt
,
383 armv7a_l1_d_cache_flush_virt(target
, virt
, size
);
384 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
390 * We assume that target core was chosen correctly. It means if same data
391 * was handled by two cores, other core will loose the changes. Since it
392 * is impossible to know (FIXME) which core has correct data, keep in mind
393 * that some kind of data lost or korruption is possible.
395 * - core1 loaded and changed data on 0x12345678
396 * - we halted target and modified same data on core0
397 * - data on core1 will be lost.
399 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
402 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
404 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
407 return armv7a_cache_flush_virt(target
, virt
, size
);
410 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
412 struct target
*target
= get_current_target(CMD_CTX
);
413 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
415 return armv7a_handle_cache_info_command(CMD_CTX
,
416 &armv7a
->armv7a_mmu
.armv7a_cache
);
419 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
421 struct target
*target
= get_current_target(CMD_CTX
);
423 armv7a_l1_d_cache_clean_inval_all(target
);
428 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
430 struct target
*target
= get_current_target(CMD_CTX
);
433 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
434 return ERROR_COMMAND_SYNTAX_ERROR
;
437 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
441 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
443 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
446 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd
)
448 struct target
*target
= get_current_target(CMD_CTX
);
451 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
452 return ERROR_COMMAND_SYNTAX_ERROR
;
455 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
459 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
461 return armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
464 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
466 struct target
*target
= get_current_target(CMD_CTX
);
468 armv7a_l1_i_cache_inval_all(target
);
473 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
475 struct target
*target
= get_current_target(CMD_CTX
);
478 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
479 return ERROR_COMMAND_SYNTAX_ERROR
;
482 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
486 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
488 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
491 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
493 struct target
*target
= get_current_target(CMD_CTX
);
494 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
497 command_print(CMD_CTX
, "auto cache is %s",
498 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
505 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
506 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
510 return ERROR_COMMAND_SYNTAX_ERROR
;
513 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
516 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
518 .help
= "flush (clean and invalidate) complete l1 d-cache",
523 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
525 .help
= "invalidate l1 d-cache by virtual address offset and range size",
526 .usage
= "<virt_addr> [size]",
530 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
532 .help
= "clean l1 d-cache by virtual address address offset and range size",
533 .usage
= "<virt_addr> [size]",
535 COMMAND_REGISTRATION_DONE
538 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
541 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
543 .help
= "invalidate complete l1 i-cache",
548 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
550 .help
= "invalidate l1 i-cache by virtual address offset and range size",
551 .usage
= "<virt_addr> [size]",
553 COMMAND_REGISTRATION_DONE
556 const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
559 .handler
= arm7a_l1_cache_info_cmd
,
561 .help
= "print cache realted information",
567 .help
= "l1 d-cache command group",
569 .chain
= arm7a_l1_d_cache_commands
,
574 .help
= "l1 i-cache command group",
576 .chain
= arm7a_l1_i_cache_commands
,
578 COMMAND_REGISTRATION_DONE
581 const struct command_registration arm7a_cache_group_handlers
[] = {
584 .handler
= arm7a_cache_disable_auto_cmd
,
586 .help
= "disable or enable automatic cache handling.",
592 .help
= "l1 cache command group",
594 .chain
= arm7a_l1_di_cache_group_handlers
,
597 .chain
= arm7a_l2x_cache_command_handler
,
599 COMMAND_REGISTRATION_DONE
602 const struct command_registration arm7a_cache_command_handlers
[] = {
606 .help
= "cache command group",
608 .chain
= arm7a_cache_group_handlers
,
610 COMMAND_REGISTRATION_DONE