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>
18 #include "target_type.h"
21 static int arm7a_l2x_sanity_check(struct target
*target
)
23 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
24 struct armv7a_l2x_cache
*l2x_cache
= (struct armv7a_l2x_cache
*)
25 (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
);
27 if (target
->state
!= TARGET_HALTED
) {
28 LOG_ERROR("%s: target not halted", __func__
);
29 return ERROR_TARGET_NOT_HALTED
;
32 if (!l2x_cache
|| !l2x_cache
->base
) {
33 LOG_DEBUG("l2x is not configured!");
40 * clean and invalidate complete l2x cache
42 int arm7a_l2x_flush_all_data(struct target
*target
)
44 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
45 struct armv7a_l2x_cache
*l2x_cache
= (struct armv7a_l2x_cache
*)
46 (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
);
50 retval
= arm7a_l2x_sanity_check(target
);
54 l2_way_val
= (1 << l2x_cache
->way
) - 1;
56 return target_write_phys_u32(target
,
57 l2x_cache
->base
+ L2X0_CLEAN_INV_WAY
,
61 int armv7a_l2x_cache_flush_virt(struct target
*target
, target_addr_t virt
,
64 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
65 struct armv7a_l2x_cache
*l2x_cache
= (struct armv7a_l2x_cache
*)
66 (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
);
67 /* FIXME: different controllers have different linelen? */
68 uint32_t i
, linelen
= 32;
71 retval
= arm7a_l2x_sanity_check(target
);
75 for (i
= 0; i
< size
; i
+= linelen
) {
76 target_addr_t pa
, offs
= virt
+ i
;
78 /* FIXME: use less verbose virt2phys? */
79 retval
= target
->type
->virt2phys(target
, offs
, &pa
);
80 if (retval
!= ERROR_OK
)
83 retval
= target_write_phys_u32(target
,
84 l2x_cache
->base
+ L2X0_CLEAN_INV_LINE_PA
, pa
);
85 if (retval
!= ERROR_OK
)
91 LOG_ERROR("d-cache invalidate failed");
96 static int armv7a_l2x_cache_inval_virt(struct target
*target
, target_addr_t virt
,
99 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
100 struct armv7a_l2x_cache
*l2x_cache
= (struct armv7a_l2x_cache
*)
101 (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
);
102 /* FIXME: different controllers have different linelen */
103 uint32_t i
, linelen
= 32;
106 retval
= arm7a_l2x_sanity_check(target
);
110 for (i
= 0; i
< size
; i
+= linelen
) {
111 target_addr_t pa
, offs
= virt
+ i
;
113 /* FIXME: use less verbose virt2phys? */
114 retval
= target
->type
->virt2phys(target
, offs
, &pa
);
115 if (retval
!= ERROR_OK
)
118 retval
= target_write_phys_u32(target
,
119 l2x_cache
->base
+ L2X0_INV_LINE_PA
, pa
);
120 if (retval
!= ERROR_OK
)
126 LOG_ERROR("d-cache invalidate failed");
131 static int armv7a_l2x_cache_clean_virt(struct target
*target
, target_addr_t virt
,
134 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
135 struct armv7a_l2x_cache
*l2x_cache
= (struct armv7a_l2x_cache
*)
136 (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
);
137 /* FIXME: different controllers have different linelen */
138 uint32_t i
, linelen
= 32;
141 retval
= arm7a_l2x_sanity_check(target
);
145 for (i
= 0; i
< size
; i
+= linelen
) {
146 target_addr_t pa
, offs
= virt
+ i
;
148 /* FIXME: use less verbose virt2phys? */
149 retval
= target
->type
->virt2phys(target
, offs
, &pa
);
150 if (retval
!= ERROR_OK
)
153 retval
= target_write_phys_u32(target
,
154 l2x_cache
->base
+ L2X0_CLEAN_LINE_PA
, pa
);
155 if (retval
!= ERROR_OK
)
161 LOG_ERROR("d-cache invalidate failed");
166 static int arm7a_handle_l2x_cache_info_command(struct command_invocation
*cmd
,
167 struct armv7a_cache_common
*armv7a_cache
)
169 struct armv7a_l2x_cache
*l2x_cache
= (struct armv7a_l2x_cache
*)
170 (armv7a_cache
->outer_cache
);
172 if (armv7a_cache
->info
== -1) {
173 command_print(cmd
, "cache not yet identified");
178 "L2 unified cache Base Address 0x%" PRIx32
", %" PRIu32
" ways",
179 l2x_cache
->base
, l2x_cache
->way
);
184 static int armv7a_l2x_cache_init(struct target
*target
, uint32_t base
, uint32_t way
)
186 struct armv7a_l2x_cache
*l2x_cache
;
187 struct target_list
*head
;
189 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
190 if (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
) {
191 LOG_ERROR("L2 cache was already initialised\n");
195 l2x_cache
= calloc(1, sizeof(struct armv7a_l2x_cache
));
196 l2x_cache
->base
= base
;
197 l2x_cache
->way
= way
;
198 armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
= l2x_cache
;
200 /* initialize all targets in this cluster (smp target)
201 * l2 cache must be configured after smp declaration */
202 foreach_smp_target(head
, target
->smp_targets
) {
203 struct target
*curr
= head
->target
;
204 if (curr
!= target
) {
205 armv7a
= target_to_armv7a(curr
);
206 if (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
) {
207 LOG_ERROR("smp target : cache l2 already initialized\n");
210 armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
= l2x_cache
;
216 COMMAND_HANDLER(arm7a_l2x_cache_info_command
)
218 struct target
*target
= get_current_target(CMD_CTX
);
219 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
222 retval
= arm7a_l2x_sanity_check(target
);
226 return arm7a_handle_l2x_cache_info_command(CMD
,
227 &armv7a
->armv7a_mmu
.armv7a_cache
);
230 COMMAND_HANDLER(arm7a_l2x_cache_flush_all_command
)
232 struct target
*target
= get_current_target(CMD_CTX
);
234 return arm7a_l2x_flush_all_data(target
);
237 COMMAND_HANDLER(arm7a_l2x_cache_flush_virt_cmd
)
239 struct target
*target
= get_current_target(CMD_CTX
);
243 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
244 return ERROR_COMMAND_SYNTAX_ERROR
;
247 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
251 COMMAND_PARSE_ADDRESS(CMD_ARGV
[0], virt
);
253 return armv7a_l2x_cache_flush_virt(target
, virt
, size
);
256 COMMAND_HANDLER(arm7a_l2x_cache_inval_virt_cmd
)
258 struct target
*target
= get_current_target(CMD_CTX
);
262 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
263 return ERROR_COMMAND_SYNTAX_ERROR
;
266 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
270 COMMAND_PARSE_ADDRESS(CMD_ARGV
[0], virt
);
272 return armv7a_l2x_cache_inval_virt(target
, virt
, size
);
275 COMMAND_HANDLER(arm7a_l2x_cache_clean_virt_cmd
)
277 struct target
*target
= get_current_target(CMD_CTX
);
281 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
282 return ERROR_COMMAND_SYNTAX_ERROR
;
285 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
289 COMMAND_PARSE_ADDRESS(CMD_ARGV
[0], virt
);
291 return armv7a_l2x_cache_clean_virt(target
, virt
, size
);
294 /* FIXME: should we configure way size? or controller type? */
295 COMMAND_HANDLER(armv7a_l2x_cache_conf_cmd
)
297 struct target
*target
= get_current_target(CMD_CTX
);
301 return ERROR_COMMAND_SYNTAX_ERROR
;
303 /* command_print(CMD, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
304 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], base
);
305 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], way
);
307 /* AP address is in bits 31:24 of DP_SELECT */
308 return armv7a_l2x_cache_init(target
, base
, way
);
311 static const struct command_registration arm7a_l2x_cache_commands
[] = {
314 .handler
= armv7a_l2x_cache_conf_cmd
,
316 .help
= "configure l2x cache",
317 .usage
= "<base_addr> <number_of_way>",
321 .handler
= arm7a_l2x_cache_info_command
,
323 .help
= "print cache related information",
328 .handler
= arm7a_l2x_cache_flush_all_command
,
330 .help
= "flush complete l2x cache",
335 .handler
= arm7a_l2x_cache_flush_virt_cmd
,
337 .help
= "flush (clean and invalidate) l2x cache by virtual address offset and range size",
338 .usage
= "<virt_addr> [size]",
342 .handler
= arm7a_l2x_cache_inval_virt_cmd
,
344 .help
= "invalidate l2x cache by virtual address offset and range size",
345 .usage
= "<virt_addr> [size]",
349 .handler
= arm7a_l2x_cache_clean_virt_cmd
,
351 .help
= "clean l2x cache by virtual address address offset and range size",
352 .usage
= "<virt_addr> [size]",
354 COMMAND_REGISTRATION_DONE
357 const struct command_registration arm7a_l2x_cache_command_handler
[] = {
361 .help
= "l2x cache command group",
363 .chain
= arm7a_l2x_cache_commands
,
365 COMMAND_REGISTRATION_DONE
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)