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

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)