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

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)