flash/nor/tcl.c: fix formatting in "rejected" error message
[openocd.git] / src / flash / nor / lpcspifi.c
1 /***************************************************************************
2 * Copyright (C) 2012 by George Harris *
3 * george@luminairecoffee.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, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "imp.h"
26 #include "spi.h"
27 #include <jtag/jtag.h>
28 #include <helper/time_support.h>
29 #include <target/algorithm.h>
30 #include <target/armv7m.h>
31
32 /* Offsets from ssp_base into config & data registers */
33 #define SSP_CR0 (0x00) /* Control register 0 */
34 #define SSP_CR1 (0x04) /* Control register 1 */
35 #define SSP_DATA (0x08) /* Data register (TX and RX) */
36 #define SSP_SR (0x0C) /* Status register */
37 #define SSP_CPSR (0x10) /* Clock prescale register */
38
39 /* Status register fields */
40 #define SSP_BSY (0x00000010)
41
42 /* Timeout in ms */
43 #define SSP_CMD_TIMEOUT (100)
44 #define SSP_PROBE_TIMEOUT (100)
45 #define SSP_MAX_TIMEOUT (3000)
46
47 /* Size of the stack to alloc in the working area for the execution of
48 * the ROM spifi_init() function */
49 #define SPIFI_INIT_STACK_SIZE 512
50
51 struct lpcspifi_flash_bank {
52 int probed;
53 uint32_t ssp_base;
54 uint32_t io_base;
55 uint32_t ioconfig_base;
56 uint32_t bank_num;
57 uint32_t max_spi_clock_mhz;
58 const struct flash_device *dev;
59 };
60
61 struct lpcspifi_target {
62 char *name;
63 uint32_t tap_idcode;
64 uint32_t spifi_base;
65 uint32_t ssp_base;
66 uint32_t io_base;
67 uint32_t ioconfig_base; /* base address for the port word pin registers */
68 };
69
70 static const struct lpcspifi_target target_devices[] = {
71 /* name, tap_idcode, spifi_base, ssp_base, io_base, ioconfig_base */
72 { "LPC43xx/18xx", 0x4ba00477, 0x14000000, 0x40083000, 0x400F4000, 0x40086000 },
73 { NULL, 0, 0, 0, 0, 0 }
74 };
75
76 /* flash_bank lpcspifi <base> <size> <chip_width> <bus_width> <target>
77 */
78 FLASH_BANK_COMMAND_HANDLER(lpcspifi_flash_bank_command)
79 {
80 struct lpcspifi_flash_bank *lpcspifi_info;
81
82 if (CMD_ARGC < 6)
83 return ERROR_COMMAND_SYNTAX_ERROR;
84
85 lpcspifi_info = malloc(sizeof(struct lpcspifi_flash_bank));
86 if (lpcspifi_info == NULL) {
87 LOG_ERROR("not enough memory");
88 return ERROR_FAIL;
89 }
90
91 bank->driver_priv = lpcspifi_info;
92 lpcspifi_info->probed = 0;
93
94 return ERROR_OK;
95 }
96
97 static inline int ioconfig_write_reg(struct target *target, uint32_t ioconfig_base, uint32_t offset, uint32_t value)
98 {
99 return target_write_u32(target, ioconfig_base + offset, value);
100 }
101
102 static inline int ssp_write_reg(struct target *target, uint32_t ssp_base, uint32_t offset, uint32_t value)
103 {
104 return target_write_u32(target, ssp_base + offset, value);
105 }
106
107 static inline int io_write_reg(struct target *target, uint32_t io_base, uint32_t offset, uint32_t value)
108 {
109 return target_write_u32(target, io_base + offset, value);
110 }
111
112 static inline int ssp_read_reg(struct target *target, uint32_t ssp_base, uint32_t offset, uint32_t *value)
113 {
114 return target_read_u32(target, ssp_base + offset, value);
115 }
116
117 static int ssp_setcs(struct target *target, uint32_t io_base, unsigned int value)
118 {
119 return io_write_reg(target, io_base, 0x12ac, value ? 0xffffffff : 0x00000000);
120 }
121
122 /* Poll the SSP busy flag. When this comes back as 0, the transfer is complete
123 * and the controller is idle. */
124 static int poll_ssp_busy(struct target *target, uint32_t ssp_base, int timeout)
125 {
126 long long endtime;
127 uint32_t value;
128 int retval;
129
130 retval = ssp_read_reg(target, ssp_base, SSP_SR, &value);
131 if ((retval == ERROR_OK) && (value & SSP_BSY) == 0)
132 return ERROR_OK;
133 else if (retval != ERROR_OK)
134 return retval;
135
136 endtime = timeval_ms() + timeout;
137 do {
138 alive_sleep(1);
139 retval = ssp_read_reg(target, ssp_base, SSP_SR, &value);
140 if ((retval == ERROR_OK) && (value & SSP_BSY) == 0)
141 return ERROR_OK;
142 else if (retval != ERROR_OK)
143 return retval;
144 } while (timeval_ms() < endtime);
145
146 LOG_ERROR("Timeout while polling BSY");
147 return ERROR_FLASH_OPERATION_FAILED;
148 }
149
150 /* Un-initialize the ssp module and initialize the SPIFI module */
151 static int lpcspifi_set_hw_mode(struct flash_bank *bank)
152 {
153 struct target *target = bank->target;
154 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
155 uint32_t ssp_base = lpcspifi_info->ssp_base;
156 struct armv7m_algorithm armv7m_info;
157 struct working_area *spifi_init_algorithm;
158 struct reg_param reg_params[2];
159 int retval = ERROR_OK;
160
161 LOG_DEBUG("Uninitializing LPC43xx SSP");
162 /* Turn off the SSP module */
163 retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000000);
164 if (retval != ERROR_OK)
165 return retval;
166
167 /* see contrib/loaders/flash/lpcspifi_init.S for src */
168 static const uint8_t spifi_init_code[] = {
169 0x4f, 0xea, 0x00, 0x08, 0xa1, 0xb0, 0x00, 0xaf,
170 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03,
171 0x4f, 0xf0, 0xf3, 0x02, 0xc3, 0xf8, 0x8c, 0x21,
172 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03,
173 0x4f, 0xf4, 0xc0, 0x42, 0xc4, 0xf2, 0x08, 0x02,
174 0x4f, 0xf4, 0xc0, 0x41, 0xc4, 0xf2, 0x08, 0x01,
175 0x4f, 0xf4, 0xc0, 0x40, 0xc4, 0xf2, 0x08, 0x00,
176 0x4f, 0xf0, 0xd3, 0x04, 0xc0, 0xf8, 0x9c, 0x41,
177 0x20, 0x46, 0xc1, 0xf8, 0x98, 0x01, 0x01, 0x46,
178 0xc2, 0xf8, 0x94, 0x11, 0xc3, 0xf8, 0x90, 0x11,
179 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03,
180 0x4f, 0xf0, 0x13, 0x02, 0xc3, 0xf8, 0xa0, 0x21,
181 0x40, 0xf2, 0x18, 0x13, 0xc1, 0xf2, 0x40, 0x03,
182 0x1b, 0x68, 0x1c, 0x68, 0x40, 0xf2, 0xb4, 0x30,
183 0xc1, 0xf2, 0x00, 0x00, 0x4f, 0xf0, 0x03, 0x01,
184 0x4f, 0xf0, 0xc0, 0x02, 0x4f, 0xea, 0x08, 0x03,
185 0xa0, 0x47, 0x00, 0xf0, 0x00, 0xb8, 0x00, 0xbe
186 };
187
188 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
189 armv7m_info.core_mode = ARM_MODE_THREAD;
190
191
192 LOG_DEBUG("Allocating working area for SPIFI init algorithm");
193 /* Get memory for spifi initialization algorithm */
194 retval = target_alloc_working_area(target, sizeof(spifi_init_code)
195 + SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm);
196 if (retval != ERROR_OK) {
197 LOG_ERROR("Insufficient working area to initialize SPIFI "\
198 "module. You must allocate at least %zdB of working "\
199 "area in order to use this driver.",
200 sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE
201 );
202
203 return retval;
204 }
205
206 LOG_DEBUG("Writing algorithm to working area at 0x%08" PRIx32,
207 spifi_init_algorithm->address);
208 /* Write algorithm to working area */
209 retval = target_write_buffer(target,
210 spifi_init_algorithm->address,
211 sizeof(spifi_init_code),
212 spifi_init_code
213 );
214
215 if (retval != ERROR_OK) {
216 target_free_working_area(target, spifi_init_algorithm);
217 return retval;
218 }
219
220 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* spifi clk speed */
221 /* the spifi_init() rom API makes use of the stack */
222 init_reg_param(&reg_params[1], "sp", 32, PARAM_OUT);
223
224 /* For now, the algorithm will set up the SPIFI module
225 * @ the IRC clock speed. In the future, it could be made
226 * a bit smarter to use other clock sources if the user has
227 * already configured them in order to speed up memory-
228 * mapped reads. */
229 buf_set_u32(reg_params[0].value, 0, 32, 12);
230 /* valid stack pointer */
231 buf_set_u32(reg_params[1].value, 0, 32, (spifi_init_algorithm->address +
232 sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE) & ~7UL);
233
234 /* Run the algorithm */
235 LOG_DEBUG("Running SPIFI init algorithm");
236 retval = target_run_algorithm(target, 0 , NULL, 2, reg_params,
237 spifi_init_algorithm->address,
238 spifi_init_algorithm->address + sizeof(spifi_init_code) - 2,
239 1000, &armv7m_info);
240
241 if (retval != ERROR_OK)
242 LOG_ERROR("Error executing SPIFI init algorithm");
243
244 target_free_working_area(target, spifi_init_algorithm);
245
246 destroy_reg_param(&reg_params[0]);
247 destroy_reg_param(&reg_params[1]);
248
249 return retval;
250 }
251
252 /* Initialize the ssp module */
253 static int lpcspifi_set_sw_mode(struct flash_bank *bank)
254 {
255 struct target *target = bank->target;
256 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
257 uint32_t ssp_base = lpcspifi_info->ssp_base;
258 uint32_t io_base = lpcspifi_info->io_base;
259 uint32_t ioconfig_base = lpcspifi_info->ioconfig_base;
260 int retval = ERROR_OK;
261
262 /* Re-initialize SPIFI. There are a couple of errata on this, so this makes
263 sure that nothing's in an unhappy state. */
264 retval = lpcspifi_set_hw_mode(bank);
265
266 /* If we couldn't initialize hardware mode, don't even bother continuing */
267 if (retval != ERROR_OK)
268 return retval;
269
270 /* Initialize the pins */
271 retval = ioconfig_write_reg(target, ioconfig_base, 0x194, 0x00000040);
272 if (retval == ERROR_OK)
273 retval = ioconfig_write_reg(target, ioconfig_base, 0x1a0, 0x00000044);
274 if (retval == ERROR_OK)
275 retval = ioconfig_write_reg(target, ioconfig_base, 0x190, 0x00000040);
276 if (retval == ERROR_OK)
277 retval = ioconfig_write_reg(target, ioconfig_base, 0x19c, 0x000000ed);
278 if (retval == ERROR_OK)
279 retval = ioconfig_write_reg(target, ioconfig_base, 0x198, 0x000000ed);
280 if (retval == ERROR_OK)
281 retval = ioconfig_write_reg(target, ioconfig_base, 0x18c, 0x000000ea);
282
283 /* Set CS high & as an output */
284 if (retval == ERROR_OK)
285 retval = io_write_reg(target, io_base, 0x12ac, 0xffffffff);
286 if (retval == ERROR_OK)
287 retval = io_write_reg(target, io_base, 0x2014, 0x00000800);
288
289 /* Initialize the module */
290 if (retval == ERROR_OK)
291 retval = ssp_write_reg(target, ssp_base, SSP_CR0, 0x00000007);
292 if (retval == ERROR_OK)
293 retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000000);
294 if (retval == ERROR_OK)
295 retval = ssp_write_reg(target, ssp_base, SSP_CPSR, 0x00000008);
296 if (retval == ERROR_OK)
297 retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000002);
298
299 /* If something didn't work out, attempt to return SPIFI to HW mode */
300 if (retval != ERROR_OK)
301 lpcspifi_set_hw_mode(bank);
302
303 return retval;
304 }
305
306 /* Read the status register of the external SPI flash chip. */
307 static int read_status_reg(struct flash_bank *bank, uint32_t *status)
308 {
309 struct target *target = bank->target;
310 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
311 uint32_t ssp_base = lpcspifi_info->ssp_base;
312 uint32_t io_base = lpcspifi_info->io_base;
313 uint32_t value;
314 int retval = ERROR_OK;
315
316 retval = ssp_setcs(target, io_base, 0);
317 if (retval == ERROR_OK)
318 retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_READ_STATUS);
319 if (retval == ERROR_OK)
320 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
321 if (retval == ERROR_OK)
322 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
323 /* Dummy write to clock in the register */
324 if (retval == ERROR_OK)
325 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
326 if (retval == ERROR_OK)
327 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
328 if (retval == ERROR_OK)
329 retval = ssp_setcs(target, io_base, 1);
330
331 if (retval == ERROR_OK)
332 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
333 if (retval == ERROR_OK)
334 *status = value;
335
336 return retval;
337 }
338
339 /* check for BSY bit in flash status register */
340 /* timeout in ms */
341 static int wait_till_ready(struct flash_bank *bank, int timeout)
342 {
343 uint32_t status;
344 int retval;
345 long long endtime;
346
347 endtime = timeval_ms() + timeout;
348 do {
349 /* read flash status register */
350 retval = read_status_reg(bank, &status);
351 if (retval != ERROR_OK)
352 return retval;
353
354 if ((status & SPIFLASH_BSY_BIT) == 0)
355 return ERROR_OK;
356 alive_sleep(1);
357 } while (timeval_ms() < endtime);
358
359 LOG_ERROR("timeout waiting for flash to finish write/erase operation");
360 return ERROR_FAIL;
361 }
362
363 /* Send "write enable" command to SPI flash chip. */
364 static int lpcspifi_write_enable(struct flash_bank *bank)
365 {
366 struct target *target = bank->target;
367 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
368 uint32_t ssp_base = lpcspifi_info->ssp_base;
369 uint32_t io_base = lpcspifi_info->io_base;
370 uint32_t status, value;
371 int retval = ERROR_OK;
372
373 retval = ssp_setcs(target, io_base, 0);
374 if (retval == ERROR_OK)
375 retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_WRITE_ENABLE);
376 if (retval == ERROR_OK)
377 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
378 if (retval == ERROR_OK)
379 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
380 if (retval == ERROR_OK)
381 retval = ssp_setcs(target, io_base, 1);
382
383 /* read flash status register */
384 if (retval == ERROR_OK)
385 retval = read_status_reg(bank, &status);
386 if (retval != ERROR_OK)
387 return retval;
388
389 /* Check write enabled */
390 if ((status & SPIFLASH_WE_BIT) == 0) {
391 LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status);
392 return ERROR_FAIL;
393 }
394
395 return retval;
396 }
397
398 static int lpcspifi_bulk_erase(struct flash_bank *bank)
399 {
400 struct target *target = bank->target;
401 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
402 uint32_t ssp_base = lpcspifi_info->ssp_base;
403 uint32_t io_base = lpcspifi_info->io_base;
404 uint32_t value;
405 int retval = ERROR_OK;
406
407 retval = lpcspifi_set_sw_mode(bank);
408
409 if (retval == ERROR_OK)
410 retval = lpcspifi_write_enable(bank);
411
412 /* send SPI command "bulk erase" */
413 if (retval == ERROR_OK)
414 ssp_setcs(target, io_base, 0);
415 if (retval == ERROR_OK)
416 retval = ssp_write_reg(target, ssp_base, SSP_DATA, lpcspifi_info->dev->chip_erase_cmd);
417 if (retval == ERROR_OK)
418 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
419 if (retval == ERROR_OK)
420 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
421 if (retval == ERROR_OK)
422 retval = ssp_setcs(target, io_base, 1);
423
424 /* poll flash BSY for self-timed bulk erase */
425 if (retval == ERROR_OK)
426 retval = wait_till_ready(bank, bank->num_sectors*SSP_MAX_TIMEOUT);
427
428 return retval;
429 }
430
431 static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
432 {
433 struct target *target = bank->target;
434 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
435 struct reg_param reg_params[4];
436 struct armv7m_algorithm armv7m_info;
437 struct working_area *erase_algorithm;
438 int retval = ERROR_OK;
439 int sector;
440
441 LOG_DEBUG("erase from sector %d to sector %d", first, last);
442
443 if (target->state != TARGET_HALTED) {
444 LOG_ERROR("Target not halted");
445 return ERROR_TARGET_NOT_HALTED;
446 }
447
448 if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
449 LOG_ERROR("Flash sector invalid");
450 return ERROR_FLASH_SECTOR_INVALID;
451 }
452
453 if (!(lpcspifi_info->probed)) {
454 LOG_ERROR("Flash bank not probed");
455 return ERROR_FLASH_BANK_NOT_PROBED;
456 }
457
458 for (sector = first; sector <= last; sector++) {
459 if (bank->sectors[sector].is_protected) {
460 LOG_ERROR("Flash sector %d protected", sector);
461 return ERROR_FAIL;
462 }
463 }
464
465 /* If we're erasing the entire chip and the flash supports
466 * it, use a bulk erase instead of going sector-by-sector. */
467 if (first == 0 && last == (bank->num_sectors - 1)
468 && lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) {
469 LOG_DEBUG("Chip supports the bulk erase command."\
470 " Will use bulk erase instead of sector-by-sector erase.");
471 retval = lpcspifi_bulk_erase(bank);
472
473 if (retval == ERROR_OK) {
474 retval = lpcspifi_set_hw_mode(bank);
475 return retval;
476 } else
477 LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase.");
478 }
479
480 retval = lpcspifi_set_hw_mode(bank);
481 if (retval != ERROR_OK)
482 return retval;
483
484 /* see contrib/loaders/flash/lpcspifi_erase.S for src */
485 static const uint8_t lpcspifi_flash_erase_code[] = {
486 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a,
487 0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81,
488 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81,
489 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81,
490 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81,
491 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81,
492 0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81,
493 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
494 0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80,
495 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
496 0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80,
497 0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a,
498 0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18,
499 0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a,
500 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08,
501 0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a,
502 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08,
503 0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08,
504 0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80,
505 0x00, 0xf0, 0x52, 0xf8, 0x4f, 0xf0, 0x06, 0x09,
506 0x00, 0xf0, 0x3b, 0xf8, 0x00, 0xf0, 0x48, 0xf8,
507 0x00, 0xf0, 0x4a, 0xf8, 0x4f, 0xf0, 0x05, 0x09,
508 0x00, 0xf0, 0x33, 0xf8, 0x4f, 0xf0, 0x00, 0x09,
509 0x00, 0xf0, 0x2f, 0xf8, 0x00, 0xf0, 0x3c, 0xf8,
510 0x19, 0xf0, 0x02, 0x0f, 0x00, 0xf0, 0x45, 0x80,
511 0x00, 0xf0, 0x3a, 0xf8, 0x4f, 0xea, 0x02, 0x09,
512 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xea, 0x10, 0x49,
513 0x00, 0xf0, 0x1f, 0xf8, 0x4f, 0xea, 0x10, 0x29,
514 0x00, 0xf0, 0x1b, 0xf8, 0x4f, 0xea, 0x00, 0x09,
515 0x00, 0xf0, 0x17, 0xf8, 0x00, 0xf0, 0x24, 0xf8,
516 0x00, 0xf0, 0x26, 0xf8, 0x4f, 0xf0, 0x05, 0x09,
517 0x00, 0xf0, 0x0f, 0xf8, 0x4f, 0xf0, 0x00, 0x09,
518 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0xf0, 0x18, 0xf8,
519 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4, 0xf0, 0xaf,
520 0x01, 0x39, 0xf9, 0xb1, 0x18, 0x44, 0xff, 0xf7,
521 0xbf, 0xbf, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2,
522 0x08, 0x0a, 0xca, 0xf8, 0x08, 0x90, 0xda, 0xf8,
523 0x0c, 0x90, 0x19, 0xf0, 0x10, 0x0f, 0x7f, 0xf4,
524 0xfa, 0xaf, 0xda, 0xf8, 0x08, 0x90, 0x70, 0x47,
525 0x4f, 0xf0, 0xff, 0x08, 0x00, 0xf0, 0x02, 0xb8,
526 0x4f, 0xf0, 0x00, 0x08, 0x4f, 0xf4, 0x80, 0x4a,
527 0xc4, 0xf2, 0x0f, 0x0a, 0xca, 0xf8, 0xab, 0x80,
528 0x70, 0x47, 0x00, 0x20, 0x00, 0xbe, 0xff, 0xff
529 };
530
531 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
532 armv7m_info.core_mode = ARM_MODE_THREAD;
533
534
535 /* Get memory for spifi initialization algorithm */
536 retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code),
537 &erase_algorithm);
538 if (retval != ERROR_OK) {
539 LOG_ERROR("Insufficient working area. You must configure a working"\
540 " area of at least %zdB in order to erase SPIFI flash.",
541 sizeof(lpcspifi_flash_erase_code));
542 return retval;
543 }
544
545 /* Write algorithm to working area */
546 retval = target_write_buffer(target, erase_algorithm->address,
547 sizeof(lpcspifi_flash_erase_code), lpcspifi_flash_erase_code);
548 if (retval != ERROR_OK) {
549 target_free_working_area(target, erase_algorithm);
550 return retval;
551 }
552
553 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* Start address */
554 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* Sector count */
555 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* Erase command */
556 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* Sector size */
557
558 buf_set_u32(reg_params[0].value, 0, 32, bank->sectors[first].offset);
559 buf_set_u32(reg_params[1].value, 0, 32, last - first + 1);
560 buf_set_u32(reg_params[2].value, 0, 32, lpcspifi_info->dev->erase_cmd);
561 buf_set_u32(reg_params[3].value, 0, 32, bank->sectors[first].size);
562
563 /* Run the algorithm */
564 retval = target_run_algorithm(target, 0 , NULL, 4, reg_params,
565 erase_algorithm->address,
566 erase_algorithm->address + sizeof(lpcspifi_flash_erase_code) - 4,
567 3000*(last - first + 1), &armv7m_info);
568
569 if (retval != ERROR_OK)
570 LOG_ERROR("Error executing flash erase algorithm");
571
572 target_free_working_area(target, erase_algorithm);
573
574 destroy_reg_param(&reg_params[0]);
575 destroy_reg_param(&reg_params[1]);
576 destroy_reg_param(&reg_params[2]);
577 destroy_reg_param(&reg_params[3]);
578
579 retval = lpcspifi_set_hw_mode(bank);
580
581 return retval;
582 }
583
584 static int lpcspifi_protect(struct flash_bank *bank, int set,
585 int first, int last)
586 {
587 int sector;
588
589 for (sector = first; sector <= last; sector++)
590 bank->sectors[sector].is_protected = set;
591 return ERROR_OK;
592 }
593
594 static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
595 uint32_t offset, uint32_t count)
596 {
597 struct target *target = bank->target;
598 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
599 uint32_t page_size, fifo_size;
600 struct working_area *fifo;
601 struct reg_param reg_params[5];
602 struct armv7m_algorithm armv7m_info;
603 struct working_area *write_algorithm;
604 int sector;
605 int retval = ERROR_OK;
606
607 LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32,
608 offset, count);
609
610 if (target->state != TARGET_HALTED) {
611 LOG_ERROR("Target not halted");
612 return ERROR_TARGET_NOT_HALTED;
613 }
614
615 if (offset + count > lpcspifi_info->dev->size_in_bytes) {
616 LOG_WARNING("Writes past end of flash. Extra data discarded.");
617 count = lpcspifi_info->dev->size_in_bytes - offset;
618 }
619
620 /* Check sector protection */
621 for (sector = 0; sector < bank->num_sectors; sector++) {
622 /* Start offset in or before this sector? */
623 /* End offset in or behind this sector? */
624 if ((offset <
625 (bank->sectors[sector].offset + bank->sectors[sector].size))
626 && ((offset + count - 1) >= bank->sectors[sector].offset)
627 && bank->sectors[sector].is_protected) {
628 LOG_ERROR("Flash sector %d protected", sector);
629 return ERROR_FAIL;
630 }
631 }
632
633 page_size = lpcspifi_info->dev->pagesize;
634
635 retval = lpcspifi_set_hw_mode(bank);
636 if (retval != ERROR_OK)
637 return retval;
638
639 /* see contrib/loaders/flash/lpcspifi_write.S for src */
640 static const uint8_t lpcspifi_flash_write_code[] = {
641 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a,
642 0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81,
643 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81,
644 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81,
645 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81,
646 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81,
647 0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81,
648 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
649 0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80,
650 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
651 0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80,
652 0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a,
653 0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18,
654 0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a,
655 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08,
656 0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a,
657 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08,
658 0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08,
659 0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80,
660 0x4f, 0xf0, 0x00, 0x0b, 0xa3, 0x44, 0x93, 0x45,
661 0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6a, 0xf8,
662 0x4f, 0xf0, 0x06, 0x09, 0x00, 0xf0, 0x53, 0xf8,
663 0x00, 0xf0, 0x60, 0xf8, 0x00, 0xf0, 0x62, 0xf8,
664 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x4b, 0xf8,
665 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x47, 0xf8,
666 0x00, 0xf0, 0x54, 0xf8, 0x19, 0xf0, 0x02, 0x0f,
667 0x00, 0xf0, 0x5d, 0x80, 0x00, 0xf0, 0x52, 0xf8,
668 0x4f, 0xf0, 0x02, 0x09, 0x00, 0xf0, 0x3b, 0xf8,
669 0x4f, 0xea, 0x12, 0x49, 0x00, 0xf0, 0x37, 0xf8,
670 0x4f, 0xea, 0x12, 0x29, 0x00, 0xf0, 0x33, 0xf8,
671 0x4f, 0xea, 0x02, 0x09, 0x00, 0xf0, 0x2f, 0xf8,
672 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f,
673 0x00, 0xf0, 0x47, 0x80, 0x47, 0x68, 0x47, 0x45,
674 0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8, 0x01, 0x9b,
675 0x00, 0xf0, 0x21, 0xf8, 0x8f, 0x42, 0x28, 0xbf,
676 0x00, 0xf1, 0x08, 0x07, 0x47, 0x60, 0x01, 0x3b,
677 0xbb, 0xb3, 0x02, 0xf1, 0x01, 0x02, 0x93, 0x45,
678 0x7f, 0xf4, 0xe6, 0xaf, 0x00, 0xf0, 0x22, 0xf8,
679 0xa3, 0x44, 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xf0,
680 0x05, 0x09, 0x00, 0xf0, 0x0c, 0xf8, 0x4f, 0xf0,
681 0x00, 0x09, 0x00, 0xf0, 0x08, 0xf8, 0x00, 0xf0,
682 0x15, 0xf8, 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4,
683 0xf0, 0xaf, 0xff, 0xf7, 0xa7, 0xbf, 0x4f, 0xf4,
684 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0xca, 0xf8,
685 0x08, 0x90, 0xda, 0xf8, 0x0c, 0x90, 0x19, 0xf0,
686 0x10, 0x0f, 0x7f, 0xf4, 0xfa, 0xaf, 0xda, 0xf8,
687 0x08, 0x90, 0x70, 0x47, 0x4f, 0xf0, 0xff, 0x08,
688 0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08,
689 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
690 0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20,
691 0x50, 0x60, 0x30, 0x46, 0x00, 0xbe, 0xff, 0xff
692 };
693
694 if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code),
695 &write_algorithm) != ERROR_OK) {
696 LOG_ERROR("Insufficient working area. You must configure"\
697 " a working area > %zdB in order to write to SPIFI flash.",
698 sizeof(lpcspifi_flash_write_code));
699 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
700 };
701
702 retval = target_write_buffer(target, write_algorithm->address,
703 sizeof(lpcspifi_flash_write_code),
704 lpcspifi_flash_write_code);
705 if (retval != ERROR_OK) {
706 target_free_working_area(target, write_algorithm);
707 return retval;
708 }
709
710 /* FIFO allocation */
711 fifo_size = target_get_working_area_avail(target);
712
713 if (fifo_size == 0) {
714 /* if we already allocated the writing code but failed to get fifo
715 * space, free the algorithm */
716 target_free_working_area(target, write_algorithm);
717
718 LOG_ERROR("Insufficient working area. Please allocate at least"\
719 " %zdB of working area to enable flash writes.",
720 sizeof(lpcspifi_flash_write_code) + 1
721 );
722
723 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
724 } else if (fifo_size < page_size)
725 LOG_WARNING("Working area size is limited; flash writes may be"\
726 " slow. Increase working area size to at least %zdB"\
727 " to reduce write times.",
728 (size_t)(sizeof(lpcspifi_flash_write_code) + page_size)
729 );
730 else if (fifo_size > 0x2000) /* Beyond this point, we start to get diminishing returns */
731 fifo_size = 0x2000;
732
733 if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) {
734 target_free_working_area(target, write_algorithm);
735 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
736 };
737
738 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
739 armv7m_info.core_mode = ARM_MODE_THREAD;
740
741 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */
742 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* buffer end */
743 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* target address */
744 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */
745 init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* page size */
746
747 buf_set_u32(reg_params[0].value, 0, 32, fifo->address);
748 buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size);
749 buf_set_u32(reg_params[2].value, 0, 32, offset);
750 buf_set_u32(reg_params[3].value, 0, 32, count);
751 buf_set_u32(reg_params[4].value, 0, 32, page_size);
752
753 retval = target_run_flash_async_algorithm(target, buffer, count, 1,
754 0, NULL,
755 5, reg_params,
756 fifo->address, fifo->size,
757 write_algorithm->address, 0,
758 &armv7m_info
759 );
760
761 if (retval != ERROR_OK)
762 LOG_ERROR("Error executing flash write algorithm");
763
764 target_free_working_area(target, fifo);
765 target_free_working_area(target, write_algorithm);
766
767 destroy_reg_param(&reg_params[0]);
768 destroy_reg_param(&reg_params[1]);
769 destroy_reg_param(&reg_params[2]);
770 destroy_reg_param(&reg_params[3]);
771 destroy_reg_param(&reg_params[4]);
772
773 /* Switch to HW mode before return to prompt */
774 retval = lpcspifi_set_hw_mode(bank);
775 return retval;
776 }
777
778 /* Return ID of flash device */
779 /* On exit, SW mode is kept */
780 static int lpcspifi_read_flash_id(struct flash_bank *bank, uint32_t *id)
781 {
782 struct target *target = bank->target;
783 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
784 uint32_t ssp_base = lpcspifi_info->ssp_base;
785 uint32_t io_base = lpcspifi_info->io_base;
786 uint32_t value;
787 uint8_t id_buf[3] = {0, 0, 0};
788 int retval;
789
790 if (target->state != TARGET_HALTED) {
791 LOG_ERROR("Target not halted");
792 return ERROR_TARGET_NOT_HALTED;
793 }
794
795 LOG_DEBUG("Getting ID");
796 retval = lpcspifi_set_sw_mode(bank);
797 if (retval != ERROR_OK)
798 return retval;
799
800 /* poll WIP */
801 if (retval == ERROR_OK)
802 retval = wait_till_ready(bank, SSP_PROBE_TIMEOUT);
803
804 /* Send SPI command "read ID" */
805 if (retval == ERROR_OK)
806 retval = ssp_setcs(target, io_base, 0);
807 if (retval == ERROR_OK)
808 retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_READ_ID);
809 if (retval == ERROR_OK)
810 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
811 if (retval == ERROR_OK)
812 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
813
814 /* Dummy write to clock in data */
815 if (retval == ERROR_OK)
816 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
817 if (retval == ERROR_OK)
818 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
819 if (retval == ERROR_OK)
820 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
821 if (retval == ERROR_OK)
822 id_buf[0] = value;
823
824 /* Dummy write to clock in data */
825 if (retval == ERROR_OK)
826 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
827 if (retval == ERROR_OK)
828 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
829 if (retval == ERROR_OK)
830 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
831 if (retval == ERROR_OK)
832 id_buf[1] = value;
833
834 /* Dummy write to clock in data */
835 if (retval == ERROR_OK)
836 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
837 if (retval == ERROR_OK)
838 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
839 if (retval == ERROR_OK)
840 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
841 if (retval == ERROR_OK)
842 id_buf[2] = value;
843
844 if (retval == ERROR_OK)
845 retval = ssp_setcs(target, io_base, 1);
846 if (retval == ERROR_OK)
847 *id = id_buf[2] << 16 | id_buf[1] << 8 | id_buf[0];
848
849 return retval;
850 }
851
852 static int lpcspifi_probe(struct flash_bank *bank)
853 {
854 struct target *target = bank->target;
855 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
856 uint32_t ssp_base;
857 uint32_t io_base;
858 uint32_t ioconfig_base;
859 struct flash_sector *sectors;
860 uint32_t id = 0; /* silence uninitialized warning */
861 const struct lpcspifi_target *target_device;
862 int retval;
863
864 /* If we've already probed, we should be fine to skip this time. */
865 if (lpcspifi_info->probed)
866 return ERROR_OK;
867 lpcspifi_info->probed = 0;
868
869 for (target_device = target_devices ; target_device->name ; ++target_device)
870 if (target_device->tap_idcode == target->tap->idcode)
871 break;
872 if (!target_device->name) {
873 LOG_ERROR("Device ID 0x%" PRIx32 " is not known as SPIFI capable",
874 target->tap->idcode);
875 return ERROR_FAIL;
876 }
877
878 ssp_base = target_device->ssp_base;
879 io_base = target_device->io_base;
880 ioconfig_base = target_device->ioconfig_base;
881 lpcspifi_info->ssp_base = ssp_base;
882 lpcspifi_info->io_base = io_base;
883 lpcspifi_info->ioconfig_base = ioconfig_base;
884 lpcspifi_info->bank_num = bank->bank_number;
885
886 LOG_DEBUG("Valid SPIFI on device %s at address 0x%" PRIx32,
887 target_device->name, bank->base);
888
889 /* read and decode flash ID; returns in SW mode */
890 retval = lpcspifi_read_flash_id(bank, &id);
891 if (retval != ERROR_OK)
892 return retval;
893
894 retval = lpcspifi_set_hw_mode(bank);
895 if (retval != ERROR_OK)
896 return retval;
897
898 lpcspifi_info->dev = NULL;
899 for (const struct flash_device *p = flash_devices; p->name ; p++)
900 if (p->device_id == id) {
901 lpcspifi_info->dev = p;
902 break;
903 }
904
905 if (!lpcspifi_info->dev) {
906 LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id);
907 return ERROR_FAIL;
908 }
909
910 LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
911 lpcspifi_info->dev->name, lpcspifi_info->dev->device_id);
912
913 /* Set correct size value */
914 bank->size = lpcspifi_info->dev->size_in_bytes;
915
916 /* create and fill sectors array */
917 bank->num_sectors =
918 lpcspifi_info->dev->size_in_bytes / lpcspifi_info->dev->sectorsize;
919 sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
920 if (sectors == NULL) {
921 LOG_ERROR("not enough memory");
922 return ERROR_FAIL;
923 }
924
925 for (int sector = 0; sector < bank->num_sectors; sector++) {
926 sectors[sector].offset = sector * lpcspifi_info->dev->sectorsize;
927 sectors[sector].size = lpcspifi_info->dev->sectorsize;
928 sectors[sector].is_erased = -1;
929 sectors[sector].is_protected = 0;
930 }
931
932 bank->sectors = sectors;
933
934 lpcspifi_info->probed = 1;
935 return ERROR_OK;
936 }
937
938 static int lpcspifi_auto_probe(struct flash_bank *bank)
939 {
940 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
941 if (lpcspifi_info->probed)
942 return ERROR_OK;
943 return lpcspifi_probe(bank);
944 }
945
946 static int lpcspifi_protect_check(struct flash_bank *bank)
947 {
948 /* Nothing to do. Protection is only handled in SW. */
949 return ERROR_OK;
950 }
951
952 static int get_lpcspifi_info(struct flash_bank *bank, char *buf, int buf_size)
953 {
954 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
955
956 if (!(lpcspifi_info->probed)) {
957 snprintf(buf, buf_size,
958 "\nSPIFI flash bank not probed yet\n");
959 return ERROR_OK;
960 }
961
962 snprintf(buf, buf_size, "\nSPIFI flash information:\n"
963 " Device \'%s\' (ID 0x%08" PRIx32 ")\n",
964 lpcspifi_info->dev->name, lpcspifi_info->dev->device_id);
965
966 return ERROR_OK;
967 }
968
969 struct flash_driver lpcspifi_flash = {
970 .name = "lpcspifi",
971 .flash_bank_command = lpcspifi_flash_bank_command,
972 .erase = lpcspifi_erase,
973 .protect = lpcspifi_protect,
974 .write = lpcspifi_write,
975 .read = default_flash_read,
976 .probe = lpcspifi_probe,
977 .auto_probe = lpcspifi_auto_probe,
978 .erase_check = default_flash_blank_check,
979 .protect_check = lpcspifi_protect_check,
980 .info = get_lpcspifi_info,
981 };

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)