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

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)