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

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)