1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius *
6 * didele.deze@gmail.com *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
30 #include <helper/binarybuffer.h>
31 #include <target/algorithm.h>
32 #include <target/armv7m.h>
35 /* flash programming support for NXP LPC17xx and LPC2xxx devices
36 * currently supported devices:
37 * variant 1 (lpc2000_v1):
45 * variant 2 (lpc2000_v2):
54 * - 176x (tested with LPC1768)
57 static int lpc2000_build_sector_list(struct flash_bank
*bank
)
59 struct lpc2000_flash_bank
*lpc2000_info
= bank
->driver_priv
;
63 /* default to a 4096 write buffer */
64 lpc2000_info
->cmd51_max_buffer
= 4096;
66 if (lpc2000_info
->variant
== lpc2000_v1
)
68 /* variant 1 has different layout for 128kb and 256kb flashes */
69 if (bank
->size
== 128 * 1024)
71 bank
->num_sectors
= 16;
72 bank
->sectors
= malloc(sizeof(struct flash_sector
) * 16);
73 for (i
= 0; i
< 16; i
++)
75 bank
->sectors
[i
].offset
= offset
;
76 bank
->sectors
[i
].size
= 8 * 1024;
77 offset
+= bank
->sectors
[i
].size
;
78 bank
->sectors
[i
].is_erased
= -1;
79 bank
->sectors
[i
].is_protected
= 1;
82 else if (bank
->size
== 256 * 1024)
84 bank
->num_sectors
= 18;
85 bank
->sectors
= malloc(sizeof(struct flash_sector
) * 18);
87 for (i
= 0; i
< 8; i
++)
89 bank
->sectors
[i
].offset
= offset
;
90 bank
->sectors
[i
].size
= 8 * 1024;
91 offset
+= bank
->sectors
[i
].size
;
92 bank
->sectors
[i
].is_erased
= -1;
93 bank
->sectors
[i
].is_protected
= 1;
95 for (i
= 8; i
< 10; i
++)
97 bank
->sectors
[i
].offset
= offset
;
98 bank
->sectors
[i
].size
= 64 * 1024;
99 offset
+= bank
->sectors
[i
].size
;
100 bank
->sectors
[i
].is_erased
= -1;
101 bank
->sectors
[i
].is_protected
= 1;
103 for (i
= 10; i
< 18; i
++)
105 bank
->sectors
[i
].offset
= offset
;
106 bank
->sectors
[i
].size
= 8 * 1024;
107 offset
+= bank
->sectors
[i
].size
;
108 bank
->sectors
[i
].is_erased
= -1;
109 bank
->sectors
[i
].is_protected
= 1;
114 LOG_ERROR("BUG: unknown bank->size encountered");
118 else if (lpc2000_info
->variant
== lpc2000_v2
)
120 /* variant 2 has a uniform layout, only number of sectors differs */
124 lpc2000_info
->cmd51_max_buffer
= 1024;
125 bank
->num_sectors
= 1;
128 lpc2000_info
->cmd51_max_buffer
= 1024;
129 bank
->num_sectors
= 2;
132 bank
->num_sectors
= 4;
135 bank
->num_sectors
= 8;
138 bank
->num_sectors
= 9;
141 bank
->num_sectors
= 11;
144 bank
->num_sectors
= 15;
148 bank
->num_sectors
= 27;
151 LOG_ERROR("BUG: unknown bank->size encountered");
156 bank
->sectors
= malloc(sizeof(struct flash_sector
) * bank
->num_sectors
);
158 for (i
= 0; i
< bank
->num_sectors
; i
++)
160 if ((i
>= 0) && (i
< 8))
162 bank
->sectors
[i
].offset
= offset
;
163 bank
->sectors
[i
].size
= 4 * 1024;
164 offset
+= bank
->sectors
[i
].size
;
165 bank
->sectors
[i
].is_erased
= -1;
166 bank
->sectors
[i
].is_protected
= 1;
168 if ((i
>= 8) && (i
< 22))
170 bank
->sectors
[i
].offset
= offset
;
171 bank
->sectors
[i
].size
= 32 * 1024;
172 offset
+= bank
->sectors
[i
].size
;
173 bank
->sectors
[i
].is_erased
= -1;
174 bank
->sectors
[i
].is_protected
= 1;
176 if ((i
>= 22) && (i
< 27))
178 bank
->sectors
[i
].offset
= offset
;
179 bank
->sectors
[i
].size
= 4 * 1024;
180 offset
+= bank
->sectors
[i
].size
;
181 bank
->sectors
[i
].is_erased
= -1;
182 bank
->sectors
[i
].is_protected
= 1;
186 else if (lpc2000_info
->variant
== lpc1700
)
191 bank
->num_sectors
= 8;
194 bank
->num_sectors
= 16;
197 bank
->num_sectors
= 18;
200 bank
->num_sectors
= 22;
203 bank
->num_sectors
= 30;
206 LOG_ERROR("BUG: unknown bank->size encountered");
210 bank
->sectors
= malloc(sizeof(struct flash_sector
) * bank
->num_sectors
);
212 for(i
= 0; i
< bank
->num_sectors
; i
++)
214 bank
->sectors
[i
].offset
= offset
;
215 /* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx devices */
216 bank
->sectors
[i
].size
= (i
< 16)? 4 * 1024 : 32 * 1024;
217 offset
+= bank
->sectors
[i
].size
;
218 bank
->sectors
[i
].is_erased
= -1;
219 bank
->sectors
[i
].is_protected
= 1;
224 LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
231 /* call LPC1700/LPC2000 IAP function
232 * uses 180 bytes working area
233 * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
234 * 0x8 to 0x1f: command parameter table (1+5 words)
235 * 0x20 to 0x33: command result table (1+4 words)
236 * 0x34 to 0xb3: stack (only 128b needed)
238 static int lpc2000_iap_call(struct flash_bank
*bank
, int code
, uint32_t param_table
[5], uint32_t result_table
[4])
241 struct lpc2000_flash_bank
*lpc2000_info
= bank
->driver_priv
;
242 struct target
*target
= bank
->target
;
243 struct mem_param mem_params
[2];
244 struct reg_param reg_params
[5];
245 struct arm_algorithm armv4_5_info
; /* for LPC2000 */
246 struct armv7m_algorithm armv7m_info
; /* for LPC1700 */
247 uint32_t status_code
;
248 uint32_t iap_entry_point
= 0; /* to make compiler happier */
250 /* regrab previously allocated working_area, or allocate a new one */
251 if (!lpc2000_info
->iap_working_area
)
253 uint8_t jump_gate
[8];
255 /* make sure we have a working area */
256 if (target_alloc_working_area(target
, 180, &lpc2000_info
->iap_working_area
) != ERROR_OK
)
258 LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
259 return ERROR_FLASH_OPERATION_FAILED
;
262 /* write IAP code to working area */
263 switch(lpc2000_info
->variant
)
266 target_buffer_set_u32(target
, jump_gate
, ARMV7M_T_BX(12));
267 target_buffer_set_u32(target
, jump_gate
+ 4, ARMV7M_T_B(0xfffffe));
271 target_buffer_set_u32(target
, jump_gate
, ARMV4_5_BX(12));
272 target_buffer_set_u32(target
, jump_gate
+ 4, ARMV4_5_B(0xfffffe, 0));
275 LOG_ERROR("BUG: unknown bank->size encountered");
279 if ((retval
= target_write_memory(target
, lpc2000_info
->iap_working_area
->address
, 4, 2, jump_gate
)) != ERROR_OK
)
281 LOG_ERROR("Write memory at address 0x%8.8" PRIx32
" failed (check work_area definition)", lpc2000_info
->iap_working_area
->address
);
286 switch(lpc2000_info
->variant
)
289 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
290 armv7m_info
.core_mode
= ARMV7M_MODE_ANY
;
291 iap_entry_point
= 0x1fff1ff1;
295 armv4_5_info
.common_magic
= ARM_COMMON_MAGIC
;
296 armv4_5_info
.core_mode
= ARM_MODE_SVC
;
297 armv4_5_info
.core_state
= ARM_STATE_ARM
;
298 iap_entry_point
= 0x7ffffff1;
301 LOG_ERROR("BUG: unknown lpc2000->variant encountered");
305 /* command parameter table */
306 init_mem_param(&mem_params
[0], lpc2000_info
->iap_working_area
->address
+ 8, 6 * 4, PARAM_OUT
);
307 target_buffer_set_u32(target
, mem_params
[0].value
, code
);
308 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x04, param_table
[0]);
309 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x08, param_table
[1]);
310 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x0c, param_table
[2]);
311 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x10, param_table
[3]);
312 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x14, param_table
[4]);
314 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
315 buf_set_u32(reg_params
[0].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0x08);
317 /* command result table */
318 init_mem_param(&mem_params
[1], lpc2000_info
->iap_working_area
->address
+ 0x20, 5 * 4, PARAM_IN
);
320 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
321 buf_set_u32(reg_params
[1].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0x20);
323 /* IAP entry point */
324 init_reg_param(®_params
[2], "r12", 32, PARAM_OUT
);
325 buf_set_u32(reg_params
[2].value
, 0, 32, iap_entry_point
);
327 switch(lpc2000_info
->variant
)
331 init_reg_param(®_params
[3], "sp", 32, PARAM_OUT
);
332 buf_set_u32(reg_params
[3].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0xb4);
335 init_reg_param(®_params
[4], "lr", 32, PARAM_OUT
);
336 buf_set_u32(reg_params
[4].value
, 0, 32, (lpc2000_info
->iap_working_area
->address
+ 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */
338 target_run_algorithm(target
, 2, mem_params
, 5, reg_params
, lpc2000_info
->iap_working_area
->address
, lpc2000_info
->iap_working_area
->address
+ 0x4, 10000, &armv7m_info
);
343 init_reg_param(®_params
[3], "r13_svc", 32, PARAM_OUT
);
344 buf_set_u32(reg_params
[3].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0xb4);
347 init_reg_param(®_params
[4], "lr_svc", 32, PARAM_OUT
);
348 buf_set_u32(reg_params
[4].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0x04);
350 target_run_algorithm(target
, 2, mem_params
, 5, reg_params
, lpc2000_info
->iap_working_area
->address
, lpc2000_info
->iap_working_area
->address
+ 0x4, 10000, &armv4_5_info
);
353 LOG_ERROR("BUG: unknown lpc2000->variant encountered");
358 status_code
= target_buffer_get_u32(target
, mem_params
[1].value
);
359 result_table
[0] = target_buffer_get_u32(target
, mem_params
[1].value
+ 0x04);
360 result_table
[1] = target_buffer_get_u32(target
, mem_params
[1].value
+ 0x08);
361 result_table
[2] = target_buffer_get_u32(target
, mem_params
[1].value
+ 0x0c);
362 result_table
[3] = target_buffer_get_u32(target
, mem_params
[1].value
+ 0x10);
364 LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32
", 0x%8.8" PRIx32
", 0x%8.8" PRIx32
", 0x%8.8" PRIx32
", 0x%8.8" PRIx32
") completed with result = %8.8" PRIx32
,
365 code
, param_table
[0], param_table
[1], param_table
[2], param_table
[3], param_table
[4], status_code
);
367 destroy_mem_param(&mem_params
[0]);
368 destroy_mem_param(&mem_params
[1]);
370 destroy_reg_param(®_params
[0]);
371 destroy_reg_param(®_params
[1]);
372 destroy_reg_param(®_params
[2]);
373 destroy_reg_param(®_params
[3]);
374 destroy_reg_param(®_params
[4]);
379 static int lpc2000_iap_blank_check(struct flash_bank
*bank
, int first
, int last
)
381 uint32_t param_table
[5];
382 uint32_t result_table
[4];
386 if ((first
< 0) || (last
>= bank
->num_sectors
))
387 return ERROR_FLASH_SECTOR_INVALID
;
389 for (i
= first
; i
<= last
; i
++)
391 /* check single sector */
392 param_table
[0] = param_table
[1] = i
;
393 status_code
= lpc2000_iap_call(bank
, 53, param_table
, result_table
);
397 case ERROR_FLASH_OPERATION_FAILED
:
398 return ERROR_FLASH_OPERATION_FAILED
;
399 case LPC2000_CMD_SUCCESS
:
400 bank
->sectors
[i
].is_erased
= 1;
402 case LPC2000_SECTOR_NOT_BLANK
:
403 bank
->sectors
[i
].is_erased
= 0;
405 case LPC2000_INVALID_SECTOR
:
406 bank
->sectors
[i
].is_erased
= 0;
409 return ERROR_FLASH_BUSY
;
412 LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code
);
421 * flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
423 FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command
)
425 struct lpc2000_flash_bank
*lpc2000_info
;
429 LOG_WARNING("incomplete flash_bank lpc2000 configuration");
430 return ERROR_FLASH_BANK_INVALID
;
433 lpc2000_info
= malloc(sizeof(struct lpc2000_flash_bank
));
434 bank
->driver_priv
= lpc2000_info
;
436 if (strcmp(CMD_ARGV
[6], "lpc2000_v1") == 0)
438 lpc2000_info
->variant
= lpc2000_v1
;
439 lpc2000_info
->cmd51_dst_boundary
= 512;
440 lpc2000_info
->cmd51_can_256b
= 0;
441 lpc2000_info
->cmd51_can_8192b
= 1;
442 lpc2000_info
->checksum_vector
= 5;
444 else if (strcmp(CMD_ARGV
[6], "lpc2000_v2") == 0)
446 lpc2000_info
->variant
= lpc2000_v2
;
447 lpc2000_info
->cmd51_dst_boundary
= 256;
448 lpc2000_info
->cmd51_can_256b
= 1;
449 lpc2000_info
->cmd51_can_8192b
= 0;
450 lpc2000_info
->checksum_vector
= 5;
452 else if (strcmp(CMD_ARGV
[6], "lpc1700") == 0)
454 lpc2000_info
->variant
= lpc1700
;
455 lpc2000_info
->cmd51_dst_boundary
= 256;
456 lpc2000_info
->cmd51_can_256b
= 1;
457 lpc2000_info
->cmd51_can_8192b
= 0;
458 lpc2000_info
->checksum_vector
= 7;
462 LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV
[6]);
464 return ERROR_FLASH_BANK_INVALID
;
467 lpc2000_info
->iap_working_area
= NULL
;
468 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[7], lpc2000_info
->cclk
);
469 lpc2000_info
->calc_checksum
= 0;
470 lpc2000_build_sector_list(bank
);
474 if (strcmp(CMD_ARGV
[8], "calc_checksum") == 0)
475 lpc2000_info
->calc_checksum
= 1;
481 static int lpc2000_erase(struct flash_bank
*bank
, int first
, int last
)
483 struct lpc2000_flash_bank
*lpc2000_info
= bank
->driver_priv
;
484 uint32_t param_table
[5];
485 uint32_t result_table
[4];
488 if (bank
->target
->state
!= TARGET_HALTED
)
490 LOG_ERROR("Target not halted");
491 return ERROR_TARGET_NOT_HALTED
;
494 param_table
[0] = first
;
495 param_table
[1] = last
;
496 param_table
[2] = lpc2000_info
->cclk
;
498 /* Prepare sectors */
499 status_code
= lpc2000_iap_call(bank
, 50, param_table
, result_table
);
502 case ERROR_FLASH_OPERATION_FAILED
:
503 return ERROR_FLASH_OPERATION_FAILED
;
504 case LPC2000_CMD_SUCCESS
:
506 case LPC2000_INVALID_SECTOR
:
507 return ERROR_FLASH_SECTOR_INVALID
;
510 LOG_WARNING("lpc2000 prepare sectors returned %i", status_code
);
511 return ERROR_FLASH_OPERATION_FAILED
;
515 status_code
= lpc2000_iap_call(bank
, 52, param_table
, result_table
);
518 case ERROR_FLASH_OPERATION_FAILED
:
519 return ERROR_FLASH_OPERATION_FAILED
;
520 case LPC2000_CMD_SUCCESS
:
522 case LPC2000_INVALID_SECTOR
:
523 return ERROR_FLASH_SECTOR_INVALID
;
526 LOG_WARNING("lpc2000 erase sectors returned %i", status_code
);
527 return ERROR_FLASH_OPERATION_FAILED
;
533 static int lpc2000_protect(struct flash_bank
*bank
, int set
, int first
, int last
)
535 /* can't protect/unprotect on the lpc2000 */
539 static int lpc2000_write(struct flash_bank
*bank
, uint8_t *buffer
, uint32_t offset
, uint32_t count
)
541 struct lpc2000_flash_bank
*lpc2000_info
= bank
->driver_priv
;
542 struct target
*target
= bank
->target
;
543 uint32_t dst_min_alignment
;
544 uint32_t bytes_remaining
= count
;
545 uint32_t bytes_written
= 0;
546 int first_sector
= 0;
548 uint32_t param_table
[5];
549 uint32_t result_table
[4];
552 struct working_area
*download_area
;
553 int retval
= ERROR_OK
;
555 if (bank
->target
->state
!= TARGET_HALTED
)
557 LOG_ERROR("Target not halted");
558 return ERROR_TARGET_NOT_HALTED
;
561 if (offset
+ count
> bank
->size
)
562 return ERROR_FLASH_DST_OUT_OF_BANK
;
564 dst_min_alignment
= lpc2000_info
->cmd51_dst_boundary
;
566 if (offset
% dst_min_alignment
)
568 LOG_WARNING("offset 0x%" PRIx32
" breaks required alignment 0x%" PRIx32
, offset
, dst_min_alignment
);
569 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
572 for (i
= 0; i
< bank
->num_sectors
; i
++)
574 if (offset
>= bank
->sectors
[i
].offset
)
576 if (offset
+ DIV_ROUND_UP(count
, dst_min_alignment
) * dst_min_alignment
> bank
->sectors
[i
].offset
)
580 LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector
, last_sector
);
582 /* check if exception vectors should be flashed */
583 if ((offset
== 0) && (count
>= 0x20) && lpc2000_info
->calc_checksum
)
585 uint32_t checksum
= 0;
587 for (i
= 0; i
< 8; i
++)
589 LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32
, i
* 4, buf_get_u32(buffer
+ (i
* 4), 0, 32));
590 if (i
!= lpc2000_info
->checksum_vector
)
591 checksum
+= buf_get_u32(buffer
+ (i
* 4), 0, 32);
593 checksum
= 0 - checksum
;
594 LOG_DEBUG("checksum: 0x%8.8" PRIx32
, checksum
);
596 uint32_t original_value
= buf_get_u32(buffer
+ (lpc2000_info
->checksum_vector
* 4), 0, 32);
597 if (original_value
!= checksum
)
599 LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32
") to be written to flash is different from calculated vector checksum (0x%8.8" PRIx32
").",
600 original_value
, checksum
);
601 LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector checksum.");
604 buf_set_u32(buffer
+ (lpc2000_info
->checksum_vector
* 4), 0, 32, checksum
);
607 /* allocate a working area */
608 if (target_alloc_working_area(target
, lpc2000_info
->cmd51_max_buffer
, &download_area
) != ERROR_OK
)
610 LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
611 return ERROR_FLASH_OPERATION_FAILED
;
614 while (bytes_remaining
> 0)
616 uint32_t thisrun_bytes
;
617 if (bytes_remaining
>= lpc2000_info
->cmd51_max_buffer
)
618 thisrun_bytes
= lpc2000_info
->cmd51_max_buffer
;
619 else if (bytes_remaining
>= 1024)
620 thisrun_bytes
= 1024;
621 else if ((bytes_remaining
>= 512) || (!lpc2000_info
->cmd51_can_256b
))
626 /* Prepare sectors */
627 param_table
[0] = first_sector
;
628 param_table
[1] = last_sector
;
629 status_code
= lpc2000_iap_call(bank
, 50, param_table
, result_table
);
632 case ERROR_FLASH_OPERATION_FAILED
:
633 retval
= ERROR_FLASH_OPERATION_FAILED
;
635 case LPC2000_CMD_SUCCESS
:
637 case LPC2000_INVALID_SECTOR
:
638 retval
= ERROR_FLASH_SECTOR_INVALID
;
641 LOG_WARNING("lpc2000 prepare sectors returned %i", status_code
);
642 retval
= ERROR_FLASH_OPERATION_FAILED
;
646 /* Exit if error occured */
647 if (retval
!= ERROR_OK
)
650 if (bytes_remaining
>= thisrun_bytes
)
652 if ((retval
= target_write_buffer(bank
->target
, download_area
->address
, thisrun_bytes
, buffer
+ bytes_written
)) != ERROR_OK
)
654 retval
= ERROR_FLASH_OPERATION_FAILED
;
660 uint8_t *last_buffer
= malloc(thisrun_bytes
);
661 memcpy(last_buffer
, buffer
+ bytes_written
, bytes_remaining
);
662 memset(last_buffer
+ bytes_remaining
, 0xff, thisrun_bytes
- bytes_remaining
);
663 target_write_buffer(bank
->target
, download_area
->address
, thisrun_bytes
, last_buffer
);
667 LOG_DEBUG("writing 0x%" PRIx32
" bytes to address 0x%" PRIx32
, thisrun_bytes
, bank
->base
+ offset
+ bytes_written
);
670 param_table
[0] = bank
->base
+ offset
+ bytes_written
;
671 param_table
[1] = download_area
->address
;
672 param_table
[2] = thisrun_bytes
;
673 param_table
[3] = lpc2000_info
->cclk
;
674 status_code
= lpc2000_iap_call(bank
, 51, param_table
, result_table
);
677 case ERROR_FLASH_OPERATION_FAILED
:
678 retval
= ERROR_FLASH_OPERATION_FAILED
;
680 case LPC2000_CMD_SUCCESS
:
682 case LPC2000_INVALID_SECTOR
:
683 retval
= ERROR_FLASH_SECTOR_INVALID
;
686 LOG_WARNING("lpc2000 returned %i", status_code
);
687 retval
= ERROR_FLASH_OPERATION_FAILED
;
691 /* Exit if error occured */
692 if (retval
!= ERROR_OK
)
695 if (bytes_remaining
> thisrun_bytes
)
696 bytes_remaining
-= thisrun_bytes
;
699 bytes_written
+= thisrun_bytes
;
702 target_free_working_area(target
, download_area
);
707 static int lpc2000_probe(struct flash_bank
*bank
)
709 /* we can't probe on an lpc2000
710 * if this is an lpc2xxx, it has the configured flash
715 static int lpc2000_erase_check(struct flash_bank
*bank
)
717 if (bank
->target
->state
!= TARGET_HALTED
)
719 LOG_ERROR("Target not halted");
720 return ERROR_TARGET_NOT_HALTED
;
723 return lpc2000_iap_blank_check(bank
, 0, bank
->num_sectors
- 1);
726 static int lpc2000_protect_check(struct flash_bank
*bank
)
728 /* sectors are always protected */
732 static int lpc2000_info(struct flash_bank
*bank
, char *buf
, int buf_size
)
734 struct lpc2000_flash_bank
*lpc2000_info
= bank
->driver_priv
;
736 snprintf(buf
, buf_size
, "lpc2000 flash driver variant: %i, clk: %" PRIi32
"kHz" , lpc2000_info
->variant
, lpc2000_info
->cclk
);
741 COMMAND_HANDLER(lpc2000_handle_part_id_command
)
743 uint32_t param_table
[5];
744 uint32_t result_table
[4];
749 return ERROR_COMMAND_SYNTAX_ERROR
;
752 struct flash_bank
*bank
;
753 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &bank
);
754 if (ERROR_OK
!= retval
)
757 if (bank
->target
->state
!= TARGET_HALTED
)
759 LOG_ERROR("Target not halted");
760 return ERROR_TARGET_NOT_HALTED
;
763 if ((status_code
= lpc2000_iap_call(bank
, 54, param_table
, result_table
)) != 0x0)
765 if (status_code
== ERROR_FLASH_OPERATION_FAILED
)
767 command_print(CMD_CTX
, "no sufficient working area specified, can't access LPC2000 IAP interface");
770 command_print(CMD_CTX
, "lpc2000 IAP returned status code %i", status_code
);
774 command_print(CMD_CTX
, "lpc2000 part id: 0x%8.8" PRIx32
, result_table
[0]);
780 static const struct command_registration lpc2000_exec_command_handlers
[] = {
783 .handler
= &lpc2000_handle_part_id_command
,
784 .mode
= COMMAND_EXEC
,
785 .help
= "print part id of lpc2000 flash bank <num>",
787 COMMAND_REGISTRATION_DONE
789 static const struct command_registration lpc2000_command_handlers
[] = {
793 .help
= "lpc2000 flash command group",
794 .chain
= lpc2000_exec_command_handlers
,
796 COMMAND_REGISTRATION_DONE
799 struct flash_driver lpc2000_flash
= {
801 .commands
= lpc2000_command_handlers
,
802 .flash_bank_command
= &lpc2000_flash_bank_command
,
803 .erase
= &lpc2000_erase
,
804 .protect
= &lpc2000_protect
,
805 .write
= &lpc2000_write
,
806 .probe
= &lpc2000_probe
,
807 .auto_probe
= &lpc2000_probe
,
808 .erase_check
= &lpc2000_erase_check
,
809 .protect_check
= &lpc2000_protect_check
,
810 .info
= &lpc2000_info
,
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)