aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Fertser <fercerpav@gmail.com>2014-08-21 15:16:55 +0400
committerSpencer Oliver <spen@spen-soft.co.uk>2014-10-06 18:40:46 +0000
commitcdcae765de9ad3736bb54192270d476f9b42485a (patch)
treec74a2daf89b2003aa69c6ca54a080e1354b0f047 /src
parent487c57d9a27244b6a916cce253d8aaaec5e22604 (diff)
flash/nor/stellaris: implement protection statuses and procedures
This should make protection work as expected on all stellaris families, including the latest Tiva C Snowflake. Run-time tested on TM4C123x (Blizzard). Change-Id: Ia017edb119bec32382b08fc037b5bbc02dd9000c Signed-off-by: Paul Fertser <fercerpav@gmail.com> Reviewed-on: http://openocd.zylin.com/2267 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Diffstat (limited to 'src')
-rw-r--r--src/flash/nor/stellaris.c198
1 files changed, 89 insertions, 109 deletions
diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c
index 4c819c61..c4fe3be9 100644
--- a/src/flash/nor/stellaris.c
+++ b/src/flash/nor/stellaris.c
@@ -107,14 +107,9 @@ struct stellaris_flash_bank {
uint8_t target_class;
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;
@@ -524,24 +519,15 @@ static int get_stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
printed = snprintf(buf,
buf_size,
"master clock: %ikHz%s, "
- "rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 "\n",
+ "rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 ", "
+ "pagesize: %" PRIu32 ", pages: %" PRIu32,
(int)(stellaris_info->mck_freq / 1000),
stellaris_info->mck_desc,
stellaris_info->rcc,
- stellaris_info->rcc2);
- buf += printed;
- buf_size -= printed;
+ stellaris_info->rcc2,
+ stellaris_info->pagesize,
+ stellaris_info->num_pages);
- if (stellaris_info->num_lockbits > 0) {
- snprintf(buf,
- 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);
- }
return ERROR_OK;
}
@@ -782,11 +768,9 @@ static int stellaris_read_part_info(struct flash_bank *bank)
target_read_u32(target, FLASH_FSIZE, &stellaris_info->fsize);
target_read_u32(target, FLASH_SSIZE, &stellaris_info->ssize);
- stellaris_info->num_lockbits = 1 + (stellaris_info->fsize & 0xFFFF);
stellaris_info->num_pages = 2 * (1 + (stellaris_info->fsize & 0xFFFF));
stellaris_info->sramsiz = (1 + (stellaris_info->ssize & 0xFFFF)) / 4;
stellaris_info->pagesize = 1024;
- stellaris_info->pages_in_lockregion = 2;
} else if (stellaris_info->target_class == 0xa) { /* Snowflake */
target_read_u32(target, FLASH_FSIZE, &stellaris_info->fsize);
target_read_u32(target, FLASH_SSIZE, &stellaris_info->ssize);
@@ -794,17 +778,11 @@ static int stellaris_read_part_info(struct flash_bank *bank)
stellaris_info->pagesize = (1 << ((stellaris_info->fsize >> 16) & 7)) * 1024;
stellaris_info->num_pages = 2048 * (1 + (stellaris_info->fsize & 0xFFFF)) /
stellaris_info->pagesize;
- stellaris_info->pages_in_lockregion = 1;
-
- stellaris_info->num_lockbits = stellaris_info->pagesize * stellaris_info->num_pages /
- 2048;
stellaris_info->sramsiz = (1 + (stellaris_info->ssize & 0xFFFF)) / 4;
} else {
- stellaris_info->num_lockbits = 1 + (stellaris_info->dc0 & 0xFFFF);
stellaris_info->num_pages = 2 * (1 + (stellaris_info->dc0 & 0xFFFF));
stellaris_info->sramsiz = (1 + ((stellaris_info->dc0 >> 16) & 0xFFFF)) / 4;
stellaris_info->pagesize = 1024;
- stellaris_info->pages_in_lockregion = 2;
}
/* REVISIT for at least Tempest parts, read NVMSTAT.FWB too.
@@ -822,18 +800,16 @@ static int stellaris_read_part_info(struct flash_bank *bank)
static int stellaris_protect_check(struct flash_bank *bank)
{
struct stellaris_flash_bank *stellaris = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t flash_sizek = stellaris->pagesize / 1024 *
+ stellaris->num_pages;
+ uint32_t fmppe_addr;
int status = ERROR_OK;
unsigned i;
- unsigned page;
if (stellaris->did1 == 0)
return ERROR_FLASH_BANK_NOT_PROBED;
- if (stellaris->target_class == 0xa) {
- LOG_WARNING("Assuming flash to be unprotected on Snowflake");
- return ERROR_OK;
- }
-
for (i = 0; i < (unsigned) bank->num_sectors; i++)
bank->sectors[i].is_protected = -1;
@@ -841,32 +817,32 @@ static int stellaris_protect_check(struct flash_bank *bank)
* 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));
+ if (stellaris->target_class >= 0x0a || flash_sizek > 64)
+ fmppe_addr = SCB_BASE | FMPPE0;
+ else
+ fmppe_addr = SCB_BASE | FMPPE;
+
+ unsigned int page = 0, lockbitnum, lockbitcnt = flash_sizek / 2;
+ unsigned int bits_per_page = stellaris->pagesize / 2048;
+ /* Every lock bit always corresponds to a 2k region */
+ for (lockbitnum = 0; lockbitnum < lockbitcnt; lockbitnum += 32) {
+ uint32_t fmppe;
+
+ target_read_u32(target, fmppe_addr, &fmppe);
+ for (i = 0; i < 32 && lockbitnum + i < lockbitcnt; i++) {
+ bool protect = !(fmppe & (1 << i));
+ if (bits_per_page) {
+ bank->sectors[page++].is_protected = protect;
+ i += bits_per_page - 1;
+ } else { /* 1024k pages, every lockbit covers 2 pages */
+ bank->sectors[page++].is_protected = protect;
+ bank->sectors[page++].is_protected = protect;
}
}
+ fmppe_addr += 4;
}
-done:
return status;
}
@@ -930,13 +906,12 @@ static int stellaris_erase(struct flash_bank *bank, int first, int last)
static int stellaris_protect(struct flash_bank *bank, int set, int first, int last)
{
- uint32_t fmppe, flash_fmc, flash_cris;
- int lockregion;
-
- struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
+ struct stellaris_flash_bank *stellaris = bank->driver_priv;
struct target *target = bank->target;
+ uint32_t flash_fmc, flash_cris;
+ unsigned int bits_per_page = stellaris->pagesize / 2048;
- if (bank->target->state != TARGET_HALTED) {
+ if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
@@ -947,26 +922,18 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
return ERROR_COMMAND_SYNTAX_ERROR;
}
- if (stellaris_info->did1 == 0)
+ if (stellaris->did1 == 0)
return ERROR_FLASH_BANK_NOT_PROBED;
- if (stellaris_info->target_class == 0x03 &&
- !((stellaris_info->did0 >> 8) & 0xFF) &&
- !((stellaris_info->did0) & 0xFF)) {
+ if (stellaris->target_class == 0x03 &&
+ !((stellaris->did0 >> 8) & 0xFF) &&
+ !((stellaris->did0) & 0xFF)) {
LOG_ERROR("DustDevil A0 parts can't be unprotected, see errata; refusing to proceed");
return ERROR_FLASH_OPERATION_FAILED;
}
- if (stellaris_info->target_class == 0xa) {
- LOG_ERROR("Protection on Snowflake is not supported yet");
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- /* lockregions are 2 pages ... must protect [even..odd] */
- if ((first < 0) || (first & 1)
- || (last < first) || !(last & 1)
- || (last >= 2 * stellaris_info->num_lockbits)) {
- LOG_ERROR("Can't protect unaligned or out-of-range pages.");
+ if (!bits_per_page && (first % 2 || !(last % 2))) {
+ LOG_ERROR("Can't protect unaligned pages");
return ERROR_FLASH_SECTOR_INVALID;
}
@@ -974,50 +941,60 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
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;
- }
-
- target_read_u32(target, SCB_BASE | FMPPE, &fmppe);
-
- for (lockregion = first; lockregion <= last; 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.
- */
+ uint32_t flash_sizek = stellaris->pagesize / 1024 *
+ stellaris->num_pages;
+ uint32_t fmppe_addr;
- LOG_DEBUG("fmppe 0x%" PRIx32 "", fmppe);
- target_write_u32(target, SCB_BASE | FMPPE, fmppe);
+ if (stellaris->target_class >= 0x0a || flash_sizek > 64)
+ fmppe_addr = SCB_BASE | FMPPE0;
+ else
+ fmppe_addr = SCB_BASE | FMPPE;
+
+ int page = 0;
+ unsigned int lockbitnum, lockbitcnt = flash_sizek / 2;
+ /* Every lock bit always corresponds to a 2k region */
+ for (lockbitnum = 0; lockbitnum < lockbitcnt; lockbitnum += 32) {
+ uint32_t fmppe;
+
+ target_read_u32(target, fmppe_addr, &fmppe);
+ for (unsigned int i = 0;
+ i < 32 && lockbitnum + i < lockbitcnt;
+ i++) {
+ if (page >= first && page <= last)
+ fmppe &= ~(1 << i);
+
+ if (bits_per_page) {
+ if (!((i + 1) % bits_per_page))
+ page++;
+ } else { /* 1024k pages, every lockbit covers 2 pages */
+ page += 2;
+ }
+ }
+ target_write_u32(target, fmppe_addr, fmppe);
- /* Commit FMPPE */
- target_write_u32(target, FLASH_FMA, 1);
- /* Write commit command */
- target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT);
+ /* Commit FMPPE* */
+ target_write_u32(target, FLASH_FMA, 1 + lockbitnum / 16);
+ /* Write commit command */
+ target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT);
- /* Wait until erase complete */
- do {
- target_read_u32(target, FLASH_FMC, &flash_fmc);
- } while (flash_fmc & FMC_COMT);
+ /* Wait until commit complete */
+ do {
+ target_read_u32(target, FLASH_FMC, &flash_fmc);
+ } while (flash_fmc & FMC_COMT);
- /* Check acess violations */
- target_read_u32(target, FLASH_CRIS, &flash_cris);
- if (flash_cris & (AMASK)) {
- LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris);
- target_write_u32(target, FLASH_CRIS, 0);
- return ERROR_FLASH_OPERATION_FAILED;
+ /* Check access violations */
+ target_read_u32(target, FLASH_CRIS, &flash_cris);
+ if (flash_cris & (AMASK)) {
+ LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris);
+ target_write_u32(target, FLASH_CRIS, 0);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ fmppe_addr += 4;
}
return ERROR_OK;
@@ -1382,6 +1359,9 @@ COMMAND_HANDLER(stellaris_handle_recover_command)
struct flash_bank *bank;
int retval;
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (retval != ERROR_OK)
return retval;