From 77c7abe4e7569ca8bb23dad6110c7209c8c55558 Mon Sep 17 00:00:00 2001 From: Dan Stahlke Date: Sun, 4 Dec 2022 18:12:16 -0800 Subject: [PATCH] at91samd: wait for nvm ready Flashing a SAMD21J17D was failing during NVM erase. The samd21 datasheet specifies that one cause of error conditions is executing an NVM command while the previous command is still running. The solution is to wait for INTFLAG.READY after a command is issued. SAMD21J17A was not exhibiting this problem. Perhaps the later silicon revision has slower NVM erase times. Signed-off-by: Dan Stahlke Change-Id: I19745dae4d3fc6e3a7611dcac628e067cb41e0f0 Reviewed-on: https://review.openocd.org/c/openocd/+/7391 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- src/flash/nor/at91samd.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index f213444d1f..33e86c76e9 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -12,6 +12,7 @@ #include "imp.h" #include "helper/binarybuffer.h" +#include #include #include @@ -31,7 +32,7 @@ #define SAMD_NVMCTRL_CTRLA 0x00 /* NVM control A register */ #define SAMD_NVMCTRL_CTRLB 0x04 /* NVM control B register */ #define SAMD_NVMCTRL_PARAM 0x08 /* NVM parameters register */ -#define SAMD_NVMCTRL_INTFLAG 0x18 /* NVM Interrupt Flag Status & Clear */ +#define SAMD_NVMCTRL_INTFLAG 0x14 /* NVM Interrupt Flag Status & Clear */ #define SAMD_NVMCTRL_STATUS 0x18 /* NVM status register */ #define SAMD_NVMCTRL_ADDR 0x1C /* NVM address register */ #define SAMD_NVMCTRL_LOCK 0x20 /* NVM Lock section register */ @@ -55,6 +56,9 @@ /* NVMCTRL bits */ #define SAMD_NVM_CTRLB_MANW 0x80 +/* NVMCTRL_INTFLAG bits */ +#define SAMD_NVM_INTFLAG_READY 0x01 + /* Known identifiers */ #define SAMD_PROCESSOR_M0 0x01 #define SAMD_FAMILY_D 0x00 @@ -497,7 +501,27 @@ static int samd_probe(struct flash_bank *bank) static int samd_check_error(struct target *target) { int ret, ret2; + uint8_t intflag; uint16_t status; + int timeout_ms = 1000; + int64_t ts_start = timeval_ms(); + + do { + ret = target_read_u8(target, + SAMD_NVMCTRL + SAMD_NVMCTRL_INTFLAG, &intflag); + if (ret != ERROR_OK) { + LOG_ERROR("Can't read NVM intflag"); + return ret; + } + if (intflag & SAMD_NVM_INTFLAG_READY) + break; + keep_alive(); + } while (timeval_ms() - ts_start < timeout_ms); + + if (!(intflag & SAMD_NVM_INTFLAG_READY)) { + LOG_ERROR("SAMD: NVM programming timed out"); + return ERROR_FLASH_OPERATION_FAILED; + } ret = target_read_u16(target, SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, &status); -- 2.30.2