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 =
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 =
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 =
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 =
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 =
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 = armv7a_cache->outer_cache;
170 
171  if (armv7a_cache->info == -1) {
172  command_print(cmd, "cache not yet identified");
173  return ERROR_OK;
174  }
175 
177  "L2 unified cache Base Address 0x%" PRIx32 ", %" PRIu32 " ways",
178  l2x_cache->base, l2x_cache->way);
179 
180  return ERROR_OK;
181 }
182 
183 static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
184 {
185  struct armv7a_l2x_cache *l2x_cache;
186  struct target_list *head;
187 
188  struct armv7a_common *armv7a = target_to_armv7a(target);
189  if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) {
190  LOG_ERROR("L2 cache was already initialised\n");
191  return ERROR_FAIL;
192  }
193 
194  l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache));
195  l2x_cache->base = base;
196  l2x_cache->way = way;
197  armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
198 
199  /* initialize all targets in this cluster (smp target)
200  * l2 cache must be configured after smp declaration */
202  struct target *curr = head->target;
203  if (curr != target) {
204  armv7a = target_to_armv7a(curr);
205  if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) {
206  LOG_ERROR("smp target : cache l2 already initialized\n");
207  return ERROR_FAIL;
208  }
209  armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
210  }
211  }
212  return ERROR_OK;
213 }
214 
215 COMMAND_HANDLER(arm7a_l2x_cache_info_command)
216 {
218  struct armv7a_common *armv7a = target_to_armv7a(target);
219  int retval;
220 
221  retval = arm7a_l2x_sanity_check(target);
222  if (retval)
223  return retval;
224 
226  &armv7a->armv7a_mmu.armv7a_cache);
227 }
228 
229 COMMAND_HANDLER(arm7a_l2x_cache_flush_all_command)
230 {
232 
234 }
235 
236 COMMAND_HANDLER(arm7a_l2x_cache_flush_virt_cmd)
237 {
239  target_addr_t virt;
240  uint32_t size;
241 
242  if (CMD_ARGC == 0 || CMD_ARGC > 2)
244 
245  if (CMD_ARGC == 2)
247  else
248  size = 1;
249 
251 
252  return armv7a_l2x_cache_flush_virt(target, virt, size);
253 }
254 
255 COMMAND_HANDLER(arm7a_l2x_cache_inval_virt_cmd)
256 {
258  target_addr_t virt;
259  uint32_t size;
260 
261  if (CMD_ARGC == 0 || CMD_ARGC > 2)
263 
264  if (CMD_ARGC == 2)
266  else
267  size = 1;
268 
270 
271  return armv7a_l2x_cache_inval_virt(target, virt, size);
272 }
273 
274 COMMAND_HANDLER(arm7a_l2x_cache_clean_virt_cmd)
275 {
277  target_addr_t virt;
278  uint32_t size;
279 
280  if (CMD_ARGC == 0 || CMD_ARGC > 2)
282 
283  if (CMD_ARGC == 2)
285  else
286  size = 1;
287 
289 
290  return armv7a_l2x_cache_clean_virt(target, virt, size);
291 }
292 
293 /* FIXME: should we configure way size? or controller type? */
294 COMMAND_HANDLER(armv7a_l2x_cache_conf_cmd)
295 {
297  uint32_t base, way;
298 
299  if (CMD_ARGC != 2)
301 
302  /* command_print(CMD, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
303  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base);
304  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way);
305 
306  /* AP address is in bits 31:24 of DP_SELECT */
307  return armv7a_l2x_cache_init(target, base, way);
308 }
309 
310 static const struct command_registration arm7a_l2x_cache_commands[] = {
311  {
312  .name = "conf",
313  .handler = armv7a_l2x_cache_conf_cmd,
314  .mode = COMMAND_ANY,
315  .help = "configure l2x cache",
316  .usage = "<base_addr> <number_of_way>",
317  },
318  {
319  .name = "info",
320  .handler = arm7a_l2x_cache_info_command,
321  .mode = COMMAND_ANY,
322  .help = "print cache related information",
323  .usage = "",
324  },
325  {
326  .name = "flush_all",
327  .handler = arm7a_l2x_cache_flush_all_command,
328  .mode = COMMAND_ANY,
329  .help = "flush complete l2x cache",
330  .usage = "",
331  },
332  {
333  .name = "flush",
334  .handler = arm7a_l2x_cache_flush_virt_cmd,
335  .mode = COMMAND_ANY,
336  .help = "flush (clean and invalidate) l2x cache by virtual address offset and range size",
337  .usage = "<virt_addr> [size]",
338  },
339  {
340  .name = "inval",
341  .handler = arm7a_l2x_cache_inval_virt_cmd,
342  .mode = COMMAND_ANY,
343  .help = "invalidate l2x cache by virtual address offset and range size",
344  .usage = "<virt_addr> [size]",
345  },
346  {
347  .name = "clean",
348  .handler = arm7a_l2x_cache_clean_virt_cmd,
349  .mode = COMMAND_ANY,
350  .help = "clean l2x cache by virtual address address offset and range size",
351  .usage = "<virt_addr> [size]",
352  },
354 };
355 
357  {
358  .name = "l2x",
359  .mode = COMMAND_ANY,
360  .help = "l2x cache command group",
361  .usage = "",
362  .chain = arm7a_l2x_cache_commands,
363  },
365 };
Holds the interface to ARM cores.
static struct armv7a_common * target_to_armv7a(struct target *target)
Definition: armv7a.h:120
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:376
#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
uint32_t size
Size of dw_spi_transaction::buffer.
Definition: dw-spi-helper.h:4
#define ERROR_FAIL
Definition: log.h:174
#define LOG_ERROR(expr ...)
Definition: log.h:133
#define LOG_DEBUG(expr ...)
Definition: log.h:110
#define ERROR_OK
Definition: log.h:168
#define foreach_smp_target(pos, head)
Definition: smp.h:15
struct armv7a_l2x_cache * outer_cache
Definition: armv7a.h:69
struct armv7a_mmu_common armv7a_mmu
Definition: armv7a.h:111
uint32_t base
Definition: armv7a.h:35
uint32_t way
Definition: armv7a.h:36
struct armv7a_cache_common armv7a_cache
Definition: armv7a.h:83
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:2730
struct target * get_current_target(struct command_context *cmd_ctx)
Definition: target.c:466
#define ERROR_TARGET_NOT_HALTED
Definition: target.h:783
@ TARGET_HALTED
Definition: target.h:56
uint64_t target_addr_t
Definition: types.h:335
uint8_t cmd
Definition: vdebug.c:1