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