1 /***************************************************************************
2 * Copyright (C) 2015 by Ivan Buliev *
3 * i.buliev@mikrosistemi.com *
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. *
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. *
15 ***************************************************************************/
17 /***************************************************************************
18 * This version for ADuCM360 is largely based on the following flash *
21 * Copyright (C) 2008 by Kevin McGuire *
22 * Copyright (C) 2008 by Marcel Wijlaars *
23 * Copyright (C) 2009 by Michael Ashton *
26 * Copyright (C) 2005 by Dominic Rath *
27 * Dominic.Rath@gmx.de *
29 * Copyright (C) 2008 by Spencer Oliver *
30 * spen@spen-soft.co.uk *
32 * Copyright (C) 2011 by Andreas Fritiofson *
33 * andreas.fritiofson@gmail.com *
34 ***************************************************************************/
41 #include <helper/binarybuffer.h>
42 #include <helper/time_support.h>
43 #include <target/algorithm.h>
44 #include <target/armv7m.h>
46 static int aducm360_build_sector_list(struct flash_bank *bank);
47 static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms);
48 static int aducm360_set_write_enable(struct target *target, int enable);
50 #define ADUCM360_FLASH_BASE 0x40002800
51 #define ADUCM360_FLASH_FEESTA 0x0000
52 #define ADUCM360_FLASH_FEECON0 0x0004
53 #define ADUCM360_FLASH_FEECMD 0x0008
54 #define ADUCM360_FLASH_FEEADR0L 0x0010
55 #define ADUCM360_FLASH_FEEADR0H 0x0014
56 #define ADUCM360_FLASH_FEEADR1L 0x0018
57 #define ADUCM360_FLASH_FEEADR1H 0x001C
58 #define ADUCM360_FLASH_FEEKEY 0x0020
59 #define ADUCM360_FLASH_FEEPROL 0x0028
60 #define ADUCM360_FLASH_FEEPROH 0x002C
61 #define ADUCM360_FLASH_FEESIGL 0x0030
62 #define ADUCM360_FLASH_FEESIGH 0x0034
63 #define ADUCM360_FLASH_FEECON1 0x0038
64 #define ADUCM360_FLASH_FEEADRAL 0x0048
65 #define ADUCM360_FLASH_FEEADRAH 0x004C
66 #define ADUCM360_FLASH_FEEAEN0 0x0078
67 #define ADUCM360_FLASH_FEEAEN1 0x007C
68 #define ADUCM360_FLASH_FEEAEN2 0x0080
70 /* flash bank aducm360 0 0 0 0 <target#> */
71 FLASH_BANK_COMMAND_HANDLER(aducm360_flash_bank_command)
73 bank->base = 0x00000000;
74 bank->size = 0x00020000;
76 aducm360_build_sector_list(bank);
81 #define FLASH_SECTOR_SIZE 512
83 /* ----------------------------------------------------------------------- */
84 static int aducm360_build_sector_list(struct flash_bank *bank)
89 /* sector size is 512 */
90 bank->num_sectors = bank->size / FLASH_SECTOR_SIZE;
91 bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
92 for (i = 0; i < bank->num_sectors; ++i) {
93 bank->sectors[i].offset = offset;
94 bank->sectors[i].size = FLASH_SECTOR_SIZE;
95 offset += bank->sectors[i].size;
96 bank->sectors[i].is_erased = -1;
97 bank->sectors[i].is_protected = 0;
103 /* ----------------------------------------------------------------------- */
104 static int aducm360_protect_check(struct flash_bank *bank)
106 LOG_WARNING("aducm360_protect_check not implemented.");
110 /* ----------------------------------------------------------------------- */
111 static int aducm360_mass_erase(struct target *target)
116 /* Clear any old status */
117 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
119 /* Enable the writing to the flash*/
120 aducm360_set_write_enable(target, 1);
122 /* Unlock for writing */
123 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456);
124 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123);
125 /* Issue the 'MASSERASE' command */
126 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000003);
128 /* Check the result */
129 res = aducm360_check_flash_completion(target, 3500);
130 if (res != ERROR_OK) {
131 LOG_ERROR("mass erase failed.");
132 aducm360_set_write_enable(target, 0);
133 res = ERROR_FLASH_OPERATION_FAILED;
139 /* ----------------------------------------------------------------------- */
140 static int aducm360_page_erase(struct target *target, uint32_t padd)
145 /* Clear any old status */
146 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
148 /* Enable the writing to the flash*/
149 aducm360_set_write_enable(target, 1);
151 /* Unlock for writing */
152 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456);
153 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123);
154 /* Write the sector address */
155 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0L, padd & 0xFFFF);
156 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0H, (padd>>16) & 0xFFFF);
157 /* Issue the 'ERASEPAGE' command */
158 target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000001);
160 /* Check the result */
161 res = aducm360_check_flash_completion(target, 50);
162 if (res != ERROR_OK) {
163 LOG_ERROR("page erase failed at 0x%08" PRIx32, padd);
164 aducm360_set_write_enable(target, 0);
165 res = ERROR_FLASH_OPERATION_FAILED;
171 /* ----------------------------------------------------------------------- */
172 static int aducm360_erase(struct flash_bank *bank, int first, int last)
177 struct target *target = bank->target;
180 if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) {
181 res = aducm360_mass_erase(target);
183 count = last - first + 1;
184 for (i = 0; i < count; ++i) {
185 padd = bank->base + ((first+i)*FLASH_SECTOR_SIZE);
186 res = aducm360_page_erase(target, padd);
195 /* ----------------------------------------------------------------------- */
196 static int aducm360_protect(struct flash_bank *bank, int set, int first, int last)
198 LOG_ERROR("aducm360_protect not implemented.");
199 return ERROR_FLASH_OPERATION_FAILED;
202 /* ----------------------------------------------------------------------- */
203 static int aducm360_write_block_sync(
204 struct flash_bank *bank,
205 const uint8_t *buffer,
209 struct target *target = bank->target;
210 uint32_t target_buffer_size = 8192;
211 struct working_area *helper;
212 struct working_area *target_buffer;
213 uint32_t address = bank->base + offset;
214 struct reg_param reg_params[8];
215 int retval = ERROR_OK;
216 uint32_t entry_point = 0, exit_point = 0;
218 struct armv7m_algorithm armv7m_algo;
220 static const uint32_t aducm360_flash_write_code[] = {
222 0x88AF4D10, 0x0704F047, 0x682F80AF, 0x600E6806,
223 0xF017882F, 0xF43F0F08, 0xF851AFFB, 0x42B77B04,
224 0x800DF040, 0x0004F100, 0xF47F3A04, 0x686FAFEF,
225 0x0704F027, 0xF04F80AF, 0xF0000400, 0xF04FB802,
226 0xBE000480, 0x40002800, 0x00015000, 0x20000000,
230 LOG_DEBUG("'aducm360_write_block_sync' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.",
233 /* ----- Check the destination area for a Long Word alignment ----- */
234 if (((count%4) != 0) || ((offset%4) != 0)) {
235 LOG_ERROR("write block must be multiple of four bytes in offset & length");
239 /* ----- Allocate space in the target's RAM for the helper code ----- */
240 if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code),
241 &helper) != ERROR_OK) {
242 LOG_WARNING("no working area available, can't do block memory writes");
243 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
246 /* ----- Upload the helper code to the space in the target's RAM ----- */
247 uint8_t code[sizeof(aducm360_flash_write_code)];
248 target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code),
249 aducm360_flash_write_code);
250 retval = target_write_buffer(target, helper->address, sizeof(code), code);
251 if (retval != ERROR_OK)
253 entry_point = helper->address;
255 /* ----- Allocate space in the target's RAM for the user application's object code ----- */
256 while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) {
257 LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.",
259 target_buffer_size /= 2;
260 if (target_buffer_size <= 256) { /* No room available */
261 LOG_WARNING("no large enough working area available, can't do block memory writes");
262 target_free_working_area(target, helper);
263 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
267 /* ----- Prepare the target for the helper ----- */
268 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
269 armv7m_algo.core_mode = ARM_MODE_THREAD;
271 init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /*SRC */
272 init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /*DST */
273 init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /*COUNT */
274 init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /*not used */
275 init_reg_param(®_params[4], "r4", 32, PARAM_IN); /*RESULT */
277 /* ===== Execute the Main Programming Loop! ===== */
279 uint32_t thisrun_count = (count > target_buffer_size) ? target_buffer_size : count;
281 /* ----- Upload the chunk ----- */
282 retval = target_write_buffer(target, target_buffer->address, thisrun_count, buffer);
283 if (retval != ERROR_OK)
285 /* Set the arguments for the helper */
286 buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address); /*SRC */
287 buf_set_u32(reg_params[1].value, 0, 32, address); /*DST */
288 buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); /*COUNT */
289 buf_set_u32(reg_params[3].value, 0, 32, 0); /*NOT USED*/
291 retval = target_run_algorithm(target, 0, NULL, 5,
292 reg_params, entry_point, exit_point, 10000, &armv7m_algo);
293 if (retval != ERROR_OK) {
294 LOG_ERROR("error executing aducm360 flash write algorithm");
298 res = buf_get_u32(reg_params[4].value, 0, 32);
300 LOG_ERROR("aducm360 fast sync algorithm reports an error (%02X)", res);
305 buffer += thisrun_count;
306 address += thisrun_count;
307 count -= thisrun_count;
310 target_free_working_area(target, target_buffer);
311 target_free_working_area(target, helper);
313 destroy_reg_param(®_params[0]);
314 destroy_reg_param(®_params[1]);
315 destroy_reg_param(®_params[2]);
316 destroy_reg_param(®_params[3]);
317 destroy_reg_param(®_params[4]);
322 /* ----------------------------------------------------------------------- */
323 static int aducm360_write_block_async(
324 struct flash_bank *bank,
325 const uint8_t *buffer,
329 struct target *target = bank->target;
330 uint32_t target_buffer_size = 1024;
331 struct working_area *helper;
332 struct working_area *target_buffer;
333 uint32_t address = bank->base + offset;
334 struct reg_param reg_params[9];
335 int retval = ERROR_OK;
336 uint32_t entry_point = 0, exit_point = 0;
339 struct armv7m_algorithm armv7m_algo;
341 static const uint32_t aducm360_flash_write_code[] = {
343 0x4050F8DF, 0xF04588A5, 0x80A50504, 0x8000F8D0,
344 0x0F00F1B8, 0x8016F000, 0x45476847, 0xAFF6F43F,
345 0x6B04F857, 0x6B04F842, 0xF0158825, 0xF43F0F08,
346 0x428FAFFB, 0xF100BF28, 0x60470708, 0xB10B3B01,
347 0xBFE4F7FF, 0xF02588A5, 0x80A50504, 0x0900F04F,
348 0xBE00BF00, 0x40002800, 0x20000000, 0x20000100,
352 LOG_DEBUG("'aducm360_write_block_async' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.",
355 /* ----- Check the destination area for a Long Word alignment ----- */
356 if (((count%4) != 0) || ((offset%4) != 0)) {
357 LOG_ERROR("write block must be multiple of four bytes in offset & length");
362 /* ----- Allocate space in the target's RAM for the helper code ----- */
363 if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code),
364 &helper) != ERROR_OK) {
365 LOG_WARNING("no working area available, can't do block memory writes");
366 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
369 /* ----- Upload the helper code to the space in the target's RAM ----- */
370 uint8_t code[sizeof(aducm360_flash_write_code)];
371 target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code),
372 aducm360_flash_write_code);
373 retval = target_write_buffer(target, helper->address, sizeof(code), code);
374 if (retval != ERROR_OK)
376 entry_point = helper->address;
378 /* ----- Allocate space in the target's RAM for the user application's object code ----- */
379 while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) {
380 LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.",
382 target_buffer_size /= 2;
383 if (target_buffer_size <= 256) { /* No room available */
384 LOG_WARNING("no large enough working area available, can't do block memory writes");
385 target_free_working_area(target, helper);
386 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
390 /* ----- Prepare the target for the helper ----- */
391 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
392 armv7m_algo.core_mode = ARM_MODE_THREAD;
394 init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /*SRCBEG */
395 init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /*SRCEND */
396 init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /*DST */
397 init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /*COUNT (LWs)*/
398 init_reg_param(®_params[4], "r9", 32, PARAM_IN); /*RESULT */
400 buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address);
401 buf_set_u32(reg_params[1].value, 0, 32, target_buffer->address + target_buffer->size);
402 buf_set_u32(reg_params[2].value, 0, 32, address);
403 buf_set_u32(reg_params[3].value, 0, 32, wcount);
405 retval = target_run_flash_async_algorithm(target, buffer, wcount, 4,
408 target_buffer->address, target_buffer->size,
409 entry_point, exit_point,
411 if (retval != ERROR_OK) {
412 LOG_ERROR("error executing aducm360 flash write algorithm");
414 res = buf_get_u32(reg_params[4].value, 0, 32); /*RESULT*/
416 LOG_ERROR("aducm360 fast async algorithm reports an error (%02X)", res);
421 target_free_working_area(target, target_buffer);
422 target_free_working_area(target, helper);
424 destroy_reg_param(®_params[0]);
425 destroy_reg_param(®_params[1]);
426 destroy_reg_param(®_params[2]);
427 destroy_reg_param(®_params[3]);
428 destroy_reg_param(®_params[4]);
433 /* ----------------------------------------------------------------------- */
434 /* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall
435 * back to another mechanism that does not require onboard RAM
437 * Caller should not check for other return values specifically
439 static int aducm360_write_block(struct flash_bank *bank,
440 const uint8_t *buffer,
448 return aducm360_write_block_sync(bank, buffer, offset, count);
451 return aducm360_write_block_async(bank, buffer, offset, count);
454 LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!");
455 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
459 /* ----------------------------------------------------------------------- */
460 #define FEESTA_WRDONE 0x00000008
462 static int aducm360_write_modified(struct flash_bank *bank,
463 const uint8_t *buffer,
470 struct target *target = bank->target;
472 LOG_DEBUG("performing slow write (offset=0x%08" PRIx32 ", count=0x%08" PRIx32 ")...",
475 /* Enable the writing to the flash */
476 aducm360_set_write_enable(target, 1);
478 /* Clear any old status */
479 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
481 for (i = 0; i < count; i += 4) {
483 for (j = 0; i < 4; i += 1)
484 *((uint8_t *)(&d) + j) = buffer[i+j];
485 target_write_u32(target, a, d);
487 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value);
488 } while (!(value & FEESTA_WRDONE));
490 aducm360_set_write_enable(target, 0);
495 /* ----------------------------------------------------------------------- */
496 static int aducm360_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
500 /* try using a block write */
501 retval = aducm360_write_block(bank, buffer, offset, count);
502 if (retval != ERROR_OK) {
503 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
504 /* if block write failed (no sufficient working area),
505 * use normal (slow) JTAG method */
506 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
508 retval = aducm360_write_modified(bank, buffer, offset, count);
509 if (retval != ERROR_OK) {
510 LOG_ERROR("slow write failed");
511 return ERROR_FLASH_OPERATION_FAILED;
518 /* ----------------------------------------------------------------------- */
519 static int aducm360_probe(struct flash_bank *bank)
524 /* ----------------------------------------------------------------------- */
525 /* sets FEECON0 bit 2
526 * enable = 1 enables writes & erases, 0 disables them */
527 static int aducm360_set_write_enable(struct target *target, int enable)
529 /* don't bother to preserve int enable bit here */
532 target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, &value);
536 value &= ~0x00000004;
537 target_write_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, value);
542 /* ----------------------------------------------------------------------- */
543 /* wait up to timeout_ms for controller to not be busy,
544 * then check whether the command passed or failed.
546 * this function sleeps 1ms between checks (after the first one),
547 * so in some cases may slow things down without a usleep after the first read */
548 static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms)
552 long long endtime = timeval_ms() + timeout_ms;
554 target_read_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEESTA, &v);
555 if ((v & 0x00000001) == 0)
558 if (timeval_ms() >= endtime)
562 if (!(v & 0x00000004)) /* b2 */
568 /* ----------------------------------------------------------------------- */
569 struct flash_driver aducm360_flash = {
571 .flash_bank_command = aducm360_flash_bank_command,
572 .erase = aducm360_erase,
573 .protect = aducm360_protect,
574 .write = aducm360_write,
575 .read = default_flash_read,
576 .probe = aducm360_probe,
577 .auto_probe = aducm360_probe,
578 .erase_check = default_flash_blank_check,
579 .protect_check = aducm360_protect_check,