X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstellaris.c;h=069ee8c1c111a86722b11ca7b82519934c598c47;hp=107b1c6d1767725d99fdc382bcd6145cf529df6f;hb=4617cd0f911d64a460d99d25c531ddc55f2452ca;hpb=303b493c229475df26d69d102bbaf5ae5e5e7a3f diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 107b1c6d17..069ee8c1c1 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -22,7 +22,7 @@ ***************************************************************************/ /*************************************************************************** -* STELLARIS is tested on LM3S811, LM3S6965 +* STELLARIS flash is tested on LM3S811, LM3S6965, LM3s3748, more. ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" @@ -255,7 +255,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 +693,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 suppport page-level unprotect. " + "Try the 'recover' command."); return ERROR_INVALID_ARGUMENTS; } @@ -706,7 +706,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; } @@ -773,6 +773,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 +807,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 +818,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 +848,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 +886,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 +1066,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 +1176,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, .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 +1268,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, };