stellaris: update bulk flash writes
[openocd.git] / src / flash / nor / stellaris.c
index 39885429872b1363c88c46a968e712f6d94b7d91..51fe677cd75a8c9acb1836c7cfa0a28b9b40eedd 100644 (file)
 
 #include "imp.h"
 #include "stellaris.h"
-#include <helper/binarybuffer.h>
 #include <target/algorithm.h>
 #include <target/armv7m.h>
 
 
 #define DID0_VER(did0) ((did0 >> 28)&0x07)
 
-static int stellaris_read_part_info(struct flash_bank *bank);
-static uint32_t stellaris_get_flash_status(struct flash_bank *bank);
-static void stellaris_set_flash_mode(struct flash_bank *bank,int mode);
-//static uint32_t stellaris_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
-
+static void stellaris_read_clock_info(struct flash_bank *bank);
 static int stellaris_mass_erase(struct flash_bank *bank);
 
 static struct {
@@ -49,154 +44,173 @@ static struct {
        char *partname;
 }      StellarisParts[] =
 {
-       {0x01,"LM3S101"},
-       {0x02,"LM3S102"},
-       {0x03,"LM3S1625"},
-       {0x04,"LM3S1626"},
-       {0x05,"LM3S1627"},
-       {0x06,"LM3S1607"},
-       {0x10,"LM3S1776"},
-       {0x19,"LM3S300"},
-       {0x11,"LM3S301"},
-       {0x12,"LM3S310"},
-       {0x1A,"LM3S308"},
-       {0x13,"LM3S315"},
-       {0x14,"LM3S316"},
-       {0x17,"LM3S317"},
-       {0x18,"LM3S318"},
-       {0x15,"LM3S328"},
-       {0x2A,"LM3S600"},
-       {0x21,"LM3S601"},
-       {0x2B,"LM3S608"},
-       {0x22,"LM3S610"},
-       {0x23,"LM3S611"},
-       {0x24,"LM3S612"},
-       {0x25,"LM3S613"},
-       {0x26,"LM3S615"},
-       {0x28,"LM3S617"},
-       {0x29,"LM3S618"},
-       {0x27,"LM3S628"},
-       {0x38,"LM3S800"},
-       {0x31,"LM3S801"},
-       {0x39,"LM3S808"},
-       {0x32,"LM3S811"},
-       {0x33,"LM3S812"},
-       /*{0x33,"LM3S2616"},*/
-       {0x34,"LM3S815"},
-       {0x36,"LM3S817"},
-       {0x37,"LM3S818"},
-       {0x35,"LM3S828"},
-       {0x39,"LM3S2276"},
-       {0x3A,"LM3S2776"},
-       {0x43,"LM3S3651"},
-       {0x44,"LM3S3739"},
-       {0x45,"LM3S3749"},
-       {0x46,"LM3S3759"},
-       {0x48,"LM3S3768"},
-       {0x49,"LM3S3748"},
-       {0x50,"LM3S2678"},
-       {0x51,"LM3S2110"},
-       {0x52,"LM3S2739"},
-       {0x53,"LM3S2651"},
-       {0x54,"LM3S2939"},
-       {0x55,"LM3S2965"},
-       {0x56,"LM3S2432"},
-       {0x57,"LM3S2620"},
-       {0x58,"LM3S2950"},
-       {0x59,"LM3S2412"},
-       {0x5A,"LM3S2533"},
-       {0x61,"LM3S8630"},
-       {0x62,"LM3S8970"},
-       {0x63,"LM3S8730"},
-       {0x64,"LM3S8530"},
-       {0x65,"LM3S8930"},
-       {0x71,"LM3S6610"},
-       {0x72,"LM3S6950"},
-       {0x73,"LM3S6965"},
-       {0x74,"LM3S6110"},
-       {0x75,"LM3S6432"},
-       {0x76,"LM3S6537"},
-       {0x77,"LM3S6753"},
-       {0x78,"LM3S6952"},
-       {0x80,"LM3S2671"},
-       {0x81,"LM3S5632"},
-       {0x82,"LM3S6422"},
-       {0x83,"LM3S6633"},
-       {0x84,"LM3S2139"},
-       {0x85,"LM3S2637"},
-       {0x86,"LM3S8738"},
-       {0x88,"LM3S8938"},
-       {0x89,"LM3S6938"},
-       {0x8A,"LM3S5652"},
-       {0x8B,"LM3S6637"},
-       {0x8C,"LM3S8933"},
-       {0x8D,"LM3S8733"},
-       {0x8E,"LM3S8538"},
-       {0x8F,"LM3S2948"},
-       {0x91,"LM3S5662"},
-       {0x96,"LM3S5732"},
-       {0x97,"LM3S5737"},
-       {0x99,"LM3S5747"},
-       {0x9A,"LM3S5752"},
-       {0x9B,"LM3S5757"},
-       {0x9C,"LM3S5762"},
-       {0x9D,"LM3S5767"},
-       {0xA0,"LM3S5739"},
-       {0xA1,"LM3S6100"},
-       {0xA2,"LM3S2410"},
-       {0xA3,"LM3S6730"},
-       {0xA4,"LM3S2730"},
-       {0xA5,"LM3S6420"},
-       {0xA6,"LM3S8962"},
-       {0xA7,"LM3S5749"},
-       {0xA8,"LM3S5769"},
-       {0xA9,"LM3S5768"},
-       {0xB3,"LM3S1635"},
-       {0xB4,"LM3S1850"},
-       {0xB5,"LM3S1960"},
-       {0xB7,"LM3S1937"},
-       {0xB8,"LM3S1968"},
-       {0xB9,"LM3S1751"},
-       {0xBA,"LM3S1439"},
-       {0xBB,"LM3S1512"},
-       {0xBC,"LM3S1435"},
-       {0xBD,"LM3S1637"},
-       {0xBE,"LM3S1958"},
-       {0xBF,"LM3S1110"},
-       {0xC0,"LM3S1620"},
-       {0xC1,"LM3S1150"},
-       {0xC2,"LM3S1165"},
-       {0xC3,"LM3S1133"},
-       {0xC4,"LM3S1162"},
-       {0xC5,"LM3S1138"},
-       {0xC6,"LM3S1332"},
-       {0xC7,"LM3S1538"},
-       {0xD0,"LM3S6815"},
-       {0xD1,"LM3S6816"},
-       {0xD2,"LM3S6915"},
-       {0xD3,"LM3S6916"},
-       {0xD4,"LM3S2016"},
-       {0xD5,"LM3S1615"},
-       {0xD6,"LM3S1616"},
-       {0xD7,"LM3S8971"},
-       {0xD8,"LM3S1108"},
-       {0xD9,"LM3S1101"},
-       {0xDA,"LM3S1608"},
-       {0xDB,"LM3S1601"},
-       {0xDC,"LM3S1918"},
-       {0xDD,"LM3S1911"},
-       {0xDE,"LM3S2108"},
-       {0xDF,"LM3S2101"},
-       {0xE0,"LM3S2608"},
-       {0xE1,"LM3S2601"},
-       {0xE2,"LM3S2918"},
-       {0xE3,"LM3S2911"},
-       {0xE4,"LM3S6118"},
-       {0xE5,"LM3S6111"},
-       {0xE6,"LM3S6618"},
-       {0xE7,"LM3S6611"},
-       {0xE8,"LM3S6918"},
-       {0xE9,"LM3S6911"},
+       {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"}
 };
 
@@ -246,15 +260,11 @@ static int stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
        int printed, device_class;
        struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
 
-       stellaris_read_part_info(bank);
-
        if (stellaris_info->did1 == 0)
-       {
-               printed = snprintf(buf, buf_size, "Cannot identify target as a Stellaris\n");
-               buf += printed;
-               buf_size -= printed;
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       /* Read main and master clock freqency register */
+       stellaris_read_clock_info(bank);
 
        if (DID0_VER(stellaris_info->did0) > 0)
        {
@@ -302,12 +312,13 @@ static int stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
        if (stellaris_info->num_lockbits > 0)
        {
                printed = snprintf(buf,
-                                  buf_size,
-                                  "pagesize: %" PRIi32 ", lockbits: %i 0x%4.4" PRIx32 ", pages in lock region: %i \n",
-                                  stellaris_info->pagesize,
-                                  stellaris_info->num_lockbits,
-                                  stellaris_info->lockbits,
-                                  (int)(stellaris_info->num_pages/stellaris_info->num_lockbits));
+                               buf_size,
+                               "pagesize: %" PRIi32 ", pages: %d, "
+                               "lockbits: %i, pages per lockbit: %i\n",
+                               stellaris_info->pagesize,
+                               (unsigned) stellaris_info->num_pages,
+                               stellaris_info->num_lockbits,
+                               (unsigned) stellaris_info->pages_in_lockregion);
                buf += printed;
                buf_size -= printed;
        }
@@ -318,18 +329,17 @@ static int stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
 *      chip identification and status                                         *
 ***************************************************************************/
 
-static uint32_t stellaris_get_flash_status(struct flash_bank *bank)
+/* Set the flash timimg register to match current clocking */
+static void stellaris_set_flash_timing(struct flash_bank *bank)
 {
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
        struct target *target = bank->target;
-       uint32_t fmc;
-
-       target_read_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, &fmc);
+       uint32_t usecrl = (stellaris_info->mck_freq/1000000ul-1);
 
-       return fmc;
+       LOG_DEBUG("usecrl = %i",(int)(usecrl));
+       target_write_u32(target, SCB_BASE | USECRL, usecrl);
 }
 
-/** Read clock configuration and set stellaris_info->usec_clocks*/
-
 static const unsigned rcc_xtal[32] = {
        [0x00] = 1000000,               /* no pll */
        [0x01] = 1843200,               /* no pll */
@@ -363,6 +373,7 @@ static const unsigned rcc_xtal[32] = {
        [0x16] = 16384000,
 };
 
+/** Read clock configuration and set stellaris_info->usec_clocks. */
 static void stellaris_read_clock_info(struct flash_bank *bank)
 {
        struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
@@ -444,64 +455,14 @@ static void stellaris_read_clock_info(struct flash_bank *bank)
                stellaris_info->mck_freq = mainfreq/(1 + sysdiv);
        else
                stellaris_info->mck_freq = mainfreq;
-
-       /* Forget old flash timing */
-       stellaris_set_flash_mode(bank, 0);
-}
-
-/* Setup the timimg registers */
-static void stellaris_set_flash_mode(struct flash_bank *bank,int mode)
-{
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-       struct target *target = bank->target;
-
-       uint32_t usecrl = (stellaris_info->mck_freq/1000000ul-1);
-       LOG_DEBUG("usecrl = %i",(int)(usecrl));
-       target_write_u32(target, SCB_BASE | USECRL, usecrl);
-}
-
-#if 0
-static uint32_t stellaris_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
-{
-       uint32_t status;
-
-       /* Stellaris waits for cmdbit to clear */
-       while (((status = stellaris_get_flash_status(bank)) & waitbits) && (timeout-- > 0))
-       {
-               LOG_DEBUG("status: 0x%x", status);
-               alive_sleep(1);
-       }
-
-       /* Flash errors are reflected in the FLASH_CRIS register */
-
-       return status;
-}
-
-/* Send one command to the flash controller */
-static int stellaris_flash_command(struct flash_bank *bank,uint8_t cmd,uint16_t pagen)
-{
-       uint32_t fmc;
-       struct target *target = bank->target;
-
-       fmc = FMC_WRKEY | cmd;
-       target_write_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, fmc);
-       LOG_DEBUG("Flash command: 0x%x", fmc);
-
-       if (stellaris_wait_status_busy(bank, cmd, 100))
-       {
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
-
-       return ERROR_OK;
 }
-#endif
 
 /* Read device id register, main clock frequency register and fill in driver info structure */
 static int stellaris_read_part_info(struct flash_bank *bank)
 {
        struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
        struct target *target = bank->target;
-       uint32_t did0, did1, ver, fam, status;
+       uint32_t did0, did1, ver, fam;
        int i;
 
        /* Read and parse chip identification register */
@@ -529,7 +490,8 @@ static int stellaris_read_part_info(struct flash_bank *bank)
        fam = (did1 >> 24) & 0xF;
        if (((ver != 0) && (ver != 1)) || (fam != 0))
        {
-               LOG_WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");
+               LOG_WARNING("Unknown did1 version/family.");
+               return ERROR_FLASH_OPERATION_FAILED;
        }
 
        /* For Sandstorm, Fury, DustDevil:  current data sheets say IOSC
@@ -569,14 +531,15 @@ static int stellaris_read_part_info(struct flash_bank *bank)
                default:
                        LOG_WARNING("Unknown did0 class");
                }
-       default:
                break;
+       default:
                LOG_WARNING("Unknown did0 version");
+               break;
        }
 
        for (i = 0; StellarisParts[i].partno; i++)
        {
-               if (StellarisParts[i].partno == ((did1 >> 16) & 0xFF))
+               if (StellarisParts[i].partno == ((did1 >> 16) & 0xFFFF))
                        break;
        }
 
@@ -588,25 +551,12 @@ static int stellaris_read_part_info(struct flash_bank *bank)
        stellaris_info->num_lockbits = 1 + (stellaris_info->dc0 & 0xFFFF);
        stellaris_info->num_pages = 2 *(1 + (stellaris_info->dc0 & 0xFFFF));
        stellaris_info->pagesize = 1024;
-       bank->size = 1024 * stellaris_info->num_pages;
        stellaris_info->pages_in_lockregion = 2;
-       target_read_u32(target, SCB_BASE | FMPPE, &stellaris_info->lockbits);
 
-       /* provide this for the benefit of the higher flash driver layers */
-       bank->num_sectors = stellaris_info->num_pages;
-       bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               bank->sectors[i].offset = i * stellaris_info->pagesize;
-               bank->sectors[i].size = stellaris_info->pagesize;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = -1;
-       }
-
-       /* Read main and master clock freqency register */
-       stellaris_read_clock_info(bank);
-
-       status = stellaris_get_flash_status(bank);
+       /* REVISIT for at least Tempest parts, read NVMSTAT.FWB too.
+        * That exposes a 32-word Flash Write Buffer ... enabling
+        * writes of more than one word at a time.
+        */
 
        return ERROR_OK;
 }
@@ -617,31 +567,48 @@ static int stellaris_read_part_info(struct flash_bank *bank)
 
 static int stellaris_protect_check(struct flash_bank *bank)
 {
-       uint32_t status;
+       struct stellaris_flash_bank *stellaris = bank->driver_priv;
+       int status = ERROR_OK;
+       unsigned i;
+       unsigned page;
 
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-
-       if (bank->target->state != TARGET_HALTED)
-       {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
+       if (stellaris->did1 == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
 
-       if (stellaris_info->did1 == 0)
-       {
-               stellaris_read_part_info(bank);
-       }
+       for (i = 0; i < (unsigned) bank->num_sectors; i++)
+               bank->sectors[i].is_protected = -1;
 
-       if (stellaris_info->did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as Stellaris");
-               return ERROR_FLASH_OPERATION_FAILED;
+       /* Read each Flash Memory Protection Program Enable (FMPPE) register
+        * to report any pages that we can't write.  Ignore the Read Enable
+        * register (FMPRE).
+        */
+       for (i = 0, page = 0;
+                       i < DIV_ROUND_UP(stellaris->num_lockbits, 32u);
+                       i++) {
+               uint32_t lockbits;
+
+               status = target_read_u32(bank->target,
+                               SCB_BASE + (i ? (FMPPE0 + 4 * i) : FMPPE),
+                               &lockbits);
+               LOG_DEBUG("FMPPE%d = %#8.8x (status %d)", i,
+                               (unsigned) lockbits, status);
+               if (status != ERROR_OK)
+                       goto done;
+
+               for (unsigned j = 0; j < 32; j++) {
+                       unsigned k;
+
+                       for (k = 0; k < stellaris->pages_in_lockregion; k++) {
+                               if (page >= (unsigned) bank->num_sectors)
+                                       goto done;
+                               bank->sectors[page++].is_protected =
+                                               !(lockbits & (1 << j));
+                       }
+               }
        }
 
-       status = stellaris_get_flash_status(bank);
-       stellaris_info->lockbits = status >> 16;
-
-       return ERROR_OK;
+done:
+       return status;
 }
 
 static int stellaris_erase(struct flash_bank *bank, int first, int last)
@@ -658,15 +625,7 @@ static int stellaris_erase(struct flash_bank *bank, int first, int last)
        }
 
        if (stellaris_info->did1 == 0)
-       {
-               stellaris_read_part_info(bank);
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as Stellaris");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
+               return ERROR_FLASH_BANK_NOT_PROBED;
 
        if ((first < 0) || (last < first) || (last >= (int)stellaris_info->num_pages))
        {
@@ -678,14 +637,18 @@ static int stellaris_erase(struct flash_bank *bank, int first, int last)
                return stellaris_mass_erase(bank);
        }
 
-       /* Configure the flash controller timing */
+       /* Refresh flash controller timing */
        stellaris_read_clock_info(bank);
-       stellaris_set_flash_mode(bank,0);
+       stellaris_set_flash_timing(bank);
 
        /* Clear and disable flash programming interrupts */
        target_write_u32(target, FLASH_CIM, 0);
        target_write_u32(target, FLASH_MISC, PMISC | AMISC);
 
+       /* REVISIT this clobbers state set by any halted firmware ...
+        * it might want to process those IRQs.
+        */
+
        for (banknr = first; banknr <= last; banknr++)
        {
                /* Address is first word in page */
@@ -728,47 +691,69 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
                return ERROR_TARGET_NOT_HALTED;
        }
 
-       if ((first < 0) || (last < first) || (last >= stellaris_info->num_lockbits))
+       if (!set)
        {
-               return ERROR_FLASH_SECTOR_INVALID;
+               LOG_ERROR("Can't unprotect write-protected pages.");
+               /* except by the "recover locked device" procedure ... */
+               return ERROR_INVALID_ARGUMENTS;
        }
 
        if (stellaris_info->did1 == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       /* lockregions are 2 pages ... must protect [even..odd] */
+       if ((first < 0) || (first & 1)
+                       || (last < first) || !(last & 1)
+                       || (last >= 2 * stellaris_info->num_lockbits))
        {
-               stellaris_read_part_info(bank);
+               LOG_ERROR("Can't protect unaligned or out-of-range sectors.");
+               return ERROR_FLASH_SECTOR_INVALID;
        }
 
-       if (stellaris_info->did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as an Stellaris MCU");
+       /* Refresh flash controller timing */
+       stellaris_read_clock_info(bank);
+       stellaris_set_flash_timing(bank);
+
+       /* convert from pages to lockregions */
+       first /= 2;
+       last /= 2;
+
+       /* FIXME this assumes single FMPPE, for a max of 64K of flash!!
+        * Current parts can be much bigger.
+        */
+       if (last >= 32) {
+               LOG_ERROR("No support yet for protection > 64K");
                return ERROR_FLASH_OPERATION_FAILED;
        }
 
-       /* Configure the flash controller timing */
-       stellaris_read_clock_info(bank);
-       stellaris_set_flash_mode(bank, 0);
+       target_read_u32(target, SCB_BASE | FMPPE, &fmppe);
 
-       fmppe = stellaris_info->lockbits;
        for (lockregion = first; lockregion <= last; lockregion++)
-       {
-               if (set)
-                       fmppe &= ~(1 << lockregion);
-               else
-                       fmppe |= (1 << lockregion);
-       }
+               fmppe &= ~(1 << lockregion);
 
        /* Clear and disable flash programming interrupts */
        target_write_u32(target, FLASH_CIM, 0);
        target_write_u32(target, FLASH_MISC, PMISC | AMISC);
 
+       /* REVISIT this clobbers state set by any halted firmware ...
+        * it might want to process those IRQs.
+        */
+
        LOG_DEBUG("fmppe 0x%" PRIx32 "",fmppe);
        target_write_u32(target, SCB_BASE | FMPPE, fmppe);
+
        /* Commit FMPPE */
        target_write_u32(target, FLASH_FMA, 1);
+
        /* Write commit command */
-       /* TODO safety check, sice this cannot be undone */
+       /* 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 !");
        /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */
+
        /* Wait until erase complete */
        do
        {
@@ -785,12 +770,10 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
                return ERROR_FLASH_OPERATION_FAILED;
        }
 
-       target_read_u32(target, SCB_BASE | FMPPE, &stellaris_info->lockbits);
-
        return ERROR_OK;
 }
 
-static uint8_t stellaris_write_code[] =
+static const uint8_t stellaris_write_code[] =
 {
 /*
        Call with :
@@ -827,10 +810,11 @@ static uint8_t stellaris_write_code[] =
 /* pFLASH_CTRL_BASE: */
        0x00,0xD0,0x0F,0x40,    /* .word        0x400FD000 */
 /* FLASHWRITECMD: */
-       0x01,0x00,0x42,0xA4     /* .word        0xA4420001 */
+       0x01,0x00,0x42,0xA4     /* .word        0xA4420001 */
 };
 
-static int stellaris_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t wcount)
+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;
@@ -841,35 +825,47 @@ static int stellaris_write_block(struct flash_bank *bank, uint8_t *buffer, uint3
        struct armv7m_algorithm armv7m_info;
        int retval = ERROR_OK;
 
+       /* power of two, and multiple of word size */
+       static const unsigned buf_min = 32;
+
+       /* for small buffers it's faster not to download an algorithm */
+       if (wcount < 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), stellaris_write_code);
+       /* plus a buffer big enough for this data */
+       if (wcount < buffer_size) {
+               buffer_size = wcount;
+               buffer_size += buf_min - 1;
+               buffer_size &= ~(buf_min - 1);
+       }
 
        /* memory buffer */
        while (target_alloc_working_area(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;
 
@@ -886,11 +882,20 @@ static int stellaris_write_block(struct flash_bank *bank, uint8_t *buffer, uint3
                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,
+                               write_algorithm->address +
+                                       sizeof(stellaris_write_code) - 10,
+                               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;
                }
@@ -900,6 +905,10 @@ static int stellaris_write_block(struct flash_bank *bank, uint8_t *buffer, uint3
                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);
 
@@ -931,15 +940,7 @@ static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t of
                        bank, buffer, offset, count);
 
        if (stellaris_info->did1 == 0)
-       {
-               stellaris_read_part_info(bank);
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as a Stellaris processor");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
+               return ERROR_FLASH_BANK_NOT_PROBED;
 
        if (offset & 0x3)
        {
@@ -950,25 +951,29 @@ static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t of
        if (offset + count > bank->size)
                return ERROR_FLASH_DST_OUT_OF_BANK;
 
-       /* Configure the flash controller timing */
+       /* Refresh flash controller timing */
        stellaris_read_clock_info(bank);
-       stellaris_set_flash_mode(bank, 0);
+       stellaris_set_flash_timing(bank);
 
        /* Clear and disable flash programming interrupts */
        target_write_u32(target, FLASH_CIM, 0);
        target_write_u32(target, FLASH_MISC, PMISC | AMISC);
 
+       /* REVISIT this clobbers state set by any halted firmware ...
+        * it might want to process those IRQs.
+        */
+
        /* multiple words to be programmed? */
        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)
                        {
@@ -1047,26 +1052,36 @@ static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t of
 
 static int stellaris_probe(struct flash_bank *bank)
 {
-       /* we can't probe on an stellaris
-        * if this is an stellaris, it has the configured flash
+       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+       int retval;
+
+       /* If this is a stellaris chip, it has flash; probe() is just
+        * to figure out how much is present.  Only do it once.
         */
+       if (stellaris_info->did1 != 0)
+               return ERROR_OK;
 
-       if (bank->target->state != TARGET_HALTED)
+       /* stellaris_read_part_info() already handled error checking and
+        * reporting.  Note that it doesn't write, so we don't care about
+        * whether the target is halted or not.
+        */
+       retval = stellaris_read_part_info(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* provide this for the benefit of the NOR flash framework */
+       bank->size = 1024 * stellaris_info->num_pages;
+       bank->num_sectors = stellaris_info->num_pages;
+       bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector));
+       for (int i = 0; i < bank->num_sectors; i++)
        {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
+               bank->sectors[i].offset = i * stellaris_info->pagesize;
+               bank->sectors[i].size = stellaris_info->pagesize;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = -1;
        }
 
-       /* stellaris_read_part_info() already takes care about error checking and reporting */
-       return stellaris_read_part_info(bank);
-}
-
-static int stellaris_auto_probe(struct flash_bank *bank)
-{
-       struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
-       if (stellaris_info->did1)
-               return ERROR_OK;
-       return stellaris_probe(bank);
+       return retval;
 }
 
 static int stellaris_mass_erase(struct flash_bank *bank)
@@ -1085,24 +1100,20 @@ static int stellaris_mass_erase(struct flash_bank *bank)
        }
 
        if (stellaris_info->did1 == 0)
-       {
-               stellaris_read_part_info(bank);
-       }
-
-       if (stellaris_info->did1 == 0)
-       {
-               LOG_WARNING("Cannot identify target as Stellaris");
-               return ERROR_FLASH_OPERATION_FAILED;
-       }
+               return ERROR_FLASH_BANK_NOT_PROBED;
 
-       /* Configure the flash controller timing */
+       /* Refresh flash controller timing */
        stellaris_read_clock_info(bank);
-       stellaris_set_flash_mode(bank, 0);
+       stellaris_set_flash_timing(bank);
 
        /* Clear and disable flash programming interrupts */
        target_write_u32(target, FLASH_CIM, 0);
        target_write_u32(target, FLASH_MISC, PMISC | AMISC);
 
+       /* REVISIT this clobbers state set by any halted firmware ...
+        * it might want to process those IRQs.
+        */
+
        target_write_u32(target, FLASH_FMA, 0);
        target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
        /* Wait until erase complete */
@@ -1182,15 +1193,15 @@ static const struct command_registration stellaris_command_handlers[] = {
 };
 
 struct flash_driver stellaris_flash = {
-               .name = "stellaris",
-               .commands = stellaris_command_handlers,
-               .flash_bank_command = &stellaris_flash_bank_command,
-               .erase = &stellaris_erase,
-               .protect = &stellaris_protect,
-               .write = &stellaris_write,
-               .probe = &stellaris_probe,
-               .auto_probe = &stellaris_auto_probe,
-               .erase_check = &default_flash_mem_blank_check,
-               .protect_check = &stellaris_protect_check,
-               .info = &stellaris_info,
-       };
+       .name = "stellaris",
+       .commands = stellaris_command_handlers,
+       .flash_bank_command = stellaris_flash_bank_command,
+       .erase = stellaris_erase,
+       .protect = stellaris_protect,
+       .write = stellaris_write,
+       .probe = stellaris_probe,
+       .auto_probe = stellaris_probe,
+       .erase_check = default_flash_mem_blank_check,
+       .protect_check = stellaris_protect_check,
+       .info = 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)