1 /***************************************************************************
2 * Copyright (C) 2018 by Simon Qian *
3 * SimonQian@SimonQian.com *
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, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
24 #include <helper/binarybuffer.h>
25 #include <target/algorithm.h>
26 #include <target/armv7m.h>
28 #define W600_FLASH_SECSIZE 0x1000
29 #define W600_FLASH_PAGESIZE 0x100
30 #define W600_FLASH_BASE 0x08000000
31 #define W600_FLASH_PROTECT_SIZE 0x2000
33 /* w600 register locations */
35 #define QFLASH_REGBASE 0X40002000
36 #define QFLASH_CMD_INFO (QFLASH_REGBASE + 0)
37 #define QFLASH_CMD_START (QFLASH_REGBASE + 4)
38 #define QFLASH_BUFFER (QFLASH_REGBASE + 0X200)
40 #define QFLASH_CMD_READ (1ul << 14)
41 #define QFLASH_CMD_WRITE 0
42 #define QFLASH_CMD_ADDR (1ul << 31)
43 #define QFLASH_CMD_DATA (1ul << 15)
44 #define QFLASH_CMD_DATALEN(len) (((len) & 0x3FF) << 16)
46 #define QFLASH_CMD_RDID (QFLASH_CMD_READ | 0x9F)
47 #define QFLASH_CMD_WREN (QFLASH_CMD_WRITE | 0x06)
48 #define QFLASH_CMD_WRDI (QFLASH_CMD_WRITE | 0x04)
49 #define QFLASH_CMD_SE (QFLASH_CMD_WRITE | QFLASH_CMD_ADDR | (1ul << 11) | 0x20)
50 #define QFLASH_CMD_PP (QFLASH_CMD_WRITE | QFLASH_CMD_ADDR | (1ul << 12) | 0x02)
52 #define QFLASH_START (1ul << 28)
53 #define QFLASH_ADDR(addr) (((addr) & 0xFFFFF) << 8)
54 #define QFLASH_CRM(crm) (((crm) & 0xFF) << 0)
56 struct w600_flash_param
{
61 static const struct w600_flash_param w600_param
[] = {
89 struct w600_flash_bank
{
93 const struct w600_flash_param
*param
;
94 uint32_t register_base
;
95 uint32_t user_bank_size
;
98 /* flash bank w600 <base> <size> 0 0 <target#>
100 FLASH_BANK_COMMAND_HANDLER(w600_flash_bank_command
)
102 struct w600_flash_bank
*w600_info
;
105 return ERROR_COMMAND_SYNTAX_ERROR
;
107 w600_info
= malloc(sizeof(struct w600_flash_bank
));
109 bank
->driver_priv
= w600_info
;
110 w600_info
->probed
= 0;
111 w600_info
->register_base
= QFLASH_REGBASE
;
112 w600_info
->user_bank_size
= bank
->size
;
117 static int w600_get_delay(struct flash_bank
*bank
, uint32_t cmd
)
119 struct w600_flash_bank
*w600_info
= bank
->driver_priv
;
121 if (!w600_info
->param
)
126 return w600_info
->param
->se_delay
;
128 return w600_info
->param
->pp_delay
;
134 static int w600_start_do(struct flash_bank
*bank
, uint32_t cmd
, uint32_t addr
,
135 uint32_t len
, int timeout
)
137 struct target
*target
= bank
->target
;
140 cmd
|= QFLASH_CMD_DATALEN(len
- 1) | QFLASH_CMD_DATA
;
142 LOG_DEBUG("WRITE CMD: 0x%08" PRIx32
"", cmd
);
143 int retval
= target_write_u32(target
, QFLASH_CMD_INFO
, cmd
);
144 if (retval
!= ERROR_OK
)
147 addr
|= QFLASH_START
;
148 LOG_DEBUG("WRITE START: 0x%08" PRIx32
"", addr
);
149 retval
= target_write_u32(target
, QFLASH_CMD_START
, addr
);
150 if (retval
!= ERROR_OK
)
153 LOG_DEBUG("DELAY %dms", timeout
);
154 alive_sleep(timeout
);
159 LOG_DEBUG("READ START...");
160 retval
= target_read_u32(target
, QFLASH_CMD_START
, &status
);
161 if (retval
== ERROR_OK
)
162 LOG_DEBUG("READ START: 0x%08" PRIx32
"", status
);
164 LOG_DEBUG("READ START FAILED");
166 if ((retval
!= ERROR_OK
) || (status
& QFLASH_START
)) {
168 LOG_ERROR("timed out waiting for flash");
179 static int w600_write_enable(struct flash_bank
*bank
)
181 return w600_start_do(bank
, QFLASH_CMD_WREN
, 0, 0, 0);
184 static int w600_write_disable(struct flash_bank
*bank
)
186 return w600_start_do(bank
, QFLASH_CMD_WRDI
, 0, 0, 0);
189 static int w600_start(struct flash_bank
*bank
, uint32_t cmd
, uint32_t addr
,
192 int retval
= w600_write_enable(bank
);
193 if (retval
!= ERROR_OK
)
196 retval
= w600_start_do(bank
, cmd
, addr
, len
, w600_get_delay(bank
, cmd
));
197 if (retval
!= ERROR_OK
)
200 retval
= w600_write_disable(bank
);
201 if (retval
!= ERROR_OK
)
207 static int w600_erase(struct flash_bank
*bank
, int first
, int last
)
209 int retval
= ERROR_OK
;
211 if (bank
->target
->state
!= TARGET_HALTED
) {
212 LOG_ERROR("Target not halted");
213 return ERROR_TARGET_NOT_HALTED
;
215 if (first
< W600_FLASH_PROTECT_SIZE
/ W600_FLASH_SECSIZE
) {
216 LOG_ERROR("can not erase protected area");
220 for (int i
= first
; i
<= last
; i
++) {
221 retval
= w600_start(bank
, QFLASH_CMD_SE
,
222 QFLASH_ADDR(bank
->sectors
[i
].offset
), 0);
223 if (retval
!= ERROR_OK
)
230 static int w600_write(struct flash_bank
*bank
, const uint8_t *buffer
,
231 uint32_t offset
, uint32_t count
)
233 struct target
*target
= bank
->target
;
234 int retval
= ERROR_OK
;
236 if (bank
->target
->state
!= TARGET_HALTED
) {
237 LOG_ERROR("Target not halted");
238 return ERROR_TARGET_NOT_HALTED
;
241 if ((offset
% W600_FLASH_PAGESIZE
) != 0) {
242 LOG_WARNING("offset 0x%" PRIx32
" breaks required %" PRIu32
"-byte alignment",
243 offset
, W600_FLASH_PAGESIZE
);
244 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
247 if ((count
% W600_FLASH_PAGESIZE
) != 0) {
248 LOG_WARNING("count 0x%" PRIx32
" breaks required %" PRIu32
"-byte alignment",
249 offset
, W600_FLASH_PAGESIZE
);
250 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
254 retval
= target_write_buffer(target
, QFLASH_BUFFER
, W600_FLASH_PAGESIZE
, buffer
);
255 if (retval
!= ERROR_OK
)
258 retval
= w600_start(bank
, QFLASH_CMD_PP
, QFLASH_ADDR(offset
),
259 W600_FLASH_PAGESIZE
);
260 if (retval
!= ERROR_OK
)
263 count
-= W600_FLASH_PAGESIZE
;
264 offset
+= W600_FLASH_PAGESIZE
;
265 buffer
+= W600_FLASH_PAGESIZE
;
271 static int w600_get_flash_id(struct flash_bank
*bank
, uint32_t *flash_id
)
273 struct target
*target
= bank
->target
;
275 int retval
= w600_start(bank
, QFLASH_CMD_RDID
, 0, 4);
276 if (retval
!= ERROR_OK
)
279 return target_read_u32(target
, QFLASH_BUFFER
, flash_id
);
282 static int w600_probe(struct flash_bank
*bank
)
284 struct w600_flash_bank
*w600_info
= bank
->driver_priv
;
289 w600_info
->probed
= 0;
291 /* read stm32 device id register */
292 int retval
= w600_get_flash_id(bank
, &flash_id
);
293 if (retval
!= ERROR_OK
)
296 LOG_INFO("flash_id id = 0x%08" PRIx32
"", flash_id
);
297 w600_info
->id
= flash_id
;
298 w600_info
->param
= NULL
;
299 for (i
= 0; i
< ARRAY_SIZE(w600_param
); i
++) {
300 if (w600_param
[i
].id
== (flash_id
& 0xFF)) {
301 w600_info
->param
= &w600_param
[i
];
305 if (!w600_info
->param
) {
306 LOG_ERROR("flash_id not supported for w600");
310 /* if the user sets the size manually then ignore the probed value
311 * this allows us to work around devices that have a invalid flash size register value */
312 if (w600_info
->user_bank_size
) {
313 LOG_INFO("ignoring flash probed value, using configured bank size");
314 flash_size
= w600_info
->user_bank_size
;
316 flash_size
= ((flash_id
& 0xFFFFFF) >> 16) & 0xFF;
317 if ((flash_size
!= 0x14) && (flash_size
!= 0x13)) {
318 LOG_ERROR("w600 flash size failed, probe inaccurate");
322 flash_size
= 1 << flash_size
;
325 LOG_INFO("flash size = %dkbytes", flash_size
/ 1024);
327 /* calculate numbers of pages */
328 size_t num_pages
= flash_size
/ W600_FLASH_SECSIZE
;
330 /* check that calculation result makes sense */
331 assert(num_pages
> 0);
335 bank
->sectors
= NULL
;
338 bank
->base
= W600_FLASH_BASE
;
339 bank
->size
= num_pages
* W600_FLASH_SECSIZE
;
340 bank
->num_sectors
= num_pages
;
341 bank
->write_start_alignment
= W600_FLASH_PAGESIZE
;
342 bank
->write_end_alignment
= W600_FLASH_PAGESIZE
;
343 bank
->sectors
= malloc(sizeof(struct flash_sector
) * num_pages
);
345 for (i
= 0; i
< num_pages
; i
++) {
346 bank
->sectors
[i
].offset
= i
* W600_FLASH_SECSIZE
;
347 bank
->sectors
[i
].size
= W600_FLASH_SECSIZE
;
348 bank
->sectors
[i
].is_erased
= -1;
349 /* offset 0 to W600_FLASH_PROTECT_SIZE shoule be protected */
350 bank
->sectors
[i
].is_protected
= (i
< W600_FLASH_PROTECT_SIZE
/ W600_FLASH_SECSIZE
);
353 w600_info
->probed
= 1;
358 static int w600_auto_probe(struct flash_bank
*bank
)
360 struct w600_flash_bank
*w600_info
= bank
->driver_priv
;
361 if (w600_info
->probed
)
363 return w600_probe(bank
);
366 static int get_w600_info(struct flash_bank
*bank
, char *buf
, int buf_size
)
370 /* read w600 device id register */
371 int retval
= w600_get_flash_id(bank
, &flash_id
);
372 if (retval
!= ERROR_OK
)
375 snprintf(buf
, buf_size
, "w600 : 0x%08" PRIx32
"", flash_id
);
379 const struct flash_driver w600_flash
= {
381 .flash_bank_command
= w600_flash_bank_command
,
384 .read
= default_flash_read
,
386 .auto_probe
= w600_auto_probe
,
387 .erase_check
= default_flash_blank_check
,
388 .info
= get_w600_info
,
389 .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)