flash/nor: Use proper data types in driver API
[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 " (%" PRId32 " 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 %" PRId32 " 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 %" PRId32 " 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 " (%" PRId32 "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, char *buf, int buf_size)
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         snprintf(buf, buf_size, "XMC%" PRIx32 "00 %X flash %uKB ROM %uKB SRAM %uKB",
433                         (chipid[0] >> 12) & 0xff,
434                         0xAA + (chipid[7] >> 28) - 1,
435                         (((chipid[6] >> 12) & 0x3f) - 1) * 4,
436                         (((chipid[4] >> 8) & 0x3f) * 256) / 1024,
437                         (((chipid[5] >> 8) & 0x1f) * 256 * 4) / 1024);
438
439         return ERROR_OK;
440 }
441
442 static int xmc1xxx_probe(struct flash_bank *bank)
443 {
444         struct xmc1xxx_flash_bank *xmc_bank = bank->driver_priv;
445         uint32_t flash_addr = bank->base;
446         uint32_t idchip, flsize;
447         int retval;
448
449         if (xmc_bank->probed)
450                 return ERROR_OK;
451
452         if (bank->target->state != TARGET_HALTED) {
453                 LOG_WARNING("Cannot communicate... target not halted.");
454                 return ERROR_TARGET_NOT_HALTED;
455         }
456
457         retval = target_read_u32(bank->target, SCU_IDCHIP, &idchip);
458         if (retval != ERROR_OK) {
459                 LOG_ERROR("Cannot read IDCHIP register.");
460                 return retval;
461         }
462
463         if ((idchip & 0xffff0000) != 0x10000) {
464                 LOG_ERROR("IDCHIP register does not match XMC1xxx.");
465                 return ERROR_FAIL;
466         }
467
468         LOG_DEBUG("IDCHIP = %08" PRIx32, idchip);
469
470         retval = target_read_u32(bank->target, PAU_FLSIZE, &flsize);
471         if (retval != ERROR_OK) {
472                 LOG_ERROR("Cannot read FLSIZE register.");
473                 return retval;
474         }
475
476         bank->num_sectors = 1 + ((flsize >> 12) & 0x3f) - 1;
477         bank->size = bank->num_sectors * 4 * 1024;
478         bank->sectors = calloc(bank->num_sectors,
479                                sizeof(struct flash_sector));
480         for (unsigned int i = 0; i < bank->num_sectors; i++) {
481                 if (i == 0) {
482                         bank->sectors[i].size = 0x200;
483                         bank->sectors[i].offset = 0xE00;
484                         flash_addr += 0x1000;
485                 } else {
486                         bank->sectors[i].size = 4 * 1024;
487                         bank->sectors[i].offset = flash_addr - bank->base;
488                         flash_addr += bank->sectors[i].size;
489                 }
490                 bank->sectors[i].is_erased = -1;
491                 bank->sectors[i].is_protected = -1;
492         }
493
494         xmc_bank->probed = true;
495
496         return ERROR_OK;
497 }
498
499 static int xmc1xxx_auto_probe(struct flash_bank *bank)
500 {
501         struct xmc1xxx_flash_bank *xmc_bank = bank->driver_priv;
502
503         if (xmc_bank->probed)
504                 return ERROR_OK;
505
506         return xmc1xxx_probe(bank);
507 }
508
509 FLASH_BANK_COMMAND_HANDLER(xmc1xxx_flash_bank_command)
510 {
511         struct xmc1xxx_flash_bank *xmc_bank;
512
513         xmc_bank = malloc(sizeof(struct xmc1xxx_flash_bank));
514         if (!xmc_bank)
515                 return ERROR_FLASH_OPERATION_FAILED;
516
517         xmc_bank->probed = false;
518
519         bank->driver_priv = xmc_bank;
520
521         return ERROR_OK;
522 }
523
524 static const struct command_registration xmc1xxx_exec_command_handlers[] = {
525         COMMAND_REGISTRATION_DONE
526 };
527
528 static const struct command_registration xmc1xxx_command_handlers[] = {
529         {
530                 .name = "xmc1xxx",
531                 .mode = COMMAND_ANY,
532                 .help = "xmc1xxx flash command group",
533                 .usage = "",
534                 .chain = xmc1xxx_exec_command_handlers,
535         },
536         COMMAND_REGISTRATION_DONE
537 };
538
539 const struct flash_driver xmc1xxx_flash = {
540         .name = "xmc1xxx",
541         .commands = xmc1xxx_command_handlers,
542         .flash_bank_command = xmc1xxx_flash_bank_command,
543         .info = xmc1xxx_get_info_command,
544         .probe = xmc1xxx_probe,
545         .auto_probe = xmc1xxx_auto_probe,
546         .protect_check = xmc1xxx_protect_check,
547         .read = default_flash_read,
548         .erase = xmc1xxx_erase,
549         .erase_check = xmc1xxx_erase_check,
550         .write = xmc1xxx_write,
551         .free_driver_priv = default_flash_free_driver_priv,
552 };