This is an automated email from Gerrit.

Tim Newsome (t...@sifive.com) just uploaded a new patch set to Gerrit, which 
you can find at http://openocd.zylin.com/4656

-- gerrit

commit f670130e9527f8331b7bc36dbfc699b84dfbcd7f
Author: Tim Newsome <t...@sifive.com>
Date:   Fri Aug 24 13:50:03 2018 -0700

    Add flash support for SiFive's Freedom E platforms
    
    Change-Id: I7757615ec52448372bdc57729cdf97c7016d97e8
    Signed-off-by: Tim Newsome <t...@sifive.com>

diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 3839d0a..8fd8dd6 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -26,6 +26,7 @@ NOR_DRIVERS = \
        %D%/efm32.c \
        %D%/em357.c \
        %D%/faux.c \
+       %D%/fespi.c \
        %D%/fm3.c \
        %D%/fm4.c \
        %D%/jtagspi.c \
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 2251b96..de56ed9 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -41,6 +41,7 @@ extern struct flash_driver em357_flash;
 extern struct flash_driver faux_flash;
 extern struct flash_driver fm3_flash;
 extern struct flash_driver fm4_flash;
+extern struct flash_driver fespi_flash;
 extern struct flash_driver jtagspi_flash;
 extern struct flash_driver kinetis_flash;
 extern struct flash_driver kinetis_ke_flash;
@@ -106,6 +107,7 @@ static struct flash_driver *flash_drivers[] = {
        &faux_flash,
        &fm3_flash,
        &fm4_flash,
+       &fespi_flash,
        &jtagspi_flash,
        &kinetis_flash,
        &kinetis_ke_flash,
diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c
new file mode 100644
index 0000000..6667d36
--- /dev/null
+++ b/src/flash/nor/fespi.c
@@ -0,0 +1,1184 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Antonio Borneo <borneo.anto...@gmail.com>       *
+ *   Modified by Megan Wachs <me...@sifive.com> from the original stmsmi.c *
+ *                                                                         *
+ *   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/>. *
+ ***************************************************************************/
+
+/* The Freedom E SPI controller is a SPI bus controller
+ * specifically designed for SPI Flash Memories on Freedom E platforms.
+ *
+ * Two working modes are available:
+ * - SW mode: the SPI is controlled by SW. Any custom commands can be sent
+ *   on the bus. Writes are only possible in this mode.
+ * - HW mode: Memory content is directly
+ *   accessible in CPU memory space. CPU can read, write and execute memory
+ *   content. */
+
+/* ATTENTION:
+ * To have flash memory mapped in CPU memory space, the controller
+ * must have "HW mode" enabled.
+ * 1) The command "reset init" has to initialize the controller and put
+ *    it in HW mode (this is actually the default out of reset for Freedom E 
systems).
+ * 2) every command in this file have to return to prompt in HW mode. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "spi.h"
+#include <jtag/jtag.h>
+#include <helper/time_support.h>
+#include <target/algorithm.h>
+#include "target/riscv/riscv.h"
+
+/* Register offsets */
+
+#define FESPI_REG_SCKDIV          0x00
+#define FESPI_REG_SCKMODE         0x04
+#define FESPI_REG_CSID            0x10
+#define FESPI_REG_CSDEF           0x14
+#define FESPI_REG_CSMODE          0x18
+
+#define FESPI_REG_DCSSCK          0x28
+#define FESPI_REG_DSCKCS          0x2a
+#define FESPI_REG_DINTERCS        0x2c
+#define FESPI_REG_DINTERXFR       0x2e
+
+#define FESPI_REG_FMT             0x40
+#define FESPI_REG_TXFIFO          0x48
+#define FESPI_REG_RXFIFO          0x4c
+#define FESPI_REG_TXCTRL          0x50
+#define FESPI_REG_RXCTRL          0x54
+
+#define FESPI_REG_FCTRL           0x60
+#define FESPI_REG_FFMT            0x64
+
+#define FESPI_REG_IE              0x70
+#define FESPI_REG_IP              0x74
+
+/* Fields */
+
+#define FESPI_SCK_POL             0x1
+#define FESPI_SCK_PHA             0x2
+
+#define FESPI_FMT_PROTO(x)        ((x) & 0x3)
+#define FESPI_FMT_ENDIAN(x)       (((x) & 0x1) << 2)
+#define FESPI_FMT_DIR(x)          (((x) & 0x1) << 3)
+#define FESPI_FMT_LEN(x)          (((x) & 0xf) << 16)
+
+/* TXCTRL register */
+#define FESPI_TXWM(x)             ((x) & 0xffff)
+/* RXCTRL register */
+#define FESPI_RXWM(x)             ((x) & 0xffff)
+
+#define FESPI_IP_TXWM             0x1
+#define FESPI_IP_RXWM             0x2
+
+#define FESPI_FCTRL_EN            0x1
+
+#define FESPI_INSN_CMD_EN         0x1
+#define FESPI_INSN_ADDR_LEN(x)    (((x) & 0x7) << 1)
+#define FESPI_INSN_PAD_CNT(x)     (((x) & 0xf) << 4)
+#define FESPI_INSN_CMD_PROTO(x)   (((x) & 0x3) << 8)
+#define FESPI_INSN_ADDR_PROTO(x)  (((x) & 0x3) << 10)
+#define FESPI_INSN_DATA_PROTO(x)  (((x) & 0x3) << 12)
+#define FESPI_INSN_CMD_CODE(x)    (((x) & 0xff) << 16)
+#define FESPI_INSN_PAD_CODE(x)    (((x) & 0xff) << 24)
+
+/* Values */
+
+#define FESPI_CSMODE_AUTO         0
+#define FESPI_CSMODE_HOLD         2
+#define FESPI_CSMODE_OFF          3
+
+#define FESPI_DIR_RX              0
+#define FESPI_DIR_TX              1
+
+#define FESPI_PROTO_S             0
+#define FESPI_PROTO_D             1
+#define FESPI_PROTO_Q             2
+
+#define FESPI_ENDIAN_MSB          0
+#define FESPI_ENDIAN_LSB          1
+
+
+/* Timeout in ms */
+#define FESPI_CMD_TIMEOUT   (100)
+#define FESPI_PROBE_TIMEOUT (100)
+#define FESPI_MAX_TIMEOUT  (3000)
+
+
+#define FESPI_READ_REG(a) (_FESPI_READ_REG(a))
+#define _FESPI_READ_REG(a)                                     \
+{                                                              \
+       int __a;                                                \
+       uint32_t __v;                                           \
+                                                               \
+       __a = target_read_u32(target, ctrl_base + (a), &__v);   \
+       if (__a != ERROR_OK) {                                  \
+               LOG_ERROR("FESPI_READ_REG error");              \
+               return __a;                                     \
+       }                                                       \
+       __v;                                                    \
+}
+
+#define FESPI_WRITE_REG(a, v)                                  \
+{                                                              \
+       int __r;                                                \
+                                                               \
+       __r = target_write_u32(target, ctrl_base + (a), (v));   \
+       if (__r != ERROR_OK) {                                  \
+               LOG_ERROR("FESPI_WRITE_REG error");             \
+               return __r;                                     \
+       }                                                       \
+}
+
+#define FESPI_DISABLE_HW_MODE()        FESPI_WRITE_REG(FESPI_REG_FCTRL, \
+               FESPI_READ_REG(FESPI_REG_FCTRL) & ~FESPI_FCTRL_EN)
+#define FESPI_ENABLE_HW_MODE() FESPI_WRITE_REG(FESPI_REG_FCTRL, \
+       FESPI_READ_REG(FESPI_REG_FCTRL) | FESPI_FCTRL_EN)
+
+struct fespi_flash_bank {
+       int probed;
+       uint32_t ctrl_base;
+       const struct flash_device *dev;
+};
+
+struct fespi_target {
+       char *name;
+       uint32_t tap_idcode;
+       uint32_t ctrl_base;
+};
+
+/* TODO !!! What is the right naming convention here? */
+static const struct fespi_target target_devices[] = {
+       /* name,   tap_idcode, ctrl_base */
+       { "Freedom E300 SPI Flash",  0x10e31913 , 0x10014000 },
+       { NULL,    0,           0          }
+};
+
+FLASH_BANK_COMMAND_HANDLER(fespi_flash_bank_command)
+{
+       struct fespi_flash_bank *fespi_info;
+
+       LOG_DEBUG("%s", __func__);
+
+       if (CMD_ARGC < 6)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       fespi_info = malloc(sizeof(struct fespi_flash_bank));
+       if (fespi_info == NULL) {
+               LOG_ERROR("not enough memory");
+               return ERROR_FAIL;
+       }
+
+       bank->driver_priv = fespi_info;
+       fespi_info->probed = 0;
+       fespi_info->ctrl_base = 0;
+       if (CMD_ARGC >= 7) {
+               int temp;
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[6], temp);
+               fespi_info->ctrl_base = (uint32_t) temp;
+               LOG_DEBUG("ASSUMING FESPI device at ctrl_base = 0x%x", 
fespi_info->ctrl_base);
+       }
+
+       return ERROR_OK;
+}
+
+static int fespi_set_dir(struct flash_bank *bank, bool dir)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+
+       FESPI_WRITE_REG(FESPI_REG_FMT,
+                       (FESPI_READ_REG(FESPI_REG_FMT) & 
~(FESPI_FMT_DIR(0xFFFFFFFF))) |
+                       FESPI_FMT_DIR(dir));
+
+       return ERROR_OK;
+
+}
+
+static int fespi_txwm_wait(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+
+       int64_t start = timeval_ms();
+
+       while (1) {
+               if (FESPI_READ_REG(FESPI_REG_IP) & FESPI_IP_TXWM)
+                       break;
+               int64_t now = timeval_ms();
+               if (now - start > 1000) {
+                       LOG_ERROR("ip.txwm didn't get set.");
+                       return ERROR_TARGET_TIMEOUT;
+               }
+       }
+
+       return ERROR_OK;
+
+}
+
+static int fespi_tx(struct flash_bank *bank, uint8_t in)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+
+       int64_t start = timeval_ms();
+
+       while (1) {
+               if ((int32_t) FESPI_READ_REG(FESPI_REG_TXFIFO) >= 0)
+                       break;
+               int64_t now = timeval_ms();
+               if (now - start > 1000) {
+                       LOG_ERROR("txfifo stayed negative.");
+                       return ERROR_TARGET_TIMEOUT;
+               }
+       }
+
+       FESPI_WRITE_REG(FESPI_REG_TXFIFO, in);
+
+       return ERROR_OK;
+}
+
+static int fespi_rx(struct flash_bank *bank, uint8_t *out)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+
+       int64_t start = timeval_ms();
+       int32_t value;
+
+       while (1) {
+               value = (int32_t) FESPI_READ_REG(FESPI_REG_RXFIFO);
+               if (value >= 0)
+                       break;
+               int64_t now = timeval_ms();
+               if (now - start > 1000) {
+                       LOG_ERROR("rxfifo didn't go positive (value=0x%x).", 
value);
+                       return ERROR_TARGET_TIMEOUT;
+               }
+       }
+
+       if (out)
+               *out = value & 0xff;
+
+       return ERROR_OK;
+}
+
+/* TODO!!! Why don't we need to call this after writing? */
+static int fespi_wip(struct flash_bank *bank, int timeout)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+
+       int64_t endtime;
+
+       fespi_set_dir(bank, FESPI_DIR_RX);
+
+       FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
+       endtime = timeval_ms() + timeout;
+
+       fespi_tx(bank, SPIFLASH_READ_STATUS);
+       if (fespi_rx(bank, NULL) != ERROR_OK)
+               return ERROR_FAIL;
+
+       do {
+               alive_sleep(1);
+
+               fespi_tx(bank, 0);
+               uint8_t rx;
+               if (fespi_rx(bank, &rx) != ERROR_OK)
+                       return ERROR_FAIL;
+               if ((rx & SPIFLASH_BSY_BIT) == 0) {
+                       FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
+                       fespi_set_dir(bank, FESPI_DIR_TX);
+                       return ERROR_OK;
+               }
+       } while (timeval_ms() < endtime);
+
+       LOG_ERROR("timeout");
+       return ERROR_FAIL;
+}
+
+static int fespi_erase_sector(struct flash_bank *bank, int sector)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+       int retval;
+
+       retval = fespi_tx(bank, SPIFLASH_WRITE_ENABLE);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = fespi_txwm_wait(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
+       retval = fespi_tx(bank, fespi_info->dev->erase_cmd);
+       if (retval != ERROR_OK)
+               return retval;
+       sector = bank->sectors[sector].offset;
+       retval = fespi_tx(bank, sector >> 16);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = fespi_tx(bank, sector >> 8);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = fespi_tx(bank, sector);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = fespi_txwm_wait(bank);
+       if (retval != ERROR_OK)
+               return retval;
+       FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
+
+       retval = fespi_wip(bank, FESPI_MAX_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int fespi_erase(struct flash_bank *bank, int first, int last)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+       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 (!(fespi_info->probed)) {
+               LOG_ERROR("Flash bank not probed");
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       for (sector = first; sector <= last; sector++) {
+               if (bank->sectors[sector].is_protected) {
+                       LOG_ERROR("Flash sector %d protected", sector);
+                       return ERROR_FAIL;
+               }
+       }
+
+       FESPI_WRITE_REG(FESPI_REG_TXCTRL, FESPI_TXWM(1));
+       retval = fespi_txwm_wait(bank);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("WM Didn't go high before attempting.");
+               return retval;
+       }
+
+       /* Disable Hardware accesses*/
+       FESPI_DISABLE_HW_MODE();
+
+       /* poll WIP */
+       retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       for (sector = first; sector <= last; sector++) {
+               retval = fespi_erase_sector(bank, sector);
+               if (retval != ERROR_OK)
+                       break;
+               keep_alive();
+       }
+
+       /* Switch to HW mode before return to prompt */
+       FESPI_ENABLE_HW_MODE();
+       return retval;
+}
+
+static int fespi_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 slow_fespi_write_buffer(struct flash_bank *bank,
+               const uint8_t *buffer, uint32_t offset, uint32_t len)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+       uint32_t ii;
+
+       if (offset & 0xFF000000) {
+               LOG_ERROR("FESPI interface does not support greater than 3B 
addressing, can't write to offset 0x%x",
+                               offset);
+               return ERROR_FAIL;
+       }
+
+       /* TODO!!! assert that len < page size */
+
+       fespi_tx(bank, SPIFLASH_WRITE_ENABLE);
+       fespi_txwm_wait(bank);
+
+       FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
+
+       fespi_tx(bank, SPIFLASH_PAGE_PROGRAM);
+
+       fespi_tx(bank, offset >> 16);
+       fespi_tx(bank, offset >> 8);
+       fespi_tx(bank, offset);
+
+       for (ii = 0; ii < len; ii++)
+               fespi_tx(bank, buffer[ii]);
+
+       fespi_txwm_wait(bank);
+
+       FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
+
+       keep_alive();
+
+       return ERROR_OK;
+}
+
+/*
+ * Here's the source for the algorithm.
+ * You can turn it into the array below using:
+       sed -n '/ALGO_START$/,/ALGO_END/ p' fespi.c | \
+               riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -x \
+               assembler-with-cpp - -nostdlib -nostartfiles -o tmp.o && \
+               riscv64-unknown-elf-objcopy -O binary tmp.o algorithm.bin && \
+               xxd -i algorithm.bin
+
+// ALGO_START
+#define SPIFLASH_READ_STATUS   0x05 // Read Status Register
+#define SPIFLASH_BSY_BIT               0x00000001 // WIP Bit of SPI SR on SMI 
SR
+
+// Register offsets
+#define FESPI_REG_FMT             0x40
+#define FESPI_REG_TXFIFO          0x48
+#define FESPI_REG_RXFIFO          0x4c
+#define FESPI_REG_IP              0x74
+
+// Fields
+#define FESPI_IP_TXWM             0x1
+#define FESPI_FMT_DIR(x)          (((x) & 0x1) << 3)
+
+// To enter, jump to the start of command_table (ie. offset 0).
+//      a0 - FESPI base address
+//      a1 - start address of buffer
+
+// The buffer contains a "program" in byte sequences. The first byte in a
+// sequence determines the operation. Some operation will read more data from
+// the program, while some will not. The operation byte is the offset into
+// command_table, so eg. 4 means exit, 8 means transmit, and so on.
+
+               .global _start
+_start:
+command_table:
+               j       main            // 0
+               ebreak                  // 4
+               j       tx              // 8
+               j       txwm_wait       // 12
+               j       write_reg       // 16
+               j               wip_wait                // 20
+               j               set_dir                 // 24
+
+// Execute the program.
+main:
+               lbu     t0, 0(a1)
+               addi    a1, a1, 1
+               la      t1, command_table
+               add     t0, t0, t1
+               jr      t0
+
+// Read 1 byte the contains the number of bytes to transmit. Then read those
+// bytes from the program and transmit them one by one.
+tx:
+               lbu     t1, 0(a1)       // read number of bytes to transmit
+               addi    a1, a1, 1
+1:      lw      t0, FESPI_REG_TXFIFO(a0)        // wait for FIFO clear
+               bltz    t0, 1b
+               lbu     t0, 0(a1)       // Load byte to write
+               sw      t0, FESPI_REG_TXFIFO(a0)
+               addi    a1, a1, 1
+               addi    t1, t1, -1
+               bgtz    t1, 1b
+               j       main
+
+// Wait until TXWM is set.
+txwm_wait:
+1:      lw      t0, FESPI_REG_IP(a0)
+               andi    t0, t0, FESPI_IP_TXWM
+               beqz    t0, 1b
+               j       main
+
+// Read 1 byte that contains the offset of the register to write, and 1 byte
+// that contains the data to write.
+write_reg:
+               lbu     t0, 0(a1)       // read register to write
+               add     t0, t0, a0
+               lbu     t1, 1(a1)       // read value to write
+               addi    a1, a1, 2
+               sw      t1, 0(t0)
+               j       main
+
+wip_wait:
+               li              a2, SPIFLASH_READ_STATUS
+               jal             txrx_byte
+               // discard first result
+1:             li              a2, 0
+               jal             txrx_byte
+               andi    t0, a2, SPIFLASH_BSY_BIT
+               bnez    t0, 1b
+               j               main
+
+txrx_byte:     // transmit the byte in a2, receive a bit into a2
+               lw      t0, FESPI_REG_TXFIFO(a0)        // wait for FIFO clear
+               bltz    t0, txrx_byte
+               sw      a2, FESPI_REG_TXFIFO(a0)
+1:             lw              a2, FESPI_REG_RXFIFO(a0)
+               bltz    a2, 1b
+               ret
+
+set_dir:
+               lw              t0, FESPI_REG_FMT(a0)
+               li              t1, ~(FESPI_FMT_DIR(0xFFFFFFFF))
+               and             t0, t0, t1
+               lbu     t1, 0(a1)       // read value to OR in
+               addi    a1, a1, 1
+               or              t0, t0, t1
+               sw              t0, FESPI_REG_FMT(a0)
+               j               main
+
+// ALGO_END
+ */
+static const uint8_t algorithm_bin[] = {
+        0x6f, 0x00, 0xc0, 0x01, 0x73, 0x00, 0x10, 0x00, 0x6f, 0x00, 0xc0, 0x02,
+        0x6f, 0x00, 0x00, 0x05, 0x6f, 0x00, 0xc0, 0x05, 0x6f, 0x00, 0x00, 0x07,
+        0x6f, 0x00, 0x00, 0x0a, 0x83, 0xc2, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00,
+        0x17, 0x03, 0x00, 0x00, 0x13, 0x03, 0xc3, 0xfd, 0xb3, 0x82, 0x62, 0x00,
+        0x67, 0x80, 0x02, 0x00, 0x03, 0xc3, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00,
+        0x83, 0x22, 0x85, 0x04, 0xe3, 0xce, 0x02, 0xfe, 0x83, 0xc2, 0x05, 0x00,
+        0x23, 0x24, 0x55, 0x04, 0x93, 0x85, 0x15, 0x00, 0x13, 0x03, 0xf3, 0xff,
+        0xe3, 0x44, 0x60, 0xfe, 0x6f, 0xf0, 0x5f, 0xfc, 0x83, 0x22, 0x45, 0x07,
+        0x93, 0xf2, 0x12, 0x00, 0xe3, 0x8c, 0x02, 0xfe, 0x6f, 0xf0, 0x5f, 0xfb,
+        0x83, 0xc2, 0x05, 0x00, 0xb3, 0x82, 0xa2, 0x00, 0x03, 0xc3, 0x15, 0x00,
+        0x93, 0x85, 0x25, 0x00, 0x23, 0xa0, 0x62, 0x00, 0x6f, 0xf0, 0xdf, 0xf9,
+        0x13, 0x06, 0x50, 0x00, 0xef, 0x00, 0x80, 0x01, 0x13, 0x06, 0x00, 0x00,
+        0xef, 0x00, 0x00, 0x01, 0x93, 0x72, 0x16, 0x00, 0xe3, 0x9a, 0x02, 0xfe,
+        0x6f, 0xf0, 0x1f, 0xf8, 0x83, 0x22, 0x85, 0x04, 0xe3, 0xce, 0x02, 0xfe,
+        0x23, 0x24, 0xc5, 0x04, 0x03, 0x26, 0xc5, 0x04, 0xe3, 0x4e, 0x06, 0xfe,
+        0x67, 0x80, 0x00, 0x00, 0x83, 0x22, 0x05, 0x04, 0x13, 0x03, 0x70, 0xff,
+        0xb3, 0xf2, 0x62, 0x00, 0x03, 0xc3, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00,
+        0xb3, 0xe2, 0x62, 0x00, 0x23, 0x20, 0x55, 0x04, 0x6f, 0xf0, 0x9f, 0xf4
+};
+#define STEP_EXIT                      4
+#define STEP_TX                                8
+#define STEP_TXWM_WAIT         12
+#define STEP_WRITE_REG         16
+#define STEP_WIP_WAIT          20
+#define STEP_SET_DIR           24
+#define STEP_NOP                       0xff
+
+struct algorithm_steps {
+       unsigned size;
+       unsigned used;
+       uint8_t **steps;
+};
+
+static struct algorithm_steps *as_new(void)
+{
+       struct algorithm_steps *as = calloc(1, sizeof(struct algorithm_steps));
+       as->size = 8;
+       as->steps = malloc(as->size * sizeof(as->steps[0]));
+       return as;
+}
+
+static struct algorithm_steps *as_delete(struct algorithm_steps *as)
+{
+       for (unsigned step = 0; step < as->used; step++) {
+               free(as->steps[step]);
+               as->steps[step] = NULL;
+       }
+       free(as);
+       return NULL;
+}
+
+static int as_empty(struct algorithm_steps *as)
+{
+       for (unsigned s = 0; s < as->used; s++) {
+               if (as->steps[s][0] != STEP_NOP)
+                       return 0;
+       }
+       return 1;
+}
+
+/* Return size of compiled program. */
+static unsigned as_compile(struct algorithm_steps *as, uint8_t *target,
+               unsigned target_size)
+{
+       unsigned offset = 0;
+       bool finish_early = false;
+       for (unsigned s = 0; s < as->used && !finish_early; s++) {
+               unsigned bytes_left = target_size - offset;
+               switch (as->steps[s][0]) {
+                       case STEP_NOP:
+                               break;
+                       case STEP_TX:
+                               {
+                                       unsigned size = as->steps[s][1];
+                                       if (size + 3 > bytes_left) {
+                                               finish_early = true;
+                                               break;
+                                       }
+                                       memcpy(target + offset, as->steps[s], 
size + 2);
+                                       offset += size + 2;
+                                       break;
+                               }
+                       case STEP_WRITE_REG:
+                               if (4 > bytes_left) {
+                                       finish_early = true;
+                                       break;
+                               }
+                               memcpy(target + offset, as->steps[s], 3);
+                               offset += 3;
+                               break;
+                       case STEP_SET_DIR:
+                               if (3 > bytes_left) {
+                                       finish_early = true;
+                                       break;
+                               }
+                               memcpy(target + offset, as->steps[s], 2);
+                               offset += 2;
+                               break;
+                       case STEP_TXWM_WAIT:
+                       case STEP_WIP_WAIT:
+                               if (2 > bytes_left) {
+                                       finish_early = true;
+                                       break;
+                               }
+                               memcpy(target + offset, as->steps[s], 1);
+                               offset += 1;
+                               break;
+                       default:
+                               assert(0);
+               }
+               if (!finish_early)
+                       as->steps[s][0] = STEP_NOP;
+       }
+       assert(offset + 1 <= target_size);
+       target[offset++] = STEP_EXIT;
+
+       LOG_DEBUG("%d-byte program:", offset);
+       for (unsigned i = 0; i < offset;) {
+               char buf[80];
+               for (unsigned x = 0; i < offset && x < 16; x++, i++)
+                       sprintf(buf + x*3, "%02x ", target[i]);
+               LOG_DEBUG("%s", buf);
+       }
+
+       return offset;
+}
+
+static void as_add_step(struct algorithm_steps *as, uint8_t *step)
+{
+       if (as->used == as->size) {
+               as->size *= 2;
+               as->steps = realloc(as->steps, sizeof(as->steps[0]) * as->size);
+               LOG_DEBUG("Increased size to 0x%x", as->size);
+       }
+       as->steps[as->used] = step;
+       as->used++;
+}
+
+static void as_add_tx(struct algorithm_steps *as, unsigned count, const 
uint8_t *data)
+{
+       LOG_DEBUG("count=%d", count);
+       while (count > 0) {
+               unsigned step_count = MIN(count, 255);
+               uint8_t *step = malloc(step_count + 2);
+               step[0] = STEP_TX;
+               step[1] = step_count;
+               memcpy(step + 2, data, step_count);
+               as_add_step(as, step);
+               data += step_count;
+               count -= step_count;
+       }
+}
+
+static void as_add_tx1(struct algorithm_steps *as, uint8_t byte)
+{
+       uint8_t data[1];
+       data[0] = byte;
+       as_add_tx(as, 1, data);
+}
+
+static void as_add_write_reg(struct algorithm_steps *as, uint8_t offset, 
uint8_t data)
+{
+       uint8_t *step = malloc(3);
+       step[0] = STEP_WRITE_REG;
+       step[1] = offset;
+       step[2] = data;
+       as_add_step(as, step);
+}
+
+static void as_add_txwm_wait(struct algorithm_steps *as)
+{
+       uint8_t *step = malloc(1);
+       step[0] = STEP_TXWM_WAIT;
+       as_add_step(as, step);
+}
+
+static void as_add_wip_wait(struct algorithm_steps *as)
+{
+       uint8_t *step = malloc(1);
+       step[0] = STEP_WIP_WAIT;
+       as_add_step(as, step);
+}
+
+static void as_add_set_dir(struct algorithm_steps *as, bool dir)
+{
+       uint8_t *step = malloc(2);
+       step[0] = STEP_SET_DIR;
+       step[1] = FESPI_FMT_DIR(dir);
+       as_add_step(as, step);
+}
+
+/* This should write something less than or equal to a page.*/
+static int steps_add_buffer_write(struct algorithm_steps *as,
+               const uint8_t *buffer, uint32_t chip_offset, uint32_t len)
+{
+       if (chip_offset & 0xFF000000) {
+               LOG_ERROR("FESPI interface does not support greater than 3B 
addressing, can't write to offset 0x%x",
+                               chip_offset);
+               return ERROR_FAIL;
+       }
+
+       as_add_tx1(as, SPIFLASH_WRITE_ENABLE);
+       as_add_txwm_wait(as);
+       as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
+
+       uint8_t setup[] = {
+               SPIFLASH_PAGE_PROGRAM,
+               chip_offset >> 16,
+               chip_offset >> 8,
+               chip_offset,
+       };
+       as_add_tx(as, sizeof(setup), setup);
+
+       as_add_tx(as, len, buffer);
+       as_add_txwm_wait(as);
+       as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
+
+       /* fespi_wip() */
+       as_add_set_dir(as, FESPI_DIR_RX);
+       as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
+       as_add_wip_wait(as);
+       as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
+       as_add_set_dir(as, FESPI_DIR_TX);
+
+       return ERROR_OK;
+}
+
+static int steps_execute(struct algorithm_steps *as,
+               struct flash_bank *bank, struct working_area *algorithm_wa,
+               struct working_area *data_wa)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+       int xlen = riscv_xlen(target);
+
+       struct reg_param reg_params[2];
+       init_reg_param(&reg_params[0], "a0", xlen, PARAM_OUT);
+       init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
+       buf_set_u64(reg_params[0].value, 0, xlen, ctrl_base);
+       buf_set_u64(reg_params[1].value, 0, xlen, data_wa->address);
+       while (!as_empty(as)) {
+               keep_alive();
+               uint8_t *data_buf = malloc(data_wa->size);
+               unsigned bytes = as_compile(as, data_buf, data_wa->size);
+               int retval = target_write_buffer(target, data_wa->address, 
bytes,
+                               data_buf);
+               free(data_buf);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Failed to write data to 0x%" TARGET_PRIxADDR 
": %d",
+                                       data_wa->address, retval);
+                       return retval;
+               }
+
+               retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
+                               algorithm_wa->address, algorithm_wa->address + 
4,
+                               10000, NULL);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Failed to execute algorithm at 0x%" 
TARGET_PRIxADDR ": %d",
+                                       algorithm_wa->address, retval);
+                       return retval;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
+               uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+       uint32_t cur_count, page_size, page_offset;
+       int sector;
+       int retval = 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 > fespi_info->dev->size_in_bytes) {
+               LOG_WARNING("Write past end of flash. Extra data discarded.");
+               count = fespi_info->dev->size_in_bytes - offset;
+       }
+
+       /* 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? */
+               if ((offset <
+                                       (bank->sectors[sector].offset + 
bank->sectors[sector].size))
+                               && ((offset + count - 1) >= 
bank->sectors[sector].offset)
+                               && bank->sectors[sector].is_protected) {
+                       LOG_ERROR("Flash sector %d protected", sector);
+                       return ERROR_FAIL;
+               }
+       }
+
+       struct working_area *algorithm_wa;
+       if (target_alloc_working_area(target, sizeof(algorithm_bin),
+                               &algorithm_wa) != ERROR_OK) {
+               LOG_WARNING("Couldn't allocate %zd-byte working area.",
+                               sizeof(algorithm_bin));
+               algorithm_wa = NULL;
+       } else {
+               retval = target_write_buffer(target, algorithm_wa->address,
+                               sizeof(algorithm_bin), algorithm_bin);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR 
": %d",
+                                       algorithm_wa->address, retval);
+                       target_free_working_area(target, algorithm_wa);
+                       algorithm_wa = NULL;
+               }
+       }
+
+       struct working_area *data_wa = NULL;
+       unsigned data_wa_size = 2 * count;
+       while (1) {
+               if (data_wa_size < 128) {
+                       LOG_WARNING("Couldn't allocate data working area.");
+                       target_free_working_area(target, algorithm_wa);
+                       algorithm_wa = NULL;
+               }
+               if (target_alloc_working_area_try(target, data_wa_size, 
&data_wa) ==
+                               ERROR_OK) {
+                       break;
+               }
+
+               data_wa_size /= 2;
+       }
+
+       page_size = fespi_info->dev->pagesize;
+
+       fespi_txwm_wait(bank);
+
+       /* Disable Hardware accesses*/
+       FESPI_DISABLE_HW_MODE();
+
+       /* poll WIP */
+       retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       struct algorithm_steps *as = as_new();
+
+       /* unaligned buffer head */
+       if (count > 0 && (offset & 3) != 0) {
+               cur_count = 4 - (offset & 3);
+               if (cur_count > count)
+                       cur_count = count;
+               if (algorithm_wa)
+                       retval = steps_add_buffer_write(as, buffer, offset, 
cur_count);
+               else
+                       retval = slow_fespi_write_buffer(bank, buffer, offset, 
cur_count);
+               if (retval != ERROR_OK)
+                       goto err;
+               offset += cur_count;
+               buffer += cur_count;
+               count -= cur_count;
+       }
+
+       page_offset = offset % page_size;
+       /* central part, aligned words */
+       while (count >= 4) {
+               /* clip block at page boundary */
+               if (page_offset + count > page_size)
+                       cur_count = page_size - page_offset;
+               else
+                       cur_count = count & ~3;
+
+               if (algorithm_wa)
+                       retval = steps_add_buffer_write(as, buffer, offset, 
cur_count);
+               else
+                       retval = slow_fespi_write_buffer(bank, buffer, offset, 
cur_count);
+               if (retval != ERROR_OK)
+                       goto err;
+
+               page_offset = 0;
+               buffer += cur_count;
+               offset += cur_count;
+               count -= cur_count;
+       }
+
+       /* buffer tail */
+       if (count > 0) {
+               if (algorithm_wa)
+                       retval = steps_add_buffer_write(as, buffer, offset, 
count);
+               else
+                       retval = slow_fespi_write_buffer(bank, buffer, offset, 
count);
+               if (retval != ERROR_OK)
+                       goto err;
+       }
+
+       if (algorithm_wa)
+               retval = steps_execute(as, bank, algorithm_wa, data_wa);
+
+err:
+       if (algorithm_wa) {
+               target_free_working_area(target, data_wa);
+               target_free_working_area(target, algorithm_wa);
+       }
+
+       as_delete(as);
+
+       /* Switch to HW mode before return to prompt */
+       FESPI_ENABLE_HW_MODE();
+       return retval;
+}
+
+/* Return ID of flash device */
+/* On exit, SW mode is kept */
+static int fespi_read_flash_id(struct flash_bank *bank, uint32_t *id)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base = fespi_info->ctrl_base;
+       int retval;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       fespi_txwm_wait(bank);
+
+       /* Disable Hardware accesses*/
+       FESPI_DISABLE_HW_MODE();
+
+       /* poll WIP */
+       retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       fespi_set_dir(bank, FESPI_DIR_RX);
+
+       /* Send SPI command "read ID" */
+       FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
+
+       fespi_tx(bank, SPIFLASH_READ_ID);
+       /* Send dummy bytes to actually read the ID.*/
+       fespi_tx(bank, 0);
+       fespi_tx(bank, 0);
+       fespi_tx(bank, 0);
+
+       /* read ID from Receive Register */
+       *id = 0;
+       if (fespi_rx(bank, NULL) != ERROR_OK)
+               return ERROR_FAIL;
+       uint8_t rx;
+       if (fespi_rx(bank, &rx) != ERROR_OK)
+               return ERROR_FAIL;
+       *id = rx;
+       if (fespi_rx(bank, &rx) != ERROR_OK)
+               return ERROR_FAIL;
+       *id |= (rx << 8);
+       if (fespi_rx(bank, &rx) != ERROR_OK)
+               return ERROR_FAIL;
+       *id |= (rx << 16);
+
+       FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
+
+       fespi_set_dir(bank, FESPI_DIR_TX);
+
+       return ERROR_OK;
+}
+
+static int fespi_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       uint32_t ctrl_base;
+       struct flash_sector *sectors;
+       uint32_t id = 0; /* silence uninitialized warning */
+       const struct fespi_target *target_device;
+       int retval;
+
+       if (fespi_info->probed)
+               free(bank->sectors);
+       fespi_info->probed = 0;
+
+       if (fespi_info->ctrl_base == 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 as 
FESPI capable",
+                                       target->tap->idcode);
+                       return ERROR_FAIL;
+               }
+
+               fespi_info->ctrl_base = target_device->ctrl_base;
+
+               LOG_DEBUG("Valid FESPI on device %s at address 0x%" PRIx32,
+                               target_device->name, bank->base);
+
+       } else {
+         LOG_DEBUG("Assuming FESPI as specified at address 0x%x with ctrl at 
0x%x",
+                   fespi_info->ctrl_base,
+                   bank->base);
+       }
+       ctrl_base = fespi_info->ctrl_base;
+
+       /* read and decode flash ID; returns in SW mode */
+       FESPI_WRITE_REG(FESPI_REG_TXCTRL, FESPI_TXWM(1));
+       fespi_set_dir(bank, FESPI_DIR_TX);
+
+       retval = fespi_read_flash_id(bank, &id);
+
+       FESPI_ENABLE_HW_MODE();
+       if (retval != ERROR_OK)
+               return retval;
+
+       fespi_info->dev = NULL;
+       for (const struct flash_device *p = flash_devices; p->name ; p++)
+               if (p->device_id == id) {
+                       fespi_info->dev = p;
+                       break;
+               }
+
+       if (!fespi_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 ")",
+                       fespi_info->dev->name, fespi_info->dev->device_id);
+
+       /* Set correct size value */
+       bank->size = fespi_info->dev->size_in_bytes;
+
+       /* create and fill sectors array */
+       bank->num_sectors =
+               fespi_info->dev->size_in_bytes / fespi_info->dev->sectorsize;
+       sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+       if (sectors == NULL) {
+               LOG_ERROR("not enough memory");
+               return ERROR_FAIL;
+       }
+
+       for (int sector = 0; sector < bank->num_sectors; sector++) {
+               sectors[sector].offset = sector * fespi_info->dev->sectorsize;
+               sectors[sector].size = fespi_info->dev->sectorsize;
+               sectors[sector].is_erased = -1;
+               sectors[sector].is_protected = 1;
+       }
+
+       bank->sectors = sectors;
+       fespi_info->probed = 1;
+       return ERROR_OK;
+}
+
+static int fespi_auto_probe(struct flash_bank *bank)
+{
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+       if (fespi_info->probed)
+               return ERROR_OK;
+       return fespi_probe(bank);
+}
+
+static int fespi_protect_check(struct flash_bank *bank)
+{
+       /* Nothing to do. Protection is only handled in SW. */
+       return ERROR_OK;
+}
+
+static int get_fespi_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct fespi_flash_bank *fespi_info = bank->driver_priv;
+
+       if (!(fespi_info->probed)) {
+               snprintf(buf, buf_size,
+                               "\nFESPI flash bank not probed yet\n");
+               return ERROR_OK;
+       }
+
+       snprintf(buf, buf_size, "\nFESPI flash information:\n"
+                       "  Device \'%s\' (ID 0x%08" PRIx32 ")\n",
+                       fespi_info->dev->name, fespi_info->dev->device_id);
+
+       return ERROR_OK;
+}
+
+struct flash_driver fespi_flash = {
+       .name = "fespi",
+       .flash_bank_command = fespi_flash_bank_command,
+       .erase = fespi_erase,
+       .protect = fespi_protect,
+       .write = fespi_write,
+       .read = default_flash_read,
+       .probe = fespi_probe,
+       .auto_probe = fespi_auto_probe,
+       .erase_check = default_flash_blank_check,
+       .protect_check = fespi_protect_check,
+       .info = get_fespi_info,
+       .free_driver_priv = default_flash_free_driver_priv
+};
diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c
index 273e850..6ac253d 100644
--- a/src/flash/nor/spi.c
+++ b/src/flash/nor/spi.c
@@ -54,6 +54,7 @@ const struct flash_device flash_devices[] = {
        FLASH_ID("sp s25fl164k",        0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 
0x800000),
        FLASH_ID("sp s25fl128",         0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 
0x1000000),
        FLASH_ID("sp s25fl256",         0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 
0x2000000),
+       FLASH_ID("cy s25fl256",         0xd8, 0xc7, 0x00196001, 0x100, 0x10000, 
0x2000000),
        FLASH_ID("atmel 25f512",        0x52, 0xc7, 0x0065001f, 0x80,  0x8000,  
0x10000),
        FLASH_ID("atmel 25f1024",       0x52, 0x62, 0x0060001f, 0x100, 0x8000,  
0x20000),
        FLASH_ID("atmel 25f2048",       0x52, 0x62, 0x0063001f, 0x100, 0x10000, 
0x40000),
@@ -71,6 +72,8 @@ const struct flash_device flash_devices[] = {
        FLASH_ID("micron n25q128",      0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 
0x1000000),
        FLASH_ID("micron n25q256 3v",   0xd8, 0xc7, 0x0019ba20, 0x100, 0x10000, 
0x2000000),
        FLASH_ID("micron n25q256 1.8v", 0xd8, 0xc7, 0x0019bb20, 0x100, 0x10000, 
0x2000000),
+       FLASH_ID("issi is25lp128",      0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 
0x1000000),
+       FLASH_ID("issi is25wp256d",     0xd8, 0xc7, 0x0019709d, 0x100, 0x10000, 
0x2000000),
        FLASH_ID("win w25q80bv",        0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 
0x100000),
        FLASH_ID("win w25q32fv",        0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 
0x400000),
        FLASH_ID("win w25q32dw",        0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 
0x400000),

-- 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
OpenOCD-devel mailing list
OpenOCD-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to