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

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)