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("l1 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("l1 data cache is not enabled");
57 return ERROR_TARGET_INVALID
;
63 static int armv7a_l1_d_cache_clean_inval_all(struct target
*target
)
65 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
66 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
67 struct armv7a_cachesize
*d_u_size
=
68 &(armv7a
->armv7a_mmu
.armv7a_cache
.d_u_size
);
69 int32_t c_way
, c_index
= d_u_size
->index
;
72 retval
= armv7a_l1_d_cache_sanity_check(target
);
73 if (retval
!= ERROR_OK
)
76 retval
= dpm
->prepare(dpm
);
77 if (retval
!= ERROR_OK
)
81 c_way
= d_u_size
->way
;
83 uint32_t value
= (c_index
<< d_u_size
->index_shift
)
84 | (c_way
<< d_u_size
->way_shift
);
86 * DCCISW - Clean and invalidate data cache
89 retval
= dpm
->instr_write_data_r0(dpm
,
90 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
92 if (retval
!= ERROR_OK
)
97 } while (c_index
>= 0);
102 LOG_ERROR("clean invalidate failed");
108 int armv7a_cache_auto_flush_all_data(struct target
*target
)
110 int retval
= ERROR_FAIL
;
111 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
113 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
117 struct target_list
*head
;
120 while (head
!= (struct target_list
*)NULL
) {
122 if (curr
->state
== TARGET_HALTED
)
123 retval
= armv7a_l1_d_cache_clean_inval_all(curr
);
128 retval
= armv7a_l1_d_cache_clean_inval_all(target
);
130 /* do outer cache flushing after inner caches have been flushed */
131 retval
= arm7a_l2x_flush_all_data(target
);
137 static int armv7a_l1_d_cache_inval_virt(struct target
*target
, uint32_t virt
,
140 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
141 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
142 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
143 uint32_t i
, linelen
= armv7a_cache
->dminline
;
146 retval
= armv7a_l1_d_cache_sanity_check(target
);
147 if (retval
!= ERROR_OK
)
150 retval
= dpm
->prepare(dpm
);
151 if (retval
!= ERROR_OK
)
154 for (i
= 0; i
< size
; i
+= linelen
) {
155 uint32_t offs
= virt
+ i
;
157 /* DCIMVAC - Clean and invalidate data cache line by VA to PoC. */
158 retval
= dpm
->instr_write_data_r0(dpm
,
159 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), offs
);
160 if (retval
!= ERROR_OK
)
166 LOG_ERROR("d-cache invalidate failed");
172 int armv7a_l1_d_cache_clean_virt(struct target
*target
, uint32_t virt
,
175 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
176 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
177 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
178 uint32_t i
, linelen
= armv7a_cache
->dminline
;
181 retval
= armv7a_l1_d_cache_sanity_check(target
);
182 if (retval
!= ERROR_OK
)
185 retval
= dpm
->prepare(dpm
);
186 if (retval
!= ERROR_OK
)
189 for (i
= 0; i
< size
; i
+= linelen
) {
190 uint32_t offs
= virt
+ i
;
192 /* FIXME: do we need DCCVAC or DCCVAU */
193 /* FIXME: in both cases it is not enough for i-cache */
194 retval
= dpm
->instr_write_data_r0(dpm
,
195 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), offs
);
196 if (retval
!= ERROR_OK
)
202 LOG_ERROR("d-cache invalidate failed");
208 int armv7a_l1_i_cache_inval_all(struct target
*target
)
210 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
211 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
214 retval
= armv7a_l1_i_cache_sanity_check(target
);
215 if (retval
!= ERROR_OK
)
218 retval
= dpm
->prepare(dpm
);
219 if (retval
!= ERROR_OK
)
224 retval
= dpm
->instr_write_data_r0(dpm
,
225 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
228 retval
= dpm
->instr_write_data_r0(dpm
,
229 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
232 if (retval
!= ERROR_OK
)
239 LOG_ERROR("i-cache invalidate failed");
245 int armv7a_l1_i_cache_inval_virt(struct target
*target
, uint32_t virt
,
248 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
249 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
250 struct armv7a_cache_common
*armv7a_cache
=
251 &armv7a
->armv7a_mmu
.armv7a_cache
;
252 uint32_t linelen
= armv7a_cache
->iminline
;
253 uint32_t va_line
, va_end
;
256 retval
= armv7a_l1_i_cache_sanity_check(target
);
257 if (retval
!= ERROR_OK
)
260 retval
= dpm
->prepare(dpm
);
261 if (retval
!= ERROR_OK
)
264 va_line
= virt
& (-linelen
);
265 va_end
= virt
+ size
;
267 while (va_line
< va_end
) {
268 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
269 retval
= dpm
->instr_write_data_r0(dpm
,
270 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
271 if (retval
!= ERROR_OK
)
274 retval
= dpm
->instr_write_data_r0(dpm
,
275 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
276 if (retval
!= ERROR_OK
)
283 LOG_ERROR("i-cache invalidate failed");
291 * We assume that target core was chosen correctly. It means if same data
292 * was handled by two cores, other core will loose the changes. Since it
293 * is impossible to know (FIXME) which core has correct data, keep in mind
294 * that some kind of data lost or korruption is possible.
296 * - core1 loaded and changed data on 0x12345678
297 * - we halted target and modified same data on core0
298 * - data on core1 will be lost.
300 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
303 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
304 int retval
= ERROR_OK
;
306 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
309 armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
310 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
313 struct target_list
*head
;
316 while (head
!= (struct target_list
*)NULL
) {
318 if (curr
->state
== TARGET_HALTED
) {
319 retval
= armv7a_l1_i_cache_inval_all(curr
);
320 if (retval
!= ERROR_OK
)
322 retval
= armv7a_l1_d_cache_inval_virt(target
,
324 if (retval
!= ERROR_OK
)
330 retval
= armv7a_l1_i_cache_inval_all(target
);
331 if (retval
!= ERROR_OK
)
333 retval
= armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
334 if (retval
!= ERROR_OK
)
341 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
343 struct target
*target
= get_current_target(CMD_CTX
);
344 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
346 return armv7a_handle_cache_info_command(CMD_CTX
,
347 &armv7a
->armv7a_mmu
.armv7a_cache
);
350 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
352 struct target
*target
= get_current_target(CMD_CTX
);
354 armv7a_l1_d_cache_clean_inval_all(target
);
359 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
361 struct target
*target
= get_current_target(CMD_CTX
);
364 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
365 return ERROR_COMMAND_SYNTAX_ERROR
;
368 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
372 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
374 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
377 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd
)
379 struct target
*target
= get_current_target(CMD_CTX
);
382 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
383 return ERROR_COMMAND_SYNTAX_ERROR
;
386 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
390 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
392 return armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
395 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
397 struct target
*target
= get_current_target(CMD_CTX
);
399 armv7a_l1_i_cache_inval_all(target
);
404 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
406 struct target
*target
= get_current_target(CMD_CTX
);
409 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
410 return ERROR_COMMAND_SYNTAX_ERROR
;
413 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
417 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
419 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
422 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
424 struct target
*target
= get_current_target(CMD_CTX
);
425 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
428 command_print(CMD_CTX
, "auto cache is %s",
429 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
436 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
437 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
441 return ERROR_COMMAND_SYNTAX_ERROR
;
444 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
447 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
449 .help
= "flush (clean and invalidate) complete l1 d-cache",
454 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
456 .help
= "invalidate l1 d-cache by virtual address offset and range size",
457 .usage
= "<virt_addr> [size]",
461 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
463 .help
= "clean l1 d-cache by virtual address address offset and range size",
464 .usage
= "<virt_addr> [size]",
466 COMMAND_REGISTRATION_DONE
469 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
472 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
474 .help
= "invalidate complete l1 i-cache",
479 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
481 .help
= "invalidate l1 i-cache by virtual address offset and range size",
482 .usage
= "<virt_addr> [size]",
484 COMMAND_REGISTRATION_DONE
487 const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
490 .handler
= arm7a_l1_cache_info_cmd
,
492 .help
= "print cache realted information",
498 .help
= "l1 d-cache command group",
500 .chain
= arm7a_l1_d_cache_commands
,
505 .help
= "l1 i-cache command group",
507 .chain
= arm7a_l1_i_cache_commands
,
509 COMMAND_REGISTRATION_DONE
512 const struct command_registration arm7a_cache_group_handlers
[] = {
515 .handler
= arm7a_cache_disable_auto_cmd
,
517 .help
= "disable or enable automatic cache handling.",
523 .help
= "l1 cache command group",
525 .chain
= arm7a_l1_di_cache_group_handlers
,
528 .chain
= arm7a_l2x_cache_command_handler
,
530 COMMAND_REGISTRATION_DONE
533 const struct command_registration arm7a_cache_command_handlers
[] = {
537 .help
= "cache command group",
539 .chain
= arm7a_cache_group_handlers
,
541 COMMAND_REGISTRATION_DONE