fbce20d5540d517f2026bb0a8a41e2520ca0ee71
[fw/openocd] / 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         bool 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 = false;
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)
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 (unsigned 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 (unsigned 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)
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 retval = target_read_u32(bank->target, BLUENRGLP_JTAG_REG, &idcode);
369
370         if (retval != ERROR_OK)
371                 return retval;
372
373         if (idcode != flash_priv_data_lp.jtag_idcode) {
374                 retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode);
375                 if (retval != ERROR_OK)
376                         return retval;
377         }
378
379         /* Default device is BlueNRG-1 */
380         bluenrgx_info->flash_ptr = &flash_priv_data_1;
381         bank->base = flash_priv_data_1.flash_base;
382
383         for (size_t i = 0; i < ARRAY_SIZE(flash_ctrl); i++) {
384                 if (idcode == (*flash_ctrl[i]).jtag_idcode) {
385                         bluenrgx_info->flash_ptr = flash_ctrl[i];
386                         bank->base = (*flash_ctrl[i]).flash_base;
387                         break;
388                 }
389         }
390         retval = bluenrgx_read_flash_reg(bank, FLASH_SIZE_REG, &size_info);
391         if (retval != ERROR_OK)
392                 return retval;
393
394         retval = target_read_u32(bank->target, DIE_ID_REG(bluenrgx_info), &die_id);
395         if (retval != ERROR_OK)
396                 return retval;
397
398         bank->size = (size_info + 1) * FLASH_WORD_LEN;
399         bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info);
400         bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors);
401
402         for (int i = 0; i < bank->num_sectors; i++) {
403                 bank->sectors[i].offset = i * FLASH_PAGE_SIZE(bluenrgx_info);
404                 bank->sectors[i].size = FLASH_PAGE_SIZE(bluenrgx_info);
405                 bank->sectors[i].is_erased = -1;
406                 bank->sectors[i].is_protected = 0;
407         }
408
409         bluenrgx_info->probed = true;
410         bluenrgx_info->die_id = die_id;
411
412         return ERROR_OK;
413 }
414
415 static int bluenrgx_auto_probe(struct flash_bank *bank)
416 {
417         struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
418
419         if (bluenrgx_info->probed)
420                 return ERROR_OK;
421
422         return bluenrgx_probe(bank);
423 }
424
425 /* This method must return a string displaying information about the bank */
426 static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
427 {
428         struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
429         int mask_number, cut_number;
430
431         if (!bluenrgx_info->probed) {
432                 int retval = bluenrgx_probe(bank);
433                 if (retval != ERROR_OK) {
434                         snprintf(buf, buf_size,
435                                  "Unable to find bank information.");
436                         return retval;
437                 }
438         }
439
440         mask_number = (bluenrgx_info->die_id >> 4) & 0xF;
441         cut_number = bluenrgx_info->die_id & 0xF;
442
443         snprintf(buf, buf_size,
444                  "%s - Rev: %d.%d", bluenrgx_info->flash_ptr->part_name, mask_number, cut_number);
445         return ERROR_OK;
446 }
447
448 const struct flash_driver bluenrgx_flash = {
449         .name = "bluenrg-x",
450         .flash_bank_command = bluenrgx_flash_bank_command,
451         .erase = bluenrgx_erase,
452         .protect = NULL,
453         .write = bluenrgx_write,
454         .read = default_flash_read,
455         .probe = bluenrgx_probe,
456         .erase_check = default_flash_blank_check,
457         .protect_check = NULL,
458         .auto_probe = bluenrgx_auto_probe,
459         .info = bluenrgx_get_info,
460 };