flash/stm32l4x: introduce table with register offsets
[openocd.git] / src / flash / nor / bluenrg-x.c
1 /***************************************************************************
2 * Copyright (C) 2017 by Michele Sardo *
3 * msmttchr@gmail.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 <target/algorithm.h>
24 #include <target/armv7m.h>
25 #include <target/cortex_m.h>
26 #include "imp.h"
27 #include "bluenrg-x.h"
28
29 #define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg)
30 #define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg)
31
32 #define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg)
33 #define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg)
34 #define FLASH_PAGE_SIZE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_page_size)
35
36 struct flash_ctrl_priv_data {
37 uint32_t die_id_reg;
38 uint32_t jtag_idcode_reg;
39 uint32_t flash_base;
40 uint32_t flash_regs_base;
41 uint32_t flash_page_size;
42 uint32_t jtag_idcode;
43 char *part_name;
44 };
45
46 static const struct flash_ctrl_priv_data flash_priv_data_1 = {
47 .die_id_reg = 0x4090001C,
48 .jtag_idcode_reg = 0x40900028,
49 .flash_base = 0x10040000,
50 .flash_regs_base = 0x40100000,
51 .flash_page_size = 2048,
52 .jtag_idcode = 0x00000000,
53 .part_name = "BLUENRG-1",
54 };
55
56 static const struct flash_ctrl_priv_data flash_priv_data_2 = {
57 .die_id_reg = 0x4090001C,
58 .jtag_idcode_reg = 0x40900028,
59 .flash_base = 0x10040000,
60 .flash_regs_base = 0x40100000,
61 .flash_page_size = 2048,
62 .jtag_idcode = 0x0200A041,
63 .part_name = "BLUENRG-2",
64 };
65
66 static const struct flash_ctrl_priv_data flash_priv_data_lp = {
67 .die_id_reg = 0x40000000,
68 .jtag_idcode_reg = 0x40000004,
69 .flash_base = 0x10040000,
70 .flash_regs_base = 0x40001000,
71 .flash_page_size = 2048,
72 .jtag_idcode = 0x0201E041,
73 .part_name = "BLUENRG-LP",
74 };
75
76 struct bluenrgx_flash_bank {
77 bool probed;
78 uint32_t die_id;
79 const struct flash_ctrl_priv_data *flash_ptr;
80 };
81
82 static const struct flash_ctrl_priv_data *flash_ctrl[] = {
83 &flash_priv_data_1,
84 &flash_priv_data_2,
85 &flash_priv_data_lp
86 };
87
88 /* flash_bank bluenrg-x 0 0 0 0 <target#> */
89 FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
90 {
91 struct bluenrgx_flash_bank *bluenrgx_info;
92 /* Create the bank structure */
93 bluenrgx_info = calloc(1, sizeof(*bluenrgx_info));
94
95 /* Check allocation */
96 if (bluenrgx_info == NULL) {
97 LOG_ERROR("failed to allocate bank structure");
98 return ERROR_FAIL;
99 }
100
101 bank->write_start_alignment = 16;
102 bank->write_end_alignment = 16;
103
104 bank->driver_priv = bluenrgx_info;
105
106 bluenrgx_info->probed = false;
107
108 if (CMD_ARGC < 6)
109 return ERROR_COMMAND_SYNTAX_ERROR;
110
111 return ERROR_OK;
112 }
113
114 static inline uint32_t bluenrgx_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
115 {
116 struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
117 return bluenrgx_info->flash_ptr->flash_regs_base + reg_offset;
118 }
119
120 static inline int bluenrgx_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
121 {
122 return target_read_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value);
123 }
124
125 static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
126 {
127 return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value);
128 }
129
130 static int bluenrgx_erase(struct flash_bank *bank, unsigned int first,
131 unsigned int last)
132 {
133 int retval = ERROR_OK;
134 struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
135 unsigned int num_sectors = (last - first + 1);
136 const bool mass_erase = (num_sectors == bank->num_sectors);
137 struct target *target = bank->target;
138 uint32_t address, command;
139
140 /* check preconditions */
141 if (!bluenrgx_info->probed)
142 return ERROR_FLASH_BANK_NOT_PROBED;
143
144 if (bank->target->state != TARGET_HALTED) {
145 LOG_ERROR("Target not halted");
146 return ERROR_TARGET_NOT_HALTED;
147 }
148 /* Disable blue module */
149 if (target_write_u32(target, 0x200000c0, 0) != ERROR_OK) {
150 LOG_ERROR("Blue disable failed");
151 return ERROR_FAIL;
152 }
153
154 if (mass_erase) {
155 command = FLASH_CMD_MASSERASE;
156 address = bank->base;
157 if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
158 LOG_ERROR("Register write failed");
159 return ERROR_FAIL;
160 }
161
162 if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS,
163 (address - bank->base) >> 2) != ERROR_OK) {
164 LOG_ERROR("Register write failed");
165 return ERROR_FAIL;
166 }
167
168 if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) {
169 LOG_ERROR("Register write failed");
170 return ERROR_FAIL;
171 }
172
173 for (unsigned int i = 0; i < 100; i++) {
174 uint32_t value;
175 if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) {
176 LOG_ERROR("Register write failed");
177 return ERROR_FAIL;
178 }
179 if (value & FLASH_INT_CMDDONE)
180 break;
181 if (i == 99) {
182 LOG_ERROR("Mass erase command failed (timeout)");
183 retval = ERROR_FAIL;
184 }
185 }
186
187 } else {
188 command = FLASH_CMD_ERASE_PAGE;
189 for (unsigned int i = first; i <= last; i++) {
190 address = bank->base+i*FLASH_PAGE_SIZE(bluenrgx_info);
191 LOG_DEBUG("address = %08" PRIx32 ", index = %u", address, i);
192
193 if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
194 LOG_ERROR("Register write failed");
195 return ERROR_FAIL;
196 }
197
198 if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS,
199 (address - bank->base) >> 2) != ERROR_OK) {
200 LOG_ERROR("Register write failed");
201 return ERROR_FAIL;
202 }
203
204 if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) {
205 LOG_ERROR("Failed");
206 return ERROR_FAIL;
207 }
208
209 for (unsigned int j = 0; j < 100; j++) {
210 uint32_t value;
211 if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) {
212 LOG_ERROR("Register write failed");
213 return ERROR_FAIL;
214 }
215 if (value & FLASH_INT_CMDDONE)
216 break;
217 if (j == 99) {
218 LOG_ERROR("Erase command failed (timeout)");
219 retval = ERROR_FAIL;
220 }
221 }
222 }
223 }
224
225 return retval;
226
227 }
228
229 static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
230 uint32_t offset, uint32_t count)
231 {
232 struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
233 struct target *target = bank->target;
234 uint32_t buffer_size = 16384 + 8;
235 struct working_area *write_algorithm;
236 struct working_area *write_algorithm_sp;
237 struct working_area *source;
238 uint32_t address = bank->base + offset;
239 struct reg_param reg_params[5];
240 struct mem_param mem_params[1];
241 struct armv7m_algorithm armv7m_info;
242 int retval = ERROR_OK;
243
244 /* See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c for source and
245 * hints how to generate the data!
246 */
247 static const uint8_t bluenrgx_flash_write_code[] = {
248 #include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc"
249 };
250
251 /* check preconditions */
252 if (!bluenrgx_info->probed)
253 return ERROR_FLASH_BANK_NOT_PROBED;
254
255 if ((offset + count) > bank->size) {
256 LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %" PRIu32 ", size=%" PRIu32,
257 (offset + count),
258 bank->size);
259 return ERROR_FLASH_DST_OUT_OF_BANK;
260 }
261
262 if (bank->target->state != TARGET_HALTED) {
263 LOG_ERROR("Target not halted");
264 return ERROR_TARGET_NOT_HALTED;
265 }
266
267 if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code),
268 &write_algorithm) != ERROR_OK) {
269 LOG_WARNING("no working area available, can't do block memory writes");
270 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
271 }
272
273 retval = target_write_buffer(target, write_algorithm->address,
274 sizeof(bluenrgx_flash_write_code),
275 bluenrgx_flash_write_code);
276 if (retval != ERROR_OK)
277 return retval;
278
279 /* memory buffer */
280 if (target_alloc_working_area(target, buffer_size, &source)) {
281 LOG_WARNING("no large enough working area available");
282 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
283 }
284
285 /* Stack pointer area */
286 if (target_alloc_working_area(target, 128,
287 &write_algorithm_sp) != ERROR_OK) {
288 LOG_DEBUG("no working area for write code stack pointer");
289 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
290 }
291
292 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
293 armv7m_info.core_mode = ARM_MODE_THREAD;
294
295 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
296 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
297 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
298 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
299 init_reg_param(&reg_params[4], "sp", 32, PARAM_OUT);
300 /* Put the parameter at the first available stack location */
301 init_mem_param(&mem_params[0], write_algorithm_sp->address + 80, 32, PARAM_OUT);
302
303 /* FIFO start address (first two words used for write and read pointers) */
304 buf_set_u32(reg_params[0].value, 0, 32, source->address);
305 /* FIFO end address (first two words used for write and read pointers) */
306 buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
307 /* Flash memory address */
308 buf_set_u32(reg_params[2].value, 0, 32, address);
309 /* Number of bytes */
310 buf_set_u32(reg_params[3].value, 0, 32, count);
311 /* Stack pointer for program working area */
312 buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address);
313 /* Flash register base address */
314 buf_set_u32(mem_params[0].value, 0, 32, bluenrgx_info->flash_ptr->flash_regs_base);
315
316 LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address);
317 LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size);
318 LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address);
319 LOG_DEBUG("address = %08" PRIx32, address);
320 LOG_DEBUG("count = %08" PRIx32, count);
321
322 retval = target_run_flash_async_algorithm(target,
323 buffer,
324 count/16,
325 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */
326 1,
327 mem_params,
328 5,
329 reg_params,
330 source->address,
331 source->size,
332 write_algorithm->address,
333 0,
334 &armv7m_info);
335
336 if (retval == ERROR_FLASH_OPERATION_FAILED) {
337 LOG_ERROR("error executing bluenrg-x flash write algorithm");
338
339 uint32_t error = buf_get_u32(reg_params[0].value, 0, 32);
340
341 if (error != 0)
342 LOG_ERROR("flash write failed = %08" PRIx32, error);
343 }
344 if (retval == ERROR_OK) {
345 uint32_t rp;
346 /* Read back rp and check that is valid */
347 retval = target_read_u32(target, source->address+4, &rp);
348 if (retval == ERROR_OK) {
349 if ((rp < source->address+8) || (rp > (source->address + source->size))) {
350 LOG_ERROR("flash write failed = %08" PRIx32, rp);
351 retval = ERROR_FLASH_OPERATION_FAILED;
352 }
353 }
354 }
355 target_free_working_area(target, source);
356 target_free_working_area(target, write_algorithm);
357 target_free_working_area(target, write_algorithm_sp);
358
359 destroy_reg_param(&reg_params[0]);
360 destroy_reg_param(&reg_params[1]);
361 destroy_reg_param(&reg_params[2]);
362 destroy_reg_param(&reg_params[3]);
363 destroy_reg_param(&reg_params[4]);
364 destroy_mem_param(&mem_params[0]);
365
366 return retval;
367 }
368
369 static int bluenrgx_probe(struct flash_bank *bank)
370 {
371 struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
372 uint32_t idcode, size_info, die_id;
373 int retval = target_read_u32(bank->target, BLUENRGLP_JTAG_REG, &idcode);
374
375 if (retval != ERROR_OK)
376 return retval;
377
378 if (idcode != flash_priv_data_lp.jtag_idcode) {
379 retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode);
380 if (retval != ERROR_OK)
381 return retval;
382 }
383
384 /* Default device is BlueNRG-1 */
385 bluenrgx_info->flash_ptr = &flash_priv_data_1;
386 bank->base = flash_priv_data_1.flash_base;
387
388 for (size_t i = 0; i < ARRAY_SIZE(flash_ctrl); i++) {
389 if (idcode == (*flash_ctrl[i]).jtag_idcode) {
390 bluenrgx_info->flash_ptr = flash_ctrl[i];
391 bank->base = (*flash_ctrl[i]).flash_base;
392 break;
393 }
394 }
395 retval = bluenrgx_read_flash_reg(bank, FLASH_SIZE_REG, &size_info);
396 if (retval != ERROR_OK)
397 return retval;
398
399 retval = target_read_u32(bank->target, DIE_ID_REG(bluenrgx_info), &die_id);
400 if (retval != ERROR_OK)
401 return retval;
402
403 bank->size = (size_info + 1) * FLASH_WORD_LEN;
404 bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info);
405 bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors);
406
407 for (unsigned int i = 0; i < bank->num_sectors; i++) {
408 bank->sectors[i].offset = i * FLASH_PAGE_SIZE(bluenrgx_info);
409 bank->sectors[i].size = FLASH_PAGE_SIZE(bluenrgx_info);
410 bank->sectors[i].is_erased = -1;
411 bank->sectors[i].is_protected = 0;
412 }
413
414 bluenrgx_info->probed = true;
415 bluenrgx_info->die_id = die_id;
416
417 return ERROR_OK;
418 }
419
420 static int bluenrgx_auto_probe(struct flash_bank *bank)
421 {
422 struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
423
424 if (bluenrgx_info->probed)
425 return ERROR_OK;
426
427 return bluenrgx_probe(bank);
428 }
429
430 /* This method must return a string displaying information about the bank */
431 static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
432 {
433 struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
434 int mask_number, cut_number;
435
436 if (!bluenrgx_info->probed) {
437 int retval = bluenrgx_probe(bank);
438 if (retval != ERROR_OK) {
439 snprintf(buf, buf_size,
440 "Unable to find bank information.");
441 return retval;
442 }
443 }
444
445 mask_number = (bluenrgx_info->die_id >> 4) & 0xF;
446 cut_number = bluenrgx_info->die_id & 0xF;
447
448 snprintf(buf, buf_size,
449 "%s - Rev: %d.%d", bluenrgx_info->flash_ptr->part_name, mask_number, cut_number);
450 return ERROR_OK;
451 }
452
453 const struct flash_driver bluenrgx_flash = {
454 .name = "bluenrg-x",
455 .flash_bank_command = bluenrgx_flash_bank_command,
456 .erase = bluenrgx_erase,
457 .protect = NULL,
458 .write = bluenrgx_write,
459 .read = default_flash_read,
460 .probe = bluenrgx_probe,
461 .erase_check = default_flash_blank_check,
462 .protect_check = NULL,
463 .auto_probe = bluenrgx_auto_probe,
464 .info = bluenrgx_get_info,
465 };

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)