jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / flash / nor / xmc1xxx.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /*
4 * XMC1000 flash driver
5 *
6 * Copyright (c) 2016 Andreas Färber
7 */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "imp.h"
14 #include <helper/align.h>
15 #include <helper/binarybuffer.h>
16 #include <target/algorithm.h>
17 #include <target/armv7m.h>
18
19 #define FLASH_BASE 0x10000000
20 #define PAU_BASE 0x40000000
21 #define SCU_BASE 0x40010000
22 #define NVM_BASE 0x40050000
23
24 #define FLASH_CS0 (FLASH_BASE + 0xf00)
25
26 #define PAU_FLSIZE (PAU_BASE + 0x404)
27
28 #define SCU_IDCHIP (SCU_BASE + 0x004)
29
30 #define NVMSTATUS (NVM_BASE + 0x00)
31 #define NVMPROG (NVM_BASE + 0x04)
32 #define NVMCONF (NVM_BASE + 0x08)
33
34 #define NVMSTATUS_BUSY (1 << 0)
35 #define NVMSTATUS_VERR_MASK (0x3 << 2)
36
37 #define NVMPROG_ACTION_OPTYPE_IDLE_VERIFY (0 << 0)
38 #define NVMPROG_ACTION_OPTYPE_WRITE (1 << 0)
39 #define NVMPROG_ACTION_OPTYPE_PAGE_ERASE (2 << 0)
40
41 #define NVMPROG_ACTION_ONE_SHOT_ONCE (1 << 4)
42 #define NVMPROG_ACTION_ONE_SHOT_CONTINUOUS (2 << 4)
43
44 #define NVMPROG_ACTION_VERIFY_EACH (1 << 6)
45 #define NVMPROG_ACTION_VERIFY_NO (2 << 6)
46 #define NVMPROG_ACTION_VERIFY_ARRAY (3 << 6)
47
48 #define NVMPROG_ACTION_IDLE 0x00
49 #define NVMPROG_ACTION_MASK 0xff
50
51 #define NVM_WORD_SIZE 4
52 #define NVM_BLOCK_SIZE (4 * NVM_WORD_SIZE)
53 #define NVM_PAGE_SIZE (16 * NVM_BLOCK_SIZE)
54
55 struct xmc1xxx_flash_bank {
56 bool probed;
57 };
58
59 static int xmc1xxx_nvm_set_idle(struct target *target)
60 {
61 return target_write_u16(target, NVMPROG, NVMPROG_ACTION_IDLE);
62 }
63
64 static int xmc1xxx_nvm_check_idle(struct target *target)
65 {
66 uint16_t val;
67 int retval;
68
69 retval = target_read_u16(target, NVMPROG, &val);
70 if (retval != ERROR_OK)
71 return retval;
72 if ((val & NVMPROG_ACTION_MASK) != NVMPROG_ACTION_IDLE) {
73 LOG_WARNING("NVMPROG.ACTION");
74 retval = xmc1xxx_nvm_set_idle(target);
75 }
76
77 return retval;
78 }
79
80 static int xmc1xxx_erase(struct flash_bank *bank, unsigned int first,
81 unsigned int last)
82 {
83 struct target *target = bank->target;
84 struct working_area *workarea;
85 struct reg_param reg_params[3];
86 struct armv7m_algorithm armv7m_algo;
87 unsigned i;
88 int retval;
89 const uint8_t erase_code[] = {
90 #include "../../../contrib/loaders/flash/xmc1xxx/erase.inc"
91 };
92
93 LOG_DEBUG("Infineon XMC1000 erase sectors %u to %u", first, last);
94
95 if (bank->target->state != TARGET_HALTED) {
96 LOG_WARNING("Cannot communicate... target not halted.");
97 return ERROR_TARGET_NOT_HALTED;
98 }
99
100 retval = xmc1xxx_nvm_check_idle(target);
101 if (retval != ERROR_OK)
102 return retval;
103
104 retval = target_alloc_working_area(target, sizeof(erase_code),
105 &workarea);
106 if (retval != ERROR_OK) {
107 LOG_ERROR("No working area available.");
108 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
109 goto err_alloc_code;
110 }
111 retval = target_write_buffer(target, workarea->address,
112 sizeof(erase_code), erase_code);
113 if (retval != ERROR_OK)
114 goto err_write_code;
115
116 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
117 armv7m_algo.core_mode = ARM_MODE_THREAD;
118
119 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
120 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
121 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
122
123 buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE);
124 buf_set_u32(reg_params[1].value, 0, 32, bank->base +
125 bank->sectors[first].offset);
126 buf_set_u32(reg_params[2].value, 0, 32, bank->base +
127 bank->sectors[last].offset + bank->sectors[last].size);
128
129 retval = target_run_algorithm(target,
130 0, NULL,
131 ARRAY_SIZE(reg_params), reg_params,
132 workarea->address, 0,
133 1000, &armv7m_algo);
134 if (retval != ERROR_OK) {
135 LOG_ERROR("Error executing flash sector erase "
136 "programming algorithm");
137 retval = xmc1xxx_nvm_set_idle(target);
138 if (retval != ERROR_OK)
139 LOG_WARNING("Couldn't restore NVMPROG.ACTION");
140 retval = ERROR_FLASH_OPERATION_FAILED;
141 goto err_run;
142 }
143
144 err_run:
145 for (i = 0; i < ARRAY_SIZE(reg_params); i++)
146 destroy_reg_param(&reg_params[i]);
147
148 err_write_code:
149 target_free_working_area(target, workarea);
150
151 err_alloc_code:
152 return retval;
153 }
154
155 static int xmc1xxx_erase_check(struct flash_bank *bank)
156 {
157 struct target *target = bank->target;
158 struct working_area *workarea;
159 struct reg_param reg_params[3];
160 struct armv7m_algorithm armv7m_algo;
161 uint16_t val;
162 unsigned i;
163 int retval;
164 const uint8_t erase_check_code[] = {
165 #include "../../../contrib/loaders/flash/xmc1xxx/erase_check.inc"
166 };
167
168 if (bank->target->state != TARGET_HALTED) {
169 LOG_WARNING("Cannot communicate... target not halted.");
170 return ERROR_TARGET_NOT_HALTED;
171 }
172
173 retval = target_alloc_working_area(target, sizeof(erase_check_code),
174 &workarea);
175 if (retval != ERROR_OK) {
176 LOG_ERROR("No working area available.");
177 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
178 goto err_alloc_code;
179 }
180 retval = target_write_buffer(target, workarea->address,
181 sizeof(erase_check_code), erase_check_code);
182 if (retval != ERROR_OK)
183 goto err_write_code;
184
185 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
186 armv7m_algo.core_mode = ARM_MODE_THREAD;
187
188 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
189 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
190 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
191
192 buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE);
193
194 for (unsigned int sector = 0; sector < bank->num_sectors; sector++) {
195 uint32_t start = bank->base + bank->sectors[sector].offset;
196 buf_set_u32(reg_params[1].value, 0, 32, start);
197 buf_set_u32(reg_params[2].value, 0, 32, start + bank->sectors[sector].size);
198
199 retval = xmc1xxx_nvm_check_idle(target);
200 if (retval != ERROR_OK)
201 goto err_nvmprog;
202
203 LOG_DEBUG("Erase-checking 0x%08" PRIx32, start);
204 retval = target_run_algorithm(target,
205 0, NULL,
206 ARRAY_SIZE(reg_params), reg_params,
207 workarea->address, 0,
208 1000, &armv7m_algo);
209 if (retval != ERROR_OK) {
210 LOG_ERROR("Error executing flash sector erase check "
211 "programming algorithm");
212 retval = xmc1xxx_nvm_set_idle(target);
213 if (retval != ERROR_OK)
214 LOG_WARNING("Couldn't restore NVMPROG.ACTION");
215 retval = ERROR_FLASH_OPERATION_FAILED;
216 goto err_run;
217 }
218
219 retval = target_read_u16(target, NVMSTATUS, &val);
220 if (retval != ERROR_OK) {
221 LOG_ERROR("Couldn't read NVMSTATUS");
222 goto err_nvmstatus;
223 }
224 bank->sectors[sector].is_erased = (val & NVMSTATUS_VERR_MASK) ? 0 : 1;
225 }
226
227 err_nvmstatus:
228 err_run:
229 err_nvmprog:
230 for (i = 0; i < ARRAY_SIZE(reg_params); i++)
231 destroy_reg_param(&reg_params[i]);
232
233 err_write_code:
234 target_free_working_area(target, workarea);
235
236 err_alloc_code:
237 return retval;
238 }
239
240 static int xmc1xxx_write(struct flash_bank *bank, const uint8_t *buffer,
241 uint32_t offset, uint32_t byte_count)
242 {
243 struct target *target = bank->target;
244 struct working_area *code_workarea, *data_workarea;
245 struct reg_param reg_params[4];
246 struct armv7m_algorithm armv7m_algo;
247 uint32_t block_count = DIV_ROUND_UP(byte_count, NVM_BLOCK_SIZE);
248 unsigned i;
249 int retval;
250 const uint8_t write_code[] = {
251 #include "../../../contrib/loaders/flash/xmc1xxx/write.inc"
252 };
253
254 LOG_DEBUG("Infineon XMC1000 write at 0x%08" PRIx32 " (%" PRIu32 " bytes)",
255 offset, byte_count);
256
257 if (!IS_ALIGNED(offset, NVM_BLOCK_SIZE)) {
258 LOG_ERROR("offset 0x%" PRIx32 " breaks required block alignment",
259 offset);
260 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
261 }
262 if (!IS_ALIGNED(byte_count, NVM_BLOCK_SIZE)) {
263 LOG_WARNING("length %" PRIu32 " is not block aligned, rounding up",
264 byte_count);
265 }
266
267 if (target->state != TARGET_HALTED) {
268 LOG_WARNING("Cannot communicate... target not halted.");
269 return ERROR_TARGET_NOT_HALTED;
270 }
271
272 retval = target_alloc_working_area(target, sizeof(write_code),
273 &code_workarea);
274 if (retval != ERROR_OK) {
275 LOG_ERROR("No working area available for write code.");
276 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
277 goto err_alloc_code;
278 }
279 retval = target_write_buffer(target, code_workarea->address,
280 sizeof(write_code), write_code);
281 if (retval != ERROR_OK)
282 goto err_write_code;
283
284 retval = target_alloc_working_area(target, MAX(NVM_BLOCK_SIZE,
285 MIN(block_count * NVM_BLOCK_SIZE, target_get_working_area_avail(target))),
286 &data_workarea);
287 if (retval != ERROR_OK) {
288 LOG_ERROR("No working area available for write data.");
289 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
290 goto err_alloc_data;
291 }
292
293 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
294 armv7m_algo.core_mode = ARM_MODE_THREAD;
295
296 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
297 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
298 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
299 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
300
301 buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE);
302
303 while (byte_count > 0) {
304 uint32_t blocks = MIN(block_count, data_workarea->size / NVM_BLOCK_SIZE);
305 uint32_t addr = bank->base + offset;
306
307 LOG_DEBUG("copying %" PRIu32 " bytes to SRAM " TARGET_ADDR_FMT,
308 MIN(blocks * NVM_BLOCK_SIZE, byte_count),
309 data_workarea->address);
310
311 retval = target_write_buffer(target, data_workarea->address,
312 MIN(blocks * NVM_BLOCK_SIZE, byte_count), buffer);
313 if (retval != ERROR_OK) {
314 LOG_ERROR("Error writing data buffer");
315 retval = ERROR_FLASH_OPERATION_FAILED;
316 goto err_write_data;
317 }
318 if (byte_count < blocks * NVM_BLOCK_SIZE) {
319 retval = target_write_memory(target,
320 data_workarea->address + byte_count, 1,
321 blocks * NVM_BLOCK_SIZE - byte_count,
322 &bank->default_padded_value);
323 if (retval != ERROR_OK) {
324 LOG_ERROR("Error writing data padding");
325 retval = ERROR_FLASH_OPERATION_FAILED;
326 goto err_write_pad;
327 }
328 }
329
330 LOG_DEBUG("writing 0x%08" PRIx32 "-0x%08" PRIx32 " (%" PRIu32 "x)",
331 addr, addr + blocks * NVM_BLOCK_SIZE - 1, blocks);
332
333 retval = xmc1xxx_nvm_check_idle(target);
334 if (retval != ERROR_OK)
335 goto err_nvmprog;
336
337 buf_set_u32(reg_params[1].value, 0, 32, addr);
338 buf_set_u32(reg_params[2].value, 0, 32, data_workarea->address);
339 buf_set_u32(reg_params[3].value, 0, 32, blocks);
340
341 retval = target_run_algorithm(target,
342 0, NULL,
343 ARRAY_SIZE(reg_params), reg_params,
344 code_workarea->address, 0,
345 5 * 60 * 1000, &armv7m_algo);
346 if (retval != ERROR_OK) {
347 LOG_ERROR("Error executing flash write "
348 "programming algorithm");
349 retval = xmc1xxx_nvm_set_idle(target);
350 if (retval != ERROR_OK)
351 LOG_WARNING("Couldn't restore NVMPROG.ACTION");
352 retval = ERROR_FLASH_OPERATION_FAILED;
353 goto err_run;
354 }
355
356 block_count -= blocks;
357 offset += blocks * NVM_BLOCK_SIZE;
358 buffer += blocks * NVM_BLOCK_SIZE;
359 byte_count -= MIN(blocks * NVM_BLOCK_SIZE, byte_count);
360 }
361
362 err_run:
363 err_nvmprog:
364 err_write_pad:
365 err_write_data:
366 for (i = 0; i < ARRAY_SIZE(reg_params); i++)
367 destroy_reg_param(&reg_params[i]);
368
369 target_free_working_area(target, data_workarea);
370 err_alloc_data:
371 err_write_code:
372 target_free_working_area(target, code_workarea);
373
374 err_alloc_code:
375 return retval;
376 }
377
378 static int xmc1xxx_protect_check(struct flash_bank *bank)
379 {
380 uint32_t nvmconf;
381 unsigned int num_protected;
382 int retval;
383
384 if (bank->target->state != TARGET_HALTED) {
385 LOG_WARNING("Cannot communicate... target not halted.");
386 return ERROR_TARGET_NOT_HALTED;
387 }
388
389 retval = target_read_u32(bank->target, NVMCONF, &nvmconf);
390 if (retval != ERROR_OK) {
391 LOG_ERROR("Cannot read NVMCONF register.");
392 return retval;
393 }
394 LOG_DEBUG("NVMCONF = %08" PRIx32, nvmconf);
395
396 num_protected = (nvmconf >> 4) & 0xff;
397
398 for (unsigned int i = 0; i < bank->num_sectors; i++)
399 bank->sectors[i].is_protected = (i < num_protected) ? 1 : 0;
400
401 return ERROR_OK;
402 }
403
404 static int xmc1xxx_get_info_command(struct flash_bank *bank, struct command_invocation *cmd)
405 {
406 uint32_t chipid[8];
407 int i, retval;
408
409 if (bank->target->state != TARGET_HALTED) {
410 LOG_WARNING("Cannot communicate... target not halted.");
411 return ERROR_TARGET_NOT_HALTED;
412 }
413
414 /* Obtain the 8-word Chip Identification Number */
415 for (i = 0; i < 7; i++) {
416 retval = target_read_u32(bank->target, FLASH_CS0 + i * 4, &chipid[i]);
417 if (retval != ERROR_OK) {
418 LOG_ERROR("Cannot read CS0 register %i.", i);
419 return retval;
420 }
421 LOG_DEBUG("ID[%d] = %08" PRIX32, i, chipid[i]);
422 }
423 retval = target_read_u32(bank->target, SCU_BASE + 0x000, &chipid[7]);
424 if (retval != ERROR_OK) {
425 LOG_ERROR("Cannot read DBGROMID register.");
426 return retval;
427 }
428 LOG_DEBUG("ID[7] = %08" PRIX32, chipid[7]);
429
430 command_print_sameline(cmd,
431 "XMC%" PRIx32 "00 %" PRIX32 " flash %" PRIu32 "KB ROM %" PRIu32 "KB SRAM %" PRIu32 "KB",
432 (chipid[0] >> 12) & 0xff,
433 0xAA + (chipid[7] >> 28) - 1,
434 (((chipid[6] >> 12) & 0x3f) - 1) * 4,
435 (((chipid[4] >> 8) & 0x3f) * 256) / 1024,
436 (((chipid[5] >> 8) & 0x1f) * 256 * 4) / 1024);
437
438 return ERROR_OK;
439 }
440
441 static int xmc1xxx_probe(struct flash_bank *bank)
442 {
443 struct xmc1xxx_flash_bank *xmc_bank = bank->driver_priv;
444 uint32_t flash_addr = bank->base;
445 uint32_t idchip, flsize;
446 int retval;
447
448 if (xmc_bank->probed)
449 return ERROR_OK;
450
451 if (bank->target->state != TARGET_HALTED) {
452 LOG_WARNING("Cannot communicate... target not halted.");
453 return ERROR_TARGET_NOT_HALTED;
454 }
455
456 retval = target_read_u32(bank->target, SCU_IDCHIP, &idchip);
457 if (retval != ERROR_OK) {
458 LOG_ERROR("Cannot read IDCHIP register.");
459 return retval;
460 }
461
462 if ((idchip & 0xffff0000) != 0x10000) {
463 LOG_ERROR("IDCHIP register does not match XMC1xxx.");
464 return ERROR_FAIL;
465 }
466
467 LOG_DEBUG("IDCHIP = %08" PRIx32, idchip);
468
469 retval = target_read_u32(bank->target, PAU_FLSIZE, &flsize);
470 if (retval != ERROR_OK) {
471 LOG_ERROR("Cannot read FLSIZE register.");
472 return retval;
473 }
474
475 bank->num_sectors = 1 + ((flsize >> 12) & 0x3f) - 1;
476 bank->size = bank->num_sectors * 4 * 1024;
477 bank->sectors = calloc(bank->num_sectors,
478 sizeof(struct flash_sector));
479 for (unsigned int i = 0; i < bank->num_sectors; i++) {
480 if (i == 0) {
481 bank->sectors[i].size = 0x200;
482 bank->sectors[i].offset = 0xE00;
483 flash_addr += 0x1000;
484 } else {
485 bank->sectors[i].size = 4 * 1024;
486 bank->sectors[i].offset = flash_addr - bank->base;
487 flash_addr += bank->sectors[i].size;
488 }
489 bank->sectors[i].is_erased = -1;
490 bank->sectors[i].is_protected = -1;
491 }
492
493 xmc_bank->probed = true;
494
495 return ERROR_OK;
496 }
497
498 static int xmc1xxx_auto_probe(struct flash_bank *bank)
499 {
500 struct xmc1xxx_flash_bank *xmc_bank = bank->driver_priv;
501
502 if (xmc_bank->probed)
503 return ERROR_OK;
504
505 return xmc1xxx_probe(bank);
506 }
507
508 FLASH_BANK_COMMAND_HANDLER(xmc1xxx_flash_bank_command)
509 {
510 struct xmc1xxx_flash_bank *xmc_bank;
511
512 xmc_bank = malloc(sizeof(struct xmc1xxx_flash_bank));
513 if (!xmc_bank)
514 return ERROR_FLASH_OPERATION_FAILED;
515
516 xmc_bank->probed = false;
517
518 bank->driver_priv = xmc_bank;
519
520 return ERROR_OK;
521 }
522
523 const struct flash_driver xmc1xxx_flash = {
524 .name = "xmc1xxx",
525 .flash_bank_command = xmc1xxx_flash_bank_command,
526 .info = xmc1xxx_get_info_command,
527 .probe = xmc1xxx_probe,
528 .auto_probe = xmc1xxx_auto_probe,
529 .protect_check = xmc1xxx_protect_check,
530 .read = default_flash_read,
531 .erase = xmc1xxx_erase,
532 .erase_check = xmc1xxx_erase_check,
533 .write = xmc1xxx_write,
534 .free_driver_priv = default_flash_free_driver_priv,
535 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)