stellaris: avoid chip writes
[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 /* Set the flash timimg register to match current clocking */
349 static void stellaris_set_flash_timing(struct flash_bank *bank)
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
476 #if 0
477 static uint32_t stellaris_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
478 {
479 uint32_t status;
480
481 /* Stellaris waits for cmdbit to clear */
482 while (((status = stellaris_get_flash_status(bank)) & waitbits) && (timeout-- > 0))
483 {
484 LOG_DEBUG("status: 0x%x", status);
485 alive_sleep(1);
486 }
487
488 /* Flash errors are reflected in the FLASH_CRIS register */
489
490 return status;
491 }
492
493 /* Send one command to the flash controller */
494 static int stellaris_flash_command(struct flash_bank *bank,uint8_t cmd,uint16_t pagen)
495 {
496 uint32_t fmc;
497 struct target *target = bank->target;
498
499 fmc = FMC_WRKEY | cmd;
500 target_write_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, fmc);
501 LOG_DEBUG("Flash command: 0x%x", fmc);
502
503 if (stellaris_wait_status_busy(bank, cmd, 100))
504 {
505 return ERROR_FLASH_OPERATION_FAILED;
506 }
507
508 return ERROR_OK;
509 }
510 #endif
511
512 /* Read device id register, main clock frequency register and fill in driver info structure */
513 static int stellaris_read_part_info(struct flash_bank *bank)
514 {
515 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
516 struct target *target = bank->target;
517 uint32_t did0, did1, ver, fam, status;
518 int i;
519
520 /* Read and parse chip identification register */
521 target_read_u32(target, SCB_BASE | DID0, &did0);
522 target_read_u32(target, SCB_BASE | DID1, &did1);
523 target_read_u32(target, SCB_BASE | DC0, &stellaris_info->dc0);
524 target_read_u32(target, SCB_BASE | DC1, &stellaris_info->dc1);
525 LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "",
526 did0, did1, stellaris_info->dc0, stellaris_info->dc1);
527
528 ver = did0 >> 28;
529 if ((ver != 0) && (ver != 1))
530 {
531 LOG_WARNING("Unknown did0 version, cannot identify target");
532 return ERROR_FLASH_OPERATION_FAILED;
533 }
534
535 if (did1 == 0)
536 {
537 LOG_WARNING("Cannot identify target as a Stellaris");
538 return ERROR_FLASH_OPERATION_FAILED;
539 }
540
541 ver = did1 >> 28;
542 fam = (did1 >> 24) & 0xF;
543 if (((ver != 0) && (ver != 1)) || (fam != 0))
544 {
545 LOG_WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");
546 }
547
548 /* For Sandstorm, Fury, DustDevil: current data sheets say IOSC
549 * is 12 MHz, but some older parts have 15 MHz. A few data sheets
550 * even give _both_ numbers! We'll use current numbers; IOSC is
551 * always approximate.
552 *
553 * For Tempest: IOSC is calibrated, 16 MHz
554 */
555 stellaris_info->iosc_freq = 12000000;
556 stellaris_info->iosc_desc = " (±30%)";
557 stellaris_info->xtal_mask = 0x0f;
558
559 switch ((did0 >> 28) & 0x7) {
560 case 0: /* Sandstorm */
561 /*
562 * Current (2009-August) parts seem to be rev C2 and use 12 MHz.
563 * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz
564 * (LM3S618), but some other C0 parts are 12 MHz (LM3S811).
565 */
566 if (((did0 >> 8) & 0xff) < 2) {
567 stellaris_info->iosc_freq = 15000000;
568 stellaris_info->iosc_desc = " (±50%)";
569 }
570 break;
571 case 1:
572 switch ((did0 >> 16) & 0xff) {
573 case 1: /* Fury */
574 break;
575 case 4: /* Tempest */
576 stellaris_info->iosc_freq = 16000000; /* +/- 1% */
577 stellaris_info->iosc_desc = " (±1%)";
578 /* FALL THROUGH */
579 case 3: /* DustDevil */
580 stellaris_info->xtal_mask = 0x1f;
581 break;
582 default:
583 LOG_WARNING("Unknown did0 class");
584 }
585 default:
586 break;
587 LOG_WARNING("Unknown did0 version");
588 }
589
590 for (i = 0; StellarisParts[i].partno; i++)
591 {
592 if (StellarisParts[i].partno == ((did1 >> 16) & 0xFFFF))
593 break;
594 }
595
596 stellaris_info->target_name = StellarisParts[i].partname;
597
598 stellaris_info->did0 = did0;
599 stellaris_info->did1 = did1;
600
601 stellaris_info->num_lockbits = 1 + (stellaris_info->dc0 & 0xFFFF);
602 stellaris_info->num_pages = 2 *(1 + (stellaris_info->dc0 & 0xFFFF));
603 stellaris_info->pagesize = 1024;
604 bank->size = 1024 * stellaris_info->num_pages;
605 stellaris_info->pages_in_lockregion = 2;
606
607 /* provide this for the benefit of the higher flash driver layers */
608 bank->num_sectors = stellaris_info->num_pages;
609 bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
610 for (i = 0; i < bank->num_sectors; i++)
611 {
612 bank->sectors[i].offset = i * stellaris_info->pagesize;
613 bank->sectors[i].size = stellaris_info->pagesize;
614 bank->sectors[i].is_erased = -1;
615 bank->sectors[i].is_protected = -1;
616 }
617
618 /* Read main and master clock freqency register */
619 stellaris_read_clock_info(bank);
620
621 status = stellaris_get_flash_status(bank);
622
623 return ERROR_OK;
624 }
625
626 /***************************************************************************
627 * flash operations *
628 ***************************************************************************/
629
630 static int stellaris_protect_check(struct flash_bank *bank)
631 {
632 struct stellaris_flash_bank *stellaris = bank->driver_priv;
633 int status = ERROR_OK;
634 unsigned i;
635 unsigned page;
636
637 if (stellaris->did1 == 0)
638 {
639 status = stellaris_read_part_info(bank);
640 if (status < 0)
641 return status;
642 }
643
644 for (i = 0; i < (unsigned) bank->num_sectors; i++)
645 bank->sectors[i].is_protected = -1;
646
647 /* Read each Flash Memory Protection Program Enable (FMPPE) register
648 * to report any pages that we can't write. Ignore the Read Enable
649 * register (FMPRE).
650 */
651 for (i = 0, page = 0;
652 i < DIV_ROUND_UP(stellaris->num_lockbits, 32u);
653 i++) {
654 uint32_t lockbits;
655
656 status = target_read_u32(bank->target,
657 SCB_BASE + (i ? (FMPPE0 + 4 * i) : FMPPE),
658 &lockbits);
659 LOG_DEBUG("FMPPE%d = %#8.8x (status %d)", i,
660 (unsigned) lockbits, status);
661 if (status != ERROR_OK)
662 goto done;
663
664 for (unsigned j = 0; j < 32; j++) {
665 unsigned k;
666
667 for (k = 0; k < stellaris->pages_in_lockregion; k++) {
668 if (page >= (unsigned) bank->num_sectors)
669 goto done;
670 bank->sectors[page++].is_protected =
671 !(lockbits & (1 << j));
672 }
673 }
674 }
675
676 done:
677 return status;
678 }
679
680 static int stellaris_erase(struct flash_bank *bank, int first, int last)
681 {
682 int banknr;
683 uint32_t flash_fmc, flash_cris;
684 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
685 struct target *target = bank->target;
686
687 if (bank->target->state != TARGET_HALTED)
688 {
689 LOG_ERROR("Target not halted");
690 return ERROR_TARGET_NOT_HALTED;
691 }
692
693 if (stellaris_info->did1 == 0)
694 {
695 stellaris_read_part_info(bank);
696 }
697
698 if (stellaris_info->did1 == 0)
699 {
700 LOG_WARNING("Cannot identify target as Stellaris");
701 return ERROR_FLASH_OPERATION_FAILED;
702 }
703
704 if ((first < 0) || (last < first) || (last >= (int)stellaris_info->num_pages))
705 {
706 return ERROR_FLASH_SECTOR_INVALID;
707 }
708
709 if ((first == 0) && (last == ((int)stellaris_info->num_pages-1)))
710 {
711 return stellaris_mass_erase(bank);
712 }
713
714 /* Refresh flash controller timing */
715 stellaris_read_clock_info(bank);
716 stellaris_set_flash_timing(bank);
717
718 /* Clear and disable flash programming interrupts */
719 target_write_u32(target, FLASH_CIM, 0);
720 target_write_u32(target, FLASH_MISC, PMISC | AMISC);
721
722 for (banknr = first; banknr <= last; banknr++)
723 {
724 /* Address is first word in page */
725 target_write_u32(target, FLASH_FMA, banknr * stellaris_info->pagesize);
726 /* Write erase command */
727 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_ERASE);
728 /* Wait until erase complete */
729 do
730 {
731 target_read_u32(target, FLASH_FMC, &flash_fmc);
732 }
733 while (flash_fmc & FMC_ERASE);
734
735 /* Check acess violations */
736 target_read_u32(target, FLASH_CRIS, &flash_cris);
737 if (flash_cris & (AMASK))
738 {
739 LOG_WARNING("Error erasing flash page %i, flash_cris 0x%" PRIx32 "", banknr, flash_cris);
740 target_write_u32(target, FLASH_CRIS, 0);
741 return ERROR_FLASH_OPERATION_FAILED;
742 }
743
744 bank->sectors[banknr].is_erased = 1;
745 }
746
747 return ERROR_OK;
748 }
749
750 static int stellaris_protect(struct flash_bank *bank, int set, int first, int last)
751 {
752 uint32_t fmppe, flash_fmc, flash_cris;
753 int lockregion;
754
755 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
756 struct target *target = bank->target;
757
758 if (bank->target->state != TARGET_HALTED)
759 {
760 LOG_ERROR("Target not halted");
761 return ERROR_TARGET_NOT_HALTED;
762 }
763
764 if (!set)
765 {
766 LOG_ERROR("Can't unprotect write-protected pages.");
767 /* except by the "recover locked device" procedure ... */
768 return ERROR_INVALID_ARGUMENTS;
769 }
770
771 /* lockregions are 2 pages ... must protect [even..odd] */
772 if ((first < 0) || (first & 1)
773 || (last < first) || !(last & 1)
774 || (last >= 2 * stellaris_info->num_lockbits))
775 {
776 LOG_ERROR("Can't protect unaligned or out-of-range sectors.");
777 return ERROR_FLASH_SECTOR_INVALID;
778 }
779
780 if (stellaris_info->did1 == 0)
781 {
782 stellaris_read_part_info(bank);
783 }
784
785 if (stellaris_info->did1 == 0)
786 {
787 LOG_WARNING("Cannot identify target as an Stellaris MCU");
788 return ERROR_FLASH_OPERATION_FAILED;
789 }
790
791 /* Refresh flash controller timing */
792 stellaris_read_clock_info(bank);
793 stellaris_set_flash_timing(bank);
794
795 /* convert from pages to lockregions */
796 first /= 2;
797 last /= 2;
798
799 /* FIXME this assumes single FMPPE, for a max of 64K of flash!!
800 * Current parts can be much bigger.
801 */
802 if (last >= 32) {
803 LOG_ERROR("No support yet for protection > 64K");
804 return ERROR_FLASH_OPERATION_FAILED;
805 }
806
807 target_read_u32(target, SCB_BASE | FMPPE, &fmppe);
808
809 for (lockregion = first; lockregion <= last; lockregion++)
810 fmppe &= ~(1 << lockregion);
811
812 /* Clear and disable flash programming interrupts */
813 target_write_u32(target, FLASH_CIM, 0);
814 target_write_u32(target, FLASH_MISC, PMISC | AMISC);
815
816 LOG_DEBUG("fmppe 0x%" PRIx32 "",fmppe);
817 target_write_u32(target, SCB_BASE | FMPPE, fmppe);
818
819 /* Commit FMPPE */
820 target_write_u32(target, FLASH_FMA, 1);
821
822 /* Write commit command */
823 /* REVISIT safety check, since this cannot be undone
824 * except by the "Recover a locked device" procedure.
825 */
826 LOG_WARNING("Flash protection cannot be removed once commited, commit is NOT executed !");
827 /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */
828
829 /* Wait until erase complete */
830 do
831 {
832 target_read_u32(target, FLASH_FMC, &flash_fmc);
833 }
834 while (flash_fmc & FMC_COMT);
835
836 /* Check acess violations */
837 target_read_u32(target, FLASH_CRIS, &flash_cris);
838 if (flash_cris & (AMASK))
839 {
840 LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris);
841 target_write_u32(target, FLASH_CRIS, 0);
842 return ERROR_FLASH_OPERATION_FAILED;
843 }
844
845 return ERROR_OK;
846 }
847
848 static const uint8_t stellaris_write_code[] =
849 {
850 /*
851 Call with :
852 r0 = buffer address
853 r1 = destination address
854 r2 = bytecount (in) - endaddr (work)
855
856 Used registers:
857 r3 = pFLASH_CTRL_BASE
858 r4 = FLASHWRITECMD
859 r5 = #1
860 r6 = bytes written
861 r7 = temp reg
862 */
863 0x07,0x4B, /* ldr r3,pFLASH_CTRL_BASE */
864 0x08,0x4C, /* ldr r4,FLASHWRITECMD */
865 0x01,0x25, /* movs r5, 1 */
866 0x00,0x26, /* movs r6, #0 */
867 /* mainloop: */
868 0x19,0x60, /* str r1, [r3, #0] */
869 0x87,0x59, /* ldr r7, [r0, r6] */
870 0x5F,0x60, /* str r7, [r3, #4] */
871 0x9C,0x60, /* str r4, [r3, #8] */
872 /* waitloop: */
873 0x9F,0x68, /* ldr r7, [r3, #8] */
874 0x2F,0x42, /* tst r7, r5 */
875 0xFC,0xD1, /* bne waitloop */
876 0x04,0x31, /* adds r1, r1, #4 */
877 0x04,0x36, /* adds r6, r6, #4 */
878 0x96,0x42, /* cmp r6, r2 */
879 0xF4,0xD1, /* bne mainloop */
880 /* exit: */
881 0xFE,0xE7, /* b exit */
882 /* pFLASH_CTRL_BASE: */
883 0x00,0xD0,0x0F,0x40, /* .word 0x400FD000 */
884 /* FLASHWRITECMD: */
885 0x01,0x00,0x42,0xA4 /* .word 0xA4420001 */
886 };
887
888 static int stellaris_write_block(struct flash_bank *bank,
889 uint8_t *buffer, uint32_t offset, uint32_t wcount)
890 {
891 struct target *target = bank->target;
892 uint32_t buffer_size = 8192;
893 struct working_area *source;
894 struct working_area *write_algorithm;
895 uint32_t address = bank->base + offset;
896 struct reg_param reg_params[3];
897 struct armv7m_algorithm armv7m_info;
898 int retval = ERROR_OK;
899
900 LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "",
901 bank, buffer, offset, wcount);
902
903 /* flash write code */
904 if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK)
905 {
906 LOG_WARNING("no working area available, can't do block memory writes");
907 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
908 };
909
910 target_write_buffer(target, write_algorithm->address,
911 sizeof(stellaris_write_code),
912 (uint8_t *) stellaris_write_code);
913
914 /* memory buffer */
915 while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
916 {
917 LOG_DEBUG("called target_alloc_working_area(target=%p buffer_size=%08" PRIx32 " source=%p)",
918 target, buffer_size, source);
919 buffer_size /= 2;
920 if (buffer_size <= 256)
921 {
922 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
923 if (write_algorithm)
924 target_free_working_area(target, write_algorithm);
925
926 LOG_WARNING("no large enough working area available, can't do block memory writes");
927 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
928 }
929 };
930
931 armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
932 armv7m_info.core_mode = ARMV7M_MODE_ANY;
933
934 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
935 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
936 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
937
938 while (wcount > 0)
939 {
940 uint32_t thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
941
942 target_write_buffer(target, source->address, thisrun_count * 4, buffer);
943
944 buf_set_u32(reg_params[0].value, 0, 32, source->address);
945 buf_set_u32(reg_params[1].value, 0, 32, address);
946 buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count);
947 LOG_INFO("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
948 LOG_DEBUG("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
949 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)
950 {
951 LOG_ERROR("error executing stellaris flash write algorithm");
952 retval = ERROR_FLASH_OPERATION_FAILED;
953 break;
954 }
955
956 buffer += thisrun_count * 4;
957 address += thisrun_count * 4;
958 wcount -= thisrun_count;
959 }
960
961 target_free_working_area(target, write_algorithm);
962 target_free_working_area(target, source);
963
964 destroy_reg_param(&reg_params[0]);
965 destroy_reg_param(&reg_params[1]);
966 destroy_reg_param(&reg_params[2]);
967
968 return retval;
969 }
970
971 static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
972 {
973 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
974 struct target *target = bank->target;
975 uint32_t address = offset;
976 uint32_t flash_cris, flash_fmc;
977 uint32_t words_remaining = (count / 4);
978 uint32_t bytes_remaining = (count & 0x00000003);
979 uint32_t bytes_written = 0;
980 int retval;
981
982 if (bank->target->state != TARGET_HALTED)
983 {
984 LOG_ERROR("Target not halted");
985 return ERROR_TARGET_NOT_HALTED;
986 }
987
988 LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "",
989 bank, buffer, offset, count);
990
991 if (stellaris_info->did1 == 0)
992 {
993 stellaris_read_part_info(bank);
994 }
995
996 if (stellaris_info->did1 == 0)
997 {
998 LOG_WARNING("Cannot identify target as a Stellaris processor");
999 return ERROR_FLASH_OPERATION_FAILED;
1000 }
1001
1002 if (offset & 0x3)
1003 {
1004 LOG_WARNING("offset size must be word aligned");
1005 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
1006 }
1007
1008 if (offset + count > bank->size)
1009 return ERROR_FLASH_DST_OUT_OF_BANK;
1010
1011 /* Refresh flash controller timing */
1012 stellaris_read_clock_info(bank);
1013 stellaris_set_flash_timing(bank);
1014
1015 /* Clear and disable flash programming interrupts */
1016 target_write_u32(target, FLASH_CIM, 0);
1017 target_write_u32(target, FLASH_MISC, PMISC | AMISC);
1018
1019 /* multiple words to be programmed? */
1020 if (words_remaining > 0)
1021 {
1022 /* try using a block write */
1023 if ((retval = stellaris_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
1024 {
1025 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
1026 {
1027 /* if block write failed (no sufficient working area),
1028 * we use normal (slow) single dword accesses */
1029 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
1030 }
1031 else if (retval == ERROR_FLASH_OPERATION_FAILED)
1032 {
1033 /* if an error occured, we examine the reason, and quit */
1034 target_read_u32(target, FLASH_CRIS, &flash_cris);
1035
1036 LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32 "", flash_cris);
1037 return ERROR_FLASH_OPERATION_FAILED;
1038 }
1039 }
1040 else
1041 {
1042 buffer += words_remaining * 4;
1043 address += words_remaining * 4;
1044 words_remaining = 0;
1045 }
1046 }
1047
1048 while (words_remaining > 0)
1049 {
1050 if (!(address & 0xff))
1051 LOG_DEBUG("0x%" PRIx32 "", address);
1052
1053 /* Program one word */
1054 target_write_u32(target, FLASH_FMA, address);
1055 target_write_buffer(target, FLASH_FMD, 4, buffer);
1056 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);
1057 /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */
1058 /* Wait until write complete */
1059 do
1060 {
1061 target_read_u32(target, FLASH_FMC, &flash_fmc);
1062 } while (flash_fmc & FMC_WRITE);
1063
1064 buffer += 4;
1065 address += 4;
1066 words_remaining--;
1067 }
1068
1069 if (bytes_remaining)
1070 {
1071 uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff};
1072 int i = 0;
1073
1074 while (bytes_remaining > 0)
1075 {
1076 last_word[i++] = *(buffer + bytes_written);
1077 bytes_remaining--;
1078 bytes_written++;
1079 }
1080
1081 if (!(address & 0xff))
1082 LOG_DEBUG("0x%" PRIx32 "", address);
1083
1084 /* Program one word */
1085 target_write_u32(target, FLASH_FMA, address);
1086 target_write_buffer(target, FLASH_FMD, 4, last_word);
1087 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE);
1088 /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */
1089 /* Wait until write complete */
1090 do
1091 {
1092 target_read_u32(target, FLASH_FMC, &flash_fmc);
1093 } while (flash_fmc & FMC_WRITE);
1094 }
1095
1096 /* Check access violations */
1097 target_read_u32(target, FLASH_CRIS, &flash_cris);
1098 if (flash_cris & (AMASK))
1099 {
1100 LOG_DEBUG("flash_cris 0x%" PRIx32 "", flash_cris);
1101 return ERROR_FLASH_OPERATION_FAILED;
1102 }
1103 return ERROR_OK;
1104 }
1105
1106 static int stellaris_probe(struct flash_bank *bank)
1107 {
1108 /* we can't probe on an stellaris
1109 * if this is an stellaris, it has the configured flash
1110 */
1111
1112 if (bank->target->state != TARGET_HALTED)
1113 {
1114 LOG_ERROR("Target not halted");
1115 return ERROR_TARGET_NOT_HALTED;
1116 }
1117
1118 /* stellaris_read_part_info() already takes care about error checking and reporting */
1119 return stellaris_read_part_info(bank);
1120 }
1121
1122 static int stellaris_auto_probe(struct flash_bank *bank)
1123 {
1124 struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
1125 if (stellaris_info->did1)
1126 return ERROR_OK;
1127 return stellaris_probe(bank);
1128 }
1129
1130 static int stellaris_mass_erase(struct flash_bank *bank)
1131 {
1132 struct target *target = NULL;
1133 struct stellaris_flash_bank *stellaris_info = NULL;
1134 uint32_t flash_fmc;
1135
1136 stellaris_info = bank->driver_priv;
1137 target = bank->target;
1138
1139 if (target->state != TARGET_HALTED)
1140 {
1141 LOG_ERROR("Target not halted");
1142 return ERROR_TARGET_NOT_HALTED;
1143 }
1144
1145 if (stellaris_info->did1 == 0)
1146 {
1147 stellaris_read_part_info(bank);
1148 }
1149
1150 if (stellaris_info->did1 == 0)
1151 {
1152 LOG_WARNING("Cannot identify target as Stellaris");
1153 return ERROR_FLASH_OPERATION_FAILED;
1154 }
1155
1156 /* Refresh flash controller timing */
1157 stellaris_read_clock_info(bank);
1158 stellaris_set_flash_timing(bank);
1159
1160 /* Clear and disable flash programming interrupts */
1161 target_write_u32(target, FLASH_CIM, 0);
1162 target_write_u32(target, FLASH_MISC, PMISC | AMISC);
1163
1164 target_write_u32(target, FLASH_FMA, 0);
1165 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
1166 /* Wait until erase complete */
1167 do
1168 {
1169 target_read_u32(target, FLASH_FMC, &flash_fmc);
1170 }
1171 while (flash_fmc & FMC_MERASE);
1172
1173 /* if device has > 128k, then second erase cycle is needed
1174 * this is only valid for older devices, but will not hurt */
1175 if (stellaris_info->num_pages * stellaris_info->pagesize > 0x20000)
1176 {
1177 target_write_u32(target, FLASH_FMA, 0x20000);
1178 target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
1179 /* Wait until erase complete */
1180 do
1181 {
1182 target_read_u32(target, FLASH_FMC, &flash_fmc);
1183 }
1184 while (flash_fmc & FMC_MERASE);
1185 }
1186
1187 return ERROR_OK;
1188 }
1189
1190 COMMAND_HANDLER(stellaris_handle_mass_erase_command)
1191 {
1192 int i;
1193
1194 if (CMD_ARGC < 1)
1195 {
1196 command_print(CMD_CTX, "stellaris mass_erase <bank>");
1197 return ERROR_OK;
1198 }
1199
1200 struct flash_bank *bank;
1201 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
1202 if (ERROR_OK != retval)
1203 return retval;
1204
1205 if (stellaris_mass_erase(bank) == ERROR_OK)
1206 {
1207 /* set all sectors as erased */
1208 for (i = 0; i < bank->num_sectors; i++)
1209 {
1210 bank->sectors[i].is_erased = 1;
1211 }
1212
1213 command_print(CMD_CTX, "stellaris mass erase complete");
1214 }
1215 else
1216 {
1217 command_print(CMD_CTX, "stellaris mass erase failed");
1218 }
1219
1220 return ERROR_OK;
1221 }
1222
1223 static const struct command_registration stellaris_exec_command_handlers[] = {
1224 {
1225 .name = "mass_erase",
1226 .handler = &stellaris_handle_mass_erase_command,
1227 .mode = COMMAND_EXEC,
1228 .help = "erase entire device",
1229 },
1230 COMMAND_REGISTRATION_DONE
1231 };
1232 static const struct command_registration stellaris_command_handlers[] = {
1233 {
1234 .name = "stellaris",
1235 .mode = COMMAND_ANY,
1236 .help = "Stellaris flash command group",
1237 .chain = stellaris_exec_command_handlers,
1238 },
1239 COMMAND_REGISTRATION_DONE
1240 };
1241
1242 struct flash_driver stellaris_flash = {
1243 .name = "stellaris",
1244 .commands = stellaris_command_handlers,
1245 .flash_bank_command = stellaris_flash_bank_command,
1246 .erase = stellaris_erase,
1247 .protect = stellaris_protect,
1248 .write = stellaris_write,
1249 .probe = stellaris_probe,
1250 .auto_probe = stellaris_auto_probe,
1251 .erase_check = default_flash_mem_blank_check,
1252 .protect_check = stellaris_protect_check,
1253 .info = stellaris_info,
1254 };

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)