1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
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 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
30 #include "algorithm.h"
31 #include "binarybuffer.h"
36 /* flash programming support for Philips LPC2xxx devices
37 * currently supported devices:
38 * variant 1 (lpc2000_v1):
46 * variant 2 (lpc2000_v2):
54 int lpc2000_register_commands(struct command_context_s
*cmd_ctx
);
55 int lpc2000_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
);
56 int lpc2000_erase(struct flash_bank_s
*bank
, int first
, int last
);
57 int lpc2000_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
);
58 int lpc2000_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
);
59 int lpc2000_probe(struct flash_bank_s
*bank
);
60 int lpc2000_erase_check(struct flash_bank_s
*bank
);
61 int lpc2000_protect_check(struct flash_bank_s
*bank
);
62 int lpc2000_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
);
64 int lpc2000_handle_part_id_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
66 flash_driver_t lpc2000_flash
=
69 .register_commands
= lpc2000_register_commands
,
70 .flash_bank_command
= lpc2000_flash_bank_command
,
71 .erase
= lpc2000_erase
,
72 .protect
= lpc2000_protect
,
73 .write
= lpc2000_write
,
74 .probe
= lpc2000_probe
,
75 .erase_check
= lpc2000_erase_check
,
76 .protect_check
= lpc2000_protect_check
,
80 int lpc2000_register_commands(struct command_context_s
*cmd_ctx
)
82 command_t
*lpc2000_cmd
= register_command(cmd_ctx
, NULL
, "lpc2000", NULL
, COMMAND_ANY
, NULL
);
84 register_command(cmd_ctx
, lpc2000_cmd
, "part_id", lpc2000_handle_part_id_command
, COMMAND_EXEC
,
85 "print part id of lpc2000 flash bank <num>");
90 int lpc2000_build_sector_list(struct flash_bank_s
*bank
)
92 lpc2000_flash_bank_t
*lpc2000_info
= bank
->driver_priv
;
94 if (lpc2000_info
->variant
== 1)
99 /* variant 1 has different layout for 128kb and 256kb flashes */
100 if (bank
->size
== 128 * 1024)
102 bank
->num_sectors
= 16;
103 bank
->sectors
= malloc(sizeof(flash_sector_t
) * 16);
104 for (i
= 0; i
< 16; 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;
113 else if (bank
->size
== 256 * 1024)
115 bank
->num_sectors
= 18;
116 bank
->sectors
= malloc(sizeof(flash_sector_t
) * 18);
118 for (i
= 0; i
< 8; i
++)
120 bank
->sectors
[i
].offset
= offset
;
121 bank
->sectors
[i
].size
= 8 * 1024;
122 offset
+= bank
->sectors
[i
].size
;
123 bank
->sectors
[i
].is_erased
= -1;
124 bank
->sectors
[i
].is_protected
= 1;
126 for (i
= 8; i
< 10; i
++)
128 bank
->sectors
[i
].offset
= offset
;
129 bank
->sectors
[i
].size
= 64 * 1024;
130 offset
+= bank
->sectors
[i
].size
;
131 bank
->sectors
[i
].is_erased
= -1;
132 bank
->sectors
[i
].is_protected
= 1;
134 for (i
= 10; i
< 18; i
++)
136 bank
->sectors
[i
].offset
= offset
;
137 bank
->sectors
[i
].size
= 8 * 1024;
138 offset
+= bank
->sectors
[i
].size
;
139 bank
->sectors
[i
].is_erased
= -1;
140 bank
->sectors
[i
].is_protected
= 1;
145 ERROR("BUG: unknown bank->size encountered");
149 else if (lpc2000_info
->variant
== 2)
155 /* variant 2 has a uniform layout, only number of sectors differs */
181 ERROR("BUG: unknown bank->size encountered");
186 bank
->num_sectors
= num_sectors
;
187 bank
->sectors
= malloc(sizeof(flash_sector_t
) * num_sectors
);
189 for (i
= 0; i
< num_sectors
; i
++)
191 if ((i
>= 0) && (i
< 8))
193 bank
->sectors
[i
].offset
= offset
;
194 bank
->sectors
[i
].size
= 4 * 1024;
195 offset
+= bank
->sectors
[i
].size
;
196 bank
->sectors
[i
].is_erased
= -1;
197 bank
->sectors
[i
].is_protected
= 1;
199 if ((i
>= 8) && (i
< 22))
201 bank
->sectors
[i
].offset
= offset
;
202 bank
->sectors
[i
].size
= 32 * 1024;
203 offset
+= bank
->sectors
[i
].size
;
204 bank
->sectors
[i
].is_erased
= -1;
205 bank
->sectors
[i
].is_protected
= 1;
207 if ((i
>= 22) && (i
< 27))
209 bank
->sectors
[i
].offset
= offset
;
210 bank
->sectors
[i
].size
= 4 * 1024;
211 offset
+= bank
->sectors
[i
].size
;
212 bank
->sectors
[i
].is_erased
= -1;
213 bank
->sectors
[i
].is_protected
= 1;
219 ERROR("BUG: unknown lpc2000_info->variant encountered");
226 /* call LPC2000 IAP function
227 * uses 172 bytes working area
228 * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
229 * 0x8 to 0x1f: command parameter table
230 * 0x20 to 0x2b: command result table
231 * 0x2c to 0xac: stack (only 128b needed)
233 int lpc2000_iap_call(flash_bank_t
*bank
, int code
, u32 param_table
[5], u32 result_table
[2])
235 lpc2000_flash_bank_t
*lpc2000_info
= bank
->driver_priv
;
236 target_t
*target
= bank
->target
;
237 mem_param_t mem_params
[2];
238 reg_param_t reg_params
[5];
239 armv4_5_algorithm_t armv4_5_info
;
242 /* regrab previously allocated working_area, or allocate a new one */
243 if (!lpc2000_info
->iap_working_area
)
247 /* make sure we have a working area */
248 if (target_alloc_working_area(target
, 172, &lpc2000_info
->iap_working_area
) != ERROR_OK
)
250 ERROR("no working area specified, can't write LPC2000 internal flash");
251 return ERROR_FLASH_OPERATION_FAILED
;
254 /* write IAP code to working area */
255 target_buffer_set_u32(target
, jump_gate
, ARMV4_5_BX(12));
256 target_buffer_set_u32(target
, jump_gate
+ 4, ARMV4_5_B(0xfffffe, 0));
257 target
->type
->write_memory(target
, lpc2000_info
->iap_working_area
->address
, 4, 2, jump_gate
);
260 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
261 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
262 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
264 /* command parameter table */
265 init_mem_param(&mem_params
[0], lpc2000_info
->iap_working_area
->address
+ 8, 4 * 6, PARAM_OUT
);
266 target_buffer_set_u32(target
, mem_params
[0].value
, code
);
267 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x4, param_table
[0]);
268 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x8, param_table
[1]);
269 target_buffer_set_u32(target
, mem_params
[0].value
+ 0xc, param_table
[2]);
270 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x10, param_table
[3]);
271 target_buffer_set_u32(target
, mem_params
[0].value
+ 0x14, param_table
[4]);
273 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
274 buf_set_u32(reg_params
[0].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0x8);
276 /* command result table */
277 init_mem_param(&mem_params
[1], lpc2000_info
->iap_working_area
->address
+ 0x20, 4 * 3, PARAM_IN
);
279 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
280 buf_set_u32(reg_params
[1].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0x20);
282 /* IAP entry point */
283 init_reg_param(®_params
[2], "r12", 32, PARAM_OUT
);
284 buf_set_u32(reg_params
[2].value
, 0, 32, 0x7ffffff1);
287 init_reg_param(®_params
[3], "r13_svc", 32, PARAM_OUT
);
288 buf_set_u32(reg_params
[3].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0xac);
291 init_reg_param(®_params
[4], "lr_svc", 32, PARAM_OUT
);
292 buf_set_u32(reg_params
[4].value
, 0, 32, lpc2000_info
->iap_working_area
->address
+ 0x4);
294 target
->type
->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
);
296 status_code
= buf_get_u32(mem_params
[1].value
, 0, 32);
297 result_table
[0] = target_buffer_get_u32(target
, mem_params
[1].value
);
298 result_table
[1] = target_buffer_get_u32(target
, mem_params
[1].value
+ 4);
300 destroy_mem_param(&mem_params
[0]);
301 destroy_mem_param(&mem_params
[1]);
303 destroy_reg_param(®_params
[0]);
304 destroy_reg_param(®_params
[1]);
305 destroy_reg_param(®_params
[2]);
306 destroy_reg_param(®_params
[3]);
307 destroy_reg_param(®_params
[4]);
312 int lpc2000_iap_blank_check(struct flash_bank_s
*bank
, int first
, int last
)
319 if ((first
< 0) || (last
> bank
->num_sectors
))
320 return ERROR_FLASH_SECTOR_INVALID
;
322 for (i
= first
; i
<= last
; i
++)
324 /* check single sector */
325 param_table
[0] = param_table
[1] = i
;
326 status_code
= lpc2000_iap_call(bank
, 53, param_table
, result_table
);
330 case ERROR_FLASH_OPERATION_FAILED
:
331 return ERROR_FLASH_OPERATION_FAILED
;
332 case LPC2000_CMD_SUCCESS
:
333 bank
->sectors
[i
].is_erased
= 1;
335 case LPC2000_SECTOR_NOT_BLANK
:
336 bank
->sectors
[i
].is_erased
= 0;
338 case LPC2000_INVALID_SECTOR
:
339 bank
->sectors
[i
].is_erased
= 0;
342 return ERROR_FLASH_BUSY
;
345 ERROR("BUG: unknown LPC2000 status code");
353 /* flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
355 int lpc2000_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
)
357 lpc2000_flash_bank_t
*lpc2000_info
;
361 WARNING("incomplete flash_bank lpc2000 configuration");
362 return ERROR_FLASH_BANK_INVALID
;
365 lpc2000_info
= malloc(sizeof(lpc2000_flash_bank_t
));
366 bank
->driver_priv
= lpc2000_info
;
368 if (strcmp(args
[6], "lpc2000_v1") == 0)
370 lpc2000_info
->variant
= 1;
371 lpc2000_info
->cmd51_dst_boundary
= 512;
372 lpc2000_info
->cmd51_can_256b
= 0;
373 lpc2000_info
->cmd51_can_8192b
= 1;
375 else if (strcmp(args
[6], "lpc2000_v2") == 0)
377 lpc2000_info
->variant
= 2;
378 lpc2000_info
->cmd51_dst_boundary
= 256;
379 lpc2000_info
->cmd51_can_256b
= 1;
380 lpc2000_info
->cmd51_can_8192b
= 0;
384 ERROR("unknown LPC2000 variant");
386 return ERROR_FLASH_BANK_INVALID
;
389 lpc2000_info
->iap_working_area
= NULL
;
390 lpc2000_info
->cclk
= strtoul(args
[7], NULL
, 0);
391 lpc2000_info
->calc_checksum
= 0;
392 lpc2000_build_sector_list(bank
);
396 if (strcmp(args
[8], "calc_checksum") == 0)
397 lpc2000_info
->calc_checksum
= 1;
403 int lpc2000_erase(struct flash_bank_s
*bank
, int first
, int last
)
405 lpc2000_flash_bank_t
*lpc2000_info
= bank
->driver_priv
;
410 if (bank
->target
->state
!= TARGET_HALTED
)
412 return ERROR_TARGET_NOT_HALTED
;
415 if ((first
< 0) || (last
< first
) || (last
>= bank
->num_sectors
))
417 return ERROR_FLASH_SECTOR_INVALID
;
420 param_table
[0] = first
;
421 param_table
[1] = last
;
422 param_table
[2] = lpc2000_info
->cclk
;
424 /* Prepare sectors */
425 status_code
= lpc2000_iap_call(bank
, 50, param_table
, result_table
);
428 case ERROR_FLASH_OPERATION_FAILED
:
429 return ERROR_FLASH_OPERATION_FAILED
;
430 case LPC2000_CMD_SUCCESS
:
432 case LPC2000_INVALID_SECTOR
:
433 return ERROR_FLASH_SECTOR_INVALID
;
436 WARNING("lpc2000 prepare sectors returned %i", status_code
);
437 return ERROR_FLASH_OPERATION_FAILED
;
441 status_code
= lpc2000_iap_call(bank
, 52, param_table
, result_table
);
444 case ERROR_FLASH_OPERATION_FAILED
:
445 return ERROR_FLASH_OPERATION_FAILED
;
446 case LPC2000_CMD_SUCCESS
:
448 case LPC2000_INVALID_SECTOR
:
449 return ERROR_FLASH_SECTOR_INVALID
;
452 WARNING("lpc2000 erase sectors returned %i", status_code
);
453 return ERROR_FLASH_OPERATION_FAILED
;
459 int lpc2000_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
)
461 /* can't protect/unprotect on the lpc2000 */
465 int lpc2000_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
)
467 lpc2000_flash_bank_t
*lpc2000_info
= bank
->driver_priv
;
468 target_t
*target
= bank
->target
;
469 u32 dst_min_alignment
;
470 u32 bytes_remaining
= count
;
471 u32 bytes_written
= 0;
472 int first_sector
= 0;
478 working_area_t
*download_area
;
480 if (bank
->target
->state
!= TARGET_HALTED
)
482 return ERROR_TARGET_NOT_HALTED
;
485 /* allocate a working area */
486 if (target_alloc_working_area(target
, 4096, &download_area
) != ERROR_OK
)
488 ERROR("no working area specified, can't write LPC2000 internal flash");
489 return ERROR_FLASH_OPERATION_FAILED
;
492 if (offset
+ count
> bank
->size
)
493 return ERROR_FLASH_DST_OUT_OF_BANK
;
495 if (lpc2000_info
->cmd51_can_256b
)
496 dst_min_alignment
= 256;
498 dst_min_alignment
= 512;
500 if (offset
% dst_min_alignment
)
502 WARNING("offset 0x%x breaks required alignment 0x%x", offset
, dst_min_alignment
);
503 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
506 for (i
= 0; i
< bank
->num_sectors
; i
++)
508 if (offset
>= bank
->sectors
[i
].offset
)
510 if (offset
+ CEIL(count
, dst_min_alignment
) * dst_min_alignment
> bank
->sectors
[i
].offset
)
514 DEBUG("first_sector: %i, last_sector: %i", first_sector
, last_sector
);
516 /* check if exception vectors should be flashed */
517 if ((offset
== 0) && (count
>= 0x20) && lpc2000_info
->calc_checksum
)
521 for (i
= 0; i
< 8; i
++)
523 DEBUG("0x%2.2x: 0x%8.8x", i
* 4, buf_get_u32(buffer
+ (i
* 4), 0, 32));
525 checksum
+= buf_get_u32(buffer
+ (i
* 4), 0, 32);
527 checksum
= 0 - checksum
;
528 DEBUG("checksum: 0x%8.8x", checksum
);
529 buf_set_u32(buffer
+ 0x14, 0, 32, checksum
);
532 while (bytes_remaining
> 0)
535 if (bytes_remaining
>= 4096)
536 thisrun_bytes
= 4096;
537 else if (bytes_remaining
>= 1024)
538 thisrun_bytes
= 1024;
539 else if ((bytes_remaining
>= 512) || (!lpc2000_info
->cmd51_can_256b
))
544 /* Prepare sectors */
545 param_table
[0] = first_sector
;
546 param_table
[1] = last_sector
;
547 status_code
= lpc2000_iap_call(bank
, 50, param_table
, result_table
);
550 case ERROR_FLASH_OPERATION_FAILED
:
551 return ERROR_FLASH_OPERATION_FAILED
;
552 case LPC2000_CMD_SUCCESS
:
554 case LPC2000_INVALID_SECTOR
:
555 return ERROR_FLASH_SECTOR_INVALID
;
558 WARNING("lpc2000 prepare sectors returned %i", status_code
);
559 return ERROR_FLASH_OPERATION_FAILED
;
562 if (bytes_remaining
>= thisrun_bytes
)
564 if (target_write_buffer(bank
->target
, download_area
->address
, thisrun_bytes
, buffer
+ bytes_written
) != ERROR_OK
)
566 target_free_working_area(target
, download_area
);
567 return ERROR_FLASH_OPERATION_FAILED
;
572 u8
*last_buffer
= malloc(thisrun_bytes
);
574 memcpy(last_buffer
, buffer
+ bytes_written
, bytes_remaining
);
575 for (i
= bytes_remaining
; i
< thisrun_bytes
; i
++)
576 last_buffer
[i
] = 0xff;
577 target_write_buffer(bank
->target
, download_area
->address
, thisrun_bytes
, last_buffer
);
581 DEBUG("writing 0x%x bytes to address 0x%x", thisrun_bytes
, bank
->base
+ offset
+ bytes_written
);
584 param_table
[0] = bank
->base
+ offset
+ bytes_written
;
585 param_table
[1] = download_area
->address
;
586 param_table
[2] = thisrun_bytes
;
587 param_table
[3] = lpc2000_info
->cclk
;
588 status_code
= lpc2000_iap_call(bank
, 51, param_table
, result_table
);
591 case ERROR_FLASH_OPERATION_FAILED
:
592 return ERROR_FLASH_OPERATION_FAILED
;
593 case LPC2000_CMD_SUCCESS
:
595 case LPC2000_INVALID_SECTOR
:
596 return ERROR_FLASH_SECTOR_INVALID
;
599 WARNING("lpc2000 returned %i", status_code
);
600 return ERROR_FLASH_OPERATION_FAILED
;
603 if (bytes_remaining
> thisrun_bytes
)
604 bytes_remaining
-= thisrun_bytes
;
607 bytes_written
+= thisrun_bytes
;
610 target_free_working_area(target
, download_area
);
615 int lpc2000_probe(struct flash_bank_s
*bank
)
617 /* we can't probe on an lpc2000
618 * if this is an lpc2xxx, it has the configured flash
623 int lpc2000_erase_check(struct flash_bank_s
*bank
)
625 if (bank
->target
->state
!= TARGET_HALTED
)
627 return ERROR_TARGET_NOT_HALTED
;
630 return lpc2000_iap_blank_check(bank
, 0, bank
->num_sectors
- 1);
633 int lpc2000_protect_check(struct flash_bank_s
*bank
)
635 /* sectors are always protected */
639 int lpc2000_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
641 lpc2000_flash_bank_t
*lpc2000_info
= bank
->driver_priv
;
643 snprintf(buf
, buf_size
, "lpc2000 flash driver variant: %i, clk: %i", lpc2000_info
->variant
, lpc2000_info
->cclk
);
648 int lpc2000_handle_part_id_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
654 lpc2000_flash_bank_t
*lpc2000_info
;
658 command_print(cmd_ctx
, "usage: lpc2000 part_id <num>");
662 bank
= get_flash_bank_by_num(strtoul(args
[0], NULL
, 0));
665 command_print(cmd_ctx
, "flash bank '#%s' is out of bounds", args
[0]);
669 lpc2000_info
= bank
->driver_priv
;
670 if (bank
->target
->state
!= TARGET_HALTED
)
672 return ERROR_TARGET_NOT_HALTED
;
675 if ((status_code
= lpc2000_iap_call(bank
, 54, param_table
, result_table
)) != 0x0)
677 if (status_code
== ERROR_FLASH_OPERATION_FAILED
)
679 command_print(cmd_ctx
, "no sufficient working area specified, can't access LPC2000 IAP interface");
682 command_print(cmd_ctx
, "lpc2000 IAP returned status code %i", status_code
);
686 command_print(cmd_ctx
, "lpc2000 part id: 0x%8.8x", result_table
[0]);
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)