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