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 <dan@stahlke.org>
Change-Id: I19745dae4d3fc6e3a7611dcac628e067cb41e0f0
Reviewed-on: https://review.openocd.org/c/openocd/+/7391
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
Dan Stahlke 2022-12-04 18:12:16 -08:00 committed by Antonio Borneo
parent 0a829efda5
commit 77c7abe4e7
1 changed files with 25 additions and 1 deletions

View File

@ -12,6 +12,7 @@
#include "imp.h"
#include "helper/binarybuffer.h"
#include <helper/time_support.h>
#include <jtag/jtag.h>
#include <target/cortex_m.h>
@ -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);