Added support for STMicroelectronics BlueNRG-1 and BlueNRG-2 SoC
[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
28 #define FLASH_SIZE_REG (0x40100014)
29 #define DIE_ID_REG (0x4090001C)
30 #define JTAG_IDCODE_REG (0x40900028)
31 #define BLUENRG2_IDCODE (0x0200A041)
32 #define FLASH_BASE (0x10040000)
33 #define FLASH_PAGE_SIZE (2048)
34 #define FLASH_REG_COMMAND (0x40100000)
35 #define FLASH_REG_IRQRAW (0x40100010)
36 #define FLASH_REG_ADDRESS (0x40100018)
37 #define FLASH_REG_DATA (0x40100040)
38 #define FLASH_CMD_ERASE_PAGE 0x11
39 #define FLASH_CMD_MASSERASE 0x22
40 #define FLASH_CMD_WRITE 0x33
41 #define FLASH_CMD_BURSTWRITE 0xCC
42 #define FLASH_INT_CMDDONE 0x01
43 #define FLASH_WORD_LEN 4
44
45 struct bluenrgx_flash_bank {
46 int probed;
47 uint32_t idcode;
48 uint32_t die_id;
49 };
50
51 static int bluenrgx_protect_check(struct flash_bank *bank)
52 {
53 /* Nothing to do. Protection is only handled in SW. */
54 return ERROR_OK;
55 }
56
57 /* flash_bank bluenrg-x 0 0 0 0 <target#> */
58 FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
59 {
60 struct bluenrgx_flash_bank *bluenrgx_info;
61 /* Create the bank structure */
62 bluenrgx_info = calloc(1, sizeof(*bluenrgx_info));
63
64 /* Check allocation */
65 if (bluenrgx_info == NULL) {
66 LOG_ERROR("failed to allocate bank structure");
67 return ERROR_FAIL;
68 }
69
70 bank->driver_priv = bluenrgx_info;
71
72 bluenrgx_info->probed = 0;
73
74 if (CMD_ARGC < 6)
75 return ERROR_COMMAND_SYNTAX_ERROR;
76
77 return ERROR_OK;
78 }
79
80 static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
81 {
82 int retval = ERROR_OK;
83 struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
84 int num_sectors = (last - first + 1);
85 int mass_erase = (num_sectors == bank->num_sectors);
86 struct target *target = bank->target;
87 uint32_t address, command;
88
89 /* check preconditions */
90 if (bluenrgx_info->probed == 0)
91 return ERROR_FLASH_BANK_NOT_PROBED;
92
93 if (bank->target->state != TARGET_HALTED) {
94 LOG_ERROR("Target not halted");
95 return ERROR_TARGET_NOT_HALTED;
96 }
97 /* Disable blue module */
98 if (target_write_u32(target, 0x200000c0, 0) != ERROR_OK) {
99 LOG_ERROR("Blue disable failed");
100 return ERROR_FAIL;
101 }
102
103 if (mass_erase) {
104 command = FLASH_CMD_MASSERASE;
105 address = bank->base;
106 if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
107 LOG_ERROR("Register write failed");
108 return ERROR_FAIL;
109 }
110
111 if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) {
112 LOG_ERROR("Register write failed");
113 return ERROR_FAIL;
114 }
115
116 if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) {
117 LOG_ERROR("Register write failed");
118 return ERROR_FAIL;
119 }
120
121 for (int i = 0; i < 100; i++) {
122 uint32_t value;
123 if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) {
124 LOG_ERROR("Register write failed");
125 return ERROR_FAIL;
126 }
127 if (value & FLASH_INT_CMDDONE)
128 break;
129 if (i == 99) {
130 LOG_ERROR("Mass erase command failed (timeout)");
131 retval = ERROR_FAIL;
132 }
133 }
134
135 } else {
136 command = FLASH_CMD_ERASE_PAGE;
137 for (int i = first; i <= last; i++) {
138 address = bank->base+i*FLASH_PAGE_SIZE;
139
140 if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
141 LOG_ERROR("Register write failed");
142 return ERROR_FAIL;
143 }
144
145 if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) {
146 LOG_ERROR("Register write failed");
147 return ERROR_FAIL;
148 }
149
150 if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) {
151 LOG_ERROR("Failed");
152 return ERROR_FAIL;
153 }
154
155 for (int j = 0; j < 100; j++) {
156 uint32_t value;
157 if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) {
158 LOG_ERROR("Register write failed");
159 return ERROR_FAIL;
160 }
161 if (value & FLASH_INT_CMDDONE)
162 break;
163 if (j == 99) {
164 LOG_ERROR("Erase command failed (timeout)");
165 retval = ERROR_FAIL;
166 }
167 }
168 }
169 }
170
171 return retval;
172
173 }
174
175 static int bluenrgx_protect(struct flash_bank *bank, int set, int first, int last)
176 {
177 /* Protection is only handled in software: no hardware write protection
178 available in BlueNRG-x devices */
179 int sector;
180
181 for (sector = first; sector <= last; sector++)
182 bank->sectors[sector].is_protected = set;
183 return ERROR_OK;
184 }
185 static int bluenrgx_write_word(struct target *target, uint32_t address_base, uint8_t *values, uint32_t count)
186 {
187 int retval = ERROR_OK;
188
189 retval = target_write_u32(target, FLASH_REG_IRQRAW, 0x3f);
190 if (retval != ERROR_OK) {
191 LOG_ERROR("Register write failed, error code: %d", retval);
192 return retval;
193 }
194
195 for (uint32_t i = 0; i < count; i++) {
196 uint32_t address = address_base + i * FLASH_WORD_LEN;
197
198 retval = target_write_u32(target, FLASH_REG_ADDRESS, address >> 2);
199 if (retval != ERROR_OK) {
200 LOG_ERROR("Register write failed, error code: %d", retval);
201 return retval;
202 }
203
204 retval = target_write_buffer(target, FLASH_REG_DATA, FLASH_WORD_LEN, values + i * FLASH_WORD_LEN);
205 if (retval != ERROR_OK) {
206 LOG_ERROR("Register write failed, error code: %d", retval);
207 return retval;
208 }
209
210 retval = target_write_u32(target, FLASH_REG_COMMAND, FLASH_CMD_WRITE);
211 if (retval != ERROR_OK) {
212 LOG_ERROR("Register write failed, error code: %d", retval);
213 return retval;
214 }
215
216 for (int j = 0; j < 100; j++) {
217 uint32_t reg_value;
218 retval = target_read_u32(target, FLASH_REG_IRQRAW, &reg_value);
219
220 if (retval != ERROR_OK) {
221 LOG_ERROR("Register read failed, error code: %d", retval);
222 return retval;
223 }
224
225 if (reg_value & FLASH_INT_CMDDONE)
226 break;
227
228 if (j == 99) {
229 LOG_ERROR("Write command failed (timeout)");
230 return ERROR_FAIL;
231 }
232 }
233 }
234 return retval;
235 }
236
237 static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, uint8_t *buffer, uint32_t count)
238 {
239 int retval = ERROR_OK;
240 uint8_t *new_buffer = NULL;
241 uint32_t pre_bytes = 0, post_bytes = 0, pre_word, post_word, pre_address, post_address;
242
243 if (count == 0) {
244 /* Just return if there are no bytes to write */
245 return retval;
246 }
247
248 if (address_base & 3) {
249 pre_bytes = address_base & 3;
250 pre_address = address_base - pre_bytes;
251 }
252
253 if ((count + pre_bytes) & 3) {
254 post_bytes = ((count + pre_bytes + 3) & ~3) - (count + pre_bytes);
255 post_address = (address_base + count) & ~3;
256 }
257
258 if (pre_bytes || post_bytes) {
259 uint32_t old_count = count;
260
261 count = old_count + pre_bytes + post_bytes;
262
263 new_buffer = malloc(count);
264
265 if (new_buffer == NULL) {
266 LOG_ERROR("odd number of bytes to write and no memory "
267 "for padding buffer");
268 return ERROR_FAIL;
269 }
270
271 LOG_INFO("Requested number of bytes to write and/or address not word aligned (%" PRIu32 "), extending to %"
272 PRIu32 " ", old_count, count);
273
274 if (pre_bytes) {
275 if (target_read_u32(target, pre_address, &pre_word)) {
276 LOG_ERROR("Memory read failed");
277 return ERROR_FAIL;
278 }
279
280 }
281
282 if (post_bytes) {
283 if (target_read_u32(target, post_address, &post_word)) {
284 LOG_ERROR("Memory read failed");
285 return ERROR_FAIL;
286 }
287
288 }
289
290 memcpy(new_buffer, &pre_word, pre_bytes);
291 memcpy((new_buffer+((pre_bytes+old_count) & ~3)), &post_word, 4);
292 memcpy(new_buffer+pre_bytes, buffer, old_count);
293 buffer = new_buffer;
294 }
295
296 retval = bluenrgx_write_word(target, address_base - pre_bytes, buffer, count/4);
297
298 if (new_buffer)
299 free(new_buffer);
300
301 return retval;
302 }
303
304 static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
305 uint32_t offset, uint32_t count)
306 {
307 struct target *target = bank->target;
308 uint32_t buffer_size = 16384 + 8;
309 struct working_area *write_algorithm;
310 struct working_area *write_algorithm_sp;
311 struct working_area *source;
312 uint32_t address = bank->base + offset;
313 struct reg_param reg_params[5];
314 struct armv7m_algorithm armv7m_info;
315 int retval = ERROR_OK;
316 uint32_t pre_size = 0, fast_size = 0, post_size = 0;
317 uint32_t pre_offset = 0, fast_offset = 0, post_offset = 0;
318
319 /* See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c for source and
320 * hints how to generate the data!
321 */
322 static const uint8_t bluenrgx_flash_write_code[] = {
323 #include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc"
324 };
325
326 if ((offset + count) > bank->size) {
327 LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d",
328 (offset + count),
329 bank->size);
330 return ERROR_FLASH_DST_OUT_OF_BANK;
331 }
332
333 if (bank->target->state != TARGET_HALTED) {
334 LOG_ERROR("Target not halted");
335 return ERROR_TARGET_NOT_HALTED;
336 }
337
338 /* We are good here and we need to compute pre_size, fast_size, post_size */
339 pre_size = MIN(count, ((offset+0xF) & ~0xF) - offset);
340 pre_offset = offset;
341 fast_size = 16*((count - pre_size) / 16);
342 fast_offset = offset + pre_size;
343 post_size = (count-pre_size-fast_size) % 16;
344 post_offset = fast_offset + fast_size;
345
346 LOG_DEBUG("pre_size = %08x, pre_offset=%08x", pre_size, pre_offset);
347 LOG_DEBUG("fast_size = %08x, fast_offset=%08x", fast_size, fast_offset);
348 LOG_DEBUG("post_size = %08x, post_offset=%08x", post_size, post_offset);
349
350 /* Program initial chunk not 16 bytes aligned */
351 retval = bluenrgx_write_bytes(target, bank->base+pre_offset, (uint8_t *) buffer, pre_size);
352 if (retval) {
353 LOG_ERROR("bluenrgx_write_bytes failed %d", retval);
354 return ERROR_FAIL;
355 }
356
357 /* Program chunk 16 bytes aligned in fast mode */
358 if (fast_size) {
359
360 if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code),
361 &write_algorithm) != ERROR_OK) {
362 LOG_WARNING("no working area available, can't do block memory writes");
363 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
364 }
365
366 retval = target_write_buffer(target, write_algorithm->address,
367 sizeof(bluenrgx_flash_write_code),
368 bluenrgx_flash_write_code);
369 if (retval != ERROR_OK)
370 return retval;
371
372 /* memory buffer */
373 if (target_alloc_working_area(target, buffer_size, &source)) {
374 LOG_WARNING("no large enough working area available");
375 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
376 }
377
378 /* Stack pointer area */
379 if (target_alloc_working_area(target, 64,
380 &write_algorithm_sp) != ERROR_OK) {
381 LOG_DEBUG("no working area for write code stack pointer");
382 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
383 }
384
385 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
386 armv7m_info.core_mode = ARM_MODE_THREAD;
387
388 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
389 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
390 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
391 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
392 init_reg_param(&reg_params[4], "sp", 32, PARAM_OUT);
393
394 /* FIFO start address (first two words used for write and read pointers) */
395 buf_set_u32(reg_params[0].value, 0, 32, source->address);
396 /* FIFO end address (first two words used for write and read pointers) */
397 buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
398 /* Flash memory address */
399 buf_set_u32(reg_params[2].value, 0, 32, address+pre_size);
400 /* Number of bytes */
401 buf_set_u32(reg_params[3].value, 0, 32, fast_size);
402 /* Stack pointer for program working area */
403 buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address);
404
405 LOG_DEBUG("source->address = %08" TARGET_PRIxADDR, source->address);
406 LOG_DEBUG("source->address+ source->size = %08" TARGET_PRIxADDR, source->address+source->size);
407 LOG_DEBUG("write_algorithm_sp->address = %08" TARGET_PRIxADDR, write_algorithm_sp->address);
408 LOG_DEBUG("address = %08x", address+pre_size);
409 LOG_DEBUG("count = %08x", count);
410
411 retval = target_run_flash_async_algorithm(target,
412 buffer+pre_size,
413 fast_size/16,
414 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */
415 0,
416 NULL,
417 5,
418 reg_params,
419 source->address,
420 source->size,
421 write_algorithm->address,
422 0,
423 &armv7m_info);
424
425 if (retval == ERROR_FLASH_OPERATION_FAILED) {
426 LOG_ERROR("error executing bluenrg-x flash write algorithm");
427
428 uint32_t error = buf_get_u32(reg_params[0].value, 0, 32);
429
430 if (error != 0)
431 LOG_ERROR("flash write failed = %08" PRIx32, error);
432 }
433 if (retval == ERROR_OK) {
434 uint32_t rp;
435 /* Read back rp and check that is valid */
436 retval = target_read_u32(target, source->address+4, &rp);
437 if (retval == ERROR_OK) {
438 if ((rp < source->address+8) || (rp > (source->address + source->size))) {
439 LOG_ERROR("flash write failed = %08" PRIx32, rp);
440 retval = ERROR_FLASH_OPERATION_FAILED;
441 }
442 }
443 }
444 target_free_working_area(target, source);
445 target_free_working_area(target, write_algorithm);
446 target_free_working_area(target, write_algorithm_sp);
447
448 destroy_reg_param(&reg_params[0]);
449 destroy_reg_param(&reg_params[1]);
450 destroy_reg_param(&reg_params[2]);
451 destroy_reg_param(&reg_params[3]);
452 destroy_reg_param(&reg_params[4]);
453 }
454
455 /* Program chunk at end, not addressable by fast burst write algorithm */
456 retval = bluenrgx_write_bytes(target, bank->base+post_offset, (uint8_t *) (buffer+pre_size+fast_size), post_size);
457 if (retval) {
458 LOG_ERROR("bluenrgx_write_bytes failed %d", retval);
459 return ERROR_FAIL;
460 }
461 return retval;
462 }
463
464 static int bluenrgx_probe(struct flash_bank *bank)
465 {
466 struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
467 uint32_t idcode, size_info, die_id;
468 int i;
469 int retval = target_read_u32(bank->target, JTAG_IDCODE_REG, &idcode);
470 if (retval != ERROR_OK)
471 return retval;
472 retval = target_read_u32(bank->target, FLASH_SIZE_REG, &size_info);
473 if (retval != ERROR_OK)
474 return retval;
475
476 retval = target_read_u32(bank->target, DIE_ID_REG, &die_id);
477 if (retval != ERROR_OK)
478 return retval;
479
480 bank->size = (size_info + 1) * 4;
481 bank->base = FLASH_BASE;
482 bank->num_sectors = bank->size/FLASH_PAGE_SIZE;
483 bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors);
484
485 for (i = 0; i < bank->num_sectors; i++) {
486 bank->sectors[i].offset = i * FLASH_PAGE_SIZE;
487 bank->sectors[i].size = FLASH_PAGE_SIZE;
488 bank->sectors[i].is_erased = -1;
489 bank->sectors[i].is_protected = 0;
490 }
491
492 bluenrgx_info->probed = 1;
493 bluenrgx_info->die_id = die_id;
494 bluenrgx_info->idcode = idcode;
495 return ERROR_OK;
496 }
497
498 static int bluenrgx_auto_probe(struct flash_bank *bank)
499 {
500 struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
501
502 if (bluenrgx_info->probed)
503 return ERROR_OK;
504
505 return bluenrgx_probe(bank);
506 }
507
508 /* This method must return a string displaying information about the bank */
509 static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
510 {
511 struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
512 int mask_number, cut_number;
513 char *part_name;
514
515 if (!bluenrgx_info->probed) {
516 int retval = bluenrgx_probe(bank);
517 if (retval != ERROR_OK) {
518 snprintf(buf, buf_size,
519 "Unable to find bank information.");
520 return retval;
521 }
522 }
523
524 if (bluenrgx_info->idcode == BLUENRG2_IDCODE)
525 part_name = "BLUENRG-2";
526 else
527 part_name = "BLUENRG-1";
528
529 mask_number = (bluenrgx_info->die_id >> 4) & 0xF;
530 cut_number = bluenrgx_info->die_id & 0xF;
531
532 snprintf(buf, buf_size,
533 "%s - Rev: %d.%d", part_name, mask_number, cut_number);
534 return ERROR_OK;
535 }
536
537 struct flash_driver bluenrgx_flash = {
538 .name = "bluenrg-x",
539 .flash_bank_command = bluenrgx_flash_bank_command,
540 .erase = bluenrgx_erase,
541 .protect = bluenrgx_protect,
542 .write = bluenrgx_write,
543 .read = default_flash_read,
544 .probe = bluenrgx_probe,
545 .erase_check = default_flash_blank_check,
546 .protect_check = bluenrgx_protect_check,
547 .auto_probe = bluenrgx_auto_probe,
548 .info = bluenrgx_get_info,
549 };

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)