This is an automated email from Gerrit.

"Mark Featherston <m...@embeddedts.com>" just uploaded a new patch set to 
Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8389

-- gerrit

commit 4b2a62db9b6ceec3f1df762558a19a113f53aa38
Author: Mark Featherston <m...@embeddedts.com>
Date:   Sun Jun 2 19:26:59 2024 -0700

    flash/nor/renesas_rv40: support Renesas RV40 flash
    
    Supports the RV40 variant of flash technology used on RA MCUs
    
    no new Clang analyzer warnings
    
    Change-Id: I47a8cf7a87b10b298565a90ad809bda100c6fb10
    Signed-off-by: Mark Featherston <m...@embeddedts.com>

diff --git a/contrib/loaders/flash/rv40f.S b/contrib/loaders/flash/rv40f.S
new file mode 100644
index 0000000000..43a3d26a3c
--- /dev/null
+++ b/contrib/loaders/flash/rv40f.S
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*
+ * This code is embedded within: src/flash/nor/renesas_rv40f.c as a "C" array.
+ *
+ * To rebuild:
+ *   arm-none-eabi-gcc -c rv40f.S
+ *   arm-none-eabi-objcopy -O binary rv40f.o rv40f.bin
+ *   xxd -c 8 -i rv40f.bin > rv40f.txt
+ *
+ * Then read and edit this result into the "C" source.
+ */
+
+#define FACI_BASE 0x407fe000 /* flash mode control register */
+#define FACI_CMD  0x407e0000 /* FACI command issuing area address */
+
+/* offsets of other registers relative to FPMCR */
+#define FASTAT   0x10   /* Flash access status register */
+#define FAEINT   0x14   /* Flash access error interrupt enable register */
+#define FRDYIE   0x18   /* Flash ready interrupt enable register */
+#define FSADDR   0x30   /* FACI command start address register */
+#define FEADDR   0x34   /* FACI command end address register */
+#define FSTATR   0x80   /* Flash status register */
+#define FENTRYR  0x84   /* Flash P/E mode entry register */
+#define FSUINITR 0x8c   /* Flash sequencer set-up initialization register */
+#define FCMDR    0xa0   /* Flash command register */
+#define FBCCNT   0xd0   /* Data flash bank check control register */
+#define FBCSTAT         0xd4   /* Data flash bank check status register */
+#define FPSADDR  0xd8   /* Data flash programming start address register */
+#define FAWMON   0xdc   /* Flash access window monitor register */
+#define FCPSR    0xe0   /* Flash sequencer processing switching register */
+#define FPCKAR   0xe4   /* Flash sequencer processing clock notification 
register */
+#define FSUACR   0xe8   /* Flash start-up area control register */
+
+/* values used in the FSTATR register */
+#define FSTATR_DBFULL 0x400
+
+/* rv40f_flash_write:
+ *   This function writes a block of data to the code flash. If the size of the
+ *   source buffer (given by 'pulWorkareaStart' and 'pulWorkareaEnd') then the
+ *   source data is repeated to fill up the destination until 'ulCount' bytes
+ *   have been written.
+ *
+ *   This function must be executed from RAM since code cannot be executed from
+ *   flash while it is in programming mode.
+ *
+ *   The arguments to this function match the arguments passed by OpenOCD to 
its
+ *   flash loader functions.
+ *
+ * Inputs:
+ *   r0 - ulong ulCount - number of halfwords to write
+ *   r1 - ulong * pulWorkareaStart - start of the work area in RAM
+ *   r2 - ulong * pulWorkareaEnd - end address of the work area
+ *   r3 - ulong * pulTarget - address to write the data To
+ * Returns:
+ *   r0 - result
+ * Registers:
+ *   r0, r1 - working registers
+ *   r5 - R_FACI - base address of flash controller peripheral
+ *   r4 - source address (iterated)
+ *   r6 - decremented count of halfwords
+ *   r7 - FACI command issuing area address
+ */
+
+    .syntax unified
+    .cpu cortex-m0plus
+    .thumb
+    .thumb_func
+
+.global rv40f_flash_write
+
+rv40f_flash_write:
+
+    mov     r9, r1
+    mov     r4, r9          /* r4 => iterated source address */
+    ldr     r5, =FACI_BASE  /* r5 => base register address */
+    ldr     r7, =FACI_CMD   /* r7 => load FACI command issuing area address */
+    mov     r9, r0
+    mov     r6, r9          /* r6 => count of halfwords */
+
+    /* set the destination address of the block */
+    str     r3, [r5, #FSADDR]
+
+    /* issue the write command */
+    movs    r0, #0xE8
+    strb    r0, [r7]
+    /* write count of halfwords */
+    mov     r0, r9
+    strb    r0, [r7]
+
+    /* write first halfword */
+    ldrh    r0, [r4]
+    strh    r0, [r7]
+    /* increment src address */
+    adds    r4, #2
+
+loop_start:
+    /* decrement counter */
+    subs     r6, #1
+
+    /* if zero, jump to completion */
+    beq     complete
+
+    /* write next halfword */
+    ldrh    r0, [r4]
+    strh    r0, [r7]
+    /* increment src address */
+    adds    r4, #2
+
+/* wait while dbfull bit == 1 */
+wait_dbfull:
+    movs    r0, #FSTATR
+    adds    r0, r5
+    ldr     r1, [r0]
+    /* check DBFULL bit */
+    ldr     r0, =FSTATR_DBFULL
+    tst     r0, r1
+    bne     wait_dbfull
+    b       loop_start
+
+/* complete transaction by writing D0h to FACI cmd issuing area */
+complete:
+    movs    r0, #0xD0
+    strb    r0, [r7]
+
+exit:
+    movs    r1, #FSTATR
+    adds    r1, r5
+    ldr     r0, [r1]
+    bkpt    #0
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index afa11e7d40..381b416b05 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -57,6 +57,7 @@ NOR_DRIVERS = \
        %D%/psoc6.c \
        %D%/qn908x.c \
        %D%/renesas_rpchf.c \
+       %D%/renesas_rv40f.c \
        %D%/rp2040.c \
        %D%/rsl10.c \
        %D%/sfdp.c \
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index 211661e214..08752c2fe8 100644
--- a/src/flash/nor/driver.h
+++ b/src/flash/nor/driver.h
@@ -287,6 +287,7 @@ extern const struct flash_driver psoc5lp_nvl_flash;
 extern const struct flash_driver psoc6_flash;
 extern const struct flash_driver qn908x_flash;
 extern const struct flash_driver renesas_rpchf_flash;
+extern const struct flash_driver renesas_rv40f_flash;
 extern const struct flash_driver rp2040_flash;
 extern const struct flash_driver rsl10_flash;
 extern const struct flash_driver sh_qspi_flash;
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 34359889a6..2d1130be8e 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -64,6 +64,7 @@ static const struct flash_driver * const flash_drivers[] = {
        &psoc6_flash,
        &qn908x_flash,
        &renesas_rpchf_flash,
+       &renesas_rv40f_flash,
        &rp2040_flash,
        &sh_qspi_flash,
        &sim3x_flash,
diff --git a/src/flash/nor/renesas_rv40f.c b/src/flash/nor/renesas_rv40f.c
new file mode 100644
index 0000000000..4e397087b0
--- /dev/null
+++ b/src/flash/nor/renesas_rv40f.c
@@ -0,0 +1,594 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Copyright (c) 2022 Miloslav Semler                                    *
+ *   Copyright (c) 2024 Mark Featherston                                   *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/binarybuffer.h>
+#include <helper/bits.h>
+#include <helper/time_support.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+/* FACI registers */
+#define FACI_FMEPROT  0x407FE044
+#define FACI_FWEPROR  0x4001E416
+#define FACI_FENTRYR  0x407FE084
+#define FACI_FSTATR   0x407FE080
+#define FACI_FASTAT   0x407FE010
+#define FACI_FSADDR   0x407FE030
+#define FACI_FEADDR   0x407FE034
+#define FACI_CMD_AREA 0x407E0000
+#define FACI_PNR      0x010080F0
+
+/* register bits */
+#define FACI_FSTATR_FLWEERR   BIT(6)
+#define FACI_FSTATR_PRGSPD    BIT(8)
+#define FACI_FSTATR_ERSSPD    BIT(9)
+#define FACI_FSTATR_DBFULL    BIT(10)
+#define FACI_FSTATR_SUSRDY    BIT(11)
+#define FACI_FSTATR_PRGERR    BIT(12)
+#define FACI_FSTATR_ERSERR    BIT(13)
+#define FACI_FSTATR_ILGLERR   BIT(14)
+#define FACI_FSTATR_FRDY      BIT(15)
+#define FACI_FSTATR_OTERR     BIT(20)
+#define FACI_FSTATR_SECERR    BIT(21)
+#define FACI_FSTATR_FESETERR  BIT(22)
+#define FACI_FSTATR_ILGCOMERR BIT(23)
+
+#define FACI_FASTAT_DFAE  BIT(3)
+#define FACI_FASTAT_CMDLK BIT(4)
+#define FACI_FASTAT_CFAE  BIT(7)
+
+#define FACI_CMD_FORCED_STOP 0xB3
+#define FACI_CMD_ERASE1      0x20
+#define FACI_CMD_PE_SUSPEND  0xB0
+#define FACI_CMD_PE_RESUME   0xD0
+#define FACI_CMD_STATUSCLR   0x50
+
+/* Rough estimates from the RA4M2
+ * Write 32KB: 848ms
+ * erase 32KB: 1040ms
+ */
+#define TIMEOUT_ERASE_MS 2000
+#define TIMEOUT_WRITE_MS 1000
+
+struct renesas_bank {
+       /* bank size in bytes */
+       unsigned int size;
+       /* base address */
+       unsigned int base;
+       /* 1 for data flash or 0 for code flash */
+       unsigned int is_data;
+       bool probed;
+       bool has_fmeprot;
+};
+
+FLASH_BANK_COMMAND_HANDLER(rv40f_flash_bank_command)
+{
+       struct renesas_bank *info;
+
+       unsigned int base = strtoul(CMD_ARGV[1], NULL, 16);
+       unsigned int size = strtoul(CMD_ARGV[2], NULL, 16);
+
+       info = malloc(sizeof(struct renesas_bank));
+       if (!info)
+               return ERROR_FAIL;
+       bank->driver_priv = info;
+
+       info->base = base;
+       info->size = size;
+       info->is_data = 0; /* assume code flash initially */
+       info->probed = false;
+       info->has_fmeprot = false;
+
+       return ERROR_OK;
+}
+
+static int rv40f_busy_wait(struct target *target, int timeout_ms)
+{
+       long long endtime;
+       uint32_t reg32;
+       int retval;
+
+       endtime = timeval_ms() + timeout_ms;
+       do {
+               /* read status register FSTATR */
+               retval = target_read_u32(target, FACI_FSTATR, &reg32);
+               if (retval != ERROR_OK)
+                       return ERROR_FAIL;
+
+               /* No (ERASE)/PROGRAM operation in progress */
+               if (reg32 & FACI_FSTATR_FRDY)
+                       return ERROR_OK;
+
+               alive_sleep(1);
+       } while (timeval_ms() < endtime);
+
+       return ERROR_TIMEOUT_REACHED;
+}
+
+static int rv40f_unlock(struct target *target, uint32_t reg32)
+{
+       uint8_t reg8;
+       int retval;
+
+       LOG_ERROR("Recovering from command-locked state");
+
+       if (reg32 & FACI_FSTATR_ILGLERR) {
+               retval = target_read_u8(target, FACI_FASTAT, &reg8);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* reset CFAE and DFAE flags if needed */
+               if (reg8 & (FACI_FASTAT_CFAE | FACI_FASTAT_DFAE)) {
+                       reg8 &= ~(FACI_FASTAT_CFAE | FACI_FASTAT_DFAE);
+
+                       retval = target_write_u8(target, FACI_FASTAT, reg8);
+                       if (retval != ERROR_OK)
+                               return retval;
+               }
+       }
+
+       retval = target_read_u32(target, FACI_FSTATR, &reg32);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (reg32 & FACI_FSTATR_FLWEERR) {
+               retval = target_write_u8(target, FACI_CMD_AREA, 
FACI_CMD_FORCED_STOP);
+               if (retval != ERROR_OK)
+                       return retval;
+       } else {
+               retval = target_write_u8(target, FACI_CMD_AREA, 
FACI_CMD_STATUSCLR);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       retval = rv40f_busy_wait(target, 2000);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* check CMDLK bit from FASTAT register */
+       retval = target_read_u8(target, FACI_FASTAT, &reg8);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* check CMDLK actually unlocked */
+       if ((reg8 & FACI_FASTAT_CMDLK) != 0) {
+               LOG_ERROR("Failed to recover from CMDLK");
+               retval = 1;
+       }
+
+       return retval;
+}
+
+/* wait for complete FACI command and do cleanup after lockup if needed */
+static int rv40f_complete(struct target *target, int timeout)
+{
+       int retval;
+       uint8_t reg8;
+       uint32_t reg32;
+
+       retval = rv40f_busy_wait(target, timeout);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* check CMDLK bit from FASTAT register */
+       retval = target_read_u8(target, FACI_FASTAT, &reg8);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* check CMDLK bit */
+       if (reg8 & 0x10) {
+               retval = target_read_u32(target, FACI_FSTATR, &reg32);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if (reg32 & FACI_FSTATR_FLWEERR)
+                       LOG_ERROR("FSTATR: Flash write/erase protect error");
+               if (reg32 & FACI_FSTATR_PRGSPD)
+                       LOG_ERROR("FSTATR: Programming Suspend");
+               if (reg32 & FACI_FSTATR_ERSSPD)
+                       LOG_ERROR("FSTATR: Erasure suspend");
+               if (reg32 & FACI_FSTATR_SUSRDY)
+                       LOG_ERROR("FSTATR: Suspend ready");
+               if (reg32 & FACI_FSTATR_ERSERR)
+                       LOG_ERROR("FSTATR: Erasure Error");
+               if (reg32 & FACI_FSTATR_ILGLERR)
+                       LOG_ERROR("FSTATR: Illegal Command Error Flag");
+               if (reg32 & FACI_FSTATR_OTERR)
+                       LOG_ERROR("FSTATR: Other Error");
+               if (reg32 & FACI_FSTATR_SECERR)
+                       LOG_ERROR("FSTATR: Security Error");
+               if (reg32 & FACI_FSTATR_FESETERR)
+                       LOG_ERROR("FSTATR: FENTRY Setting Error");
+               if (reg32 & FACI_FSTATR_ILGCOMERR)
+                       LOG_ERROR("FSTATR: Illegal Command");
+
+               rv40f_unlock(target, reg32);
+               retval = ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return retval;
+}
+
+/* switch to read mode after erasing or programming */
+static int rv40f_to_readonly(struct target *target)
+{
+       int retval;
+       uint32_t reg32;
+
+       retval = target_read_u32(target, FACI_FSTATR, &reg32);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* operation in progress */
+       if ((reg32 & FACI_FSTATR_FRDY) == 0)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       retval = target_write_u16(target, FACI_FENTRYR, 0xAA00);
+
+       return retval;
+}
+
+static int rv40f_pe_mode(struct flash_bank *bank)
+{
+       struct renesas_bank *info = bank->driver_priv;
+       int retval;
+       uint16_t r16;
+
+       /* unprotect memories from program/erase */
+       retval = target_write_u8(bank->target, FACI_FWEPROR, 1);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u16(bank->target, FACI_FENTRYR, &r16);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Enter data flash if needed*/
+       if (info->is_data && ((r16 & 0xff) != 0x80)) {
+               /* data flash */
+               retval = target_write_u16(bank->target, FACI_FENTRYR, 0xAA80);
+               if (retval != ERROR_OK)
+                       return retval;
+       } else if (!info->is_data && ((r16 & 0xff) != 0x01)) {
+               /* code flash */
+               if (info->has_fmeprot) {
+                       /* Some platforms have this additional code flash 
protection */
+                       retval = target_write_u16(bank->target, FACI_FMEPROT, 
0xD900);
+                       if (retval != ERROR_OK)
+                               return retval;
+               }
+               retval = target_write_u16(bank->target, FACI_FENTRYR, 0xAA01);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       /* check if the things are OK */
+       retval = target_read_u16(bank->target, FACI_FENTRYR, &r16);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (info->is_data && (r16 & 0xaa80) == 0x80) {
+               LOG_INFO("FACI in data flash P/E mode ...");
+       } else if ((r16 & 0xaa01) == 0x1) {
+               LOG_INFO("FACI in code flash P/E mode ...");
+       } else {
+               LOG_ERROR("Flash not in P/E mode (0x%X)", r16);
+               retval = ERROR_FLASH_OPERATION_FAILED;
+       }
+
+       return retval;
+}
+
+static int rv40f_erase(struct flash_bank *bank, unsigned int first,
+               unsigned int last)
+{
+       struct renesas_bank *info = bank->driver_priv;
+       struct target *target = bank->target;
+       int retval;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* enter P/E mode */
+       retval = rv40f_pe_mode(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       for (unsigned int sector = first ; sector <= last ; sector++) {
+               unsigned int offset = bank->sectors[sector].offset;
+
+               /* start address */
+               retval = target_write_u32(bank->target, FACI_FSADDR, offset + 
info->base);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* fire the erase */
+               retval = target_write_u8(target, FACI_CMD_AREA, 
FACI_CMD_ERASE1);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = target_write_u8(target, FACI_CMD_AREA, 
FACI_CMD_PE_RESUME);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = rv40f_complete(target, TIMEOUT_ERASE_MS);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       /* switch back to readonly after operation */
+       retval = rv40f_to_readonly(target);
+
+       return retval;
+}
+
+static int rv40f_write_block(struct flash_bank *bank, const uint8_t *buffer,
+                                                        uint32_t offset, 
uint32_t count)
+{
+       struct renesas_bank *info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t buffer_size = 2048;            /* Default minimum value */
+       struct working_area *write_algorithm;
+       struct working_area *source;
+       uint32_t address = bank->base + offset;
+       struct reg_param reg_params[4];
+       struct armv7m_algorithm armv7m_info;
+       int retval = ERROR_OK;
+       unsigned int thisrun_count;
+       uint8_t r8;
+
+       /* Increase buffer_size if needed */
+       if (buffer_size < (target->working_area_size / 2))
+               buffer_size = (target->working_area_size / 2);
+
+       /* RAMCODE used for rv40f Flash programming:
+        * R0 keeps number of halfwords to write (4,8,16 - data, 64 - program)
+        * R1 keeps source start address         (u32SourceStart)
+        * R2 keeps source end address           (u32SourceEnd)
+        * R3 keeps target start address         (u32Target) */
+       unsigned char rv40f_flash_write_code[] = {
+               0x89, 0x46, 0x4c, 0x46, 0x0e, 0x4d, 0x0f, 0x4f,
+               0x81, 0x46, 0x4e, 0x46, 0x2b, 0x63, 0xe8, 0x20,
+               0x38, 0x70, 0x48, 0x46, 0x38, 0x70, 0x20, 0x88,
+               0x38, 0x80, 0x02, 0x34, 0x01, 0x3e, 0x09, 0xd0,
+               0x20, 0x88, 0x38, 0x80, 0x02, 0x34, 0x80, 0x20,
+               0x40, 0x19, 0x01, 0x68, 0x06, 0x48, 0x08, 0x42,
+               0xf9, 0xd1, 0xf3, 0xe7, 0xd0, 0x20, 0x38, 0x70,
+               0x80, 0x21, 0x49, 0x19, 0x08, 0x68, 0x00, 0xbe,
+               0x00, 0xe0, 0x7f, 0x40, 0x00, 0x00, 0x7e, 0x40,
+               0x00, 0x04, 0x00, 0x00
+       };
+
+       LOG_INFO("Renesas RV40F FLASH Write ...");
+
+       if (info->is_data) {
+               /* check alignment - data flash */
+               if (offset & 0x7) {
+                       LOG_WARNING("offset 0x%" PRIx32 " breaks required 
8-byte alignment", offset);
+                       return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+               }
+       } else {
+               /* check alignment - code flash */
+               if (offset & 0x7f) {
+                       LOG_WARNING("offset 0x%" PRIx32 " breaks required 
128-byte alignment", offset);
+                       return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+               }
+       }
+
+       /* enter P/E mode */
+       retval = rv40f_pe_mode(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       count = count / 2; /* number bytes -> number halfwords */
+
+       /* allocate working area and variables with flash programming code */
+       if (target_alloc_working_area(target, sizeof(rv40f_flash_write_code),
+               &write_algorithm) != ERROR_OK) {
+               LOG_WARNING("no working area available, can't do block memory 
writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       retval = target_write_buffer(target, write_algorithm->address,
+       sizeof(rv40f_flash_write_code), rv40f_flash_write_code);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* memory buffer */
+       while (target_alloc_working_area(target, buffer_size, &source) != 
ERROR_OK) {
+               buffer_size /= 2;
+               if (buffer_size <= 256) {
+                       /* free working area, write algorithm already allocated 
*/
+                       target_free_working_area(target, write_algorithm);
+
+                       LOG_WARNING("No large enough working area available, 
can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       }
+
+       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+       armv7m_info.core_mode = ARM_MODE_THREAD;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* number of 
halfwords to program */
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* source start 
address */
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* source end 
address */
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* target start 
address */
+
+       /* write code buffer and use Flash programming code within rv40f */
+       /* Set breakpoint to 0 with time-out of 1000 ms */
+       while (count > 0) {
+               /* dataflash has a write count 2,4,8 halfwords */
+               if (info->is_data) {
+                       if (count >= 8)
+                               thisrun_count = 8;
+                       else if (count >= 4)
+                               thisrun_count = 4;
+                       else
+                               thisrun_count = 2;
+                       /* code flash has 64 halfwords programming block */
+               } else {
+                       thisrun_count = 64;
+               }
+
+               retval = target_write_buffer(target, source->address, 
thisrun_count * 2, buffer);
+               if (retval != ERROR_OK)
+                       break;
+
+               buf_set_u32(reg_params[0].value, 0, 32, thisrun_count);
+               buf_set_u32(reg_params[1].value, 0, 32, source->address);
+               buf_set_u32(reg_params[2].value, 0, 32, source->address + 
thisrun_count * 2);
+               buf_set_u32(reg_params[3].value, 0, 32, address);
+               retval = target_run_algorithm(target, 0, NULL, 4, reg_params,
+                       write_algorithm->address, 0, 1000, &armv7m_info);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Error executing RV40f Flash programming 
algorithm");
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               target_read_u8(bank->target, FACI_FWEPROR, &r8);
+
+               if (retval != ERROR_OK || r8 != 1) {
+                       LOG_ERROR("Flash locked for write");
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               /* wait for write 1000 ms */
+               retval = rv40f_busy_wait(target, TIMEOUT_WRITE_MS);
+               if (retval != ERROR_OK)
+                       break;
+
+               /* decrement counters */
+               if (count >= thisrun_count) {
+                       buffer  += thisrun_count * 2;
+                       address += thisrun_count * 2;
+                       count   -= thisrun_count;
+               }
+       }
+
+       target_free_working_area(target, source);
+       target_free_working_area(target, write_algorithm);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* switch back to readonly after operation */
+       return rv40f_to_readonly(target);
+}
+
+static int rv40f_probe(struct flash_bank *bank)
+{
+       struct renesas_bank *info = bank->driver_priv;
+       struct flash_sector *s;
+       unsigned int n, num_pages;
+       char part_number[17] = {0};
+       int retval;
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       info->probed = false;
+       bank->base = info->base;
+       bank->size = info->size; /* bytes */
+
+       if (info->base > 0) {
+               /* data flash - same for all types */
+               info->is_data = 1;
+               num_pages = info->size / 64; /* 1 block = 64 bytes */
+               bank->num_sectors = num_pages;
+               bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+               if (!bank->sectors)
+                       return ERROR_FAIL;
+               for (n = 0; n < num_pages; n++) {
+                       s = &bank->sectors[n];
+                       s->offset = n * 64;
+                       s->size = 64;
+                       s->is_erased = -1;
+                       s->is_protected = -1;
+               }
+       } else {
+               /* code flash 8k x 8 + 32k x N */
+               info->is_data = 0;
+               num_pages = (info->size - 8 * 8192) / 32768 + 8;
+               bank->num_sectors = num_pages;
+               bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+               if (!bank->sectors)
+                       return ERROR_FAIL;
+               for (n = 0; n < 8; n++) {
+                       s = &bank->sectors[n];
+                       s->offset = n * 8192;
+                       s->size = 8192;
+                       s->is_erased = -1;
+                       s->is_protected = -1;
+               }
+               /* rest of sectors (bigger) */
+               for (; n < num_pages; n++) {
+                       s = &bank->sectors[n];
+                       s->offset = (n - 8) * 32768 + 8 * 8192;
+                       s->size = 32768;
+                       s->is_erased = -1;
+                       s->is_protected = -1;
+               }
+       }
+
+       retval = target_read_memory(bank->target, FACI_PNR, 4, 4, (uint8_t 
*)part_number);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Trim out end spaces */
+       for (int i = 15; i != 0; i--)
+               if (part_number[i] == ' ')
+                       part_number[i] = 0;
+               else
+                       break;
+
+       LOG_INFO("Renesas RV40 \"%s\" detected", part_number);
+
+       if (strncmp(part_number, "R7FA4M2", 7) == 0)
+               info->has_fmeprot = true;
+
+       info->probed = true;
+
+       return ERROR_OK;
+}
+
+static int rv40f_auto_probe(struct flash_bank *bank)
+{
+       struct renesas_bank *info = bank->driver_priv;
+
+       if (info->probed)
+               return ERROR_OK;
+
+       return rv40f_probe(bank);
+}
+
+const struct flash_driver renesas_rv40f_flash = {
+       .name = "renesas_rv40f",
+       .flash_bank_command = rv40f_flash_bank_command,
+       .erase = rv40f_erase,
+       .write = rv40f_write_block,
+       .read = default_flash_read,
+       .probe = rv40f_probe,
+       .auto_probe = rv40f_auto_probe,
+       .erase_check = default_flash_blank_check,
+       .free_driver_priv = default_flash_free_driver_priv,
+       .usage = "flash bank bank_id 'renesas_rv40f' base_address size"
+};

-- 

Reply via email to