1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2018 by Simon Qian *
5 * SimonQian@SimonQian.com *
6 ***************************************************************************/
13 #include <helper/binarybuffer.h>
14 #include <target/algorithm.h>
15 #include <target/armv7m.h>
17 #define W600_FLASH_SECSIZE 0x1000
18 #define W600_FLASH_PAGESIZE 0x100
19 #define W600_FLASH_BASE 0x08000000
20 #define W600_FLASH_PROTECT_SIZE 0x2000
22 /* w600 register locations */
24 #define QFLASH_REGBASE 0X40002000
25 #define QFLASH_CMD_INFO (QFLASH_REGBASE + 0)
26 #define QFLASH_CMD_START (QFLASH_REGBASE + 4)
27 #define QFLASH_BUFFER (QFLASH_REGBASE + 0X200)
29 #define QFLASH_CMD_READ (1ul << 14)
30 #define QFLASH_CMD_WRITE 0
31 #define QFLASH_CMD_ADDR (1ul << 31)
32 #define QFLASH_CMD_DATA (1ul << 15)
33 #define QFLASH_CMD_DATALEN(len) (((len) & 0x3FF) << 16)
35 #define QFLASH_CMD_RDID (QFLASH_CMD_READ | 0x9F)
36 #define QFLASH_CMD_WREN (QFLASH_CMD_WRITE | 0x06)
37 #define QFLASH_CMD_WRDI (QFLASH_CMD_WRITE | 0x04)
38 #define QFLASH_CMD_SE (QFLASH_CMD_WRITE | QFLASH_CMD_ADDR | (1ul << 11) | 0x20)
39 #define QFLASH_CMD_PP (QFLASH_CMD_WRITE | QFLASH_CMD_ADDR | (1ul << 12) | 0x02)
41 #define QFLASH_START (1ul << 28)
42 #define QFLASH_ADDR(addr) (((addr) & 0xFFFFF) << 8)
43 #define QFLASH_CRM(crm) (((crm) & 0xFF) << 0)
45 struct w600_flash_param
{
50 static const struct w600_flash_param w600_param
[] = {
78 struct w600_flash_bank
{
82 const struct w600_flash_param
*param
;
83 uint32_t register_base
;
84 uint32_t user_bank_size
;
87 /* flash bank w600 <base> <size> 0 0 <target#>
89 FLASH_BANK_COMMAND_HANDLER(w600_flash_bank_command
)
91 struct w600_flash_bank
*w600_info
;
94 return ERROR_COMMAND_SYNTAX_ERROR
;
96 w600_info
= malloc(sizeof(struct w600_flash_bank
));
98 bank
->driver_priv
= w600_info
;
99 w600_info
->probed
= false;
100 w600_info
->register_base
= QFLASH_REGBASE
;
101 w600_info
->user_bank_size
= bank
->size
;
106 static int w600_get_delay(struct flash_bank
*bank
, uint32_t cmd
)
108 struct w600_flash_bank
*w600_info
= bank
->driver_priv
;
110 if (!w600_info
->param
)
115 return w600_info
->param
->se_delay
;
117 return w600_info
->param
->pp_delay
;
123 static int w600_start_do(struct flash_bank
*bank
, uint32_t cmd
, uint32_t addr
,
124 uint32_t len
, int timeout
)
126 struct target
*target
= bank
->target
;
129 cmd
|= QFLASH_CMD_DATALEN(len
- 1) | QFLASH_CMD_DATA
;
131 LOG_DEBUG("WRITE CMD: 0x%08" PRIx32
"", cmd
);
132 int retval
= target_write_u32(target
, QFLASH_CMD_INFO
, cmd
);
133 if (retval
!= ERROR_OK
)
136 addr
|= QFLASH_START
;
137 LOG_DEBUG("WRITE START: 0x%08" PRIx32
"", addr
);
138 retval
= target_write_u32(target
, QFLASH_CMD_START
, addr
);
139 if (retval
!= ERROR_OK
)
142 LOG_DEBUG("DELAY %dms", timeout
);
143 alive_sleep(timeout
);
148 LOG_DEBUG("READ START...");
149 retval
= target_read_u32(target
, QFLASH_CMD_START
, &status
);
150 if (retval
== ERROR_OK
)
151 LOG_DEBUG("READ START: 0x%08" PRIx32
"", status
);
153 LOG_DEBUG("READ START FAILED");
155 if ((retval
!= ERROR_OK
) || (status
& QFLASH_START
)) {
157 LOG_ERROR("timed out waiting for flash");
168 static int w600_write_enable(struct flash_bank
*bank
)
170 return w600_start_do(bank
, QFLASH_CMD_WREN
, 0, 0, 0);
173 static int w600_write_disable(struct flash_bank
*bank
)
175 return w600_start_do(bank
, QFLASH_CMD_WRDI
, 0, 0, 0);
178 static int w600_start(struct flash_bank
*bank
, uint32_t cmd
, uint32_t addr
,
181 int retval
= w600_write_enable(bank
);
182 if (retval
!= ERROR_OK
)
185 retval
= w600_start_do(bank
, cmd
, addr
, len
, w600_get_delay(bank
, cmd
));
186 if (retval
!= ERROR_OK
)
189 retval
= w600_write_disable(bank
);
190 if (retval
!= ERROR_OK
)
196 static int w600_erase(struct flash_bank
*bank
, unsigned int first
,
199 int retval
= ERROR_OK
;
201 if (bank
->target
->state
!= TARGET_HALTED
) {
202 LOG_ERROR("Target not halted");
203 return ERROR_TARGET_NOT_HALTED
;
205 if (first
< W600_FLASH_PROTECT_SIZE
/ W600_FLASH_SECSIZE
) {
206 LOG_ERROR("can not erase protected area");
210 for (unsigned int i
= first
; i
<= last
; i
++) {
211 retval
= w600_start(bank
, QFLASH_CMD_SE
,
212 QFLASH_ADDR(bank
->sectors
[i
].offset
), 0);
213 if (retval
!= ERROR_OK
)
220 static int w600_write(struct flash_bank
*bank
, const uint8_t *buffer
,
221 uint32_t offset
, uint32_t count
)
223 struct target
*target
= bank
->target
;
224 int retval
= ERROR_OK
;
226 if (bank
->target
->state
!= TARGET_HALTED
) {
227 LOG_ERROR("Target not halted");
228 return ERROR_TARGET_NOT_HALTED
;
231 if ((offset
% W600_FLASH_PAGESIZE
) != 0) {
232 LOG_WARNING("offset 0x%" PRIx32
" breaks required %d-byte alignment",
233 offset
, W600_FLASH_PAGESIZE
);
234 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
237 if ((count
% W600_FLASH_PAGESIZE
) != 0) {
238 LOG_WARNING("count 0x%" PRIx32
" breaks required %d-byte alignment",
239 offset
, W600_FLASH_PAGESIZE
);
240 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
244 retval
= target_write_buffer(target
, QFLASH_BUFFER
, W600_FLASH_PAGESIZE
, buffer
);
245 if (retval
!= ERROR_OK
)
248 retval
= w600_start(bank
, QFLASH_CMD_PP
, QFLASH_ADDR(offset
),
249 W600_FLASH_PAGESIZE
);
250 if (retval
!= ERROR_OK
)
253 count
-= W600_FLASH_PAGESIZE
;
254 offset
+= W600_FLASH_PAGESIZE
;
255 buffer
+= W600_FLASH_PAGESIZE
;
261 static int w600_get_flash_id(struct flash_bank
*bank
, uint32_t *flash_id
)
263 struct target
*target
= bank
->target
;
265 int retval
= w600_start(bank
, QFLASH_CMD_RDID
, 0, 4);
266 if (retval
!= ERROR_OK
)
269 return target_read_u32(target
, QFLASH_BUFFER
, flash_id
);
272 static int w600_probe(struct flash_bank
*bank
)
274 struct w600_flash_bank
*w600_info
= bank
->driver_priv
;
279 w600_info
->probed
= false;
281 /* read stm32 device id register */
282 int retval
= w600_get_flash_id(bank
, &flash_id
);
283 if (retval
!= ERROR_OK
)
286 LOG_INFO("flash_id id = 0x%08" PRIx32
"", flash_id
);
287 w600_info
->id
= flash_id
;
288 w600_info
->param
= NULL
;
289 for (i
= 0; i
< ARRAY_SIZE(w600_param
); i
++) {
290 if (w600_param
[i
].id
== (flash_id
& 0xFF)) {
291 w600_info
->param
= &w600_param
[i
];
295 if (!w600_info
->param
) {
296 LOG_ERROR("flash_id not supported for w600");
300 /* if the user sets the size manually then ignore the probed value
301 * this allows us to work around devices that have a invalid flash size register value */
302 if (w600_info
->user_bank_size
) {
303 LOG_INFO("ignoring flash probed value, using configured bank size");
304 flash_size
= w600_info
->user_bank_size
;
306 flash_size
= ((flash_id
& 0xFFFFFF) >> 16) & 0xFF;
307 if ((flash_size
!= 0x14) && (flash_size
!= 0x13)) {
308 LOG_ERROR("w600 flash size failed, probe inaccurate");
312 flash_size
= 1 << flash_size
;
315 LOG_INFO("flash size = %" PRIu32
" KiB", flash_size
/ 1024);
317 /* calculate numbers of pages */
318 size_t num_pages
= flash_size
/ W600_FLASH_SECSIZE
;
320 /* check that calculation result makes sense */
321 assert(num_pages
> 0);
324 bank
->sectors
= NULL
;
326 bank
->base
= W600_FLASH_BASE
;
327 bank
->size
= num_pages
* W600_FLASH_SECSIZE
;
328 bank
->num_sectors
= num_pages
;
329 bank
->write_start_alignment
= W600_FLASH_PAGESIZE
;
330 bank
->write_end_alignment
= W600_FLASH_PAGESIZE
;
331 bank
->sectors
= malloc(sizeof(struct flash_sector
) * num_pages
);
333 for (i
= 0; i
< num_pages
; i
++) {
334 bank
->sectors
[i
].offset
= i
* W600_FLASH_SECSIZE
;
335 bank
->sectors
[i
].size
= W600_FLASH_SECSIZE
;
336 bank
->sectors
[i
].is_erased
= -1;
337 /* offset 0 to W600_FLASH_PROTECT_SIZE should be protected */
338 bank
->sectors
[i
].is_protected
= (i
< W600_FLASH_PROTECT_SIZE
/ W600_FLASH_SECSIZE
);
341 w600_info
->probed
= true;
346 static int w600_auto_probe(struct flash_bank
*bank
)
348 struct w600_flash_bank
*w600_info
= bank
->driver_priv
;
349 if (w600_info
->probed
)
351 return w600_probe(bank
);
354 static int get_w600_info(struct flash_bank
*bank
, struct command_invocation
*cmd
)
358 /* read w600 device id register */
359 int retval
= w600_get_flash_id(bank
, &flash_id
);
360 if (retval
!= ERROR_OK
)
363 command_print_sameline(cmd
, "w600 : 0x%08" PRIx32
"", flash_id
);
367 const struct flash_driver w600_flash
= {
369 .flash_bank_command
= w600_flash_bank_command
,
372 .read
= default_flash_read
,
374 .auto_probe
= w600_auto_probe
,
375 .erase_check
= default_flash_blank_check
,
376 .info
= get_w600_info
,
377 .free_driver_priv
= default_flash_free_driver_priv
,
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)