doc: Improve ftdi driver section
[openocd.git] / src / target / armv7a_cache.c
blob7af3e6d4e8a2d6ff1cf8ba9917613fcea9fe1f0b
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 ***************************************************************************/
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
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"
30 static int armv7a_l1_d_cache_sanity_check(struct target *target)
32 struct armv7a_common *armv7a = target_to_armv7a(target);
34 if (target->state != TARGET_HALTED) {
35 LOG_ERROR("%s: target not halted", __func__);
36 return ERROR_TARGET_NOT_HALTED;
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;
45 return ERROR_OK;
48 static int armv7a_l1_i_cache_sanity_check(struct target *target)
50 struct armv7a_common *armv7a = target_to_armv7a(target);
52 if (target->state != TARGET_HALTED) {
53 LOG_ERROR("%s: target not halted", __func__);
54 return ERROR_TARGET_NOT_HALTED;
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;
63 return ERROR_OK;
66 static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl)
68 int retval = ERROR_OK;
69 int32_t c_way, c_index = size->index;
71 LOG_DEBUG("cl %" PRId32, cl);
72 do {
73 c_way = size->way;
74 do {
75 uint32_t value = (c_index << size->index_shift)
76 | (c_way << size->way_shift) | (cl << 1);
78 * DCCISW - Clean and invalidate data cache
79 * line by Set/Way.
81 retval = dpm->instr_write_data_r0(dpm,
82 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
83 value);
84 if (retval != ERROR_OK)
85 goto done;
86 c_way -= 1;
87 } while (c_way >= 0);
88 c_index -= 1;
89 } while (c_index >= 0);
91 done:
92 return retval;
95 static int armv7a_l1_d_cache_clean_inval_all(struct target *target)
97 struct armv7a_common *armv7a = target_to_armv7a(target);
98 struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache);
99 struct arm_dpm *dpm = armv7a->arm.dpm;
100 int cl;
101 int retval;
103 retval = armv7a_l1_d_cache_sanity_check(target);
104 if (retval != ERROR_OK)
105 return retval;
107 retval = dpm->prepare(dpm);
108 if (retval != ERROR_OK)
109 goto done;
111 for (cl = 0; cl < cache->loc; cl++) {
112 /* skip i-only caches */
113 if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE)
114 continue;
116 armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, cl);
119 retval = dpm->finish(dpm);
120 return retval;
122 done:
123 LOG_ERROR("clean invalidate failed");
124 dpm->finish(dpm);
126 return retval;
129 int armv7a_cache_auto_flush_all_data(struct target *target)
131 int retval = ERROR_FAIL;
132 struct armv7a_common *armv7a = target_to_armv7a(target);
134 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
135 return ERROR_OK;
137 if (target->smp) {
138 struct target_list *head;
139 struct target *curr;
140 head = target->head;
141 while (head != (struct target_list *)NULL) {
142 curr = head->target;
143 if (curr->state == TARGET_HALTED)
144 retval = armv7a_l1_d_cache_clean_inval_all(curr);
146 head = head->next;
148 } else
149 retval = armv7a_l1_d_cache_clean_inval_all(target);
151 /* do outer cache flushing after inner caches have been flushed */
152 retval = arm7a_l2x_flush_all_data(target);
154 return retval;
158 int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
159 uint32_t size)
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;
168 retval = armv7a_l1_d_cache_sanity_check(target);
169 if (retval != ERROR_OK)
170 return retval;
172 retval = dpm->prepare(dpm);
173 if (retval != ERROR_OK)
174 goto done;
176 va_line = virt & (-linelen);
177 va_end = virt + size;
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;
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;
199 while (va_line < va_end) {
200 /* DCIMVAC - Invalidate data cache line by VA to PoC. */
201 retval = dpm->instr_write_data_r0(dpm,
202 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
203 if (retval != ERROR_OK)
204 goto done;
205 va_line += linelen;
208 dpm->finish(dpm);
209 return retval;
211 done:
212 LOG_ERROR("d-cache invalidate failed");
213 dpm->finish(dpm);
215 return retval;
218 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
219 unsigned int size)
221 struct armv7a_common *armv7a = target_to_armv7a(target);
222 struct arm_dpm *dpm = armv7a->arm.dpm;
223 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
224 uint32_t linelen = armv7a_cache->dminline;
225 uint32_t va_line, va_end;
226 int retval;
228 retval = armv7a_l1_d_cache_sanity_check(target);
229 if (retval != ERROR_OK)
230 return retval;
232 retval = dpm->prepare(dpm);
233 if (retval != ERROR_OK)
234 goto done;
236 va_line = virt & (-linelen);
237 va_end = virt + size;
239 while (va_line < va_end) {
240 /* DCCMVAC - Data Cache Clean by MVA to PoC */
241 retval = dpm->instr_write_data_r0(dpm,
242 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line);
243 if (retval != ERROR_OK)
244 goto done;
245 va_line += linelen;
248 dpm->finish(dpm);
249 return retval;
251 done:
252 LOG_ERROR("d-cache invalidate failed");
253 dpm->finish(dpm);
255 return retval;
258 int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
259 unsigned int size)
261 struct armv7a_common *armv7a = target_to_armv7a(target);
262 struct arm_dpm *dpm = armv7a->arm.dpm;
263 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
264 uint32_t linelen = armv7a_cache->dminline;
265 uint32_t va_line, va_end;
266 int retval;
268 retval = armv7a_l1_d_cache_sanity_check(target);
269 if (retval != ERROR_OK)
270 return retval;
272 retval = dpm->prepare(dpm);
273 if (retval != ERROR_OK)
274 goto done;
276 va_line = virt & (-linelen);
277 va_end = virt + size;
279 while (va_line < va_end) {
280 /* DCCIMVAC */
281 retval = dpm->instr_write_data_r0(dpm,
282 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
283 if (retval != ERROR_OK)
284 goto done;
285 va_line += linelen;
288 dpm->finish(dpm);
289 return retval;
291 done:
292 LOG_ERROR("d-cache invalidate failed");
293 dpm->finish(dpm);
295 return retval;
298 int armv7a_l1_i_cache_inval_all(struct target *target)
300 struct armv7a_common *armv7a = target_to_armv7a(target);
301 struct arm_dpm *dpm = armv7a->arm.dpm;
302 int retval;
304 retval = armv7a_l1_i_cache_sanity_check(target);
305 if (retval != ERROR_OK)
306 return retval;
308 retval = dpm->prepare(dpm);
309 if (retval != ERROR_OK)
310 goto done;
312 if (target->smp) {
313 /* ICIALLUIS */
314 retval = dpm->instr_write_data_r0(dpm,
315 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
316 } else {
317 /* ICIALLU */
318 retval = dpm->instr_write_data_r0(dpm,
319 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
322 if (retval != ERROR_OK)
323 goto done;
325 dpm->finish(dpm);
326 return retval;
328 done:
329 LOG_ERROR("i-cache invalidate failed");
330 dpm->finish(dpm);
332 return retval;
335 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
336 uint32_t size)
338 struct armv7a_common *armv7a = target_to_armv7a(target);
339 struct arm_dpm *dpm = armv7a->arm.dpm;
340 struct armv7a_cache_common *armv7a_cache =
341 &armv7a->armv7a_mmu.armv7a_cache;
342 uint32_t linelen = armv7a_cache->iminline;
343 uint32_t va_line, va_end;
344 int retval;
346 retval = armv7a_l1_i_cache_sanity_check(target);
347 if (retval != ERROR_OK)
348 return retval;
350 retval = dpm->prepare(dpm);
351 if (retval != ERROR_OK)
352 goto done;
354 va_line = virt & (-linelen);
355 va_end = virt + size;
357 while (va_line < va_end) {
358 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
359 retval = dpm->instr_write_data_r0(dpm,
360 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
361 if (retval != ERROR_OK)
362 goto done;
363 /* BPIMVA */
364 retval = dpm->instr_write_data_r0(dpm,
365 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line);
366 if (retval != ERROR_OK)
367 goto done;
368 va_line += linelen;
370 return retval;
372 done:
373 LOG_ERROR("i-cache invalidate failed");
374 dpm->finish(dpm);
376 return retval;
379 int armv7a_cache_flush_virt(struct target *target, uint32_t virt,
380 uint32_t size)
382 armv7a_l1_d_cache_flush_virt(target, virt, size);
383 armv7a_l2x_cache_flush_virt(target, virt, size);
385 return ERROR_OK;
389 * We assume that target core was chosen correctly. It means if same data
390 * was handled by two cores, other core will loose the changes. Since it
391 * is impossible to know (FIXME) which core has correct data, keep in mind
392 * that some kind of data lost or korruption is possible.
393 * Possible scenario:
394 * - core1 loaded and changed data on 0x12345678
395 * - we halted target and modified same data on core0
396 * - data on core1 will be lost.
398 int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt,
399 uint32_t size)
401 struct armv7a_common *armv7a = target_to_armv7a(target);
403 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
404 return ERROR_OK;
406 return armv7a_cache_flush_virt(target, virt, size);
409 COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
411 struct target *target = get_current_target(CMD_CTX);
412 struct armv7a_common *armv7a = target_to_armv7a(target);
414 return armv7a_handle_cache_info_command(CMD_CTX,
415 &armv7a->armv7a_mmu.armv7a_cache);
418 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd)
420 struct target *target = get_current_target(CMD_CTX);
422 armv7a_l1_d_cache_clean_inval_all(target);
424 return 0;
427 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
429 struct target *target = get_current_target(CMD_CTX);
430 uint32_t virt, size;
432 if (CMD_ARGC == 0 || CMD_ARGC > 2)
433 return ERROR_COMMAND_SYNTAX_ERROR;
435 if (CMD_ARGC == 2)
436 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
437 else
438 size = 1;
440 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
442 return armv7a_l1_d_cache_inval_virt(target, virt, size);
445 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd)
447 struct target *target = get_current_target(CMD_CTX);
448 uint32_t virt, size;
450 if (CMD_ARGC == 0 || CMD_ARGC > 2)
451 return ERROR_COMMAND_SYNTAX_ERROR;
453 if (CMD_ARGC == 2)
454 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
455 else
456 size = 1;
458 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
460 return armv7a_l1_d_cache_clean_virt(target, virt, size);
463 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd)
465 struct target *target = get_current_target(CMD_CTX);
467 armv7a_l1_i_cache_inval_all(target);
469 return 0;
472 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
474 struct target *target = get_current_target(CMD_CTX);
475 uint32_t virt, size;
477 if (CMD_ARGC == 0 || CMD_ARGC > 2)
478 return ERROR_COMMAND_SYNTAX_ERROR;
480 if (CMD_ARGC == 2)
481 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
482 else
483 size = 1;
485 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
487 return armv7a_l1_i_cache_inval_virt(target, virt, size);
490 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd)
492 struct target *target = get_current_target(CMD_CTX);
493 struct armv7a_common *armv7a = target_to_armv7a(target);
495 if (CMD_ARGC == 0) {
496 command_print(CMD_CTX, "auto cache is %s",
497 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled ? "enabled" : "disabled");
498 return ERROR_OK;
501 if (CMD_ARGC == 1) {
502 uint32_t set;
504 COMMAND_PARSE_ENABLE(CMD_ARGV[0], set);
505 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = !!set;
506 return ERROR_OK;
509 return ERROR_COMMAND_SYNTAX_ERROR;
512 static const struct command_registration arm7a_l1_d_cache_commands[] = {
514 .name = "flush_all",
515 .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
516 .mode = COMMAND_ANY,
517 .help = "flush (clean and invalidate) complete l1 d-cache",
518 .usage = "",
521 .name = "inval",
522 .handler = arm7a_l1_d_cache_inval_virt_cmd,
523 .mode = COMMAND_ANY,
524 .help = "invalidate l1 d-cache by virtual address offset and range size",
525 .usage = "<virt_addr> [size]",
528 .name = "clean",
529 .handler = arm7a_l1_d_cache_clean_virt_cmd,
530 .mode = COMMAND_ANY,
531 .help = "clean l1 d-cache by virtual address address offset and range size",
532 .usage = "<virt_addr> [size]",
534 COMMAND_REGISTRATION_DONE
537 static const struct command_registration arm7a_l1_i_cache_commands[] = {
539 .name = "inval_all",
540 .handler = armv7a_i_cache_clean_inval_all_cmd,
541 .mode = COMMAND_ANY,
542 .help = "invalidate complete l1 i-cache",
543 .usage = "",
546 .name = "inval",
547 .handler = arm7a_l1_i_cache_inval_virt_cmd,
548 .mode = COMMAND_ANY,
549 .help = "invalidate l1 i-cache by virtual address offset and range size",
550 .usage = "<virt_addr> [size]",
552 COMMAND_REGISTRATION_DONE
555 const struct command_registration arm7a_l1_di_cache_group_handlers[] = {
557 .name = "info",
558 .handler = arm7a_l1_cache_info_cmd,
559 .mode = COMMAND_ANY,
560 .help = "print cache realted information",
561 .usage = "",
564 .name = "d",
565 .mode = COMMAND_ANY,
566 .help = "l1 d-cache command group",
567 .usage = "",
568 .chain = arm7a_l1_d_cache_commands,
571 .name = "i",
572 .mode = COMMAND_ANY,
573 .help = "l1 i-cache command group",
574 .usage = "",
575 .chain = arm7a_l1_i_cache_commands,
577 COMMAND_REGISTRATION_DONE
580 const struct command_registration arm7a_cache_group_handlers[] = {
582 .name = "auto",
583 .handler = arm7a_cache_disable_auto_cmd,
584 .mode = COMMAND_ANY,
585 .help = "disable or enable automatic cache handling.",
586 .usage = "(1|0)",
589 .name = "l1",
590 .mode = COMMAND_ANY,
591 .help = "l1 cache command group",
592 .usage = "",
593 .chain = arm7a_l1_di_cache_group_handlers,
596 .chain = arm7a_l2x_cache_command_handler,
598 COMMAND_REGISTRATION_DONE
601 const struct command_registration arm7a_cache_command_handlers[] = {
603 .name = "cache",
604 .mode = COMMAND_ANY,
605 .help = "cache command group",
606 .usage = "",
607 .chain = arm7a_cache_group_handlers,
609 COMMAND_REGISTRATION_DONE