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