diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 5c0ffbd6..2f2d92b6 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -386,6 +386,7 @@ static const struct kinetis_type kinetis_types_old[] = { #define MDM_ACCESS_TIMEOUT 500 /* msec */ +static bool force_slow_write = false; static bool allow_fcf_writes; static uint8_t fcf_fopt = 0xff; static bool create_banks; @@ -1244,6 +1245,9 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, int retval; uint8_t fstat; + if (force_slow_write == true) + return (ERROR_TARGET_RESOURCE_NOT_AVAILABLE); + /* Increase buffer_size if needed */ if (buffer_size < (target->working_area_size/2)) buffer_size = (target->working_area_size/2); @@ -1459,16 +1463,54 @@ static int kinetis_ftfx_command(struct target *target, uint8_t fcmd, uint32_t fa fccobb, fccoba, fccob9, fccob8}; int result; uint8_t fstat; - int64_t ms_timeout = timeval_ms() + 250; + volatile int64_t ms_timeout; result = target_write_memory(target, FTFx_FCCOB3, 4, 3, command); if (result != ERROR_OK) return result; + /* + * We do not want to check the return status when writing + * to the FSTAT register to initiate a flash command. + * This is because some JTAG devices perform an automatic + * verify operation on write. + * + * Since we're writing to a "write 1 to clear" bit, the + * ready bit will be cleared briefly once the memory write + * completes and flash command starts, and then become set + * again when the flash command finishes. The bit remains + * clear only while the flash command is in progress. + * + * If the JTAG probe reads from the status register during the + * window while the command is in progress, the read-back + * value will never match the value we tried to write, and the + * verification will fail. But this behavior is expected, not + * an error, so we should not bail out here. + * + * Unfortunately the error status we receive here is not + * specific enough to determine if the write fails due to + * this verification glitch or because of some other hard + * failure, so our only recourse is to just not do any + * error checking here. If there really is a problem accessing + * the MCU, it will be detected in the status check loop + * below. + * + * This is intended mainly for the ST-Link V2 dongles. + */ + /* start command */ - result = target_write_u8(target, FTFx_FSTAT, 0x80); - if (result != ERROR_OK) - return result; + (void) target_write_u8(target, FTFx_FSTAT, 0x80); + + /* + * Set the timeout time here, rather than initializing it + * on entry to this function. It takes time to perform the + * two target writes above, and that time will effectively + * be subtracted from the total before we reach the loop + * below, meaning the time we wait for the loop to complete + * will be less than 250ms. + */ + + ms_timeout = timeval_ms() + 250; /* wait for done */ do { @@ -1646,7 +1688,25 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last) uint8_t fcf_buffer[FCF_SIZE]; kinetis_fill_fcf(bank, fcf_buffer); + + /* + * Since writing the flash security field + * is such a critical operation, how about + * we force a fallback to the slow but safe + * write mechanism to write it. With some + * debuggers, notably the ST-Link V2, + * the fast block mode can fail in some + * scenarios, leaving the chip stuck in + * secure mode. And since the ST-Link V2 + * is not a low-level adapter, this leaves + * us stuck without a way to recover the + * device. Best to use belt *and* suspenders + * approach here. + */ + + force_slow_write = true; result = kinetis_write_inner(bank, fcf_buffer, FCF_ADDRESS, FCF_SIZE); + force_slow_write = false; if (result != ERROR_OK) LOG_WARNING("Flash Configuration Field write failed"); bank->sectors[i].is_erased = 0;