X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstellaris.c;h=89cc8ef08a61f6b16aae1d739829279b99e33ccc;hb=898dd3af46e76fb195c6894f54e9bc9272375ffb;hp=8d35f9b10f1d158f07725ffefa9cff145bf185fa;hpb=b3bf1d12b2fdfba1c1cbee3e1afbfbb27cbd1a26;p=openocd.git diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 8d35f9b10f..89cc8ef08a 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -22,26 +22,112 @@ ***************************************************************************/ /*************************************************************************** -* 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 #include #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); +struct stellaris_flash_bank +{ + /* 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 6734 static struct { uint32_t partno; - char *partname; + const char *partname; } StellarisParts[] = { {0x0001,"LM3S101"}, @@ -94,6 +180,7 @@ static struct { {0x1005,"LM3S1627"}, {0x10B3,"LM3S1635"}, {0x10BD,"LM3S1637"}, + {0x10B1,"LM3S1651"}, {0x10B9,"LM3S1751"}, {0x1010,"LM3S1776"}, {0x1016,"LM3S1811"}, @@ -109,6 +196,8 @@ static struct { {0x103C,"LM3S1J16"}, {0x100E,"LM3S1N11"}, {0x103B,"LM3S1N16"}, + {0x10B2,"LM3S1P51"}, + {0x109E,"LM3S1R21"}, {0x1030,"LM3S1W16"}, {0x102F,"LM3S1Z16"}, {0x1051,"LM3S2110"}, @@ -137,6 +226,7 @@ static struct { {0x1058,"LM3S2950"}, {0x1055,"LM3S2965"}, {0x106C,"LM3S2B93"}, + {0x1008,"LM3S3634"}, {0x1043,"LM3S3651"}, {0x1044,"LM3S3739"}, {0x1049,"LM3S3748"}, @@ -255,7 +345,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; @@ -693,8 +783,8 @@ 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 ... */ + LOG_ERROR("Hardware doesn't support page-level unprotect. " + "Try the 'recover' command."); return ERROR_INVALID_ARGUMENTS; } @@ -706,7 +796,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; } @@ -751,7 +841,7 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la * 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 */ @@ -773,6 +863,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[] = { /* @@ -805,8 +897,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: */ @@ -817,7 +908,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; @@ -847,7 +938,7 @@ static int stellaris_write_block(struct flash_bank *bank, 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) { buffer_size /= 2; if (buffer_size <= buf_min) @@ -885,8 +976,7 @@ static int stellaris_write_block(struct flash_bank *bank, (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, + 0, 10000, &armv7m_info); if (retval != ERROR_OK) { @@ -1066,6 +1156,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; @@ -1170,13 +1266,79 @@ 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, + .handler = stellaris_handle_mass_erase_command, .mode = COMMAND_EXEC, + .usage = "bank_id", .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[] = { @@ -1196,9 +1358,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, };