stellaris: device IDs
[openocd.git] / src / flash / nor / stellaris.c
1 /***************************************************************************
2 * Copyright (C) 2006 by Magnus Lundin *
3 * lundin@mlu.mine.nu *
4 * *
5 * Copyright (C) 2008 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
23
24 /***************************************************************************
25 * STELLARIS is tested on LM3S811, LM3S6965
26 ***************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "imp.h"
32 #include "stellaris.h"
33 #include <target/algorithm.h>
34 #include <target/armv7m.h>
35
36
37 #define DID0_VER(did0) ((did0 >> 28)&0x07)
38
39 static int stellaris_read_part_info(struct flash_bank *bank);
40 static uint32_t stellaris_get_flash_status(struct flash_bank *bank);
41
42 static int stellaris_mass_erase(struct flash_bank *bank);
43
44 static struct {
45 uint32_t partno;
46 char *partname;
47 } StellarisParts[] =
48 {
49 {0x0001,"LM3S101"},
50 {0x0002,"LM3S102"},
51 {0x0019,"LM3S300"},
52 {0x0011,"LM3S301"},
53 {0x001A,"LM3S308"},
54 {0x0012,"LM3S310"},
55 {0x0013,"LM3S315"},
56 {0x0014,"LM3S316"},
57 {0x0017,"LM3S317"},
58 {0x0015,"LM3S328"},
59 {0x002A,"LM3S600"},
60 {0x0021,"LM3S601"},
61 {0x002B,"LM3S608"},
62 {0x0022,"LM3S610"},
63 {0x0023,"LM3S611"},
64 {0x0024,"LM3S612"},
65 {0x0025,"LM3S613"},
66 {0x0026,"LM3S615"},
67 {0x0028,"LM3S617"},
68 {0x0029,"LM3S618"},
69 {0x0027,"LM3S628"},
70 {0x0038,"LM3S800"},
71 {0x0031,"LM3S801"},
72 {0x0039,"LM3S808"},
73 {0x0032,"LM3S811"},
74 {0x0033,"LM3S812"},
75 {0x0034,"LM3S815"},
76 {0x0036,"LM3S817"},
77 {0x0037,"LM3S818"},
78 {0x0035,"LM3S828"},
79 {0x10BF,"LM3S1110"},
80 {0x10C3,"LM3S1133"},
81 {0x10C5,"LM3S1138"},
82 {0x10C1,"LM3S1150"},
83 {0x10C4,"LM3S1162"},
84 {0x10C2,"LM3S1165"},
85 {0x10C6,"LM3S1332"},
86 {0x10BC,"LM3S1435"},
87 {0x10BA,"LM3S1439"},
88 {0x10BB,"LM3S1512"},
89 {0x10C7,"LM3S1538"},
90 {0x10DB,"LM3S1601"},
91 {0x1006,"LM3S1607"},
92 {0x10DA,"LM3S1608"},
93 {0x10C0,"LM3S1620"},
94 {0x1003,"LM3S1625"},
95 {0x1004,"LM3S1626"},
96 {0x1005,"LM3S1627"},
97 {0x10B3,"LM3S1635"},
98 {0x10BD,"LM3S1637"},
99 {0x10B9,"LM3S1751"},
100 {0x1010,"LM3S1776"},
101 {0x1016,"LM3S1811"},
102 {0x103D,"LM3S1816"},
103 {0x10B4,"LM3S1850"},
104 {0x10DD,"LM3S1911"},
105 {0x10DC,"LM3S1918"},
106 {0x10B7,"LM3S1937"},
107 {0x10BE,"LM3S1958"},
108 {0x10B5,"LM3S1960"},
109 {0x10B8,"LM3S1968"},
110 {0x100F,"LM3S1J11"},
111 {0x103C,"LM3S1J16"},
112 {0x100E,"LM3S1N11"},
113 {0x103B,"LM3S1N16"},
114 {0x1030,"LM3S1W16"},
115 {0x102F,"LM3S1Z16"},
116 {0x1051,"LM3S2110"},
117 {0x1084,"LM3S2139"},
118 {0x1039,"LM3S2276"},
119 {0x10A2,"LM3S2410"},
120 {0x1059,"LM3S2412"},
121 {0x1056,"LM3S2432"},
122 {0x105A,"LM3S2533"},
123 {0x10E1,"LM3S2601"},
124 {0x10E0,"LM3S2608"},
125 {0x1033,"LM3S2616"},
126 {0x1057,"LM3S2620"},
127 {0x1085,"LM3S2637"},
128 {0x1053,"LM3S2651"},
129 {0x1080,"LM3S2671"},
130 {0x1050,"LM3S2678"},
131 {0x10A4,"LM3S2730"},
132 {0x1052,"LM3S2739"},
133 {0x103A,"LM3S2776"},
134 {0x106D,"LM3S2793"},
135 {0x10E3,"LM3S2911"},
136 {0x10E2,"LM3S2918"},
137 {0x1054,"LM3S2939"},
138 {0x108F,"LM3S2948"},
139 {0x1058,"LM3S2950"},
140 {0x1055,"LM3S2965"},
141 {0x106C,"LM3S2B93"},
142 {0x1043,"LM3S3651"},
143 {0x1044,"LM3S3739"},
144 {0x1049,"LM3S3748"},
145 {0x1045,"LM3S3749"},
146 {0x1042,"LM3S3826"},
147 {0x1041,"LM3S3J26"},
148 {0x1040,"LM3S3N26"},
149 {0x103F,"LM3S3W26"},
150 {0x103E,"LM3S3Z26"},
151 {0x1081,"LM3S5632"},
152 {0x100C,"LM3S5651"},
153 {0x108A,"LM3S5652"},
154 {0x104D,"LM3S5656"},
155 {0x1091,"LM3S5662"},
156 {0x1096,"LM3S5732"},
157 {0x1097,"LM3S5737"},
158 {0x10A0,"LM3S5739"},
159 {0x1099,"LM3S5747"},
160 {0x10A7,"LM3S5749"},
161 {0x109A,"LM3S5752"},
162 {0x109C,"LM3S5762"},
163 {0x1069,"LM3S5791"},
164 {0x100B,"LM3S5951"},
165 {0x104E,"LM3S5956"},
166 {0x1068,"LM3S5B91"},
167 {0x1009,"LM3S5K31"},
168 {0x104A,"LM3S5K36"},
169 {0x100A,"LM3S5P31"},
170 {0x1048,"LM3S5P36"},
171 {0x100D,"LM3S5P51"},
172 {0x104C,"LM3S5P56"},
173 {0x1007,"LM3S5R31"},
174 {0x104B,"LM3S5R36"},
175 {0x1047,"LM3S5T36"},
176 {0x1046,"LM3S5Y36"},
177 {0x10A1,"LM3S6100"},
178 {0x1074,"LM3S6110"},
179 {0x10A5,"LM3S6420"},
180 {0x1082,"LM3S6422"},
181 {0x1075,"LM3S6432"},
182 {0x1076,"LM3S6537"},
183 {0x1071,"LM3S6610"},
184 {0x10E7,"LM3S6611"},
185 {0x10E6,"LM3S6618"},
186 {0x1083,"LM3S6633"},
187 {0x108B,"LM3S6637"},
188 {0x10A3,"LM3S6730"},
189 {0x1077,"LM3S6753"},
190 {0x10E9,"LM3S6911"},
191 {0x10E8,"LM3S6918"},
192 {0x1089,"LM3S6938"},
193 {0x1072,"LM3S6950"},
194 {0x1078,"LM3S6952"},
195 {0x1073,"LM3S6965"},
196 {0x1064,"LM3S8530"},
197 {0x108E,"LM3S8538"},
198 {0x1061,"LM3S8630"},
199 {0x1063,"LM3S8730"},
200 {0x108D,"LM3S8733"},
201 {0x1086,"LM3S8738"},
202 {0x1065,"LM3S8930"},
203 {0x108C,"LM3S8933"},
204 {0x1088,"LM3S8938"},
205 {0x10A6,"LM3S8962"},
206 {0x1062,"LM3S8970"},
207 {0x10D7,"LM3S8971"},
208 {0x1067,"LM3S9790"},
209 {0x106B,"LM3S9792"},
210 {0x1020,"LM3S9997"},
211 {0x1066,"LM3S9B90"},
212 {0x106A,"LM3S9B92"},
213 {0x106E,"LM3S9B95"},
214 {0x106F,"LM3S9B96"},
215 {0x1018,"LM3S9L97"},
216 {0,"Unknown part"}
217 };
218
219 static char * StellarisClassname[5] =
220 {
221 "Sandstorm",
222 "Fury",
223 "Unknown",
224 "DustDevil",
225 "Tempest"
226 };
227
228 /***************************************************************************
229 * openocd command interface *
230 ***************************************************************************/
231
232 /* flash_bank stellaris <base> <size> 0 0 <target#>
233 */
234 FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command)
235 {
236 struct stellaris_flash_bank *stellaris_info;
237
238 if (CMD_ARGC < 6)
239 {
240 LOG_WARNING("incomplete flash_bank stellaris configuration");
241 return ERROR_FLASH_BANK_INVALID;
242 }
243
244 stellaris_info = calloc(sizeof(struct stellaris_flash_bank), 1);
245 bank->base = 0x0;
246 bank->driver_priv = stellaris_info;
247
248 stellaris_info->target_name = "Unknown target";
249
250 /* part wasn't probed for info yet */
251 stellaris_info->did1 = 0;
252
253 /* TODO Specify the main crystal speed in kHz using an optional
254 * argument; ditto, the speed of an external oscillator used
255 * instead of a crystal. Avoid programming flash using IOSC.
256 */
257 return ERROR_OK;
258 }
259
260 static int stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
261 {
262 int printed, device_class;
263 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
264
265 stellaris_read_part_info(bank);
266
267 if (stellaris_info->did1 == 0)
268 {
269 printed = snprintf(buf, buf_size, "Cannot identify target as a Stellaris\n");
270 buf += printed;
271 buf_size -= printed;
272 return ERROR_FLASH_OPERATION_FAILED;
273 }
274
275 if (DID0_VER(stellaris_info->did0) > 0)
276 {
277 device_class = (stellaris_info->did0 >> 16) & 0xFF;
278 }
279 else
280 {
281 device_class = 0;
282 }
283 printed = snprintf(buf,
284 buf_size,
285 "\nTI/LMI Stellaris information: Chip is "
286 "class %i (%s) %s rev %c%i\n",
287 device_class,
288 StellarisClassname[device_class],
289 stellaris_info->target_name,
290 (int)('A' + ((stellaris_info->did0 >> 8) & 0xFF)),
291 (int)((stellaris_info->did0) & 0xFF));
292 buf += printed;
293 buf_size -= printed;
294
295 printed = snprintf(buf,
296 buf_size,
297 "did1: 0x%8.8" PRIx32 ", arch: 0x%4.4" PRIx32
298 ", eproc: %s, ramsize: %ik, flashsize: %ik\n",
299 stellaris_info->did1,
300 stellaris_info->did1,
301 "ARMv7M",
302 (int)((1 + ((stellaris_info->dc0 >> 16) & 0xFFFF))/4),
303 (int)((1 + (stellaris_info->dc0 & 0xFFFF))*2));
304 buf += printed;
305 buf_size -= printed;
306
307 printed = snprintf(buf,
308 buf_size,
309 "master clock: %ikHz%s, "
310 "rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 "\n",
311 (int)(stellaris_info->mck_freq / 1000),
312 stellaris_info->mck_desc,
313 stellaris_info->rcc,
314 stellaris_info->rcc2);
315 buf += printed;
316 buf_size -= printed;
317
318 if (stellaris_info->num_lockbits > 0)
319 {
320 printed = snprintf(buf,
321 buf_size,
322 "pagesize: %" PRIi32 ", pages: %d, "
323 "lockbits: %i, pages per lockbit: %i\n",
324 stellaris_info->pagesize,
325 (unsigned) stellaris_info->num_pages,
326 stellaris_info->num_lockbits,
327 (unsigned) stellaris_info->pages_in_lockregion);
328 buf += printed;
329 buf_size -= printed;
330 }
331 return ERROR_OK;
332 }
333
334 /***************************************************************************
335 * chip identification and status *
336 ***************************************************************************/
337
338 static uint32_t stellaris_get_flash_status(struct flash_bank *bank)
339 {
340 struct target *target = bank->target;
341 uint32_t fmc;
342
343 target_read_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, &fmc);
344
345 return fmc;
346 }
347
348 /* Setup the timimg registers */
349 static void stellaris_set_flash_mode(struct flash_bank *bank,int mode)
350 {
351 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
352 struct target *target = bank->target;
353 uint32_t usecrl = (stellaris_info->mck_freq/1000000ul-1);
354
355 LOG_DEBUG("usecrl = %i",(int)(usecrl));
356 target_write_u32(target, SCB_BASE | USECRL, usecrl);
357 }
358
359 static const unsigned rcc_xtal[32] = {
360 [0x00] = 1000000, /* no pll */
361 [0x01] = 1843200, /* no pll */
362 [0x02] = 2000000, /* no pll */
363 [0x03] = 2457600, /* no pll */
364
365 [0x04] = 3579545,
366 [0x05] = 3686400,
367 [0x06] = 4000000, /* usb */
368 [0x07] = 4096000,
369
370 [0x08] = 4915200,
371 [0x09] = 5000000, /* usb */
372 [0x0a] = 5120000,
373 [0x0b] = 6000000, /* (reset) usb */
374
375 [0x0c] = 6144000,
376 [0x0d] = 7372800,
377 [0x0e] = 8000000, /* usb */
378 [0x0f] = 8192000,
379
380 /* parts before DustDevil use just 4 bits for xtal spec */
381
382 [0x10] = 10000000, /* usb */
383 [0x11] = 12000000, /* usb */
384 [0x12] = 12288000,
385 [0x13] = 13560000,
386
387 [0x14] = 14318180,
388 [0x15] = 16000000, /* usb */
389 [0x16] = 16384000,
390 };
391
392 /** Read clock configuration and set stellaris_info->usec_clocks. */
393 static void stellaris_read_clock_info(struct flash_bank *bank)
394 {
395 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
396 struct target *target = bank->target;
397 uint32_t rcc, rcc2, pllcfg, sysdiv, usesysdiv, bypass, oscsrc;
398 unsigned xtal;
399 unsigned long mainfreq;
400
401 target_read_u32(target, SCB_BASE | RCC, &rcc);
402 LOG_DEBUG("Stellaris RCC %" PRIx32 "", rcc);
403
404 target_read_u32(target, SCB_BASE | RCC2, &rcc2);
405 LOG_DEBUG("Stellaris RCC2 %" PRIx32 "", rcc);
406
407 target_read_u32(target, SCB_BASE | PLLCFG, &pllcfg);
408 LOG_DEBUG("Stellaris PLLCFG %" PRIx32 "", pllcfg);
409
410 stellaris_info->rcc = rcc;
411 stellaris_info->rcc = rcc2;
412
413 sysdiv = (rcc >> 23) & 0xF;
414 usesysdiv = (rcc >> 22) & 0x1;
415 bypass = (rcc >> 11) & 0x1;
416 oscsrc = (rcc >> 4) & 0x3;
417 xtal = (rcc >> 6) & stellaris_info->xtal_mask;
418
419 /* NOTE: post-Sandstorm parts have RCC2 which may override
420 * parts of RCC ... with more sysdiv options, option for
421 * 32768 Hz mainfreq, PLL controls. On Sandstorm it reads
422 * as zero, so the "use RCC2" flag is always clear.
423 */
424 if (rcc2 & (1 << 31)) {
425 sysdiv = (rcc2 >> 23) & 0x3F;
426 bypass = (rcc2 >> 11) & 0x1;
427 oscsrc = (rcc2 >> 4) & 0x7;
428
429 /* FIXME Tempest parts have an additional lsb for
430 * fractional sysdiv (200 MHz / 2.5 == 80 MHz)
431 */
432 }
433
434 stellaris_info->mck_desc = "";
435
436 switch (oscsrc)
437 {
438 case 0: /* MOSC */
439 mainfreq = rcc_xtal[xtal];
440 break;
441 case 1: /* IOSC */
442 mainfreq = stellaris_info->iosc_freq;
443 stellaris_info->mck_desc = stellaris_info->iosc_desc;
444 break;
445 case 2: /* IOSC/4 */
446 mainfreq = stellaris_info->iosc_freq / 4;
447 stellaris_info->mck_desc = stellaris_info->iosc_desc;
448 break;
449 case 3: /* lowspeed */
450 /* Sandstorm doesn't have this 30K +/- 30% osc */
451 mainfreq = 30000;
452 stellaris_info->mck_desc = " (±30%)";
453 break;
454 case 8: /* hibernation osc */
455 /* not all parts support hibernation */
456 mainfreq = 32768;
457 break;
458
459 default: /* NOTREACHED */
460 mainfreq = 0;
461 break;
462 }
463
464 /* PLL is used if it's not bypassed; its output is 200 MHz
465 * even when it runs at 400 MHz (adds divide-by-two stage).
466 */
467 if (!bypass)
468 mainfreq = 200000000;
469
470 if (usesysdiv)
471 stellaris_info->mck_freq = mainfreq/(1 + sysdiv);
472 else
473 stellaris_info->mck_freq = mainfreq;
474
475 /* Forget old flash timing */
476 stellaris_set_flash_mode(bank, 0);
477 }
478
479 #if 0
480 static uint32_t stellaris_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
481 {
482 uint32_t status;
483
484 /* Stellaris waits for cmdbit to clear */
485 while (((status = stellaris_get_flash_status(bank)) & waitbits) && (timeout-- > 0))
486 {
487 LOG_DEBUG("status: 0x%x", status);
488 alive_sleep(1);
489 }
490
491 /* Flash errors are reflected in the FLASH_CRIS register */
492
493 return status;
494 }
495
496 /* Send one command to the flash controller */
497 static int stellaris_flash_command(struct flash_bank *bank,uint8_t cmd,uint16_t pagen)
498 {
499 uint32_t fmc;
500 struct target *target = bank->target;
501
502 fmc = FMC_WRKEY | cmd;
503 target_write_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, fmc);
504 LOG_DEBUG("Flash command: 0x%x", fmc);
505
506 if (stellaris_wait_status_busy(bank, cmd, 100))
507 {
508 return ERROR_FLASH_OPERATION_FAILED;
509 }
510
511 return ERROR_OK;
512 }
513 #endif
514
515 /* Read device id register, main clock frequency register and fill in driver info structure */
516 static int stellaris_read_part_info(struct flash_bank *bank)
517 {
518 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
519 struct target *target = bank->target;
520 uint32_t did0, did1, ver, fam, status;
521 int i;
522
523 /* Read and parse chip identification register */
524 target_read_u32(target, SCB_BASE | DID0, &did0);
525 target_read_u32(target, SCB_BASE | DID1, &did1);
526 target_read_u32(target, SCB_BASE | DC0, &stellaris_info->dc0);
527 target_read_u32(target, SCB_BASE | DC1, &stellaris_info->dc1);
528 LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "",
529 did0, did1, stellaris_info->dc0, stellaris_info->dc1);
530
531 ver = did0 >> 28;
532 if ((ver != 0) && (ver != 1))
533 {
534 LOG_WARNING("Unknown did0 version, cannot identify target");
535 return ERROR_FLASH_OPERATION_FAILED;
536 }
537
538 if (did1 == 0)
539 {
540 LOG_WARNING("Cannot identify target as a Stellaris");
541 return ERROR_FLASH_OPERATION_FAILED;
542 }
543
544 ver = did1 >> 28;
545 fam = (did1 >> 24) & 0xF;
546 if (((ver != 0) && (ver != 1)) || (fam != 0))
547 {
548 LOG_WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");
549 }
550
551 /* For Sandstorm, Fury, DustDevil: current data sheets say IOSC
552 * is 12 MHz, but some older parts have 15 MHz. A few data sheets
553 * even give _both_ numbers! We'll use current numbers; IOSC is
554 * always approximate.
555 *
556 * For Tempest: IOSC is calibrated, 16 MHz
557 */
558 stellaris_info->iosc_freq = 12000000;
559 stellaris_info->iosc_desc = " (±30%)";
560 stellaris_info->xtal_mask = 0x0f;
561
562 switch ((did0 >> 28) & 0x7) {
563 case 0: /* Sandstorm */
564 /*
565 * Current (2009-August) parts seem to be rev C2 and use 12 MHz.
566 * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz
567 * (LM3S618), but some other C0 parts are 12 MHz (LM3S811).
568 */
569 if (((did0 >> 8) & 0xff) < 2) {
570 stellaris_info->iosc_freq = 15000000;
571 stellaris_info->iosc_desc = " (±50%)";
572 }
573 break;
574 case 1:
575 switch ((did0 >> 16) & 0xff) {
576 case 1: /* Fury */
577 break;
578 case 4: /* Tempest */
579 stellaris_info->iosc_freq = 16000000; /* +/- 1% */
580 stellaris_info->iosc_desc = " (±1%)";
581 /* FALL THROUGH */
582 case 3: /* DustDevil */
583 stellaris_info->xtal_mask = 0x1f;
584 break;
585 default:
586 LOG_WARNING("Unknown did0 class");
587 }
588 default:
589 break;
590 LOG_WARNING("Unknown did0 version");
591 }
592
593 for (i = 0; StellarisParts[i].partno; i++)
594 {
595 if (StellarisParts[i].partno == ((did1 >> 16) & 0xFFFF))
596 break;
597 }
598
599 stellaris_info->target_name = StellarisParts[i].partname;
600
601 stellaris_info->did0 = did0;
602 stellaris_info->did1 = did1;
603
604 stellaris_info->num_lockbits = 1 + (stellaris_info->dc0 & 0xFFFF);
605 stellaris_info->num_pages = 2 *(1 + (stellaris_info->dc0 & 0xFFFF));
606 stellaris_info->pagesize = 1024;
607 bank->size = 1024 * stellaris_info->num_pages;
608 stellaris_info->pages_in_lockregion = 2;
609
610 /* provide this for the benefit of the higher flash driver layers */
611 bank->num_sectors = stellaris_info->num_pages;
612 bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
613 for (i = 0; i < bank->num_sectors; i++)
614 {
615 bank->sectors[i].offset = i * stellaris_info->pagesize;
616 bank->sectors[i].size = stellaris_info->pagesize;
617 bank->sectors[i].is_erased = -1;
618 bank->sectors[i].is_protected = -1;
619 }
620
621 /* Read main and master clock freqency register */
622 stellaris_read_clock_info(bank);
623
624 status = stellaris_get_flash_status(bank);
625
626 return ERROR_OK;
627 }
628
629 /***************************************************************************
630 * flash operations *
631 ***************************************************************************/
632
633 static int stellaris_protect_check(struct flash_bank *bank)
634 {
635 struct stellaris_flash_bank *stellaris = bank->driver_priv;
636 int status = ERROR_OK;
637 unsigned i;
638 unsigned page;
639
640 if (stellaris->did1 == 0)
641 {
642 status = stellaris_read_part_info(bank);
643 if (status < 0)
644 return status;
645 }
646
647 for (i = 0; i < (unsigned) bank->num_sectors; i++)
648 bank->sectors[i].is_protected = -1;
649
650 /* Read each Flash Memory Protection Program Enable (FMPPE) register
651 * to report any pages that we can't write. Ignore the Read Enable
652 * register (FMPRE).
653 */
654 for (i = 0, page = 0;
655 i < DIV_ROUND_UP(stellaris->num_lockbits, 32u);
656 i++) {
657 uint32_t lockbits;
658
659 status = target_read_u32(bank->target,
660 SCB_BASE + (i ? (FMPPE0 + 4 * i) : FMPPE),
661 &lockbits);
662 LOG_DEBUG("FMPPE%d = %#8.8x (status %d)", i,
663 (unsigned) lockbits, status);
664 if (status != ERROR_OK)
665 goto done;
666
667 for (unsigned j = 0; j < 32; j++) {
668 unsigned k;
669
670 for (k = 0; k < stellaris->pages_in_lockregion; k++) {
671 if (page >= (unsigned) bank->num_sectors)
672 goto done;
673 bank->sectors[page++].is_protected =
674 !(lockbits & (1 << j));
675 }
676 }
677 }
678
679 done:
680 return status;
681 }
682
683 static int stellaris_erase(struct flash_bank *bank, int first, int last)
684 {
685 int banknr;
686 uint32_t flash_fmc, flash_cris;
687 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
688 struct target *target = bank->target;
689
690 if (bank->target->state != TARGET_HALTED)
691 {
692 LOG_ERROR("Target not halted");
693 return ERROR_TARGET_NOT_HALTED;
694 }
695
696 if (stellaris_info->did1 == 0)
697 {
698 stellaris_read_part_info(bank);
699 }
700
701 if (stellaris_info->did1 == 0)
702 {
703 LOG_WARNING("Cannot identify target as Stellaris");
704 return ERROR_FLASH_OPERATION_FAILED;
705 }
706
707 if ((first < 0) || (last < first) || (last >= (int)stellaris_info->num_pages))
708 {
709 return ERROR_FLASH_SECTOR_INVALID;
710 }
711
712 if ((first == 0) && (last == ((int)stellaris_info->num_pages-1)))
713 {
714 return stellaris_mass_erase(bank);
715 }
716
717 /* Configure the flash controller timing */
718 stellaris_read_clock_info(bank);
719 stellaris_set_flash_mode(bank,0);
720
721 /* Clear and disable flash programming interrupts */
722 target_write_u32(target, FLASH_CIM, 0);
723 target_write_u32(target, FLASH_MISC, PMISC | AMISC);
724
725 for (banknr = first; banknr <= last; banknr++)
726 {
727 /* Address is first word in page */
728 target_write_u32(target, FLASH_FMA, banknr * stellaris_info->pagesize);
729 /* Write erase command */
730 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_ERASE);
731 /* Wait until erase complete */
732 do
733 {
734 target_read_u32(target, FLASH_FMC, &flash_fmc);
735 }
736 while (flash_fmc & FMC_ERASE);
737
738 /* Check acess violations */
739 target_read_u32(target, FLASH_CRIS, &flash_cris);
740 if (flash_cris & (AMASK))
741 {
742 LOG_WARNING("Error erasing flash page %i, flash_cris 0x%" PRIx32 "", banknr, flash_cris);
743 target_write_u32(target, FLASH_CRIS, 0);
744 return ERROR_FLASH_OPERATION_FAILED;
745 }
746
747 bank->sectors[banknr].is_erased = 1;
748 }
749
750 return ERROR_OK;
751 }
752
753 static int stellaris_protect(struct flash_bank *bank, int set, int first, int last)
754 {
755 uint32_t fmppe, flash_fmc, flash_cris;
756 int lockregion;
757
758 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
759 struct target *target = bank->target;
760
761 if (bank->target->state != TARGET_HALTED)
762 {
763 LOG_ERROR("Target not halted");
764 return ERROR_TARGET_NOT_HALTED;
765 }
766
767 if (!set)
768 {
769 LOG_ERROR("Can't unprotect write-protected pages.");
770 /* except by the "recover locked device" procedure ... */
771 return ERROR_INVALID_ARGUMENTS;
772 }
773
774 /* lockregions are 2 pages ... must protect [even..odd] */
775 if ((first < 0) || (first & 1)
776 || (last < first) || !(last & 1)
777 || (last >= 2 * stellaris_info->num_lockbits))
778 {
779 LOG_ERROR("Can't protect unaligned or out-of-range sectors.");
780 return ERROR_FLASH_SECTOR_INVALID;
781 }
782
783 if (stellaris_info->did1 == 0)
784 {
785 stellaris_read_part_info(bank);
786 }
787
788 if (stellaris_info->did1 == 0)
789 {
790 LOG_WARNING("Cannot identify target as an Stellaris MCU");
791 return ERROR_FLASH_OPERATION_FAILED;
792 }
793
794 /* Configure the flash controller timing */
795 stellaris_read_clock_info(bank);
796 stellaris_set_flash_mode(bank, 0);
797
798 /* convert from pages to lockregions */
799 first /= 2;
800 last /= 2;
801
802 /* FIXME this assumes single FMPPE, for a max of 64K of flash!!
803 * Current parts can be much bigger.
804 */
805 if (last >= 32) {
806 LOG_ERROR("No support yet for protection > 64K");
807 return ERROR_FLASH_OPERATION_FAILED;
808 }
809
810 target_read_u32(target, SCB_BASE | FMPPE, &fmppe);
811
812 for (lockregion = first; lockregion <= last; lockregion++)
813 fmppe &= ~(1 << lockregion);
814
815 /* Clear and disable flash programming interrupts */
816 target_write_u32(target, FLASH_CIM, 0);
817 target_write_u32(target, FLASH_MISC, PMISC | AMISC);
818
819 LOG_DEBUG("fmppe 0x%" PRIx32 "",fmppe);
820 target_write_u32(target, SCB_BASE | FMPPE, fmppe);
821
822 /* Commit FMPPE */
823 target_write_u32(target, FLASH_FMA, 1);
824
825 /* Write commit command */
826 /* REVISIT safety check, since this cannot be undone
827 * except by the "Recover a locked device" procedure.
828 */
829 LOG_WARNING("Flash protection cannot be removed once commited, commit is NOT executed !");
830 /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */
831
832 /* Wait until erase complete */
833 do
834 {
835 target_read_u32(target, FLASH_FMC, &flash_fmc);
836 }
837 while (flash_fmc & FMC_COMT);
838
839 /* Check acess violations */
840 target_read_u32(target, FLASH_CRIS, &flash_cris);
841 if (flash_cris & (AMASK))
842 {
843 LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris);
844 target_write_u32(target, FLASH_CRIS, 0);
845 return ERROR_FLASH_OPERATION_FAILED;
846 }
847
848 return ERROR_OK;
849 }
850
851 static const uint8_t stellaris_write_code[] =
852 {
853 /*
854 Call with :
855 r0 = buffer address
856 r1 = destination address
857 r2 = bytecount (in) - endaddr (work)
858
859 Used registers:
860 r3 = pFLASH_CTRL_BASE
861 r4 = FLASHWRITECMD
862 r5 = #1
863 r6 = bytes written
864 r7 = temp reg
865 */
866 0x07,0x4B, /* ldr r3,pFLASH_CTRL_BASE */
867 0x08,0x4C, /* ldr r4,FLASHWRITECMD */
868 0x01,0x25, /* movs r5, 1 */
869 0x00,0x26, /* movs r6, #0 */
870 /* mainloop: */
871 0x19,0x60, /* str r1, [r3, #0] */
872 0x87,0x59, /* ldr r7, [r0, r6] */
873 0x5F,0x60, /* str r7, [r3, #4] */
874 0x9C,0x60, /* str r4, [r3, #8] */
875 /* waitloop: */
876 0x9F,0x68, /* ldr r7, [r3, #8] */
877 0x2F,0x42, /* tst r7, r5 */
878 0xFC,0xD1, /* bne waitloop */
879 0x04,0x31, /* adds r1, r1, #4 */
880 0x04,0x36, /* adds r6, r6, #4 */
881 0x96,0x42, /* cmp r6, r2 */
882 0xF4,0xD1, /* bne mainloop */
883 /* exit: */
884 0xFE,0xE7, /* b exit */
885 /* pFLASH_CTRL_BASE: */
886 0x00,0xD0,0x0F,0x40, /* .word 0x400FD000 */
887 /* FLASHWRITECMD: */
888 0x01,0x00,0x42,0xA4 /* .word 0xA4420001 */
889 };
890
891 static int stellaris_write_block(struct flash_bank *bank,
892 uint8_t *buffer, uint32_t offset, uint32_t wcount)
893 {
894 struct target *target = bank->target;
895 uint32_t buffer_size = 8192;
896 struct working_area *source;
897 struct working_area *write_algorithm;
898 uint32_t address = bank->base + offset;
899 struct reg_param reg_params[3];
900 struct armv7m_algorithm armv7m_info;
901 int retval = ERROR_OK;
902
903 LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "",
904 bank, buffer, offset, wcount);
905
906 /* flash write code */
907 if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK)
908 {
909 LOG_WARNING("no working area available, can't do block memory writes");
910 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
911 };
912
913 target_write_buffer(target, write_algorithm->address,
914 sizeof(stellaris_write_code),
915 (uint8_t *) stellaris_write_code);
916
917 /* memory buffer */
918 while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
919 {
920 LOG_DEBUG("called target_alloc_working_area(target=%p buffer_size=%08" PRIx32 " source=%p)",
921 target, buffer_size, source);
922 buffer_size /= 2;
923 if (buffer_size <= 256)
924 {
925 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
926 if (write_algorithm)
927 target_free_working_area(target, write_algorithm);
928
929 LOG_WARNING("no large enough working area available, can't do block memory writes");
930 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
931 }
932 };
933
934 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
935 armv7m_info.core_mode = ARMV7M_MODE_ANY;
936
937 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
938 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
939 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
940
941 while (wcount > 0)
942 {
943 uint32_t thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
944
945 target_write_buffer(target, source->address, thisrun_count * 4, buffer);
946
947 buf_set_u32(reg_params[0].value, 0, 32, source->address);
948 buf_set_u32(reg_params[1].value, 0, 32, address);
949 buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count);
950 LOG_INFO("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
951 LOG_DEBUG("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
952 if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, write_algorithm->address + sizeof(stellaris_write_code)-10, 10000, &armv7m_info)) != ERROR_OK)
953 {
954 LOG_ERROR("error executing stellaris flash write algorithm");
955 retval = ERROR_FLASH_OPERATION_FAILED;
956 break;
957 }
958
959 buffer += thisrun_count * 4;
960 address += thisrun_count * 4;
961 wcount -= thisrun_count;
962 }
963
964 target_free_working_area(target, write_algorithm);
965 target_free_working_area(target, source);
966
967 destroy_reg_param(&reg_params[0]);
968 destroy_reg_param(&reg_params[1]);
969 destroy_reg_param(&reg_params[2]);
970
971 return retval;
972 }
973
974 static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
975 {
976 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
977 struct target *target = bank->target;
978 uint32_t address = offset;
979 uint32_t flash_cris, flash_fmc;
980 uint32_t words_remaining = (count / 4);
981 uint32_t bytes_remaining = (count & 0x00000003);
982 uint32_t bytes_written = 0;
983 int retval;
984
985 if (bank->target->state != TARGET_HALTED)
986 {
987 LOG_ERROR("Target not halted");
988 return ERROR_TARGET_NOT_HALTED;
989 }
990
991 LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "",
992 bank, buffer, offset, count);
993
994 if (stellaris_info->did1 == 0)
995 {
996 stellaris_read_part_info(bank);
997 }
998
999 if (stellaris_info->did1 == 0)
1000 {
1001 LOG_WARNING("Cannot identify target as a Stellaris processor");
1002 return ERROR_FLASH_OPERATION_FAILED;
1003 }
1004
1005 if (offset & 0x3)
1006 {
1007 LOG_WARNING("offset size must be word aligned");
1008 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
1009 }
1010
1011 if (offset + count > bank->size)
1012 return ERROR_FLASH_DST_OUT_OF_BANK;
1013
1014 /* Configure the flash controller timing */
1015 stellaris_read_clock_info(bank);
1016 stellaris_set_flash_mode(bank, 0);
1017
1018 /* Clear and disable flash programming interrupts */
1019 target_write_u32(target, FLASH_CIM, 0);
1020 target_write_u32(target, FLASH_MISC, PMISC | AMISC);
1021
1022 /* multiple words to be programmed? */
1023 if (words_remaining > 0)
1024 {
1025 /* try using a block write */
1026 if ((retval = stellaris_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
1027 {
1028 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
1029 {
1030 /* if block write failed (no sufficient working area),
1031 * we use normal (slow) single dword accesses */
1032 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
1033 }
1034 else if (retval == ERROR_FLASH_OPERATION_FAILED)
1035 {
1036 /* if an error occured, we examine the reason, and quit */
1037 target_read_u32(target, FLASH_CRIS, &flash_cris);
1038
1039 LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32 "", flash_cris);
1040 return ERROR_FLASH_OPERATION_FAILED;
1041 }
1042 }
1043 else
1044 {
1045 buffer += words_remaining * 4;
1046 address += words_remaining * 4;
1047 words_remaining = 0;
1048 }
1049 }
1050
1051 while (words_remaining > 0)
1052 {
1053 if (!(address & 0xff))
1054 LOG_DEBUG("0x%" PRIx32 "", address);
1055
1056 /* Program one word */
1057 target_write_u32(target, FLASH_FMA, address);
1058 target_write_buffer(target, FLASH_FMD, 4, buffer);
1059 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);
1060 /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */
1061 /* Wait until write complete */
1062 do
1063 {
1064 target_read_u32(target, FLASH_FMC, &flash_fmc);
1065 } while (flash_fmc & FMC_WRITE);
1066
1067 buffer += 4;
1068 address += 4;
1069 words_remaining--;
1070 }
1071
1072 if (bytes_remaining)
1073 {
1074 uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff};
1075 int i = 0;
1076
1077 while (bytes_remaining > 0)
1078 {
1079 last_word[i++] = *(buffer + bytes_written);
1080 bytes_remaining--;
1081 bytes_written++;
1082 }
1083
1084 if (!(address & 0xff))
1085 LOG_DEBUG("0x%" PRIx32 "", address);
1086
1087 /* Program one word */
1088 target_write_u32(target, FLASH_FMA, address);
1089 target_write_buffer(target, FLASH_FMD, 4, last_word);
1090 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);
1091 /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */
1092 /* Wait until write complete */
1093 do
1094 {
1095 target_read_u32(target, FLASH_FMC, &flash_fmc);
1096 } while (flash_fmc & FMC_WRITE);
1097 }
1098
1099 /* Check access violations */
1100 target_read_u32(target, FLASH_CRIS, &flash_cris);
1101 if (flash_cris & (AMASK))
1102 {
1103 LOG_DEBUG("flash_cris 0x%" PRIx32 "", flash_cris);
1104 return ERROR_FLASH_OPERATION_FAILED;
1105 }
1106 return ERROR_OK;
1107 }
1108
1109 static int stellaris_probe(struct flash_bank *bank)
1110 {
1111 /* we can't probe on an stellaris
1112 * if this is an stellaris, it has the configured flash
1113 */
1114
1115 if (bank->target->state != TARGET_HALTED)
1116 {
1117 LOG_ERROR("Target not halted");
1118 return ERROR_TARGET_NOT_HALTED;
1119 }
1120
1121 /* stellaris_read_part_info() already takes care about error checking and reporting */
1122 return stellaris_read_part_info(bank);
1123 }
1124
1125 static int stellaris_auto_probe(struct flash_bank *bank)
1126 {
1127 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
1128 if (stellaris_info->did1)
1129 return ERROR_OK;
1130 return stellaris_probe(bank);
1131 }
1132
1133 static int stellaris_mass_erase(struct flash_bank *bank)
1134 {
1135 struct target *target = NULL;
1136 struct stellaris_flash_bank *stellaris_info = NULL;
1137 uint32_t flash_fmc;
1138
1139 stellaris_info = bank->driver_priv;
1140 target = bank->target;
1141
1142 if (target->state != TARGET_HALTED)
1143 {
1144 LOG_ERROR("Target not halted");
1145 return ERROR_TARGET_NOT_HALTED;
1146 }
1147
1148 if (stellaris_info->did1 == 0)
1149 {
1150 stellaris_read_part_info(bank);
1151 }
1152
1153 if (stellaris_info->did1 == 0)
1154 {
1155 LOG_WARNING("Cannot identify target as Stellaris");
1156 return ERROR_FLASH_OPERATION_FAILED;
1157 }
1158
1159 /* Configure the flash controller timing */
1160 stellaris_read_clock_info(bank);
1161 stellaris_set_flash_mode(bank, 0);
1162
1163 /* Clear and disable flash programming interrupts */
1164 target_write_u32(target, FLASH_CIM, 0);
1165 target_write_u32(target, FLASH_MISC, PMISC | AMISC);
1166
1167 target_write_u32(target, FLASH_FMA, 0);
1168 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
1169 /* Wait until erase complete */
1170 do
1171 {
1172 target_read_u32(target, FLASH_FMC, &flash_fmc);
1173 }
1174 while (flash_fmc & FMC_MERASE);
1175
1176 /* if device has > 128k, then second erase cycle is needed
1177 * this is only valid for older devices, but will not hurt */
1178 if (stellaris_info->num_pages * stellaris_info->pagesize > 0x20000)
1179 {
1180 target_write_u32(target, FLASH_FMA, 0x20000);
1181 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
1182 /* Wait until erase complete */
1183 do
1184 {
1185 target_read_u32(target, FLASH_FMC, &flash_fmc);
1186 }
1187 while (flash_fmc & FMC_MERASE);
1188 }
1189
1190 return ERROR_OK;
1191 }
1192
1193 COMMAND_HANDLER(stellaris_handle_mass_erase_command)
1194 {
1195 int i;
1196
1197 if (CMD_ARGC < 1)
1198 {
1199 command_print(CMD_CTX, "stellaris mass_erase <bank>");
1200 return ERROR_OK;
1201 }
1202
1203 struct flash_bank *bank;
1204 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
1205 if (ERROR_OK != retval)
1206 return retval;
1207
1208 if (stellaris_mass_erase(bank) == ERROR_OK)
1209 {
1210 /* set all sectors as erased */
1211 for (i = 0; i < bank->num_sectors; i++)
1212 {
1213 bank->sectors[i].is_erased = 1;
1214 }
1215
1216 command_print(CMD_CTX, "stellaris mass erase complete");
1217 }
1218 else
1219 {
1220 command_print(CMD_CTX, "stellaris mass erase failed");
1221 }
1222
1223 return ERROR_OK;
1224 }
1225
1226 static const struct command_registration stellaris_exec_command_handlers[] = {
1227 {
1228 .name = "mass_erase",
1229 .handler = &stellaris_handle_mass_erase_command,
1230 .mode = COMMAND_EXEC,
1231 .help = "erase entire device",
1232 },
1233 COMMAND_REGISTRATION_DONE
1234 };
1235 static const struct command_registration stellaris_command_handlers[] = {
1236 {
1237 .name = "stellaris",
1238 .mode = COMMAND_ANY,
1239 .help = "Stellaris flash command group",
1240 .chain = stellaris_exec_command_handlers,
1241 },
1242 COMMAND_REGISTRATION_DONE
1243 };
1244
1245 struct flash_driver stellaris_flash = {
1246 .name = "stellaris",
1247 .commands = stellaris_command_handlers,
1248 .flash_bank_command = stellaris_flash_bank_command,
1249 .erase = stellaris_erase,
1250 .protect = stellaris_protect,
1251 .write = stellaris_write,
1252 .probe = stellaris_probe,
1253 .auto_probe = stellaris_auto_probe,
1254 .erase_check = default_flash_mem_blank_check,
1255 .protect_check = stellaris_protect_check,
1256 .info = stellaris_info,
1257 };

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)