jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / target / armv7a_cache.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2015 by Oleksij Rempel *
5 * linux@rempel-privat.de *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "jtag/interface.h"
13 #include "arm.h"
14 #include "armv7a.h"
15 #include "armv7a_cache.h"
16 #include <helper/time_support.h>
17 #include "arm_opcodes.h"
18 #include "smp.h"
19
20 static int armv7a_l1_d_cache_sanity_check(struct target *target)
21 {
22 struct armv7a_common *armv7a = target_to_armv7a(target);
23
24 if (target->state != TARGET_HALTED) {
25 LOG_TARGET_ERROR(target, "not halted");
26 return ERROR_TARGET_NOT_HALTED;
27 }
28
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;
33 }
34
35 return ERROR_OK;
36 }
37
38 static int armv7a_l1_i_cache_sanity_check(struct target *target)
39 {
40 struct armv7a_common *armv7a = target_to_armv7a(target);
41
42 if (target->state != TARGET_HALTED) {
43 LOG_TARGET_ERROR(target, "not halted");
44 return ERROR_TARGET_NOT_HALTED;
45 }
46
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;
51 }
52
53 return ERROR_OK;
54 }
55
56 static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl)
57 {
58 int retval = ERROR_OK;
59 int32_t c_way, c_index = size->index;
60
61 LOG_DEBUG("cl %" PRId32, cl);
62 do {
63 keep_alive();
64 c_way = size->way;
65 do {
66 uint32_t value = (c_index << size->index_shift)
67 | (c_way << size->way_shift) | (cl << 1);
68 /*
69 * DCCISW - Clean and invalidate data cache
70 * line by Set/Way.
71 */
72 retval = dpm->instr_write_data_r0(dpm,
73 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
74 value);
75 if (retval != ERROR_OK)
76 goto done;
77 c_way -= 1;
78 } while (c_way >= 0);
79 c_index -= 1;
80 } while (c_index >= 0);
81
82 done:
83 keep_alive();
84 return retval;
85 }
86
87 static int armv7a_l1_d_cache_clean_inval_all(struct target *target)
88 {
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;
92 int cl;
93 int retval;
94
95 retval = armv7a_l1_d_cache_sanity_check(target);
96 if (retval != ERROR_OK)
97 return retval;
98
99 retval = dpm->prepare(dpm);
100 if (retval != ERROR_OK)
101 goto done;
102
103 for (cl = 0; cl < cache->loc; cl++) {
104 /* skip i-only caches */
105 if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE)
106 continue;
107
108 armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, cl);
109 }
110
111 retval = dpm->finish(dpm);
112 return retval;
113
114 done:
115 LOG_ERROR("clean invalidate failed");
116 dpm->finish(dpm);
117
118 return retval;
119 }
120
121 int armv7a_cache_auto_flush_all_data(struct target *target)
122 {
123 int retval = ERROR_FAIL;
124 struct armv7a_common *armv7a = target_to_armv7a(target);
125
126 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
127 return ERROR_OK;
128
129 if (target->smp) {
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);
135 }
136 } else
137 retval = armv7a_l1_d_cache_clean_inval_all(target);
138
139 if (retval != ERROR_OK)
140 return retval;
141
142 /* do outer cache flushing after inner caches have been flushed */
143 return arm7a_l2x_flush_all_data(target);
144 }
145
146
147 int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
148 uint32_t size)
149 {
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;
155 int retval, i = 0;
156
157 retval = armv7a_l1_d_cache_sanity_check(target);
158 if (retval != ERROR_OK)
159 return retval;
160
161 retval = dpm->prepare(dpm);
162 if (retval != ERROR_OK)
163 goto done;
164
165 va_line = virt & (-linelen);
166 va_end = virt + size;
167
168 /* handle unaligned start */
169 if (virt != va_line) {
170 /* DCCIMVAC */
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)
174 goto done;
175 va_line += linelen;
176 }
177
178 /* handle unaligned end */
179 if ((va_end & (linelen-1)) != 0) {
180 va_end &= (-linelen);
181 /* DCCIMVAC */
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)
185 goto done;
186 }
187
188 while (va_line < va_end) {
189 if ((i++ & 0x3f) == 0)
190 keep_alive();
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)
195 goto done;
196 va_line += linelen;
197 }
198
199 keep_alive();
200 dpm->finish(dpm);
201 return retval;
202
203 done:
204 LOG_ERROR("d-cache invalidate failed");
205 keep_alive();
206 dpm->finish(dpm);
207
208 return retval;
209 }
210
211 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
212 unsigned int size)
213 {
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;
219 int retval, i = 0;
220
221 retval = armv7a_l1_d_cache_sanity_check(target);
222 if (retval != ERROR_OK)
223 return retval;
224
225 retval = dpm->prepare(dpm);
226 if (retval != ERROR_OK)
227 goto done;
228
229 va_line = virt & (-linelen);
230 va_end = virt + size;
231
232 while (va_line < va_end) {
233 if ((i++ & 0x3f) == 0)
234 keep_alive();
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)
239 goto done;
240 va_line += linelen;
241 }
242
243 keep_alive();
244 dpm->finish(dpm);
245 return retval;
246
247 done:
248 LOG_ERROR("d-cache invalidate failed");
249 keep_alive();
250 dpm->finish(dpm);
251
252 return retval;
253 }
254
255 int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
256 unsigned int size)
257 {
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;
263 int retval, i = 0;
264
265 retval = armv7a_l1_d_cache_sanity_check(target);
266 if (retval != ERROR_OK)
267 return retval;
268
269 retval = dpm->prepare(dpm);
270 if (retval != ERROR_OK)
271 goto done;
272
273 va_line = virt & (-linelen);
274 va_end = virt + size;
275
276 while (va_line < va_end) {
277 if ((i++ & 0x3f) == 0)
278 keep_alive();
279 /* DCCIMVAC */
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)
283 goto done;
284 va_line += linelen;
285 }
286
287 keep_alive();
288 dpm->finish(dpm);
289 return retval;
290
291 done:
292 LOG_ERROR("d-cache invalidate failed");
293 keep_alive();
294 dpm->finish(dpm);
295
296 return retval;
297 }
298
299 int armv7a_l1_i_cache_inval_all(struct target *target)
300 {
301 struct armv7a_common *armv7a = target_to_armv7a(target);
302 struct arm_dpm *dpm = armv7a->arm.dpm;
303 int retval;
304
305 retval = armv7a_l1_i_cache_sanity_check(target);
306 if (retval != ERROR_OK)
307 return retval;
308
309 retval = dpm->prepare(dpm);
310 if (retval != ERROR_OK)
311 goto done;
312
313 if (target->smp) {
314 /* ICIALLUIS */
315 retval = dpm->instr_write_data_r0(dpm,
316 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
317 } else {
318 /* ICIALLU */
319 retval = dpm->instr_write_data_r0(dpm,
320 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
321 }
322
323 if (retval != ERROR_OK)
324 goto done;
325
326 dpm->finish(dpm);
327 return retval;
328
329 done:
330 LOG_ERROR("i-cache invalidate failed");
331 dpm->finish(dpm);
332
333 return retval;
334 }
335
336 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
337 uint32_t size)
338 {
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;
345 int retval, i = 0;
346
347 retval = armv7a_l1_i_cache_sanity_check(target);
348 if (retval != ERROR_OK)
349 return retval;
350
351 retval = dpm->prepare(dpm);
352 if (retval != ERROR_OK)
353 goto done;
354
355 va_line = virt & (-linelen);
356 va_end = virt + size;
357
358 while (va_line < va_end) {
359 if ((i++ & 0x3f) == 0)
360 keep_alive();
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)
365 goto done;
366 /* BPIMVA */
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)
370 goto done;
371 va_line += linelen;
372 }
373 keep_alive();
374 dpm->finish(dpm);
375 return retval;
376
377 done:
378 LOG_ERROR("i-cache invalidate failed");
379 keep_alive();
380 dpm->finish(dpm);
381
382 return retval;
383 }
384
385 int armv7a_cache_flush_virt(struct target *target, uint32_t virt,
386 uint32_t size)
387 {
388 armv7a_l1_d_cache_flush_virt(target, virt, size);
389 armv7a_l2x_cache_flush_virt(target, virt, size);
390
391 return ERROR_OK;
392 }
393
394 /*
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.
399 * Possible scenario:
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.
403 */
404 int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt,
405 uint32_t size)
406 {
407 struct armv7a_common *armv7a = target_to_armv7a(target);
408
409 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
410 return ERROR_OK;
411
412 return armv7a_cache_flush_virt(target, virt, size);
413 }
414
415 COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
416 {
417 struct target *target = get_current_target(CMD_CTX);
418 struct armv7a_common *armv7a = target_to_armv7a(target);
419
420 return armv7a_handle_cache_info_command(CMD,
421 &armv7a->armv7a_mmu.armv7a_cache);
422 }
423
424 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd)
425 {
426 struct target *target = get_current_target(CMD_CTX);
427
428 armv7a_l1_d_cache_clean_inval_all(target);
429
430 return 0;
431 }
432
433 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
434 {
435 struct target *target = get_current_target(CMD_CTX);
436 uint32_t virt, size;
437
438 if (CMD_ARGC == 0 || CMD_ARGC > 2)
439 return ERROR_COMMAND_SYNTAX_ERROR;
440
441 if (CMD_ARGC == 2)
442 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
443 else
444 size = 1;
445
446 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
447
448 return armv7a_l1_d_cache_inval_virt(target, virt, size);
449 }
450
451 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd)
452 {
453 struct target *target = get_current_target(CMD_CTX);
454 uint32_t virt, size;
455
456 if (CMD_ARGC == 0 || CMD_ARGC > 2)
457 return ERROR_COMMAND_SYNTAX_ERROR;
458
459 if (CMD_ARGC == 2)
460 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
461 else
462 size = 1;
463
464 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
465
466 return armv7a_l1_d_cache_clean_virt(target, virt, size);
467 }
468
469 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd)
470 {
471 struct target *target = get_current_target(CMD_CTX);
472
473 armv7a_l1_i_cache_inval_all(target);
474
475 return 0;
476 }
477
478 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
479 {
480 struct target *target = get_current_target(CMD_CTX);
481 uint32_t virt, size;
482
483 if (CMD_ARGC == 0 || CMD_ARGC > 2)
484 return ERROR_COMMAND_SYNTAX_ERROR;
485
486 if (CMD_ARGC == 2)
487 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
488 else
489 size = 1;
490
491 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
492
493 return armv7a_l1_i_cache_inval_virt(target, virt, size);
494 }
495
496 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd)
497 {
498 struct target *target = get_current_target(CMD_CTX);
499 struct armv7a_common *armv7a = target_to_armv7a(target);
500
501 if (CMD_ARGC == 0) {
502 command_print(CMD, "auto cache is %s",
503 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled ? "enabled" : "disabled");
504 return ERROR_OK;
505 }
506
507 if (CMD_ARGC == 1) {
508 uint32_t set;
509
510 COMMAND_PARSE_ENABLE(CMD_ARGV[0], set);
511 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = !!set;
512 return ERROR_OK;
513 }
514
515 return ERROR_COMMAND_SYNTAX_ERROR;
516 }
517
518 static const struct command_registration arm7a_l1_d_cache_commands[] = {
519 {
520 .name = "flush_all",
521 .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
522 .mode = COMMAND_ANY,
523 .help = "flush (clean and invalidate) complete l1 d-cache",
524 .usage = "",
525 },
526 {
527 .name = "inval",
528 .handler = arm7a_l1_d_cache_inval_virt_cmd,
529 .mode = COMMAND_ANY,
530 .help = "invalidate l1 d-cache by virtual address offset and range size",
531 .usage = "<virt_addr> [size]",
532 },
533 {
534 .name = "clean",
535 .handler = arm7a_l1_d_cache_clean_virt_cmd,
536 .mode = COMMAND_ANY,
537 .help = "clean l1 d-cache by virtual address address offset and range size",
538 .usage = "<virt_addr> [size]",
539 },
540 COMMAND_REGISTRATION_DONE
541 };
542
543 static const struct command_registration arm7a_l1_i_cache_commands[] = {
544 {
545 .name = "inval_all",
546 .handler = armv7a_i_cache_clean_inval_all_cmd,
547 .mode = COMMAND_ANY,
548 .help = "invalidate complete l1 i-cache",
549 .usage = "",
550 },
551 {
552 .name = "inval",
553 .handler = arm7a_l1_i_cache_inval_virt_cmd,
554 .mode = COMMAND_ANY,
555 .help = "invalidate l1 i-cache by virtual address offset and range size",
556 .usage = "<virt_addr> [size]",
557 },
558 COMMAND_REGISTRATION_DONE
559 };
560
561 static const struct command_registration arm7a_l1_di_cache_group_handlers[] = {
562 {
563 .name = "info",
564 .handler = arm7a_l1_cache_info_cmd,
565 .mode = COMMAND_ANY,
566 .help = "print cache related information",
567 .usage = "",
568 },
569 {
570 .name = "d",
571 .mode = COMMAND_ANY,
572 .help = "l1 d-cache command group",
573 .usage = "",
574 .chain = arm7a_l1_d_cache_commands,
575 },
576 {
577 .name = "i",
578 .mode = COMMAND_ANY,
579 .help = "l1 i-cache command group",
580 .usage = "",
581 .chain = arm7a_l1_i_cache_commands,
582 },
583 COMMAND_REGISTRATION_DONE
584 };
585
586 static const struct command_registration arm7a_cache_group_handlers[] = {
587 {
588 .name = "auto",
589 .handler = arm7a_cache_disable_auto_cmd,
590 .mode = COMMAND_ANY,
591 .help = "disable or enable automatic cache handling.",
592 .usage = "(1|0)",
593 },
594 {
595 .name = "l1",
596 .mode = COMMAND_ANY,
597 .help = "l1 cache command group",
598 .usage = "",
599 .chain = arm7a_l1_di_cache_group_handlers,
600 },
601 {
602 .chain = arm7a_l2x_cache_command_handler,
603 },
604 COMMAND_REGISTRATION_DONE
605 };
606
607 const struct command_registration arm7a_cache_command_handlers[] = {
608 {
609 .name = "cache",
610 .mode = COMMAND_ANY,
611 .help = "cache command group",
612 .usage = "",
613 .chain = arm7a_cache_group_handlers,
614 },
615 COMMAND_REGISTRATION_DONE
616 };

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)