OpenOCD
armv7a_cache_l2x.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2015 by Oleksij Rempel *
5  * linux@rempel-privat.de *
6  ***************************************************************************/
7 
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11 
12 #include "jtag/interface.h"
13 #include "arm.h"
14 #include "armv7a.h"
15 #include "armv7a_cache.h"
16 #include <helper/time_support.h>
17 #include "target.h"
18 #include "target_type.h"
19 #include "smp.h"
20 
22 {
23  struct armv7a_common *armv7a = target_to_armv7a(target);
24  struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
26 
27  if (target->state != TARGET_HALTED) {
28  LOG_ERROR("%s: target not halted", __func__);
30  }
31 
32  if (!l2x_cache || !l2x_cache->base) {
33  LOG_DEBUG("l2x is not configured!");
34  return ERROR_FAIL;
35  }
36 
37  return ERROR_OK;
38 }
39 /*
40  * clean and invalidate complete l2x cache
41  */
43 {
44  struct armv7a_common *armv7a = target_to_armv7a(target);
45  struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
47  uint32_t l2_way_val;
48  int retval;
49 
51  if (retval)
52  return retval;
53 
54  l2_way_val = (1 << l2x_cache->way) - 1;
55 
57  l2x_cache->base + L2X0_CLEAN_INV_WAY,
58  l2_way_val);
59 }
60 
62  uint32_t size)
63 {
64  struct armv7a_common *armv7a = target_to_armv7a(target);
65  struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
67  /* FIXME: different controllers have different linelen? */
68  uint32_t i, linelen = 32;
69  int retval;
70 
72  if (retval)
73  return retval;
74 
75  for (i = 0; i < size; i += linelen) {
76  target_addr_t pa, offs = virt + i;
77 
78  /* FIXME: use less verbose virt2phys? */
79  retval = target->type->virt2phys(target, offs, &pa);
80  if (retval != ERROR_OK)
81  goto done;
82 
84  l2x_cache->base + L2X0_CLEAN_INV_LINE_PA, pa);
85  if (retval != ERROR_OK)
86  goto done;
87  }
88  return retval;
89 
90 done:
91  LOG_ERROR("d-cache invalidate failed");
92 
93  return retval;
94 }
95 
97  uint32_t size)
98 {
99  struct armv7a_common *armv7a = target_to_armv7a(target);
100  struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
102  /* FIXME: different controllers have different linelen */
103  uint32_t i, linelen = 32;
104  int retval;
105 
106  retval = arm7a_l2x_sanity_check(target);
107  if (retval)
108  return retval;
109 
110  for (i = 0; i < size; i += linelen) {
111  target_addr_t pa, offs = virt + i;
112 
113  /* FIXME: use less verbose virt2phys? */
114  retval = target->type->virt2phys(target, offs, &pa);
115  if (retval != ERROR_OK)
116  goto done;
117 
118  retval = target_write_phys_u32(target,
119  l2x_cache->base + L2X0_INV_LINE_PA, pa);
120  if (retval != ERROR_OK)
121  goto done;
122  }
123  return retval;
124 
125 done:
126  LOG_ERROR("d-cache invalidate failed");
127 
128  return retval;
129 }
130 
132  unsigned int size)
133 {
134  struct armv7a_common *armv7a = target_to_armv7a(target);
135  struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
137  /* FIXME: different controllers have different linelen */
138  uint32_t i, linelen = 32;
139  int retval;
140 
141  retval = arm7a_l2x_sanity_check(target);
142  if (retval)
143  return retval;
144 
145  for (i = 0; i < size; i += linelen) {
146  target_addr_t pa, offs = virt + i;
147 
148  /* FIXME: use less verbose virt2phys? */
149  retval = target->type->virt2phys(target, offs, &pa);
150  if (retval != ERROR_OK)
151  goto done;
152 
153  retval = target_write_phys_u32(target,
154  l2x_cache->base + L2X0_CLEAN_LINE_PA, pa);
155  if (retval != ERROR_OK)
156  goto done;
157  }
158  return retval;
159 
160 done:
161  LOG_ERROR("d-cache invalidate failed");
162 
163  return retval;
164 }
165 
167  struct armv7a_cache_common *armv7a_cache)
168 {
169  struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
170  (armv7a_cache->outer_cache);
171 
172  if (armv7a_cache->info == -1) {
173  command_print(cmd, "cache not yet identified");
174  return ERROR_OK;
175  }
176 
178  "L2 unified cache Base Address 0x%" PRIx32 ", %" PRIu32 " ways",
179  l2x_cache->base, l2x_cache->way);
180 
181  return ERROR_OK;
182 }
183 
184 static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
185 {
186  struct armv7a_l2x_cache *l2x_cache;
187  struct target_list *head;
188 
189  struct armv7a_common *armv7a = target_to_armv7a(target);
190  if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) {
191  LOG_ERROR("L2 cache was already initialised\n");
192  return ERROR_FAIL;
193  }
194 
195  l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache));
196  l2x_cache->base = base;
197  l2x_cache->way = way;
198  armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
199 
200  /* initialize all targets in this cluster (smp target)
201  * l2 cache must be configured after smp declaration */
203  struct target *curr = head->target;
204  if (curr != target) {
205  armv7a = target_to_armv7a(curr);
206  if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) {
207  LOG_ERROR("smp target : cache l2 already initialized\n");
208  return ERROR_FAIL;
209  }
210  armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
211  }
212  }
213  return ERROR_OK;
214 }
215 
216 COMMAND_HANDLER(arm7a_l2x_cache_info_command)
217 {
219  struct armv7a_common *armv7a = target_to_armv7a(target);
220  int retval;
221 
222  retval = arm7a_l2x_sanity_check(target);
223  if (retval)
224  return retval;
225 
227  &armv7a->armv7a_mmu.armv7a_cache);
228 }
229 
230 COMMAND_HANDLER(arm7a_l2x_cache_flush_all_command)
231 {
233 
235 }
236 
237 COMMAND_HANDLER(arm7a_l2x_cache_flush_virt_cmd)
238 {
240  target_addr_t virt;
241  uint32_t size;
242 
243  if (CMD_ARGC == 0 || CMD_ARGC > 2)
245 
246  if (CMD_ARGC == 2)
248  else
249  size = 1;
250 
252 
253  return armv7a_l2x_cache_flush_virt(target, virt, size);
254 }
255 
256 COMMAND_HANDLER(arm7a_l2x_cache_inval_virt_cmd)
257 {
259  target_addr_t virt;
260  uint32_t size;
261 
262  if (CMD_ARGC == 0 || CMD_ARGC > 2)
264 
265  if (CMD_ARGC == 2)
267  else
268  size = 1;
269 
271 
272  return armv7a_l2x_cache_inval_virt(target, virt, size);
273 }
274 
275 COMMAND_HANDLER(arm7a_l2x_cache_clean_virt_cmd)
276 {
278  target_addr_t virt;
279  uint32_t size;
280 
281  if (CMD_ARGC == 0 || CMD_ARGC > 2)
283 
284  if (CMD_ARGC == 2)
286  else
287  size = 1;
288 
290 
291  return armv7a_l2x_cache_clean_virt(target, virt, size);
292 }
293 
294 /* FIXME: should we configure way size? or controller type? */
295 COMMAND_HANDLER(armv7a_l2x_cache_conf_cmd)
296 {
298  uint32_t base, way;
299 
300  if (CMD_ARGC != 2)
302 
303  /* command_print(CMD, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
304  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base);
305  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way);
306 
307  /* AP address is in bits 31:24 of DP_SELECT */
308  return armv7a_l2x_cache_init(target, base, way);
309 }
310 
311 static const struct command_registration arm7a_l2x_cache_commands[] = {
312  {
313  .name = "conf",
314  .handler = armv7a_l2x_cache_conf_cmd,
315  .mode = COMMAND_ANY,
316  .help = "configure l2x cache",
317  .usage = "<base_addr> <number_of_way>",
318  },
319  {
320  .name = "info",
321  .handler = arm7a_l2x_cache_info_command,
322  .mode = COMMAND_ANY,
323  .help = "print cache related information",
324  .usage = "",
325  },
326  {
327  .name = "flush_all",
328  .handler = arm7a_l2x_cache_flush_all_command,
329  .mode = COMMAND_ANY,
330  .help = "flush complete l2x cache",
331  .usage = "",
332  },
333  {
334  .name = "flush",
335  .handler = arm7a_l2x_cache_flush_virt_cmd,
336  .mode = COMMAND_ANY,
337  .help = "flush (clean and invalidate) l2x cache by virtual address offset and range size",
338  .usage = "<virt_addr> [size]",
339  },
340  {
341  .name = "inval",
342  .handler = arm7a_l2x_cache_inval_virt_cmd,
343  .mode = COMMAND_ANY,
344  .help = "invalidate l2x cache by virtual address offset and range size",
345  .usage = "<virt_addr> [size]",
346  },
347  {
348  .name = "clean",
349  .handler = arm7a_l2x_cache_clean_virt_cmd,
350  .mode = COMMAND_ANY,
351  .help = "clean l2x cache by virtual address address offset and range size",
352  .usage = "<virt_addr> [size]",
353  },
355 };
356 
358  {
359  .name = "l2x",
360  .mode = COMMAND_ANY,
361  .help = "l2x cache command group",
362  .usage = "",
363  .chain = arm7a_l2x_cache_commands,
364  },
366 };
Holds the interface to ARM cores.
static struct armv7a_common * target_to_armv7a(struct target *target)
Definition: armv7a.h:122
COMMAND_HANDLER(arm7a_l2x_cache_info_command)
static int arm7a_l2x_sanity_check(struct target *target)
static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
static int armv7a_l2x_cache_clean_virt(struct target *target, target_addr_t virt, unsigned int size)
static const struct command_registration arm7a_l2x_cache_commands[]
int arm7a_l2x_flush_all_data(struct target *target)
static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd, struct armv7a_cache_common *armv7a_cache)
int armv7a_l2x_cache_flush_virt(struct target *target, target_addr_t virt, uint32_t size)
const struct command_registration arm7a_l2x_cache_command_handler[]
static int armv7a_l2x_cache_inval_virt(struct target *target, target_addr_t virt, uint32_t size)
#define L2X0_INV_LINE_PA
#define L2X0_CLEAN_LINE_PA
#define L2X0_CLEAN_INV_WAY
#define L2X0_CLEAN_INV_LINE_PA
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:443
#define CMD
Use this macro to access the command being handled, rather than accessing the variable directly.
Definition: command.h:141
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:156
#define COMMAND_PARSE_ADDRESS(in, out)
Definition: command.h:452
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:402
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:151
#define COMMAND_PARSE_NUMBER(type, in, out)
parses the string in into out as a type, or prints a command error and passes the error code to the c...
Definition: command.h:442
#define CMD_CTX
Use this macro to access the context of the command being handled, rather than accessing the variable...
Definition: command.h:146
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:253
@ COMMAND_ANY
Definition: command.h:42
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
size_t size
Size of the control block search area.
Definition: rtt/rtt.c:30
#define foreach_smp_target(pos, head)
Definition: smp.h:15
void * outer_cache
Definition: armv7a.h:71
struct armv7a_mmu_common armv7a_mmu
Definition: armv7a.h:113
uint32_t base
Definition: armv7a.h:35
uint32_t way
Definition: armv7a.h:36
struct armv7a_cache_common armv7a_cache
Definition: armv7a.h:85
When run_command is called, a new instance will be created on the stack, filled with the proper value...
Definition: command.h:76
const char * name
Definition: command.h:235
struct target * target
Definition: target.h:214
int(* virt2phys)(struct target *target, target_addr_t address, target_addr_t *physical)
Definition: target_type.h:252
Definition: target.h:116
enum target_state state
Definition: target.h:157
struct list_head * smp_targets
Definition: target.h:188
struct target_type * type
Definition: target.h:117
int target_write_phys_u32(struct target *target, target_addr_t address, uint32_t value)
Definition: target.c:2722
struct target * get_current_target(struct command_context *cmd_ctx)
Definition: target.c:458
#define ERROR_TARGET_NOT_HALTED
Definition: target.h:790
@ TARGET_HALTED
Definition: target.h:56
uint64_t target_addr_t
Definition: types.h:335
uint8_t cmd
Definition: vdebug.c:1