flash: efm32: Add support for EZR32LG and EZR32WG.
[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, 0xff, 0xf7, 0xef, 0xff, 0x30, 0x46,
692 0x00, 0xbe, 0xff, 0xff
693 };
694
695 if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code),
696 &write_algorithm) != ERROR_OK) {
697 LOG_ERROR("Insufficient working area. You must configure"\
698 " a working area > %zdB in order to write to SPIFI flash.",
699 sizeof(lpcspifi_flash_write_code));
700 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
701 };
702
703 retval = target_write_buffer(target, write_algorithm->address,
704 sizeof(lpcspifi_flash_write_code),
705 lpcspifi_flash_write_code);
706 if (retval != ERROR_OK) {
707 target_free_working_area(target, write_algorithm);
708 return retval;
709 }
710
711 /* FIFO allocation */
712 fifo_size = target_get_working_area_avail(target);
713
714 if (fifo_size == 0) {
715 /* if we already allocated the writing code but failed to get fifo
716 * space, free the algorithm */
717 target_free_working_area(target, write_algorithm);
718
719 LOG_ERROR("Insufficient working area. Please allocate at least"\
720 " %zdB of working area to enable flash writes.",
721 sizeof(lpcspifi_flash_write_code) + 1
722 );
723
724 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
725 } else if (fifo_size < page_size)
726 LOG_WARNING("Working area size is limited; flash writes may be"\
727 " slow. Increase working area size to at least %zdB"\
728 " to reduce write times.",
729 (size_t)(sizeof(lpcspifi_flash_write_code) + page_size)
730 );
731 else if (fifo_size > 0x2000) /* Beyond this point, we start to get diminishing returns */
732 fifo_size = 0x2000;
733
734 if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) {
735 target_free_working_area(target, write_algorithm);
736 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
737 };
738
739 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
740 armv7m_info.core_mode = ARM_MODE_THREAD;
741
742 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */
743 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* buffer end */
744 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* target address */
745 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */
746 init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* page size */
747
748 buf_set_u32(reg_params[0].value, 0, 32, fifo->address);
749 buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size);
750 buf_set_u32(reg_params[2].value, 0, 32, offset);
751 buf_set_u32(reg_params[3].value, 0, 32, count);
752 buf_set_u32(reg_params[4].value, 0, 32, page_size);
753
754 retval = target_run_flash_async_algorithm(target, buffer, count, 1,
755 0, NULL,
756 5, reg_params,
757 fifo->address, fifo->size,
758 write_algorithm->address, 0,
759 &armv7m_info
760 );
761
762 if (retval != ERROR_OK)
763 LOG_ERROR("Error executing flash write algorithm");
764
765 target_free_working_area(target, fifo);
766 target_free_working_area(target, write_algorithm);
767
768 destroy_reg_param(&reg_params[0]);
769 destroy_reg_param(&reg_params[1]);
770 destroy_reg_param(&reg_params[2]);
771 destroy_reg_param(&reg_params[3]);
772 destroy_reg_param(&reg_params[4]);
773
774 /* Switch to HW mode before return to prompt */
775 retval = lpcspifi_set_hw_mode(bank);
776 return retval;
777 }
778
779 /* Return ID of flash device */
780 /* On exit, SW mode is kept */
781 static int lpcspifi_read_flash_id(struct flash_bank *bank, uint32_t *id)
782 {
783 struct target *target = bank->target;
784 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
785 uint32_t ssp_base = lpcspifi_info->ssp_base;
786 uint32_t io_base = lpcspifi_info->io_base;
787 uint32_t value;
788 uint8_t id_buf[3] = {0, 0, 0};
789 int retval;
790
791 if (target->state != TARGET_HALTED) {
792 LOG_ERROR("Target not halted");
793 return ERROR_TARGET_NOT_HALTED;
794 }
795
796 LOG_DEBUG("Getting ID");
797 retval = lpcspifi_set_sw_mode(bank);
798 if (retval != ERROR_OK)
799 return retval;
800
801 /* poll WIP */
802 if (retval == ERROR_OK)
803 retval = wait_till_ready(bank, SSP_PROBE_TIMEOUT);
804
805 /* Send SPI command "read ID" */
806 if (retval == ERROR_OK)
807 retval = ssp_setcs(target, io_base, 0);
808 if (retval == ERROR_OK)
809 retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_READ_ID);
810 if (retval == ERROR_OK)
811 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
812 if (retval == ERROR_OK)
813 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
814
815 /* Dummy write to clock in data */
816 if (retval == ERROR_OK)
817 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
818 if (retval == ERROR_OK)
819 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
820 if (retval == ERROR_OK)
821 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
822 if (retval == ERROR_OK)
823 id_buf[0] = value;
824
825 /* Dummy write to clock in data */
826 if (retval == ERROR_OK)
827 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
828 if (retval == ERROR_OK)
829 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
830 if (retval == ERROR_OK)
831 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
832 if (retval == ERROR_OK)
833 id_buf[1] = value;
834
835 /* Dummy write to clock in data */
836 if (retval == ERROR_OK)
837 retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00);
838 if (retval == ERROR_OK)
839 retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT);
840 if (retval == ERROR_OK)
841 retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value);
842 if (retval == ERROR_OK)
843 id_buf[2] = value;
844
845 if (retval == ERROR_OK)
846 retval = ssp_setcs(target, io_base, 1);
847 if (retval == ERROR_OK)
848 *id = id_buf[2] << 16 | id_buf[1] << 8 | id_buf[0];
849
850 return retval;
851 }
852
853 static int lpcspifi_probe(struct flash_bank *bank)
854 {
855 struct target *target = bank->target;
856 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
857 uint32_t ssp_base;
858 uint32_t io_base;
859 uint32_t ioconfig_base;
860 struct flash_sector *sectors;
861 uint32_t id = 0; /* silence uninitialized warning */
862 const struct lpcspifi_target *target_device;
863 int retval;
864
865 /* If we've already probed, we should be fine to skip this time. */
866 if (lpcspifi_info->probed)
867 return ERROR_OK;
868 lpcspifi_info->probed = 0;
869
870 for (target_device = target_devices ; target_device->name ; ++target_device)
871 if (target_device->tap_idcode == target->tap->idcode)
872 break;
873 if (!target_device->name) {
874 LOG_ERROR("Device ID 0x%" PRIx32 " is not known as SPIFI capable",
875 target->tap->idcode);
876 return ERROR_FAIL;
877 }
878
879 ssp_base = target_device->ssp_base;
880 io_base = target_device->io_base;
881 ioconfig_base = target_device->ioconfig_base;
882 lpcspifi_info->ssp_base = ssp_base;
883 lpcspifi_info->io_base = io_base;
884 lpcspifi_info->ioconfig_base = ioconfig_base;
885 lpcspifi_info->bank_num = bank->bank_number;
886
887 LOG_DEBUG("Valid SPIFI on device %s at address 0x%" PRIx32,
888 target_device->name, bank->base);
889
890 /* read and decode flash ID; returns in SW mode */
891 retval = lpcspifi_read_flash_id(bank, &id);
892 if (retval != ERROR_OK)
893 return retval;
894
895 retval = lpcspifi_set_hw_mode(bank);
896 if (retval != ERROR_OK)
897 return retval;
898
899 lpcspifi_info->dev = NULL;
900 for (const struct flash_device *p = flash_devices; p->name ; p++)
901 if (p->device_id == id) {
902 lpcspifi_info->dev = p;
903 break;
904 }
905
906 if (!lpcspifi_info->dev) {
907 LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id);
908 return ERROR_FAIL;
909 }
910
911 LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
912 lpcspifi_info->dev->name, lpcspifi_info->dev->device_id);
913
914 /* Set correct size value */
915 bank->size = lpcspifi_info->dev->size_in_bytes;
916
917 /* create and fill sectors array */
918 bank->num_sectors =
919 lpcspifi_info->dev->size_in_bytes / lpcspifi_info->dev->sectorsize;
920 sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
921 if (sectors == NULL) {
922 LOG_ERROR("not enough memory");
923 return ERROR_FAIL;
924 }
925
926 for (int sector = 0; sector < bank->num_sectors; sector++) {
927 sectors[sector].offset = sector * lpcspifi_info->dev->sectorsize;
928 sectors[sector].size = lpcspifi_info->dev->sectorsize;
929 sectors[sector].is_erased = -1;
930 sectors[sector].is_protected = 0;
931 }
932
933 bank->sectors = sectors;
934
935 lpcspifi_info->probed = 1;
936 return ERROR_OK;
937 }
938
939 static int lpcspifi_auto_probe(struct flash_bank *bank)
940 {
941 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
942 if (lpcspifi_info->probed)
943 return ERROR_OK;
944 return lpcspifi_probe(bank);
945 }
946
947 static int lpcspifi_protect_check(struct flash_bank *bank)
948 {
949 /* Nothing to do. Protection is only handled in SW. */
950 return ERROR_OK;
951 }
952
953 static int get_lpcspifi_info(struct flash_bank *bank, char *buf, int buf_size)
954 {
955 struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
956
957 if (!(lpcspifi_info->probed)) {
958 snprintf(buf, buf_size,
959 "\nSPIFI flash bank not probed yet\n");
960 return ERROR_OK;
961 }
962
963 snprintf(buf, buf_size, "\nSPIFI flash information:\n"
964 " Device \'%s\' (ID 0x%08" PRIx32 ")\n",
965 lpcspifi_info->dev->name, lpcspifi_info->dev->device_id);
966
967 return ERROR_OK;
968 }
969
970 struct flash_driver lpcspifi_flash = {
971 .name = "lpcspifi",
972 .flash_bank_command = lpcspifi_flash_bank_command,
973 .erase = lpcspifi_erase,
974 .protect = lpcspifi_protect,
975 .write = lpcspifi_write,
976 .read = default_flash_read,
977 .probe = lpcspifi_probe,
978 .auto_probe = lpcspifi_auto_probe,
979 .erase_check = default_flash_blank_check,
980 .protect_check = lpcspifi_protect_check,
981 .info = get_lpcspifi_info,
982 };

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)