1 /***************************************************************************
2 * Copyright (C) 2013 Cosmin Gorgovan *
3 * cosmin [at] linux-geek [dot] org *
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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
22 Flash driver for the Nuvoton NuMicro Mini51 and M051 series microcontrollers
24 Part |APROM Size |Part ID (at 0x5000_0000)
25 ----------------------------------------------
26 MINI51LAN 4 KB 0x00205100
27 MINI51ZAN 4 KB 0x00205103
28 MINI51TAN 4 KB 0x00205104
29 MINI52LAN 8 KB 0x00205200
30 MINI52ZAN 8 KB 0x00205203
31 MINI52TAN 8 KB 0x00205204
32 MINI54LAN 16 KB 0x00205400
33 MINI54ZAN 16 KB 0x00205403
34 MINI54TAN 16 KB 0x00205404
35 M052LBN 8 KB 0x10005200
36 M054LBN 16 KB 0x10005400
37 M058LBN 32 KB 0x10005800
38 M0516LBN 64 KB 0x10005A00
39 M052ZBN 8 KB 0x10005203
40 M054ZBN 16 KB 0x10005403
41 M058ZBN 32 KB 0x10005803
42 M0516ZBN 64 KB 0x10005A03
43 M052LDN 8 KB 0x20005200
44 M054LDN 16 KB 0x20005400
45 M058LDN 32 KB 0x20005800
46 M0516LDN 64 KB 0x20005A00
47 M052ZDN 8 KB 0x20005203
48 M054ZDN 16 KB 0x20005403
49 M058ZDN 32 KB 0x20005803
50 M0516ZDN 64 KB 0x20005A03
51 M052LDE 8 KB 0x30005200
52 M054LDE 16 KB 0x30005400
53 M058LDE 32 KB 0x30005800
54 M0516LDE 64 KB 0x30005A00
55 M052ZDE 8 KB 0x30005203
56 M054ZDE 16 KB 0x30005403
57 M058ZDE 32 KB 0x30005803
58 M0516ZDE 64 KB 0x30005A03
63 The ISP flash programming procedure is described on pages 130 and 131 of the (not very verbose) TRM.
65 http://www.keil.com/dd/docs/datashts/nuvoton/mini51/da00-mini51_52_54c1.pdf
67 M051 ISP datasheet pages 190-206:
68 http://www.nuvoton.com/hq/resource-download.jsp?tp_GUID=DA05-M052-54-58-516
73 * chip_erase, erase, read and write operations have been implemented;
74 * All operations support APROM, LDROM, FLASH DATA and CONFIG;
76 Flash access limitations
77 ------------------------
79 For implementing the read operation, please note that the APROM isn't memory mapped when booted from LDROM.
88 #define PART_ID_REG 0x50000000
89 #define IPRSTC1 0x50000008
90 #define REGLOCKADDR 0x50000100
91 #define ISPCON 0x5000C000
92 #define ISPADR 0x5000C004
93 #define ISPDAT 0x5000C008
94 #define ISPCMD 0x5000C00C
95 #define ISPTRG 0x5000C010
96 /* Undocumented isp register */
97 #define ISPUNKNOWN 0x5000C01C
99 #define IPRSTC_CPU_RST 0x02
101 #define ISPCON_ISPFF 0x40
102 #define ISPCON_LDUEN 0x20
103 #define ISPCON_CFGUEN 0x10
104 #define ISPCON_APUEN 0x08
105 #define ISPCON_BS_LDROM 0x02
106 #define ISPCON_ISPEN 0x01
108 #define ISPCMD_READ 0x00
109 #define ISPCMD_PROGRAM 0x21
110 #define ISPCMD_ERASE 0x22
111 #define ISPCMD_CHIP_ERASE 0x26
113 #define ISPTRG_ISPGO 0x01
115 #define MINI51_APROM_BASE 0x00000000
116 #define MINI51_DATA_BASE 0x0001F000
117 #define MINI51_LDROM_BASE 0x00100000
118 #define MINI51_CONFIG_BASE 0x00300000
120 #define MINI51_KB 1024
121 #define MINI51_PAGE_SIZE 512
122 #define MINI51_TIMEOUT 1000
125 #define ENSURE_OK(status) if (status != ERROR_OK) return status
127 #define MINI51_MAX_FLASH_BANKS 4
129 struct mini51_flash_bank_type
{
134 struct mini51_cpu_type
{
138 struct mini51_flash_bank_type bank
[MINI51_MAX_FLASH_BANKS
];
141 #define MINI51_BANKS_MINI51(aprom_size) \
143 { {MINI51_APROM_BASE, (aprom_size)}, {MINI51_LDROM_BASE, 2*1024}, {MINI51_CONFIG_BASE, 512} }
145 #define MINI51_BANKS_M051(aprom_size) \
147 { {MINI51_APROM_BASE, (aprom_size)}, {MINI51_DATA_BASE, 4*1024}, {MINI51_LDROM_BASE, 4*1024}, \
148 {MINI51_CONFIG_BASE, 1024} }
150 static const struct mini51_cpu_type mini51_cpu
[] = {
151 { "MINI51LAN", 0x00205100, MINI51_BANKS_MINI51(4*1024) },
152 { "MINI51ZAN", 0x00205103, MINI51_BANKS_MINI51(4*1024) },
153 { "MINI51TAN", 0x00205104, MINI51_BANKS_MINI51(4*1024) },
154 { "MINI52LAN", 0x00205200, MINI51_BANKS_MINI51(8*1024) },
155 { "MINI52ZAN", 0x00205203, MINI51_BANKS_MINI51(8*1024) },
156 { "MINI52TAN", 0x00205204, MINI51_BANKS_MINI51(8*1024) },
157 { "MINI54LAN", 0x00205400, MINI51_BANKS_MINI51(16*1024) },
158 { "MINI54ZAN", 0x00205403, MINI51_BANKS_MINI51(16*1024) },
159 { "MINI54TAN", 0x00205404, MINI51_BANKS_MINI51(16*1024) },
161 { "M052LBN", 0x10005200, MINI51_BANKS_M051(8*1024) },
162 { "M054LBN", 0x10005400, MINI51_BANKS_M051(16*1024) },
163 { "M058LBN", 0x10005800, MINI51_BANKS_M051(32*1024) },
164 { "M0516LBN", 0x10005A00, MINI51_BANKS_M051(64*1024) },
165 { "M052ZBN", 0x10005203, MINI51_BANKS_M051(8*1024) },
166 { "M054ZBN", 0x10005403, MINI51_BANKS_M051(16*1024) },
167 { "M058ZBN", 0x10005803, MINI51_BANKS_M051(32*1024) },
168 { "M0516ZBN", 0x10005A03, MINI51_BANKS_M051(64*1024) },
169 { "M052LDN", 0x20005200, MINI51_BANKS_M051(8*1024) },
170 { "M054LDN", 0x20005400, MINI51_BANKS_M051(16*1024) },
171 { "M058LDN", 0x20005800, MINI51_BANKS_M051(32*1024) },
172 { "M0516LDN", 0x20005A00, MINI51_BANKS_M051(64*1024) },
173 { "M052ZDN", 0x20005203, MINI51_BANKS_M051(8*1024) },
174 { "M054ZDN", 0x20005403, MINI51_BANKS_M051(16*1024) },
175 { "M058ZDN", 0x20005803, MINI51_BANKS_M051(32*1024) },
176 { "M0516ZDN", 0x20005A03, MINI51_BANKS_M051(64*1024) },
177 { "M052LDE", 0x30005200, MINI51_BANKS_M051(8*1024) },
178 { "M054LDE", 0x30005400, MINI51_BANKS_M051(16*1024) },
179 { "M058LDE", 0x30005800, MINI51_BANKS_M051(32*1024) },
180 { "M0516LDE", 0x30005A00, MINI51_BANKS_M051(64*1024) },
181 { "M052ZDE", 0x30005203, MINI51_BANKS_M051(8*1024) },
182 { "M054ZDE", 0x30005403, MINI51_BANKS_M051(16*1024) },
183 { "M058ZDE", 0x30005803, MINI51_BANKS_M051(32*1024) },
184 { "M0516ZDE", 0x30005A03, MINI51_BANKS_M051(64*1024) },
187 struct mini51_flash_bank
{
189 const struct mini51_cpu_type
*cpu
;
192 /* Private methods */
194 static int mini51_unlock_reg(struct target
*target
)
197 status
= target_write_u32(target
, REGLOCKADDR
, 0x59);
198 if (status
!= ERROR_OK
)
200 status
= target_write_u32(target
, REGLOCKADDR
, 0x16);
201 if (status
!= ERROR_OK
)
203 status
= target_write_u32(target
, REGLOCKADDR
, 0x88);
204 if (status
!= ERROR_OK
)
211 static int mini51_get_part_id(struct target
*target
, uint32_t *part_id
)
213 int retu
= target_read_u32(target
, PART_ID_REG
, part_id
);
214 LOG_INFO("device id = 0x%08" PRIx32
"", *part_id
);
218 static int mini51_get_cpu_type(struct target
*target
, const struct mini51_cpu_type
** cpu
)
223 status
= mini51_get_part_id(target
, &part_id
);
226 for (size_t i
= 0; i
< sizeof(mini51_cpu
)/sizeof(mini51_cpu
[0]); i
++) {
227 if (part_id
== mini51_cpu
[i
].ppid
) {
228 *cpu
= &mini51_cpu
[i
];
229 LOG_INFO("device name = %s", (*cpu
)->name
);
234 return ERROR_FLASH_OPERATION_FAILED
;
237 static int mini51_get_flash_size(struct flash_bank
*bank
, const struct mini51_cpu_type
*cpu
, uint32_t *flash_size
)
239 for (size_t i
= 0; i
< cpu
->n_banks
; i
++) {
240 if (bank
->base
== cpu
->bank
[i
].base
) {
241 *flash_size
= cpu
->bank
[i
].size
;
242 LOG_INFO("bank base = 0x%08" PRIx32
", size = 0x%08" PRIx32
"", bank
->base
, *flash_size
);
246 return ERROR_FLASH_OPERATION_FAILED
;
249 static int mini51_isp_execute(struct target
*target
)
256 /* start ISP operation */
257 status
= target_write_u32(target
, ISPTRG
, ISPTRG_ISPGO
);
260 /* Wait for for command to finish executing */
261 timeout
= MINI51_TIMEOUT
;
263 target_read_u32(target
, ISPTRG
, &isptrg
);
265 } while ((isptrg
& ISPTRG_ISPGO
) && (timeout
> 0));
267 LOG_WARNING("Mini51 flash driver: Timeout executing flash command\n");
268 return ERROR_FLASH_OPERATION_FAILED
;
271 /* Check for errors */
272 status
= target_read_u32(target
, ISPCON
, &ispcon
);
274 if (ispcon
& ISPCON_ISPFF
) {
275 LOG_WARNING("Mini51 flash driver: operation failed\n");
276 return ERROR_FLASH_OPERATION_FAILED
;
281 static int mini51_isp_execute_cmd(struct target
*target
, uint32_t cmd
, uint32_t address
, uint32_t data
)
284 status
= target_write_u32(target
, ISPDAT
, data
);
286 status
= target_write_u32(target
, ISPADR
, address
);
288 status
= target_write_u32(target
, ISPCMD
, cmd
);
291 status
= mini51_isp_execute(target
);
295 static int mini51_isp_execute_cmd_read(struct target
*target
, uint32_t cmd
, uint32_t address
, uint32_t *data
)
298 status
= target_write_u32(target
, ISPADR
, address
);
300 status
= target_write_u32(target
, ISPCMD
, cmd
);
303 status
= mini51_isp_execute(target
);
306 status
= target_read_u32(target
, ISPDAT
, data
);
312 static int mini51_isp_enable(struct target
*target
)
317 if (target
->state
!= TARGET_HALTED
) {
318 LOG_ERROR("Target not halted");
319 return ERROR_TARGET_NOT_HALTED
;
322 status
= mini51_unlock_reg(target
);
324 status
= target_read_u32(target
, ISPCON
, &ispcon
);
326 ispcon
|= ISPCON_ISPEN
| ISPCON_LDUEN
| ISPCON_APUEN
| ISPCON_CFGUEN
;
327 status
= target_write_u32(target
, ISPCON
, ispcon
);
331 /* Public (API) methods */
333 FLASH_BANK_COMMAND_HANDLER(mini51_flash_bank_command
)
335 struct mini51_flash_bank
*mini51_info
;
336 mini51_info
= malloc(sizeof(struct mini51_flash_bank
));
337 mini51_info
->probed
= false;
338 bank
->driver_priv
= mini51_info
;
343 static int mini51_protect_check(struct flash_bank
*bank
)
345 LOG_WARNING("Mini51 flash driver: protect_check not implemented yet\n");
347 return ERROR_FLASH_OPERATION_FAILED
;
350 static int mini51_read(struct flash_bank
*bank
, uint8_t *buffer
, uint32_t offset
, uint32_t count
)
354 struct target
*target
= bank
->target
;
356 if ((offset
& 0x3) || (count
& 0x3)) {
357 LOG_WARNING("Mini51 flash driver: unaligned access not supported\n");
358 return ERROR_FLASH_OPERATION_FAILED
;
361 status
= mini51_isp_enable(target
);
364 for (uint32_t i
= offset
; i
< offset
+ count
; i
+= 4) {
365 status
= mini51_isp_execute_cmd_read(target
, ISPCMD_READ
, bank
->base
+ i
, &ispdat
);
366 memcpy(buffer
, &ispdat
, sizeof(ispdat
));
368 buffer
+= sizeof(ispdat
);
375 static int mini51_erase(struct flash_bank
*bank
, int first
, int last
)
378 struct target
*target
= bank
->target
;
381 status
= mini51_isp_enable(target
);
384 for (int page_start
= first
; page_start
<= last
; page_start
++) {
385 /* Set up erase command */
386 uint32_t address
= bank
->base
+ page_start
*MINI51_PAGE_SIZE
;
387 status
= mini51_isp_execute_cmd(target
, ISPCMD_ERASE
, address
, 0);
394 static int mini51_protect(struct flash_bank
*bank
, int set
, int first
, int last
)
396 LOG_WARNING("Mini51 flash driver: protect operation not implemented yet\n");
398 return ERROR_FLASH_OPERATION_FAILED
;
401 static int mini51_write(struct flash_bank
*bank
, const uint8_t *buffer
, uint32_t offset
, uint32_t count
)
405 struct target
*target
= bank
->target
;
407 if ((offset
& 0x3) || (count
& 0x3)) {
408 LOG_WARNING("Mini51 flash driver: unaligned access not supported\n");
409 return ERROR_FLASH_OPERATION_FAILED
;
412 status
= mini51_isp_enable(target
);
415 for (uint32_t i
= offset
; i
< offset
+ count
; i
+= 4) {
416 memcpy(&ispdat
, buffer
, sizeof(ispdat
));
417 status
= mini51_isp_execute_cmd(target
, ISPCMD_PROGRAM
, bank
->base
+ i
, ispdat
);
419 buffer
+= sizeof(ispdat
);
425 static int mini51_probe(struct flash_bank
*bank
)
431 const struct mini51_cpu_type
*cpu
;
432 struct target
*target
= bank
->target
;
434 status
= mini51_get_cpu_type(target
, &cpu
);
435 if (status
!= ERROR_OK
) {
436 LOG_WARNING("Mini51 flash driver: Failed to detect a known part\n");
437 return ERROR_FLASH_OPERATION_FAILED
;
440 status
= mini51_get_flash_size(bank
, cpu
, &flash_size
);
441 if (status
!= ERROR_OK
) {
442 LOG_WARNING("Mini51 flash driver: Failed to detect flash size\n");
443 return ERROR_FLASH_OPERATION_FAILED
;
446 num_pages
= flash_size
/ MINI51_PAGE_SIZE
;
448 bank
->num_sectors
= num_pages
;
449 bank
->sectors
= malloc(sizeof(struct flash_sector
) * num_pages
);
450 bank
->size
= flash_size
;
452 for (int i
= 0; i
< num_pages
; i
++) {
453 bank
->sectors
[i
].offset
= offset
;
454 bank
->sectors
[i
].size
= MINI51_PAGE_SIZE
;
455 bank
->sectors
[i
].is_erased
= -1;
456 bank
->sectors
[i
].is_protected
= 0;
457 offset
+= MINI51_PAGE_SIZE
;
460 struct mini51_flash_bank
*mini51_info
= bank
->driver_priv
;
461 mini51_info
->probed
= true;
462 mini51_info
->cpu
= cpu
;
467 static int mini51_auto_probe(struct flash_bank
*bank
)
469 struct mini51_flash_bank
*mini51_info
= bank
->driver_priv
;
470 if (mini51_info
->probed
)
472 return mini51_probe(bank
);
475 COMMAND_HANDLER(mini51_handle_read_isp_command
)
482 return ERROR_COMMAND_SYNTAX_ERROR
;
484 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
486 struct target
*target
= get_current_target(CMD_CTX
);
488 status
= mini51_isp_enable(target
);
490 status
= mini51_isp_execute_cmd_read(target
, ISPCMD_READ
, address
, &ispdat
);
492 LOG_INFO("0x%08" PRIx32
": 0x%08" PRIx32
, address
, ispdat
);
496 COMMAND_HANDLER(mini51_handle_write_isp_command
)
503 return ERROR_COMMAND_SYNTAX_ERROR
;
505 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
506 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], ispdat
);
508 struct target
*target
= get_current_target(CMD_CTX
);
510 status
= mini51_isp_enable(target
);
512 status
= mini51_isp_execute_cmd(target
, ISPCMD_PROGRAM
, address
, ispdat
);
514 LOG_INFO("0x%08" PRIx32
": 0x%08" PRIx32
, address
, ispdat
);
518 COMMAND_HANDLER(mini51_handle_chip_erase_command
)
522 return ERROR_COMMAND_SYNTAX_ERROR
;
524 struct target
*target
= get_current_target(CMD_CTX
);
526 status
= mini51_isp_enable(target
);
528 /* Write one to undocumented flash control register */
529 status
= target_write_u32(target
, ISPUNKNOWN
, 1);
532 status
= mini51_isp_execute_cmd(target
, ISPCMD_CHIP_ERASE
, 0, 0);
537 static const struct command_registration mini51_exec_command_handlers
[] = {
540 .handler
= mini51_handle_read_isp_command
,
542 .mode
= COMMAND_EXEC
,
543 .help
= "read flash through ISP.",
547 .handler
= mini51_handle_write_isp_command
,
548 .usage
= "address value",
549 .mode
= COMMAND_EXEC
,
550 .help
= "write flash through ISP.",
553 .name
= "chip_erase",
554 .handler
= mini51_handle_chip_erase_command
,
555 .mode
= COMMAND_EXEC
,
556 .help
= "chip erase.",
558 COMMAND_REGISTRATION_DONE
561 static const struct command_registration mini51_command_handlers
[] = {
565 .help
= "mini51 flash command group",
567 .chain
= mini51_exec_command_handlers
,
569 COMMAND_REGISTRATION_DONE
572 struct flash_driver mini51_flash
= {
574 .commands
= mini51_command_handlers
,
575 .flash_bank_command
= mini51_flash_bank_command
,
576 .erase
= mini51_erase
,
577 .protect
= mini51_protect
,
578 .write
= mini51_write
,
580 .probe
= mini51_probe
,
581 .auto_probe
= mini51_auto_probe
,
582 .erase_check
= default_flash_blank_check
,
583 .protect_check
= mini51_protect_check
,
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)