target/renesas: add rv40 flash error check

This commit is contained in:
Rafael Silva 2022-07-25 18:07:34 +01:00 committed by Rachel Mant
parent 01cd733745
commit 31856f028f
1 changed files with 106 additions and 20 deletions

View File

@ -242,9 +242,21 @@ typedef enum {
#define RV40_BASE 0x407FE000UL
#define RV40_FSTATR (RV40_BASE + 0x80U) /* Flash Status */
#define RV40_FSTATR_RDY (1U << 15U) /* Flash Ready */
#define RV40_FSTATR_DBFULL (1U << 10U) /* Data Buffer Full */
#define RV40_FASTAT (RV40_BASE + 0x10U) /* Flash Access Status */
#define RV40_FASTAT_CMDLK (1U << 4U) /* Command Lock */
#define RV40_FSTATR (RV40_BASE + 0x80U) /* Flash Status */
#define RV40_FSTATR_DBFULL (1U << 10U) /* Data Buffer Full */
#define RV40_FSTATR_RDY (1U << 15U) /* Flash Ready */
#define RV40_FSTATR_PRGERR (1U << 12U) /* Programming Error */
#define RV40_FSTATR_ERSERR (1U << 13U) /* Erasure Error */
#define RV40_FSTATR_ILGLERR (1U << 14U) /* Illegal Command Error */
#define RV40_FSTATR_OTERR (1U << 20U) /* Other Error */
#define RV40_FSTATR_SECERR (1U << 21U) /* Security Error */
#define RV40_FSTATR_FESETERR (1U << 22U) /* FENTRY Setting Error */
#define RV40_FSTATR_ILGCOMERR (1U << 23U) /* Illegal Command Error */
#define RV40_FSADDR (RV40_BASE + 0x30U)
@ -409,19 +421,59 @@ static bool renesas_rv40_pe_mode(target *t, pe_mode_e pe_mode)
platform_timeout timeout;
platform_timeout_set(&timeout, 10);
/* Wait for the operation to complete or timeout, Read FENTRYR until it has been set */
while (target_mem_read16(t, RV40_FENTRYR) != fentryr) {
/* Wait for the operation to complete or timeout, Read until FENTRYR and FRDY is set */
while (target_mem_read16(t, RV40_FENTRYR) != fentryr || !(target_mem_read32(t, RV40_FSTATR) & RV40_FSTATR_RDY)) {
if (target_check_error(t) || platform_timeout_is_expired(&timeout))
return false;
};
if (has_fmeprot && pe_mode == PE_MODE_READ) {
target_mem_write16(t, RV40_FMEPROT, RV40_FMEPROT_LOCK);
}
if (has_fmeprot && pe_mode == PE_MODE_READ)
target_mem_write16(t, RV40_FMEPROT, RV40_FMEPROT_LOCK);
return true;
}
static bool renesas_rv40_error_check(target *t, uint32_t error_bits)
{
bool error = false;
uint8_t fstatr = target_mem_read32(t, RV40_FSTATR);
/* see "Recovery from the Command-Locked State": Section 47.9.3.6 of the RA6M4 manual R01UH0890EJ0100.*/
if (target_mem_read8(t, RV40_FASTAT) & RV40_FASTAT_CMDLK) {
/* if an illegal error occurred read and clear CFAE and DFAE in FASTAT. */
if (fstatr & RV40_FSTATR_ILGLERR) {
target_mem_read8(t, RV40_FASTAT);
target_mem_write8(t, RV40_FASTAT, 0);
}
error = true;
}
/* check if status is indicating a programming error */
if (fstatr & error_bits)
error = true;
if (error) {
/* Stop the flash */
target_mem_write8(t, RV40_CMD, RV40_CMD_FORCED_STOP);
platform_timeout timeout;
platform_timeout_set(&timeout, 10);
/* Wait until the operation has completed or timeout */
/* Read FRDY bit until it has been set to 1 indicating that the current operation is complete.*/
while (!(target_mem_read32(t, RV40_FSTATR) & RV40_FSTATR_RDY)) {
if (target_check_error(t) || platform_timeout_is_expired(&timeout))
return error;
}
if (target_mem_read8(t, RV40_FASTAT) & RV40_FASTAT_CMDLK)
return error;
}
return error;
}
/* !TODO: implement blank check */
static int renesas_rv40_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{
@ -459,6 +511,11 @@ static int renesas_rv40_flash_erase(target_flash_s *f, target_addr_t addr, size_
len += RV40_DF_BLOCK_SIZE - len % RV40_DF_BLOCK_SIZE;
}
if (!(target_mem_read32(t, RV40_FSTATR) & RV40_FSTATR_RDY) || target_mem_read16(t, RV40_FENTRYR) != 0) {
DEBUG_WARN("flash is not ready, may be hanging mid unfinished command due to something going wrong, "
"please power on reset the device\n");
}
/* Transition to PE mode */
const pe_mode_e pe_mode = code_flash ? PE_MODE_CF : PE_MODE_DF;
if (!renesas_rv40_pe_mode(t, pe_mode))
@ -467,6 +524,8 @@ static int renesas_rv40_flash_erase(target_flash_s *f, target_addr_t addr, size_
/* Set Erasure Priority Mode */
target_mem_write16(t, RV40_FCPSR, RV40_FCPSR_ESUSPMD);
int result = 0;
while (len) {
/* Set block start address*/
target_mem_write32(t, RV40_FSADDR, addr);
@ -494,15 +553,24 @@ static int renesas_rv40_flash_erase(target_flash_s *f, target_addr_t addr, size_
/* Wait until the operation has completed or timeout */
/* Read FRDY bit until it has been set to 1 indicating that the current operation is complete.*/
while (!(target_mem_read32(t, RV40_FSTATR) & RV40_FSTATR_RDY)) {
if (target_check_error(t) || platform_timeout_is_expired(&timeout))
return -1;
};
if (target_check_error(t) || platform_timeout_is_expired(&timeout)) {
result = -1;
goto exit;
}
}
if (renesas_rv40_error_check(t, RV40_FSTATR_ERSERR | RV40_FSTATR_ILGLERR)) {
result = -1;
goto exit;
}
}
exit:
/* return to read mode */
renesas_rv40_pe_mode(t, PE_MODE_READ);
return 0;
return result;
}
static int renesas_rv40_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len)
@ -521,11 +589,18 @@ static int renesas_rv40_flash_write(target_flash_s *f, target_addr_t dest, const
if (dest % write_size || len % write_size) /* dest/len must be aligned to write_size */
return -1;
if (!(target_mem_read32(t, RV40_FSTATR) & RV40_FSTATR_RDY) || target_mem_read16(t, RV40_FENTRYR) != 0) {
DEBUG_WARN("flash is not ready, may be hanging mid unfinished command due to something going wrong, "
"please power on reset the device\n");
}
/* transition to PE mode */
const pe_mode_t pe_mode = code_flash ? PE_MODE_CF : PE_MODE_DF;
if (!renesas_rv40_pe_mode(t, pe_mode))
return -1;
int result = 0;
while (len) {
/* set block start address */
target_mem_write32(t, RV40_FSADDR, dest);
@ -551,9 +626,11 @@ static int renesas_rv40_flash_write(target_flash_s *f, target_addr_t dest, const
target_mem_write16(t, RV40_CMD, *(uint16_t *)src);
while (target_mem_read32(t, RV40_FSTATR) & RV40_FSTATR_DBFULL) {
if (target_check_error(t) || platform_timeout_is_expired(&timeout))
return -1;
};
if (target_check_error(t) || platform_timeout_is_expired(&timeout)) {
result = -1;
goto exit;
}
}
/* 2 bytes of data */
src += 2U;
@ -565,15 +642,24 @@ static int renesas_rv40_flash_write(target_flash_s *f, target_addr_t dest, const
/* wait until the operation has completed or timeout */
/* read FRDY bit until it has been set to 1 indicating that the current operation is complete.*/
while (!(target_mem_read32(t, RV40_FSTATR) & RV40_FSTATR_RDY)) {
if (target_check_error(t) || platform_timeout_is_expired(&timeout))
return -1;
};
if (target_check_error(t) || platform_timeout_is_expired(&timeout)) {
result = -1;
goto exit;
}
}
if (renesas_rv40_error_check(t, RV40_FSTATR_PRGERR | RV40_FSTATR_ILGLERR)) {
result = -1;
goto exit;
}
}
exit:
/* return to read mode*/
renesas_rv40_pe_mode(t, PE_MODE_READ);
return 0;
return result;
}
static void renesas_add_rv40_flash(target *t, target_addr_t addr, size_t length)