flash: fix typos and duplicated words
[fw/openocd] / 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         bool 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 = false;
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, unsigned int first,
208                 unsigned int last)
209 {
210         int retval = ERROR_OK;
211
212         if (bank->target->state != TARGET_HALTED) {
213                 LOG_ERROR("Target not halted");
214                 return ERROR_TARGET_NOT_HALTED;
215         }
216         if (first < W600_FLASH_PROTECT_SIZE / W600_FLASH_SECSIZE) {
217                 LOG_ERROR("can not erase protected area");
218                 return ERROR_FAIL;
219         }
220
221         for (unsigned int i = first; i <= last; i++) {
222                 retval = w600_start(bank, QFLASH_CMD_SE,
223                         QFLASH_ADDR(bank->sectors[i].offset), 0);
224                 if (retval != ERROR_OK)
225                         break;
226         }
227
228         return retval;
229 }
230
231 static int w600_write(struct flash_bank *bank, const uint8_t *buffer,
232                 uint32_t offset, uint32_t count)
233 {
234         struct target *target = bank->target;
235         int retval = ERROR_OK;
236
237         if (bank->target->state != TARGET_HALTED) {
238                 LOG_ERROR("Target not halted");
239                 return ERROR_TARGET_NOT_HALTED;
240         }
241
242         if ((offset % W600_FLASH_PAGESIZE) != 0) {
243                 LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment",
244                         offset, W600_FLASH_PAGESIZE);
245                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
246         }
247
248         if ((count % W600_FLASH_PAGESIZE) != 0) {
249                 LOG_WARNING("count 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment",
250                         offset, W600_FLASH_PAGESIZE);
251                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
252         }
253
254         while (count > 0) {
255                 retval = target_write_buffer(target, QFLASH_BUFFER, W600_FLASH_PAGESIZE, buffer);
256                 if (retval != ERROR_OK)
257                         break;
258
259                 retval = w600_start(bank, QFLASH_CMD_PP, QFLASH_ADDR(offset),
260                                 W600_FLASH_PAGESIZE);
261                 if (retval != ERROR_OK)
262                         break;
263
264                 count -= W600_FLASH_PAGESIZE;
265                 offset += W600_FLASH_PAGESIZE;
266                 buffer += W600_FLASH_PAGESIZE;
267         }
268
269         return retval;
270 }
271
272 static int w600_get_flash_id(struct flash_bank *bank, uint32_t *flash_id)
273 {
274         struct target *target = bank->target;
275
276         int retval = w600_start(bank, QFLASH_CMD_RDID, 0, 4);
277         if (retval != ERROR_OK)
278                 return retval;
279
280         return target_read_u32(target, QFLASH_BUFFER, flash_id);
281 }
282
283 static int w600_probe(struct flash_bank *bank)
284 {
285         struct w600_flash_bank *w600_info = bank->driver_priv;
286         uint32_t flash_size;
287         uint32_t flash_id;
288         size_t i;
289
290         w600_info->probed = false;
291
292         /* read stm32 device id register */
293         int retval = w600_get_flash_id(bank, &flash_id);
294         if (retval != ERROR_OK)
295                 return retval;
296
297         LOG_INFO("flash_id id = 0x%08" PRIx32 "", flash_id);
298         w600_info->id = flash_id;
299         w600_info->param = NULL;
300         for (i = 0; i < ARRAY_SIZE(w600_param); i++) {
301                 if (w600_param[i].id == (flash_id & 0xFF)) {
302                         w600_info->param = &w600_param[i];
303                         break;
304                 }
305         }
306         if (!w600_info->param) {
307                 LOG_ERROR("flash_id not supported for w600");
308                 return ERROR_FAIL;
309         }
310
311         /* if the user sets the size manually then ignore the probed value
312          * this allows us to work around devices that have a invalid flash size register value */
313         if (w600_info->user_bank_size) {
314                 LOG_INFO("ignoring flash probed value, using configured bank size");
315                 flash_size = w600_info->user_bank_size;
316         } else {
317                 flash_size = ((flash_id & 0xFFFFFF) >> 16) & 0xFF;
318                 if ((flash_size != 0x14) && (flash_size != 0x13)) {
319                         LOG_ERROR("w600 flash size failed, probe inaccurate");
320                         return ERROR_FAIL;
321                 }
322
323                 flash_size = 1 << flash_size;
324         }
325
326         LOG_INFO("flash size = %dkbytes", flash_size / 1024);
327
328         /* calculate numbers of pages */
329         size_t num_pages = flash_size / W600_FLASH_SECSIZE;
330
331         /* check that calculation result makes sense */
332         assert(num_pages > 0);
333
334         if (bank->sectors) {
335                 free(bank->sectors);
336                 bank->sectors = NULL;
337         }
338
339         bank->base = W600_FLASH_BASE;
340         bank->size = num_pages * W600_FLASH_SECSIZE;
341         bank->num_sectors = num_pages;
342         bank->write_start_alignment = W600_FLASH_PAGESIZE;
343         bank->write_end_alignment = W600_FLASH_PAGESIZE;
344         bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
345
346         for (i = 0; i < num_pages; i++) {
347                 bank->sectors[i].offset = i * W600_FLASH_SECSIZE;
348                 bank->sectors[i].size = W600_FLASH_SECSIZE;
349                 bank->sectors[i].is_erased = -1;
350                 /* offset 0 to W600_FLASH_PROTECT_SIZE should be protected */
351                 bank->sectors[i].is_protected = (i < W600_FLASH_PROTECT_SIZE / W600_FLASH_SECSIZE);
352         }
353
354         w600_info->probed = true;
355
356         return ERROR_OK;
357 }
358
359 static int w600_auto_probe(struct flash_bank *bank)
360 {
361         struct w600_flash_bank *w600_info = bank->driver_priv;
362         if (w600_info->probed)
363                 return ERROR_OK;
364         return w600_probe(bank);
365 }
366
367 static int get_w600_info(struct flash_bank *bank, char *buf, int buf_size)
368 {
369         uint32_t flash_id;
370
371         /* read w600 device id register */
372         int retval = w600_get_flash_id(bank, &flash_id);
373         if (retval != ERROR_OK)
374                 return retval;
375
376         snprintf(buf, buf_size, "w600 : 0x%08" PRIx32 "", flash_id);
377         return ERROR_OK;
378 }
379
380 const struct flash_driver w600_flash = {
381         .name = "w600",
382         .flash_bank_command = w600_flash_bank_command,
383         .erase = w600_erase,
384         .write = w600_write,
385         .read = default_flash_read,
386         .probe = w600_probe,
387         .auto_probe = w600_auto_probe,
388         .erase_check = default_flash_blank_check,
389         .info = get_w600_info,
390         .free_driver_priv = default_flash_free_driver_priv,
391 };