Hi all,
this patch contain support for programming/erasing MCUs with RV40F type
memory inside (RA6M1, RA6M2, RA6M3, RA6T1 series).
Erasing and programming worked on R6AM2 MCUs.
Locking/unlocking not implemented. Only programming/erasing of memory
working.
Miloslav
diff --git a/contrib/loaders/flash/rv40f.S b/contrib/loaders/flash/rv40f.S
new file mode 100644
index 000000000..12449c737
--- /dev/null
+++ b/contrib/loaders/flash/rv40f.S
@@ -0,0 +1,159 @@
+/**************************************************************************************************
+*
+* File: rv40f.s
+*
+* Description: This file contains flash writing functions for SST's "RV40F" type flash cells which
+* are used in the Renesas R6AM2 processor.
+*
+* 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.
+*
+*
+* Contents: 01 Constant declarations
+*
+* 02 Public functions
+* rv40f_flash_write
+*
+**************************************************************************************************/
+
+
+/**************************************************************************************************
+*
+* 01 Constant declarations
+*
+**************************************************************************************************/
+
+#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 adress 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 FSTAT register */
+#define FSTAT_DBFUL 0x400
+
+/**************************************************************************************************
+*
+* 02 Public functions
+*
+**************************************************************************************************/
+
+/**************************************************************************************************
+*
+* Function: rv40f_flash_write
+*
+* 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
+*
+* Description: 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.
+*
+* Note: The arguments to this function match the arguments passed by OpenOCD to its flash
+* loader functions.
+*
+**************************************************************************************************/
+
+ .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
+
+loopStart:
+
+ /* 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 */
+waitDBFULL:
+ movs r0, #FSTATR
+ adds r0, r5
+ ldr r1, [r0]
+ /* check DBFULL bit */
+ ldr r0, =FSTATR_DBFUL
+ tst r0, r1
+ bne waitDBFULL
+ b loopStart
+
+/* complete transaction by writting 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 a5ef42210..7edbbd1f6 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -53,6 +53,7 @@ NOR_DRIVERS = \
%D%/psoc5lp.c \
%D%/psoc6.c \
%D%/renesas_rpchf.c \
+ %D%/renesas_rv40f.c \
%D%/rp2040.c \
%D%/sfdp.c \
%D%/sh_qspi.c \
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 3e35c0954..62bf6ac29 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -68,6 +68,7 @@ extern const struct flash_driver psoc5lp_eeprom_flash;
extern const struct flash_driver psoc5lp_nvl_flash;
extern const struct flash_driver psoc6_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 sh_qspi_flash;
extern const struct flash_driver sim3x_flash;
@@ -143,6 +144,7 @@ static const struct flash_driver * const flash_drivers[] = {
&psoc5lp_nvl_flash,
&psoc6_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 000000000..df68a8387
--- /dev/null
+++ b/src/flash/nor/renesas_rv40f.c
@@ -0,0 +1,560 @@
+/***************************************************************************
+ * Copyright (c) 2022 Miloslav Semler *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+/* 29-Mar-22: Minor changes to make it compile. (KH) */
+/* 29-Mar-22: Added 'const struct flash_driver' at the end so that the
+ driver can be added to OpenOCD (KH) */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/binarybuffer.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+/* FACI registers */
+#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
+
+/* register bits */
+#define FACI_FSTATR_FLWEERR 0x0040
+#define FACI_FSTATR_PRGSPD 0x0100
+#define FACI_FSTATR_ERSSPD 0x0200
+#define FACI_FSTATR_DBFULL 0x0400
+#define FACI_FSTATR_SUSRDY 0x0800
+#define FACI_FSTATR_PRGERR 0x1000
+#define FACI_FSTATR_ERSERR 0x2000
+#define FACI_FSTATR_ILGLERR 0x4000
+#define FACI_FSTATR_FRDY 0x8000
+#define FACI_FSTATR_OTERR 0x100000
+#define FACI_FSTATR_SECERR 0x200000
+#define FACI_FSTATR_FESETERR 0x400000
+#define FACI_FSTATR_ILGCOMERR 0x800000
+
+#define FACI_FASTAT_CFAE 0x80
+#define FACI_FASTAT_CMDLK 0x10
+#define FACI_FASTAT_DFAE 0x08
+
+
+struct renesas_bank {
+ /* bank size in bytes */
+ unsigned size;
+ /* base address */
+ unsigned base;
+ /* 1 for data flash or 0 for program flash */
+ unsigned is_data;
+ bool probed;
+};
+
+FLASH_BANK_COMMAND_HANDLER(rv40f_flash_bank_command)
+{
+ struct renesas_bank *info;
+
+ /* base address */
+ unsigned base = strtoul(CMD_ARGV[1], NULL, 16);
+ /* memory size */
+ unsigned size = strtoul(CMD_ARGV[2], NULL, 16);
+
+ info = malloc(sizeof(struct renesas_bank));
+ bank->driver_priv = info;
+
+ info->base = base;
+ info->size = size;
+ info->is_data = 0; /* assume program flash initially */
+ info->probed = false;
+
+ return ERROR_OK;
+}
+
+/* Data polling algorithm */
+static int rv40f_busy_wait(struct target *target, int timeout_ms)
+{
+ int retval = ERROR_OK;
+ int ms =0;
+ uint32_t reg32;
+
+ do {
+ /* read status register FSTATR */
+ retval = target_read_u32(target, FACI_FSTATR, ®32);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* No ERASE/PROGRAM operation in progress */
+ if(reg32 & FACI_FSTATR_FRDY){
+ break;
+ }
+
+ usleep(1000);
+ ++ms;
+
+ /* Polling time exceeded? */
+ if (ms > timeout_ms) {
+ LOG_ERROR("Waiting on FSTATR->FRDY timed out!");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ } while(1);
+
+ if (retval == ERROR_OK)
+ LOG_DEBUG("rv40f_busy_wait() took about %d ms", ms);
+
+ return retval;
+}
+
+static int rv40f_unlock(struct target *target)
+{
+ uint32_t reg32;
+ uint8_t reg8;
+ int retval;
+
+ LOG_ERROR("Unlocking FACI after lockup.");
+
+ /* we do not need check FRDY flag, as we check it in all functions */
+ retval = target_read_u32(target, FACI_FSTATR, ®32);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ if(reg32 & FACI_FSTATR_ILGLERR){
+ retval = target_read_u8(target, FACI_FASTAT, ®8);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* reset FAE 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;
+ }
+ }
+
+ /* issue force stop command - 3B */
+ retval = target_write_u8(target, FACI_CMD_AREA, 0x3B);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = rv40f_busy_wait(target, 1000);
+
+ 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;
+
+ 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, ®8);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* check CMDLK bit */
+ if (reg8 & 0x10){
+ rv40f_unlock(target);
+ 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, ®32);
+
+ 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;
+
+ /* set P/E mode according to base address (FENTRYR) */
+ if(info->is_data){
+ /* data flash */
+ retval = target_write_u16(bank->target, FACI_FENTRYR, 0xAA80);
+ }else{
+ /* code flash */
+ 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(info->is_data && (r16 & 0xaa80) == 0x80){
+ LOG_INFO("FACI in data flash P/E mode ...");
+ }else if((r16 & 0xaa01) == 0x1){
+ LOG_INFO("FACI in program flash P/E mode ...");
+ }else{
+ LOG_ERROR("Flash not in P/E mode");
+ 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 offset = bank->sectors[sector].offset;
+
+ /* start adddress */
+ 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, 0x20);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = target_write_u8(target, FACI_CMD_AREA, 0xd0);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = rv40f_complete(target, 500);
+
+ 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 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) */
+
+ static const uint8_t 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, 0x00, 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(®_params[0], "r0", 32, PARAM_OUT); /* number of halfwords to program */
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* source start address */
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* source end address */
+ init_reg_param(®_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_complete(target, 1000);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* decrement counters */
+ if(count >= thisrun_count){
+ buffer += thisrun_count * 2;
+ address += thisrun_count * 2;
+ count -= thisrun_count;
+ }else{
+ count = 0;
+ break;
+ }
+ }
+
+ /* switch back to readonly after operation */
+ retval = rv40f_to_readonly(target);
+
+ target_free_working_area(target, source);
+ target_free_working_area(target, write_algorithm);
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+
+ return retval;
+}
+
+static int rv40f_probe(struct flash_bank *bank)
+{
+ struct renesas_bank *info = bank->driver_priv;
+ struct flash_sector *s;
+ unsigned n, num_pages;
+
+ 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 */
+
+ /* data flash - same for all types */
+ if(info->base > 0){
+ 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);
+ 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;
+ }
+ /* code flash 8k x 8 + 32k x N */
+ }else{
+ 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);
+ 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;
+ }
+ }
+
+ 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);
+}
+
+/* this is the public interface to this module. 'renesas_rv40f_flash' is added to the list of
+ * available flash drivers in 'drivers.c'
+ */
+const struct flash_driver renesas_rv40f_flash = {
+ .name = "renesas_rv40f",
+ /* .commands = ??, */
+ .flash_bank_command = rv40f_flash_bank_command,
+ .erase = rv40f_erase,
+ /* .protect = ??, */
+ .write = rv40f_write_block,
+ .read = default_flash_read,
+ .probe = rv40f_probe,
+ .auto_probe = rv40f_auto_probe,
+ .erase_check = default_flash_blank_check,
+ /* .protect_check = ??, */
+ /* .info = ??, */
+ .free_driver_priv = default_flash_free_driver_priv,
+ .usage = "flash bank bank_id 'renesas_rv40f' base_address size"
+};
+