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/+/8390

-- gerrit

commit d4cc10515e4239e3a8c5c33107c7e9d1878fc7c5
Author: Mark Featherston <m...@embeddedts.com>
Date:   Tue Jun 4 11:01:13 2024 -0700

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

diff --git a/contrib/loaders/flash/mf3.S b/contrib/loaders/flash/mf3.S
new file mode 100644
index 0000000000..d66cd3d0f5
--- /dev/null
+++ b/contrib/loaders/flash/mf3.S
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*
+ * This code is embedded within: src/flash/nor/sst_mf3.c as a "C" array.
+ * To rebuild:
+ *      arm-none-eabi-gcc -c mf3.S
+ *      arm-none-eabi-objcopy -O binary mf3.o mf3.bin
+ *      xxd -c 8 -i mf3.bin > mf3.txt
+ * Then read and edit this result into the "C" source.
+ */
+/***************************************************************************
+ *   Copyright (C) 2022 by Kevlar Harness                                  *
+ *   softw...@klystron.com                                                 *
+ ***************************************************************************/
+
+#define FACI_FPMCR                  0x407ec100            /* flash mode 
control register */
+
+/* offsets of other registers relative to FPMCR */
+#define FSARL                  0x08            /* start address (low 16 bits) 
*/
+#define FSARH                  0x10            /* start address (high 16 bits) 
*/
+#define FCR                    0x14            /* flash control register */
+#define FEARL                  0x18            /* end address (low 16 bits) */
+#define FEARH                  0x20            /* end address (high 16 bits) */
+#define FRESETR                0x24                    /* flash reset register 
*/
+#define FSTATR00               0x28
+#define FSTATR1                0x2c
+#define FWBL0                  0x30
+#define FWBH0                  0x38
+#define FSTATR01               0x3c
+#define FPR                    0x80            /* flash protection register */
+#define FPSR                   0x84            /* flash protection status 
register */
+#define FSTATR2                0xf0
+
+/* values used in the FCR register */
+#define FACI_FCR_CMD_PROGRAM       0x01                        /* program data 
*/
+#define FACI_FCR_OPST                          0x80                    /* 
start processing the command */
+
+/* values used in the FRESETR register */
+#define FACI_FRESETR_FRESET                    0x01            /* reset flash 
programming registers */
+
+/* values used in the FSTATR1 register */
+#define FACI_FSTATR1_FRDY                      0x40            /* command 
complete */
+
+/* values used in the FSTATR2 register */
+#define FACI_FSTATR2_ILGLERR           0x10            /* illegal command 
error flag */
+#define FACI_FSTATR2_ERERR                     0x01            /* erase error 
flag */
+
+/* mf3_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.
+ * Inputs:
+ *   r0 ulong ulCount - number of bytes 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:
+ *   r4 - count - number of bytes to write
+ *   r5 - R_FACI - base address of flash controller peripheral
+ *   r6 - source address (rotates in the area between r1 and r2)
+ *   r7 - working register
+ *   r10 - start address of the work area in RAM
+ *   r11 - end address of the work area in RAM
+ */
+
+       .syntax unified
+       .thumb
+       .thumb_func
+
+.global mf3_flash_write
+
+mf3_flash_write:
+       movs    r0, #0          /* r0 => result code (0 == no error) */
+       ldr     r5, =FACI_FPMCR /* r5 => base register address */
+       mov     r6, r1          /* r6 => source address */
+       mov     r10, r1         /* r10 => source start address*/
+       mov     r11, r2         /* r11 => source end address*/
+       movs    r4, r0          /* r4 => ulCount */
+       b.n     loop_end
+
+loop_start:
+       /* set the destination address */
+       mov     r7, r3
+       strh    r7, [r5, #FSARL]
+       lsrs    r7, r7, #16
+       strh    r7, [r5, #FSARH]
+
+       /* set the source address */
+       mov     r7, r6
+       strh    r7, [r5, #FWBL0]
+       lsrs    r7, r7, #16
+       strh    r7, [r5, #FWBH0]
+
+       /* trigger the write command */
+       movs    r7, #(FACI_FCR_OPST | FACI_FCR_CMD_PROGRAM)
+       strb    r7, [r5, #FCR]
+       nop
+
+wait_complete:
+       /* wait for the operation to complete */
+       ldr     r7, [r5, #FSTATR1]
+       movs    r3, #FACI_FSTATR1_FRDY
+       ands    r7, r3
+       beq.n   wait_complete
+
+       /* reset the command register */
+       movs    r7, #0
+       strb    r7, [r5, #FCR]
+       nop
+
+wait_clear:
+       /* wait for the command status register to clear */
+       ldr     r7, [r5, #FSTATR1]
+       movs    r3, #FACI_FSTATR1_FRDY
+       ands    r7, r3
+       bne.n   wait_complete
+
+       /* check for errors */
+       movs    r0, #FSTATR2
+       ldr     r0, [r5, r0]
+       mov     r7, r0
+       movs    r3, #(FACI_FSTATR2_ILGLERR | FACI_FSTATR2_ERERR)
+       ands    r7, r3
+       beq.n   no_error
+
+       /* an error has occurred - reset the error flags and exit */
+       movs    r7, #FACI_FRESETR_FRESET
+       str     r7, [r5, #FRESETR]
+       movs    r7, #0
+       str     r7, [r5, #FRESETR]
+       b.n     exit
+
+no_error:
+       /* increment the source pointer */
+       adds    r6, #4
+       cmp     r6, r11
+       bcc.n   no_wrap
+
+       /* wrap the source pointer round to the beginning of the source buffer 
*/
+       mov     r6, r10
+
+no_wrap:
+       /* increment the destination pointer */
+       adds    r3, #4
+
+       /* decrement the loop counter */
+       subs    r4, #4
+
+loop_end:
+       bne.n   loop_start
+
+exit:
+       movs    r0, #0x39
+       bkpt    #0
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index afa11e7d40..cec4229e42 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -63,6 +63,7 @@ NOR_DRIVERS = \
        %D%/sh_qspi.c \
        %D%/sim3x.c \
        %D%/spi.c \
+       %D%/sst_mf3.c \
        %D%/stmsmi.c \
        %D%/stmqspi.c \
        %D%/stellaris.c \
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index 211661e214..6991270c37 100644
--- a/src/flash/nor/driver.h
+++ b/src/flash/nor/driver.h
@@ -291,6 +291,7 @@ extern const struct flash_driver rp2040_flash;
 extern const struct flash_driver rsl10_flash;
 extern const struct flash_driver sh_qspi_flash;
 extern const struct flash_driver sim3x_flash;
+extern const struct flash_driver sst_mf3_flash;
 extern const struct flash_driver stellaris_flash;
 extern const struct flash_driver stm32f1x_flash;
 extern const struct flash_driver stm32f2x_flash;
@@ -299,6 +300,7 @@ extern const struct flash_driver stm32l4x_flash;
 extern const struct flash_driver stm32lx_flash;
 extern const struct flash_driver stmqspi_flash;
 extern const struct flash_driver stmsmi_flash;
+extern const struct flash_driver stmsmi_flash;
 extern const struct flash_driver str7x_flash;
 extern const struct flash_driver str9x_flash;
 extern const struct flash_driver str9xpec_flash;
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 34359889a6..f9951d98a1 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -67,6 +67,7 @@ static const struct flash_driver * const flash_drivers[] = {
        &rp2040_flash,
        &sh_qspi_flash,
        &sim3x_flash,
+       &sst_mf3_flash,
        &stellaris_flash,
        &stm32f1x_flash,
        &stm32f2x_flash,
diff --git a/src/flash/nor/sst_mf3.c b/src/flash/nor/sst_mf3.c
new file mode 100644
index 0000000000..8a7f3eb102
--- /dev/null
+++ b/src/flash/nor/sst_mf3.c
@@ -0,0 +1,687 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Kevlar Harness                                  *
+ *   softw...@klystron.com                                                 *
+ ***************************************************************************/
+
+/***************************************************************************
+ *
+ * New flash setup command:
+ *
+ * flash bank <id> sst_mf3 <base> <size> <buswidth> <chipwidth> <target#> 
[driver_options ...]
+ *
+ * The driver options specific to this driver are:
+ *   <is_data>
+ *     '0' indicates that the bank is a 'code flash' bank and
+ *     '1' indicates that the bank is a 'data flash' bank.
+ *       If the <is_data> parameter is not specified, then the
+ *       'mf3_probe' function assumes that the bank is a 'data flash'
+ *       bank if the address is 0x4010.xxxx and in the 'code flash'
+ *       otherwise.
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/binarybuffer.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+#include <target/cortex_m.h>
+
+#define FACI_SECTOR_SIZE_MF3        0x400       /* MF3 type flash is divided 
into 1 kib sectors */
+
+/* addresses of the FACI registers in the S124 (R7FS3A7) */
+#define FACI_FENTRYR                0x407effb2
+#define FACI_DFLCTL                 0x407ec090  /* data flash control register 
*/
+#define FACI_FPMCR                  0x407ec100  /* flash mode control register 
*/
+#define FACI_FSARL                  0x407ec108  /* start address (low 16 bits) 
*/
+#define FACI_FSARH                  0x407ec110  /* start address (high 16 
bits) */
+#define FACI_FCR                    0x407ec114  /* flash control register */
+#define FACI_FEARL                  0x407ec118  /* end address (low 16 bits) */
+#define FACI_FEARH                  0x407ec120  /* end address (high 16 bits) 
*/
+#define FACI_FRESETR                0x407ec124  /* flash reset register */
+#define FACI_FSTATR00               0x407ec128
+#define FACI_FSTATR1                0x407ec12c
+#define FACI_FSTATR01               0x407ec13c
+#define FACI_FPR                    0x407ec180  /* flash protection register */
+#define FACI_FPSR                   0x407ec184  /* flash protection status 
register */
+#define FACI_FISR                   0x407ec1d8  /* flash speed select register 
*/
+#define FACI_FSTATR2                0x407ec1f0
+
+
+/* values used in the FENTRY register */
+#define FACI_FENTRY_FEKEY           0xaa00      /* key value for the FENTRYR 
register */
+#define FACI_FENTRY_FENTRYD         0x80        /* set data flash to 
program/erase mode */
+#define FACI_FENTRY_FENTRY0         0x01        /* set the code flash to 
program/erase mode */
+#define FACI_FENTRY_READ_MODE       0x00        /* flash controller is in read 
(normal) mode */
+
+/* values used in the DFLCTL register */
+#define FACI_DFLCTL_DFLEN_ENABLE    0x01        /* enable access to the data 
flash */
+
+/* values used in the FPMCR register */
+#define FACI_FPMCR_FMS_10           0x10
+#define FACI_FPMCR_FMS_DISCHARGE1   0x12
+#define FACI_FPMCR_FMS_DISCHARGE2   0x92
+#define FACI_FPMCR_FMS_PROGRAM_CODE 0x82
+#define FACI_FPMCR_FMS_READ_MODE    0x00
+
+/* values used in the FCR register */
+#define FACI_FCR_CMD_PROGRAM        0x01        /* program data */
+#define FACI_FCR_CMD_BLANK_CHECK    0x03
+#define FACI_FCR_CMD_BLOCK_ERASE    0x04        /* block erase */
+#define FACI_FCR_CMD_READ           0x05
+#define FACI_FCR_CMD_CHIP_ERASE     0x06        /* chip erase */
+#define FACI_FCR_OPST               0x80        /* start processing the 
command */
+
+/* values used in the FRESETR register */
+#define FACI_FRESETR_FRESET         0x01        /* reset flash programming 
registers */
+
+/* values used in the FSTATR1 register */
+#define FACI_FSTATR1_DRRDY          0x02        /* read data is ready */
+#define FACI_FSTATR1_FRDY           0x40        /* command complete */
+#define FACI_FSTATR1_EXRDY          0x80        /* extra area command complete 
*/
+
+/* values used in the FPR register */
+#define FACI_FPR_UNLOCK             0xa5        /* unlock value for the 
protection unlock register */
+
+/* values used in the FISR register */
+#define FISR_PCKA_32MHZ             0x1f        /* the flash IF clock is 32MHz 
*/
+
+/* values used in the FSTATR2 register */
+#define FACI_FSTATR2_ILGLERR        0x10        /* illegal command error flag 
*/
+#define FACI_FSTATR2_ERERR          0x01        /* erase error flag */
+
+/* addresses of the SYSTEM registers in the S124 (R7FS3A7) */
+#define SYSTEM_OPCCR                0x4001e0a0
+#define SYSTEM_SCKSCR               0x4001e026
+#define SYSTEM_SCKSCR_CKSEL_HOCO    0x00        /* select HOCO as the source 
for ICLK */
+#define SYSTEM_PRCR                 0x4001e3fe
+
+/* the base address of the main flash area (executable code / data) */
+#define S124_PROGRAM_FLASH_BASE     0x00000000
+
+/* the base address of the data flash area */
+#define S124_DATA_FLASH_BASE        0x40100000
+
+/* additional data for each flash bank which is not part of the standard
+ * 'flash_bank' structure. A pointer to this structure is stored in
+ * 'flash_bank->driver_priv */
+struct renesas_bank {
+       bool is_data; /* 0 for 'code flash' or 1 for 'data flash' */
+       bool probed;  /* set when the bank has been probed */
+};
+
+const struct flash_driver sst_mf3_flash;
+
+FLASH_BANK_COMMAND_HANDLER(flash_bank_command)
+{
+       struct renesas_bank *info = NULL;
+
+       if (CMD_ARGC < 6)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       int bank_index = strtoul(CMD_ARGV[0], NULL, 0);
+
+       LOG_INFO("Processing 'flash bank' command for index %d at %08lx", 
bank_index, bank->base);
+
+       /* look for an existing flash structure matching target */
+       for (struct flash_bank *bank_iter = flash_bank_list(); bank_iter; 
bank_iter = bank_iter->next) {
+               if (bank_iter->driver == &sst_mf3_flash
+                       && bank_iter->target == bank->target
+                       && bank->driver_priv) {
+                       info = bank->driver_priv;
+                       break;
+               }
+       }
+
+       if (!info) {
+               /* target not matched, make a new one */
+               info = calloc(1, sizeof(struct renesas_bank));
+       }
+
+       bank->driver_priv = info;
+
+       return ERROR_OK;
+}
+
+/* This function sets the flash mode control register which can
+ * only be changed by:
+ *    - writing a key value to the FPR register
+ *    - writing the FPMCR value
+ *    - writing the inverse of the FPMCR value
+ *    - writing the FPMCR value again */
+static int select_flash_mode(struct target *target, uint8_t mode)
+{
+       int retval;
+
+       retval = target_write_u8(target, FACI_FPR, FACI_FPR_UNLOCK);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u8(target, FACI_FPMCR, mode);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u8(target, FACI_FPMCR, mode ^ 0xff);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u8(target, FACI_FPMCR, mode);
+
+       return retval;
+}
+
+/* This function sets the flash controller into programming or
+ * normal operation modes depending on the value of the 'enable'
+ * parameter. When placed into 'programming' mode the selects
+ * between 'program flash' or 'code flash' mode according to the
+ * 'is_data' parameter.*/
+static int set_programming_mode(struct target *target, bool enable, bool 
is_data)
+{
+       int retval;
+       uint16_t status16;      /* status read from the FENTRYR */
+       uint8_t status8;        /* status read from the FPSR */
+
+       if (enable) {
+               if (is_data)
+                       /* set data flash into programming mode */
+                       retval = target_write_u16(target, FACI_FENTRYR, 
FACI_FENTRY_FEKEY | FACI_FENTRY_FENTRYD);
+               else
+                       /* set code flash into programming mode */
+                       retval = target_write_u16(target, FACI_FENTRYR, 
FACI_FENTRY_FEKEY | FACI_FENTRY_FENTRY0);
+
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = select_flash_mode(target, FACI_FPMCR_FMS_DISCHARGE1);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* delay for (at least) the P/E mode transition time - tDIS 
(2uS) */
+               retval = target_read_u8 (target, FACI_FPSR, &status8);
+               if (retval != ERROR_OK)
+                       return retval;
+               if (status8 != 0) {
+                       LOG_ERROR("Failed to put flash in DISCHARGE1 mode");
+                       return ERROR_FAIL;
+               }
+
+               retval = select_flash_mode(target, FACI_FPMCR_FMS_DISCHARGE2);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = select_flash_mode(target, FACI_FPMCR_FMS_PROGRAM_CODE);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /*  delay for (at least) the mode setup time - tMS (5uS) */
+               retval = target_read_u8 (target, FACI_FPSR, &status8);
+               if (retval != ERROR_OK)
+                       return retval;
+               if (status8 != 0) {
+                       LOG_ERROR("Failed to put flash in PROGRAM mode");
+                       return ERROR_FAIL;
+               }
+
+               retval = target_write_u8(target, FACI_FISR, FISR_PCKA_32MHZ);
+               if (retval != ERROR_OK)
+                       return retval;
+       } else {
+               retval = select_flash_mode(target, FACI_FPMCR_FMS_DISCHARGE2);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* delay for (at least) the P/E mode transition time - tDIS 
(2uS) */
+               retval = target_read_u8 (target, FACI_FPSR, &status8);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if (status8 != 0) {
+                       LOG_ERROR("Failed to put flash in DISCHARGE2 mode");
+                       return ERROR_FAIL;
+               }
+
+               retval = select_flash_mode(target, FACI_FPMCR_FMS_DISCHARGE1);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = select_flash_mode(target, FACI_FPMCR_FMS_READ_MODE);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* read the status register twice in order to generate a delay 
of (at
+                * least) the mode setup time - tMS (5uS) */
+               retval = target_read_u8 (target, FACI_FPSR, &status8);
+               if (retval != ERROR_OK)
+                       return retval;
+               retval = target_read_u8 (target, FACI_FPSR, &status8);
+               if (retval != ERROR_OK)
+                       return retval;
+               if (status8 != 0)
+                       return ERROR_FAIL;
+
+               /* set the code flash back into read mode */
+               retval = target_write_u16(target, FACI_FENTRYR, 
FACI_FENTRY_FEKEY);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               for (int i = 0; i < 10; i++) {
+                       /* wait for the flash to return to read mode */
+                       retval = target_read_u16 (target, FACI_FENTRYR, 
&status16);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       if (status16 == FACI_FENTRY_READ_MODE)
+                               break;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+/* This function does not place the flash into programming mode as
+* this is done in 'mf3_erase' before potentially calling this
+* function multiple times to erase successive pages. */
+static int mf3_erase_page(struct flash_bank *bank, uint32_t addr)
+{
+       int retval = ERROR_OK;
+       uint16_t status16 = 0;
+       uint8_t status8 = 0;
+       struct target *target = bank->target;
+       uint32_t timeout;
+
+       LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr);
+
+       /* write the start address of the sector to be erased */
+       retval = target_write_u16(target, FACI_FSARL, (addr >> 0));
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u16(target, FACI_FSARH, (addr >> 16));
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* write the end address of the sector to be erased */
+       addr = addr + bank->size;
+       retval = target_write_u16(target, FACI_FEARL, ((addr + 
FACI_SECTOR_SIZE_MF3 - 1) >> 0));
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u16(target, FACI_FEARH, ((addr + 
FACI_SECTOR_SIZE_MF3 - 1) >> 16));
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* trigger the erase command */
+       retval = target_write_u8(target, FACI_FCR, FACI_FCR_OPST | 
FACI_FCR_CMD_BLOCK_ERASE);
+       if (retval != ERROR_OK)
+               return retval;
+
+       for (timeout = 0; timeout < 20; timeout++) {
+               /* wait for the erase operation to complete */
+               alive_sleep(10);
+
+               retval = target_read_u8(target, FACI_FSTATR1, &status8);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if ((status8 & FACI_FSTATR1_FRDY) != 0)
+                       break;
+       }
+
+       /* reset the command register */
+       retval = target_write_u8(target, FACI_FCR, 0);
+       if (retval != ERROR_OK)
+               return retval;
+
+       for (timeout = 0; timeout < 20; timeout++) {
+               /* wait for the result flag to clear */
+               retval = target_read_u8(target, FACI_FSTATR1, &status8);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if ((status8 & FACI_FSTATR1_FRDY) == 0)
+                       break;
+       }
+
+       /* check if any error flags have been set */
+       retval = target_read_u16(target, FACI_FSTATR2, &status16);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if ((status16 & (FACI_FSTATR2_ILGLERR | FACI_FSTATR2_ERERR)) != 0) {
+               /* an error occurred - reset the error flags */
+               retval = target_write_u8(target, FACI_FRESETR, 
FACI_FRESETR_FRESET);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = target_write_u8(target, FACI_FRESETR, 0);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = ERROR_FAIL;
+       }
+
+       return retval;
+}
+
+static int mf3_erase(struct flash_bank *bank, unsigned int first,
+       unsigned int last)
+{
+       struct target *target = bank->target;
+       struct renesas_bank *info = bank->driver_priv;
+       int retval = ERROR_OK;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!info) {
+               LOG_ERROR("Bank info not configured");
+               return ERROR_FAIL;
+       }
+
+       /* place the flash controller into programming mode */
+       set_programming_mode(target, true, info->is_data);
+
+       for (unsigned int i = first; i <= last; i++) {
+               retval = mf3_erase_page(bank, bank->base + 
bank->sectors[i].offset);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Failed to erase sector %d", i);
+                       break;
+               }
+       }
+
+       /* place the flash controller into normal operation mode */
+       set_programming_mode(target, false, info->is_data);
+
+       return retval;
+}
+
+static int mf3_protect(struct flash_bank *bank, int set, unsigned int first,
+       unsigned int last)
+{
+       struct target *target = bank->target;
+       int retval = ERROR_OK;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       LOG_ERROR("sector protection is not supported yet");
+
+       return retval;
+}
+
+
+
+/* uint32_t count - number of bytes to write (in R0)
+ * uint32_t workarea_start - address of the start of the work area (in R1)
+ * uint32_t workarea_end - address of the end of the work area (in R2)
+ * uint32_t dest - destination address in flash (in R3)
+ * Returns:     result (in R0) */
+static const uint8_t mf3_flash_write_code[] = {
+       0x1b, 0x4d, 0x04, 0x46, 0x8a, 0x46, 0x93, 0x46,
+       0x00, 0x20, 0x1f, 0x46, 0x2f, 0x81, 0x3f, 0x0c,
+       0x2f, 0x82, 0x29, 0xe0, 0x1f, 0x0e, 0x05, 0xd0,
+       0x0f, 0x78, 0x2f, 0x86, 0x01, 0x31, 0x01, 0x3c,
+       0x06, 0xe0, 0xc0, 0x46, 0x0f, 0x68, 0x2f, 0x86,
+       0x3f, 0x0c, 0x2f, 0x87, 0x04, 0x31, 0x04, 0x3c,
+       0x81, 0x27, 0x2f, 0x75, 0xc0, 0x46, 0xef, 0x6a,
+       0x40, 0x26, 0x37, 0x40, 0xfb, 0xd0, 0x00, 0x27,
+       0x2f, 0x75, 0xc0, 0x46, 0xef, 0x6a, 0x40, 0x26,
+       0x37, 0x40, 0xfb, 0xd1, 0xf0, 0x20, 0x28, 0x58,
+       0x07, 0x46, 0x11, 0x26, 0x37, 0x40, 0x04, 0xd0,
+       0x01, 0x27, 0x6f, 0x62, 0x00, 0x27, 0x6f, 0x62,
+       0x04, 0xe0, 0x59, 0x45, 0x00, 0xd3, 0x51, 0x46,
+       0x24, 0x40, 0xd3, 0xd1, 0x00, 0xbe, 0x00, 0x00,
+       0x00, 0xc1, 0x7e, 0x40
+};
+
+static int mf3_write(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;
+
+       /* Todo: check if bank is locked/protected? before trying to write */
+
+       /* Increase buffer_size if needed */
+       if (buffer_size < (target->working_area_size / 2))
+               buffer_size = (target->working_area_size / 2);
+
+
+       if (!info->is_data) {
+               /* check alignment - code flash */
+               if ((offset & 0x03) != 0) {
+                       LOG_WARNING("offset 0x%" PRIx32 " is not word aligned", 
offset);
+                       return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+               }
+       }
+
+       /* allocate a buffer to hold the flash write function */
+       /* this is allocated from the "work area" declared in the target 
configuration file */
+       if (target_alloc_working_area(target, sizeof(mf3_flash_write_code) + 8,
+               &write_algorithm) != ERROR_OK) {
+               LOG_WARNING("no working area available, can't do block memory 
writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       /* allocate a buffer to hold the blocks of data to be written */
+       while (target_alloc_working_area(target, buffer_size, &source) != 
ERROR_OK) {
+               buffer_size /= 2;       /* halve the size of the requested 
buffer */
+               buffer_size &= ~3;      /* make sure it's 4 byte aligned */
+               if (buffer_size <= 256) {
+                       /* give up if a buffer larger than 256 bytes cannot be 
allocated */
+                       target_free_working_area(target, write_algorithm);
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       }
+
+       /* copy the 'mf3_flash_write_code' function into RAM */
+       retval = target_write_buffer(target, write_algorithm->address,
+       sizeof(mf3_flash_write_code), mf3_flash_write_code);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* place the flash controller into programming mode */
+       retval = set_programming_mode(target, true, info->is_data);
+       if (retval != ERROR_OK)
+               return retval;
+
+       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+       armv7m_info.core_mode = ARM_MODE_THREAD;
+
+       /* declare the parameters to the write function */
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* number of 
bytes 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 */
+
+       /* so obscure: dataflash has a different address for write from P/E 
mode,
+       we must add a difference (0xfe00 0000 - 0x4010 0000) (M.S.) */
+       if (info->is_data)
+               address += 0xbdf00000;
+
+       while (count > 0) {
+               thisrun_count = buffer_size;
+               if (thisrun_count > count)
+                       thisrun_count = count;
+
+               /* copy the next chunk of data into RAM on the target */
+               retval = target_write_buffer(target, source->address, 
thisrun_count, buffer);
+               if (retval != ERROR_OK)
+                       break;
+
+               /* set the parameters for the write function */
+               buf_set_u32(reg_params[0].value, 0, 32, thisrun_count);
+               buf_set_u32(reg_params[1].value, 0, 32, 
(intptr_t)source->address);
+               buf_set_u32(reg_params[2].value, 0, 32, 
(intptr_t)(source->address + thisrun_count));
+               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("flash write function returned %04x", retval);
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               if (count >= thisrun_count) {
+                       /* increment the source and destination pointers */
+                       buffer  += thisrun_count;
+                       address += thisrun_count;
+                       /* decrement the byte counter */
+                       count   -= thisrun_count;
+               } else {
+                       break;
+               }
+       }
+
+       /* place the flash controller into normal operation mode */
+       /* (retain the current status in 'retval') */
+       (void)set_programming_mode(target, false, info->is_data);
+
+       /* free the allocated buffers */
+       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]);
+
+       return retval;
+}
+
+/* Renesas seem to have defined a structure called the "Factory MCU
+ * Information Flash Root Table (FMIFRT)" which may contain
+ * information to allow firmware to automatically determine the
+ * configuration of the flash. However, it also appears that the
+ * R6AM2 is the *only* device to actually contain this table!
+ *
+ * Therefore, as automatically detecting the flash configuration
+ * of most Renesas devices seems impossible, the addresses and
+ * sizes of each flash bank need to be specified in the target
+ * configuration file. */
+static int mf3_probe(struct flash_bank *bank)
+{
+       struct renesas_bank *info = bank->driver_priv;
+       uint8_t data_flash_enable;
+
+       LOG_DEBUG("probing bank %d at %08lx", bank->bank_number, bank->base);
+
+       /* fill in the details in the common 'flash_bank' structure */
+       bank->num_sectors = bank->size / FACI_SECTOR_SIZE_MF3;
+
+       bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+
+       for (uint32_t i = 0; i < bank->num_sectors; i++) {
+               bank->sectors[i].offset = i * FACI_SECTOR_SIZE_MF3;
+               bank->sectors[i].size = FACI_SECTOR_SIZE_MF3;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 1;
+       }
+
+       /* fill in the details in the additional 'renesas_bank' structure */
+       info->probed = true;
+
+       if ((bank->base >> 24) == 0x00)
+               info->is_data = false;      /* the address is in the 'code 
flash' */
+       else
+               info->is_data = true;       /* the address is in the 'data 
flash' */
+
+       if (info->is_data) {
+               /* check that the data flash is enabled */
+               target_read_u8 (bank->target, FACI_DFLCTL, &data_flash_enable);
+
+               if (data_flash_enable != FACI_DFLCTL_DFLEN_ENABLE) {
+                       LOG_INFO("Enabling data flash access");
+                       target_write_u8(bank->target, FACI_DFLCTL, 
FACI_DFLCTL_DFLEN_ENABLE);
+                       target_read_u8 (bank->target, FACI_DFLCTL, 
&data_flash_enable);
+                       if (data_flash_enable != FACI_DFLCTL_DFLEN_ENABLE) {
+                               LOG_ERROR("Failed to enable data flash access");
+                               return ERROR_FAIL;
+                       }
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int mf3_auto_probe(struct flash_bank *bank)
+{
+       struct renesas_bank *info = bank->driver_priv;
+       uint8_t operating_mode;
+       uint8_t system_clock_select;
+
+       /* check that the HOCO clock is selected */
+       target_read_u8 (bank->target, SYSTEM_SCKSCR, &system_clock_select);
+       if (system_clock_select != SYSTEM_SCKSCR_CKSEL_HOCO) {
+               LOG_INFO("Selecting HOCO clock");
+               target_write_u16(bank->target, SYSTEM_PRCR, 0xa503);
+               target_write_u8(bank->target, SYSTEM_SCKSCR, 
SYSTEM_SCKSCR_CKSEL_HOCO);
+               target_read_u8 (bank->target, SYSTEM_SCKSCR, 
&system_clock_select);
+               if (system_clock_select != SYSTEM_SCKSCR_CKSEL_HOCO) {
+                       LOG_ERROR("Failed to select HOCO clock");
+                       return ERROR_FAIL;
+               }
+       }
+
+       /* check the operating mode of the processor */
+       target_read_u8 (bank->target, SYSTEM_OPCCR, &operating_mode);
+       if (operating_mode != SYSTEM_SCKSCR_CKSEL_HOCO) {
+               LOG_INFO("Selecting high-speed mode");
+               target_write_u16(bank->target, SYSTEM_PRCR, 0xa503);
+               target_write_u8(bank->target, SYSTEM_OPCCR, 
SYSTEM_SCKSCR_CKSEL_HOCO);
+               target_read_u8 (bank->target, SYSTEM_OPCCR, &operating_mode);
+               if (operating_mode != SYSTEM_SCKSCR_CKSEL_HOCO) {
+                       LOG_ERROR("Failed to select high-speed mode");
+                       return ERROR_FAIL;
+               }
+       }
+
+       info->probed = false;
+       if (info->probed)
+               return ERROR_OK; /* the bank has already been probed */
+
+       return mf3_probe(bank);
+}
+
+static const struct command_registration mf3_command_handlers[] = {
+       {
+               .name = "mf3",
+               .mode = COMMAND_ANY,
+               .help = "mf3 flash command group",
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct flash_driver sst_mf3_flash = {
+       .name = "sst_mf3",
+       .commands = mf3_command_handlers,
+       .flash_bank_command = flash_bank_command,
+       .erase = mf3_erase,
+       .protect = mf3_protect,
+       .write = mf3_write,
+       .read = default_flash_read,
+       .probe = mf3_probe,
+       .auto_probe = mf3_auto_probe,
+       .erase_check = default_flash_blank_check,
+       .free_driver_priv = default_flash_free_driver_priv,
+       .usage = "flash bank bank_id 'sst_mf3' base_address"
+};

-- 

Reply via email to