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

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)