From 31856f028f5fa1b1329a42f69b51cd229bd7e8b6 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Mon, 25 Jul 2022 18:07:34 +0100 Subject: [PATCH] target/renesas: add rv40 flash error check --- src/target/renesas.c | 126 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 20 deletions(-) diff --git a/src/target/renesas.c b/src/target/renesas.c index 0c1485a..beb1dd2 100644 --- a/src/target/renesas.c +++ b/src/target/renesas.c @@ -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)