openocd: fix SPDX tag format for files .c
[fw/openocd] / src / flash / nor / aducm360.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4  *   Copyright (C) 2015 by Ivan Buliev                                     *
5  *   i.buliev@mikrosistemi.com                                             *
6  ***************************************************************************/
7
8 /***************************************************************************
9  *  This version for ADuCM360 is largely based on the following flash      *
10  *  drivers:                                                               *
11  *    - aduc702x.c                                                         *
12  *          Copyright (C) 2008 by Kevin McGuire                            *
13  *          Copyright (C) 2008 by Marcel Wijlaars                          *
14  *          Copyright (C) 2009 by Michael Ashton                           *
15  *   and                                                                   *
16  *    - stm32f1x.c                                                         *
17  *          Copyright (C) 2005 by Dominic Rath                             *
18  *          Dominic.Rath@gmx.de                                            *
19  *                                                                         *
20  *          Copyright (C) 2008 by Spencer Oliver                           *
21  *          spen@spen-soft.co.uk                                           *
22  *                                                                         *
23  *          Copyright (C) 2011 by Andreas Fritiofson                       *
24  *          andreas.fritiofson@gmail.com                                   *
25  ***************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "imp.h"
32 #include <helper/binarybuffer.h>
33 #include <helper/time_support.h>
34 #include <target/algorithm.h>
35 #include <target/armv7m.h>
36
37 static int aducm360_build_sector_list(struct flash_bank *bank);
38 static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms);
39 static int aducm360_set_write_enable(struct target *target, int enable);
40
41 #define ADUCM360_FLASH_BASE             0x40002800
42 #define ADUCM360_FLASH_FEESTA           0x0000
43 #define ADUCM360_FLASH_FEECON0          0x0004
44 #define ADUCM360_FLASH_FEECMD           0x0008
45 #define ADUCM360_FLASH_FEEADR0L         0x0010
46 #define ADUCM360_FLASH_FEEADR0H         0x0014
47 #define ADUCM360_FLASH_FEEADR1L         0x0018
48 #define ADUCM360_FLASH_FEEADR1H         0x001C
49 #define ADUCM360_FLASH_FEEKEY           0x0020
50 #define ADUCM360_FLASH_FEEPROL          0x0028
51 #define ADUCM360_FLASH_FEEPROH          0x002C
52 #define ADUCM360_FLASH_FEESIGL          0x0030
53 #define ADUCM360_FLASH_FEESIGH          0x0034
54 #define ADUCM360_FLASH_FEECON1          0x0038
55 #define ADUCM360_FLASH_FEEADRAL         0x0048
56 #define ADUCM360_FLASH_FEEADRAH         0x004C
57 #define ADUCM360_FLASH_FEEAEN0          0x0078
58 #define ADUCM360_FLASH_FEEAEN1          0x007C
59 #define ADUCM360_FLASH_FEEAEN2          0x0080
60
61 /* flash bank aducm360 0 0 0 0 <target#> */
62 FLASH_BANK_COMMAND_HANDLER(aducm360_flash_bank_command)
63 {
64         bank->base = 0x00000000;
65         bank->size = 0x00020000;
66
67         aducm360_build_sector_list(bank);
68
69         return ERROR_OK;
70 }
71
72 #define FLASH_SECTOR_SIZE       512
73
74 /* ----------------------------------------------------------------------- */
75 static int aducm360_build_sector_list(struct flash_bank *bank)
76 {
77         uint32_t offset = 0;
78
79         /* sector size is 512 */
80         bank->num_sectors = bank->size / FLASH_SECTOR_SIZE;
81         bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
82         for (unsigned i = 0; i < bank->num_sectors; ++i) {
83                 bank->sectors[i].offset = offset;
84                 bank->sectors[i].size = FLASH_SECTOR_SIZE;
85                 offset += bank->sectors[i].size;
86                 bank->sectors[i].is_erased = -1;
87                 bank->sectors[i].is_protected = 0;
88         }
89
90         return ERROR_OK;
91 }
92
93 /* ----------------------------------------------------------------------- */
94 static int aducm360_mass_erase(struct target *target)
95 {
96         uint32_t                value;
97         int                             res = ERROR_OK;
98
99         /* Clear any old status */
100         target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
101
102         /* Enable the writing to the flash*/
103         aducm360_set_write_enable(target, 1);
104
105         /* Unlock for writing */
106         target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456);
107         target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123);
108         /* Issue the 'MASSERASE' command */
109         target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000003);
110
111         /* Check the result */
112         res = aducm360_check_flash_completion(target, 3500);
113         if (res != ERROR_OK) {
114                 LOG_ERROR("mass erase failed.");
115                 aducm360_set_write_enable(target, 0);
116                 res = ERROR_FLASH_OPERATION_FAILED;
117         }
118
119         return res;
120 }
121
122 /* ----------------------------------------------------------------------- */
123 static int aducm360_page_erase(struct target *target, uint32_t padd)
124 {
125         uint32_t                value;
126         int                             res = ERROR_OK;
127
128         /* Clear any old status */
129         target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
130
131         /* Enable the writing to the flash*/
132         aducm360_set_write_enable(target, 1);
133
134         /* Unlock for writing */
135         target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456);
136         target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123);
137         /* Write the sector address */
138         target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0L, padd & 0xFFFF);
139         target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0H, (padd>>16) & 0xFFFF);
140         /* Issue the 'ERASEPAGE' command */
141         target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000001);
142
143         /* Check the result */
144         res = aducm360_check_flash_completion(target, 50);
145         if (res != ERROR_OK) {
146                 LOG_ERROR("page erase failed at 0x%08" PRIx32, padd);
147                 aducm360_set_write_enable(target, 0);
148                 res = ERROR_FLASH_OPERATION_FAILED;
149         }
150
151         return res;
152 }
153
154 /* ----------------------------------------------------------------------- */
155 static int aducm360_erase(struct flash_bank *bank, unsigned int first,
156                 unsigned int last)
157 {
158         int             res = ERROR_OK;
159         int             i;
160         int             count;
161         struct target   *target = bank->target;
162         uint32_t        padd;
163
164         if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) {
165                 res = aducm360_mass_erase(target);
166         } else {
167                 count = last - first + 1;
168                 for (i = 0; i < count; ++i) {
169                         padd = bank->base + ((first+i)*FLASH_SECTOR_SIZE);
170                         res = aducm360_page_erase(target, padd);
171                         if (res != ERROR_OK)
172                                 break;
173                 }
174         }
175
176         return res;
177 }
178
179 /* ----------------------------------------------------------------------- */
180 static int aducm360_write_block_sync(
181                 struct flash_bank *bank,
182                 const uint8_t *buffer,
183                 uint32_t offset,
184                 uint32_t count)
185 {
186         struct target           *target = bank->target;
187         uint32_t                target_buffer_size = 8192;
188         struct working_area     *helper;
189         struct working_area     *target_buffer;
190         uint32_t                address = bank->base + offset;
191         struct reg_param        reg_params[8];
192         int                     retval = ERROR_OK;
193         uint32_t                entry_point = 0, exit_point = 0;
194         uint32_t                res;
195         struct armv7m_algorithm armv7m_algo;
196
197         static const uint32_t aducm360_flash_write_code[] = {
198                         /* helper.code */
199                         0x88AF4D10, 0x0704F047, 0x682F80AF, 0x600E6806,
200                         0xF017882F, 0xF43F0F08, 0xF851AFFB, 0x42B77B04,
201                         0x800DF040, 0x0004F100, 0xF47F3A04, 0x686FAFEF,
202                         0x0704F027, 0xF04F80AF, 0xF0000400, 0xF04FB802,
203                         0xBE000480, 0x40002800, 0x00015000, 0x20000000,
204                         0x00013000
205         };
206
207         LOG_DEBUG("'aducm360_write_block_sync' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.",
208                         address, count);
209
210         /*  ----- Check the destination area for a Long Word alignment -----  */
211         if (((count%4) != 0) || ((offset%4) != 0)) {
212                 LOG_ERROR("write block must be multiple of four bytes in offset & length");
213                 return ERROR_FAIL;
214         }
215
216         /*  ----- Allocate space in the target's RAM for the helper code -----  */
217         if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code),
218                         &helper) != ERROR_OK) {
219                 LOG_WARNING("no working area available, can't do block memory writes");
220                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
221         }
222
223         /*  ----- Upload the helper code to the space in the target's RAM -----  */
224         uint8_t code[sizeof(aducm360_flash_write_code)];
225         target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code),
226                         aducm360_flash_write_code);
227         retval = target_write_buffer(target, helper->address, sizeof(code), code);
228         if (retval != ERROR_OK)
229                 return retval;
230         entry_point = helper->address;
231
232         /*  ----- Allocate space in the target's RAM for the user application's object code -----  */
233         while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) {
234                 LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.",
235                                 target_buffer_size);
236                 target_buffer_size /= 2;
237                 if (target_buffer_size <= 256) {                /* No room available */
238                         LOG_WARNING("no large enough working area available, can't do block memory writes");
239                         target_free_working_area(target, helper);
240                         return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
241                 }
242         }
243
244         /* ----- Prepare the target for the helper ----- */
245         armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
246         armv7m_algo.core_mode = ARM_MODE_THREAD;
247
248         init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /*SRC      */
249         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /*DST      */
250         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /*COUNT    */
251         init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /*not used */
252         init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);      /*RESULT   */
253
254         /*  ===== Execute the Main Programming Loop! ===== */
255         while (count > 0) {
256                 uint32_t thisrun_count = (count > target_buffer_size) ? target_buffer_size : count;
257
258                 /* ----- Upload the chunk ----- */
259                 retval = target_write_buffer(target, target_buffer->address, thisrun_count, buffer);
260                 if (retval != ERROR_OK)
261                         break;
262                 /* Set the arguments for the helper */
263                 buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address);        /*SRC     */
264                 buf_set_u32(reg_params[1].value, 0, 32, address);                                       /*DST     */
265                 buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);                         /*COUNT   */
266                 buf_set_u32(reg_params[3].value, 0, 32, 0);                                                     /*NOT USED*/
267
268                 retval = target_run_algorithm(target, 0, NULL, 5,
269                                 reg_params,     entry_point, exit_point, 10000, &armv7m_algo);
270                 if (retval != ERROR_OK) {
271                         LOG_ERROR("error executing aducm360 flash write algorithm");
272                         break;
273                 }
274
275                 res = buf_get_u32(reg_params[4].value, 0, 32);
276                 if (res) {
277                         LOG_ERROR("aducm360 fast sync algorithm reports an error (%02" PRIX32 ")", res);
278                         retval = ERROR_FAIL;
279                         break;
280                 }
281
282                 buffer += thisrun_count;
283                 address += thisrun_count;
284                 count -= thisrun_count;
285         }
286
287         target_free_working_area(target, target_buffer);
288         target_free_working_area(target, helper);
289
290         destroy_reg_param(&reg_params[0]);
291         destroy_reg_param(&reg_params[1]);
292         destroy_reg_param(&reg_params[2]);
293         destroy_reg_param(&reg_params[3]);
294         destroy_reg_param(&reg_params[4]);
295
296         return retval;
297 }
298
299 /* ----------------------------------------------------------------------- */
300 static int aducm360_write_block_async(
301                 struct flash_bank *bank,
302                 const uint8_t *buffer,
303                 uint32_t offset,
304                 uint32_t count)
305 {
306         struct target           *target = bank->target;
307         uint32_t                target_buffer_size = 1024;
308         struct working_area     *helper;
309         struct working_area     *target_buffer;
310         uint32_t                address = bank->base + offset;
311         struct reg_param        reg_params[9];
312         int                     retval = ERROR_OK;
313         uint32_t                entry_point = 0, exit_point = 0;
314         uint32_t                res;
315         uint32_t                wcount;
316         struct armv7m_algorithm armv7m_algo;
317
318         static const uint32_t aducm360_flash_write_code[] = {
319                         /* helper.code */
320                         0x4050F8DF,     0xF04588A5,     0x80A50504,     0x8000F8D0,
321                         0x0F00F1B8, 0x8016F000, 0x45476847,     0xAFF6F43F,
322                         0x6B04F857, 0x6B04F842, 0xF0158825,     0xF43F0F08,
323                         0x428FAFFB, 0xF100BF28, 0x60470708,     0xB10B3B01,
324                         0xBFE4F7FF, 0xF02588A5, 0x80A50504,     0x0900F04F,
325                         0xBE00BF00, 0x40002800, 0x20000000,     0x20000100,
326                         0x00013000
327         };
328
329         LOG_DEBUG("'aducm360_write_block_async' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.",
330                         address, count);
331
332         /*  ----- Check the destination area for a Long Word alignment -----  */
333         if (((count%4) != 0) || ((offset%4) != 0)) {
334                 LOG_ERROR("write block must be multiple of four bytes in offset & length");
335                 return ERROR_FAIL;
336         }
337         wcount = count/4;
338
339         /*  ----- Allocate space in the target's RAM for the helper code -----  */
340         if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code),
341                         &helper) != ERROR_OK) {
342                 LOG_WARNING("no working area available, can't do block memory writes");
343                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
344         }
345
346         /*  ----- Upload the helper code to the space in the target's RAM -----  */
347         uint8_t code[sizeof(aducm360_flash_write_code)];
348         target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code),
349                         aducm360_flash_write_code);
350         retval = target_write_buffer(target, helper->address, sizeof(code), code);
351         if (retval != ERROR_OK)
352                 return retval;
353         entry_point = helper->address;
354
355         /*  ----- Allocate space in the target's RAM for the user application's object code ----- */
356         while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) {
357                 LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.",
358                                 target_buffer_size);
359                 target_buffer_size /= 2;
360                 if (target_buffer_size <= 256) {                /* No room available */
361                         LOG_WARNING("no large enough working area available, can't do block memory writes");
362                         target_free_working_area(target, helper);
363                         return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
364                 }
365         }
366
367         /* ----- Prepare the target for the helper ----- */
368         armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
369         armv7m_algo.core_mode = ARM_MODE_THREAD;
370
371         init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /*SRCBEG     */
372         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /*SRCEND     */
373         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /*DST        */
374         init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /*COUNT (LWs)*/
375         init_reg_param(&reg_params[4], "r9", 32, PARAM_IN);  /*RESULT     */
376
377         buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address);
378         buf_set_u32(reg_params[1].value, 0, 32, target_buffer->address + target_buffer->size);
379         buf_set_u32(reg_params[2].value, 0, 32, address);
380         buf_set_u32(reg_params[3].value, 0, 32, wcount);
381
382         retval = target_run_flash_async_algorithm(target, buffer, wcount, 4,
383                         0, NULL,
384                         5, reg_params,
385                         target_buffer->address, target_buffer->size,
386                         entry_point, exit_point,
387                         &armv7m_algo);
388         if (retval != ERROR_OK) {
389                 LOG_ERROR("error executing aducm360 flash write algorithm");
390         } else {
391                 res = buf_get_u32(reg_params[4].value, 0, 32);  /*RESULT*/
392                 if (res) {
393                         LOG_ERROR("aducm360 fast async algorithm reports an error (%02" PRIX32 ")", res);
394                         retval = ERROR_FAIL;
395                 }
396         }
397
398         target_free_working_area(target, target_buffer);
399         target_free_working_area(target, helper);
400
401         destroy_reg_param(&reg_params[0]);
402         destroy_reg_param(&reg_params[1]);
403         destroy_reg_param(&reg_params[2]);
404         destroy_reg_param(&reg_params[3]);
405         destroy_reg_param(&reg_params[4]);
406
407         return retval;
408 }
409
410 /* ----------------------------------------------------------------------- */
411 /* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall
412  * back to another mechanism that does not require onboard RAM
413  *
414  * Caller should not check for other return values specifically
415  */
416 static int aducm360_write_block(struct flash_bank *bank,
417         const uint8_t *buffer,
418         uint32_t offset,
419         uint32_t count)
420 {
421         int     choice = 0;
422
423         switch (choice) {
424         case 0:
425                 return aducm360_write_block_sync(bank, buffer, offset, count);
426         case 1:
427                 return aducm360_write_block_async(bank, buffer, offset, count);
428         default:
429                 LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!");
430                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
431         }
432 }
433
434 /* ----------------------------------------------------------------------- */
435 #define FEESTA_WRDONE   0x00000008
436
437 static int aducm360_write_modified(struct flash_bank *bank,
438                 const uint8_t *buffer,
439                 uint32_t offset,
440                 uint32_t count)
441 {
442         uint32_t                value;
443         int                             res = ERROR_OK;
444         uint32_t        i, j, a, d;
445         struct target   *target = bank->target;
446
447         LOG_DEBUG("performing slow write (offset=0x%08" PRIx32 ", count=0x%08" PRIx32 ")...",
448                         offset, count);
449
450         /* Enable the writing to the flash */
451         aducm360_set_write_enable(target, 1);
452
453         /* Clear any old status */
454         target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
455
456         for (i = 0; i < count; i += 4) {
457                 a = offset+i;
458                 for (j = 0; i < 4; i += 1)
459                         *((uint8_t *)(&d) + j) = buffer[i+j];
460                 target_write_u32(target, a, d);
461                 do {
462                         target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
463                 } while (!(value & FEESTA_WRDONE));
464         }
465         aducm360_set_write_enable(target, 0);
466
467         return res;
468 }
469
470 /* ----------------------------------------------------------------------- */
471 static int aducm360_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
472 {
473         int retval;
474
475         /* try using a block write */
476         retval = aducm360_write_block(bank, buffer, offset, count);
477         if (retval != ERROR_OK) {
478                 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
479                         /* if block write failed (no sufficient working area),
480                          * use normal (slow) JTAG method */
481                         LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
482
483                         retval = aducm360_write_modified(bank, buffer, offset, count);
484                         if (retval != ERROR_OK) {
485                                 LOG_ERROR("slow write failed");
486                                 return ERROR_FLASH_OPERATION_FAILED;
487                         }
488                 }
489         }
490         return retval;
491 }
492
493 /* ----------------------------------------------------------------------- */
494 static int aducm360_probe(struct flash_bank *bank)
495 {
496         return ERROR_OK;
497 }
498
499 /* ----------------------------------------------------------------------- */
500 /* sets FEECON0 bit 2
501  * enable = 1 enables writes & erases, 0 disables them */
502 static int aducm360_set_write_enable(struct target *target, int enable)
503 {
504         /* don't bother to preserve int enable bit here */
505         uint32_t        value;
506
507         target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, &value);
508         if (enable)
509                 value |= 0x00000004;
510         else
511                 value &= ~0x00000004;
512         target_write_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, value);
513
514         return ERROR_OK;
515 }
516
517 /* ----------------------------------------------------------------------- */
518 /* wait up to timeout_ms for controller to not be busy,
519  * then check whether the command passed or failed.
520  *
521  * this function sleeps 1ms between checks (after the first one),
522  * so in some cases may slow things down without a usleep after the first read */
523 static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms)
524 {
525         uint32_t v = 1;
526
527         int64_t endtime = timeval_ms() + timeout_ms;
528         while (1) {
529                 target_read_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEESTA, &v);
530                 if ((v & 0x00000001) == 0)
531                         break;
532                 alive_sleep(1);
533                 if (timeval_ms() >= endtime)
534                         break;
535         }
536
537         if (!(v & 0x00000004))  /* b2 */
538                 return ERROR_FAIL;
539
540         return ERROR_OK;
541 }
542
543 /* ----------------------------------------------------------------------- */
544 const struct flash_driver aducm360_flash = {
545         .name = "aducm360",
546         .flash_bank_command = aducm360_flash_bank_command,
547         .erase = aducm360_erase,
548         .write = aducm360_write,
549         .read = default_flash_read,
550         .probe = aducm360_probe,
551         .auto_probe = aducm360_probe,
552         .erase_check = default_flash_blank_check,
553 };