openocd: src/flash: replace the GPL-2.0-or-later license tag
[openocd.git] / src / flash / nor / w600.c
blob52105bd6d9db2b08e3645d627bc1698bb7a5f24f
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2018 by Simon Qian *
5 * SimonQian@SimonQian.com *
6 ***************************************************************************/
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
12 #include "imp.h"
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 {
46 uint8_t id;
47 uint8_t se_delay;
48 uint8_t pp_delay;
50 static const struct w600_flash_param w600_param[] = {
52 .id = 0x85,
53 .se_delay = 8,
54 .pp_delay = 2,
57 .id = 0x1C,
58 .se_delay = 50,
59 .pp_delay = 1,
62 .id = 0xC8,
63 .se_delay = 45,
64 .pp_delay = 1,
67 .id = 0x0B,
68 .se_delay = 60,
69 .pp_delay = 1,
72 .id = 0x68,
73 .se_delay = 50,
74 .pp_delay = 1,
78 struct w600_flash_bank {
79 bool probed;
81 uint32_t id;
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;
93 if (CMD_ARGC < 6)
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;
103 return ERROR_OK;
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)
111 return 0;
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;
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;
128 if (len > 0)
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)
134 return retval;
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;
142 LOG_DEBUG("DELAY %dms", timeout);
143 alive_sleep(timeout);
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");
155 if ((retval != ERROR_OK) || (status & QFLASH_START)) {
156 if (retry-- <= 0) {
157 LOG_ERROR("timed out waiting for flash");
158 return ERROR_FAIL;
160 continue;
162 break;
165 return retval;
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,
179 uint32_t len)
181 int retval = w600_write_enable(bank);
182 if (retval != ERROR_OK)
183 return retval;
185 retval = w600_start_do(bank, cmd, addr, len, w600_get_delay(bank, cmd));
186 if (retval != ERROR_OK)
187 return retval;
189 retval = w600_write_disable(bank);
190 if (retval != ERROR_OK)
191 return retval;
193 return retval;
196 static int w600_erase(struct flash_bank *bank, unsigned int first,
197 unsigned int last)
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");
207 return ERROR_FAIL;
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;
217 return retval;
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;
243 while (count > 0) {
244 retval = target_write_buffer(target, QFLASH_BUFFER, W600_FLASH_PAGESIZE, buffer);
245 if (retval != ERROR_OK)
246 break;
248 retval = w600_start(bank, QFLASH_CMD_PP, QFLASH_ADDR(offset),
249 W600_FLASH_PAGESIZE);
250 if (retval != ERROR_OK)
251 break;
253 count -= W600_FLASH_PAGESIZE;
254 offset += W600_FLASH_PAGESIZE;
255 buffer += W600_FLASH_PAGESIZE;
258 return retval;
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)
267 return retval;
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;
275 uint32_t flash_size;
276 uint32_t flash_id;
277 size_t i;
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)
284 return retval;
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;
295 if (!w600_info->param) {
296 LOG_ERROR("flash_id not supported for w600");
297 return ERROR_FAIL;
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;
312 flash_size = 1 << flash_size;
315 LOG_INFO("flash size = %" PRIu32 "kbytes", 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);
323 free(bank->sectors);
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;
343 return ERROR_OK;
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)
350 return ERROR_OK;
351 return w600_probe(bank);
354 static int get_w600_info(struct flash_bank *bank, struct command_invocation *cmd)
356 uint32_t flash_id;
358 /* read w600 device id register */
359 int retval = w600_get_flash_id(bank, &flash_id);
360 if (retval != ERROR_OK)
361 return retval;
363 command_print_sameline(cmd, "w600 : 0x%08" PRIx32 "", flash_id);
364 return ERROR_OK;
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,