cfg: add Fujitsu FM3 config
[openocd.git] / src / flash / nor / stm32f2xxx.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2008 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
7 * *
8 * Copyright (C) 2011 Øyvind Harboe *
9 * oyvind.harboe@zylin.com *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
20 * *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
25 ***************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "imp.h"
31 #include <helper/binarybuffer.h>
32 #include <target/algorithm.h>
33 #include <target/armv7m.h>
34
35 /* Regarding performance:
36 *
37 * Short story - it might be best to leave the performance at
38 * current levels.
39 *
40 * You may see a jump in speed if you change to using
41 * 32bit words for the block programming.
42 *
43 * Its a shame you cannot use the double word as its
44 * even faster - but you require external VPP for that mode.
45 *
46 * Having said all that 16bit writes give us the widest vdd
47 * operating range, so may be worth adding a note to that effect.
48 *
49 */
50
51
52 /* Danger!!!! The STM32F1xxxx and STM32F2xxxx series actually have
53 * quite different flash controllers.
54 *
55 * What's more scary is that the names of the registers and their
56 * addresses are the same, but the actual bits and what they do are
57 * can be very different.
58 *
59 * To reduce testing complexity and dangers of regressions,
60 * a seperate file is used for stm32fx2222.
61 *
62 * 1mByte part with 4 x 16, 1 x 64, 7 x 128kBytes sectors
63 *
64 * What's the protection page size???
65 *
66 * Tested with STM3220F-EVAL board.
67 *
68 * STM32F21xx series for reference.
69 *
70 * RM0033
71 * http://www.st.com/internet/mcu/product/250192.jsp
72 *
73 * PM0059
74 * www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/PROGRAMMING_MANUAL/CD00233952.pdf
75 *
76 * STM32F1xxx series - notice that this code was copy, pasted and knocked
77 * into a stm32f2xxx driver, so in case something has been converted or
78 * bugs haven't been fixed, here are the original manuals:
79 *
80 * RM0008 - Reference manual
81 *
82 * RM0042, the Flash programming manual for low-, medium- high-density and
83 * connectivity line STM32F10xxx devices
84 *
85 * PM0068, the Flash programming manual for XL-density STM32F10xxx devices.
86 *
87 */
88
89 // Erase time can be as high as 1000ms, 10x this and it's toast...
90 #define FLASH_ERASE_TIMEOUT 10000
91 #define FLASH_WRITE_TIMEOUT 5
92
93
94 #define STM32_FLASH_BASE 0x40023c00
95 #define STM32_FLASH_ACR 0x40023c00
96 #define STM32_FLASH_KEYR 0x40023c04
97 #define STM32_FLASH_OPTKEYR 0x40023c08
98 #define STM32_FLASH_SR 0x40023c0C
99 #define STM32_FLASH_CR 0x40023c10
100 #define STM32_FLASH_OPTCR 0x40023c14
101 #define STM32_FLASH_OBR 0x40023c1C
102
103
104
105 /* option byte location */
106
107 #define STM32_OB_RDP 0x1FFFF800
108 #define STM32_OB_USER 0x1FFFF802
109 #define STM32_OB_DATA0 0x1FFFF804
110 #define STM32_OB_DATA1 0x1FFFF806
111 #define STM32_OB_WRP0 0x1FFFF808
112 #define STM32_OB_WRP1 0x1FFFF80A
113 #define STM32_OB_WRP2 0x1FFFF80C
114 #define STM32_OB_WRP3 0x1FFFF80E
115
116 /* FLASH_CR register bits */
117
118 #define FLASH_PG (1 << 0)
119 #define FLASH_SER (1 << 1)
120 #define FLASH_MER (1 << 2)
121 #define FLASH_STRT (1 << 16)
122 #define FLASH_PSIZE_8 (0 << 8)
123 #define FLASH_PSIZE_16 (1 << 8)
124 #define FLASH_PSIZE_32 (2 << 8)
125 #define FLASH_PSIZE_64 (3 << 8)
126 #define FLASH_SNB(a) ((a) << 3)
127 #define FLASH_LOCK (1 << 31)
128
129 /* FLASH_SR register bits */
130
131 #define FLASH_BSY (1 << 16)
132 #define FLASH_PGSERR (1 << 7) // Programming sequence error
133 #define FLASH_PGPERR (1 << 6) // Programming parallelism error
134 #define FLASH_PGAERR (1 << 5) // Programming alignment error
135 #define FLASH_WRPERR (1 << 4) // Write protection error
136 #define FLASH_OPERR (1 << 1) // Operation error
137
138 #define FLASH_ERROR (FLASH_PGSERR | FLASH_PGPERR | FLASH_PGAERR| FLASH_WRPERR| FLASH_OPERR)
139
140 /* STM32_FLASH_OBR bit definitions (reading) */
141
142 #define OPT_ERROR 0
143 #define OPT_READOUT 1
144 #define OPT_RDWDGSW 2
145 #define OPT_RDRSTSTOP 3
146 #define OPT_RDRSTSTDBY 4
147 #define OPT_BFB2 5 /* dual flash bank only */
148
149 /* register unlock keys */
150
151 #define KEY1 0x45670123
152 #define KEY2 0xCDEF89AB
153
154 struct stm32x_flash_bank
155 {
156 struct working_area *write_algorithm;
157 int probed;
158 };
159
160
161 /* flash bank stm32x <base> <size> 0 0 <target#>
162 */
163 FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
164 {
165 struct stm32x_flash_bank *stm32x_info;
166
167 if (CMD_ARGC < 6)
168 {
169 LOG_WARNING("incomplete flash_bank stm32x configuration");
170 return ERROR_FLASH_BANK_INVALID;
171 }
172
173 stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
174 bank->driver_priv = stm32x_info;
175
176 stm32x_info->write_algorithm = NULL;
177 stm32x_info->probed = 0;
178
179 return ERROR_OK;
180 }
181
182 static inline int stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg)
183 {
184 return reg;
185 }
186
187 static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status)
188 {
189 struct target *target = bank->target;
190 return target_read_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), status);
191 }
192
193 static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
194 {
195 struct target *target = bank->target;
196 uint32_t status;
197 int retval = ERROR_OK;
198
199 /* wait for busy to clear */
200 for (;;)
201 {
202 retval = stm32x_get_flash_status(bank, &status);
203 if (retval != ERROR_OK)
204 return retval;
205 LOG_DEBUG("status: 0x%" PRIx32 "", status);
206 if ((status & FLASH_BSY) == 0)
207 break;
208 if (timeout-- <= 0)
209 {
210 LOG_ERROR("timed out waiting for flash");
211 return ERROR_FAIL;
212 }
213 alive_sleep(1);
214 }
215
216
217 if (status & FLASH_WRPERR)
218 {
219 LOG_ERROR("stm32x device protected");
220 retval = ERROR_FAIL;
221 }
222
223 /* Clear but report errors */
224 if (status & FLASH_ERROR)
225 {
226 /* If this operation fails, we ignore it and report the original
227 * retval
228 */
229 target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR),
230 status & FLASH_ERROR);
231 }
232 return retval;
233 }
234
235 static int stm32x_unlock_reg(struct target *target)
236 {
237 /* unlock flash registers */
238 int retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1);
239 if (retval != ERROR_OK)
240 return retval;
241
242 retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2);
243 if (retval != ERROR_OK)
244 return retval;
245 return ERROR_OK;
246 }
247
248 static int stm32x_protect_check(struct flash_bank *bank)
249 {
250 return ERROR_OK;
251 }
252
253 static int stm32x_erase(struct flash_bank *bank, int first, int last)
254 {
255 struct target *target = bank->target;
256 int i;
257
258 if (bank->target->state != TARGET_HALTED)
259 {
260 LOG_ERROR("Target not halted");
261 return ERROR_TARGET_NOT_HALTED;
262 }
263
264 int retval;
265 retval = stm32x_unlock_reg(target);
266 if (retval != ERROR_OK)
267 return retval;
268
269 /*
270 Sector Erase
271 To erase a sector, follow the procedure below:
272 1. Check that no Flash memory operation is ongoing by checking the BSY bit in the
273 FLASH_SR register
274 2. Set the SER bit and select the sector (out of the 12 sectors in the main memory block)
275 you wish to erase (SNB) in the FLASH_CR register
276 3. Set the STRT bit in the FLASH_CR register
277 4. Wait for the BSY bit to be cleared
278 */
279
280 for (i = first; i <= last; i++)
281 {
282 retval = target_write_u32(target,
283 stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_SER | FLASH_SNB(i) | FLASH_STRT);
284 if (retval != ERROR_OK)
285 return retval;
286
287 retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
288 if (retval != ERROR_OK)
289 return retval;
290
291 bank->sectors[i].is_erased = 1;
292 }
293
294 retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
295 if (retval != ERROR_OK)
296 return retval;
297
298 return ERROR_OK;
299 }
300
301 static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
302 {
303 return ERROR_OK;
304 }
305
306 static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
307 uint32_t offset, uint32_t count)
308 {
309 struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
310 struct target *target = bank->target;
311 uint32_t buffer_size = 16384;
312 struct working_area *source;
313 uint32_t address = bank->base + offset;
314 struct reg_param reg_params[5];
315 struct armv7m_algorithm armv7m_info;
316 int retval = ERROR_OK;
317
318 /* see contib/loaders/flash/stm32x.s for src */
319
320 static const uint16_t stm32x_flash_write_code_16[] = {
321 // 00000000 <write>:
322 0x4b07, // ldr r3, [pc, #28] (20 <STM32_PROG16>)
323 0x6123, // str r3, [r4, #16]
324 0xf830, 0x3b02, //ldrh.w r3, [r0], #2
325 0xf821, 0x3b02, //strh.w r3, [r1], #2
326
327 //0000000c <busy>:
328 0x68e3, //ldr r3, [r4, #12]
329 0xf413, 0x3f80, // tst.w r3, #65536 ; 0x10000
330 0xd0fb, //beq.n c <busy>
331 0xf013, 0x0ff0, //tst.w r3, #240 ; 0xf0
332 0xd101, //bne.n 1e <exit>
333 0x3a01, //subs r2, #1
334 0xd1f0, //bne.n 0 <write>
335 //0000001e <exit>:
336 0xbe00, // bkpt 0x0000
337
338 //00000020 <STM32_PROG16>:
339 0x0101, 0x0000, // .word 0x00000101
340
341 };
342
343 // Flip endian
344 uint8_t stm32x_flash_write_code[sizeof(stm32x_flash_write_code_16)*2];
345 for (unsigned i = 0; i < sizeof(stm32x_flash_write_code_16) / 2; i++)
346 {
347 stm32x_flash_write_code[i*2 + 0] = stm32x_flash_write_code_16[i] & 0xff;
348 stm32x_flash_write_code[i*2 + 1] = (stm32x_flash_write_code_16[i] >> 8) & 0xff;
349 }
350
351 if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code),
352 &stm32x_info->write_algorithm) != ERROR_OK)
353 {
354 LOG_WARNING("no working area available, can't do block memory writes");
355 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
356 };
357
358 if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address,
359 sizeof(stm32x_flash_write_code),
360 (uint8_t*)stm32x_flash_write_code)) != ERROR_OK)
361 return retval;
362
363 /* memory buffer */
364 while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
365 {
366 buffer_size /= 2;
367 if (buffer_size <= 256)
368 {
369 /* if we already allocated the writing code, but failed to get a
370 * buffer, free the algorithm */
371 if (stm32x_info->write_algorithm)
372 target_free_working_area(target, stm32x_info->write_algorithm);
373
374 LOG_WARNING("no large enough working area available, can't do block memory writes");
375 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
376 }
377 };
378
379 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
380 armv7m_info.core_mode = ARMV7M_MODE_ANY;
381
382 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
383 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
384 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
385 init_reg_param(&reg_params[3], "r3", 32, PARAM_IN_OUT);
386 init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
387
388 while (count > 0)
389 {
390 uint32_t thisrun_count = (count > (buffer_size / 2)) ?
391 (buffer_size / 2) : count;
392
393 if ((retval = target_write_buffer(target, source->address,
394 thisrun_count * 2, buffer)) != ERROR_OK)
395 break;
396
397 buf_set_u32(reg_params[0].value, 0, 32, source->address);
398 buf_set_u32(reg_params[1].value, 0, 32, address);
399 buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
400 // R3 is a return value only
401 buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE);
402
403 if ((retval = target_run_algorithm(target, 0, NULL,
404 sizeof(reg_params) / sizeof(*reg_params),
405 reg_params,
406 stm32x_info->write_algorithm->address,
407 0,
408 10000, &armv7m_info)) != ERROR_OK)
409 {
410 LOG_ERROR("error executing stm32x flash write algorithm");
411 break;
412 }
413
414 uint32_t error = buf_get_u32(reg_params[3].value, 0, 32) & FLASH_ERROR;
415
416 if (error & FLASH_WRPERR)
417 {
418 LOG_ERROR("flash memory write protected");
419 }
420
421 if (error != 0)
422 {
423 LOG_ERROR("flash write failed = %08x", error);
424 /* Clear but report errors */
425 target_write_u32(target, STM32_FLASH_SR, error);
426 retval = ERROR_FAIL;
427 break;
428 }
429
430 buffer += thisrun_count * 2;
431 address += thisrun_count * 2;
432 count -= thisrun_count;
433 }
434
435 target_free_working_area(target, source);
436 target_free_working_area(target, stm32x_info->write_algorithm);
437
438 destroy_reg_param(&reg_params[0]);
439 destroy_reg_param(&reg_params[1]);
440 destroy_reg_param(&reg_params[2]);
441 destroy_reg_param(&reg_params[3]);
442 destroy_reg_param(&reg_params[4]);
443
444 return retval;
445 }
446
447 static int stm32x_write(struct flash_bank *bank, uint8_t *buffer,
448 uint32_t offset, uint32_t count)
449 {
450 struct target *target = bank->target;
451 uint32_t words_remaining = (count / 2);
452 uint32_t bytes_remaining = (count & 0x00000001);
453 uint32_t address = bank->base + offset;
454 uint32_t bytes_written = 0;
455 int retval;
456
457 if (bank->target->state != TARGET_HALTED)
458 {
459 LOG_ERROR("Target not halted");
460 return ERROR_TARGET_NOT_HALTED;
461 }
462
463 if (offset & 0x1)
464 {
465 LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
466 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
467 }
468
469 retval = stm32x_unlock_reg(target);
470 if (retval != ERROR_OK)
471 return retval;
472
473 /* multiple half words (2-byte) to be programmed? */
474 if (words_remaining > 0)
475 {
476 /* try using a block write */
477 if ((retval = stm32x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
478 {
479 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
480 {
481 /* if block write failed (no sufficient working area),
482 * we use normal (slow) single dword accesses */
483 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
484 }
485 }
486 else
487 {
488 buffer += words_remaining * 2;
489 address += words_remaining * 2;
490 words_remaining = 0;
491 }
492 }
493
494 if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE))
495 return retval;
496
497 /*
498 Standard programming
499 The Flash memory programming sequence is as follows:
500 1. Check that no main Flash memory operation is ongoing by checking the BSY bit in the
501 FLASH_SR register.
502 2. Set the PG bit in the FLASH_CR register
503 3. Perform the data write operation(s) to the desired memory address (inside main
504 memory block or OTP area):
505 – – Half-word access in case of x16 parallelism
506 – Word access in case of x32 parallelism
507
508 4.
509 Byte access in case of x8 parallelism
510 Double word access in case of x64 parallelism
511 Wait for the BSY bit to be cleared
512 */
513 while (words_remaining > 0)
514 {
515 uint16_t value;
516 memcpy(&value, buffer + bytes_written, sizeof(uint16_t));
517
518 retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR),
519 FLASH_PG | FLASH_PSIZE_16);
520 if (retval != ERROR_OK)
521 return retval;
522
523 retval = target_write_u16(target, address, value);
524 if (retval != ERROR_OK)
525 return retval;
526
527 retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT);
528 if (retval != ERROR_OK)
529 return retval;
530
531 bytes_written += 2;
532 words_remaining--;
533 address += 2;
534 }
535
536 if (bytes_remaining)
537 {
538 retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR),
539 FLASH_PG | FLASH_PSIZE_8);
540 if (retval != ERROR_OK)
541 return retval;
542 retval = target_write_u8(target, address, buffer[bytes_written]);
543 if (retval != ERROR_OK)
544 return retval;
545
546 retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT);
547 if (retval != ERROR_OK)
548 return retval;
549 }
550
551 return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
552 }
553
554 static void setup_sector(struct flash_bank *bank, int start, int num, int size)
555 {
556 for (int i = start; i < (start + num) ; i++)
557 {
558 bank->sectors[i].offset = bank->size;
559 bank->sectors[i].size = size;
560 bank->size += bank->sectors[i].size;
561 }
562 }
563
564 static int stm32x_probe(struct flash_bank *bank)
565 {
566 struct target *target = bank->target;
567 struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
568 int i;
569 uint16_t num_pages;
570 uint32_t device_id;
571 uint32_t base_address = 0x08000000;
572
573 stm32x_info->probed = 0;
574
575 /* read stm32 device id register */
576 int retval = target_read_u32(target, 0xE0042000, &device_id);
577 if (retval != ERROR_OK)
578 return retval;
579 LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
580
581 if ((device_id & 0x7ff) != 0x411)
582 {
583 LOG_WARNING("Cannot identify target as a STM32 family, try the other STM32 drivers.");
584 return ERROR_FAIL;
585 }
586
587 /* sectors sizes vary, handle this in a different code path
588 * than the rest.
589 */
590 // Uhhh.... what to use here?
591
592 /* calculate numbers of pages*/
593 num_pages = 4 + 1 + 7;
594
595 if (bank->sectors)
596 {
597 free(bank->sectors);
598 bank->sectors = NULL;
599 }
600
601 bank->base = base_address;
602 bank->num_sectors = num_pages;
603 bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
604
605 bank->size = 0;
606 setup_sector(bank, 0, 4, 16 * 1024);
607 setup_sector(bank, 4, 1, 64 * 1024);
608 setup_sector(bank, 4+1, 7, 128 * 1024);
609
610 for (i = 0; i < num_pages; i++)
611 {
612 bank->sectors[i].is_erased = -1;
613 bank->sectors[i].is_protected = 0;
614 }
615
616 LOG_INFO("flash size = %dkBytes", bank->size / 1024);
617
618 stm32x_info->probed = 1;
619
620 return ERROR_OK;
621 }
622
623 static int stm32x_auto_probe(struct flash_bank *bank)
624 {
625 struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
626 if (stm32x_info->probed)
627 return ERROR_OK;
628 return stm32x_probe(bank);
629 }
630
631 static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
632 {
633 struct target *target = bank->target;
634 uint32_t device_id;
635 int printed;
636
637 /* read stm32 device id register */
638 int retval = target_read_u32(target, 0xE0042000, &device_id);
639 if (retval != ERROR_OK)
640 return retval;
641
642 if ((device_id & 0x7ff) == 0x411)
643 {
644 printed = snprintf(buf, buf_size, "stm32x (1mByte part) - Rev: ");
645 buf += printed;
646 buf_size -= printed;
647
648 switch (device_id >> 16)
649 {
650 case 0x1000:
651 snprintf(buf, buf_size, "A");
652 break;
653
654 case 0x2000:
655 snprintf(buf, buf_size, "B");
656 break;
657
658 case 0x1001:
659 snprintf(buf, buf_size, "Z");
660 break;
661
662 case 0x2001:
663 snprintf(buf, buf_size, "Y");
664 break;
665
666 default:
667 snprintf(buf, buf_size, "unknown");
668 break;
669 }
670 }
671 else
672 {
673 snprintf(buf, buf_size, "Cannot identify target as a stm32x\n");
674 return ERROR_FAIL;
675 }
676
677 return ERROR_OK;
678 }
679
680 static const struct command_registration stm32x_exec_command_handlers[] = {
681 COMMAND_REGISTRATION_DONE
682 };
683
684 static const struct command_registration stm32x_command_handlers[] = {
685 {
686 .name = "stm32f2xxx",
687 .mode = COMMAND_ANY,
688 .help = "stm32f2xxx flash command group",
689 .chain = stm32x_exec_command_handlers,
690 },
691 COMMAND_REGISTRATION_DONE
692 };
693
694 struct flash_driver stm32xf2xxx_flash = {
695 .name = "stm32f2xxx",
696 .commands = stm32x_command_handlers,
697 .flash_bank_command = stm32x_flash_bank_command,
698 .erase = stm32x_erase,
699 .protect = stm32x_protect,
700 .write = stm32x_write,
701 .read = default_flash_read,
702 .probe = stm32x_probe,
703 .auto_probe = stm32x_auto_probe,
704 .erase_check = default_flash_mem_blank_check,
705 .protect_check = stm32x_protect_check,
706 .info = get_stm32x_info,
707 };

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)