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

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)