optimize: replace while loop by memcpy
[openocd.git] / src / flash / nor / stellaris.c
index 4183cba8bead0a84c12d028665283193abcdcba0..13b7071e3f813b7f57350347d7510435751660f9 100644 (file)
  ***************************************************************************/
 
 /***************************************************************************
-* STELLARIS is tested on LM3S811, LM3S6965
+* STELLARIS flash is tested on LM3S811, LM3S6965, LM3s3748, more.
 ***************************************************************************/
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "imp.h"
-#include "stellaris.h"
 #include <target/algorithm.h>
 #include <target/armv7m.h>
 
 
 #define DID0_VER(did0) ((did0 >> 28)&0x07)
 
+/* STELLARIS control registers */
+#define SCB_BASE       0x400FE000
+#define DID0           0x000
+#define DID1           0x004
+#define DC0                    0x008
+#define DC1                    0x010
+#define DC2                    0x014
+#define DC3                    0x018
+#define DC4                    0x01C
+
+#define RIS                    0x050
+#define RCC                    0x060
+#define PLLCFG         0x064
+#define RCC2           0x070
+#define NVMSTAT                0x1a0
+
+/* "legacy" flash memory protection registers (64KB max) */
+#define FMPRE          0x130
+#define FMPPE          0x134
+
+/* new flash memory protection registers (for more than 64KB) */
+#define FMPRE0         0x200           /* PRE1 = PRE0 + 4, etc */
+#define FMPPE0         0x400           /* PPE1 = PPE0 + 4, etc */
+
+#define USECRL         0x140
+
+#define FLASH_CONTROL_BASE     0x400FD000
+#define FLASH_FMA      (FLASH_CONTROL_BASE | 0x000)
+#define FLASH_FMD      (FLASH_CONTROL_BASE | 0x004)
+#define FLASH_FMC      (FLASH_CONTROL_BASE | 0x008)
+#define FLASH_CRIS     (FLASH_CONTROL_BASE | 0x00C)
+#define FLASH_CIM      (FLASH_CONTROL_BASE | 0x010)
+#define FLASH_MISC     (FLASH_CONTROL_BASE | 0x014)
+
+#define AMISC  1
+#define PMISC  2
+
+#define AMASK  1
+#define PMASK  2
+
+/* Flash Controller Command bits */
+#define FMC_WRKEY      (0xA442 << 16)
+#define FMC_COMT       (1 << 3)
+#define FMC_MERASE     (1 << 2)
+#define FMC_ERASE      (1 << 1)
+#define FMC_WRITE      (1 << 0)
+
+/* STELLARIS constants */
+
+/* values to write in FMA to commit write-"once" values */
+#define FLASH_FMA_PRE(x)       (2 * (x))       /* for FMPPREx */
+#define FLASH_FMA_PPE(x)       (2 * (x) + 1)   /* for FMPPPEx */
+
+
 static void stellaris_read_clock_info(struct flash_bank *bank);
 static int stellaris_mass_erase(struct flash_bank *bank);
 
-static struct {
-       uint32_t partno;
-       char *partname;
-}      StellarisParts[] =
+struct stellaris_flash_bank
 {
-       {0x0001,"LM3S101"},
-       {0x0002,"LM3S102"},
-       {0x0019,"LM3S300"},
-       {0x0011,"LM3S301"},
-       {0x001A,"LM3S308"},
-       {0x0012,"LM3S310"},
-       {0x0013,"LM3S315"},
-       {0x0014,"LM3S316"},
-       {0x0017,"LM3S317"},
-       {0x0015,"LM3S328"},
-       {0x002A,"LM3S600"},
-       {0x0021,"LM3S601"},
-       {0x002B,"LM3S608"},
-       {0x0022,"LM3S610"},
-       {0x0023,"LM3S611"},
-       {0x0024,"LM3S612"},
-       {0x0025,"LM3S613"},
-       {0x0026,"LM3S615"},
-       {0x0028,"LM3S617"},
-       {0x0029,"LM3S618"},
-       {0x0027,"LM3S628"},
-       {0x0038,"LM3S800"},
-       {0x0031,"LM3S801"},
-       {0x0039,"LM3S808"},
-       {0x0032,"LM3S811"},
-       {0x0033,"LM3S812"},
-       {0x0034,"LM3S815"},
-       {0x0036,"LM3S817"},
-       {0x0037,"LM3S818"},
-       {0x0035,"LM3S828"},
-       {0x10BF,"LM3S1110"},
-       {0x10C3,"LM3S1133"},
-       {0x10C5,"LM3S1138"},
-       {0x10C1,"LM3S1150"},
-       {0x10C4,"LM3S1162"},
-       {0x10C2,"LM3S1165"},
-       {0x10C6,"LM3S1332"},
-       {0x10BC,"LM3S1435"},
-       {0x10BA,"LM3S1439"},
-       {0x10BB,"LM3S1512"},
-       {0x10C7,"LM3S1538"},
-       {0x10DB,"LM3S1601"},
-       {0x1006,"LM3S1607"},
-       {0x10DA,"LM3S1608"},
-       {0x10C0,"LM3S1620"},
-       {0x1003,"LM3S1625"},
-       {0x1004,"LM3S1626"},
-       {0x1005,"LM3S1627"},
-       {0x10B3,"LM3S1635"},
-       {0x10BD,"LM3S1637"},
-       {0x10B9,"LM3S1751"},
-       {0x1010,"LM3S1776"},
-       {0x1016,"LM3S1811"},
-       {0x103D,"LM3S1816"},
-       {0x10B4,"LM3S1850"},
-       {0x10DD,"LM3S1911"},
-       {0x10DC,"LM3S1918"},
-       {0x10B7,"LM3S1937"},
-       {0x10BE,"LM3S1958"},
-       {0x10B5,"LM3S1960"},
-       {0x10B8,"LM3S1968"},
-       {0x100F,"LM3S1J11"},
-       {0x103C,"LM3S1J16"},
-       {0x100E,"LM3S1N11"},
-       {0x103B,"LM3S1N16"},
-       {0x1030,"LM3S1W16"},
-       {0x102F,"LM3S1Z16"},
-       {0x1051,"LM3S2110"},
-       {0x1084,"LM3S2139"},
-       {0x1039,"LM3S2276"},
-       {0x10A2,"LM3S2410"},
-       {0x1059,"LM3S2412"},
-       {0x1056,"LM3S2432"},
-       {0x105A,"LM3S2533"},
-       {0x10E1,"LM3S2601"},
-       {0x10E0,"LM3S2608"},
-       {0x1033,"LM3S2616"},
-       {0x1057,"LM3S2620"},
-       {0x1085,"LM3S2637"},
-       {0x1053,"LM3S2651"},
-       {0x1080,"LM3S2671"},
-       {0x1050,"LM3S2678"},
-       {0x10A4,"LM3S2730"},
-       {0x1052,"LM3S2739"},
-       {0x103A,"LM3S2776"},
-       {0x106D,"LM3S2793"},
-       {0x10E3,"LM3S2911"},
-       {0x10E2,"LM3S2918"},
-       {0x1054,"LM3S2939"},
-       {0x108F,"LM3S2948"},
-       {0x1058,"LM3S2950"},
-       {0x1055,"LM3S2965"},
-       {0x106C,"LM3S2B93"},
-       {0x1043,"LM3S3651"},
-       {0x1044,"LM3S3739"},
-       {0x1049,"LM3S3748"},
-       {0x1045,"LM3S3749"},
-       {0x1042,"LM3S3826"},
-       {0x1041,"LM3S3J26"},
-       {0x1040,"LM3S3N26"},
-       {0x103F,"LM3S3W26"},
-       {0x103E,"LM3S3Z26"},
-       {0x1081,"LM3S5632"},
-       {0x100C,"LM3S5651"},
-       {0x108A,"LM3S5652"},
-       {0x104D,"LM3S5656"},
-       {0x1091,"LM3S5662"},
-       {0x1096,"LM3S5732"},
-       {0x1097,"LM3S5737"},
-       {0x10A0,"LM3S5739"},
-       {0x1099,"LM3S5747"},
-       {0x10A7,"LM3S5749"},
-       {0x109A,"LM3S5752"},
-       {0x109C,"LM3S5762"},
-       {0x1069,"LM3S5791"},
-       {0x100B,"LM3S5951"},
-       {0x104E,"LM3S5956"},
-       {0x1068,"LM3S5B91"},
-       {0x1009,"LM3S5K31"},
-       {0x104A,"LM3S5K36"},
-       {0x100A,"LM3S5P31"},
-       {0x1048,"LM3S5P36"},
-       {0x100D,"LM3S5P51"},
-       {0x104C,"LM3S5P56"},
-       {0x1007,"LM3S5R31"},
-       {0x104B,"LM3S5R36"},
-       {0x1047,"LM3S5T36"},
-       {0x1046,"LM3S5Y36"},
-       {0x10A1,"LM3S6100"},
-       {0x1074,"LM3S6110"},
-       {0x10A5,"LM3S6420"},
-       {0x1082,"LM3S6422"},
-       {0x1075,"LM3S6432"},
-       {0x1076,"LM3S6537"},
-       {0x1071,"LM3S6610"},
-       {0x10E7,"LM3S6611"},
-       {0x10E6,"LM3S6618"},
-       {0x1083,"LM3S6633"},
-       {0x108B,"LM3S6637"},
-       {0x10A3,"LM3S6730"},
-       {0x1077,"LM3S6753"},
-       {0x10E9,"LM3S6911"},
-       {0x10E8,"LM3S6918"},
-       {0x1089,"LM3S6938"},
-       {0x1072,"LM3S6950"},
-       {0x1078,"LM3S6952"},
-       {0x1073,"LM3S6965"},
-       {0x1064,"LM3S8530"},
-       {0x108E,"LM3S8538"},
-       {0x1061,"LM3S8630"},
-       {0x1063,"LM3S8730"},
-       {0x108D,"LM3S8733"},
-       {0x1086,"LM3S8738"},
-       {0x1065,"LM3S8930"},
-       {0x108C,"LM3S8933"},
-       {0x1088,"LM3S8938"},
-       {0x10A6,"LM3S8962"},
-       {0x1062,"LM3S8970"},
-       {0x10D7,"LM3S8971"},
-       {0x1067,"LM3S9790"},
-       {0x106B,"LM3S9792"},
-       {0x1020,"LM3S9997"},
-       {0x1066,"LM3S9B90"},
-       {0x106A,"LM3S9B92"},
-       {0x106E,"LM3S9B95"},
-       {0x106F,"LM3S9B96"},
-       {0x1018,"LM3S9L97"},
-       {0,"Unknown part"}
+       /* chip id register */
+       uint32_t did0;
+       uint32_t did1;
+       uint32_t dc0;
+       uint32_t dc1;
+
+       const char * target_name;
+
+       uint32_t sramsiz;
+       uint32_t flshsz;
+       /* flash geometry */
+       uint32_t num_pages;
+       uint32_t pagesize;
+       uint32_t pages_in_lockregion;
+
+       /* nv memory bits */
+       uint16_t num_lockbits;
+
+       /* main clock status */
+       uint32_t rcc;
+       uint32_t rcc2;
+       uint8_t  mck_valid;
+       uint8_t  xtal_mask;
+       uint32_t iosc_freq;
+       uint32_t mck_freq;
+       const char *iosc_desc;
+       const char *mck_desc;
+};
+
+// Autogenerated by contrib/gen-stellaris-part-header.pl
+// From Stellaris Firmware Development Package revision 8049
+static struct {
+       uint8_t class;
+       uint8_t partno;
+       const char *partname;
+} StellarisParts[] = {
+       {0x00, 0x01, "LM3S101"},
+       {0x00, 0x02, "LM3S102"},
+       {0x01, 0xBF, "LM3S1110"},
+       {0x01, 0xC3, "LM3S1133"},
+       {0x01, 0xC5, "LM3S1138"},
+       {0x01, 0xC1, "LM3S1150"},
+       {0x01, 0xC4, "LM3S1162"},
+       {0x01, 0xC2, "LM3S1165"},
+       {0x01, 0xEC, "LM3S1166"},
+       {0x01, 0xC6, "LM3S1332"},
+       {0x01, 0xBC, "LM3S1435"},
+       {0x01, 0xBA, "LM3S1439"},
+       {0x01, 0xBB, "LM3S1512"},
+       {0x01, 0xC7, "LM3S1538"},
+       {0x01, 0xDB, "LM3S1601"},
+       {0x03, 0x06, "LM3S1607"},
+       {0x01, 0xDA, "LM3S1608"},
+       {0x01, 0xC0, "LM3S1620"},
+       {0x04, 0xCD, "LM3S1621"},
+       {0x03, 0x03, "LM3S1625"},
+       {0x03, 0x04, "LM3S1626"},
+       {0x03, 0x05, "LM3S1627"},
+       {0x01, 0xB3, "LM3S1635"},
+       {0x01, 0xEB, "LM3S1636"},
+       {0x01, 0xBD, "LM3S1637"},
+       {0x04, 0xB1, "LM3S1651"},
+       {0x01, 0xB9, "LM3S1751"},
+       {0x03, 0x10, "LM3S1776"},
+       {0x04, 0x16, "LM3S1811"},
+       {0x04, 0x3D, "LM3S1816"},
+       {0x01, 0xB4, "LM3S1850"},
+       {0x01, 0xDD, "LM3S1911"},
+       {0x01, 0xDC, "LM3S1918"},
+       {0x01, 0xB7, "LM3S1937"},
+       {0x01, 0xBE, "LM3S1958"},
+       {0x01, 0xB5, "LM3S1960"},
+       {0x01, 0xB8, "LM3S1968"},
+       {0x01, 0xEA, "LM3S1969"},
+       {0x04, 0xCE, "LM3S1B21"},
+       {0x06, 0xCA, "LM3S1C21"},
+       {0x06, 0xCB, "LM3S1C26"},
+       {0x06, 0x98, "LM3S1C58"},
+       {0x06, 0xB0, "LM3S1D21"},
+       {0x06, 0xCC, "LM3S1D26"},
+       {0x06, 0x1D, "LM3S1F11"},
+       {0x06, 0x1B, "LM3S1F16"},
+       {0x06, 0xAF, "LM3S1G21"},
+       {0x06, 0x95, "LM3S1G58"},
+       {0x06, 0x1E, "LM3S1H11"},
+       {0x06, 0x1C, "LM3S1H16"},
+       {0x04, 0x0F, "LM3S1J11"},
+       {0x04, 0x3C, "LM3S1J16"},
+       {0x04, 0x0E, "LM3S1N11"},
+       {0x04, 0x3B, "LM3S1N16"},
+       {0x04, 0xB2, "LM3S1P51"},
+       {0x04, 0x9E, "LM3S1R21"},
+       {0x04, 0xC9, "LM3S1R26"},
+       {0x04, 0x30, "LM3S1W16"},
+       {0x04, 0x2F, "LM3S1Z16"},
+       {0x01, 0xD4, "LM3S2016"},
+       {0x01, 0x51, "LM3S2110"},
+       {0x01, 0x84, "LM3S2139"},
+       {0x03, 0x39, "LM3S2276"},
+       {0x01, 0xA2, "LM3S2410"},
+       {0x01, 0x59, "LM3S2412"},
+       {0x01, 0x56, "LM3S2432"},
+       {0x01, 0x5A, "LM3S2533"},
+       {0x01, 0xE1, "LM3S2601"},
+       {0x01, 0xE0, "LM3S2608"},
+       {0x03, 0x33, "LM3S2616"},
+       {0x01, 0x57, "LM3S2620"},
+       {0x01, 0x85, "LM3S2637"},
+       {0x01, 0x53, "LM3S2651"},
+       {0x03, 0x80, "LM3S2671"},
+       {0x03, 0x50, "LM3S2678"},
+       {0x01, 0xA4, "LM3S2730"},
+       {0x01, 0x52, "LM3S2739"},
+       {0x03, 0x3A, "LM3S2776"},
+       {0x04, 0x6D, "LM3S2793"},
+       {0x01, 0xE3, "LM3S2911"},
+       {0x01, 0xE2, "LM3S2918"},
+       {0x01, 0xED, "LM3S2919"},
+       {0x01, 0x54, "LM3S2939"},
+       {0x01, 0x8F, "LM3S2948"},
+       {0x01, 0x58, "LM3S2950"},
+       {0x01, 0x55, "LM3S2965"},
+       {0x04, 0x6C, "LM3S2B93"},
+       {0x06, 0x94, "LM3S2D93"},
+       {0x06, 0x93, "LM3S2U93"},
+       {0x00, 0x19, "LM3S300"},
+       {0x00, 0x11, "LM3S301"},
+       {0x00, 0x1A, "LM3S308"},
+       {0x00, 0x12, "LM3S310"},
+       {0x00, 0x13, "LM3S315"},
+       {0x00, 0x14, "LM3S316"},
+       {0x00, 0x17, "LM3S317"},
+       {0x00, 0x15, "LM3S328"},
+       {0x03, 0x08, "LM3S3634"},
+       {0x03, 0x43, "LM3S3651"},
+       {0x04, 0xC8, "LM3S3654"},
+       {0x03, 0x44, "LM3S3739"},
+       {0x03, 0x49, "LM3S3748"},
+       {0x03, 0x45, "LM3S3749"},
+       {0x04, 0x42, "LM3S3826"},
+       {0x04, 0x41, "LM3S3J26"},
+       {0x04, 0x40, "LM3S3N26"},
+       {0x04, 0x3F, "LM3S3W26"},
+       {0x04, 0x3E, "LM3S3Z26"},
+       {0x03, 0x81, "LM3S5632"},
+       {0x04, 0x0C, "LM3S5651"},
+       {0x03, 0x8A, "LM3S5652"},
+       {0x04, 0x4D, "LM3S5656"},
+       {0x03, 0x91, "LM3S5662"},
+       {0x03, 0x96, "LM3S5732"},
+       {0x03, 0x97, "LM3S5737"},
+       {0x03, 0xA0, "LM3S5739"},
+       {0x03, 0x99, "LM3S5747"},
+       {0x03, 0xA7, "LM3S5749"},
+       {0x03, 0x9A, "LM3S5752"},
+       {0x03, 0x9C, "LM3S5762"},
+       {0x04, 0x69, "LM3S5791"},
+       {0x04, 0x0B, "LM3S5951"},
+       {0x04, 0x4E, "LM3S5956"},
+       {0x04, 0x68, "LM3S5B91"},
+       {0x06, 0x2E, "LM3S5C31"},
+       {0x06, 0x2C, "LM3S5C36"},
+       {0x06, 0x5E, "LM3S5C51"},
+       {0x06, 0x5B, "LM3S5C56"},
+       {0x06, 0x5F, "LM3S5D51"},
+       {0x06, 0x5C, "LM3S5D56"},
+       {0x06, 0x87, "LM3S5D91"},
+       {0x06, 0x2D, "LM3S5G31"},
+       {0x06, 0x1F, "LM3S5G36"},
+       {0x06, 0x5D, "LM3S5G51"},
+       {0x06, 0x4F, "LM3S5G56"},
+       {0x04, 0x09, "LM3S5K31"},
+       {0x04, 0x4A, "LM3S5K36"},
+       {0x04, 0x0A, "LM3S5P31"},
+       {0x04, 0x48, "LM3S5P36"},
+       {0x04, 0xB6, "LM3S5P3B"},
+       {0x04, 0x0D, "LM3S5P51"},
+       {0x04, 0x4C, "LM3S5P56"},
+       {0x04, 0x07, "LM3S5R31"},
+       {0x04, 0x4B, "LM3S5R36"},
+       {0x04, 0x47, "LM3S5T36"},
+       {0x06, 0x7F, "LM3S5U91"},
+       {0x04, 0x46, "LM3S5Y36"},
+       {0x00, 0x2A, "LM3S600"},
+       {0x00, 0x21, "LM3S601"},
+       {0x00, 0x2B, "LM3S608"},
+       {0x00, 0x22, "LM3S610"},
+       {0x01, 0xA1, "LM3S6100"},
+       {0x00, 0x23, "LM3S611"},
+       {0x01, 0x74, "LM3S6110"},
+       {0x00, 0x24, "LM3S612"},
+       {0x00, 0x25, "LM3S613"},
+       {0x00, 0x26, "LM3S615"},
+       {0x00, 0x28, "LM3S617"},
+       {0x00, 0x29, "LM3S618"},
+       {0x00, 0x27, "LM3S628"},
+       {0x01, 0xA5, "LM3S6420"},
+       {0x01, 0x82, "LM3S6422"},
+       {0x01, 0x75, "LM3S6432"},
+       {0x01, 0x76, "LM3S6537"},
+       {0x01, 0x71, "LM3S6610"},
+       {0x01, 0xE7, "LM3S6611"},
+       {0x01, 0xE6, "LM3S6618"},
+       {0x01, 0x83, "LM3S6633"},
+       {0x01, 0x8B, "LM3S6637"},
+       {0x01, 0xA3, "LM3S6730"},
+       {0x01, 0x77, "LM3S6753"},
+       {0x01, 0xD1, "LM3S6816"},
+       {0x01, 0xE9, "LM3S6911"},
+       {0x01, 0xD3, "LM3S6916"},
+       {0x01, 0xE8, "LM3S6918"},
+       {0x01, 0x89, "LM3S6938"},
+       {0x01, 0x72, "LM3S6950"},
+       {0x01, 0x78, "LM3S6952"},
+       {0x01, 0x73, "LM3S6965"},
+       {0x06, 0xAA, "LM3S6C11"},
+       {0x06, 0xAC, "LM3S6C65"},
+       {0x06, 0x9F, "LM3S6G11"},
+       {0x06, 0xAB, "LM3S6G65"},
+       {0x00, 0x38, "LM3S800"},
+       {0x00, 0x31, "LM3S801"},
+       {0x00, 0x39, "LM3S808"},
+       {0x00, 0x32, "LM3S811"},
+       {0x00, 0x33, "LM3S812"},
+       {0x00, 0x34, "LM3S815"},
+       {0x00, 0x36, "LM3S817"},
+       {0x00, 0x37, "LM3S818"},
+       {0x00, 0x35, "LM3S828"},
+       {0x01, 0x64, "LM3S8530"},
+       {0x01, 0x8E, "LM3S8538"},
+       {0x01, 0x61, "LM3S8630"},
+       {0x01, 0x63, "LM3S8730"},
+       {0x01, 0x8D, "LM3S8733"},
+       {0x01, 0x86, "LM3S8738"},
+       {0x01, 0x65, "LM3S8930"},
+       {0x01, 0x8C, "LM3S8933"},
+       {0x01, 0x88, "LM3S8938"},
+       {0x01, 0xA6, "LM3S8962"},
+       {0x01, 0x62, "LM3S8970"},
+       {0x01, 0xD7, "LM3S8971"},
+       {0x06, 0xAE, "LM3S8C62"},
+       {0x06, 0xAD, "LM3S8G62"},
+       {0x04, 0xCF, "LM3S9781"},
+       {0x04, 0x67, "LM3S9790"},
+       {0x04, 0x6B, "LM3S9792"},
+       {0x04, 0x2D, "LM3S9971"},
+       {0x04, 0x20, "LM3S9997"},
+       {0x04, 0xD0, "LM3S9B81"},
+       {0x04, 0x66, "LM3S9B90"},
+       {0x04, 0x6A, "LM3S9B92"},
+       {0x04, 0x6E, "LM3S9B95"},
+       {0x04, 0x6F, "LM3S9B96"},
+       {0x04, 0x1D, "LM3S9BN2"},
+       {0x04, 0x1E, "LM3S9BN5"},
+       {0x04, 0x1F, "LM3S9BN6"},
+       {0x06, 0x70, "LM3S9C97"},
+       {0x06, 0x7A, "LM3S9CN5"},
+       {0x06, 0xA9, "LM3S9D81"},
+       {0x06, 0x7E, "LM3S9D90"},
+       {0x06, 0x92, "LM3S9D92"},
+       {0x06, 0xC8, "LM3S9D95"},
+       {0x06, 0x9D, "LM3S9D96"},
+       {0x06, 0x7B, "LM3S9DN5"},
+       {0x06, 0x7C, "LM3S9DN6"},
+       {0x06, 0x60, "LM3S9G97"},
+       {0x06, 0x79, "LM3S9GN5"},
+       {0x04, 0x1B, "LM3S9L71"},
+       {0x04, 0x18, "LM3S9L97"},
+       {0x06, 0xA8, "LM3S9U81"},
+       {0x06, 0x7D, "LM3S9U90"},
+       {0x06, 0x90, "LM3S9U92"},
+       {0x06, 0xB7, "LM3S9U95"},
+       {0x06, 0x9B, "LM3S9U96"},
+       {0x05, 0x18, "LM4F110B2QR"},
+       {0x05, 0x19, "LM4F110C4QR"},
+       {0x05, 0x10, "LM4F110E5QR"},
+       {0x05, 0x11, "LM4F110H5QR"},
+       {0x05, 0x22, "LM4F111B2QR"},
+       {0x05, 0x23, "LM4F111C4QR"},
+       {0x05, 0x20, "LM4F111E5QR"},
+       {0x05, 0x21, "LM4F111H5QR"},
+       {0x05, 0x36, "LM4F112C4QC"},
+       {0x05, 0x30, "LM4F112E5QC"},
+       {0x05, 0x31, "LM4F112H5QC"},
+       {0x05, 0x35, "LM4F112H5QD"},
+       {0x05, 0x01, "LM4F120B2QR"},
+       {0x05, 0x02, "LM4F120C4QR"},
+       {0x05, 0x03, "LM4F120E5QR"},
+       {0x05, 0x04, "LM4F120H5QR"},
+       {0x05, 0x08, "LM4F121B2QR"},
+       {0x05, 0x09, "LM4F121C4QR"},
+       {0x05, 0x0A, "LM4F121E5QR"},
+       {0x05, 0x0B, "LM4F121H5QR"},
+       {0x05, 0xD0, "LM4F122C4QC"},
+       {0x05, 0xD1, "LM4F122E5QC"},
+       {0x05, 0xD2, "LM4F122H5QC"},
+       {0x05, 0xD6, "LM4F122H5QD"},
+       {0x05, 0x48, "LM4F130C4QR"},
+       {0x05, 0x40, "LM4F130E5QR"},
+       {0x05, 0x41, "LM4F130H5QR"},
+       {0x05, 0x52, "LM4F131C4QR"},
+       {0x05, 0x50, "LM4F131E5QR"},
+       {0x05, 0x51, "LM4F131H5QR"},
+       {0x05, 0x66, "LM4F132C4QC"},
+       {0x05, 0x60, "LM4F132E5QC"},
+       {0x05, 0x61, "LM4F132H5QC"},
+       {0x05, 0x65, "LM4F132H5QD"},
+       {0x05, 0xA0, "LM4F230E5QR"},
+       {0x05, 0xA1, "LM4F230H5QR"},
+       {0x05, 0xB0, "LM4F231E5QR"},
+       {0x05, 0xB1, "LM4F231H5QR"},
+       {0x05, 0xC0, "LM4F232E5QC"},
+       {0x05, 0xE3, "LM4F232H5BB"},
+       {0x05, 0xC1, "LM4F232H5QC"},
+       {0x05, 0xC5, "LM4F232H5QD"},
+       {0x05, 0xE5, "LM4FS1AH5BB"},
+       {0x05, 0xE4, "LM4FS99H5BB"},
+       {0x05, 0xE0, "LM4FSXAH5BB"},
+       {0xFF, 0x00, "Unknown Part"}
 };
 
-static char * StellarisClassname[5] =
+static char * StellarisClassname[7] =
 {
        "Sandstorm",
        "Fury",
        "Unknown",
        "DustDevil",
-       "Tempest"
+       "Tempest",
+       "Blizzard",
+       "Firestorm"
 };
 
 /***************************************************************************
@@ -235,8 +438,7 @@ FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command)
 
        if (CMD_ARGC < 6)
        {
-               LOG_WARNING("incomplete flash_bank stellaris configuration");
-               return ERROR_FLASH_BANK_INVALID;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        stellaris_info = calloc(sizeof(struct stellaris_flash_bank), 1);
@@ -255,7 +457,7 @@ FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command)
        return ERROR_OK;
 }
 
-static int stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
+static int get_stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
 {
        int printed, device_class;
        struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
@@ -311,7 +513,7 @@ static int stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
 
        if (stellaris_info->num_lockbits > 0)
        {
-               printed = snprintf(buf,
+               snprintf(buf,
                                buf_size,
                                "pagesize: %" PRIi32 ", pages: %d, "
                                "lockbits: %i, pages per lockbit: %i\n",
@@ -319,8 +521,6 @@ static int stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
                                (unsigned) stellaris_info->num_pages,
                                stellaris_info->num_lockbits,
                                (unsigned) stellaris_info->pages_in_lockregion);
-               buf += printed;
-               buf_size -= printed;
        }
        return ERROR_OK;
 }
@@ -539,7 +739,8 @@ static int stellaris_read_part_info(struct flash_bank *bank)
 
        for (i = 0; StellarisParts[i].partno; i++)
        {
-               if (StellarisParts[i].partno == ((did1 >> 16) & 0xFFFF))
+               if ((StellarisParts[i].partno == ((did1 >> 16) & 0xFF)) &&
+                               (StellarisParts[i].class == ((did0 >> 16) & 0xFF)))
                        break;
        }
 
@@ -693,9 +894,9 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
 
        if (!set)
        {
-               LOG_ERROR("Can't unprotect write-protected pages.");
-               /* except by the "recover locked device" procedure ... */
-               return ERROR_INVALID_ARGUMENTS;
+               LOG_ERROR("Hardware doesn't support page-level unprotect. "
+                       "Try the 'recover' command.");
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        if (stellaris_info->did1 == 0)
@@ -706,7 +907,7 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
                        || (last < first) || !(last & 1)
                        || (last >= 2 * stellaris_info->num_lockbits))
        {
-               LOG_ERROR("Can't protect unaligned or out-of-range sectors.");
+               LOG_ERROR("Can't protect unaligned or out-of-range pages.");
                return ERROR_FLASH_SECTOR_INVALID;
        }
 
@@ -748,8 +949,10 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
        /* Write commit command */
        /* REVISIT safety check, since this cannot be undone
         * except by the "Recover a locked device" procedure.
+        * REVISIT DustDevil-A0 parts have an erratum making FMPPE commits
+        * inadvisable ... it makes future mass erase operations fail.
         */
-       LOG_WARNING("Flash protection cannot be removed once commited, commit is NOT executed !");
+       LOG_WARNING("Flash protection cannot be removed once committed, commit is NOT executed !");
        /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */
 
        /* Wait until erase complete */
@@ -771,6 +974,8 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
        return ERROR_OK;
 }
 
+/* see contib/loaders/flash/stellaris.s for src */
+
 static const uint8_t stellaris_write_code[] =
 {
 /*
@@ -803,8 +1008,7 @@ static const uint8_t stellaris_write_code[] =
        0x04,0x36,                      /* adds r6, r6, #4 */
        0x96,0x42,                      /* cmp  r6, r2 */
        0xF4,0xD1,                      /* bne  mainloop */
-                                               /* exit: */
-       0xFE,0xE7,                      /* b exit */
+       0x00,0xBE,              /* bkpt #0 */
 /* pFLASH_CTRL_BASE: */
        0x00,0xD0,0x0F,0x40,    /* .word        0x400FD000 */
 /* FLASHWRITECMD: */
@@ -815,7 +1019,7 @@ static int stellaris_write_block(struct flash_bank *bank,
                uint8_t *buffer, uint32_t offset, uint32_t wcount)
 {
        struct target *target = bank->target;
-       uint32_t buffer_size = 8192;
+       uint32_t buffer_size = 16384;
        struct working_area *source;
        struct working_area *write_algorithm;
        uint32_t address = bank->base + offset;
@@ -823,37 +1027,44 @@ static int stellaris_write_block(struct flash_bank *bank,
        struct armv7m_algorithm armv7m_info;
        int retval = ERROR_OK;
 
+       /* power of two, and multiple of word size */
+       static const unsigned buf_min = 128;
+
+       /* for small buffers it's faster not to download an algorithm */
+       if (wcount * 4 < buf_min)
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
        LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "",
                        bank, buffer, offset, wcount);
 
        /* flash write code */
        if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK)
        {
-               LOG_WARNING("no working area available, can't do block memory writes");
+               LOG_DEBUG("no working area for block memory writes");
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        };
 
-       target_write_buffer(target, write_algorithm->address,
-                       sizeof(stellaris_write_code),
-                       (uint8_t *) stellaris_write_code);
+       /* plus a buffer big enough for this data */
+       if (wcount * 4 < buffer_size)
+               buffer_size = wcount * 4;
 
        /* memory buffer */
-       while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+       while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
        {
-               LOG_DEBUG("called target_alloc_working_area(target=%p buffer_size=%08" PRIx32 " source=%p)",
-                               target, buffer_size, source);
                buffer_size /= 2;
-               if (buffer_size <= 256)
+               if (buffer_size <= buf_min)
                {
-                       /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
-                       if (write_algorithm)
-                               target_free_working_area(target, write_algorithm);
-
-                       LOG_WARNING("no large enough working area available, can't do block memory writes");
+                       target_free_working_area(target, write_algorithm);
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
+               LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)",
+                               target_name(target), (unsigned) buffer_size);
        };
 
+       retval = target_write_buffer(target, write_algorithm->address,
+                       sizeof(stellaris_write_code),
+                       (uint8_t *) stellaris_write_code);
+
        armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
        armv7m_info.core_mode = ARMV7M_MODE_ANY;
 
@@ -870,11 +1081,19 @@ static int stellaris_write_block(struct flash_bank *bank,
                buf_set_u32(reg_params[0].value, 0, 32, source->address);
                buf_set_u32(reg_params[1].value, 0, 32, address);
                buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count);
-               LOG_INFO("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
-               LOG_DEBUG("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
-               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)
+               LOG_DEBUG("Algorithm flash write %u words to 0x%" PRIx32
+                               ", %u remaining",
+                               (unsigned) thisrun_count, address,
+                               (unsigned) (wcount - thisrun_count));
+               retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
+                               write_algorithm->address,
+                               0,
+                               10000, &armv7m_info);
+               if (retval != ERROR_OK)
                {
-                       LOG_ERROR("error executing stellaris flash write algorithm");
+                       LOG_ERROR("error %d executing stellaris "
+                                       "flash write algorithm",
+                                       retval);
                        retval = ERROR_FLASH_OPERATION_FAILED;
                        break;
                }
@@ -884,6 +1103,10 @@ static int stellaris_write_block(struct flash_bank *bank,
                wcount -= thisrun_count;
        }
 
+       /* REVISIT we could speed up writing multi-section images by
+        * not freeing the initialized write_algorithm this way.
+        */
+
        target_free_working_area(target, write_algorithm);
        target_free_working_area(target, source);
 
@@ -942,13 +1165,13 @@ static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t of
        if (words_remaining > 0)
        {
                /* try using a block write */
-               if ((retval = stellaris_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
+               retval = stellaris_write_block(bank, buffer, offset,
+                               words_remaining);
+               if (retval != ERROR_OK)
                {
                        if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
                        {
-                               /* if block write failed (no sufficient working area),
-                                * we use normal (slow) single dword accesses */
-                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+                               LOG_DEBUG("writing flash word-at-a-time");
                        }
                        else if (retval == ERROR_FLASH_OPERATION_FAILED)
                        {
@@ -991,14 +1214,9 @@ static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t of
        if (bytes_remaining)
        {
                uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff};
-               int i = 0;
 
-               while (bytes_remaining > 0)
-               {
-                       last_word[i++] = *(buffer + bytes_written);
-                       bytes_remaining--;
-                       bytes_written++;
-               }
+               /* copy the last remaining bytes into the write buffer */
+               memcpy(last_word, buffer+bytes_written, bytes_remaining);
 
                if (!(address & 0xff))
                        LOG_DEBUG("0x%" PRIx32 "", address);
@@ -1044,6 +1262,12 @@ static int stellaris_probe(struct flash_bank *bank)
        if (retval != ERROR_OK)
                return retval;
 
+       if (bank->sectors)
+       {
+               free(bank->sectors);
+               bank->sectors = NULL;
+       }
+
        /* provide this for the benefit of the NOR flash framework */
        bank->size = 1024 * stellaris_info->num_pages;
        bank->num_sectors = stellaris_info->num_pages;
@@ -1121,8 +1345,7 @@ COMMAND_HANDLER(stellaris_handle_mass_erase_command)
 
        if (CMD_ARGC < 1)
        {
-               command_print(CMD_CTX, "stellaris mass_erase <bank>");
-               return ERROR_OK;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        struct flash_bank *bank;
@@ -1148,19 +1371,85 @@ COMMAND_HANDLER(stellaris_handle_mass_erase_command)
        return ERROR_OK;
 }
 
+/**
+ * Perform the Stellaris "Recovering a 'Locked' Device procedure.
+ * This performs a mass erase and then restores all nonvolatile registers
+ * (including USER_* registers and flash lock bits) to their defaults.
+ * Accordingly, flash can be reprogrammed, and JTAG can be used.
+ *
+ * NOTE that DustDevil parts (at least rev A0 silicon) have errata which
+ * can affect this operation if flash protection has been enabled.
+ */
+COMMAND_HANDLER(stellaris_handle_recover_command)
+{
+       struct flash_bank *bank;
+       int retval;
+
+       retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* REVISIT ... it may be worth sanity checking that the AP is
+        * inactive before we start.  ARM documents that switching a DP's
+        * mode while it's active can cause fault modes that need a power
+        * cycle to recover.
+        */
+
+       /* assert SRST */
+       if (!(jtag_get_reset_config() & RESET_HAS_SRST)) {
+               LOG_ERROR("Can't recover Stellaris flash without SRST");
+               return ERROR_FAIL;
+       }
+       jtag_add_reset(0, 1);
+
+       for (int i = 0; i < 5; i++) {
+               retval = dap_to_swd(bank->target);
+               if (retval != ERROR_OK)
+                       goto done;
+
+               retval = dap_to_jtag(bank->target);
+               if (retval != ERROR_OK)
+                       goto done;
+       }
+
+       /* de-assert SRST */
+       jtag_add_reset(0, 0);
+       retval = jtag_execute_queue();
+
+       /* wait 400+ msec ... OK, "1+ second" is simpler */
+       usleep(1000);
+
+       /* USER INTERVENTION required for the power cycle
+        * Restarting OpenOCD is likely needed because of mode switching.
+        */
+       LOG_INFO("USER ACTION:  "
+               "power cycle Stellaris chip, then restart OpenOCD.");
+
+done:
+       return retval;
+}
+
 static const struct command_registration stellaris_exec_command_handlers[] = {
        {
                .name = "mass_erase",
-               .handler = &stellaris_handle_mass_erase_command,
+               .usage = "<bank>",
+               .handler = stellaris_handle_mass_erase_command,
                .mode = COMMAND_EXEC,
                .help = "erase entire device",
        },
+       {
+               .name = "recover",
+               .handler = stellaris_handle_recover_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "recover (and erase) locked device",
+       },
        COMMAND_REGISTRATION_DONE
 };
 static const struct command_registration stellaris_command_handlers[] = {
        {
                .name = "stellaris",
-               .mode = COMMAND_ANY,
+               .mode = COMMAND_EXEC,
                .help = "Stellaris flash command group",
                .chain = stellaris_exec_command_handlers,
        },
@@ -1174,9 +1463,10 @@ struct flash_driver stellaris_flash = {
        .erase = stellaris_erase,
        .protect = stellaris_protect,
        .write = stellaris_write,
+       .read = default_flash_read,
        .probe = stellaris_probe,
        .auto_probe = stellaris_probe,
        .erase_check = default_flash_mem_blank_check,
        .protect_check = stellaris_protect_check,
-       .info = stellaris_info,
+       .info = get_stellaris_info,
 };

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)