]> git.sur5r.net Git - openocd/blob - src/flash/nor/fm4.c
flash: New Spansion FM4 flash driver
[openocd] / src / flash / nor / fm4.c
1 /*
2  * Spansion FM4 flash
3  *
4  * Copyright (c) 2015 Andreas Färber
5  *
6  * Based on S6E2CC_MN709-00007 for S6E2CC/C5/C4/C3/C2/C1 series
7  * Based on MB9B560R_MN709-00005 for MB9BFx66/x67/x68 series
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include "imp.h"
15 #include <helper/binarybuffer.h>
16 #include <target/algorithm.h>
17 #include <target/armv7m.h>
18
19 #define FLASH_BASE 0x40000000
20 #define FASZR   (FLASH_BASE + 0x000)
21 #define DFCTRLR (FLASH_BASE + 0x030)
22 #define DFCTRLR_DFE (1UL << 0)
23
24 #define WDG_BASE 0x40011000
25 #define WDG_CTL (WDG_BASE + 0x008)
26 #define WDG_LCK (WDG_BASE + 0xC00)
27
28 enum fm4_variant {
29         mb9bfx66,
30         mb9bfx67,
31         mb9bfx68,
32
33         s6e2cx8,
34         s6e2cx9,
35         s6e2cxa,
36 };
37
38 struct fm4_flash_bank {
39         enum fm4_variant variant;
40         int macro_nr;
41         bool probed;
42 };
43
44 static int fm4_disable_hw_watchdog(struct target *target)
45 {
46         int retval;
47
48         retval = target_write_u32(target, WDG_LCK, 0x1ACCE551);
49         if (retval != ERROR_OK)
50                 return retval;
51
52         retval = target_write_u32(target, WDG_LCK, 0xE5331AAE);
53         if (retval != ERROR_OK)
54                 return retval;
55
56         retval = target_write_u32(target, WDG_CTL, 0);
57         if (retval != ERROR_OK)
58                 return retval;
59
60         return ERROR_OK;
61 }
62
63 static int fm4_enter_flash_cpu_programming_mode(struct target *target)
64 {
65         uint32_t u32_value;
66         int retval;
67
68         /* FASZR ASZ = CPU programming mode */
69         retval = target_write_u32(target, FASZR, 0x00000001);
70         if (retval != ERROR_OK)
71                 return retval;
72         retval = target_read_u32(target, FASZR, &u32_value);
73         if (retval != ERROR_OK)
74                 return retval;
75
76         return ERROR_OK;
77 }
78
79 static int fm4_enter_flash_cpu_rom_mode(struct target *target)
80 {
81         uint32_t u32_value;
82         int retval;
83
84         /* FASZR ASZ = CPU ROM mode */
85         retval = target_write_u32(target, FASZR, 0x00000002);
86         if (retval != ERROR_OK)
87                 return retval;
88         retval = target_read_u32(target, FASZR, &u32_value);
89         if (retval != ERROR_OK)
90                 return retval;
91
92         return ERROR_OK;
93 }
94
95 static int fm4_flash_erase(struct flash_bank *bank, int first, int last)
96 {
97         struct target *target = bank->target;
98         struct working_area *workarea;
99         struct reg_param reg_params[4];
100         struct armv7m_algorithm armv7m_algo;
101         unsigned i;
102         int retval, sector;
103         const uint8_t erase_sector_code[] = {
104 #include "../../../contrib/loaders/flash/fm4/erase.inc"
105         };
106
107         if (target->state != TARGET_HALTED) {
108                 LOG_WARNING("Cannot communicate... target not halted.");
109                 return ERROR_TARGET_NOT_HALTED;
110         }
111
112         LOG_DEBUG("Spansion FM4 erase sectors %d to %d", first, last);
113
114         retval = fm4_disable_hw_watchdog(target);
115         if (retval != ERROR_OK)
116                 return retval;
117
118         retval = fm4_enter_flash_cpu_programming_mode(target);
119         if (retval != ERROR_OK)
120                 return retval;
121
122         retval = target_alloc_working_area(target, sizeof(erase_sector_code),
123                         &workarea);
124         if (retval != ERROR_OK) {
125                 LOG_ERROR("No working area available.");
126                 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
127                 goto err_alloc_code;
128         }
129         retval = target_write_buffer(target, workarea->address,
130                         sizeof(erase_sector_code), erase_sector_code);
131         if (retval != ERROR_OK)
132                 goto err_write_code;
133
134         armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
135         armv7m_algo.core_mode = ARM_MODE_THREAD;
136
137         init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
138         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
139         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
140         init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
141
142         for (sector = first; sector <= last; sector++) {
143                 uint32_t addr = bank->base + bank->sectors[sector].offset;
144                 uint32_t result;
145
146                 buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8);
147                 buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554);
148                 buf_set_u32(reg_params[2].value, 0, 32, addr);
149
150                 retval = target_run_algorithm(target,
151                                 0, NULL,
152                                 ARRAY_SIZE(reg_params), reg_params,
153                                 workarea->address, 0,
154                                 1000, &armv7m_algo);
155                 if (retval != ERROR_OK) {
156                         LOG_ERROR("Error executing flash sector erase "
157                                 "programming algorithm");
158                         retval = ERROR_FLASH_OPERATION_FAILED;
159                         goto err_run;
160                 }
161
162                 result = buf_get_u32(reg_params[3].value, 0, 32);
163                 if (result == 2) {
164                         LOG_ERROR("Timeout error from flash sector erase programming algorithm");
165                         retval = ERROR_FLASH_OPERATION_FAILED;
166                         goto err_run_ret;
167                 } else if (result != 0) {
168                         LOG_ERROR("Unexpected error %d from flash sector erase programming algorithm", result);
169                         retval = ERROR_FLASH_OPERATION_FAILED;
170                         goto err_run_ret;
171                 } else
172                         retval = ERROR_OK;
173
174                 bank->sectors[sector].is_erased = 1;
175         }
176
177 err_run_ret:
178 err_run:
179         for (i = 0; i < ARRAY_SIZE(reg_params); i++)
180                 destroy_reg_param(&reg_params[i]);
181
182 err_write_code:
183         target_free_working_area(target, workarea);
184
185 err_alloc_code:
186         if (retval != ERROR_OK)
187                 fm4_enter_flash_cpu_rom_mode(target);
188         else
189                 retval = fm4_enter_flash_cpu_rom_mode(target);
190
191         return retval;
192 }
193
194 static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
195                 uint32_t offset, uint32_t byte_count)
196 {
197         struct target *target = bank->target;
198         struct working_area *code_workarea, *data_workarea;
199         struct reg_param reg_params[6];
200         struct armv7m_algorithm armv7m_algo;
201         uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2);
202         uint32_t result;
203         unsigned i;
204         int retval;
205         const uint8_t write_block_code[] = {
206 #include "../../../contrib/loaders/flash/fm4/write.inc"
207         };
208
209         LOG_DEBUG("Spansion FM4 write at 0x%08" PRIx32 " (%" PRId32 " bytes)",
210                 offset, byte_count);
211
212         if (offset & 0x1) {
213                 LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment",
214                         offset);
215                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
216         }
217         if (byte_count & 0x1) {
218                 LOG_WARNING("length %" PRId32 " is not 2-byte aligned, rounding up",
219                         byte_count);
220         }
221
222         if (target->state != TARGET_HALTED) {
223                 LOG_WARNING("Cannot communicate... target not halted.");
224                 return ERROR_TARGET_NOT_HALTED;
225         }
226
227         retval = fm4_disable_hw_watchdog(target);
228         if (retval != ERROR_OK)
229                 return retval;
230
231         retval = target_alloc_working_area(target, sizeof(write_block_code),
232                         &code_workarea);
233         if (retval != ERROR_OK) {
234                 LOG_ERROR("No working area available for write code.");
235                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
236         }
237         retval = target_write_buffer(target, code_workarea->address,
238                         sizeof(write_block_code), write_block_code);
239         if (retval != ERROR_OK)
240                 goto err_write_code;
241
242         retval = target_alloc_working_area(target,
243                 MIN(halfword_count * 2, target_get_working_area_avail(target)),
244                 &data_workarea);
245         if (retval != ERROR_OK) {
246                 LOG_ERROR("No working area available for write data.");
247                 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
248                 goto err_alloc_data;
249         }
250
251         armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
252         armv7m_algo.core_mode = ARM_MODE_THREAD;
253
254         init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
255         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
256         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
257         init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
258         init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
259         init_reg_param(&reg_params[5], "r5", 32, PARAM_IN);
260
261         retval = fm4_enter_flash_cpu_programming_mode(target);
262         if (retval != ERROR_OK)
263                 goto err_flash_mode;
264
265         while (byte_count > 0) {
266                 uint32_t halfwords = MIN(halfword_count, data_workarea->size / 2);
267                 uint32_t addr = bank->base + offset;
268
269                 LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" PRIx32,
270                         MIN(halfwords * 2, byte_count), data_workarea->address);
271
272                 retval = target_write_buffer(target, data_workarea->address,
273                         MIN(halfwords * 2, byte_count), buffer);
274                 if (retval != ERROR_OK) {
275                         LOG_ERROR("Error writing data buffer");
276                         retval = ERROR_FLASH_OPERATION_FAILED;
277                         goto err_write_data;
278                 }
279
280                 LOG_DEBUG("writing 0x%08" PRIx32 "-0x%08" PRIx32 " (%" PRId32 "x)",
281                         addr, addr + halfwords * 2 - 1, halfwords);
282
283                 buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8);
284                 buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554);
285                 buf_set_u32(reg_params[2].value, 0, 32, addr);
286                 buf_set_u32(reg_params[3].value, 0, 32, data_workarea->address);
287                 buf_set_u32(reg_params[4].value, 0, 32, halfwords);
288
289                 retval = target_run_algorithm(target,
290                                 0, NULL,
291                                 ARRAY_SIZE(reg_params), reg_params,
292                                 code_workarea->address, 0,
293                                 5 * 60 * 1000, &armv7m_algo);
294                 if (retval != ERROR_OK) {
295                         LOG_ERROR("Error executing flash sector erase "
296                                 "programming algorithm");
297                         retval = ERROR_FLASH_OPERATION_FAILED;
298                         goto err_run;
299                 }
300
301                 result = buf_get_u32(reg_params[5].value, 0, 32);
302                 if (result == 2) {
303                         LOG_ERROR("Timeout error from flash write "
304                                 "programming algorithm");
305                         retval = ERROR_FLASH_OPERATION_FAILED;
306                         goto err_run_ret;
307                 } else if (result != 0) {
308                         LOG_ERROR("Unexpected error %d from flash write "
309                                 "programming algorithm", result);
310                         retval = ERROR_FLASH_OPERATION_FAILED;
311                         goto err_run_ret;
312                 } else
313                         retval = ERROR_OK;
314
315                 halfword_count -= halfwords;
316                 offset += halfwords * 2;
317                 buffer += halfwords * 2;
318                 byte_count -= MIN(halfwords * 2, byte_count);
319         }
320
321 err_run_ret:
322 err_run:
323 err_write_data:
324         retval = fm4_enter_flash_cpu_rom_mode(target);
325
326 err_flash_mode:
327         for (i = 0; i < ARRAY_SIZE(reg_params); i++)
328                 destroy_reg_param(&reg_params[i]);
329
330         target_free_working_area(target, data_workarea);
331 err_alloc_data:
332 err_write_code:
333         target_free_working_area(target, code_workarea);
334
335         return retval;
336 }
337
338 static int mb9bf_probe(struct flash_bank *bank)
339 {
340         struct fm4_flash_bank *fm4_bank = bank->driver_priv;
341         uint32_t flash_addr = bank->base;
342         int i;
343
344         switch (fm4_bank->variant) {
345         case mb9bfx66:
346                 bank->num_sectors = 12;
347                 break;
348         case mb9bfx67:
349                 bank->num_sectors = 16;
350                 break;
351         case mb9bfx68:
352                 bank->num_sectors = 20;
353                 break;
354         default:
355                 return ERROR_FLASH_OPER_UNSUPPORTED;
356         }
357
358         LOG_DEBUG("%d sectors", bank->num_sectors);
359         bank->sectors = calloc(bank->num_sectors,
360                                 sizeof(struct flash_sector));
361         for (i = 0; i < bank->num_sectors; i++) {
362                 if (i < 4)
363                         bank->sectors[i].size = 8 * 1024;
364                 else if (i == 4)
365                         bank->sectors[i].size = 32 * 1024;
366                 else
367                         bank->sectors[i].size = 64 * 1024;
368                 bank->sectors[i].offset = flash_addr - bank->base;
369                 bank->sectors[i].is_erased = -1;
370                 bank->sectors[i].is_protected = -1;
371
372                 bank->size += bank->sectors[i].size;
373                 flash_addr += bank->sectors[i].size;
374         }
375
376         return ERROR_OK;
377 }
378
379 static void s6e2cc_init_sector(struct flash_sector *sector, int sa)
380 {
381         if (sa < 8)
382                 sector->size = 8 * 1024;
383         else if (sa == 8)
384                 sector->size = 32 * 1024;
385         else
386                 sector->size = 64 * 1024;
387
388         sector->is_erased = -1;
389         sector->is_protected = -1;
390 }
391
392 static int s6e2cc_probe(struct flash_bank *bank)
393 {
394         struct target *target = bank->target;
395         struct fm4_flash_bank *fm4_bank = bank->driver_priv;
396         uint32_t u32_value;
397         uint32_t flash_addr = bank->base;
398         int i, retval, num_sectors, num_extra_sectors;
399
400         retval = target_read_u32(target, DFCTRLR, &u32_value);
401         if (retval != ERROR_OK)
402                 return retval;
403         if (u32_value & DFCTRLR_DFE) {
404                 LOG_WARNING("Dual Flash mode is not implemented.");
405                 return ERROR_FLASH_OPER_UNSUPPORTED;
406         }
407
408         switch (fm4_bank->variant) {
409         case s6e2cx8:
410                 num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 0;
411                 break;
412         case s6e2cx9:
413                 num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 12;
414                 break;
415         case s6e2cxa:
416                 num_sectors = 20;
417                 break;
418         default:
419                 return ERROR_FLASH_OPER_UNSUPPORTED;
420         }
421         num_extra_sectors = (fm4_bank->macro_nr == 0) ? 1 : 4;
422         bank->num_sectors = num_sectors + num_extra_sectors;
423
424         LOG_DEBUG("%d sectors", bank->num_sectors);
425         bank->sectors = calloc(bank->num_sectors,
426                                 sizeof(struct flash_sector));
427         for (i = 0; i < num_sectors; i++) {
428                 int sa = 4 + i;
429                 bank->sectors[i].offset = flash_addr - bank->base;
430                 s6e2cc_init_sector(&bank->sectors[i], sa);
431
432                 bank->size += bank->sectors[i].size;
433                 flash_addr += bank->sectors[i].size;
434         }
435
436         flash_addr = (fm4_bank->macro_nr == 0) ? 0x00406000 : 0x00408000;
437         for (; i < bank->num_sectors; i++) {
438                 int sa = 4 - num_extra_sectors + (i - num_sectors);
439                 bank->sectors[i].offset = flash_addr - bank->base;
440                 s6e2cc_init_sector(&bank->sectors[i], sa);
441
442                 /*
443                  * Don't increase bank->size for these sectors
444                  * to avoid an overlap between Flash Macros #0 and #1.
445                  */
446                 flash_addr += bank->sectors[i].size;
447         }
448
449         return ERROR_OK;
450 }
451
452 static int fm4_probe(struct flash_bank *bank)
453 {
454         struct fm4_flash_bank *fm4_bank = bank->driver_priv;
455         int retval;
456
457         if (fm4_bank->probed)
458                 return ERROR_OK;
459
460         if (bank->target->state != TARGET_HALTED) {
461                 LOG_WARNING("Cannot communicate... target not halted.");
462                 return ERROR_TARGET_NOT_HALTED;
463         }
464
465         switch (fm4_bank->variant) {
466         case mb9bfx66:
467         case mb9bfx67:
468         case mb9bfx68:
469                 retval = mb9bf_probe(bank);
470                 break;
471         case s6e2cx8:
472         case s6e2cx9:
473         case s6e2cxa:
474                 retval = s6e2cc_probe(bank);
475                 break;
476         default:
477                 return ERROR_FLASH_OPER_UNSUPPORTED;
478         }
479         if (retval != ERROR_OK)
480                 return retval;
481
482         fm4_bank->probed = true;
483
484         return ERROR_OK;
485 }
486
487 static int fm4_auto_probe(struct flash_bank *bank)
488 {
489         struct fm4_flash_bank *fm4_bank = bank->driver_priv;
490
491         if (fm4_bank->probed)
492                 return ERROR_OK;
493
494         return fm4_probe(bank);
495 }
496
497 static int fm4_protect_check(struct flash_bank *bank)
498 {
499         return ERROR_OK;
500 }
501
502 static int fm4_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
503 {
504         struct fm4_flash_bank *fm4_bank = bank->driver_priv;
505         const char *name;
506
507         if (bank->target->state != TARGET_HALTED) {
508                 LOG_WARNING("Cannot communicate... target not halted.");
509                 return ERROR_TARGET_NOT_HALTED;
510         }
511
512         switch (fm4_bank->variant) {
513         case mb9bfx66:
514                 name = "MB9BFx66";
515                 break;
516         case mb9bfx67:
517                 name = "MB9BFx67";
518                 break;
519         case mb9bfx68:
520                 name = "MB9BFx68";
521                 break;
522         case s6e2cx8:
523                 name = "S6E2Cx8";
524                 break;
525         case s6e2cx9:
526                 name = "S6E2Cx9";
527                 break;
528         case s6e2cxa:
529                 name = "S6E2CxA";
530                 break;
531         default:
532                 name = "unknown";
533                 break;
534         }
535
536         switch (fm4_bank->variant) {
537         case s6e2cx8:
538         case s6e2cx9:
539         case s6e2cxa:
540                 snprintf(buf, buf_size, "%s MainFlash Macro #%i",
541                         name, fm4_bank->macro_nr);
542                 break;
543         default:
544                 snprintf(buf, buf_size, "%s MainFlash", name);
545                 break;
546         }
547
548         return ERROR_OK;
549 }
550
551 static bool fm4_name_match(const char *s, const char *pattern)
552 {
553         int i = 0;
554
555         while (s[i]) {
556                 /* If the match string is shorter, ignore excess */
557                 if (!pattern[i])
558                         return true;
559                 /* Use x as wildcard */
560                 if (pattern[i] != 'x' && tolower(s[i]) != tolower(pattern[i]))
561                         return false;
562                 i++;
563         }
564         return true;
565 }
566
567 static int mb9bf_bank_setup(struct flash_bank *bank, const char *variant)
568 {
569         struct fm4_flash_bank *fm4_bank = bank->driver_priv;
570
571         if (fm4_name_match(variant, "MB9BFx66")) {
572                 fm4_bank->variant = mb9bfx66;
573         } else if (fm4_name_match(variant, "MB9BFx67")) {
574                 fm4_bank->variant = mb9bfx67;
575         } else if (fm4_name_match(variant, "MB9BFx68")) {
576                 fm4_bank->variant = mb9bfx68;
577         } else {
578                 LOG_WARNING("MB9BF variant %s not recognized.", variant);
579                 return ERROR_FLASH_OPER_UNSUPPORTED;
580         }
581
582         return ERROR_OK;
583 }
584
585 static int s6e2cc_bank_setup(struct flash_bank *bank, const char *variant)
586 {
587         struct fm4_flash_bank *fm4_bank = bank->driver_priv;
588
589         if (fm4_name_match(variant, "S6E2Cx8")) {
590                 fm4_bank->variant = s6e2cx8;
591         } else if (fm4_name_match(variant, "S6E2Cx9")) {
592                 fm4_bank->variant = s6e2cx9;
593         } else if (fm4_name_match(variant, "S6E2CxA")) {
594                 fm4_bank->variant = s6e2cxa;
595         } else {
596                 LOG_WARNING("S6E2CC variant %s not recognized.", variant);
597                 return ERROR_FLASH_OPER_UNSUPPORTED;
598         }
599
600         return ERROR_OK;
601 }
602
603 FLASH_BANK_COMMAND_HANDLER(fm4_flash_bank_command)
604 {
605         struct fm4_flash_bank *fm4_bank;
606         const char *variant;
607         int ret;
608
609         if (CMD_ARGC < 7)
610                 return ERROR_COMMAND_SYNTAX_ERROR;
611
612         variant = CMD_ARGV[6];
613
614         fm4_bank = malloc(sizeof(struct fm4_flash_bank));
615         if (!fm4_bank)
616                 return ERROR_FLASH_OPERATION_FAILED;
617
618         fm4_bank->probed = false;
619         fm4_bank->macro_nr = (bank->base == 0x00000000) ? 0 : 1;
620
621         bank->driver_priv = fm4_bank;
622
623         if (fm4_name_match(variant, "MB9BF"))
624                 ret = mb9bf_bank_setup(bank, variant);
625         else if (fm4_name_match(variant, "S6E2Cx"))
626                 ret = s6e2cc_bank_setup(bank, variant);
627         else {
628                 LOG_WARNING("Family %s not recognized.", variant);
629                 ret = ERROR_FLASH_OPER_UNSUPPORTED;
630         }
631         if (ret != ERROR_OK)
632                 free(fm4_bank);
633         return ret;
634 }
635
636 static const struct command_registration fm4_exec_command_handlers[] = {
637         COMMAND_REGISTRATION_DONE
638 };
639
640 static const struct command_registration fm4_command_handlers[] = {
641         {
642                 .name = "fm4",
643                 .mode = COMMAND_ANY,
644                 .help = "fm4 flash command group",
645                 .usage = "",
646                 .chain = fm4_exec_command_handlers,
647         },
648         COMMAND_REGISTRATION_DONE
649 };
650
651 struct flash_driver fm4_flash = {
652         .name = "fm4",
653         .commands = fm4_command_handlers,
654         .flash_bank_command = fm4_flash_bank_command,
655         .info = fm4_get_info_command,
656         .probe = fm4_probe,
657         .auto_probe = fm4_auto_probe,
658         .protect_check = fm4_protect_check,
659         .erase = fm4_flash_erase,
660         .erase_check = default_flash_blank_check,
661         .write = fm4_flash_write,
662 };