Remove FSF address from GPL notices
[openocd.git] / src / flash / nor / aducm360.c
blob0f85254a86af887cf02c8aa778fc8373d1620f42
1 /***************************************************************************
2 * Copyright (C) 2015 by Ivan Buliev *
3 * i.buliev@mikrosistemi.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
19 /***************************************************************************
20 * This version for ADuCM360 is largely based on the following flash *
21 * drivers: *
22 * - aduc702x.c *
23 * Copyright (C) 2008 by Kevin McGuire *
24 * Copyright (C) 2008 by Marcel Wijlaars *
25 * Copyright (C) 2009 by Michael Ashton *
26 * and *
27 * - stm32f1x.c *
28 * Copyright (C) 2005 by Dominic Rath *
29 * Dominic.Rath@gmx.de *
30 * *
31 * Copyright (C) 2008 by Spencer Oliver *
32 * spen@spen-soft.co.uk *
33 * *
34 * Copyright (C) 2011 by Andreas Fritiofson *
35 * andreas.fritiofson@gmail.com *
36 ***************************************************************************/
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
42 #include "imp.h"
43 #include <helper/binarybuffer.h>
44 #include <helper/time_support.h>
45 #include <target/algorithm.h>
46 #include <target/armv7m.h>
48 static int aducm360_build_sector_list(struct flash_bank *bank);
49 static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms);
50 static int aducm360_set_write_enable(struct target *target, int enable);
52 #define ADUCM360_FLASH_BASE 0x40002800
53 #define ADUCM360_FLASH_FEESTA 0x0000
54 #define ADUCM360_FLASH_FEECON0 0x0004
55 #define ADUCM360_FLASH_FEECMD 0x0008
56 #define ADUCM360_FLASH_FEEADR0L 0x0010
57 #define ADUCM360_FLASH_FEEADR0H 0x0014
58 #define ADUCM360_FLASH_FEEADR1L 0x0018
59 #define ADUCM360_FLASH_FEEADR1H 0x001C
60 #define ADUCM360_FLASH_FEEKEY 0x0020
61 #define ADUCM360_FLASH_FEEPROL 0x0028
62 #define ADUCM360_FLASH_FEEPROH 0x002C
63 #define ADUCM360_FLASH_FEESIGL 0x0030
64 #define ADUCM360_FLASH_FEESIGH 0x0034
65 #define ADUCM360_FLASH_FEECON1 0x0038
66 #define ADUCM360_FLASH_FEEADRAL 0x0048
67 #define ADUCM360_FLASH_FEEADRAH 0x004C
68 #define ADUCM360_FLASH_FEEAEN0 0x0078
69 #define ADUCM360_FLASH_FEEAEN1 0x007C
70 #define ADUCM360_FLASH_FEEAEN2 0x0080
72 /* flash bank aducm360 0 0 0 0 <target#> */
73 FLASH_BANK_COMMAND_HANDLER(aducm360_flash_bank_command)
75 bank->base = 0x00000000;
76 bank->size = 0x00020000;
78 aducm360_build_sector_list(bank);
80 return ERROR_OK;
83 #define FLASH_SECTOR_SIZE 512
85 /* ----------------------------------------------------------------------- */
86 static int aducm360_build_sector_list(struct flash_bank *bank)
88 int i = 0;
89 uint32_t offset = 0;
91 /* sector size is 512 */
92 bank->num_sectors = bank->size / FLASH_SECTOR_SIZE;
93 bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
94 for (i = 0; i < bank->num_sectors; ++i) {
95 bank->sectors[i].offset = offset;
96 bank->sectors[i].size = FLASH_SECTOR_SIZE;
97 offset += bank->sectors[i].size;
98 bank->sectors[i].is_erased = -1;
99 bank->sectors[i].is_protected = 0;
102 return ERROR_OK;
105 /* ----------------------------------------------------------------------- */
106 static int aducm360_protect_check(struct flash_bank *bank)
108 LOG_WARNING("aducm360_protect_check not implemented.");
109 return ERROR_OK;
112 /* ----------------------------------------------------------------------- */
113 static int aducm360_mass_erase(struct target *target)
115 uint32_t value;
116 int res = ERROR_OK;
118 /* Clear any old status */
119 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
121 /* Enable the writing to the flash*/
122 aducm360_set_write_enable(target, 1);
124 /* Unlock for writing */
125 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456);
126 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123);
127 /* Issue the 'MASSERASE' command */
128 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000003);
130 /* Check the result */
131 res = aducm360_check_flash_completion(target, 3500);
132 if (res != ERROR_OK) {
133 LOG_ERROR("mass erase failed.");
134 aducm360_set_write_enable(target, 0);
135 res = ERROR_FLASH_OPERATION_FAILED;
138 return res;
141 /* ----------------------------------------------------------------------- */
142 static int aducm360_page_erase(struct target *target, uint32_t padd)
144 uint32_t value;
145 int res = ERROR_OK;
147 /* Clear any old status */
148 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
150 /* Enable the writing to the flash*/
151 aducm360_set_write_enable(target, 1);
153 /* Unlock for writing */
154 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456);
155 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123);
156 /* Write the sector address */
157 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0L, padd & 0xFFFF);
158 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0H, (padd>>16) & 0xFFFF);
159 /* Issue the 'ERASEPAGE' command */
160 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000001);
162 /* Check the result */
163 res = aducm360_check_flash_completion(target, 50);
164 if (res != ERROR_OK) {
165 LOG_ERROR("page erase failed at 0x%08" PRIx32, padd);
166 aducm360_set_write_enable(target, 0);
167 res = ERROR_FLASH_OPERATION_FAILED;
170 return res;
173 /* ----------------------------------------------------------------------- */
174 static int aducm360_erase(struct flash_bank *bank, int first, int last)
176 int res = ERROR_OK;
177 int i;
178 int count;
179 struct target *target = bank->target;
180 uint32_t padd;
182 if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) {
183 res = aducm360_mass_erase(target);
184 } else {
185 count = last - first + 1;
186 for (i = 0; i < count; ++i) {
187 padd = bank->base + ((first+i)*FLASH_SECTOR_SIZE);
188 res = aducm360_page_erase(target, padd);
189 if (res != ERROR_OK)
190 break;
194 return res;
197 /* ----------------------------------------------------------------------- */
198 static int aducm360_protect(struct flash_bank *bank, int set, int first, int last)
200 LOG_ERROR("aducm360_protect not implemented.");
201 return ERROR_FLASH_OPERATION_FAILED;
204 /* ----------------------------------------------------------------------- */
205 static int aducm360_write_block_sync(
206 struct flash_bank *bank,
207 const uint8_t *buffer,
208 uint32_t offset,
209 uint32_t count)
211 struct target *target = bank->target;
212 uint32_t target_buffer_size = 8192;
213 struct working_area *helper;
214 struct working_area *target_buffer;
215 uint32_t address = bank->base + offset;
216 struct reg_param reg_params[8];
217 int retval = ERROR_OK;
218 uint32_t entry_point = 0, exit_point = 0;
219 uint32_t res;
220 struct armv7m_algorithm armv7m_algo;
222 static const uint32_t aducm360_flash_write_code[] = {
223 /* helper.code */
224 0x88AF4D10, 0x0704F047, 0x682F80AF, 0x600E6806,
225 0xF017882F, 0xF43F0F08, 0xF851AFFB, 0x42B77B04,
226 0x800DF040, 0x0004F100, 0xF47F3A04, 0x686FAFEF,
227 0x0704F027, 0xF04F80AF, 0xF0000400, 0xF04FB802,
228 0xBE000480, 0x40002800, 0x00015000, 0x20000000,
229 0x00013000
232 LOG_DEBUG("'aducm360_write_block_sync' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.",
233 address, count);
235 /* ----- Check the destination area for a Long Word alignment ----- */
236 if (((count%4) != 0) || ((offset%4) != 0)) {
237 LOG_ERROR("write block must be multiple of four bytes in offset & length");
238 return ERROR_FAIL;
241 /* ----- Allocate space in the target's RAM for the helper code ----- */
242 if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code),
243 &helper) != ERROR_OK) {
244 LOG_WARNING("no working area available, can't do block memory writes");
245 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
248 /* ----- Upload the helper code to the space in the target's RAM ----- */
249 uint8_t code[sizeof(aducm360_flash_write_code)];
250 target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code),
251 aducm360_flash_write_code);
252 retval = target_write_buffer(target, helper->address, sizeof(code), code);
253 if (retval != ERROR_OK)
254 return retval;
255 entry_point = helper->address;
257 /* ----- Allocate space in the target's RAM for the user application's object code ----- */
258 while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) {
259 LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.",
260 target_buffer_size);
261 target_buffer_size /= 2;
262 if (target_buffer_size <= 256) { /* No room available */
263 LOG_WARNING("no large enough working area available, can't do block memory writes");
264 target_free_working_area(target, helper);
265 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
269 /* ----- Prepare the target for the helper ----- */
270 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
271 armv7m_algo.core_mode = ARM_MODE_THREAD;
273 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /*SRC */
274 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /*DST */
275 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /*COUNT */
276 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /*not used */
277 init_reg_param(&reg_params[4], "r4", 32, PARAM_IN); /*RESULT */
279 /* ===== Execute the Main Programming Loop! ===== */
280 while (count > 0) {
281 uint32_t thisrun_count = (count > target_buffer_size) ? target_buffer_size : count;
283 /* ----- Upload the chunk ----- */
284 retval = target_write_buffer(target, target_buffer->address, thisrun_count, buffer);
285 if (retval != ERROR_OK)
286 break;
287 /* Set the arguments for the helper */
288 buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address); /*SRC */
289 buf_set_u32(reg_params[1].value, 0, 32, address); /*DST */
290 buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); /*COUNT */
291 buf_set_u32(reg_params[3].value, 0, 32, 0); /*NOT USED*/
293 retval = target_run_algorithm(target, 0, NULL, 5,
294 reg_params, entry_point, exit_point, 10000, &armv7m_algo);
295 if (retval != ERROR_OK) {
296 LOG_ERROR("error executing aducm360 flash write algorithm");
297 break;
300 res = buf_get_u32(reg_params[4].value, 0, 32);
301 if (res) {
302 LOG_ERROR("aducm360 fast sync algorithm reports an error (%02X)", res);
303 retval = ERROR_FAIL;
304 break;
307 buffer += thisrun_count;
308 address += thisrun_count;
309 count -= thisrun_count;
312 target_free_working_area(target, target_buffer);
313 target_free_working_area(target, helper);
315 destroy_reg_param(&reg_params[0]);
316 destroy_reg_param(&reg_params[1]);
317 destroy_reg_param(&reg_params[2]);
318 destroy_reg_param(&reg_params[3]);
319 destroy_reg_param(&reg_params[4]);
321 return retval;
324 /* ----------------------------------------------------------------------- */
325 static int aducm360_write_block_async(
326 struct flash_bank *bank,
327 const uint8_t *buffer,
328 uint32_t offset,
329 uint32_t count)
331 struct target *target = bank->target;
332 uint32_t target_buffer_size = 1024;
333 struct working_area *helper;
334 struct working_area *target_buffer;
335 uint32_t address = bank->base + offset;
336 struct reg_param reg_params[9];
337 int retval = ERROR_OK;
338 uint32_t entry_point = 0, exit_point = 0;
339 uint32_t res;
340 uint32_t wcount;
341 struct armv7m_algorithm armv7m_algo;
343 static const uint32_t aducm360_flash_write_code[] = {
344 /* helper.code */
345 0x4050F8DF, 0xF04588A5, 0x80A50504, 0x8000F8D0,
346 0x0F00F1B8, 0x8016F000, 0x45476847, 0xAFF6F43F,
347 0x6B04F857, 0x6B04F842, 0xF0158825, 0xF43F0F08,
348 0x428FAFFB, 0xF100BF28, 0x60470708, 0xB10B3B01,
349 0xBFE4F7FF, 0xF02588A5, 0x80A50504, 0x0900F04F,
350 0xBE00BF00, 0x40002800, 0x20000000, 0x20000100,
351 0x00013000
354 LOG_DEBUG("'aducm360_write_block_async' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.",
355 address, count);
357 /* ----- Check the destination area for a Long Word alignment ----- */
358 if (((count%4) != 0) || ((offset%4) != 0)) {
359 LOG_ERROR("write block must be multiple of four bytes in offset & length");
360 return ERROR_FAIL;
362 wcount = count/4;
364 /* ----- Allocate space in the target's RAM for the helper code ----- */
365 if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code),
366 &helper) != ERROR_OK) {
367 LOG_WARNING("no working area available, can't do block memory writes");
368 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
371 /* ----- Upload the helper code to the space in the target's RAM ----- */
372 uint8_t code[sizeof(aducm360_flash_write_code)];
373 target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code),
374 aducm360_flash_write_code);
375 retval = target_write_buffer(target, helper->address, sizeof(code), code);
376 if (retval != ERROR_OK)
377 return retval;
378 entry_point = helper->address;
380 /* ----- Allocate space in the target's RAM for the user application's object code ----- */
381 while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) {
382 LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.",
383 target_buffer_size);
384 target_buffer_size /= 2;
385 if (target_buffer_size <= 256) { /* No room available */
386 LOG_WARNING("no large enough working area available, can't do block memory writes");
387 target_free_working_area(target, helper);
388 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
392 /* ----- Prepare the target for the helper ----- */
393 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
394 armv7m_algo.core_mode = ARM_MODE_THREAD;
396 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /*SRCBEG */
397 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /*SRCEND */
398 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /*DST */
399 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /*COUNT (LWs)*/
400 init_reg_param(&reg_params[4], "r9", 32, PARAM_IN); /*RESULT */
402 buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address);
403 buf_set_u32(reg_params[1].value, 0, 32, target_buffer->address + target_buffer->size);
404 buf_set_u32(reg_params[2].value, 0, 32, address);
405 buf_set_u32(reg_params[3].value, 0, 32, wcount);
407 retval = target_run_flash_async_algorithm(target, buffer, wcount, 4,
408 0, NULL,
409 5, reg_params,
410 target_buffer->address, target_buffer->size,
411 entry_point, exit_point,
412 &armv7m_algo);
413 if (retval != ERROR_OK) {
414 LOG_ERROR("error executing aducm360 flash write algorithm");
415 } else {
416 res = buf_get_u32(reg_params[4].value, 0, 32); /*RESULT*/
417 if (res) {
418 LOG_ERROR("aducm360 fast async algorithm reports an error (%02X)", res);
419 retval = ERROR_FAIL;
423 target_free_working_area(target, target_buffer);
424 target_free_working_area(target, helper);
426 destroy_reg_param(&reg_params[0]);
427 destroy_reg_param(&reg_params[1]);
428 destroy_reg_param(&reg_params[2]);
429 destroy_reg_param(&reg_params[3]);
430 destroy_reg_param(&reg_params[4]);
432 return retval;
435 /* ----------------------------------------------------------------------- */
436 /* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall
437 * back to another mechanism that does not require onboard RAM
439 * Caller should not check for other return values specifically
441 static int aducm360_write_block(struct flash_bank *bank,
442 const uint8_t *buffer,
443 uint32_t offset,
444 uint32_t count)
446 int choice = 0;
448 switch (choice) {
449 case 0:
450 return aducm360_write_block_sync(bank, buffer, offset, count);
451 break;
452 case 1:
453 return aducm360_write_block_async(bank, buffer, offset, count);
454 break;
455 default:
456 LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!");
457 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
461 /* ----------------------------------------------------------------------- */
462 #define FEESTA_WRDONE 0x00000008
464 static int aducm360_write_modified(struct flash_bank *bank,
465 const uint8_t *buffer,
466 uint32_t offset,
467 uint32_t count)
469 uint32_t value;
470 int res = ERROR_OK;
471 uint32_t i, j, a, d;
472 struct target *target = bank->target;
474 LOG_DEBUG("performing slow write (offset=0x%08" PRIx32 ", count=0x%08" PRIx32 ")...",
475 offset, count);
477 /* Enable the writing to the flash */
478 aducm360_set_write_enable(target, 1);
480 /* Clear any old status */
481 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
483 for (i = 0; i < count; i += 4) {
484 a = offset+i;
485 for (j = 0; i < 4; i += 1)
486 *((uint8_t *)(&d) + j) = buffer[i+j];
487 target_write_u32(target, a, d);
488 do {
489 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
490 } while (!(value & FEESTA_WRDONE));
492 aducm360_set_write_enable(target, 0);
494 return res;
497 /* ----------------------------------------------------------------------- */
498 static int aducm360_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
500 int retval;
502 /* try using a block write */
503 retval = aducm360_write_block(bank, buffer, offset, count);
504 if (retval != ERROR_OK) {
505 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
506 /* if block write failed (no sufficient working area),
507 * use normal (slow) JTAG method */
508 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
510 retval = aducm360_write_modified(bank, buffer, offset, count);
511 if (retval != ERROR_OK) {
512 LOG_ERROR("slow write failed");
513 return ERROR_FLASH_OPERATION_FAILED;
517 return retval;
520 /* ----------------------------------------------------------------------- */
521 static int aducm360_probe(struct flash_bank *bank)
523 return ERROR_OK;
526 /* ----------------------------------------------------------------------- */
527 /* sets FEECON0 bit 2
528 * enable = 1 enables writes & erases, 0 disables them */
529 static int aducm360_set_write_enable(struct target *target, int enable)
531 /* don't bother to preserve int enable bit here */
532 uint32_t value;
534 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, &value);
535 if (enable)
536 value |= 0x00000004;
537 else
538 value &= ~0x00000004;
539 target_write_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, value);
541 return ERROR_OK;
544 /* ----------------------------------------------------------------------- */
545 /* wait up to timeout_ms for controller to not be busy,
546 * then check whether the command passed or failed.
548 * this function sleeps 1ms between checks (after the first one),
549 * so in some cases may slow things down without a usleep after the first read */
550 static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms)
552 uint32_t v = 1;
554 long long endtime = timeval_ms() + timeout_ms;
555 while (1) {
556 target_read_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEESTA, &v);
557 if ((v & 0x00000001) == 0)
558 break;
559 alive_sleep(1);
560 if (timeval_ms() >= endtime)
561 break;
564 if (!(v & 0x00000004)) /* b2 */
565 return ERROR_FAIL;
567 return ERROR_OK;
570 /* ----------------------------------------------------------------------- */
571 struct flash_driver aducm360_flash = {
572 .name = "aducm360",
573 .flash_bank_command = aducm360_flash_bank_command,
574 .erase = aducm360_erase,
575 .protect = aducm360_protect,
576 .write = aducm360_write,
577 .read = default_flash_read,
578 .probe = aducm360_probe,
579 .auto_probe = aducm360_probe,
580 .erase_check = default_flash_blank_check,
581 .protect_check = aducm360_protect_check,