4c5dbeee69c96b9fc5712fd58c5b47db8c9ea649
[fw/openocd] / src / target / armv7a_cache_l2x.c
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
21 static int arm7a_l2x_sanity_check(struct target *target)
22 {
23         struct armv7a_common *armv7a = target_to_armv7a(target);
24         struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
25                 (armv7a->armv7a_mmu.armv7a_cache.outer_cache);
26
27         if (target->state != TARGET_HALTED) {
28                 LOG_ERROR("%s: target not halted", __func__);
29                 return ERROR_TARGET_NOT_HALTED;
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  */
42 int arm7a_l2x_flush_all_data(struct target *target)
43 {
44         struct armv7a_common *armv7a = target_to_armv7a(target);
45         struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
46                 (armv7a->armv7a_mmu.armv7a_cache.outer_cache);
47         uint32_t l2_way_val;
48         int retval;
49
50         retval = arm7a_l2x_sanity_check(target);
51         if (retval)
52                 return retval;
53
54         l2_way_val = (1 << l2x_cache->way) - 1;
55
56         return target_write_phys_u32(target,
57                         l2x_cache->base + L2X0_CLEAN_INV_WAY,
58                         l2_way_val);
59 }
60
61 int armv7a_l2x_cache_flush_virt(struct target *target, target_addr_t virt,
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 *)
66                 (armv7a->armv7a_mmu.armv7a_cache.outer_cache);
67         /* FIXME: different controllers have different linelen? */
68         uint32_t i, linelen = 32;
69         int retval;
70
71         retval = arm7a_l2x_sanity_check(target);
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
83                 retval = target_write_phys_u32(target,
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
96 static int armv7a_l2x_cache_inval_virt(struct target *target, target_addr_t virt,
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 *)
101                 (armv7a->armv7a_mmu.armv7a_cache.outer_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
131 static int armv7a_l2x_cache_clean_virt(struct target *target, target_addr_t virt,
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 *)
136                 (armv7a->armv7a_mmu.armv7a_cache.outer_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
166 static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd,
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
177         command_print(cmd,
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 */
202         foreach_smp_target(head, target->smp_targets) {
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 {
218         struct target *target = get_current_target(CMD_CTX);
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
226         return arm7a_handle_l2x_cache_info_command(CMD,
227                         &armv7a->armv7a_mmu.armv7a_cache);
228 }
229
230 COMMAND_HANDLER(arm7a_l2x_cache_flush_all_command)
231 {
232         struct target *target = get_current_target(CMD_CTX);
233
234         return arm7a_l2x_flush_all_data(target);
235 }
236
237 COMMAND_HANDLER(arm7a_l2x_cache_flush_virt_cmd)
238 {
239         struct target *target = get_current_target(CMD_CTX);
240         target_addr_t virt;
241         uint32_t size;
242
243         if (CMD_ARGC == 0 || CMD_ARGC > 2)
244                 return ERROR_COMMAND_SYNTAX_ERROR;
245
246         if (CMD_ARGC == 2)
247                 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
248         else
249                 size = 1;
250
251         COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt);
252
253         return armv7a_l2x_cache_flush_virt(target, virt, size);
254 }
255
256 COMMAND_HANDLER(arm7a_l2x_cache_inval_virt_cmd)
257 {
258         struct target *target = get_current_target(CMD_CTX);
259         target_addr_t virt;
260         uint32_t size;
261
262         if (CMD_ARGC == 0 || CMD_ARGC > 2)
263                 return ERROR_COMMAND_SYNTAX_ERROR;
264
265         if (CMD_ARGC == 2)
266                 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
267         else
268                 size = 1;
269
270         COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt);
271
272         return armv7a_l2x_cache_inval_virt(target, virt, size);
273 }
274
275 COMMAND_HANDLER(arm7a_l2x_cache_clean_virt_cmd)
276 {
277         struct target *target = get_current_target(CMD_CTX);
278         target_addr_t virt;
279         uint32_t size;
280
281         if (CMD_ARGC == 0 || CMD_ARGC > 2)
282                 return ERROR_COMMAND_SYNTAX_ERROR;
283
284         if (CMD_ARGC == 2)
285                 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
286         else
287                 size = 1;
288
289         COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt);
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 {
297         struct target *target = get_current_target(CMD_CTX);
298         uint32_t base, way;
299
300         if (CMD_ARGC != 2)
301                 return ERROR_COMMAND_SYNTAX_ERROR;
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         },
354         COMMAND_REGISTRATION_DONE
355 };
356
357 const struct command_registration arm7a_l2x_cache_command_handler[] = {
358         {
359                 .name = "l2x",
360                 .mode = COMMAND_ANY,
361                 .help = "l2x cache command group",
362                 .usage = "",
363                 .chain = arm7a_l2x_cache_commands,
364         },
365         COMMAND_REGISTRATION_DONE
366 };