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/arm_opcodes.h>
33 #include <target/armv7m.h>
36 /* flash programming support for NXP LPC17xx and LPC2xxx devices
37 * currently supported devices:
38 * variant 1 (lpc2000_v1):
46 * variant 2 (lpc2000_v2):
55 * - 176x (tested with LPC1768)
58 static int lpc2000_build_sector_list(struct flash_bank
*bank
)
60 struct lpc2000_flash_bank
*lpc2000_info
= bank
->driver_priv
;
64 /* default to a 4096 write buffer */
65 lpc2000_info
->cmd51_max_buffer
= 4096;
67 if (lpc2000_info
->variant
== lpc2000_v1
)
69 /* variant 1 has different layout for 128kb and 256kb flashes */
70 if (bank
->size
== 128 * 1024)
72 bank
->num_sectors
= 16;
73 bank
->sectors
= malloc(sizeof(struct flash_sector
) * 16);
74 for (i
= 0; i
< 16; i
++)
76 bank
->sectors
[i
].offset
= offset
;
77 bank
->sectors
[i
].size
= 8 * 1024;
78 offset
+= bank
->sectors
[i
].size
;
79 bank
->sectors
[i
].is_erased
= -1;
80 bank
->sectors
[i
].is_protected
= 1;
83 else if (bank
->size
== 256 * 1024)
85 bank
->num_sectors
= 18;
86 bank
->sectors
= malloc(sizeof(struct flash_sector
) * 18);
88 for (i
= 0; i
< 8; i
++)
90 bank
->sectors
[i
].offset
= offset
;
91 bank
->sectors
[i
].size
= 8 * 1024;
92 offset
+= bank
->sectors
[i
].size
;
93 bank
->sectors
[i
].is_erased
= -1;
94 bank
->sectors
[i
].is_protected
= 1;
96 for (i
= 8; i
< 10; i
++)
98 bank
->sectors
[i
].offset
= offset
;
99 bank
->sectors
[i
].size
= 64 * 1024;
100 offset
+= bank
->sectors
[i
].size
;
101 bank
->sectors
[i
].is_erased
= -1;
102 bank
->sectors
[i
].is_protected
= 1;
104 for (i
= 10; i
< 18; i
++)
106 bank
->sectors
[i
].offset
= offset
;
107 bank
->sectors
[i
].size
= 8 * 1024;
108 offset
+= bank
->sectors
[i
].size
;
109 bank
->sectors
[i
].is_erased
= -1;
110 bank
->sectors
[i
].is_protected
= 1;
115 LOG_ERROR("BUG: unknown bank->size encountered");
119 else if (lpc2000_info
->variant
== lpc2000_v2
)
121 /* variant 2 has a uniform layout, only number of sectors differs */
125 lpc2000_info
->cmd51_max_buffer
= 1024;
126 bank
->num_sectors
= 1;
129 lpc2000_info
->cmd51_max_buffer
= 1024;
130 bank
->num_sectors
= 2;
133 bank
->num_sectors
= 4;
136 bank
->num_sectors
= 8;
139 bank
->num_sectors
= 9;
142 bank
->num_sectors
= 11;
145 bank
->num_sectors
= 15;
149 bank
->num_sectors
= 27;
152 LOG_ERROR("BUG: unknown bank->size encountered");
157 bank
->sectors
= malloc(sizeof(struct flash_sector
) * bank
->num_sectors
);
159 for (i
= 0; i
< bank
->num_sectors
; i
++)
161 if ((i
>= 0) && (i
< 8))
163 bank
->sectors
[i
].offset
= offset
;
164 bank
->sectors
[i
].size
= 4 * 1024;
165 offset
+= bank
->sectors
[i
].size
;
166 bank
->sectors
[i
].is_erased
= -1;
167 bank
->sectors
[i
].is_protected
= 1;
169 if ((i
>= 8) && (i
< 22))
171 bank
->sectors
[i
].offset
= offset
;
172 bank
->sectors
[i
].size
= 32 * 1024;
173 offset
+= bank
->sectors
[i
].size
;
174 bank
->sectors
[i
].is_erased
= -1;
175 bank
->sectors
[i
].is_protected
= 1;
177 if ((i
>= 22) && (i
< 27))
179 bank
->sectors
[i
].offset
= offset
;
180 bank
->sectors
[i
].size
= 4 * 1024;
181 offset
+= bank
->sectors
[i
].size
;
182 bank
->sectors
[i
].is_erased
= -1;
183 bank
->sectors
[i
].is_protected
= 1;
187 else if (lpc2000_info
->variant
== lpc1700
)
192 bank
->num_sectors
= 8;
195 bank
->num_sectors
= 16;
198 bank
->num_sectors
= 18;
201 bank
->num_sectors
= 22;
204 bank
->num_sectors
= 30;
207 LOG_ERROR("BUG: unknown bank->size encountered");
211 bank
->sectors
= malloc(sizeof(struct flash_sector
) * bank
->num_sectors
);
213 for(i
= 0; i
< bank
->num_sectors
; i
++)
215 bank
->sectors
[i
].offset
= offset
;
216 /* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx devices */
217 bank
->sectors
[i
].size
= (i
< 16)? 4 * 1024 : 32 * 1024;
218 offset
+= bank
->sectors
[i
].size
;
219 bank
->sectors
[i
].is_erased
= -1;
220 bank
->sectors
[i
].is_protected
= 1;
225 LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
232 /* call LPC1700/LPC2000 IAP function
233 * uses 180 bytes working area
234 * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
235 * 0x8 to 0x1f: command parameter table (1+5 words)
236 * 0x20 to 0x33: command result table (1+4 words)
237 * 0x34 to 0xb3: stack (only 128b needed)
239 static int lpc2000_iap_call(struct flash_bank
*bank
, int code
, uint32_t param_table
[5], uint32_t result_table
[4])
242 struct lpc2000_flash_bank
*lpc2000_info
= bank
->driver_priv
;
243 struct target
*target
= bank
->target
;
244 struct mem_param mem_params
[2];
245 struct reg_param reg_params
[5];
246 struct arm_algorithm armv4_5_info
; /* for LPC2000 */
247 struct armv7m_algorithm armv7m_info
; /* for LPC1700 */
248 uint32_t status_code
;
249 uint32_t iap_entry_point
= 0; /* to make compiler happier */
251 /* regrab previously allocated working_area, or allocate a new one */
252 if (!lpc2000_info
->iap_working_area
)
254 uint8_t jump_gate
[8];
256 /* make sure we have a working area */
257 if (target_alloc_working_area(target
, 180, &lpc2000_info
->iap_working_area
) != ERROR_OK
)
259 LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
260 return ERROR_FLASH_OPERATION_FAILED
;
263 /* write IAP code to working area */
264 switch(lpc2000_info
->variant
)
267 target_buffer_set_u32(target
, jump_gate
,
269 target_buffer_set_u32(target
, jump_gate
+ 4,
270 ARMV4_5_T_B(0xfffffe));
274 target_buffer_set_u32(target
, jump_gate
, ARMV4_5_BX(12));
275 target_buffer_set_u32(target
, jump_gate
+ 4, ARMV4_5_B(0xfffffe, 0));
278 LOG_ERROR("BUG: unknown bank->size encountered");
282 if ((retval
= target_write_memory(target
, lpc2000_info
->iap_working_area
->address
, 4, 2, jump_gate
)) != ERROR_OK
)
284 LOG_ERROR("Write memory at address 0x%8.8" PRIx32
" failed (check work_area definition)", lpc2000_info
->iap_working_area
->address
);
289 switch(lpc2000_info
->variant
)
292 armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
293 armv7m_info
.core_mode
= ARMV7M_MODE_ANY
;
294 iap_entry_point
= 0x1fff1ff1;
298 armv4_5_info
.common_magic
= ARM_COMMON_MAGIC
;
299 armv4_5_info
.core_mode
= ARM_MODE_SVC
;
300 armv4_5_info
.core_state
= ARM_STATE_ARM
;
301 iap_entry_point
= 0x7ffffff1;
304 LOG_ERROR("BUG: unknown lpc2000->variant encountered");
308 /* command parameter table */
309 init_mem_param(&mem_params
[0], lpc2000_info
->iap_working_area
->address
+ 8, 6 * 4, PARAM_OUT
);
310 target_buffer_set_u32(target
, mem_params
[0].value
, code
);
311 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x04, param_table
[0]);
312 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x08, param_table
[1]);
313 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x0c, param_table
[2]);
314 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x10, param_table
[3]);
315 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x14, param_table
[4]);
317 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
318 buf_set_u32(reg_params
[0].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0x08);
320 /* command result table */
321 init_mem_param(&mem_params
[1], lpc2000_info
->iap_working_area
->address
+ 0x20, 5 * 4, PARAM_IN
);
323 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
324 buf_set_u32(reg_params
[1].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0x20);
326 /* IAP entry point */
327 init_reg_param(®_params
[2], "r12", 32, PARAM_OUT
);
328 buf_set_u32(reg_params
[2].value
, 0, 32, iap_entry_point
);
330 switch(lpc2000_info
->variant
)
334 init_reg_param(®_params
[3], "sp", 32, PARAM_OUT
);
335 buf_set_u32(reg_params
[3].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0xb4);
338 init_reg_param(®_params
[4], "lr", 32, PARAM_OUT
);
339 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 */
341 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
);
346 init_reg_param(®_params
[3], "sp_svc", 32, PARAM_OUT
);
347 buf_set_u32(reg_params
[3].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0xb4);
350 init_reg_param(®_params
[4], "lr_svc", 32, PARAM_OUT
);
351 buf_set_u32(reg_params
[4].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0x04);
353 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
);
356 LOG_ERROR("BUG: unknown lpc2000->variant encountered");
361 status_code
= target_buffer_get_u32(target
, mem_params
[1].value
);
362 result_table
[0] = target_buffer_get_u32(target
, mem_params
[1].value
+ 0x04);
363 result_table
[1] = target_buffer_get_u32(target
, mem_params
[1].value
+ 0x08);
364 result_table
[2] = target_buffer_get_u32(target
, mem_params
[1].value
+ 0x0c);
365 result_table
[3] = target_buffer_get_u32(target
, mem_params
[1].value
+ 0x10);
367 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
,
368 code
, param_table
[0], param_table
[1], param_table
[2], param_table
[3], param_table
[4], status_code
);
370 destroy_mem_param(&mem_params
[0]);
371 destroy_mem_param(&mem_params
[1]);
373 destroy_reg_param(®_params
[0]);
374 destroy_reg_param(®_params
[1]);
375 destroy_reg_param(®_params
[2]);
376 destroy_reg_param(®_params
[3]);
377 destroy_reg_param(®_params
[4]);
382 static int lpc2000_iap_blank_check(struct flash_bank
*bank
, int first
, int last
)
384 uint32_t param_table
[5];
385 uint32_t result_table
[4];
389 if ((first
< 0) || (last
>= bank
->num_sectors
))
390 return ERROR_FLASH_SECTOR_INVALID
;
392 for (i
= first
; i
<= last
; i
++)
394 /* check single sector */
395 param_table
[0] = param_table
[1] = i
;
396 status_code
= lpc2000_iap_call(bank
, 53, param_table
, result_table
);
400 case ERROR_FLASH_OPERATION_FAILED
:
401 return ERROR_FLASH_OPERATION_FAILED
;
402 case LPC2000_CMD_SUCCESS
:
403 bank
->sectors
[i
].is_erased
= 1;
405 case LPC2000_SECTOR_NOT_BLANK
:
406 bank
->sectors
[i
].is_erased
= 0;
408 case LPC2000_INVALID_SECTOR
:
409 bank
->sectors
[i
].is_erased
= 0;
412 return ERROR_FLASH_BUSY
;
415 LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code
);
424 * flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
426 FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command
)
428 struct lpc2000_flash_bank
*lpc2000_info
;
432 LOG_WARNING("incomplete flash_bank lpc2000 configuration");
433 return ERROR_FLASH_BANK_INVALID
;
436 lpc2000_info
= malloc(sizeof(struct lpc2000_flash_bank
));
437 bank
->driver_priv
= lpc2000_info
;
439 if (strcmp(CMD_ARGV
[6], "lpc2000_v1") == 0)
441 lpc2000_info
->variant
= lpc2000_v1
;
442 lpc2000_info
->cmd51_dst_boundary
= 512;
443 lpc2000_info
->cmd51_can_256b
= 0;
444 lpc2000_info
->cmd51_can_8192b
= 1;
445 lpc2000_info
->checksum_vector
= 5;
447 else if (strcmp(CMD_ARGV
[6], "lpc2000_v2") == 0)
449 lpc2000_info
->variant
= lpc2000_v2
;
450 lpc2000_info
->cmd51_dst_boundary
= 256;
451 lpc2000_info
->cmd51_can_256b
= 1;
452 lpc2000_info
->cmd51_can_8192b
= 0;
453 lpc2000_info
->checksum_vector
= 5;
455 else if (strcmp(CMD_ARGV
[6], "lpc1700") == 0)
457 lpc2000_info
->variant
= lpc1700
;
458 lpc2000_info
->cmd51_dst_boundary
= 256;
459 lpc2000_info
->cmd51_can_256b
= 1;
460 lpc2000_info
->cmd51_can_8192b
= 0;
461 lpc2000_info
->checksum_vector
= 7;
465 LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV
[6]);
467 return ERROR_FLASH_BANK_INVALID
;
470 lpc2000_info
->iap_working_area
= NULL
;
471 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[7], lpc2000_info
->cclk
);
472 lpc2000_info
->calc_checksum
= 0;
473 lpc2000_build_sector_list(bank
);
477 if (strcmp(CMD_ARGV
[8], "calc_checksum") == 0)
478 lpc2000_info
->calc_checksum
= 1;
484 static int lpc2000_erase(struct flash_bank
*bank
, int first
, int last
)
486 struct lpc2000_flash_bank
*lpc2000_info
= bank
->driver_priv
;
487 uint32_t param_table
[5];
488 uint32_t result_table
[4];
491 if (bank
->target
->state
!= TARGET_HALTED
)
493 LOG_ERROR("Target not halted");
494 return ERROR_TARGET_NOT_HALTED
;
497 param_table
[0] = first
;
498 param_table
[1] = last
;
499 param_table
[2] = lpc2000_info
->cclk
;
501 /* Prepare sectors */
502 status_code
= lpc2000_iap_call(bank
, 50, param_table
, result_table
);
505 case ERROR_FLASH_OPERATION_FAILED
:
506 return ERROR_FLASH_OPERATION_FAILED
;
507 case LPC2000_CMD_SUCCESS
:
509 case LPC2000_INVALID_SECTOR
:
510 return ERROR_FLASH_SECTOR_INVALID
;
513 LOG_WARNING("lpc2000 prepare sectors returned %i", status_code
);
514 return ERROR_FLASH_OPERATION_FAILED
;
518 status_code
= lpc2000_iap_call(bank
, 52, param_table
, result_table
);
521 case ERROR_FLASH_OPERATION_FAILED
:
522 return ERROR_FLASH_OPERATION_FAILED
;
523 case LPC2000_CMD_SUCCESS
:
525 case LPC2000_INVALID_SECTOR
:
526 return ERROR_FLASH_SECTOR_INVALID
;
529 LOG_WARNING("lpc2000 erase sectors returned %i", status_code
);
530 return ERROR_FLASH_OPERATION_FAILED
;
536 static int lpc2000_protect(struct flash_bank
*bank
, int set
, int first
, int last
)
538 /* can't protect/unprotect on the lpc2000 */
542 static int lpc2000_write(struct flash_bank
*bank
, uint8_t *buffer
, uint32_t offset
, uint32_t count
)
544 struct lpc2000_flash_bank
*lpc2000_info
= bank
->driver_priv
;
545 struct target
*target
= bank
->target
;
546 uint32_t dst_min_alignment
;
547 uint32_t bytes_remaining
= count
;
548 uint32_t bytes_written
= 0;
549 int first_sector
= 0;
551 uint32_t param_table
[5];
552 uint32_t result_table
[4];
555 struct working_area
*download_area
;
556 int retval
= ERROR_OK
;
558 if (bank
->target
->state
!= TARGET_HALTED
)
560 LOG_ERROR("Target not halted");
561 return ERROR_TARGET_NOT_HALTED
;
564 if (offset
+ count
> bank
->size
)
565 return ERROR_FLASH_DST_OUT_OF_BANK
;
567 dst_min_alignment
= lpc2000_info
->cmd51_dst_boundary
;
569 if (offset
% dst_min_alignment
)
571 LOG_WARNING("offset 0x%" PRIx32
" breaks required alignment 0x%" PRIx32
, offset
, dst_min_alignment
);
572 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
575 for (i
= 0; i
< bank
->num_sectors
; i
++)
577 if (offset
>= bank
->sectors
[i
].offset
)
579 if (offset
+ DIV_ROUND_UP(count
, dst_min_alignment
) * dst_min_alignment
> bank
->sectors
[i
].offset
)
583 LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector
, last_sector
);
585 /* check if exception vectors should be flashed */
586 if ((offset
== 0) && (count
>= 0x20) && lpc2000_info
->calc_checksum
)
588 uint32_t checksum
= 0;
590 for (i
= 0; i
< 8; i
++)
592 LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32
, i
* 4, buf_get_u32(buffer
+ (i
* 4), 0, 32));
593 if (i
!= lpc2000_info
->checksum_vector
)
594 checksum
+= buf_get_u32(buffer
+ (i
* 4), 0, 32);
596 checksum
= 0 - checksum
;
597 LOG_DEBUG("checksum: 0x%8.8" PRIx32
, checksum
);
599 uint32_t original_value
= buf_get_u32(buffer
+ (lpc2000_info
->checksum_vector
* 4), 0, 32);
600 if (original_value
!= checksum
)
602 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
").",
603 original_value
, checksum
);
604 LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector checksum.");
607 buf_set_u32(buffer
+ (lpc2000_info
->checksum_vector
* 4), 0, 32, checksum
);
610 /* allocate a working area */
611 if (target_alloc_working_area(target
, lpc2000_info
->cmd51_max_buffer
, &download_area
) != ERROR_OK
)
613 LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
614 return ERROR_FLASH_OPERATION_FAILED
;
617 while (bytes_remaining
> 0)
619 uint32_t thisrun_bytes
;
620 if (bytes_remaining
>= lpc2000_info
->cmd51_max_buffer
)
621 thisrun_bytes
= lpc2000_info
->cmd51_max_buffer
;
622 else if (bytes_remaining
>= 1024)
623 thisrun_bytes
= 1024;
624 else if ((bytes_remaining
>= 512) || (!lpc2000_info
->cmd51_can_256b
))
629 /* Prepare sectors */
630 param_table
[0] = first_sector
;
631 param_table
[1] = last_sector
;
632 status_code
= lpc2000_iap_call(bank
, 50, param_table
, result_table
);
635 case ERROR_FLASH_OPERATION_FAILED
:
636 retval
= ERROR_FLASH_OPERATION_FAILED
;
638 case LPC2000_CMD_SUCCESS
:
640 case LPC2000_INVALID_SECTOR
:
641 retval
= ERROR_FLASH_SECTOR_INVALID
;
644 LOG_WARNING("lpc2000 prepare sectors returned %i", status_code
);
645 retval
= ERROR_FLASH_OPERATION_FAILED
;
649 /* Exit if error occured */
650 if (retval
!= ERROR_OK
)
653 if (bytes_remaining
>= thisrun_bytes
)
655 if ((retval
= target_write_buffer(bank
->target
, download_area
->address
, thisrun_bytes
, buffer
+ bytes_written
)) != ERROR_OK
)
657 retval
= ERROR_FLASH_OPERATION_FAILED
;
663 uint8_t *last_buffer
= malloc(thisrun_bytes
);
664 memcpy(last_buffer
, buffer
+ bytes_written
, bytes_remaining
);
665 memset(last_buffer
+ bytes_remaining
, 0xff, thisrun_bytes
- bytes_remaining
);
666 target_write_buffer(bank
->target
, download_area
->address
, thisrun_bytes
, last_buffer
);
670 LOG_DEBUG("writing 0x%" PRIx32
" bytes to address 0x%" PRIx32
, thisrun_bytes
, bank
->base
+ offset
+ bytes_written
);
673 param_table
[0] = bank
->base
+ offset
+ bytes_written
;
674 param_table
[1] = download_area
->address
;
675 param_table
[2] = thisrun_bytes
;
676 param_table
[3] = lpc2000_info
->cclk
;
677 status_code
= lpc2000_iap_call(bank
, 51, param_table
, result_table
);
680 case ERROR_FLASH_OPERATION_FAILED
:
681 retval
= ERROR_FLASH_OPERATION_FAILED
;
683 case LPC2000_CMD_SUCCESS
:
685 case LPC2000_INVALID_SECTOR
:
686 retval
= ERROR_FLASH_SECTOR_INVALID
;
689 LOG_WARNING("lpc2000 returned %i", status_code
);
690 retval
= ERROR_FLASH_OPERATION_FAILED
;
694 /* Exit if error occured */
695 if (retval
!= ERROR_OK
)
698 if (bytes_remaining
> thisrun_bytes
)
699 bytes_remaining
-= thisrun_bytes
;
702 bytes_written
+= thisrun_bytes
;
705 target_free_working_area(target
, download_area
);
710 static int lpc2000_probe(struct flash_bank
*bank
)
712 /* we can't probe on an lpc2000
713 * if this is an lpc2xxx, it has the configured flash
718 static int lpc2000_erase_check(struct flash_bank
*bank
)
720 if (bank
->target
->state
!= TARGET_HALTED
)
722 LOG_ERROR("Target not halted");
723 return ERROR_TARGET_NOT_HALTED
;
726 return lpc2000_iap_blank_check(bank
, 0, bank
->num_sectors
- 1);
729 static int lpc2000_protect_check(struct flash_bank
*bank
)
731 /* sectors are always protected */
735 static int lpc2000_info(struct flash_bank
*bank
, char *buf
, int buf_size
)
737 struct lpc2000_flash_bank
*lpc2000_info
= bank
->driver_priv
;
739 snprintf(buf
, buf_size
, "lpc2000 flash driver variant: %i, clk: %" PRIi32
"kHz" , lpc2000_info
->variant
, lpc2000_info
->cclk
);
744 COMMAND_HANDLER(lpc2000_handle_part_id_command
)
746 uint32_t param_table
[5];
747 uint32_t result_table
[4];
752 return ERROR_COMMAND_SYNTAX_ERROR
;
755 struct flash_bank
*bank
;
756 int retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &bank
);
757 if (ERROR_OK
!= retval
)
760 if (bank
->target
->state
!= TARGET_HALTED
)
762 LOG_ERROR("Target not halted");
763 return ERROR_TARGET_NOT_HALTED
;
766 if ((status_code
= lpc2000_iap_call(bank
, 54, param_table
, result_table
)) != 0x0)
768 if (status_code
== ERROR_FLASH_OPERATION_FAILED
)
770 command_print(CMD_CTX
, "no sufficient working area specified, can't access LPC2000 IAP interface");
773 command_print(CMD_CTX
, "lpc2000 IAP returned status code %i", status_code
);
777 command_print(CMD_CTX
, "lpc2000 part id: 0x%8.8" PRIx32
, result_table
[0]);
783 static const struct command_registration lpc2000_exec_command_handlers
[] = {
786 .handler
= lpc2000_handle_part_id_command
,
787 .mode
= COMMAND_EXEC
,
788 .help
= "print part id of lpc2000 flash bank <num>",
790 COMMAND_REGISTRATION_DONE
792 static const struct command_registration lpc2000_command_handlers
[] = {
796 .help
= "lpc2000 flash command group",
797 .chain
= lpc2000_exec_command_handlers
,
799 COMMAND_REGISTRATION_DONE
802 struct flash_driver lpc2000_flash
= {
804 .commands
= lpc2000_command_handlers
,
805 .flash_bank_command
= lpc2000_flash_bank_command
,
806 .erase
= lpc2000_erase
,
807 .protect
= lpc2000_protect
,
808 .write
= lpc2000_write
,
809 .probe
= lpc2000_probe
,
810 .auto_probe
= lpc2000_probe
,
811 .erase_check
= lpc2000_erase_check
,
812 .protect_check
= lpc2000_protect_check
,
813 .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)