jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / flash / nor / w600.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2018 by Simon Qian *
5 * SimonQian@SimonQian.com *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "imp.h"
13 #include <helper/binarybuffer.h>
14 #include <target/algorithm.h>
15 #include <target/armv7m.h>
16
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
21
22 /* w600 register locations */
23
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)
28
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)
34
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)
40
41 #define QFLASH_START (1ul << 28)
42 #define QFLASH_ADDR(addr) (((addr) & 0xFFFFF) << 8)
43 #define QFLASH_CRM(crm) (((crm) & 0xFF) << 0)
44
45 struct w600_flash_param {
46 uint8_t id;
47 uint8_t se_delay;
48 uint8_t pp_delay;
49 };
50 static const struct w600_flash_param w600_param[] = {
51 {
52 .id = 0x85,
53 .se_delay = 8,
54 .pp_delay = 2,
55 },
56 {
57 .id = 0x1C,
58 .se_delay = 50,
59 .pp_delay = 1,
60 },
61 {
62 .id = 0xC8,
63 .se_delay = 45,
64 .pp_delay = 1,
65 },
66 {
67 .id = 0x0B,
68 .se_delay = 60,
69 .pp_delay = 1,
70 },
71 {
72 .id = 0x68,
73 .se_delay = 50,
74 .pp_delay = 1,
75 },
76 };
77
78 struct w600_flash_bank {
79 bool probed;
80
81 uint32_t id;
82 const struct w600_flash_param *param;
83 uint32_t register_base;
84 uint32_t user_bank_size;
85 };
86
87 /* flash bank w600 <base> <size> 0 0 <target#>
88 */
89 FLASH_BANK_COMMAND_HANDLER(w600_flash_bank_command)
90 {
91 struct w600_flash_bank *w600_info;
92
93 if (CMD_ARGC < 6)
94 return ERROR_COMMAND_SYNTAX_ERROR;
95
96 w600_info = malloc(sizeof(struct w600_flash_bank));
97
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;
102
103 return ERROR_OK;
104 }
105
106 static int w600_get_delay(struct flash_bank *bank, uint32_t cmd)
107 {
108 struct w600_flash_bank *w600_info = bank->driver_priv;
109
110 if (!w600_info->param)
111 return 0;
112
113 switch (cmd) {
114 case QFLASH_CMD_SE:
115 return w600_info->param->se_delay;
116 case QFLASH_CMD_PP:
117 return w600_info->param->pp_delay;
118 default:
119 return 0;
120 }
121 }
122
123 static int w600_start_do(struct flash_bank *bank, uint32_t cmd, uint32_t addr,
124 uint32_t len, int timeout)
125 {
126 struct target *target = bank->target;
127
128 if (len > 0)
129 cmd |= QFLASH_CMD_DATALEN(len - 1) | QFLASH_CMD_DATA;
130
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)
134 return retval;
135
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)
140 return retval;
141
142 LOG_DEBUG("DELAY %dms", timeout);
143 alive_sleep(timeout);
144
145 int retry = 100;
146 uint32_t status;
147 for (;;) {
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);
152 else
153 LOG_DEBUG("READ START FAILED");
154
155 if ((retval != ERROR_OK) || (status & QFLASH_START)) {
156 if (retry-- <= 0) {
157 LOG_ERROR("timed out waiting for flash");
158 return ERROR_FAIL;
159 }
160 continue;
161 }
162 break;
163 }
164
165 return retval;
166 }
167
168 static int w600_write_enable(struct flash_bank *bank)
169 {
170 return w600_start_do(bank, QFLASH_CMD_WREN, 0, 0, 0);
171 }
172
173 static int w600_write_disable(struct flash_bank *bank)
174 {
175 return w600_start_do(bank, QFLASH_CMD_WRDI, 0, 0, 0);
176 }
177
178 static int w600_start(struct flash_bank *bank, uint32_t cmd, uint32_t addr,
179 uint32_t len)
180 {
181 int retval = w600_write_enable(bank);
182 if (retval != ERROR_OK)
183 return retval;
184
185 retval = w600_start_do(bank, cmd, addr, len, w600_get_delay(bank, cmd));
186 if (retval != ERROR_OK)
187 return retval;
188
189 retval = w600_write_disable(bank);
190 if (retval != ERROR_OK)
191 return retval;
192
193 return retval;
194 }
195
196 static int w600_erase(struct flash_bank *bank, unsigned int first,
197 unsigned int last)
198 {
199 int retval = ERROR_OK;
200
201 if (bank->target->state != TARGET_HALTED) {
202 LOG_ERROR("Target not halted");
203 return ERROR_TARGET_NOT_HALTED;
204 }
205 if (first < W600_FLASH_PROTECT_SIZE / W600_FLASH_SECSIZE) {
206 LOG_ERROR("can not erase protected area");
207 return ERROR_FAIL;
208 }
209
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)
214 break;
215 }
216
217 return retval;
218 }
219
220 static int w600_write(struct flash_bank *bank, const uint8_t *buffer,
221 uint32_t offset, uint32_t count)
222 {
223 struct target *target = bank->target;
224 int retval = ERROR_OK;
225
226 if (bank->target->state != TARGET_HALTED) {
227 LOG_ERROR("Target not halted");
228 return ERROR_TARGET_NOT_HALTED;
229 }
230
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;
235 }
236
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;
241 }
242
243 while (count > 0) {
244 retval = target_write_buffer(target, QFLASH_BUFFER, W600_FLASH_PAGESIZE, buffer);
245 if (retval != ERROR_OK)
246 break;
247
248 retval = w600_start(bank, QFLASH_CMD_PP, QFLASH_ADDR(offset),
249 W600_FLASH_PAGESIZE);
250 if (retval != ERROR_OK)
251 break;
252
253 count -= W600_FLASH_PAGESIZE;
254 offset += W600_FLASH_PAGESIZE;
255 buffer += W600_FLASH_PAGESIZE;
256 }
257
258 return retval;
259 }
260
261 static int w600_get_flash_id(struct flash_bank *bank, uint32_t *flash_id)
262 {
263 struct target *target = bank->target;
264
265 int retval = w600_start(bank, QFLASH_CMD_RDID, 0, 4);
266 if (retval != ERROR_OK)
267 return retval;
268
269 return target_read_u32(target, QFLASH_BUFFER, flash_id);
270 }
271
272 static int w600_probe(struct flash_bank *bank)
273 {
274 struct w600_flash_bank *w600_info = bank->driver_priv;
275 uint32_t flash_size;
276 uint32_t flash_id;
277 size_t i;
278
279 w600_info->probed = false;
280
281 /* read stm32 device id register */
282 int retval = w600_get_flash_id(bank, &flash_id);
283 if (retval != ERROR_OK)
284 return retval;
285
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];
292 break;
293 }
294 }
295 if (!w600_info->param) {
296 LOG_ERROR("flash_id not supported for w600");
297 return ERROR_FAIL;
298 }
299
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;
305 } else {
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");
309 return ERROR_FAIL;
310 }
311
312 flash_size = 1 << flash_size;
313 }
314
315 LOG_INFO("flash size = %" PRIu32 " KiB", flash_size / 1024);
316
317 /* calculate numbers of pages */
318 size_t num_pages = flash_size / W600_FLASH_SECSIZE;
319
320 /* check that calculation result makes sense */
321 assert(num_pages > 0);
322
323 free(bank->sectors);
324 bank->sectors = NULL;
325
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);
332
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);
339 }
340
341 w600_info->probed = true;
342
343 return ERROR_OK;
344 }
345
346 static int w600_auto_probe(struct flash_bank *bank)
347 {
348 struct w600_flash_bank *w600_info = bank->driver_priv;
349 if (w600_info->probed)
350 return ERROR_OK;
351 return w600_probe(bank);
352 }
353
354 static int get_w600_info(struct flash_bank *bank, struct command_invocation *cmd)
355 {
356 uint32_t flash_id;
357
358 /* read w600 device id register */
359 int retval = w600_get_flash_id(bank, &flash_id);
360 if (retval != ERROR_OK)
361 return retval;
362
363 command_print_sameline(cmd, "w600 : 0x%08" PRIx32 "", flash_id);
364 return ERROR_OK;
365 }
366
367 const struct flash_driver w600_flash = {
368 .name = "w600",
369 .flash_bank_command = w600_flash_bank_command,
370 .erase = w600_erase,
371 .write = w600_write,
372 .read = default_flash_read,
373 .probe = w600_probe,
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,
378 };

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)