helper/align.h: use it
[openocd.git] / src / flash / nor / xmc1xxx.c
1 /*
2 * XMC1000 flash driver
3 *
4 * Copyright (c) 2016 Andreas Färber
5 *
6 * License: GPL-2.0+
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 for (unsigned int sector = first; sector <= last; sector++)
145 bank->sectors[sector].is_erased = 1;
146
147 err_run:
148 for (i = 0; i < ARRAY_SIZE(reg_params); i++)
149 destroy_reg_param(&reg_params[i]);
150
151 err_write_code:
152 target_free_working_area(target, workarea);
153
154 err_alloc_code:
155 return retval;
156 }
157
158 static int xmc1xxx_erase_check(struct flash_bank *bank)
159 {
160 struct target *target = bank->target;
161 struct working_area *workarea;
162 struct reg_param reg_params[3];
163 struct armv7m_algorithm armv7m_algo;
164 uint16_t val;
165 unsigned i;
166 int retval;
167 const uint8_t erase_check_code[] = {
168 #include "../../../contrib/loaders/flash/xmc1xxx/erase_check.inc"
169 };
170
171 if (bank->target->state != TARGET_HALTED) {
172 LOG_WARNING("Cannot communicate... target not halted.");
173 return ERROR_TARGET_NOT_HALTED;
174 }
175
176 retval = target_alloc_working_area(target, sizeof(erase_check_code),
177 &workarea);
178 if (retval != ERROR_OK) {
179 LOG_ERROR("No working area available.");
180 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
181 goto err_alloc_code;
182 }
183 retval = target_write_buffer(target, workarea->address,
184 sizeof(erase_check_code), erase_check_code);
185 if (retval != ERROR_OK)
186 goto err_write_code;
187
188 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
189 armv7m_algo.core_mode = ARM_MODE_THREAD;
190
191 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
192 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
193 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
194
195 buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE);
196
197 for (unsigned int sector = 0; sector < bank->num_sectors; sector++) {
198 uint32_t start = bank->base + bank->sectors[sector].offset;
199 buf_set_u32(reg_params[1].value, 0, 32, start);
200 buf_set_u32(reg_params[2].value, 0, 32, start + bank->sectors[sector].size);
201
202 retval = xmc1xxx_nvm_check_idle(target);
203 if (retval != ERROR_OK)
204 goto err_nvmprog;
205
206 LOG_DEBUG("Erase-checking 0x%08" PRIx32, start);
207 retval = target_run_algorithm(target,
208 0, NULL,
209 ARRAY_SIZE(reg_params), reg_params,
210 workarea->address, 0,
211 1000, &armv7m_algo);
212 if (retval != ERROR_OK) {
213 LOG_ERROR("Error executing flash sector erase check "
214 "programming algorithm");
215 retval = xmc1xxx_nvm_set_idle(target);
216 if (retval != ERROR_OK)
217 LOG_WARNING("Couldn't restore NVMPROG.ACTION");
218 retval = ERROR_FLASH_OPERATION_FAILED;
219 goto err_run;
220 }
221
222 retval = target_read_u16(target, NVMSTATUS, &val);
223 if (retval != ERROR_OK) {
224 LOG_ERROR("Couldn't read NVMSTATUS");
225 goto err_nvmstatus;
226 }
227 bank->sectors[sector].is_erased = (val & NVMSTATUS_VERR_MASK) ? 0 : 1;
228 }
229
230 err_nvmstatus:
231 err_run:
232 err_nvmprog:
233 for (i = 0; i < ARRAY_SIZE(reg_params); i++)
234 destroy_reg_param(&reg_params[i]);
235
236 err_write_code:
237 target_free_working_area(target, workarea);
238
239 err_alloc_code:
240 return retval;
241 }
242
243 static int xmc1xxx_write(struct flash_bank *bank, const uint8_t *buffer,
244 uint32_t offset, uint32_t byte_count)
245 {
246 struct target *target = bank->target;
247 struct working_area *code_workarea, *data_workarea;
248 struct reg_param reg_params[4];
249 struct armv7m_algorithm armv7m_algo;
250 uint32_t block_count = DIV_ROUND_UP(byte_count, NVM_BLOCK_SIZE);
251 unsigned i;
252 int retval;
253 const uint8_t write_code[] = {
254 #include "../../../contrib/loaders/flash/xmc1xxx/write.inc"
255 };
256
257 LOG_DEBUG("Infineon XMC1000 write at 0x%08" PRIx32 " (%" PRIu32 " bytes)",
258 offset, byte_count);
259
260 if (!IS_ALIGNED(offset, NVM_BLOCK_SIZE)) {
261 LOG_ERROR("offset 0x%" PRIx32 " breaks required block alignment",
262 offset);
263 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
264 }
265 if (!IS_ALIGNED(byte_count, NVM_BLOCK_SIZE)) {
266 LOG_WARNING("length %" PRIu32 " is not block aligned, rounding up",
267 byte_count);
268 }
269
270 if (target->state != TARGET_HALTED) {
271 LOG_WARNING("Cannot communicate... target not halted.");
272 return ERROR_TARGET_NOT_HALTED;
273 }
274
275 retval = target_alloc_working_area(target, sizeof(write_code),
276 &code_workarea);
277 if (retval != ERROR_OK) {
278 LOG_ERROR("No working area available for write code.");
279 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
280 goto err_alloc_code;
281 }
282 retval = target_write_buffer(target, code_workarea->address,
283 sizeof(write_code), write_code);
284 if (retval != ERROR_OK)
285 goto err_write_code;
286
287 retval = target_alloc_working_area(target, MAX(NVM_BLOCK_SIZE,
288 MIN(block_count * NVM_BLOCK_SIZE, target_get_working_area_avail(target))),
289 &data_workarea);
290 if (retval != ERROR_OK) {
291 LOG_ERROR("No working area available for write data.");
292 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
293 goto err_alloc_data;
294 }
295
296 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
297 armv7m_algo.core_mode = ARM_MODE_THREAD;
298
299 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
300 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
301 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
302 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
303
304 buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE);
305
306 while (byte_count > 0) {
307 uint32_t blocks = MIN(block_count, data_workarea->size / NVM_BLOCK_SIZE);
308 uint32_t addr = bank->base + offset;
309
310 LOG_DEBUG("copying %" PRIu32 " bytes to SRAM " TARGET_ADDR_FMT,
311 MIN(blocks * NVM_BLOCK_SIZE, byte_count),
312 data_workarea->address);
313
314 retval = target_write_buffer(target, data_workarea->address,
315 MIN(blocks * NVM_BLOCK_SIZE, byte_count), buffer);
316 if (retval != ERROR_OK) {
317 LOG_ERROR("Error writing data buffer");
318 retval = ERROR_FLASH_OPERATION_FAILED;
319 goto err_write_data;
320 }
321 if (byte_count < blocks * NVM_BLOCK_SIZE) {
322 retval = target_write_memory(target,
323 data_workarea->address + byte_count, 1,
324 blocks * NVM_BLOCK_SIZE - byte_count,
325 &bank->default_padded_value);
326 if (retval != ERROR_OK) {
327 LOG_ERROR("Error writing data padding");
328 retval = ERROR_FLASH_OPERATION_FAILED;
329 goto err_write_pad;
330 }
331 }
332
333 LOG_DEBUG("writing 0x%08" PRIx32 "-0x%08" PRIx32 " (%" PRIu32 "x)",
334 addr, addr + blocks * NVM_BLOCK_SIZE - 1, blocks);
335
336 retval = xmc1xxx_nvm_check_idle(target);
337 if (retval != ERROR_OK)
338 goto err_nvmprog;
339
340 buf_set_u32(reg_params[1].value, 0, 32, addr);
341 buf_set_u32(reg_params[2].value, 0, 32, data_workarea->address);
342 buf_set_u32(reg_params[3].value, 0, 32, blocks);
343
344 retval = target_run_algorithm(target,
345 0, NULL,
346 ARRAY_SIZE(reg_params), reg_params,
347 code_workarea->address, 0,
348 5 * 60 * 1000, &armv7m_algo);
349 if (retval != ERROR_OK) {
350 LOG_ERROR("Error executing flash write "
351 "programming algorithm");
352 retval = xmc1xxx_nvm_set_idle(target);
353 if (retval != ERROR_OK)
354 LOG_WARNING("Couldn't restore NVMPROG.ACTION");
355 retval = ERROR_FLASH_OPERATION_FAILED;
356 goto err_run;
357 }
358
359 block_count -= blocks;
360 offset += blocks * NVM_BLOCK_SIZE;
361 buffer += blocks * NVM_BLOCK_SIZE;
362 byte_count -= MIN(blocks * NVM_BLOCK_SIZE, byte_count);
363 }
364
365 err_run:
366 err_nvmprog:
367 err_write_pad:
368 err_write_data:
369 for (i = 0; i < ARRAY_SIZE(reg_params); i++)
370 destroy_reg_param(&reg_params[i]);
371
372 target_free_working_area(target, data_workarea);
373 err_alloc_data:
374 err_write_code:
375 target_free_working_area(target, code_workarea);
376
377 err_alloc_code:
378 return retval;
379 }
380
381 static int xmc1xxx_protect_check(struct flash_bank *bank)
382 {
383 uint32_t nvmconf;
384 unsigned int num_protected;
385 int retval;
386
387 if (bank->target->state != TARGET_HALTED) {
388 LOG_WARNING("Cannot communicate... target not halted.");
389 return ERROR_TARGET_NOT_HALTED;
390 }
391
392 retval = target_read_u32(bank->target, NVMCONF, &nvmconf);
393 if (retval != ERROR_OK) {
394 LOG_ERROR("Cannot read NVMCONF register.");
395 return retval;
396 }
397 LOG_DEBUG("NVMCONF = %08" PRIx32, nvmconf);
398
399 num_protected = (nvmconf >> 4) & 0xff;
400
401 for (unsigned int i = 0; i < bank->num_sectors; i++)
402 bank->sectors[i].is_protected = (i < num_protected) ? 1 : 0;
403
404 return ERROR_OK;
405 }
406
407 static int xmc1xxx_get_info_command(struct flash_bank *bank, struct command_invocation *cmd)
408 {
409 uint32_t chipid[8];
410 int i, retval;
411
412 if (bank->target->state != TARGET_HALTED) {
413 LOG_WARNING("Cannot communicate... target not halted.");
414 return ERROR_TARGET_NOT_HALTED;
415 }
416
417 /* Obtain the 8-word Chip Identification Number */
418 for (i = 0; i < 7; i++) {
419 retval = target_read_u32(bank->target, FLASH_CS0 + i * 4, &chipid[i]);
420 if (retval != ERROR_OK) {
421 LOG_ERROR("Cannot read CS0 register %i.", i);
422 return retval;
423 }
424 LOG_DEBUG("ID[%d] = %08" PRIX32, i, chipid[i]);
425 }
426 retval = target_read_u32(bank->target, SCU_BASE + 0x000, &chipid[7]);
427 if (retval != ERROR_OK) {
428 LOG_ERROR("Cannot read DBGROMID register.");
429 return retval;
430 }
431 LOG_DEBUG("ID[7] = %08" PRIX32, chipid[7]);
432
433 command_print_sameline(cmd,
434 "XMC%" PRIx32 "00 %" PRIX32 " flash %" PRIu32 "KB ROM %" PRIu32 "KB SRAM %" PRIu32 "KB",
435 (chipid[0] >> 12) & 0xff,
436 0xAA + (chipid[7] >> 28) - 1,
437 (((chipid[6] >> 12) & 0x3f) - 1) * 4,
438 (((chipid[4] >> 8) & 0x3f) * 256) / 1024,
439 (((chipid[5] >> 8) & 0x1f) * 256 * 4) / 1024);
440
441 return ERROR_OK;
442 }
443
444 static int xmc1xxx_probe(struct flash_bank *bank)
445 {
446 struct xmc1xxx_flash_bank *xmc_bank = bank->driver_priv;
447 uint32_t flash_addr = bank->base;
448 uint32_t idchip, flsize;
449 int retval;
450
451 if (xmc_bank->probed)
452 return ERROR_OK;
453
454 if (bank->target->state != TARGET_HALTED) {
455 LOG_WARNING("Cannot communicate... target not halted.");
456 return ERROR_TARGET_NOT_HALTED;
457 }
458
459 retval = target_read_u32(bank->target, SCU_IDCHIP, &idchip);
460 if (retval != ERROR_OK) {
461 LOG_ERROR("Cannot read IDCHIP register.");
462 return retval;
463 }
464
465 if ((idchip & 0xffff0000) != 0x10000) {
466 LOG_ERROR("IDCHIP register does not match XMC1xxx.");
467 return ERROR_FAIL;
468 }
469
470 LOG_DEBUG("IDCHIP = %08" PRIx32, idchip);
471
472 retval = target_read_u32(bank->target, PAU_FLSIZE, &flsize);
473 if (retval != ERROR_OK) {
474 LOG_ERROR("Cannot read FLSIZE register.");
475 return retval;
476 }
477
478 bank->num_sectors = 1 + ((flsize >> 12) & 0x3f) - 1;
479 bank->size = bank->num_sectors * 4 * 1024;
480 bank->sectors = calloc(bank->num_sectors,
481 sizeof(struct flash_sector));
482 for (unsigned int i = 0; i < bank->num_sectors; i++) {
483 if (i == 0) {
484 bank->sectors[i].size = 0x200;
485 bank->sectors[i].offset = 0xE00;
486 flash_addr += 0x1000;
487 } else {
488 bank->sectors[i].size = 4 * 1024;
489 bank->sectors[i].offset = flash_addr - bank->base;
490 flash_addr += bank->sectors[i].size;
491 }
492 bank->sectors[i].is_erased = -1;
493 bank->sectors[i].is_protected = -1;
494 }
495
496 xmc_bank->probed = true;
497
498 return ERROR_OK;
499 }
500
501 static int xmc1xxx_auto_probe(struct flash_bank *bank)
502 {
503 struct xmc1xxx_flash_bank *xmc_bank = bank->driver_priv;
504
505 if (xmc_bank->probed)
506 return ERROR_OK;
507
508 return xmc1xxx_probe(bank);
509 }
510
511 FLASH_BANK_COMMAND_HANDLER(xmc1xxx_flash_bank_command)
512 {
513 struct xmc1xxx_flash_bank *xmc_bank;
514
515 xmc_bank = malloc(sizeof(struct xmc1xxx_flash_bank));
516 if (!xmc_bank)
517 return ERROR_FLASH_OPERATION_FAILED;
518
519 xmc_bank->probed = false;
520
521 bank->driver_priv = xmc_bank;
522
523 return ERROR_OK;
524 }
525
526 static const struct command_registration xmc1xxx_exec_command_handlers[] = {
527 COMMAND_REGISTRATION_DONE
528 };
529
530 static const struct command_registration xmc1xxx_command_handlers[] = {
531 {
532 .name = "xmc1xxx",
533 .mode = COMMAND_ANY,
534 .help = "xmc1xxx flash command group",
535 .usage = "",
536 .chain = xmc1xxx_exec_command_handlers,
537 },
538 COMMAND_REGISTRATION_DONE
539 };
540
541 const struct flash_driver xmc1xxx_flash = {
542 .name = "xmc1xxx",
543 .commands = xmc1xxx_command_handlers,
544 .flash_bank_command = xmc1xxx_flash_bank_command,
545 .info = xmc1xxx_get_info_command,
546 .probe = xmc1xxx_probe,
547 .auto_probe = xmc1xxx_auto_probe,
548 .protect_check = xmc1xxx_protect_check,
549 .read = default_flash_read,
550 .erase = xmc1xxx_erase,
551 .erase_check = xmc1xxx_erase_check,
552 .write = xmc1xxx_write,
553 .free_driver_priv = default_flash_free_driver_priv,
554 };

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)