openocd: fix SPDX tag format for files .c
[fw/openocd] / src / target / arm946e.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4  *   Copyright (C) 2005 by Dominic Rath                                    *
5  *   Dominic.Rath@gmx.de                                                   *
6  *                                                                         *
7  *   Copyright (C) 2008 by Spencer Oliver                                  *
8  *   spen@spen-soft.co.uk                                                  *
9  *                                                                         *
10  *   Copyright (C) 2010 by Drasko DRASKOVIC                                *
11  *   drasko.draskovic@gmail.com                                            *
12  ***************************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17
18 #include "arm946e.h"
19 #include "target_type.h"
20 #include "arm_opcodes.h"
21
22 #include "breakpoints.h"
23
24 #if 0
25 #define _DEBUG_INSTRUCTION_EXECUTION_
26 #endif
27
28 #define NB_CACHE_WAYS 4
29
30 #define CP15_CTL                0x02
31 #define CP15_CTL_DCACHE (1<<2)
32 #define CP15_CTL_ICACHE (1<<12)
33
34 /**
35  * flag to give info about cache manipulation during debug :
36  * "0"  -       cache lines are invalidated "on the fly", for affected addresses.
37  *                      This is preferred from performance point of view.
38  * "1"  -       cache is invalidated and switched off on debug_entry, and switched back on on restore.
39  *                      It is kept off during debugging.
40  */
41 static uint8_t arm946e_preserve_cache;
42
43 static int arm946e_post_debug_entry(struct target *target);
44 static void arm946e_pre_restore_context(struct target *target);
45 static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value);
46
47 static int arm946e_init_arch_info(struct target *target,
48         struct arm946e_common *arm946e,
49         struct jtag_tap *tap)
50 {
51         struct arm7_9_common *arm7_9 = &arm946e->arm7_9_common;
52
53         /* initialize arm7/arm9 specific info (including armv4_5) */
54         arm9tdmi_init_arch_info(target, arm7_9, tap);
55
56         arm946e->common_magic = ARM946E_COMMON_MAGIC;
57
58         /**
59          * The ARM946E-S implements the ARMv5TE architecture which
60          * has the BKPT instruction, so we don't have to use a watchpoint comparator
61          */
62         arm7_9->arm_bkpt = ARMV5_BKPT(0x0);
63         arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff;
64
65
66         arm7_9->post_debug_entry = arm946e_post_debug_entry;
67         arm7_9->pre_restore_context = arm946e_pre_restore_context;
68
69         /**
70          * disabling linefills leads to lockups, so keep them enabled for now
71          * this doesn't affect correctness, but might affect timing issues, if
72          * important data is evicted from the cache during the debug session
73          */
74         arm946e_preserve_cache = 0;
75
76         /* override hw single-step capability from ARM9TDMI */
77         /* arm7_9->has_single_step = 1; */
78
79         return ERROR_OK;
80 }
81
82 static int arm946e_target_create(struct target *target, Jim_Interp *interp)
83 {
84         struct arm946e_common *arm946e = calloc(1, sizeof(struct arm946e_common));
85
86         arm946e_init_arch_info(target, arm946e, target->tap);
87
88         return ERROR_OK;
89 }
90
91 static void arm946e_deinit_target(struct target *target)
92 {
93         struct arm *arm = target_to_arm(target);
94         struct arm946e_common *arm946e = target_to_arm946(target);
95
96         arm7_9_deinit(target);
97         arm_free_reg_cache(arm);
98         free(arm946e);
99 }
100
101 static int arm946e_verify_pointer(struct command_invocation *cmd,
102         struct arm946e_common *arm946e)
103 {
104         if (arm946e->common_magic != ARM946E_COMMON_MAGIC) {
105                 command_print(cmd, "target is not an ARM946");
106                 return ERROR_TARGET_INVALID;
107         }
108         return ERROR_OK;
109 }
110
111 /*
112  * Update cp15_control_reg, saved on debug_entry.
113  */
114 static void arm946e_update_cp15_caches(struct target *target, uint32_t value)
115 {
116         struct arm946e_common *arm946e = target_to_arm946(target);
117         arm946e->cp15_control_reg = (arm946e->cp15_control_reg & ~(CP15_CTL_DCACHE|CP15_CTL_ICACHE))
118                 | (value & (CP15_CTL_DCACHE|CP15_CTL_ICACHE));
119 }
120
121 /*
122  * REVISIT:  The "read_cp15" and "write_cp15" commands could hook up
123  * to eventual mrc() and mcr() routines ... the reg_addr values being
124  * constructed (for CP15 only) from Opcode_1, Opcode_2, and CRn values.
125  * See section 7.3 of the ARM946E-S TRM.
126  */
127 static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value)
128 {
129         int retval = ERROR_OK;
130         struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
131         struct arm_jtag *jtag_info = &arm7_9->jtag_info;
132         struct scan_field fields[3];
133         uint8_t reg_addr_buf = reg_addr & 0x3f;
134         uint8_t nr_w_buf = 0;
135
136         retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE);
137         if (retval != ERROR_OK)
138                 return retval;
139         retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE);
140         if (retval != ERROR_OK)
141                 return retval;
142
143         fields[0].num_bits = 32;
144         /* REVISIT: table 7-2 shows that bits 31-31 need to be
145          * specified for accessing BIST registers ...
146          */
147         fields[0].out_value = NULL;
148         fields[0].in_value = NULL;
149
150         fields[1].num_bits = 6;
151         fields[1].out_value = &reg_addr_buf;
152         fields[1].in_value = NULL;
153
154         fields[2].num_bits = 1;
155         fields[2].out_value = &nr_w_buf;
156         fields[2].in_value = NULL;
157
158         jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
159
160         fields[0].in_value = (uint8_t *)value;
161         jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
162
163         jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value);
164
165 #ifdef _DEBUG_INSTRUCTION_EXECUTION_
166         LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value);
167 #endif
168
169         retval = jtag_execute_queue();
170         if (retval != ERROR_OK)
171                 return retval;
172
173         return ERROR_OK;
174 }
175
176 static int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value)
177 {
178         int retval = ERROR_OK;
179         struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
180         struct arm_jtag *jtag_info = &arm7_9->jtag_info;
181         struct scan_field fields[3];
182         uint8_t reg_addr_buf = reg_addr & 0x3f;
183         uint8_t nr_w_buf = 1;
184         uint8_t value_buf[4];
185
186         buf_set_u32(value_buf, 0, 32, value);
187
188         retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE);
189         if (retval != ERROR_OK)
190                 return retval;
191         retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE);
192         if (retval != ERROR_OK)
193                 return retval;
194
195         fields[0].num_bits = 32;
196         fields[0].out_value = value_buf;
197         fields[0].in_value = NULL;
198
199         fields[1].num_bits = 6;
200         fields[1].out_value = &reg_addr_buf;
201         fields[1].in_value = NULL;
202
203         fields[2].num_bits = 1;
204         fields[2].out_value = &nr_w_buf;
205         fields[2].in_value = NULL;
206
207         jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
208
209 #ifdef _DEBUG_INSTRUCTION_EXECUTION_
210         LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value);
211 #endif
212
213         retval = jtag_execute_queue();
214         if (retval != ERROR_OK)
215                 return retval;
216
217         return ERROR_OK;
218 }
219
220 #define GET_ICACHE_SIZE  6
221 #define GET_DCACHE_SIZE 18
222
223 /*
224  * \param target struct target pointer
225  * \param idsel  select GET_ICACHE_SIZE or GET_DCACHE_SIZE
226  * \returns      cache size, given in bytes
227  */
228 static uint32_t arm946e_cp15_get_csize(struct target *target, int idsel)
229 {
230         struct arm946e_common *arm946e = target_to_arm946(target);
231         uint32_t csize = arm946e->cp15_cache_info;
232         if (csize == 0) {
233                 if (arm946e_read_cp15(target, 0x01, &csize) == ERROR_OK)
234                         arm946e->cp15_cache_info = csize;
235         }
236         if (csize & (1<<(idsel-4)))     /* cache absent */
237                 return 0;
238         csize = (csize >> idsel) & 0x0F;
239         return csize ? 1 << (12 + (csize-3)) : 0;
240 }
241
242 static uint32_t arm946e_invalidate_whole_dcache(struct target *target)
243 {
244         uint32_t csize = arm946e_cp15_get_csize(target, GET_DCACHE_SIZE);
245         if (csize == 0)
246                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
247
248         /* One line (index) is 32 bytes (8 words) long, 4-way assoc
249          * ARM DDI 0201D, Section 3.3.5
250          */
251         int nb_idx = (csize / (4*8*NB_CACHE_WAYS));     /* gives nb of lines (indexes) in the cache */
252
253         /* Loop for all segments (i.e. ways) */
254         uint32_t seg;
255         for (seg = 0; seg < NB_CACHE_WAYS; seg++) {
256                 /* Loop for all indexes */
257                 int idx;
258                 for (idx = 0; idx < nb_idx; idx++) {
259                         /* Form and write cp15 index (segment + line idx) */
260                         uint32_t cp15_idx = seg << 30 | idx << 5;
261                         int retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
262                         if (retval != ERROR_OK) {
263                                 LOG_DEBUG("ERROR writing index");
264                                 return retval;
265                         }
266
267                         /* Read dtag */
268                         uint32_t dtag;
269                         retval = arm946e_read_cp15(target, 0x16, &dtag);
270                         if (retval != ERROR_OK) {
271                                 LOG_DEBUG("ERROR reading dtag");
272                                 return retval;
273                         }
274
275                         /* Check cache line VALID bit */
276                         if (!(dtag >> 4 & 0x1))
277                                 continue;
278
279                         /* Clean data cache line */
280                         retval = arm946e_write_cp15(target, 0x35, 0x1);
281                         if (retval != ERROR_OK) {
282                                 LOG_DEBUG("ERROR cleaning cache line");
283                                 return retval;
284                         }
285
286                         /* Flush data cache line */
287                         retval = arm946e_write_cp15(target, 0x1a, 0x1);
288                         if (retval != ERROR_OK) {
289                                 LOG_DEBUG("ERROR flushing cache line");
290                                 return retval;
291                         }
292                 }
293         }
294
295         return ERROR_OK;
296 }
297
298 static uint32_t arm946e_invalidate_whole_icache(struct target *target)
299 {
300         /* Check cache presence before flushing - avoid undefined behavior */
301         uint32_t csize = arm946e_cp15_get_csize(target, GET_ICACHE_SIZE);
302         if (csize == 0)
303                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
304
305         LOG_DEBUG("FLUSHING I$");
306         /**
307          *  Invalidate (flush) I$
308          *  mcr 15, 0, r0, cr7, cr5, {0}
309          */
310         int retval = arm946e_write_cp15(target, 0x0f, 0x1);
311         if (retval != ERROR_OK) {
312                 LOG_DEBUG("ERROR flushing I$");
313                 return retval;
314         }
315
316         return ERROR_OK;
317 }
318
319 static int arm946e_post_debug_entry(struct target *target)
320 {
321         uint32_t ctr_reg = 0x0;
322         uint32_t retval = ERROR_OK;
323         struct arm946e_common *arm946e = target_to_arm946(target);
324
325         /* See if CACHES are enabled, and save that info
326          * in the context bits, so that arm946e_pre_restore_context() can use them */
327         arm946e_read_cp15(target, CP15_CTL, &ctr_reg);
328
329         /* Save control reg in the context */
330         arm946e->cp15_control_reg = ctr_reg;
331
332         if (arm946e_preserve_cache) {
333                 if (ctr_reg & CP15_CTL_DCACHE) {
334                         /* Clean and flush D$ */
335                         arm946e_invalidate_whole_dcache(target);
336
337                         /* Disable D$ */
338                         ctr_reg &= ~CP15_CTL_DCACHE;
339                 }
340
341                 if (ctr_reg & CP15_CTL_ICACHE) {
342                         /* Flush I$ */
343                         arm946e_invalidate_whole_icache(target);
344
345                         /* Disable I$ */
346                         ctr_reg &= ~CP15_CTL_ICACHE;
347                 }
348
349                 /* Write the new configuration */
350                 retval = arm946e_write_cp15(target, CP15_CTL, ctr_reg);
351                 if (retval != ERROR_OK) {
352                         LOG_DEBUG("ERROR disabling cache");
353                         return retval;
354                 }
355         }       /* if preserve_cache */
356
357         return ERROR_OK;
358 }
359
360 static void arm946e_pre_restore_context(struct target *target)
361 {
362         uint32_t ctr_reg = 0x0;
363         uint32_t retval;
364
365         if (arm946e_preserve_cache) {
366                 struct arm946e_common *arm946e = target_to_arm946(target);
367                 /* Get the contents of the CTR reg */
368                 arm946e_read_cp15(target, CP15_CTL, &ctr_reg);
369
370                 /**
371                  * Read-modify-write CP15 control
372                  * to reenable I/D-cache operation
373                  * NOTE: It is not possible to disable cache by CP15.
374                  * if arm946e_preserve_cache debugging flag enabled.
375                  */
376                 ctr_reg |= arm946e->cp15_control_reg & (CP15_CTL_DCACHE|CP15_CTL_ICACHE);
377
378                 /* Write the new configuration */
379                 retval = arm946e_write_cp15(target, CP15_CTL, ctr_reg);
380                 if (retval != ERROR_OK)
381                         LOG_DEBUG("ERROR enabling cache");
382         }       /* if preserve_cache */
383 }
384
385 static uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address,
386         uint32_t size, uint32_t count)
387 {
388         uint32_t cur_addr = 0x0;
389         uint32_t cp15_idx, set, way, dtag;
390         uint32_t i = 0;
391         int retval;
392
393         for (i = 0; i < count*size; i++) {
394                 cur_addr = address + i;
395
396
397                 set = (cur_addr >> 5) & 0xff;   /* set field is 8 bits long */
398
399                 for (way = 0; way < NB_CACHE_WAYS; way++) {
400                         /**
401                          * Find if the affected address is kept in the cache.
402                          * Because JTAG Scan Chain 15 offers limited approach,
403                          * we have to loop through all cache ways (segments) and
404                          * read cache tags, then compare them with with address.
405                          */
406
407                         /* Form and write cp15 index (segment + line idx) */
408                         cp15_idx = way << 30 | set << 5;
409                         retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
410                         if (retval != ERROR_OK) {
411                                 LOG_DEBUG("ERROR writing index");
412                                 return retval;
413                         }
414
415                         /* Read dtag */
416                         retval = arm946e_read_cp15(target, 0x16, &dtag);
417                         if (retval != ERROR_OK) {
418                                 LOG_DEBUG("ERROR reading dtag");
419                                 return retval;
420                         }
421
422                         /* Check cache line VALID bit */
423                         if (!(dtag >> 4 & 0x1))
424                                 continue;
425
426                         /* If line is valid and corresponds to affected address - invalidate it */
427                         if (dtag >> 5 == cur_addr >> 5) {
428                                 /* Clean data cache line */
429                                 retval = arm946e_write_cp15(target, 0x35, 0x1);
430                                 if (retval != ERROR_OK) {
431                                         LOG_DEBUG("ERROR cleaning cache line");
432                                         return retval;
433                                 }
434
435                                 /* Flush data cache line */
436                                 retval = arm946e_write_cp15(target, 0x1c, 0x1);
437                                 if (retval != ERROR_OK) {
438                                         LOG_DEBUG("ERROR flushing cache line");
439                                         return retval;
440                                 }
441
442                                 break;
443                         }
444                 }       /* loop through all 4 ways */
445         }       /* loop through all addresses */
446
447         return ERROR_OK;
448 }
449
450 static uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address,
451         uint32_t size, uint32_t count)
452 {
453         uint32_t cur_addr = 0x0;
454         uint32_t cp15_idx, set, way, itag;
455         uint32_t i = 0;
456         int retval;
457
458         for (i = 0; i < count*size; i++) {
459                 cur_addr = address + i;
460
461                 set = (cur_addr >> 5) & 0xff;   /* set field is 8 bits long */
462
463                 for (way = 0; way < NB_CACHE_WAYS; way++) {
464                         /* Form and write cp15 index (segment + line idx) */
465                         cp15_idx = way << 30 | set << 5;
466                         retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
467                         if (retval != ERROR_OK) {
468                                 LOG_DEBUG("ERROR writing index");
469                                 return retval;
470                         }
471
472                         /* Read itag */
473                         retval = arm946e_read_cp15(target, 0x17, &itag);
474                         if (retval != ERROR_OK) {
475                                 LOG_DEBUG("ERROR reading itag");
476                                 return retval;
477                         }
478
479                         /* Check cache line VALID bit */
480                         if (!(itag >> 4 & 0x1))
481                                 continue;
482
483                         /* If line is valid and corresponds to affected address - invalidate it */
484                         if (itag >> 5 == cur_addr >> 5) {
485                                 /* Flush I$ line */
486                                 retval = arm946e_write_cp15(target, 0x1d, 0x0);
487                                 if (retval != ERROR_OK) {
488                                         LOG_DEBUG("ERROR flushing cache line");
489                                         return retval;
490                                 }
491
492                                 break;
493                         }
494                 }       /* way loop */
495         }       /* addr loop */
496
497         return ERROR_OK;
498 }
499
500 /** Writes a buffer, in the specified word size, with current MMU settings. */
501 static int arm946e_write_memory(struct target *target, target_addr_t address,
502         uint32_t size, uint32_t count, const uint8_t *buffer)
503 {
504         int retval;
505
506         LOG_DEBUG("-");
507
508         struct arm946e_common *arm946e = target_to_arm946(target);
509         /* Invalidate D$ if it is ON */
510         if (!arm946e_preserve_cache && (arm946e->cp15_control_reg & CP15_CTL_DCACHE))
511                 arm946e_invalidate_dcache(target, address, size, count);
512
513         /**
514          * Write memory
515          */
516         retval = arm7_9_write_memory_opt(target, address, size, count, buffer);
517         if (retval != ERROR_OK)
518                 return retval;
519
520         /* *
521          * Invalidate I$ if it is ON.
522          *
523          * D$ has been cleaned and flushed before mem write thus forcing it to behave like write-through,
524          * because arm7_9_write_memory() has seen non-valid bit in D$
525          * and wrote data into physical RAM (without touching or allocating the cache line).
526          * From ARM946ES Technical Reference Manual we can see that it uses "allocate on read-miss"
527          * policy for both I$ and D$ (Chapter 3.2 and 3.3)
528          *
529          * Explanation :
530          * "ARM system developer's guide: designing and optimizing system software" by
531          * Andrew N. Sloss, Dominic Symes and Chris Wright,
532          * Chapter 12.3.3 Allocating Policy on a Cache Miss :
533          * A read allocate on cache miss policy allocates a cache line only during a read from main memory.
534          * If the victim cache line contains valid data, then it is written to main memory before the cache line
535          * is filled with new data.
536          * Under this strategy, a write of new data to memory does not update the contents of the cache memory
537          * unless a cache line was allocated on a previous read from main memory.
538          * If the cache line contains valid data, then the write updates the cache and may update the main memory if
539          * the cache write policy is write-through.
540          * If the data is not in the cache, the controller writes to main memory only.
541          */
542         if (!arm946e_preserve_cache && (arm946e->cp15_control_reg & CP15_CTL_ICACHE))
543                 arm946e_invalidate_icache(target, address, size, count);
544
545         return ERROR_OK;
546
547 }
548
549 static int arm946e_read_memory(struct target *target, target_addr_t address,
550         uint32_t size, uint32_t count, uint8_t *buffer)
551 {
552         int retval;
553
554         LOG_DEBUG("-");
555
556         retval = arm7_9_read_memory(target, address, size, count, buffer);
557         if (retval != ERROR_OK)
558                 return retval;
559
560         return ERROR_OK;
561 }
562
563 COMMAND_HANDLER(arm946e_handle_cp15)
564 {
565         /* one or two arguments, access a single register (write if second argument is given) */
566         if (CMD_ARGC < 1 || CMD_ARGC > 2)
567                 return ERROR_COMMAND_SYNTAX_ERROR;
568
569         struct target *target = get_current_target(CMD_CTX);
570
571         struct arm946e_common *arm946e = target_to_arm946(target);
572         int retval = arm946e_verify_pointer(CMD, arm946e);
573         if (retval != ERROR_OK)
574                 return retval;
575
576         if (target->state != TARGET_HALTED) {
577                 command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME);
578                 return ERROR_TARGET_NOT_HALTED;
579         }
580
581         uint32_t address;
582         COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
583
584         if (CMD_ARGC == 1) {
585                 uint32_t value;
586                 retval = arm946e_read_cp15(target, address, &value);
587                 if (retval != ERROR_OK) {
588                         command_print(CMD, "%s cp15 reg %" PRIu32 " access failed", target_name(target), address);
589                         return retval;
590                 }
591                 retval = jtag_execute_queue();
592                 if (retval != ERROR_OK)
593                         return retval;
594
595                 /* Return value in hex format */
596                 command_print(CMD, "0x%08" PRIx32, value);
597         } else if (CMD_ARGC == 2) {
598                 uint32_t value;
599                 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
600
601                 retval = arm946e_write_cp15(target, address, value);
602                 if (retval != ERROR_OK) {
603                         command_print(CMD, "%s cp15 reg %" PRIu32 " access failed", target_name(target), address);
604                         return retval;
605                 }
606                 if (address == CP15_CTL)
607                         arm946e_update_cp15_caches(target, value);
608         }
609
610         return ERROR_OK;
611 }
612
613 COMMAND_HANDLER(arm946e_handle_idcache)
614 {
615         if (CMD_ARGC > 1)
616                 return ERROR_COMMAND_SYNTAX_ERROR;
617
618         int retval;
619         struct target *target = get_current_target(CMD_CTX);
620         struct arm946e_common *arm946e = target_to_arm946(target);
621
622         retval = arm946e_verify_pointer(CMD, arm946e);
623         if (retval != ERROR_OK)
624                 return retval;
625
626         if (target->state != TARGET_HALTED) {
627                 command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME);
628                 return ERROR_TARGET_NOT_HALTED;
629         }
630
631         bool icache = (strcmp(CMD_NAME, "icache") == 0);
632         uint32_t csize = arm946e_cp15_get_csize(target, icache ? GET_ICACHE_SIZE : GET_DCACHE_SIZE) / 1024;
633         if (CMD_ARGC == 0) {
634                 bool  bena = ((arm946e->cp15_control_reg & (icache ? CP15_CTL_ICACHE : CP15_CTL_DCACHE)) != 0)
635                           && (arm946e->cp15_control_reg & 0x1);
636                 if (csize == 0)
637                         command_print(CMD, "%s-cache absent", icache ? "I" : "D");
638                 else
639                         command_print(CMD, "%s-cache size: %" PRIu32 "K, %s",
640                                       icache ? "I" : "D", csize, bena ? "enabled" : "disabled");
641                 return ERROR_OK;
642         }
643
644         bool flush = false;
645         bool enable = false;
646         retval = command_parse_bool_arg(CMD_ARGV[0], &enable);
647         if (retval == ERROR_COMMAND_SYNTAX_ERROR) {
648                 if (strcmp(CMD_ARGV[0], "flush") == 0) {
649                         flush = true;
650                         retval = ERROR_OK;
651                 } else
652                         return retval;
653         }
654
655         /* Do not invalidate or change state, if cache is absent */
656         if (csize == 0) {
657                 command_print(CMD, "%s-cache absent, '%s' operation undefined", icache ? "I" : "D", CMD_ARGV[0]);
658                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
659         }
660
661         /* NOTE: flushing entire cache will not preserve lock-down cache regions */
662         if (icache) {
663                 if ((arm946e->cp15_control_reg & CP15_CTL_ICACHE) && !enable)
664                         retval = arm946e_invalidate_whole_icache(target);
665         } else {
666                 if ((arm946e->cp15_control_reg & CP15_CTL_DCACHE) && !enable)
667                         retval = arm946e_invalidate_whole_dcache(target);
668         }
669
670         if (retval != ERROR_OK || flush)
671                 return retval;
672
673         uint32_t value;
674         retval = arm946e_read_cp15(target, CP15_CTL, &value);
675         if (retval != ERROR_OK)
676                 return retval;
677
678         uint32_t vnew = value;
679         uint32_t cmask = icache ? CP15_CTL_ICACHE : CP15_CTL_DCACHE;
680         if (enable) {
681                 if ((value & 0x1) == 0)
682                         LOG_WARNING("arm946e: MPU must be enabled for cache to operate");
683                 vnew |= cmask;
684         } else
685                 vnew &= ~cmask;
686
687         if (vnew == value)
688                 return ERROR_OK;
689
690         retval = arm946e_write_cp15(target, CP15_CTL, vnew);
691         if (retval != ERROR_OK)
692                 return retval;
693
694         arm946e_update_cp15_caches(target, vnew);
695         return ERROR_OK;
696 }
697
698 static const struct command_registration arm946e_exec_command_handlers[] = {
699         {
700                 .name = "cp15",
701                 .handler = arm946e_handle_cp15,
702                 .mode = COMMAND_EXEC,
703                 .usage = "regnum [value]",
704                 .help = "read/modify cp15 register",
705         },
706         {
707                 .name = "icache",
708                 .handler = arm946e_handle_idcache,
709                 .mode = COMMAND_EXEC,
710                 .usage = "['enable'|'disable'|'flush']",
711                 .help = "I-cache info and operations",
712         },
713         {
714                 .name = "dcache",
715                 .handler = arm946e_handle_idcache,
716                 .mode = COMMAND_EXEC,
717                 .usage = "['enable'|'disable'|'flush']",
718                 .help = "D-cache info and operations",
719         },
720         COMMAND_REGISTRATION_DONE
721 };
722
723 static const struct command_registration arm946e_command_handlers[] = {
724         {
725                 .chain = arm9tdmi_command_handlers,
726         },
727         {
728                 .name = "arm946e",
729                 .mode = COMMAND_ANY,
730                 .help = "arm946e command group",
731                 .usage = "",
732                 .chain = arm946e_exec_command_handlers,
733         },
734         COMMAND_REGISTRATION_DONE
735 };
736
737 /** Holds methods for ARM946 targets. */
738 struct target_type arm946e_target = {
739         .name = "arm946e",
740
741         .poll = arm7_9_poll,
742         .arch_state = arm_arch_state,
743
744         .target_request_data = arm7_9_target_request_data,
745
746         .halt = arm7_9_halt,
747         .resume = arm7_9_resume,
748         .step = arm7_9_step,
749
750         .assert_reset = arm7_9_assert_reset,
751         .deassert_reset = arm7_9_deassert_reset,
752         .soft_reset_halt = arm7_9_soft_reset_halt,
753
754         .get_gdb_arch = arm_get_gdb_arch,
755         .get_gdb_reg_list = arm_get_gdb_reg_list,
756
757         /* .read_memory = arm7_9_read_memory, */
758         /* .write_memory = arm7_9_write_memory, */
759         .read_memory = arm946e_read_memory,
760         .write_memory = arm946e_write_memory,
761
762         .checksum_memory = arm_checksum_memory,
763         .blank_check_memory = arm_blank_check_memory,
764
765         .run_algorithm = armv4_5_run_algorithm,
766
767         .add_breakpoint = arm7_9_add_breakpoint,
768         .remove_breakpoint = arm7_9_remove_breakpoint,
769         /* .add_breakpoint = arm946e_add_breakpoint, */
770         /* .remove_breakpoint = arm946e_remove_breakpoint, */
771
772         .add_watchpoint = arm7_9_add_watchpoint,
773         .remove_watchpoint = arm7_9_remove_watchpoint,
774
775         .commands = arm946e_command_handlers,
776         .target_create = arm946e_target_create,
777         .init_target = arm9tdmi_init_target,
778         .deinit_target = arm946e_deinit_target,
779         .examine = arm7_9_examine,
780         .check_reset = arm7_9_check_reset,
781 };