60eccefaf04baeb3326d508919b2fe2d7426b385
[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 <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 };