From ee74377e054a5d667f261e6736a36acd03558421 Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Tue, 11 Nov 2025 14:03:11 -0700 Subject: [PATCH 01/17] renesas_ra: Add ID codes for RA6M5 and RA2E1 --- src/target/renesas_ra.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 435183bc72e..03ad98f9cc0 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -39,10 +39,12 @@ #include "cortexm.h" #include "adiv5.h" +#define RENESAS_PARTID_RA2E1 0x0390U #define RENESAS_PARTID_RA2A1 0x01b0U #define RENESAS_PARTID_RA4M2 0x0340U #define RENESAS_PARTID_RA4M3 0x0310U #define RENESAS_PARTID_RA6M2 0x0150U +#define RENESAS_PARTID_RA6M5 0x0360U /* * Part numbering scheme @@ -407,18 +409,18 @@ bool renesas_ra_probe(target_s *const target) /* Read the PNR */ switch (target->part_id) { - // case : + case RENESAS_PARTID_RA2E1: /* mcus with PNR located at 0x01001c10 * ra2l1 (part_id wanted) - * ra2e1 (part_id wanted) * ra2e2 (part_id wanted) */ - // if (!renesas_pnr_read(t, RENESAS_FIXED1_PNR, pnr)) - // return false; - // break; + if (!renesas_pnr_read(target, RENESAS_FIXED1_PNR, pnr)) + return false; + break; case RENESAS_PARTID_RA4M2: case RENESAS_PARTID_RA4M3: + case RENESAS_PARTID_RA6M5: /* mcus with PNR located at 0x010080f0 * ra4e1 (part_id wanted) * ra4e2 (part_id wanted) From 14ce49980b73300652bb6cb483e6cb06b18007e1 Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:11:36 -0700 Subject: [PATCH 02/17] renesas_ra: Add defines for MF3/4 flash --- src/target/renesas_ra.c | 100 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 03ad98f9cc0..ee2c34da4c2 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -212,13 +212,109 @@ typedef enum { * Block Size: Code area: 2 KB (except RA2A1 is 1KB), Data area: 1 KB * Program/Erase unit Program: Code area: 64 bits, Data area: 8 bits * Erase: 1 block + * RA2E1: Program: Code area: 32 bits, Data area: 8 bits + * Ref: R01UH0852EJ0170, Flash Memory Overview, §35.1, pg 915 */ #define MF3_CF_BLOCK_SIZE (0x800U) #define MF3_RA2A1_CF_BLOCK_SIZE (0x400U) #define MF3_DF_BLOCK_SIZE (0x400U) #define MF3_CF_WRITE_SIZE (0x40U) +#define MF3_RA2E1_CF_WRITE_SIZE (0x20U) #define MF3_DF_WRITE_SIZE (0x1U) +/* MF3/4 Flash commands*/ +/* Taken from R01AN5367EU0120, (MF3) Software Commands, §1.5.2, pg 35 + * and R01UH0852EJ0170, Flash Control Register, §35.3.10, pg 924 */ +#define MF3_CMD_PROGRAM 0x1U +#define MF3_CMD_CF_BLANK_CHECK 0x3U +#define MF3_CMD_BLOCK_ERASE 0x4U +#define MF3_CMD_CONSECUTIVE_READ 0x5U +#define MF3_CMD_CHIP_ERASE 0x6U +#define MF3_CMD_DF_BLANK_CHECK 0xbU + +#define MF3_BASE UINT32_C(0x407ec000) + +#define MF3_DFLCTL (MF3_BASE + 0x090U) /* Data Flash Control */ +#define MF3_DFLCTL_DFLEN (1U) /* Data Flash Access Enable */ + +#define MF3_FENTRYR (MF3_BASE + 0x3fb2U) /* Flash P/E Mode Entry */ +#define MF3_FENTRYR_KEY_OFFSET 8U +#define MF3_FENTRYR_KEY (0xaaU << MF3_FENTRYR_KEY_OFFSET) +#define MF3_FENTRYR_PE_CF (1U) /* Enable CF Program/Erase */ +#define MF3_FENTRYR_PE_DF (1U << 7U) /* Enable DF Program/Erase */ + +#define MF3_FCR (MF3_BASE + 0x114U) /* Command Register */ +#define MF3_FCR_DRC (1U << 4U) /* Data Read Complete */ +#define MF3_FCR_STOP (1U << 6U) /* Forced Processing Stop */ +#define MF3_FCR_OPST (1U << 7U) /* Processing Start */ + +// Seems to duplicate FSTATR2 ? +#define MF3_FSTATR0 (MF3_BASE + 0x128U) /* Flash Status 0 (RA4) */ +#define MF3_FSTATR0_ERERR0 (1U << 0U) /* Erase Error */ +#define MF3_FSTATR0_PRGERR0 (1U << 1U) /* Program Error */ +#define MF3_FSTATR0_PRGERR01 (1U << 2U) /* Extra Area Program Error */ +#define MF3_FSTATR0_BCERR0 (1U << 3U) /* Blank Check Error */ +#define MF3_FSTATR0_ILGLERR (1U << 4U) /* Illegal Command Error */ +#define MF3_FSTATR0_EILGLERR (1U << 5U) /* Extra Area Illegal Command Error */ + +#define MF3_FSTATR1 (MF3_BASE + 0x12cU) /* Flash Status 1 */ +#define MF3_FSTATR1_DRRDY (1U << 1U) /* Data Read Ready */ +#define MF3_FSTATR1_FRDY (1U << 6U) /* Flash Ready */ +#define MF3_FSTATR1_EXRDY (1U << 7U) /* Extra Area Ready */ + +#define MF3_FSTATR2 (MF3_BASE + 0x1f0U) /* Flash Status 2 */ +#define MF3_FSTATR2_ERRERR (1U << 0U) /* Erase Error */ +#define MF3_FSTATR2_PRGERR (1U << 1U) /* Program Error */ +#define MF3_FSTATR2_PRGERR01 (1U << 2U) /* Extra Area Program Error */ +#define MF3_FSTATR2_BCERR (1U << 3U) /* Blank Check Error */ +#define MF3_FSTATR2_ILGLERR (1U << 4U) /* Illegal Command Error */ +#define MF3_FSTATR2_EILGLERR (1U << 5U) /* Extra Area Illegal Command Error */ + +#define MF3_FSTATR01 (MF3_BASE + 0x13cU) /* Flash Status 01 (RA4) */ +#define MF3_FSTATR01_ERERR1 (1U << 0U) /* Erase Error */ +#define MF3_FSTATR01_PRGERR1 (1U << 1U) /* Program Error */ +#define MF3_FSTATR01_BCERR1 (1U << 3U) /* Blank Check Error */ + +#define MF3_FPR (MF3_BASE + 0x180U) /* Flash Mode Protection */ +#define MF3_FPR_KEY 0xa5U + +/* And here is where RA4 and RA2 implementations diverge. FMS2 is specified as + * read/write 0 for RA2, and (011) is specified as Setting Prohibited. TODO: + * Verify this... + * + * FMS2 FMS1 FMS0 | Mode + * ------------------------------------- + * 0 0 0 | Read only + * 0 1 0 | Data flash P/E + * (1) 0 1 | Code flash P/E + * 0 1 1 | Discharge Mode 1 + * 1 1 1 | Discharge Mode 2 + * + * Taken from R01AN5367EU0120, Flash P/E Mode Control Register, §1.2.5, pg 12 + * and R01UH0852EJ0170, Flash P/E Mode Control Register, §35.3.6, pg 921 */ +#define MF3_FPMCR (MF3_BASE + 0x100U) /* Flash P/E Mode Control */ +#define MF3_FPMCR_FMS0 (1U << 1U) /* Operating Mode Select 0 */ +#define MF3_FPMCR_RPDIS (1U << 3U) /* Code Flash P/E Disable */ +#define MF3_FPMCR_FMS1 (1U << 4U) /* Operating Mode Select 1 */ +#define MF3_FPMCR_FMS2 (1U << 7U) /* Operating Mode Select 2 */ + +#define MF3_FSARL (MF3_BASE + 0x108U) /* Start Addr Low */ +#define MF3_FSARH (MF3_BASE + 0x110U) /* Start Addr High */ +#define MF3_FEARL (MF3_BASE + 0x118U) /* End Addr Low */ +#define MF3_FEARH (MF3_BASE + 0x120U) /* End Addr High */ + +#define MF3_FWBL0 (MF3_BASE + 0x130U) /* Write Buffer 0 Low */ +#define MF3_FWBH0 (MF3_BASE + 0x138U) /* Write Buffer 0 High */ +#define MF3_FWBL1 (MF3_BASE + 0x140U) /* Write Buffer 1 Low (RA4) */ +#define MF3_FWBH1 (MF3_BASE + 0x144U) /* Write Buffer 1 High (RA4) */ +#define MF3_FRBL0 (MF3_BASE + 0x188U) /* Write Buffer 0 Low */ +#define MF3_FRBH0 (MF3_BASE + 0x190U) /* Write Buffer 0 High */ +#define MF3_FRBL1 (MF3_BASE + 0x148U) /* Write Buffer 1 Low (RA4) */ +#define MF3_FRBH1 (MF3_BASE + 0x14cU) /* Write Buffer 1 High (RA4) */ + +/* RA4M1 has a flash cache, which needs to be disabled before writing */ +//TODO + /* RV40 Flash */ /* * RV40F Flash Memory Specifications @@ -383,9 +479,9 @@ static void renesas_add_flash(target_s *const target, const target_addr_t addr, case PNR_SERIES_RA6M2: case PNR_SERIES_RA6M3: case PNR_SERIES_RA6M4: + case PNR_SERIES_RA6M5: case PNR_SERIES_RA6E1: case PNR_SERIES_RA6E2: - case PNR_SERIES_RA6M5: case PNR_SERIES_RA6T1: case PNR_SERIES_RA6T2: target->enter_flash_mode = renesas_enter_flash_mode; @@ -416,7 +512,7 @@ bool renesas_ra_probe(target_s *const target) */ if (!renesas_pnr_read(target, RENESAS_FIXED1_PNR, pnr)) return false; - break; + break; case RENESAS_PARTID_RA4M2: case RENESAS_PARTID_RA4M3: From 808056ebd7a4dc02a281c2c5b9b5b437e38fd64b Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:33:20 -0700 Subject: [PATCH 03/17] renesas_ra: Add PNR enums for newer Renesas parts --- src/target/renesas_ra.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index ee2c34da4c2..bf2b82bf054 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -73,16 +73,30 @@ #define PNR_SERIES(pnr3, pnr4, pnr5, pnr6) (((pnr3) << 24U) | ((pnr4) << 16U) | ((pnr5) << 8U) | (pnr6)) typedef enum { + // RA0 + PNR_SERIES_RA0L1 = PNR_SERIES('A', '0', 'L', '1'), + PNR_SERIES_RA0E1 = PNR_SERIES('A', '0', 'E', '1'), + PNR_SERIES_RA0E2 = PNR_SERIES('A', '0', 'E', '2'), + // RA2 PNR_SERIES_RA2L1 = PNR_SERIES('A', '2', 'L', '1'), + PNR_SERIES_RA2L2 = PNR_SERIES('A', '2', 'L', '2'), PNR_SERIES_RA2E1 = PNR_SERIES('A', '2', 'E', '1'), PNR_SERIES_RA2E2 = PNR_SERIES('A', '2', 'E', '2'), + PNR_SERIES_RA2E3 = PNR_SERIES('A', '2', 'E', '3'), PNR_SERIES_RA2A1 = PNR_SERIES('A', '2', 'A', '1'), + PNR_SERIES_RA2A2 = PNR_SERIES('A', '2', 'A', '2'), + PNR_SERIES_RA2T1 = PNR_SERIES('A', '2', 'T', '1'), + // RA4 PNR_SERIES_RA4M1 = PNR_SERIES('A', '4', 'M', '1'), PNR_SERIES_RA4M2 = PNR_SERIES('A', '4', 'M', '2'), PNR_SERIES_RA4M3 = PNR_SERIES('A', '4', 'M', '3'), PNR_SERIES_RA4E1 = PNR_SERIES('A', '4', 'E', '1'), PNR_SERIES_RA4E2 = PNR_SERIES('A', '4', 'E', '2'), PNR_SERIES_RA4W1 = PNR_SERIES('A', '4', 'W', '1'), + PNR_SERIES_RA4C1 = PNR_SERIES('A', '4', 'C', '1'), + PNR_SERIES_RA4T1 = PNR_SERIES('A', '4', 'T', '1'), + PNR_SERIES_RA4L1 = PNR_SERIES('A', '4', 'L', '1'), + // RA6 PNR_SERIES_RA6M1 = PNR_SERIES('A', '6', 'M', '1'), PNR_SERIES_RA6M2 = PNR_SERIES('A', '6', 'M', '2'), PNR_SERIES_RA6M3 = PNR_SERIES('A', '6', 'M', '3'), @@ -92,6 +106,17 @@ typedef enum { PNR_SERIES_RA6E2 = PNR_SERIES('A', '6', 'E', '2'), PNR_SERIES_RA6T1 = PNR_SERIES('A', '6', 'T', '1'), PNR_SERIES_RA6T2 = PNR_SERIES('A', '6', 'T', '2'), + PNR_SERIES_RA6T3 = PNR_SERIES('A', '6', 'T', '3'), + // RA8 + PNR_SERIES_RA8M1 = PNR_SERIES('A', '8', 'M', '1'), + PNR_SERIES_RA8M2 = PNR_SERIES('A', '8', 'M', '2'), + PNR_SERIES_RA8E1 = PNR_SERIES('A', '8', 'E', '1'), + PNR_SERIES_RA8E2 = PNR_SERIES('A', '8', 'E', '2'), + PNR_SERIES_RA8T1 = PNR_SERIES('A', '8', 'T', '1'), + PNR_SERIES_RA8T2 = PNR_SERIES('A', '8', 'T', '2'), + PNR_SERIES_RA8D1 = PNR_SERIES('A', '8', 'D', '1'), + PNR_SERIES_RA8D2 = PNR_SERIES('A', '8', 'D', '2'), + PNR_SERIES_RA8P1 = PNR_SERIES('A', '8', 'P', '1'), } renesas_pnr_series_e; /* Code flash memory size */ @@ -152,6 +177,8 @@ typedef enum { * newer series have a 'Flash Root Table' * older series have a fixed location in the flash memory * + * TODO: UPDATE + * * ra2l1 - Fixed location 1 * ra2e1 - Fixed location 1 * ra2e2 - Fixed location 1 @@ -439,7 +466,7 @@ static void renesas_add_flash(target_s *const target, const target_addr_t addr, /* * Renesas RA MCUs can have one of two kinds of flash memory, MF3/4 and RV40 - * Flash type by series: + * Flash type by series: (TODO: Update) * ra2l1 - MF4 * ra2e1 - MF4 * ra2e2 - MF4 @@ -590,6 +617,7 @@ bool renesas_ra_probe(target_s *const target) target->target_storage = priv; target->driver = (char *)priv->pnr; + // TODO: Update with more models switch (priv->series) { case PNR_SERIES_RA2L1: case PNR_SERIES_RA2A1: @@ -1013,6 +1041,7 @@ static bool renesas_uid(target_s *const target, const int argc, const char **con const renesas_priv_s *const priv = (renesas_priv_s *)target->target_storage; target_addr_t uid_addr; + //TODO: Update switch (priv->series) { case PNR_SERIES_RA2L1: case PNR_SERIES_RA2E1: From 96d150acb5613dcaa70e31f4ef28464ba1765d21 Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:46:16 -0700 Subject: [PATCH 04/17] fixup/renesas: Add RA4M1 ID code --- src/target/renesas_ra.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index bf2b82bf054..87474ea13a0 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -41,6 +41,7 @@ #define RENESAS_PARTID_RA2E1 0x0390U #define RENESAS_PARTID_RA2A1 0x01b0U +#define RENESAS_PARTID_RA4M1 0x0160U #define RENESAS_PARTID_RA4M2 0x0340U #define RENESAS_PARTID_RA4M3 0x0310U #define RENESAS_PARTID_RA6M2 0x0150U From fc563f78d3c201cb6480b97c477e3c2dafeae9bf Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Tue, 18 Nov 2025 15:15:46 -0700 Subject: [PATCH 05/17] renesas_ra: Start implementing MF3 Flash support --- src/target/renesas_ra.c | 122 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 9 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 87474ea13a0..f9f82444473 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -74,11 +74,11 @@ #define PNR_SERIES(pnr3, pnr4, pnr5, pnr6) (((pnr3) << 24U) | ((pnr4) << 16U) | ((pnr5) << 8U) | (pnr6)) typedef enum { - // RA0 + // RA0 PNR_SERIES_RA0L1 = PNR_SERIES('A', '0', 'L', '1'), PNR_SERIES_RA0E1 = PNR_SERIES('A', '0', 'E', '1'), PNR_SERIES_RA0E2 = PNR_SERIES('A', '0', 'E', '2'), - // RA2 + // RA2 PNR_SERIES_RA2L1 = PNR_SERIES('A', '2', 'L', '1'), PNR_SERIES_RA2L2 = PNR_SERIES('A', '2', 'L', '2'), PNR_SERIES_RA2E1 = PNR_SERIES('A', '2', 'E', '1'), @@ -87,7 +87,7 @@ typedef enum { PNR_SERIES_RA2A1 = PNR_SERIES('A', '2', 'A', '1'), PNR_SERIES_RA2A2 = PNR_SERIES('A', '2', 'A', '2'), PNR_SERIES_RA2T1 = PNR_SERIES('A', '2', 'T', '1'), - // RA4 + // RA4 PNR_SERIES_RA4M1 = PNR_SERIES('A', '4', 'M', '1'), PNR_SERIES_RA4M2 = PNR_SERIES('A', '4', 'M', '2'), PNR_SERIES_RA4M3 = PNR_SERIES('A', '4', 'M', '3'), @@ -97,7 +97,7 @@ typedef enum { PNR_SERIES_RA4C1 = PNR_SERIES('A', '4', 'C', '1'), PNR_SERIES_RA4T1 = PNR_SERIES('A', '4', 'T', '1'), PNR_SERIES_RA4L1 = PNR_SERIES('A', '4', 'L', '1'), - // RA6 + // RA6 PNR_SERIES_RA6M1 = PNR_SERIES('A', '6', 'M', '1'), PNR_SERIES_RA6M2 = PNR_SERIES('A', '6', 'M', '2'), PNR_SERIES_RA6M3 = PNR_SERIES('A', '6', 'M', '3'), @@ -108,7 +108,7 @@ typedef enum { PNR_SERIES_RA6T1 = PNR_SERIES('A', '6', 'T', '1'), PNR_SERIES_RA6T2 = PNR_SERIES('A', '6', 'T', '2'), PNR_SERIES_RA6T3 = PNR_SERIES('A', '6', 'T', '3'), - // RA8 + // RA8 PNR_SERIES_RA8M1 = PNR_SERIES('A', '8', 'M', '1'), PNR_SERIES_RA8M2 = PNR_SERIES('A', '8', 'M', '2'), PNR_SERIES_RA8E1 = PNR_SERIES('A', '8', 'E', '1'), @@ -244,7 +244,7 @@ typedef enum { * Ref: R01UH0852EJ0170, Flash Memory Overview, §35.1, pg 915 */ #define MF3_CF_BLOCK_SIZE (0x800U) -#define MF3_RA2A1_CF_BLOCK_SIZE (0x400U) +#define MF3_RA2A1_CF_BLOCK_SIZE (0x400U) // Contradicted by RA2A1 Ref Manual #define MF3_DF_BLOCK_SIZE (0x400U) #define MF3_CF_WRITE_SIZE (0x40U) #define MF3_RA2E1_CF_WRITE_SIZE (0x20U) @@ -426,6 +426,42 @@ static renesas_pnr_series_e renesas_series(const uint8_t *pnr); static uint32_t renesas_flash_size(const uint8_t *pnr); static bool renesas_enter_flash_mode(target_s *target); +static bool renesas_enter_mf3_flash_mode(target_s *target); + +static bool renesas_mf3_prepare(target_flash_s *flash); +static bool renesas_mf3_done(target_flash_s *flash); +static bool renesas_mf3_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); +static bool renesas_mf3_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); + +static void renesas_add_mf3_flash(target_s *const target, const target_addr_t addr, const size_t length) +{ + target_flash_s *flash = calloc(1, sizeof(*flash)); + if (!flash) { /* calloc failed: heap exhaustion */ + DEBUG_ERROR("calloc: failed in %s\n", __func__); + return; + } + + const bool code_flash = addr < RENESAS_CF_END; + + flash->start = addr; + flash->length = length; + flash->erased = 0xffU; + flash->erase = renesas_mf3_flash_erase; + flash->write = renesas_mf3_flash_write; + flash->prepare = renesas_mf3_prepare; + flash->done = renesas_mf3_done; + + if (code_flash) { + flash->blocksize = MF3_CF_BLOCK_SIZE; + //TODO Make this generic + flash->writesize = MF3_RA2E1_CF_WRITE_SIZE; + } else { + flash->blocksize = MF3_DF_BLOCK_SIZE; + flash->writesize = MF3_DF_WRITE_SIZE; + } + + target_add_flash(target, flash); +} static bool renesas_rv40_prepare(target_flash_s *flash); static bool renesas_rv40_done(target_flash_s *flash); @@ -496,7 +532,14 @@ static void renesas_add_flash(target_s *const target, const target_addr_t addr, case PNR_SERIES_RA2A1: case PNR_SERIES_RA4M1: case PNR_SERIES_RA4W1: - /* FIXME: implement MF3/4 flash */ + /* + * We need a new enter_flash_mode here because the MF3/4 parts don't + * seem to have the SYSC_FWEPROR register. Alternatively, we could + * duplicate the switch statement inside enter_flash_mode, but this + * feels slightly cleaner + */ + target->enter_flash_mode = renesas_enter_mf3_flash_mode; + renesas_add_mf3_flash(target, addr, length); return; case PNR_SERIES_RA4M2: @@ -618,7 +661,7 @@ bool renesas_ra_probe(target_s *const target) target->target_storage = priv; target->driver = (char *)priv->pnr; - // TODO: Update with more models + // TODO: Update with more models switch (priv->series) { case PNR_SERIES_RA2L1: case PNR_SERIES_RA2A1: @@ -1033,6 +1076,67 @@ static bool renesas_rv40_flash_write(target_flash_s *const flash, target_addr_t return !renesas_rv40_error_check(target, RV40_FSTATR_PRGERR | RV40_FSTATR_ILGLERR); } +static bool renesas_enter_mf3_flash_mode(target_s *const target) +{ + /* + * Make sure that we are in the Code Flash/Data Flash Read mode, as a reset + * starts us in the Data Flash Disabled mode (R01AN5367EU0120, Sequencer Modes, + * §1.5.1, pg 35) + */ + target_mem32_write8(target, MF3_DFLCTL, MF3_DFLCTL_DFLEN); + return true; +} + +static bool renesas_mf3_pe_mode(target_s *const target, const pe_mode_e pe_mode) +{ + /* See "Switching to Code Flash P/E Mode": §35.13.3.2 of the RA2E1 manual R01UH0852EJ0170. */ + /* Set PE/READ mode. Note that this is very similar to the RV40 mode control, + * just with a different target register address. This probably ought to be + * deduplicated, but getting it working is more important first + */ + uint16_t fentryr = 0; + uint8_t fpmcr = 0; + switch (pe_mode) { + case PE_MODE_CF: + fentryr |= FENTRYR_PE_CF; + fpmcr |= MF3_FPMCR_FMS0; // & ~(MF3_FPMCR_FMS1 | MF3_FPMCR_RPDIS); + break; + case PE_MODE_DF: + fentryr |= FENTRYR_PE_DF; + fpmcr |= MF3_FPMCR_FMS1; // & ~(MF3_FPMCR_FMS0 | MF3_FPMCR_RPDIS); + break; + case PE_MODE_READ: + fpmcr |= MF3_FPMCR_RPDIS; // & ~(MF3_FPMCR_FMS0 | MF3_FPMCR_FMS1); + break; + default: + break; + } + target_mem32_write16(target, MF3_FENTRYR, FENTRYR_KEY | fentryr); + + /* + * Perform a series of writes to unlock the mode control register and set it + * to the appropriate state. Right now, this primarily focuses on the RA2 + * implementation (i.e. ignoring FMS2) as that is what I have to test on + * currently. + */ + target_mem32_write8(target, MF3_FPR, MF3_FPR_KEY); + target_mem32_write8(target, MF3_FPMCR, fpmcr); + target_mem32_write8(target, MF3_FPMCR, ~fpmcr); + target_mem32_write8(target, MF3_FPMCR, fpmcr); + + platform_timeout_s timeout; + platform_timeout_set(&timeout, 10); + + /* Wait for the operation to complete or timeout, Read until FENTRYR and FRDY is set */ + while (target_mem32_read16(target, MF3_FENTRYR) != fentryr || + !(target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { + if (target_check_error(target) || platform_timeout_is_expired(&timeout)) + return false; + } + + return true; +} + /* Reads the 16-byte unique id */ static bool renesas_uid(target_s *const target, const int argc, const char **const argv) { @@ -1042,7 +1146,7 @@ static bool renesas_uid(target_s *const target, const int argc, const char **con const renesas_priv_s *const priv = (renesas_priv_s *)target->target_storage; target_addr_t uid_addr; - //TODO: Update + //TODO: Update switch (priv->series) { case PNR_SERIES_RA2L1: case PNR_SERIES_RA2E1: From 1c5c57f513e83b601895585c67e8c0cf30df5269 Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Tue, 18 Nov 2025 15:59:11 -0700 Subject: [PATCH 06/17] renesas_ra: Further MF3/4 flash implementation Currently missing only write and erase. And testing. That's important. --- src/target/renesas_ra.c | 79 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index f9f82444473..4146a75ef27 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -246,8 +246,8 @@ typedef enum { #define MF3_CF_BLOCK_SIZE (0x800U) #define MF3_RA2A1_CF_BLOCK_SIZE (0x400U) // Contradicted by RA2A1 Ref Manual #define MF3_DF_BLOCK_SIZE (0x400U) -#define MF3_CF_WRITE_SIZE (0x40U) -#define MF3_RA2E1_CF_WRITE_SIZE (0x20U) +#define MF3_CF_WRITE_SIZE (0x8U) +#define MF3_RA2E1_CF_WRITE_SIZE (0x4U) #define MF3_DF_WRITE_SIZE (0x1U) /* MF3/4 Flash commands*/ @@ -265,7 +265,7 @@ typedef enum { #define MF3_DFLCTL (MF3_BASE + 0x090U) /* Data Flash Control */ #define MF3_DFLCTL_DFLEN (1U) /* Data Flash Access Enable */ -#define MF3_FENTRYR (MF3_BASE + 0x3fb2U) /* Flash P/E Mode Entry */ +#define MF3_FENTRYR (MF3_BASE + 0x3fb0U) /* Flash P/E Mode Entry */ #define MF3_FENTRYR_KEY_OFFSET 8U #define MF3_FENTRYR_KEY (0xaaU << MF3_FENTRYR_KEY_OFFSET) #define MF3_FENTRYR_PE_CF (1U) /* Enable CF Program/Erase */ @@ -291,7 +291,7 @@ typedef enum { #define MF3_FSTATR1_EXRDY (1U << 7U) /* Extra Area Ready */ #define MF3_FSTATR2 (MF3_BASE + 0x1f0U) /* Flash Status 2 */ -#define MF3_FSTATR2_ERRERR (1U << 0U) /* Erase Error */ +#define MF3_FSTATR2_ERERR (1U << 0U) /* Erase Error */ #define MF3_FSTATR2_PRGERR (1U << 1U) /* Program Error */ #define MF3_FSTATR2_PRGERR01 (1U << 2U) /* Extra Area Program Error */ #define MF3_FSTATR2_BCERR (1U << 3U) /* Blank Check Error */ @@ -306,6 +306,9 @@ typedef enum { #define MF3_FPR (MF3_BASE + 0x180U) /* Flash Mode Protection */ #define MF3_FPR_KEY 0xa5U +#define MF3_FRESETR (MF3_BASE + 0x124U) /* Flash Reset */ +#define MF3_FRESETR_RESET (1U << 0U) /* Trigger software reset of flash */ + /* And here is where RA4 and RA2 implementations diverge. FMS2 is specified as * read/write 0 for RA2, and (011) is specified as Setting Prohibited. TODO: * Verify this... @@ -335,10 +338,10 @@ typedef enum { #define MF3_FWBH0 (MF3_BASE + 0x138U) /* Write Buffer 0 High */ #define MF3_FWBL1 (MF3_BASE + 0x140U) /* Write Buffer 1 Low (RA4) */ #define MF3_FWBH1 (MF3_BASE + 0x144U) /* Write Buffer 1 High (RA4) */ -#define MF3_FRBL0 (MF3_BASE + 0x188U) /* Write Buffer 0 Low */ -#define MF3_FRBH0 (MF3_BASE + 0x190U) /* Write Buffer 0 High */ -#define MF3_FRBL1 (MF3_BASE + 0x148U) /* Write Buffer 1 Low (RA4) */ -#define MF3_FRBH1 (MF3_BASE + 0x14cU) /* Write Buffer 1 High (RA4) */ +#define MF3_FRBL0 (MF3_BASE + 0x188U) /* Read Buffer 0 Low */ +#define MF3_FRBH0 (MF3_BASE + 0x190U) /* Read Buffer 0 High */ +#define MF3_FRBL1 (MF3_BASE + 0x148U) /* Read Buffer 1 Low (RA4) */ +#define MF3_FRBH1 (MF3_BASE + 0x14cU) /* Read Buffer 1 High (RA4) */ /* RA4M1 has a flash cache, which needs to be disabled before writing */ //TODO @@ -1118,6 +1121,9 @@ static bool renesas_mf3_pe_mode(target_s *const target, const pe_mode_e pe_mode) * to the appropriate state. Right now, this primarily focuses on the RA2 * implementation (i.e. ignoring FMS2) as that is what I have to test on * currently. + * + * Might also need a 5 us delay here (unlikely given the speed at which this + * will be occurring is limited by the debug link) when changing to data flash p/e mode. */ target_mem32_write8(target, MF3_FPR, MF3_FPR_KEY); target_mem32_write8(target, MF3_FPMCR, fpmcr); @@ -1137,6 +1143,63 @@ static bool renesas_mf3_pe_mode(target_s *const target, const pe_mode_e pe_mode) return true; } +static bool renesas_mf3_error_check(target_s *const target, const uint16_t error_bits) +{ + // TODO: update with RA4 consideration + const uint8_t fstatr2 = target_mem32_read16(target, MF3_FSTATR2); + + /* Check if status indicates a programming error */ + if (fstatr2 & error_bits) { + /* Stop the flash */ + target_mem32_write8(target, MF3_FCR, MF3_FCR_STOP); + + platform_timeout_s 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_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { + if (target_check_error(target) || platform_timeout_is_expired(&timeout)) + return true; + } + + /* Reset the flash controller */ + target_mem32_write8(target, MF3_FRESETR, MF3_FRESETR_RESET); + target_mem32_write8(target, MF3_FRESETR, 0); + } + + return false; +} + +static bool renesas_mf3_prepare(target_flash_s *const flash) +{ + target_s *const target = flash->t; + + if (!(target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY) || + target_mem32_read16(target, MF3_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"); + + return false; + } + + /* Code flash or data flash operation */ + const bool code_flash = flash->start < RENESAS_CF_END; + + /* Transition to PE mode */ + const pe_mode_e pe_mode = code_flash ? PE_MODE_CF : PE_MODE_DF; + + return renesas_mf3_pe_mode(target, pe_mode) && !renesas_mf3_error_check(target, MF3_FSTATR2_ILGLERR); +} + +static bool renesas_mf3_done(target_flash_s *const flash) +{ + target_s *const target = flash->t; + + /* Return to read mode */ + return renesas_mf3_pe_mode(target, PE_MODE_READ); +} + /* Reads the 16-byte unique id */ static bool renesas_uid(target_s *const target, const int argc, const char **const argv) { From 567149a7e5929900589e4fc354ecc970d102d7d1 Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Tue, 18 Nov 2025 17:12:12 -0700 Subject: [PATCH 07/17] renesas_ra: Add MF3 flash write implementation --- src/target/renesas_ra.c | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 4146a75ef27..3a6dbab9c4a 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -1200,6 +1200,67 @@ static bool renesas_mf3_done(target_flash_s *const flash) return renesas_mf3_pe_mode(target, PE_MODE_READ); } +static bool renesas_mf3_flash_write(target_flash_s *const flash, target_addr_t dest, const void *src, size_t len) +{ + target_s *const target = flash->t; + + /* code flash or data flash operation */ + const bool code_flash = dest < RENESAS_CF_END; + + /* write size for code flash / data flash FIXME: RA2E1 vs others */ + const uint8_t write_size = code_flash ? MF3_RA2E1_CF_WRITE_SIZE : MF3_DF_WRITE_SIZE; + + /* set start address */ + target_mem32_write16(target, MF3_FSARL, (const uint16_t)(dest & 0xffffU)); + target_mem32_write16(target, MF3_FSARH, (const uint16_t)((dest >> 16) & 0xffffU)); + + while (len) { + /* set the data to be written (Adjust for RA4!) */ + if (code_flash) { + target_mem32_write16(target, MF3_FWBL0, *(const uint16_t *)src); + target_mem32_write16(target, MF3_FWBH0, *((const uint16_t *)src + 1U)); + } else { + target_mem32_write16(target, MF3_FWBL0, *(const uint8_t *)src); + } + + src = (const uint8_t *)src + write_size; + + /* decrement length remaining */ + len -= write_size; + + /* trigger write command */ + target_mem32_write8(target, MF3_FCR, MF3_FCR_OPST | MF3_CMD_PROGRAM); + + platform_timeout_s 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_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { + if (target_check_error(target) || platform_timeout_is_expired(&timeout)) + return false; + } + + /* + * Clear the command register (Figure 35.21, Flowchart for consecutive + * programming of the code flash, pg 953, R01UH0852EJ0170) and wait + * until ready again + */ + target_mem32_write8(target, MF3_FCR, MF3_CMD_PROGRAM); + target_mem32_write8(target, MF3_FCR, 0); + + platform_timeout_set(&timeout, 10); + + /* Read FRDY bit until it has been set to 1 indicating that the current operation is complete.*/ + while (!(target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { + if (target_check_error(target) || platform_timeout_is_expired(&timeout)) + return false; + } + } + + return !renesas_mf3_error_check(target, MF3_FSTATR2_PRGERR | MF3_FSTATR2_ILGLERR); +} + /* Reads the 16-byte unique id */ static bool renesas_uid(target_s *const target, const int argc, const char **const argv) { From 3b1fbbdf51fdc81f5bd56b1279a233a97cfc4133 Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:56:30 -0700 Subject: [PATCH 08/17] renesas_ra: Add in block erase --- src/target/renesas_ra.c | 71 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 3a6dbab9c4a..6e11206d0e8 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -1200,6 +1200,77 @@ static bool renesas_mf3_done(target_flash_s *const flash) return renesas_mf3_pe_mode(target, PE_MODE_READ); } +/* This could be improved by leveraging the built-in blank-checking... */ +static bool renesas_mf3_flash_erase(target_flash_s *const flash, target_addr_t addr, size_t len) +{ + target_s *const target = flash->t; + + /* Code flash or data flash operation */ + const bool code_flash = addr < RENESAS_CF_END; + + while (len) { + /* Set block start address*/ + target_mem32_write16(target, MF3_FSARL, (const uint16_t)(addr & 0xffffU)); + target_mem32_write16(target, MF3_FSARH, (const uint16_t)((addr >> 16) & 0xffffU)); + + /* Increment block address */ + uint16_t block_size; + if (code_flash) + block_size = MF3_CF_BLOCK_SIZE; + else + block_size = MF3_DF_BLOCK_SIZE; + + /* Point to the end of the block */ + addr += block_size - 1U; + len -= block_size; + + /* Set block end address*/ + target_mem32_write16(target, MF3_FEARL, (const uint16_t)(addr & 0xffffU)); + target_mem32_write16(target, MF3_FEARH, (const uint16_t)((addr >> 16) & 0xffffU)); + + /* Adjust to the start of the next block */ + addr += 1U; + + /* Send the Block Erase command */ + target_mem32_write8(target, MF3_FCR, MF3_FCR_OPST | MF3_CMD_BLOCK_ERASE); + + /* + * The reference manual quotes a max erase time of 355 ms for the 2KB block + * size; set a timeout a bit longer than that. + * See Table 39.53-55, Code flash characteristics, pg 1026, R01UH0852EJ0170 + */ + platform_timeout_s timeout; + platform_timeout_set(&timeout, 400); + + /* Read FRDY bit until it has been set to 1 indicating that the current operation is complete.*/ + while (!(target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { + if (target_check_error(target) || platform_timeout_is_expired(&timeout)) + return false; + } + + /* + * Clear the command register (Figure 35.23, Flowchart for Code Flash + * Block Erase Procedure, pg 955, R01UH0852EJ0170) and wait + * until ready again + */ + target_mem32_write8(target, MF3_FCR, MF3_CMD_BLOCK_ERASE); + target_mem32_write8(target, MF3_FCR, 0); + + platform_timeout_set(&timeout, 10); + + /* Read FRDY bit until it has been set to 1 indicating that the current operation is complete.*/ + while (!(target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { + if (target_check_error(target) || platform_timeout_is_expired(&timeout)) + return false; + } + + if (renesas_mf3_error_check(target, MF3_FSTATR2_ERERR | MF3_FSTATR2_ILGLERR)) + return false; + } + + return true; +} + static bool renesas_mf3_flash_write(target_flash_s *const flash, target_addr_t dest, const void *src, size_t len) { target_s *const target = flash->t; From 5f81890b430541dec2de3e3d8afabab61465c597 Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Mon, 24 Nov 2025 13:33:47 -0700 Subject: [PATCH 09/17] renesas_ra: Add license attribution --- src/target/renesas_ra.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 6e11206d0e8..f5bc93613a3 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -4,6 +4,7 @@ * Copyright (C) 2022-2023 1BitSquared * Written by Rafael Silva * Modified by Rachel Mant + * Modified by Sage Myers * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: From e6b4f836378867c934af4be1ee5e2b547ab1a960 Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Wed, 26 Nov 2025 11:25:01 -0700 Subject: [PATCH 10/17] renesas_ra: Cleanup defines --- src/target/renesas_ra.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index f5bc93613a3..0b5152e93ed 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -228,7 +228,7 @@ typedef enum { /* Flash Memory Control */ #define FENTRYR_KEY_OFFSET 8U #define FENTRYR_KEY (0xaaU << FENTRYR_KEY_OFFSET) -#define FENTRYR_PE_CF (1U) +#define FENTRYR_PE_CF 1U #define FENTRYR_PE_DF (1U << 7U) /* Renesas RA MCUs can have one of two kinds of flash memory, MF3/4 and RV40 */ @@ -244,12 +244,12 @@ typedef enum { * RA2E1: Program: Code area: 32 bits, Data area: 8 bits * Ref: R01UH0852EJ0170, Flash Memory Overview, §35.1, pg 915 */ -#define MF3_CF_BLOCK_SIZE (0x800U) -#define MF3_RA2A1_CF_BLOCK_SIZE (0x400U) // Contradicted by RA2A1 Ref Manual -#define MF3_DF_BLOCK_SIZE (0x400U) -#define MF3_CF_WRITE_SIZE (0x8U) -#define MF3_RA2E1_CF_WRITE_SIZE (0x4U) -#define MF3_DF_WRITE_SIZE (0x1U) +#define MF3_CF_BLOCK_SIZE 0x800U +#define MF3_RA2A1_CF_BLOCK_SIZE 0x400U // Contradicted by RA2A1 Ref Manual +#define MF3_DF_BLOCK_SIZE 0x400U +#define MF3_CF_WRITE_SIZE 0x8U +#define MF3_RA2E1_CF_WRITE_SIZE 0x4U +#define MF3_DF_WRITE_SIZE 0x1U /* MF3/4 Flash commands*/ /* Taken from R01AN5367EU0120, (MF3) Software Commands, §1.5.2, pg 35 @@ -354,12 +354,12 @@ typedef enum { * Program/Erase unit Program: Code area: 128 Bytes, Data area: 4/8/16 Bytes * Erase: 1 block */ -#define RV40_CF_REGION0_SIZE (0x10000U) -#define RV40_CF_REGION0_BLOCK_SIZE (0x2000U) -#define RV40_CF_REGION1_BLOCK_SIZE (0x8000U) -#define RV40_DF_BLOCK_SIZE (0x40U) -#define RV40_CF_WRITE_SIZE (0x80U) -#define RV40_DF_WRITE_SIZE (0x4U) +#define RV40_CF_REGION0_SIZE 0x10000U +#define RV40_CF_REGION0_BLOCK_SIZE 0x2000U +#define RV40_CF_REGION1_BLOCK_SIZE 0x8000U +#define RV40_DF_BLOCK_SIZE 0x40U +#define RV40_CF_WRITE_SIZE 0x80U +#define RV40_DF_WRITE_SIZE 0x4U /* RV40 Flash Commands */ #define RV40_CMD UINT32_C(0x407e0000) From 00ccc9d566e1309cd7767598b56b60b8321526ee Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Wed, 26 Nov 2025 11:34:14 -0700 Subject: [PATCH 11/17] fixup! renesas_ra: Adjust error messages/comments for prepare/mode --- src/target/renesas_ra.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 0b5152e93ed..2e32a3b32ec 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -1123,8 +1123,12 @@ static bool renesas_mf3_pe_mode(target_s *const target, const pe_mode_e pe_mode) * implementation (i.e. ignoring FMS2) as that is what I have to test on * currently. * - * Might also need a 5 us delay here (unlikely given the speed at which this - * will be occurring is limited by the debug link) when changing to data flash p/e mode. + * Might also need a 2-15us delay here (t_DIS or t_MS) due to state change times + * depending on which states you are changing between (unlikely given the speed + * at which this will be occurring is limited by the debug link). See the Code + * flash characteristics table in the Electrical Characteristics section of the + * appropriate User Manual (For RA2E1, it would be table 39.53 in section + * 39.10.1, page 1026) */ target_mem32_write8(target, MF3_FPR, MF3_FPR_KEY); target_mem32_write8(target, MF3_FPMCR, fpmcr); @@ -1178,8 +1182,8 @@ static bool renesas_mf3_prepare(target_flash_s *const flash) if (!(target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY) || target_mem32_read16(target, MF3_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"); + DEBUG_ERROR("Flash is not ready, may be hanging mid unfinished command due to something going wrong, " + "please power on reset the device\n"); return false; } From 0c3a93a6b72b14ee4a7cffd173902744b4a4b83c Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Wed, 26 Nov 2025 11:44:53 -0700 Subject: [PATCH 12/17] fixup! renesas_ra: Cleanup flash erase to use a for loop --- src/target/renesas_ra.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 2e32a3b32ec..a11ee7941a2 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -1210,31 +1210,24 @@ static bool renesas_mf3_flash_erase(target_flash_s *const flash, target_addr_t a { target_s *const target = flash->t; - /* Code flash or data flash operation */ - const bool code_flash = addr < RENESAS_CF_END; - - while (len) { - /* Set block start address*/ - target_mem32_write16(target, MF3_FSARL, (const uint16_t)(addr & 0xffffU)); - target_mem32_write16(target, MF3_FSARH, (const uint16_t)((addr >> 16) & 0xffffU)); - - /* Increment block address */ - uint16_t block_size; - if (code_flash) - block_size = MF3_CF_BLOCK_SIZE; - else - block_size = MF3_DF_BLOCK_SIZE; + /* Choose the correct block size based on the address to write to */ + uint16_t block_size; + if (addr < RENESAS_CF_END) + block_size = MF3_CF_BLOCK_SIZE; + else + block_size = MF3_DF_BLOCK_SIZE; - /* Point to the end of the block */ - addr += block_size - 1U; - len -= block_size; + for (uint32_t i = 0; i < len; i += block_size) { + uint32_t block_addr = addr + i; - /* Set block end address*/ - target_mem32_write16(target, MF3_FEARL, (const uint16_t)(addr & 0xffffU)); - target_mem32_write16(target, MF3_FEARH, (const uint16_t)((addr >> 16) & 0xffffU)); + /* Set block start address */ + target_mem32_write16(target, MF3_FSARL, (uint16_t)(block_addr & 0xffffU)); + target_mem32_write16(target, MF3_FSARH, (uint16_t)((block_addr >> 16) & 0xffffU)); - /* Adjust to the start of the next block */ - addr += 1U; + /* Set block end address */ + block_addr += block_size - 1; + target_mem32_write16(target, MF3_FEARL, (uint16_t)(block_addr & 0xffffU)); + target_mem32_write16(target, MF3_FEARH, (uint16_t)((block_addr >> 16) & 0xffffU)); /* Send the Block Erase command */ target_mem32_write8(target, MF3_FCR, MF3_FCR_OPST | MF3_CMD_BLOCK_ERASE); @@ -1255,8 +1248,7 @@ static bool renesas_mf3_flash_erase(target_flash_s *const flash, target_addr_t a /* * Clear the command register (Figure 35.23, Flowchart for Code Flash - * Block Erase Procedure, pg 955, R01UH0852EJ0170) and wait - * until ready again + * Block Erase Procedure, pg 955, R01UH0852EJ0170) and wait until ready again */ target_mem32_write8(target, MF3_FCR, MF3_CMD_BLOCK_ERASE); target_mem32_write8(target, MF3_FCR, 0); From 1632db85a0baf96835e476730c81a05ca22c8dad Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Wed, 26 Nov 2025 13:32:31 -0700 Subject: [PATCH 13/17] fixup! renesas_ra: Confirm flash writes/erases --- src/target/renesas_ra.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index a11ee7941a2..3c843272e32 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -1138,9 +1138,8 @@ static bool renesas_mf3_pe_mode(target_s *const target, const pe_mode_e pe_mode) platform_timeout_s timeout; platform_timeout_set(&timeout, 10); - /* Wait for the operation to complete or timeout, Read until FENTRYR and FRDY is set */ - while (target_mem32_read16(target, MF3_FENTRYR) != fentryr || - !(target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { + /* Wait for the operation to complete or timeout, Read until FENTRYR is set */ + while (target_mem32_read16(target, MF3_FENTRYR) != fentryr) { if (target_check_error(target) || platform_timeout_is_expired(&timeout)) return false; } @@ -1155,6 +1154,7 @@ static bool renesas_mf3_error_check(target_s *const target, const uint16_t error /* Check if status indicates a programming error */ if (fstatr2 & error_bits) { + DEBUG_WARN("Flash encountered an error; FSTATR2: 0x%x\n", fstatr2); /* Stop the flash */ target_mem32_write8(target, MF3_FCR, MF3_FCR_STOP); @@ -1171,6 +1171,8 @@ static bool renesas_mf3_error_check(target_s *const target, const uint16_t error /* Reset the flash controller */ target_mem32_write8(target, MF3_FRESETR, MF3_FRESETR_RESET); target_mem32_write8(target, MF3_FRESETR, 0); + + return true; } return false; @@ -1180,13 +1182,11 @@ static bool renesas_mf3_prepare(target_flash_s *const flash) { target_s *const target = flash->t; - if (!(target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY) || - target_mem32_read16(target, MF3_FENTRYR) != 0) { - DEBUG_ERROR("Flash is not ready, may be hanging mid unfinished command due to something going wrong, " - "please power on reset the device\n"); - - return false; - } + /* This doesn't check to see if the FRDY bit is set, unlike the RV40 flash, + * as FRDY is only set after a command executes and is zero on reset. Thus, + * if you've attached after a reset and haven't done anything, it will be + * zero and erroneously trigger the check. + */ /* Code flash or data flash operation */ const bool code_flash = flash->start < RENESAS_CF_END; @@ -1255,8 +1255,8 @@ static bool renesas_mf3_flash_erase(target_flash_s *const flash, target_addr_t a platform_timeout_set(&timeout, 10); - /* Read FRDY bit until it has been set to 1 indicating that the current operation is complete.*/ - while (!(target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { + /* Read FRDY bit until it has been set to 0. */ + while ((target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { if (target_check_error(target) || platform_timeout_is_expired(&timeout)) return false; } @@ -1319,14 +1319,17 @@ static bool renesas_mf3_flash_write(target_flash_s *const flash, target_addr_t d platform_timeout_set(&timeout, 10); - /* Read FRDY bit until it has been set to 1 indicating that the current operation is complete.*/ - while (!(target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { + /* Read FRDY bit until it has been set to 0 */ + while ((target_mem32_read8(target, MF3_FSTATR1) & MF3_FSTATR1_FRDY)) { if (target_check_error(target) || platform_timeout_is_expired(&timeout)) return false; } + + if (renesas_mf3_error_check(target, MF3_FSTATR2_PRGERR | MF3_FSTATR2_ILGLERR)) + return false; } - return !renesas_mf3_error_check(target, MF3_FSTATR2_PRGERR | MF3_FSTATR2_ILGLERR); + return true; } /* Reads the 16-byte unique id */ From 6f4861c3377df1a455c246e63d97354c4329ef6a Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Wed, 26 Nov 2025 13:47:03 -0700 Subject: [PATCH 14/17] fixup! renesas_ra: Redo flash write with a for loop --- src/target/renesas_ra.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 3c843272e32..8dcf5591c52 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -1279,24 +1279,20 @@ static bool renesas_mf3_flash_write(target_flash_s *const flash, target_addr_t d const uint8_t write_size = code_flash ? MF3_RA2E1_CF_WRITE_SIZE : MF3_DF_WRITE_SIZE; /* set start address */ - target_mem32_write16(target, MF3_FSARL, (const uint16_t)(dest & 0xffffU)); - target_mem32_write16(target, MF3_FSARH, (const uint16_t)((dest >> 16) & 0xffffU)); + target_mem32_write16(target, MF3_FSARL, (uint16_t)(dest & 0xffffU)); + target_mem32_write16(target, MF3_FSARH, (uint16_t)((dest >> 16) & 0xffffU)); - while (len) { - /* set the data to be written (Adjust for RA4!) */ + for (uint32_t off = 0; off < len; off += write_size) { + /* Set up the data to be written (Adjust for RA4!) */ if (code_flash) { - target_mem32_write16(target, MF3_FWBL0, *(const uint16_t *)src); - target_mem32_write16(target, MF3_FWBH0, *((const uint16_t *)src + 1U)); + const uint16_t *buf = (const uint16_t *)src + off; + target_mem32_write16(target, MF3_FWBL0, buf[0]); + target_mem32_write16(target, MF3_FWBH0, buf[1]); } else { - target_mem32_write16(target, MF3_FWBL0, *(const uint8_t *)src); + target_mem32_write16(target, MF3_FWBL0, *((const uint8_t *)src + off)); } - src = (const uint8_t *)src + write_size; - - /* decrement length remaining */ - len -= write_size; - - /* trigger write command */ + /* Dispatch the write command */ target_mem32_write8(target, MF3_FCR, MF3_FCR_OPST | MF3_CMD_PROGRAM); platform_timeout_s timeout; From 22d6619ff49e537cd30786fa4d10567dc1dbaaad Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Wed, 10 Dec 2025 13:34:47 -0700 Subject: [PATCH 15/17] renesas_ra: Added in flash/UID info for new families --- src/target/renesas_ra.c | 146 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 133 insertions(+), 13 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 8dcf5591c52..df8c8ef8ef6 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -67,7 +67,7 @@ * * Renesas Flash MCUs have an internal 16 byte read only register that stores * the part number, the code is stored ascii encoded, starting from the lowest memory address - * except for pnrs stored in 'FIXED_PNR1', where the code is stored in reverse order (but the last 3 bytes are still 0x20 aka ' ') + * except for pnrs stored in 'FIXED_PNR1/3/4', where the code is stored in reverse order (but the last 3 bytes are still 0x20 aka ' ') */ /* family + series + group no */ @@ -176,21 +176,29 @@ typedef enum { */ /* PNR/UID location by series - * newer series have a 'Flash Root Table' - * older series have a fixed location in the flash memory - * - * TODO: UPDATE + * Some series have a 'Flash Root Table' + * Other series have a fixed location in the flash memory * + * ra0l1 - Fixed location 3 + * ra0e1 - Fixed location 3 + * ra0e2 - Fixed location 3 * ra2l1 - Fixed location 1 + * ra2l2 - Fixed location 4 (?!) * ra2e1 - Fixed location 1 * ra2e2 - Fixed location 1 - * ra2a1 - Flash Root Table *undocumented - * ra4m1 - Flash Root Table *undocumented + * ra2e3 - Fixed location 1 + * ra2a1 - Flash Root Table + * ra2a2 - Fixed location 1 + * ra2t1 - Fixed location 1 + * ra4m1 - Flash Root Table * ra4m2 - Fixed location 2 *undocumented * ra4m3 - Fixed location 2 *undocumented * ra4e1 - Fixed location 2 * ra4e2 - Fixed location 2 * ra4w1 - Flash Root Table *undocumented + * ra4c1 - Fixed location 2 + * ra4t1 - Fixed location 2 + * ra4l1 - Fixed location 2 * ra6m1 - Flash Root Table * ra6m2 - Flash Root Table * ra6m3 - Flash Root Table @@ -200,6 +208,16 @@ typedef enum { * ra6e2 - Fixed location 2 * ra6t1 - Flash Root Table * ra6t2 - Fixed location 2 + * ra6t3 - Fixed location 2 + * ra8m1 - Fixed location 5 (!!) + * ra8m2 - Fixed location 6 (!!) + * ra8e1 - Fixed location 5 + * ra8e2 - Fixed location 5 + * ra8t1 - Fixed location 5 + * ra8t2 - Fixed location 6 + * ra8d1 - Fixed location 5 + * ra8d2 - Fixed location 6 + * ra8p1 - Fixed location 6 */ #define RENESAS_FIXED1_UID UINT32_C(0x01001c00) /* Unique ID Register */ #define RENESAS_FIXED1_PNR UINT32_C(0x01001c10) /* Part Numbering Register */ @@ -209,6 +227,33 @@ typedef enum { #define RENESAS_FIXED2_PNR UINT32_C(0x010080f0) /* Part Numbering Register */ #define RENESAS_FIXED2_MCUVER UINT32_C(0x010081b0) /* MCU Version Register */ +// R01UH1143EJ0110, Flash Register Descriptions, §29.3.24-26, pg 685 +#define RENESAS_FIXED3_UID UINT32_C(0x01011070) /* Unique ID Register */ +#define RENESAS_FIXED3_PNR UINT32_C(0x01011080) /* Part Numbering Register */ +#define RENESAS_FIXED3_MCUVER UINT32_C(0x01011090) /* MCU Version Register */ + +// R01UH1080EJ0110, Flash Register Descriptions, §38.3.27-29, pg 1226 +#define RENESAS_FIXED4_UID UINT32_C(0x01011110) /* Unique ID Register */ +#define RENESAS_FIXED4_PNR UINT32_C(0x01011120) /* Part Numbering Register */ +#define RENESAS_FIXED4_MCUVER UINT32_C(0x01011130) /* MCU Version Register */ + +// R01UH0994EJ0120, Flash Register Descriptions, §52.4.5-6, pg 2416 +// This one comes in secure/non-secure flavours, since there is TrustZone in play. +// It seems to be Fixed2 at a different offset. +#define RENESAS_FIXED5_UID UINT32_C(0x13008190) /* Unique ID Register */ +#define RENESAS_FIXED5_PNR UINT32_C(0x130080f0) /* Part Numbering Register */ +#define RENESAS_FIXED5_MCUVER UINT32_C(0x130081b0) /* MCU Version Register */ +#define RENESAS_FIXED5_SECURE_UID UINT32_C(0x03008190) /* Unique ID Register */ +#define RENESAS_FIXED5_SECURE_PNR UINT32_C(0x030080f0) /* Part Numbering Register */ +#define RENESAS_FIXED5_SECURE_MCUVER UINT32_C(0x030081b0) /* MCU Version Register */ + +// R01UH1066EJ0120, Flash Register Descriptions, §59.5.41-43, pg 3537 +// Despite the RA8M2 supporting and using TrustZone, these only have one +// address... +#define RENESAS_FIXED6_UID UINT32_C(0x02f07b00) /* Unique ID Register */ +#define RENESAS_FIXED6_PNR UINT32_C(0x02c1ec38) /* Part Numbering Register */ +#define RENESAS_FIXED6_MCUVER UINT32_C(0x02c1ec48) /* MCU Version Register */ + /* The FMIFRT is a read-only register that stores the Flash Root Table address */ #define RENESAS_FMIFRT UINT32_C(0x407fb19c) #define RENESAS_FMIFRT_UID(frt) ((frt) + 0x14U) /* UID Register offset from Flash Root Table */ @@ -240,9 +285,15 @@ typedef enum { * MF3/4 Flash Memory Specifications * Block Size: Code area: 2 KB (except RA2A1 is 1KB), Data area: 1 KB * Program/Erase unit Program: Code area: 64 bits, Data area: 8 bits - * Erase: 1 block - * RA2E1: Program: Code area: 32 bits, Data area: 8 bits - * Ref: R01UH0852EJ0170, Flash Memory Overview, §35.1, pg 915 + * Erase: 1 block + * RA0xx: Block size: Code area: 2 KB, Data area: 256B + * Program: Code area: 32 bits, Data area: 8 bits + * Erase: 1 block + * Ref: R01UH1143EJ0110, Flash Memory Overview, §29.1, pg 669 + * RA2xx*: Program: Code area: 32 bits, Data area: 8 bits + * Ref: R01UH0852EJ0170, Flash Memory Overview, §35.1, pg 915 + * + * *Other than RA2A1, evidently. It is listed as 64-bit CF programming units */ #define MF3_CF_BLOCK_SIZE 0x800U #define MF3_RA2A1_CF_BLOCK_SIZE 0x400U // Contradicted by RA2A1 Ref Manual @@ -352,7 +403,10 @@ typedef enum { * RV40F Flash Memory Specifications * Block Size: Code area: 8 KB/32KB Data area: 64 Bytes * Program/Erase unit Program: Code area: 128 Bytes, Data area: 4/8/16 Bytes - * Erase: 1 block + * Erase: 1 block + * RA4[CL]1: Block Size: Code area: 2 KB, Data area: 256 Bytes + * Program: Code area: 8 Bytes, Data area: 1 Byte + * Ref: R01UH1137EJ0110, Flash Memory Overview, §39.1, pg 1404 */ #define RV40_CF_REGION0_SIZE 0x10000U #define RV40_CF_REGION0_BLOCK_SIZE 0x2000U @@ -411,6 +465,21 @@ typedef enum { #define RV40_FCPSR (RV40_BASE + 0xe0U) #define RV40_FCPSR_ESUSPMD 1U +/* Renesas MRAM */ +/* + * Some newer chips eschew the traditional RV40 or MF3/4 flash solutions for a + * MRAM based solution (and include an OSPI flash in the device package). The + * MRAM interface appears to be loosely structured on the RV40 flash architecture, + * from a brief glance through the block diagrams + * + * Program buffer: 1/2/4/8 Bytes + * Code MRAM: 32 Bytes + * + * Chips containing: RA8M2, RA8T2, RA8D2, RA8P1 + */ + +//TODO: Implement MRAM + static bool renesas_uid(target_s *t, int argc, const char **argv); const command_s renesas_cmd_list[] = { @@ -506,18 +575,30 @@ static void renesas_add_flash(target_s *const target, const target_addr_t addr, renesas_priv_s *priv = (renesas_priv_s *)target->target_storage; /* - * Renesas RA MCUs can have one of two kinds of flash memory, MF3/4 and RV40 - * Flash type by series: (TODO: Update) + * Renesas RA MCUs can have one of two kinds of flash memory, MF3/4 and + * RV40, or MRAM code memory and an external OSPI flash. + * + * Flash type by series: + * ra0l1 - MF3/4 + * ra0e1 - MF3/4 + * ra0e2 - MF3/4 * ra2l1 - MF4 + * ra2l2 - MF3/4 * ra2e1 - MF4 * ra2e2 - MF4 + * ra2e3 - MF3/4 * ra2a1 - MF3 + * ra2a2 - MF3/4 + * ra2t1 - MF3/4 * ra4m1 - MF3 * ra4m2 - RV40 * ra4m3 - RV40 * ra4e1 - RV40 * ra4e2 - RV40 * ra4w1 - MF3 + * ra4c1 - RV40 + * ra4t1 - RV40 + * ra4l1 - RV40 * ra6m1 - RV40 * ra6m2 - RV40 * ra6m3 - RV40 @@ -527,13 +608,33 @@ static void renesas_add_flash(target_s *const target, const target_addr_t addr, * ra6e2 - RV40 * ra6t1 - RV40 * ra6t2 - RV40 + * ra6t3 - RV40 + * ra8m1 - RV40 + * ra8m2 - MRAM + OSPI Flash + * ra8e1 - RV40 + * ra8e2 - RV40 + * ra8t1 - RV40 + * ra8t2 - MRAM + OSPI Flash + * ra8d1 - RV40 + * ra8d2 - MRAM + OSPI Flash + * ra8p1 - MRAM + OSPI Flash + * + * This needs to be adjusted as the RA8 parts tend to be dual-bank flash or + * other fancier memory configurations */ switch (priv->series) { + case PNR_SERIES_RA0L1: + case PNR_SERIES_RA0E1: + case PNR_SERIES_RA0E2: case PNR_SERIES_RA2L1: + case PNR_SERIES_RA2L2: case PNR_SERIES_RA2E1: case PNR_SERIES_RA2E2: + case PNR_SERIES_RA2E3: case PNR_SERIES_RA2A1: + case PNR_SERIES_RA2A2: + case PNR_SERIES_RA2T1: case PNR_SERIES_RA4M1: case PNR_SERIES_RA4W1: /* @@ -550,6 +651,9 @@ static void renesas_add_flash(target_s *const target, const target_addr_t addr, case PNR_SERIES_RA4M3: case PNR_SERIES_RA4E1: case PNR_SERIES_RA4E2: + case PNR_SERIES_RA4T1: + case PNR_SERIES_RA4L1: + case PNR_SERIES_RA4C1: case PNR_SERIES_RA6M1: case PNR_SERIES_RA6M2: case PNR_SERIES_RA6M3: @@ -559,10 +663,24 @@ static void renesas_add_flash(target_s *const target, const target_addr_t addr, case PNR_SERIES_RA6E2: case PNR_SERIES_RA6T1: case PNR_SERIES_RA6T2: + case PNR_SERIES_RA6T3: + case PNR_SERIES_RA8M1: + case PNR_SERIES_RA8E1: + case PNR_SERIES_RA8E2: + case PNR_SERIES_RA8T1: + case PNR_SERIES_RA8D1: + /* TODO: Support the parts with dual-bank flash properly */ target->enter_flash_mode = renesas_enter_flash_mode; renesas_add_rv40_flash(target, addr, length); return; + case PNR_SERIES_RA8M2: + case PNR_SERIES_RA8T2: + case PNR_SERIES_RA8D2: + case PNR_SERIES_RA8P1: + /* FIXME: MRAM/OSPI flashing not implemented currently */ + return; + default: return; } @@ -628,6 +746,8 @@ bool renesas_ra_probe(target_s *const target) * * try the fixed address RENESAS_FIXED2_PNR first, as it should lead to less illegal/erroneous * memory accesses in case of failure, and is the most common case + * + * TODO: Update with the new known locations */ if (renesas_pnr_read(target, RENESAS_FIXED2_PNR, pnr)) { From 39d9f490c5494f3d4925aec28a89c4af9b75b861 Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Wed, 10 Dec 2025 13:37:28 -0700 Subject: [PATCH 16/17] fixup!renesas_ra: Remove comments wanting part_ids for known ids --- src/target/renesas_ra.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index df8c8ef8ef6..836f2bb2014 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -714,7 +714,6 @@ bool renesas_ra_probe(target_s *const target) * ra4e1 (part_id wanted) * ra4e2 (part_id wanted) * ra6m4 (part_id wanted) - * ra6m5 (part_id wanted) * ra6e1 (part_id wanted) * ra6e2 (part_id wanted) * ra6t2 (part_id wanted) @@ -724,9 +723,9 @@ bool renesas_ra_probe(target_s *const target) break; case RENESAS_PARTID_RA2A1: + case RENESAS_PARTID_RA4M1: case RENESAS_PARTID_RA6M2: /* mcus with Flash Root Table - * ra4m1 *undocumented (part_id wanted) * ra4w1 *undocumented (part_id wanted) * ra6m1 (part_id wanted) * ra6m3 (part_id wanted) From d9d91f80f8d2902bef8ba042ae3e2d79db003052 Mon Sep 17 00:00:00 2001 From: Sage Myers <10702176+desertsagebrush@users.noreply.github.com> Date: Fri, 12 Dec 2025 17:34:25 -0700 Subject: [PATCH 17/17] renesas_ra: Add new families to probe mechanism --- src/target/renesas_ra.c | 248 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 242 insertions(+), 6 deletions(-) diff --git a/src/target/renesas_ra.c b/src/target/renesas_ra.c index 836f2bb2014..01af255277e 100644 --- a/src/target/renesas_ra.c +++ b/src/target/renesas_ra.c @@ -34,6 +34,12 @@ /* Support for the Renesas RA family of microcontrollers (Arm Core) */ +/* + * This has the framework for support for the RA8 families, but due to changes + * in their memory map, it is *very* unlikely that this will work out of the box + * as it has not been tested against any RA8 families. + */ + #include "general.h" #include "target.h" #include "target_internal.h" @@ -62,7 +68,7 @@ * | | | | \_____________________ Group number * | | | \__________________________ Series name * | | \______________________________ Family (A: RA) - * | \__________________________________ Flash memory + * | \__________________________________ Memory type (F: Flash, K: MRAM, J: MRAM + SiP Flash) * \_______________________________________ Renesas microcontroller (always 'R7') * * Renesas Flash MCUs have an internal 16 byte read only register that stores @@ -109,6 +115,7 @@ typedef enum { PNR_SERIES_RA6T1 = PNR_SERIES('A', '6', 'T', '1'), PNR_SERIES_RA6T2 = PNR_SERIES('A', '6', 'T', '2'), PNR_SERIES_RA6T3 = PNR_SERIES('A', '6', 'T', '3'), + PNR_SERIES_RA6W1 = PNR_SERIES('A', '6', 'W', '1'), // RA8 PNR_SERIES_RA8M1 = PNR_SERIES('A', '8', 'M', '1'), PNR_SERIES_RA8M2 = PNR_SERIES('A', '8', 'M', '2'), @@ -136,11 +143,13 @@ typedef enum { PNR_MEMSIZE_1MB = 'F', PNR_MEMSIZE_1_5MB = 'G', PNR_MEMSIZE_2MB = 'H', + PNR_MEMSIZE_5MB = 'R', // 1MB MRAM + 4MB SiP Flash + PNR_MEMSIZE_9MB = 'S', // 1MB MRAM + 8MB SiP Flash } renesas_pnr_memsize_e; /* For future reference, if we want to add an info command * - * Package type + * Package type (Could use updating) * FP: LQFP 100 pins 0.5 mm pitch * FN: LQFP 80 pins 0.5 mm pitch * FM: LQFP 64 pins 0.5 mm pitch @@ -209,6 +218,7 @@ typedef enum { * ra6t1 - Flash Root Table * ra6t2 - Fixed location 2 * ra6t3 - Fixed location 2 + * ra6w1 - FIXME -- Lacking user manual as of 2025/12/12, so unknown. * ra8m1 - Fixed location 5 (!!) * ra8m2 - Fixed location 6 (!!) * ra8e1 - Fixed location 5 @@ -278,6 +288,14 @@ typedef enum { /* Renesas RA MCUs can have one of two kinds of flash memory, MF3/4 and RV40 */ +/* This is broken with the addition of the RA8 families -- by default, they have + * their code flash located at 0x12000000/0x02000000, which is above this point. + * Unfortunately, we can't just increase this to that address, as some + * other series locate their data flash at 0x08000000. + * + * FIXME -- This still needs addressing, but I also do not have any RA8 chips to + * test against. + */ #define RENESAS_CF_END UINT32_C(0x00300000) /* End of Flash (maximum possible across families) */ /* MF3/4 Flash */ @@ -609,6 +627,7 @@ static void renesas_add_flash(target_s *const target, const target_addr_t addr, * ra6t1 - RV40 * ra6t2 - RV40 * ra6t3 - RV40 + * ra6w1 - No internal flash, only O/QSPI * ra8m1 - RV40 * ra8m2 - MRAM + OSPI Flash * ra8e1 - RV40 @@ -681,6 +700,10 @@ static void renesas_add_flash(target_s *const target, const target_addr_t addr, /* FIXME: MRAM/OSPI flashing not implemented currently */ return; + case PNR_SERIES_RA6W1: + /* No internal flash */ + return; + default: return; } @@ -702,6 +725,9 @@ bool renesas_ra_probe(target_s *const target) /* mcus with PNR located at 0x01001c10 * ra2l1 (part_id wanted) * ra2e2 (part_id wanted) + * ra2e3 (part_id wanted) + * ra2a2 (part_id wanted) + * ra2t1 (part_id wanted) */ if (!renesas_pnr_read(target, RENESAS_FIXED1_PNR, pnr)) return false; @@ -713,15 +739,60 @@ bool renesas_ra_probe(target_s *const target) /* mcus with PNR located at 0x010080f0 * ra4e1 (part_id wanted) * ra4e2 (part_id wanted) + * ra4c1 (part_id wanted) + * ra4t1 (part_id wanted) + * ra4l1 (part_id wanted) * ra6m4 (part_id wanted) * ra6e1 (part_id wanted) * ra6e2 (part_id wanted) * ra6t2 (part_id wanted) + * ra6t3 (part_id wanted) */ if (!renesas_pnr_read(target, RENESAS_FIXED2_PNR, pnr)) return false; break; + // case: + /* mcus with PNR located at 0x01011080 + * ra0l1 (part_id wanted) + * ra0e1 (part_id wanted) + * ra0e2 (part_id wanted) + */ + // if(!renesas_pnr_read(target, RENESAS_FIXED3_PNR, pnr)) + // return false; + // break; + + // case: + /* mcus with PNR located at 0x01011120 + * ra2l2 (part_id wanted) + */ + // if(!renesas_pnr_read(target, RENESAS_FIXED4_PNR, pnr)) + // return false; + // break; + + // case: + /* mcus with PNR located at 0x130080f0 + * ra8m1 (part_id wanted) + * ra8e1 (part_id wanted) + * ra8e2 (part_id wanted) + * ra8t1 (part_id wanted) + * ra8d1 (part_id wanted) + */ + // if(!renesas_pnr_read(target, RENESAS_FIXED5_PNR, pnr)) + // return false; + // break; + + // case: + /* mcus with PNR located at 0x02c1ec38 + * ra8m2 (part_id wanted) + * ra8t2 (part_id wanted) + * ra8d2 (part_id wanted) + * ra8p1 (part_id wanted) + */ + // if(!renesas_pnr_read(target, RENESAS_FIXED6_PNR, pnr)) + // return false; + // break; + case RENESAS_PARTID_RA2A1: case RENESAS_PARTID_RA4M1: case RENESAS_PARTID_RA6M2: @@ -744,9 +815,9 @@ bool renesas_ra_probe(target_s *const target) * but experimentally there doesn't seem to be an issue with these in particular * * try the fixed address RENESAS_FIXED2_PNR first, as it should lead to less illegal/erroneous - * memory accesses in case of failure, and is the most common case + * memory accesses in case of failure, and is the most common case. * - * TODO: Update with the new known locations + * These are tried in order of most to least common. */ if (renesas_pnr_read(target, RENESAS_FIXED2_PNR, pnr)) { @@ -768,6 +839,29 @@ bool renesas_ra_probe(target_s *const target) break; } + if (renesas_pnr_read(target, RENESAS_FIXED5_PNR, pnr)) { + DEBUG_WARN("Found renesas chip (%.*s) with %s and unsupported Part ID 0x%x, please report it\n", + (int)sizeof(pnr), pnr, "pnr location RENESAS_FIXED5_PNR", target->part_id); + break; + } + if (renesas_pnr_read(target, RENESAS_FIXED6_PNR, pnr)) { + DEBUG_WARN("Found renesas chip (%.*s) with %s and unsupported Part ID 0x%x, please report it\n", + (int)sizeof(pnr), pnr, "pnr location RENESAS_FIXED6_PNR", target->part_id); + break; + } + + if (renesas_pnr_read(target, RENESAS_FIXED3_PNR, pnr)) { + DEBUG_WARN("Found renesas chip (%.*s) with %s and unsupported Part ID 0x%x, please report it\n", + (int)sizeof(pnr), pnr, "pnr location RENESAS_FIXED3_PNR", target->part_id); + break; + } + + if (renesas_pnr_read(target, RENESAS_FIXED4_PNR, pnr)) { + DEBUG_WARN("Found renesas chip (%.*s) with %s and unsupported Part ID 0x%x, please report it\n", + (int)sizeof(pnr), pnr, "pnr location RENESAS_FIXED4_PNR", target->part_id); + break; + } + return false; } @@ -784,8 +878,22 @@ bool renesas_ra_probe(target_s *const target) target->target_storage = priv; target->driver = (char *)priv->pnr; - // TODO: Update with more models switch (priv->series) { + case PNR_SERIES_RA0L1: + renesas_add_flash(target, 0x40100000, 1U * 1024U); /* Data flash memory 1 KB 0x40100000 */ + target_add_ram32(target, 0x20004000, 16U * 1024U); /* SRAM 16 KB 0x20004000 */ + break; + + case PNR_SERIES_RA0E2: + renesas_add_flash(target, 0x40100000, 2U * 1024U); /* Data flash memory 2 KB 0x40100000 */ + target_add_ram32(target, 0x20004000, 16U * 1024U); /* SRAM 16 KB 0x20004000 */ + break; + + case PNR_SERIES_RA0E1: + renesas_add_flash(target, 0x40100000, 1U * 1024U); /* Data flash memory 1 KB 0x40100000 */ + target_add_ram32(target, 0x20004000, 12U * 1024U); /* SRAM 12 KB 0x20004000 */ + break; + case PNR_SERIES_RA2L1: case PNR_SERIES_RA2A1: case PNR_SERIES_RA4M1: @@ -793,16 +901,28 @@ bool renesas_ra_probe(target_s *const target) target_add_ram32(target, 0x20000000, 32U * 1024U); /* SRAM 32 KB 0x20000000 */ break; + case PNR_SERIES_RA2A2: + renesas_add_flash(target, 0x40100000, 8U * 1024U); /* Data flash memory 8 KB 0x40100000 */ + target_add_ram32(target, 0x20000000, 48U * 1024U); /* SRAM 48 KB 0x20000000 */ + break; + case PNR_SERIES_RA2E1: + case PNR_SERIES_RA2L2: renesas_add_flash(target, 0x40100000, 4U * 1024U); /* Data flash memory 4 KB 0x40100000 */ target_add_ram32(target, 0x20004000, 16U * 1024U); /* SRAM 16 KB 0x20004000 */ break; case PNR_SERIES_RA2E2: + case PNR_SERIES_RA2T1: renesas_add_flash(target, 0x40100000, 2U * 1024U); /* Data flash memory 2 KB 0x40100000 */ target_add_ram32(target, 0x20004000, 8U * 1024U); /* SRAM 8 KB 0x20004000 */ break; + case PNR_SERIES_RA2E3: + renesas_add_flash(target, 0x40100000, 2U * 1024U); /* Data flash memory 2 KB 0x40100000 */ + target_add_ram32(target, 0x20004000, 16U * 1024U); /* SRAM 16 KB 0x20004000 */ + break; + case PNR_SERIES_RA4M2: case PNR_SERIES_RA4M3: case PNR_SERIES_RA4E1: @@ -823,6 +943,23 @@ bool renesas_ra_probe(target_s *const target) target_add_ram32(target, 0x20000000, 96U * 1024U); /* SRAM 96 KB 0x20000000 */ break; + case PNR_SERIES_RA4C1: + renesas_add_flash(target, 0x08000000, 8U * 1024U); /* Data flash memory 8 KB 0x08000000 */ + target_add_ram32(target, 0x20000000, 96U * 1024U); /* SRAM 96 KB 0x20000000 */ + /* Potential for external mem-mapped QSPI at 0x60000000--0x68000000 */ + break; + + case PNR_SERIES_RA4L1: + renesas_add_flash(target, 0x08000000, 8U * 1024U); /* Data flash memory 8 KB 0x08000000 */ + target_add_ram32(target, 0x20000000, 64U * 1024U); /* SRAM 64 KB 0x20000000 */ + /* Potential for external mem-mapped QSPI at 0x60000000--0x68000000 */ + break; + + case PNR_SERIES_RA4T1: + renesas_add_flash(target, 0x08000000, 4U * 1024U); /* Data flash memory 4 KB 0x08000000 */ + target_add_ram32(target, 0x20000000, 40U * 1024U); /* SRAM 40 KB 0x20000000 */ + break; + case PNR_SERIES_RA6M1: /* conflicting information in the datasheet, here be dragons */ renesas_add_flash(target, 0x40100000, 8U * 1024U); /* Data flash memory 8 KB 0x40100000 */ @@ -870,6 +1007,101 @@ bool renesas_ra_probe(target_s *const target) target_add_ram32(target, 0x28000000, 1024U); /* Standby SRAM 1 KB 0x28000000 */ break; + case PNR_SERIES_RA6T3: + renesas_add_flash(target, 0x08000000, 4U * 1024U); /* Data flash memory 4 KB 0x08000000 */ + target_add_ram32(target, 0x20000000, 40U * 1024U); /* SRAM 40 KB 0x20000000 */ + break; + + case PNR_SERIES_RA6W1: + /* TODO: Handle external QSPI-mapped flash! */ + /* FIXME: Update when the User Manual is released... */ + target_add_ram32(target, 0x20000000, 256U * 1024U); /* SRAM0 256 KB 0x20000000 */ + target_add_ram32(target, 0x20040000, 256U * 1024U); /* SRAM1 256 KB 0x20000000 */ + target_add_ram32(target, 0x20080000, 128U * 1024U); /* SRAM2 128 KB 0x20000000 */ + target_add_ram32(target, 0x28600000, 64U * 1024U); /* Retention RAM 64 KB 0x28600000 */ + break; + + /* All the RA8 families have TrustZone and thus have their main flash memory + * located at a different location from all the other families. That's the + * reason for duplicating the add commands/etc for these parts + */ + case PNR_SERIES_RA8M1: + /* These are the non-secure aliases */ + renesas_add_flash(target, 0x37000000, 12U * 1024U); /* Data flash memory 12 KB 0x37000000 */ + target_add_ram32(target, 0x32000000, 384U * 1024U); /* SRAM0 384 KB 0x32000000 */ + target_add_ram32(target, 0x32060000, 512U * 1024U); /* SRAM1 512 KB 0x32060000 */ + target_add_ram32(target, 0x30000000, 64U * 1024U); /* DTCM 64 KB 0x30000000 */ + target_add_ram32(target, 0x10000000, 64U * 1024U); /* ITCM 64 KB 0x10000000 */ + target_add_ram32(target, 0x36000000, 1024U); /* Standby SRAM 1 KB 0x36000000 */ + + renesas_add_flash(target, 0x12000000, renesas_flash_size(pnr)); /* Code flash memory 0x12000000 */ + target_add_commands(target, renesas_cmd_list, target->driver); + return true; + + case PNR_SERIES_RA8E1: + /* These are the non-secure aliases */ + renesas_add_flash(target, 0x37000000, 12U * 1024U); /* Data flash memory 12 KB 0x37000000 */ + target_add_ram32(target, 0x32040000, 128U * 1024U); /* SRAM0 128 KB 0x32040000 */ + target_add_ram32(target, 0x32060000, 512U * 1024U); /* SRAM1 512 KB 0x32060000 */ + target_add_ram32(target, 0x30000000, 16U * 1024U); /* DTCM 16 KB 0x30000000 */ + target_add_ram32(target, 0x10000000, 16U * 1024U); /* ITCM 16 KB 0x10000000 */ + target_add_ram32(target, 0x36000000, 1024U); /* Standby SRAM 1 KB 0x36000000 */ + + renesas_add_flash(target, 0x12000000, renesas_flash_size(pnr)); /* Code flash memory 0x12000000 */ + target_add_commands(target, renesas_cmd_list, target->driver); + return true; + + case PNR_SERIES_RA8E2: + /* These are the non-secure aliases */ + renesas_add_flash(target, 0x37000000, 12U * 1024U); /* Data flash memory 12 KB 0x37000000 */ + target_add_ram32(target, 0x32060000, 512U * 1024U); /* SRAM1 512 KB 0x32060000 */ + target_add_ram32(target, 0x30000000, 16U * 1024U); /* DTCM 16 KB 0x30000000 */ + target_add_ram32(target, 0x10000000, 16U * 1024U); /* ITCM 16 KB 0x10000000 */ + target_add_ram32(target, 0x36000000, 1024U); /* Standby SRAM 1 KB 0x36000000 */ + + renesas_add_flash(target, 0x12000000, renesas_flash_size(pnr)); /* Code flash memory 0x12000000 */ + target_add_commands(target, renesas_cmd_list, target->driver); + return true; + + case PNR_SERIES_RA8T1: + case PNR_SERIES_RA8D1: + /* These are the non-secure aliases */ + renesas_add_flash(target, 0x37000000, 12U * 1024U); /* Data flash memory 12 KB 0x37000000 */ + target_add_ram32(target, 0x32000000, 384U * 1024U); /* SRAM0 384 KB 0x32000000 */ + target_add_ram32(target, 0x32060000, 512U * 1024U); /* SRAM1 512 KB 0x32060000 */ + target_add_ram32(target, 0x30000000, 64U * 1024U); /* DTCM 64 KB 0x30000000 */ + target_add_ram32(target, 0x10000000, 64U * 1024U); /* ITCM 64 KB 0x10000000 */ + target_add_ram32(target, 0x36000000, 1024U); /* Standby SRAM 1 KB 0x36000000 */ + + renesas_add_flash(target, 0x12000000, renesas_flash_size(pnr)); /* Code flash memory 0x12000000 */ + target_add_commands(target, renesas_cmd_list, target->driver); + return true; + + /* These are the MRAM/SiP models */ + case PNR_SERIES_RA8M2: + case PNR_SERIES_RA8T2: + case PNR_SERIES_RA8D2: + case PNR_SERIES_RA8P1: + /* These are the non-secure aliases */ + /* TODO: Handle the multi-core TCM and the extra ECC regions*/ + target_add_ram32(target, 0x32000000, 512U * 1024U); /* SRAM0 512 KB 0x32000000 */ + target_add_ram32(target, 0x32080000, 512U * 1024U); /* SRAM1 512 KB 0x32080000 */ + target_add_ram32(target, 0x32100000, 512U * 1024U); /* SRAM2 512 KB 0x32100000 */ + target_add_ram32(target, 0x32180000, 128U * 1024U); /* SRAM3 128 KB 0x32180000 */ + + uint32_t flash = renesas_flash_size(pnr); + + // Check for the SiP variant with SPI Flash + if (flash > (2048U * 1024U)) { + renesas_add_flash(target, 0x12000000, 1024U * 1024U); /* Code MRAM 0x12000000 */ + renesas_add_flash(target, 0x18000000, flash - 1024U * 1024U); /* External SPI 0x18000000 */ + } else { + renesas_add_flash(target, 0x12000000, flash); /* Code MRAM 0x12000000 */ + } + + target_add_commands(target, renesas_cmd_list, target->driver); + return true; + default: return false; } @@ -905,7 +1137,7 @@ static bool renesas_pnr_read(target_s *const target, const target_addr_t base, u pnrr[i] = target_mem32_read32(target, base + i * 4U); /* Write bytewise into provided container */ - if (base == RENESAS_FIXED1_PNR) { + if (base == RENESAS_FIXED1_PNR || base == RENESAS_FIXED3_PNR || base == RENESAS_FIXED4_PNR) { /* Renesas... look what you made me do... */ /* reverse order, see 'Part numbering scheme' note for context */ for (size_t i = 0U; i < 13U; i++) @@ -954,6 +1186,10 @@ static uint32_t renesas_flash_size(const uint8_t *const pnr) return UINT32_C(1536 * 1024); case PNR_MEMSIZE_2MB: return UINT32_C(2048 * 1024); + case PNR_MEMSIZE_5MB: + return UINT32_C(5120 * 1024); + case PNR_MEMSIZE_9MB: + return UINT32_C(9216 * 1024); default: return 0; }