This is an automated email from Gerrit.

Marek Vasut (marek.va...@gmail.com) just uploaded a new patch set to Gerrit, 
which you can find at http://openocd.zylin.com/5143

-- gerrit

commit 47bb85cedb112c568d5c47bdb6d0c147cf256d71
Author: Marek Vasut <marek.va...@gmail.com>
Date:   Tue Apr 2 16:44:18 2019 +0200

    flash/nor/sh_qspi: Add SH QSPI driver
    
    Add driver for the SH QSPI controller. This SPI controller is often
    connected to the boot SPI NOR flash on R-Car Gen2 platforms.
    
    Add the following two lines to board TCL file to bind the driver on
    R-Car Gen2 SoC and make SRAM work area available:
    
      flash bank flash0 sh_qspi 0xe6b10000 0 0 0 ${_TARGETNAME}0 cs0
      ${_TARGETNAME}0 configure -work-area-phys 0xe6300000 -work-area-virt 
0xe6300000 -work-area-size 0x10000 -work-area-backup 0
    
    To install mainline U-Boot on the board, use the following procedure:
    
      proc update_uboot {} {
        # SPL
        flash erase_sector 0 0x0 0x0
        flash write_bank 0 /u-boot/spl/u-boot-spl.bin 0x0
        # U-Boot
        flash erase_sector 0 0x5 0x6
        flash write_bank 0 /u-boot/u-boot.img 0x140000
      }
    
    Change-Id: Ief22f61e93bcabae37f6e371156dece6c4be3459
    Signed-off-by: Marek Vasut <marek.va...@gmail.com>

diff --git a/contrib/loaders/flash/sh_qspi.s b/contrib/loaders/flash/sh_qspi.s
new file mode 100644
index 0000000..f83664c
--- /dev/null
+++ b/contrib/loaders/flash/sh_qspi.s
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SH QSPI (Quad SPI) driver
+ * Copyright (C) 2019 Marek Vasut <marek.va...@gmail.com>
+ */
+
+#define BIT(n)         (1UL << (n))
+/* SH QSPI register bit masks <REG>_<BIT> */
+#define SPCR_MSTR      0x08
+#define SPCR_SPE       0x40
+#define SPSR_SPRFF     0x80
+#define SPSR_SPTEF     0x20
+#define SPPCR_IO3FV    0x04
+#define SPPCR_IO2FV    0x02
+#define SPPCR_IO1FV    0x01
+#define SPBDCR_RXBC0   BIT(0)
+#define SPCMD_SCKDEN   BIT(15)
+#define SPCMD_SLNDEN   BIT(14)
+#define SPCMD_SPNDEN   BIT(13)
+#define SPCMD_SSLKP    BIT(7)
+#define SPCMD_BRDV0    BIT(2)
+#define SPCMD_INIT1    SPCMD_SCKDEN | SPCMD_SLNDEN | \
+                       SPCMD_SPNDEN | SPCMD_SSLKP | \
+                       SPCMD_BRDV0
+#define SPCMD_INIT2    SPCMD_SPNDEN | SPCMD_SSLKP | \
+                       SPCMD_BRDV0
+#define SPBFCR_TXRST   BIT(7)
+#define SPBFCR_RXRST   BIT(6)
+#define SPBFCR_TXTRG   0x30
+#define SPBFCR_RXTRG   0x07
+
+/* SH QSPI register set */
+#define SH_QSPI_SPCR           0x00
+#define SH_QSPI_SSLP           0x01
+#define SH_QSPI_SPPCR          0x02
+#define SH_QSPI_SPSR           0x03
+#define SH_QSPI_SPDR           0x04
+#define SH_QSPI_SPSCR          0x08
+#define SH_QSPI_SPSSR          0x09
+#define SH_QSPI_SPBR           0x0a
+#define SH_QSPI_SPDCR          0x0b
+#define SH_QSPI_SPCKD          0x0c
+#define SH_QSPI_SSLND          0x0d
+#define SH_QSPI_SPND           0x0e
+#define SH_QSPI_DUMMY0         0x0f
+#define SH_QSPI_SPCMD0         0x10
+#define SH_QSPI_SPCMD1         0x12
+#define SH_QSPI_SPCMD2         0x14
+#define SH_QSPI_SPCMD3         0x16
+#define SH_QSPI_SPBFCR         0x18
+#define SH_QSPI_DUMMY1         0x19
+#define SH_QSPI_SPBDCR         0x1a
+#define SH_QSPI_SPBMUL0                0x1c
+#define SH_QSPI_SPBMUL1                0x20
+#define SH_QSPI_SPBMUL2                0x24
+#define SH_QSPI_SPBMUL3                0x28
+
+.syntax unified
+.arm
+.text
+
+.macro wait_for_spsr, spsrbit
+       1:      ldrb    r12, [r0, #SH_QSPI_SPSR]
+               tst     r12, \spsrbit
+               beq     1b
+.endm
+
+.macro sh_qspi_xfer
+       bl      sh_qspi_cs_activate
+       str     r6, [r0, SH_QSPI_SPBMUL0]
+       bl      sh_qspi_xfer_common
+       bl      sh_qspi_cs_deactivate
+.endm
+
+.macro sh_qspi_write_enable
+       ldr     r4,     =SPIFLASH_WRITE_ENABLE
+       adr     r5,     _start
+       add     r4,     r5
+       mov     r5,     #0x0
+       mov     r6,     #0x1
+       sh_qspi_xfer
+.endm
+
+.macro sh_qspi_wait_till_ready
+       1:      ldr     r4,     =SPIFLASH_READ_STATUS
+               adr     r5,     _start
+               add     r4,     r5
+               mov     r5,     #0x0
+               mov     r6,     #0x2
+               sh_qspi_xfer
+               and     r13,    #0x1
+               cmp     r13,    #0x1
+               beq     1b
+.endm
+
+/*
+ * r0: controller base address
+ * r1: data buffer base address
+ * r2: BIT(31) -- page program (not read)
+ *     BIT(30) -- 4-byte address (not 3-byte)
+ *     BIT(29) -- 512-byte page (not 256-byte)
+ *     BIT(27:20) -- SF command
+ *     BIT(19:0)  -- amount of data to read/write
+ * r3: SF target address
+ *
+ * r7: data size
+ * r8: page size
+ *
+ * r14: lr, link register
+ * r15: pc, program counter
+ *
+ * Clobber: r4, r5, r6, r7, r8
+ */
+
+.global _start
+_start:
+       bic     r7,     r2, #0xff000000
+       bic     r7,     r7, #0x00f00000
+
+       and     r8,     r2, #(1 << 31)
+       cmp     r8,     #(1 << 31)
+       beq     do_page_program
+
+/* fast read */
+
+       bl      sh_qspi_cs_activate
+
+       bl      sh_qspi_setup_command
+       add     r8, r6, r7
+       str     r8, [r0, SH_QSPI_SPBMUL0]
+       bl      sh_qspi_xfer_common
+
+       mov     r4,     #0x0
+       mov     r5,     r1
+       mov     r6,     r7
+       bl      sh_qspi_xfer_common
+
+       bl      sh_qspi_cs_deactivate
+
+       b end
+
+do_page_program:
+
+       mov     r8,     #0x100
+       tst     r2,     (1 << 29)
+       movne   r8,     #0x200
+
+do_pp_next_page:
+       /* Check if less then page bytes left. */
+       cmp     r7,     r8
+       movlt   r8,     r7
+
+       sh_qspi_write_enable
+
+       bl      sh_qspi_cs_activate
+
+       bl      sh_qspi_setup_command
+       str     r6, [r0, SH_QSPI_SPBMUL0]
+       bl      sh_qspi_xfer_common
+
+       mov     r4,     r1
+       mov     r5,     #0x0
+       mov     r6,     r8
+
+       bl      sh_qspi_xfer_common
+
+       bl      sh_qspi_cs_deactivate
+
+       sh_qspi_wait_till_ready
+
+       add     r1,     r8
+       add     r3,     r8
+       sub     r7,     r8
+       cmp     r7,     #0
+
+       bne     do_pp_next_page
+
+end:
+       bkpt    #0
+
+sh_qspi_cs_activate:
+       /* Set master mode only */
+       mov     r12,    #SPCR_MSTR
+       strb    r12,    [r0, SH_QSPI_SPCR]
+
+       /* Set command */
+       mov     r12,    #SPCMD_INIT1
+       strh    r12,    [r0, SH_QSPI_SPCMD0]
+
+       /* Reset transfer and receive Buffer */
+       ldrb    r12,    [r0, SH_QSPI_SPSCR]
+       orr     r12,    #(SPBFCR_TXRST | SPBFCR_RXRST)
+       strb    r12,    [r0, SH_QSPI_SPBFCR]
+
+       /* Clear transfer and receive Buffer control bit */
+       ldrb    r12,    [r0, SH_QSPI_SPBFCR]
+       bic     r12,    #(SPBFCR_TXRST | SPBFCR_RXRST)
+       strb    r12,    [r0, SH_QSPI_SPBFCR]
+
+       /* Set sequence control method. Use sequence0 only */
+       mov     r12,    #0x00
+       strb    r12,    [r0, SH_QSPI_SPSCR]
+
+       /* Enable SPI function */
+       ldrb    r12,    [r0, SH_QSPI_SPCR]
+       orr     r12,    #SPCR_SPE
+       strb    r12,    [r0, SH_QSPI_SPCR]
+
+       mov     pc,     lr
+
+sh_qspi_cs_deactivate:
+       /* Disable SPI function */
+       ldrb    r12,    [r0, SH_QSPI_SPCR]
+       bic     r12,    #SPCR_SPE
+       strb    r12,    [r0, SH_QSPI_SPCR]
+
+       mov     pc,     lr
+
+/*
+ * r0, controller base address
+ * r4, tx buffer
+ * r5, rx buffer
+ * r6, xfer len, non-zero
+ *
+ * Upon exit, r13 contains the last byte in SPDR
+ *
+ * Clobber: r11, r12, r13
+ */
+sh_qspi_xfer_common:
+prepcopy:
+       ldr     r13, [r0, #SH_QSPI_SPBFCR]
+       orr     r13, #(SPBFCR_TXTRG | SPBFCR_RXTRG)
+       mov     r11, #32
+       cmp     r6, #32
+
+       biclt   r13, #(SPBFCR_TXTRG | SPBFCR_RXTRG)
+       movlt   r11, #1
+
+copy:
+       str     r13, [r0, #SH_QSPI_SPBFCR]
+
+       wait_for_spsr SPSR_SPTEF
+
+       mov     r12, r11
+       mov     r13, #0
+       cmp     r4, #0
+       beq     3f
+
+2:     ldrb    r13, [r4], #1
+       strb    r13, [r0, #SH_QSPI_SPDR]
+       subs    r12, #1
+       bne     2b
+       b       4f
+
+3:     strb    r13, [r0, #SH_QSPI_SPDR]
+       subs    r12, #1
+       bne     3b
+
+4:     wait_for_spsr SPSR_SPRFF
+
+       mov     r12, r11
+       cmp     r5, #0
+       beq     6f
+
+5:     ldrb    r13, [r0, #SH_QSPI_SPDR]
+       strb    r13, [r5], #1
+       subs    r12, #1
+       bne     5b
+       b       7f
+
+6:     ldrb    r13, [r0, #SH_QSPI_SPDR]
+       subs    r12, #1
+       bne     6b
+
+7:     subs    r6, r11
+       bne     prepcopy
+
+       mov     pc,     lr
+
+sh_qspi_setup_command:
+       ldr     r4,     =SPIFLASH_SCRATCH_DATA
+       adr     r5,     _start
+       add     r4,     r5
+       and     r12,    r2, #0x0ff00000
+       lsr     r12,    #20
+       strb    r12,    [r4]
+       mov     r12,    r3
+       strb    r12,    [r4, #4]
+       lsr     r12,    #8
+       strb    r12,    [r4, #3]
+       lsr     r12,    #8
+       strb    r12,    [r4, #2]
+       lsr     r12,    #8
+       strb    r12,    [r4, #1]
+       lsr     r12,    #8
+       mov     r5,     #0x0
+       mov     r6,     #0x4
+       tst     r2,     (1 << 30)
+       movne   r6,     #0x5
+
+       mov     pc,     lr
+
+SPIFLASH_READ_STATUS:  .byte   0x05 /* Read Status Register */
+SPIFLASH_WRITE_ENABLE: .byte   0x06 /* Write Enable */
+SPIFLASH_NOOP:         .byte   0x00
+SPIFLASH_SCRATCH_DATA: .byte   0x00, 0x0, 0x0, 0x0, 0x0
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 135128e..7818414 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -51,6 +51,7 @@ NOR_DRIVERS = \
        %D%/psoc4.c \
        %D%/psoc5lp.c \
        %D%/psoc6.c \
+       %D%/sh_qspi.c \
        %D%/sim3x.c \
        %D%/spi.c \
        %D%/stmsmi.c \
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 955d149..1c61587 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -66,6 +66,7 @@ extern const struct flash_driver psoc5lp_flash;
 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 sh_qspi_flash;
 extern const struct flash_driver sim3x_flash;
 extern const struct flash_driver stellaris_flash;
 extern const struct flash_driver stm32f1x_flash;
@@ -135,6 +136,7 @@ static const struct flash_driver * const flash_drivers[] = {
        &psoc5lp_eeprom_flash,
        &psoc5lp_nvl_flash,
        &psoc6_flash,
+       &sh_qspi_flash,
        &sim3x_flash,
        &stellaris_flash,
        &stm32f1x_flash,
diff --git a/src/flash/nor/sh_qspi.c b/src/flash/nor/sh_qspi.c
new file mode 100644
index 0000000..7e566d9
--- /dev/null
+++ b/src/flash/nor/sh_qspi.c
@@ -0,0 +1,1072 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SH QSPI (Quad SPI) driver
+ * Copyright (C) 2019 Marek Vasut <marek.va...@gmail.com>
+ *
+ * Based on U-Boot SH QSPI driver
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu...@renesas.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "spi.h"
+#include <helper/binarybuffer.h>
+#include <helper/time_support.h>
+#include <helper/types.h>
+#include <jtag/jtag.h>
+#include <target/algorithm.h>
+#include <target/arm.h>
+#include <target/arm_opcodes.h>
+#include <target/target.h>
+
+#define BIT(n)         (1UL << (n))
+/* SH QSPI register bit masks <REG>_<BIT> */
+#define SPCR_MSTR      0x08
+#define SPCR_SPE       0x40
+#define SPSR_SPRFF     0x80
+#define SPSR_SPTEF     0x20
+#define SPPCR_IO3FV    0x04
+#define SPPCR_IO2FV    0x02
+#define SPPCR_IO1FV    0x01
+#define SPBDCR_RXBC0   BIT(0)
+#define SPCMD_SCKDEN   BIT(15)
+#define SPCMD_SLNDEN   BIT(14)
+#define SPCMD_SPNDEN   BIT(13)
+#define SPCMD_SSLKP    BIT(7)
+#define SPCMD_BRDV0    BIT(2)
+#define SPCMD_INIT1    SPCMD_SCKDEN | SPCMD_SLNDEN | \
+                       SPCMD_SPNDEN | SPCMD_SSLKP | \
+                       SPCMD_BRDV0
+#define SPCMD_INIT2    SPCMD_SPNDEN | SPCMD_SSLKP | \
+                       SPCMD_BRDV0
+#define SPBFCR_TXRST   BIT(7)
+#define SPBFCR_RXRST   BIT(6)
+#define SPBFCR_TXTRG   0x30
+#define SPBFCR_RXTRG   0x07
+
+/* SH QSPI register set */
+#define SH_QSPI_SPCR           0x00
+#define SH_QSPI_SSLP           0x01
+#define SH_QSPI_SPPCR          0x02
+#define SH_QSPI_SPSR           0x03
+#define SH_QSPI_SPDR           0x04
+#define SH_QSPI_SPSCR          0x08
+#define SH_QSPI_SPSSR          0x09
+#define SH_QSPI_SPBR           0x0a
+#define SH_QSPI_SPDCR          0x0b
+#define SH_QSPI_SPCKD          0x0c
+#define SH_QSPI_SSLND          0x0d
+#define SH_QSPI_SPND           0x0e
+#define SH_QSPI_DUMMY0         0x0f
+#define SH_QSPI_SPCMD0         0x10
+#define SH_QSPI_SPCMD1         0x12
+#define SH_QSPI_SPCMD2         0x14
+#define SH_QSPI_SPCMD3         0x16
+#define SH_QSPI_SPBFCR         0x18
+#define SH_QSPI_DUMMY1         0x19
+#define SH_QSPI_SPBDCR         0x1a
+#define SH_QSPI_SPBMUL0                0x1c
+#define SH_QSPI_SPBMUL1                0x20
+#define SH_QSPI_SPBMUL2                0x24
+#define SH_QSPI_SPBMUL3                0x28
+
+struct sh_qspi_flash_bank {
+       const struct flash_device *dev;
+       uint32_t                io_base;
+       int                     probed;
+       struct working_area     *io_algorithm;
+       struct working_area     *source;
+       unsigned int            buffer_size;
+};
+
+struct sh_qspi_target {
+       char            *name;
+       uint32_t        tap_idcode;
+       uint32_t        io_base;
+};
+
+static const struct sh_qspi_target target_devices[] = {
+       /* name,        tap_idcode,     io_base */
+       { "SH QSPI",    0x4ba00477,     0xe6b10000 },
+       { NULL,         0,              0 }
+};
+
+static int sh_qspi_init(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+       uint8_t val;
+       int ret;
+
+       /* QSPI initialize */
+       /* Set master mode only */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR);
+       if (ret)
+               return ret;
+
+       /* Set SSL signal level */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SSLP, 0x00);
+       if (ret)
+               return ret;
+
+       /* Set MOSI signal value when transfer is in idle state */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPPCR,
+                             SPPCR_IO3FV | SPPCR_IO2FV);
+       if (ret)
+               return ret;
+
+       /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPBR, 0x01);
+       if (ret)
+               return ret;
+
+       /* Disable Dummy Data Transmission */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPDCR, 0x00);
+       if (ret)
+               return ret;
+
+       /* Set clock delay value */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPCKD, 0x00);
+       if (ret)
+               return ret;
+
+       /* Set SSL negation delay value */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SSLND, 0x00);
+       if (ret)
+               return ret;
+
+       /* Set next-access delay value */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPND, 0x00);
+       if (ret)
+               return ret;
+
+       /* Set equence command */
+       ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0,
+                              SPCMD_INIT2);
+       if (ret)
+               return ret;
+
+       /* Reset transfer and receive Buffer */
+       ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+       if (ret)
+               return ret;
+
+       val |= SPBFCR_TXRST | SPBFCR_RXRST;
+
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+       if (ret)
+               return ret;
+
+       /* Clear transfer and receive Buffer control bit */
+       ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+       if (ret)
+               return ret;
+
+       val &= ~(SPBFCR_TXRST|SPBFCR_RXRST);
+
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+       if (ret)
+               return ret;
+
+       /* Set equence control method. Use equence0 only */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00);
+       if (ret)
+               return ret;
+
+       /* Enable SPI function */
+       ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
+       if (ret)
+               return ret;
+
+       val |= SPCR_SPE;
+
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
+       if (ret)
+               return ret;
+
+       return ERROR_OK;
+}
+
+static int sh_qspi_cs_activate(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+       uint8_t val;
+       int ret;
+
+       /* Set master mode only */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR);
+       if (ret)
+               return ret;
+
+       /* Set command */
+       ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0,
+                              SPCMD_INIT1);
+       if (ret)
+               return ret;
+
+       /* Reset transfer and receive Buffer */
+       ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+       if (ret)
+               return ret;
+
+       val |= SPBFCR_TXRST|SPBFCR_RXRST;
+
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+       if (ret)
+               return ret;
+
+       /* Clear transfer and receive Buffer control bit */
+       ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
+       if (ret)
+               return ret;
+
+       val &= ~(SPBFCR_TXRST|SPBFCR_RXRST);
+
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
+       if (ret)
+               return ret;
+
+       /* Set equence control method. Use equence0 only */
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00);
+       if (ret)
+               return ret;
+
+       /* Enable SPI function */
+       ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
+       if (ret)
+               return ret;
+
+       val |= SPCR_SPE;
+
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
+       if (ret)
+               return ret;
+
+       return ERROR_OK;
+}
+
+static int sh_qspi_cs_deactivate(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+       uint8_t val;
+       int ret;
+
+       /* Disable SPI Function */
+       ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
+       if (ret)
+               return ret;
+
+       val &= ~SPCR_SPE;
+
+       ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
+       if (ret)
+               return ret;
+
+       return ERROR_OK;
+}
+
+static int sh_qspi_wait_for_bit(struct flash_bank *bank, uint8_t reg,
+                               uint32_t mask, bool set,
+                               unsigned long timeout)
+{
+       struct target *target = bank->target;
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+       long long endtime;
+       uint8_t val;
+       int ret;
+
+       endtime = timeval_ms() + timeout;
+       do {
+               ret = target_read_u8(target, info->io_base + reg, &val);
+               if (ret)
+                       return ERROR_FAIL;
+
+               if (!set)
+                       val = ~val;
+
+               if ((val & mask) == mask)
+                       return ERROR_OK;
+
+               alive_sleep(1);
+       } while (timeval_ms() < endtime);
+
+       LOG_ERROR("timeout");
+       return ERROR_FAIL;
+}
+
+static int sh_qspi_xfer_common(struct flash_bank *bank,
+                              const uint8_t *dout, unsigned int outlen,
+                              uint8_t *din, unsigned int inlen,
+                              bool xfer_start, bool xfer_end)
+{
+       struct target *target = bank->target;
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+       uint8_t tdata, rdata;
+       uint8_t val;
+       unsigned int nbyte = outlen + inlen;
+       int ret = 0;
+
+       if (xfer_start) {
+               ret = sh_qspi_cs_activate(bank);
+               if (ret)
+                       return ret;
+
+               ret = target_write_u32(target, info->io_base + SH_QSPI_SPBMUL0,
+                                      nbyte);
+               if (ret)
+                       return ret;
+
+               ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR,
+                                    &val);
+               if (ret)
+                       return ret;
+
+               val &= ~(SPBFCR_TXTRG | SPBFCR_RXTRG);
+
+               ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR,
+                                     val);
+               if (ret)
+                       return ret;
+       }
+
+       while (nbyte > 0) {
+               ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPTEF,
+                                               true, 1000);
+               if (ret)
+                       return ret;
+
+               tdata = outlen ? *dout++ : 0;
+               ret = target_write_u8(target, info->io_base + SH_QSPI_SPDR,
+                                     tdata);
+               if (ret)
+                       return ret;
+
+               ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPRFF,
+                                               true, 1000);
+               if (ret)
+                       return ret;
+
+               ret = target_read_u8(target, info->io_base + SH_QSPI_SPDR,
+                                    &rdata);
+               if (ret)
+                       return ret;
+               if (!outlen && inlen) {
+                       *din++ = rdata;
+                       inlen--;
+               }
+
+               if (outlen)
+                       outlen--;
+
+               nbyte--;
+       }
+
+       if (xfer_end)
+               return sh_qspi_cs_deactivate(bank);
+       else
+               return ERROR_OK;
+}
+
+/* Send "write enable" command to SPI flash chip. */
+static int sh_qspi_write_enable(struct flash_bank *bank)
+{
+       uint8_t dout = SPIFLASH_WRITE_ENABLE;
+       int ret;
+
+       ret = sh_qspi_xfer_common(bank, &dout, 1, NULL, 0, 1, 1);
+       if (ret != ERROR_OK)
+               return ret;
+
+       return ERROR_OK;
+}
+
+/* Read the status register of the external SPI flash chip. */
+static int read_status_reg(struct flash_bank *bank, uint32_t *status)
+{
+       uint8_t dout = SPIFLASH_READ_STATUS;
+       uint8_t din;
+       int ret;
+
+       ret = sh_qspi_xfer_common(bank, &dout, 1, &din, 1, 1, 1);
+       if (ret != ERROR_OK)
+               return ret;
+
+       *status = din & 0xff;
+
+       return ERROR_OK;
+}
+
+/* check for WIP (write in progress) bit in status register */
+/* timeout in ms */
+static int wait_till_ready(struct flash_bank *bank, int timeout)
+{
+       long long endtime;
+       uint32_t status;
+       int ret;
+
+       endtime = timeval_ms() + timeout;
+       do {
+               /* read flash status register */
+               ret = read_status_reg(bank, &status);
+               if (ret != ERROR_OK)
+                       return ret;
+
+               if ((status & SPIFLASH_BSY_BIT) == 0)
+                       return ERROR_OK;
+               alive_sleep(1);
+       } while (timeval_ms() < endtime);
+
+       LOG_ERROR("timeout");
+       return ERROR_FAIL;
+}
+
+static int sh_qspi_erase_sector(struct flash_bank *bank, int sector)
+{
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+       bool addr4b = info->dev->size_in_bytes > (1UL << 24);
+       uint32_t address = (sector * info->dev->sectorsize) <<
+                          (addr4b ? 0 : 8);
+       uint8_t dout[5] = {
+               info->dev->erase_cmd,
+               (address >> 24) & 0xff, (address >> 16) & 0xff,
+               (address >> 8) & 0xff, (address >> 0) & 0xff
+       };
+       unsigned int doutlen = addr4b ? 5 : 4;
+       int ret;
+
+       /* Write Enable */
+       ret = sh_qspi_write_enable(bank);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* Erase */
+       ret = sh_qspi_xfer_common(bank, dout, doutlen, NULL, 0, 1, 1);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* Poll status register */
+       ret = wait_till_ready(bank, 3000);
+       if (ret != ERROR_OK)
+               return ret;
+
+       return ERROR_OK;
+}
+
+static int sh_qspi_erase(struct flash_bank *bank, int first, int last)
+{
+       struct target *target = bank->target;
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+       int retval = ERROR_OK;
+       int sector;
+
+       LOG_DEBUG("%s: from sector %d to sector %d", __func__, first, last);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
+               LOG_ERROR("Flash sector invalid");
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       if (!info->probed) {
+               LOG_ERROR("Flash bank not probed");
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       if (info->dev->erase_cmd == 0x00)
+               return ERROR_FLASH_OPER_UNSUPPORTED;
+
+       for (sector = first; sector <= last; sector++) {
+               if (bank->sectors[sector].is_protected) {
+                       LOG_ERROR("Flash sector %d protected", sector);
+                       return ERROR_FAIL;
+               }
+       }
+
+       for (sector = first; sector <= last; sector++) {
+               retval = sh_qspi_erase_sector(bank, sector);
+               if (retval != ERROR_OK)
+                       break;
+               keep_alive();
+       }
+
+       return retval;
+}
+
+static int sh_qspi_write(struct flash_bank *bank, const uint8_t *buffer,
+                      uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+       struct reg_param reg_params[4];
+       struct arm_algorithm arm_algo;
+       uint32_t io_base = (uint32_t)(info->io_base);
+       uint32_t src_base = (uint32_t)(info->source->address);
+       uint32_t chunk;
+       bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24));
+       int ret = ERROR_OK;
+       int sector;
+
+       LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+                 __func__, offset, count);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset + count > bank->size) {
+               LOG_WARNING("Write pasts end of flash. Extra data discarded.");
+               count = bank->size - offset;
+       }
+
+       if (offset & 0xff) {
+               LOG_ERROR("sh_qspi_write_page: unaligned write address: %08x",
+                         offset);
+               return ERROR_FAIL;
+       }
+
+       /* Check sector protection */
+       for (sector = 0; sector < bank->num_sectors; sector++) {
+               /* Start offset in or before this sector? */
+               /* End offset in or behind this sector? */
+               struct flash_sector *bs = &bank->sectors[sector];
+
+               if ((offset < (bs->offset + bs->size)) &&
+                   ((offset + count - 1) >= bs->offset) &&
+                   bs->is_protected) {
+                       LOG_ERROR("Flash sector %d protected", sector);
+                       return ERROR_FAIL;
+               }
+       }
+
+       LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+                 __func__, offset, count);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset + count > bank->size) {
+               LOG_WARNING("Reads past end of flash. Extra data discarded.");
+               count = bank->size - offset;
+       }
+
+       arm_algo.common_magic = ARM_COMMON_MAGIC;
+       arm_algo.core_mode = ARM_MODE_SVC;
+       arm_algo.core_state = ARM_STATE_ARM;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+
+       while (count > 0) {
+               chunk = (count > info->buffer_size) ?
+                       info->buffer_size : count;
+
+               target_write_buffer(target, info->source->address,
+                                   chunk, buffer);
+
+               buf_set_u32(reg_params[0].value, 0, 32, io_base);
+               buf_set_u32(reg_params[1].value, 0, 32, src_base);
+               buf_set_u32(reg_params[2].value, 0, 32,
+                               (1 << 31) | (addr4b << 30) |
+                               (info->dev->pprog_cmd << 20) | chunk);
+               buf_set_u32(reg_params[3].value, 0, 32, offset);
+
+               ret = target_run_algorithm(target, 0, NULL, 4, reg_params,
+                               info->io_algorithm->address,
+                               0, 10000, &arm_algo);
+               if (ret != ERROR_OK) {
+                       LOG_ERROR("error executing SH QSPI flash IO algorithm");
+                       ret = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               buffer += chunk;
+               offset += chunk;
+               count -= chunk;
+       }
+
+       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 ret;
+}
+
+static int sh_qspi_read(struct flash_bank *bank, uint8_t *buffer,
+                       uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+       struct reg_param reg_params[4];
+       struct arm_algorithm arm_algo;
+       uint32_t io_base = (uint32_t)(info->io_base);
+       uint32_t src_base = (uint32_t)(info->source->address);
+       uint32_t chunk;
+       bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24));
+       int ret = ERROR_OK;
+
+       LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+                 __func__, offset, count);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset + count > bank->size) {
+               LOG_WARNING("Reads past end of flash. Extra data discarded.");
+               count = bank->size - offset;
+       }
+
+       arm_algo.common_magic = ARM_COMMON_MAGIC;
+       arm_algo.core_mode = ARM_MODE_SVC;
+       arm_algo.core_state = ARM_STATE_ARM;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+
+       while (count > 0) {
+               chunk = (count > info->buffer_size) ?
+                       info->buffer_size : count;
+
+               buf_set_u32(reg_params[0].value, 0, 32, io_base);
+               buf_set_u32(reg_params[1].value, 0, 32, src_base);
+               buf_set_u32(reg_params[2].value, 0, 32,
+                               (addr4b << 30) | (info->dev->read_cmd << 20) |
+                               chunk);
+               buf_set_u32(reg_params[3].value, 0, 32, offset);
+
+               ret = target_run_algorithm(target, 0, NULL, 4, reg_params,
+                               info->io_algorithm->address,
+                               0, 10000, &arm_algo);
+               if (ret != ERROR_OK) {
+                       LOG_ERROR("error executing SH QSPI flash IO algorithm");
+                       ret = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               target_read_buffer(target, info->source->address,
+                                  chunk, buffer);
+
+               buffer += chunk;
+               offset += chunk;
+               count -= chunk;
+       }
+
+       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 ERROR_OK;
+}
+
+/* Return ID of flash device */
+static int read_flash_id(struct flash_bank *bank, uint32_t *id)
+{
+       struct target *target = bank->target;
+       uint8_t dout = SPIFLASH_READ_ID;
+       uint8_t din[3] = { 0, 0, 0 };
+       int ret;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       ret = sh_qspi_xfer_common(bank, &dout, 1, din, 3, 1, 1);
+       if (ret != ERROR_OK)
+               return ret;
+
+       *id = (din[0] << 0) | (din[1] << 8) | (din[2] << 16);
+
+       if (*id == 0xffffff) {
+               LOG_ERROR("No SPI flash found");
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int sh_qspi_protect(struct flash_bank *bank, int set,
+                        int first, int last)
+{
+       int sector;
+
+       for (sector = first; sector <= last; sector++)
+               bank->sectors[sector].is_protected = set;
+
+       return ERROR_OK;
+}
+
+static int sh_qspi_upload_helper(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+
+       /* see contrib/loaders/flash/sh_qspi.s for src */
+       static const uint32_t sh_qspi_io_code[] = {
+               0xe3c274ff,
+               0xe3c7760f,
+               0xe2028102,
+               0xe3580102,
+               0x0a00000a,
+               0xeb000032,
+               0xeb00006c,
+               0xe0868007,
+               0xe580801c,
+               0xeb000042,
+               0xe3a04000,
+               0xe1a05001,
+               0xe1a06007,
+               0xeb00003e,
+               0xeb000039,
+               0xea000027,
+               0xe3a08c01,
+               0xe3120202,
+               0x13a08c02,
+               0xe1570008,
+               0xb1a08007,
+               0xe59f41cc,
+               0xe24f5060,
+               0xe0844005,
+               0xe3a05000,
+               0xe3a06001,
+               0xeb00001d,
+               0xe580601c,
+               0xeb00002f,
+               0xeb00002a,
+               0xeb000019,
+               0xeb000053,
+               0xe580601c,
+               0xeb00002a,
+               0xe1a04001,
+               0xe3a05000,
+               0xe1a06008,
+               0xeb000026,
+               0xeb000021,
+               0xe59f4188,
+               0xe24f50a8,
+               0xe0844005,
+               0xe3a05000,
+               0xe3a06002,
+               0xeb00000b,
+               0xe580601c,
+               0xeb00001d,
+               0xeb000018,
+               0xe20dd001,
+               0xe35d0001,
+               0x0afffff3,
+               0xe0811008,
+               0xe0833008,
+               0xe0477008,
+               0xe3570000,
+               0x1affffda,
+               0xe1200070,
+               0xe3a0c008,
+               0xe5c0c000,
+               0xe30ec084,
+               0xe1c0c1b0,
+               0xe5d0c008,
+               0xe38cc0c0,
+               0xe5c0c018,
+               0xe5d0c018,
+               0xe3ccc0c0,
+               0xe5c0c018,
+               0xe3a0c000,
+               0xe5c0c008,
+               0xe5d0c000,
+               0xe38cc040,
+               0xe5c0c000,
+               0xe1a0f00e,
+               0xe5d0c000,
+               0xe3ccc040,
+               0xe5c0c000,
+               0xe1a0f00e,
+               0xe590d018,
+               0xe38dd037,
+               0xe3a0b020,
+               0xe3560020,
+               0xb3cdd037,
+               0xb3a0b001,
+               0xe580d018,
+               0xe5d0c003,
+               0xe31c0020,
+               0x0afffffc,
+               0xe1a0c00b,
+               0xe3a0d000,
+               0xe3540000,
+               0x0a000004,
+               0xe4d4d001,
+               0xe5c0d004,
+               0xe25cc001,
+               0x1afffffb,
+               0xea000002,
+               0xe5c0d004,
+               0xe25cc001,
+               0x1afffffc,
+               0xe5d0c003,
+               0xe31c0080,
+               0x0afffffc,
+               0xe1a0c00b,
+               0xe3550000,
+               0x0a000004,
+               0xe5d0d004,
+               0xe4c5d001,
+               0xe25cc001,
+               0x1afffffb,
+               0xea000002,
+               0xe5d0d004,
+               0xe25cc001,
+               0x1afffffc,
+               0xe056600b,
+               0x1affffd9,
+               0xe1a0f00e,
+               0xe59f4058,
+               0xe24f5f77,
+               0xe0844005,
+               0xe202c6ff,
+               0xe1a0ca2c,
+               0xe5c4c000,
+               0xe1a0c003,
+               0xe5c4c004,
+               0xe1a0c42c,
+               0xe5c4c003,
+               0xe1a0c42c,
+               0xe5c4c002,
+               0xe1a0c42c,
+               0xe5c4c001,
+               0xe1a0c42c,
+               0xe3a05000,
+               0xe3a06004,
+               0xe3120101,
+               0x13a06005,
+               0xe1a0f00e,
+               0x00000605,
+               0x00000000,
+               0x00000221,
+               0x00000220,
+               0x00000223,
+       };
+       uint8_t code[sizeof(sh_qspi_io_code)];
+       int ret;
+
+       if (info->source)
+               target_free_working_area(target, info->source);
+       if (info->io_algorithm)
+               target_free_working_area(target, info->io_algorithm);
+
+       /* flash write code */
+       if (target_alloc_working_area(target, sizeof(sh_qspi_io_code),
+                       &info->io_algorithm) != ERROR_OK) {
+               LOG_WARNING("no working area available, can't do block memory 
writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       target_buffer_set_u32_array(target, code, ARRAY_SIZE(sh_qspi_io_code),
+                                   sh_qspi_io_code);
+       target_write_buffer(target, info->io_algorithm->address,
+                           sizeof(code), code);
+
+       /* memory buffer */
+       info->buffer_size = 32768;
+       while (true) {
+               ret = target_alloc_working_area_try(target, info->buffer_size,
+                                                   &info->source);
+               if (ret == ERROR_OK)
+                       break;
+
+               info->buffer_size /= 2;
+               if (info->buffer_size <= 256) {
+                       target_free_working_area(target, info->io_algorithm);
+
+                       LOG_WARNING("no large enough working area available, 
can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int sh_qspi_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+       struct flash_sector *sectors;
+       uint32_t id = 0; /* silence uninitialized warning */
+       uint32_t sectorsize;
+       const struct sh_qspi_target *target_device;
+       int ret;
+
+       if (info->probed) {
+               free(bank->sectors);
+       }
+       info->probed = 0;
+
+       for (target_device = target_devices; target_device->name;
+               ++target_device)
+               if (target_device->tap_idcode == target->tap->idcode)
+                       break;
+       if (!target_device->name) {
+               LOG_ERROR("Device ID 0x%" PRIx32 " is not known",
+                         target->tap->idcode);
+               return ERROR_FAIL;
+       }
+
+       info->io_base = target_device->io_base;
+
+       LOG_DEBUG("Found device %s at address " TARGET_ADDR_FMT,
+                 target_device->name, bank->base);
+
+       ret = sh_qspi_upload_helper(bank);
+       if (ret != ERROR_OK)
+               return ret;
+
+       ret = sh_qspi_init(bank);
+       if (ret != ERROR_OK)
+               return ret;
+
+       ret = read_flash_id(bank, &id);
+       if (ret != ERROR_OK)
+               return ret;
+
+       info->dev = NULL;
+       for (const struct flash_device *p = flash_devices; p->name; p++)
+               if (p->device_id == id) {
+                       info->dev = p;
+                       break;
+               }
+
+       if (!info->dev) {
+               LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id);
+               return ERROR_FAIL;
+       }
+
+       LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
+                info->dev->name, info->dev->device_id);
+
+       /* Set correct size value */
+       bank->size = info->dev->size_in_bytes;
+       if (bank->size <= (1UL << 16))
+               LOG_WARNING("device needs 2-byte addresses - not implemented");
+
+       /* if no sectors, treat whole bank as single sector */
+       sectorsize = info->dev->sectorsize ?
+                    info->dev->sectorsize :
+                    info->dev->size_in_bytes;
+
+       /* create and fill sectors array */
+       bank->num_sectors = info->dev->size_in_bytes / sectorsize;
+       sectors = calloc(1, sizeof(*sectors) * bank->num_sectors);
+       if (!sectors) {
+               LOG_ERROR("not enough memory");
+               return ERROR_FAIL;
+       }
+
+       for (int sector = 0; sector < bank->num_sectors; sector++) {
+               sectors[sector].offset = sector * sectorsize;
+               sectors[sector].size = sectorsize;
+               sectors[sector].is_erased = 0;
+               sectors[sector].is_protected = 0;
+       }
+
+       bank->sectors = sectors;
+       info->probed = 1;
+       return ERROR_OK;
+}
+
+static int sh_qspi_auto_probe(struct flash_bank *bank)
+{
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+
+       if (info->probed)
+               return ERROR_OK;
+
+       return sh_qspi_probe(bank);
+}
+
+static int sh_qspi_flash_blank_check(struct flash_bank *bank)
+{
+       /* Not implemented */
+       return ERROR_OK;
+}
+
+static int sh_qspi_protect_check(struct flash_bank *bank)
+{
+       /* Not implemented */
+       return ERROR_OK;
+}
+
+static int sh_qspi_get_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct sh_qspi_flash_bank *info = bank->driver_priv;
+
+       if (!info->probed) {
+               snprintf(buf, buf_size,
+                        "\nSH QSPI flash bank not probed yet\n");
+               return ERROR_OK;
+       }
+
+       snprintf(buf, buf_size, "\nSH QSPI flash information:\n"
+               "  Device \'%s\' (ID 0x%08" PRIx32 ")\n",
+               info->dev->name, info->dev->device_id);
+
+       return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(sh_qspi_flash_bank_command)
+{
+       struct sh_qspi_flash_bank *info;
+
+       LOG_DEBUG("%s", __func__);
+
+       if (CMD_ARGC < 6 || CMD_ARGC > 7)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if ((CMD_ARGC == 7) && strcmp(CMD_ARGV[6], "cs0")) {
+               LOG_ERROR("Unknown arg: %s", CMD_ARGV[6]);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       info = calloc(1, sizeof(struct sh_qspi_flash_bank));
+       if (!info) {
+               LOG_ERROR("not enough memory");
+               return ERROR_FAIL;
+       }
+
+       bank->driver_priv = info;
+
+       return ERROR_OK;
+}
+
+const struct flash_driver sh_qspi_flash = {
+       .name                   = "sh_qspi",
+       .flash_bank_command     = sh_qspi_flash_bank_command,
+       .erase                  = sh_qspi_erase,
+       .protect                = sh_qspi_protect,
+       .write                  = sh_qspi_write,
+       .read                   = sh_qspi_read,
+       .probe                  = sh_qspi_probe,
+       .auto_probe             = sh_qspi_auto_probe,
+       .erase_check            = sh_qspi_flash_blank_check,
+       .protect_check          = sh_qspi_protect_check,
+       .info                   = sh_qspi_get_info,
+       .free_driver_priv       = default_flash_free_driver_priv,
+};

-- 


_______________________________________________
OpenOCD-devel mailing list
OpenOCD-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to