3d376161784e4579056ad7c2c9d264d2c55351ed
[openocd.git] / src / flash / nor / w600.c
1 /***************************************************************************
2 * Copyright (C) 2018 by Simon Qian *
3 * SimonQian@SimonQian.com *
4 * *
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. *
9 * *
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. *
14 * *
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 ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "imp.h"
24 #include <helper/binarybuffer.h>
25 #include <target/algorithm.h>
26 #include <target/armv7m.h>
27
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
32
33 /* w600 register locations */
34
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)
39
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)
45
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)
51
52 #define QFLASH_START (1ul << 28)
53 #define QFLASH_ADDR(addr) (((addr) & 0xFFFFF) << 8)
54 #define QFLASH_CRM(crm) (((crm) & 0xFF) << 0)
55
56 struct w600_flash_param {
57 uint8_t id;
58 uint8_t se_delay;
59 uint8_t pp_delay;
60 };
61 static const struct w600_flash_param w600_param[] = {
62 {
63 .id = 0x85,
64 .se_delay = 8,
65 .pp_delay = 2,
66 },
67 {
68 .id = 0x1C,
69 .se_delay = 50,
70 .pp_delay = 1,
71 },
72 {
73 .id = 0xC8,
74 .se_delay = 45,
75 .pp_delay = 1,
76 },
77 {
78 .id = 0x0B,
79 .se_delay = 60,
80 .pp_delay = 1,
81 },
82 {
83 .id = 0x68,
84 .se_delay = 50,
85 .pp_delay = 1,
86 },
87 };
88
89 struct w600_flash_bank {
90 int probed;
91
92 uint32_t id;
93 const struct w600_flash_param *param;
94 uint32_t register_base;
95 uint32_t user_bank_size;
96 };
97
98 /* flash bank w600 <base> <size> 0 0 <target#>
99 */
100 FLASH_BANK_COMMAND_HANDLER(w600_flash_bank_command)
101 {
102 struct w600_flash_bank *w600_info;
103
104 if (CMD_ARGC < 6)
105 return ERROR_COMMAND_SYNTAX_ERROR;
106
107 w600_info = malloc(sizeof(struct w600_flash_bank));
108
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;
113
114 return ERROR_OK;
115 }
116
117 static int w600_get_delay(struct flash_bank *bank, uint32_t cmd)
118 {
119 struct w600_flash_bank *w600_info = bank->driver_priv;
120
121 if (!w600_info->param)
122 return 0;
123
124 switch (cmd) {
125 case QFLASH_CMD_SE:
126 return w600_info->param->se_delay;
127 case QFLASH_CMD_PP:
128 return w600_info->param->pp_delay;
129 default:
130 return 0;
131 }
132 }
133
134 static int w600_start_do(struct flash_bank *bank, uint32_t cmd, uint32_t addr,
135 uint32_t len, int timeout)
136 {
137 struct target *target = bank->target;
138
139 if (len > 0)
140 cmd |= QFLASH_CMD_DATALEN(len - 1) | QFLASH_CMD_DATA;
141
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)
145 return retval;
146
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)
151 return retval;
152
153 LOG_DEBUG("DELAY %dms", timeout);
154 alive_sleep(timeout);
155
156 int retry = 100;
157 uint32_t status;
158 for (;;) {
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);
163 else
164 LOG_DEBUG("READ START FAILED");
165
166 if ((retval != ERROR_OK) || (status & QFLASH_START)) {
167 if (retry-- <= 0) {
168 LOG_ERROR("timed out waiting for flash");
169 return ERROR_FAIL;
170 }
171 continue;
172 }
173 break;
174 }
175
176 return retval;
177 }
178
179 static int w600_write_enable(struct flash_bank *bank)
180 {
181 return w600_start_do(bank, QFLASH_CMD_WREN, 0, 0, 0);
182 }
183
184 static int w600_write_disable(struct flash_bank *bank)
185 {
186 return w600_start_do(bank, QFLASH_CMD_WRDI, 0, 0, 0);
187 }
188
189 static int w600_start(struct flash_bank *bank, uint32_t cmd, uint32_t addr,
190 uint32_t len)
191 {
192 int retval = w600_write_enable(bank);
193 if (retval != ERROR_OK)
194 return retval;
195
196 retval = w600_start_do(bank, cmd, addr, len, w600_get_delay(bank, cmd));
197 if (retval != ERROR_OK)
198 return retval;
199
200 retval = w600_write_disable(bank);
201 if (retval != ERROR_OK)
202 return retval;
203
204 return retval;
205 }
206
207 static int w600_erase(struct flash_bank *bank, int first, int last)
208 {
209 int retval = ERROR_OK;
210
211 if (bank->target->state != TARGET_HALTED) {
212 LOG_ERROR("Target not halted");
213 return ERROR_TARGET_NOT_HALTED;
214 }
215 if (first < W600_FLASH_PROTECT_SIZE / W600_FLASH_SECSIZE) {
216 LOG_ERROR("can not erase protected area");
217 return ERROR_FAIL;
218 }
219
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)
224 break;
225 }
226
227 return retval;
228 }
229
230 static int w600_write(struct flash_bank *bank, const uint8_t *buffer,
231 uint32_t offset, uint32_t count)
232 {
233 struct target *target = bank->target;
234 int retval = ERROR_OK;
235
236 if (bank->target->state != TARGET_HALTED) {
237 LOG_ERROR("Target not halted");
238 return ERROR_TARGET_NOT_HALTED;
239 }
240
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;
245 }
246
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;
251 }
252
253 while (count > 0) {
254 retval = target_write_buffer(target, QFLASH_BUFFER, W600_FLASH_PAGESIZE, buffer);
255 if (retval != ERROR_OK)
256 break;
257
258 retval = w600_start(bank, QFLASH_CMD_PP, QFLASH_ADDR(offset),
259 W600_FLASH_PAGESIZE);
260 if (retval != ERROR_OK)
261 break;
262
263 count -= W600_FLASH_PAGESIZE;
264 offset += W600_FLASH_PAGESIZE;
265 buffer += W600_FLASH_PAGESIZE;
266 }
267
268 return retval;
269 }
270
271 static int w600_get_flash_id(struct flash_bank *bank, uint32_t *flash_id)
272 {
273 struct target *target = bank->target;
274
275 int retval = w600_start(bank, QFLASH_CMD_RDID, 0, 4);
276 if (retval != ERROR_OK)
277 return retval;
278
279 return target_read_u32(target, QFLASH_BUFFER, flash_id);
280 }
281
282 static int w600_probe(struct flash_bank *bank)
283 {
284 struct w600_flash_bank *w600_info = bank->driver_priv;
285 uint32_t flash_size;
286 uint32_t flash_id;
287 size_t i;
288
289 w600_info->probed = 0;
290
291 /* read stm32 device id register */
292 int retval = w600_get_flash_id(bank, &flash_id);
293 if (retval != ERROR_OK)
294 return retval;
295
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];
302 break;
303 }
304 }
305 if (!w600_info->param) {
306 LOG_ERROR("flash_id not supported for w600");
307 return ERROR_FAIL;
308 }
309
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;
315 } else {
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");
319 return ERROR_FAIL;
320 }
321
322 flash_size = 1 << flash_size;
323 }
324
325 LOG_INFO("flash size = %dkbytes", flash_size / 1024);
326
327 /* calculate numbers of pages */
328 size_t num_pages = flash_size / W600_FLASH_SECSIZE;
329
330 /* check that calculation result makes sense */
331 assert(num_pages > 0);
332
333 if (bank->sectors) {
334 free(bank->sectors);
335 bank->sectors = NULL;
336 }
337
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);
344
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);
351 }
352
353 w600_info->probed = 1;
354
355 return ERROR_OK;
356 }
357
358 static int w600_auto_probe(struct flash_bank *bank)
359 {
360 struct w600_flash_bank *w600_info = bank->driver_priv;
361 if (w600_info->probed)
362 return ERROR_OK;
363 return w600_probe(bank);
364 }
365
366 static int get_w600_info(struct flash_bank *bank, char *buf, int buf_size)
367 {
368 uint32_t flash_id;
369
370 /* read w600 device id register */
371 int retval = w600_get_flash_id(bank, &flash_id);
372 if (retval != ERROR_OK)
373 return retval;
374
375 snprintf(buf, buf_size, "w600 : 0x%08" PRIx32 "", flash_id);
376 return ERROR_OK;
377 }
378
379 struct flash_driver w600_flash = {
380 .name = "w600",
381 .flash_bank_command = w600_flash_bank_command,
382 .erase = w600_erase,
383 .write = w600_write,
384 .read = default_flash_read,
385 .probe = w600_probe,
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,
390 };

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)