This is an automated email from Gerrit.

Bas Vermeulen ([email protected]) just uploaded a new patch set to Gerrit, 
which you can find at http://openocd.zylin.com/4304

-- gerrit

commit 03a03749226698273896c3a387206d9bdb80f0b7
Author: Bas Vermeulen <[email protected]>
Date:   Thu Nov 30 17:43:43 2017 +0100

    Flash driver for the QSPI NOR on LS1012ARDB board
    
    This is a first (very, very slow) version of a driver for
    the QSPI NOR on the LS1012ARDB board.
    
    Change-Id: Ie4a659457d111776483dcdd53784aa48be338609
    Signed-off-by: Bas Vermeulen <[email protected]>

diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 4dac110..e8cae32 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -38,6 +38,7 @@ NOR_DRIVERS = \
        %D%/non_cfi.c \
        %D%/nrf5.c \
        %D%/numicro.c \
+       %D%/nxpqspi.c \
        %D%/ocl.c \
        %D%/pic32mx.c \
        %D%/psoc4.c \
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 9594ed9..c426e93 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -51,6 +51,7 @@ extern struct flash_driver niietcm4_flash;
 extern struct flash_driver nrf5_flash;
 extern struct flash_driver nrf51_flash;
 extern struct flash_driver numicro_flash;
+extern struct flash_driver nxpqspi_flash;
 extern struct flash_driver ocl_flash;
 extern struct flash_driver pic32mx_flash;
 extern struct flash_driver psoc4_flash;
@@ -105,6 +106,7 @@ static struct flash_driver *flash_drivers[] = {
        &nrf5_flash,
        &nrf51_flash,
        &numicro_flash,
+       &nxpqspi_flash,
        &ocl_flash,
        &pic32mx_flash,
        &psoc4_flash,
diff --git a/src/flash/nor/nxpqspi.c b/src/flash/nor/nxpqspi.c
new file mode 100644
index 0000000..fd2d5ed
--- /dev/null
+++ b/src/flash/nor/nxpqspi.c
@@ -0,0 +1,586 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "imp.h"
+#include "spi.h"
+#include "nxpqspi.h"
+
+struct nxpqspi_flash_bank {
+       int probed;
+       uint32_t reg_base;
+       uint32_t bank_num;
+       const struct flash_device *dev;
+};
+
+static inline uint32_t swab32(uint32_t x)
+{
+       return ((uint32_t)(
+               (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) |
+               (((uint32_t)(x) & (uint32_t)0x0000ff00UL) <<  8) |
+               (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >>  8) |
+               (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)));
+}
+
+static uint32_t qspi_read32(struct flash_bank* bank, uint32_t addr)
+{
+       struct target *target = bank->target;
+       uint32_t value = 0xdeadbeef;
+
+       target_read_u32(target, addr, &value);
+
+       return be_to_h_u32((uint8_t*)&value);
+}
+
+static int qspi_write32(struct flash_bank *bank, uint32_t addr, uint32_t val)
+{
+       struct target *target = bank->target;
+       uint32_t value;
+
+       h_u32_to_be((uint8_t*)&value, val);
+       return target_write_u32(target, addr, value);
+}
+
+
+static void qspi_set_lut_sequence(struct flash_bank *bank, uint32_t seqid,
+       uint32_t lut_cmd0, uint32_t lut_cmd1, uint32_t lut_cmd2, uint32_t 
lut_cmd3)
+{
+       qspi_write32(bank, QSPI_LUT_BASE + ((seqid * 4 + 0) * 
sizeof(uint32_t)), lut_cmd0);
+       qspi_write32(bank, QSPI_LUT_BASE + ((seqid * 4 + 1) * 
sizeof(uint32_t)), lut_cmd1);
+       qspi_write32(bank, QSPI_LUT_BASE + ((seqid * 4 + 2) * 
sizeof(uint32_t)), lut_cmd2);
+       qspi_write32(bank, QSPI_LUT_BASE + ((seqid * 4 + 3) * 
sizeof(uint32_t)), lut_cmd3);
+}
+
+static void qspi_set_lut(struct flash_bank *bank)
+{
+       qspi_write32(bank, QSPI_LUTKEY, LUT_KEY_VALUE);
+       qspi_write32(bank, QSPI_LCKCR, QSPI_LCKCR_UNLOCK);
+
+       /* Write Enable */
+       qspi_set_lut_sequence(bank, SEQID_WREN, 
+               OPRND0(QSPI_CMD_WREN) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD),
+               0, 0, 0);
+       /* Fast Read */
+       qspi_set_lut_sequence(bank, SEQID_FAST_READ,
+               OPRND0(QSPI_CMD_FAST_READ_4B) | PAD0(LUT_PAD1) | 
INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR),
+               OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) | 
OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) | INSTR1(LUT_READ),
+               0, 0);
+       /* Read Status */
+       qspi_set_lut_sequence(bank, SEQID_RDSR,
+               OPRND0(QSPI_CMD_RDSR) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | 
OPRND1(1) | PAD1(LUT_PAD1) | INSTR1(LUT_READ),
+               0, 0, 0);
+       /* Erase a sector */
+       qspi_set_lut_sequence(bank, SEQID_SE,
+               OPRND0(QSPI_CMD_SE_4B) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | 
OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR),
+               0, 0, 0);
+       /* Erase the whole chip */
+       qspi_set_lut_sequence(bank, SEQID_CHIP_ERASE,
+               OPRND0(QSPI_CMD_CHIP_ERASE) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD), 
0, 0, 0);
+       /* Page Program */
+       qspi_set_lut_sequence(bank, SEQID_PP,
+               OPRND0(QSPI_CMD_PP_4B) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | 
OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR),
+               OPRND0(TX_BUFFER_SIZE) | PAD0(LUT_PAD1) | INSTR0(LUT_WRITE), 0, 
0);
+       /* Read JEDEC ID */
+       qspi_set_lut_sequence(bank, SEQID_RDID,
+               OPRND0(QSPI_CMD_RDID) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | 
OPRND1(8) | PAD1(LUT_PAD1) | INSTR1(LUT_READ),
+               0, 0, 0);
+       /* sub sector 4K erase */
+       qspi_set_lut_sequence(bank, SEQID_BE_4K,
+               OPRND0(QSPI_CMD_BE_4K) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | 
OPRND1(ADDR24BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR),
+               0, 0, 0);
+       /* read any device register */
+       qspi_set_lut_sequence(bank, SEQID_RDAR,
+               OPRND0(QSPI_CMD_RDAR) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | 
OPRND1(ADDR24BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR),
+               OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) | OPRND1(1) | 
PAD1(LUT_PAD1) | INSTR1(LUT_READ),
+               0, 0);
+       /* write any device register */
+       qspi_set_lut_sequence(bank, SEQID_WRAR,
+               OPRND0(QSPI_CMD_WRAR) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | 
OPRND1(ADDR24BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR),
+               OPRND0(1) | PAD0(LUT_PAD1) | INSTR0(LUT_WRITE),
+               0, 0);
+
+       /* lock the LUT */
+       qspi_write32(bank, QSPI_LUTKEY, LUT_KEY_VALUE);
+       qspi_write32(bank, QSPI_LCKCR, QSPI_LCKCR_LOCK);
+}
+
+static void qspi_op_rdid(struct flash_bank *bank, uint32_t *rxbuf, uint32_t 
len)
+{
+       uint32_t mcr_reg, rbsr_reg, data, size;
+       int i;
+
+       /* Save MCR */
+       mcr_reg = qspi_read32(bank, QSPI_MCR);
+       /* Reconfigure MCR */
+       qspi_write32(bank, QSPI_MCR, QSPI_MCR_CLR_RXF_MASK | 
QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+       /* USE IPS */
+       qspi_write32(bank, QSPI_RBCT, 1 << 8);
+
+       /* Select the right chip */
+       qspi_write32(bank, QSPI_SFAR, bank->base);
+       /* select the LUT command target */
+       qspi_write32(bank, QSPI_IPCR, (SEQID_RDID << 24));
+       /* wait for the command to finish */
+       while (qspi_read32(bank, QSPI_SR) & QSPI_SR_BUSY)
+               ;
+
+       /* read the data */
+       i = 0;
+       while ((RX_BUFFER_SIZE >= len) && (len > 0)) {
+               rbsr_reg = qspi_read32(bank, QSPI_RBSR);
+               if (rbsr_reg & (0x3f << 8)) {
+                       data = qspi_read32(bank, QSPI_RBDR_BASE + i * 
sizeof(uint32_t));
+                       data = swab32(data);
+                       size = (len < 4) ? len : 4;
+                       memcpy(rxbuf, &data, size);
+                       len -= size;
+                       rxbuf++;
+                       i++;
+               }
+       }
+
+       /* restore MCR */
+       qspi_write32(bank, QSPI_MCR, mcr_reg);
+}
+
+
+static int nxpqspi_read_id(struct flash_bank *bank, uint32_t *id)
+{
+       //qspi_set_lut(bank);
+       qspi_op_rdid(bank, id, sizeof(uint32_t));
+
+       return ERROR_OK;
+}
+
+static void qspi_op_erase(struct flash_bank *bank, uint32_t offset)
+{
+       uint32_t mcr_reg;
+
+       /* Save MCR */
+       mcr_reg = qspi_read32(bank, QSPI_MCR);
+       /* Reconfigure MCR */
+       qspi_write32(bank, QSPI_MCR, QSPI_MCR_CLR_RXF_MASK | 
QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+       /* USE IPS */
+       qspi_write32(bank, QSPI_RBCT, 1 << 8);
+
+       /* Select the right chip */
+       qspi_write32(bank, QSPI_SFAR, bank->base + offset);
+
+       /* Write enable */
+       LOG_INFO("Write Enable");
+       qspi_write32(bank, QSPI_IPCR, (SEQID_WREN << 24));
+       /* wait for the command to finish */
+       while (qspi_read32(bank, QSPI_SR) & QSPI_SR_BUSY)
+               ;
+       LOG_INFO("Write Enable done");
+
+       /* select the LUT command target */
+       LOG_INFO("Sector Erase");
+       qspi_write32(bank, QSPI_IPCR, (SEQID_SE << 24));
+       /* wait for the command to finish */
+       while (qspi_read32(bank, QSPI_SR) & QSPI_SR_BUSY)
+               ;
+       LOG_INFO("Sector Erase done");
+
+       /* restore MCR */
+       qspi_write32(bank, QSPI_MCR, mcr_reg);
+}
+
+static int nxpqspi_block_erase(struct flash_bank *bank, uint32_t offset)
+{
+       //qspi_set_lut(bank);
+       qspi_op_erase(bank, offset);
+       return ERROR_OK;
+}
+
+static void qspi_op_chip_erase(struct flash_bank *bank)
+{
+       uint32_t mcr_reg;
+
+       /* Save MCR */
+       mcr_reg = qspi_read32(bank, QSPI_MCR);
+       /* Reconfigure MCR */
+       qspi_write32(bank, QSPI_MCR, QSPI_MCR_CLR_RXF_MASK | 
QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+       /* USE IPS */
+       qspi_write32(bank, QSPI_RBCT, 1 << 8);
+
+       /* Select the right chip */
+       qspi_write32(bank, QSPI_SFAR, bank->base);
+
+       /* Write enable */
+       qspi_write32(bank, QSPI_IPCR, (SEQID_WREN << 24));
+       /* wait for the command to finish */
+       while (qspi_read32(bank, QSPI_SR) & QSPI_SR_BUSY)
+               ;
+
+       /* select the LUT command target */
+       qspi_write32(bank, QSPI_IPCR, (SEQID_CHIP_ERASE << 24));
+       /* wait for the command to finish */
+       while (qspi_read32(bank, QSPI_SR) & QSPI_SR_BUSY)
+               ;
+
+       /* restore MCR */
+       qspi_write32(bank, QSPI_MCR, mcr_reg);
+}
+
+static int nxpqspi_bulk_erase(struct flash_bank *bank)
+{
+       //qspi_set_lut(bank);
+       qspi_op_chip_erase(bank);
+
+       return ERROR_OK;
+}
+
+static int nxpqspi_flash_erase(struct flash_bank *bank, int first, int last)
+{
+       struct target *target = bank->target;
+       struct nxpqspi_flash_bank *info = bank->driver_priv;
+       int retval = ERROR_OK;
+       int sector;
+
+       LOG_INFO("Erase from sector %d to sector %d", 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;
+       }
+
+       for (sector = first; sector <= last; sector++) {
+               if (bank->sectors[sector].is_protected) {
+                       LOG_ERROR("FLash sector %d protected", sector);
+                       return ERROR_FAIL;
+               }
+       }
+
+       if (first == 0 && last == (bank->num_sectors - 1) &&
+               info->dev->chip_erase_cmd != info->dev->erase_cmd) {
+               LOG_DEBUG("Chip supports the bulk erase command."\
+                       " Will use bulk erase instead of sector by sector 
erase.");
+               retval = nxpqspi_bulk_erase(bank);
+               if (retval == ERROR_OK)
+                       return retval;
+               else
+                       LOG_WARNING("Bulk flash erase failed."
+                               " Falling back to sector by sector erase.");
+       }
+
+       for (sector = first; sector <= last; sector++) {
+               retval = nxpqspi_block_erase(bank, sector * 
info->dev->sectorsize);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return retval;
+}
+
+static void qspi_op_write(struct flash_bank *bank, const uint8_t *buffer, 
uint32_t offset, uint32_t count)
+{
+       uint32_t mcr_reg, data, status_reg, rbsr_reg;
+       int i, size, tx_size;
+
+       LOG_INFO("Writing 0x%08" PRIx32 " bytes at offset 0x%08" PRIx32, count, 
offset);
+
+       /* Save MCR */
+       mcr_reg = qspi_read32(bank, QSPI_MCR);
+       /* Reconfigure MCR */
+       qspi_write32(bank, QSPI_MCR, QSPI_MCR_CLR_RXF_MASK | 
QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+       /* USE IPS */
+       qspi_write32(bank, QSPI_RBCT, 1 << 8);
+
+       status_reg = 0;
+       while ((status_reg & 0x02) != 0x02) {
+               qspi_write32(bank, QSPI_IPCR, SEQID_WREN << 24);
+               while (qspi_read32(bank, QSPI_SR) & QSPI_SR_BUSY)
+                       ;
+
+               qspi_write32(bank, QSPI_IPCR, (SEQID_RDSR << 24) | 1 /* PAR_EN 
*/);
+               while (qspi_read32(bank, QSPI_SR) & QSPI_SR_BUSY)
+                       ;
+
+               rbsr_reg = qspi_read32(bank, QSPI_RBSR);
+               if (rbsr_reg & (0x3f << 8))
+                       status_reg = qspi_read32(bank, QSPI_RBDR_BASE + 0 * 
sizeof(uint32_t));
+
+               qspi_write32(bank, QSPI_MCR,
+                               qspi_read32(bank, QSPI_MCR) | 
QSPI_MCR_CLR_RXF_MASK);
+       }
+
+       qspi_write32(bank, QSPI_SFAR, bank->base + offset);
+
+       tx_size = count > TX_BUFFER_SIZE ? TX_BUFFER_SIZE : count;
+       size = tx_size / 16;
+       if (tx_size % 16)
+               size++;
+       for (i = 0; i < (size * 4); i++) {
+               memcpy(&data, buffer, sizeof(uint32_t));
+               qspi_write32(bank, QSPI_TBDR, data);
+               buffer += 4;
+       }
+
+       qspi_write32(bank, QSPI_IPCR, (SEQID_PP << 24) | tx_size);
+       while (qspi_read32(bank, QSPI_SR) & QSPI_SR_BUSY)
+               ;
+
+       qspi_write32(bank, QSPI_MCR, mcr_reg);
+}
+
+static int nxpqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
+       uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct nxpqspi_flash_bank *info = bank->driver_priv;
+       int retval = ERROR_OK;
+       int sector;
+
+       LOG_INFO("Writing 0x%08" PRIx32 " bytes to offset 0x%08" PRIx32, count, 
offset);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset + count > info->dev->size_in_bytes) {
+               LOG_WARNING("Writes past the end of flash. Extra data 
discarded.");
+               count = info->dev->size_in_bytes - offset;
+       }
+
+       for (sector = 0; sector < bank->num_sectors; sector++) {
+               /* Start offset in or before this sector? */
+               /* End offset in or before 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 is protected", sector);
+                       return ERROR_FAIL;
+               }
+       }
+
+       do {
+               int len = count > TX_BUFFER_SIZE ? TX_BUFFER_SIZE : count;
+               qspi_op_write(bank, buffer, offset, len);
+               /* advance */
+               count -= len;
+               offset += len;
+               buffer += len;
+       } while (count);
+
+       return retval;
+}
+
+static void qspi_op_read(struct flash_bank *bank, uint8_t *buffer, uint32_t 
offset, uint32_t count)
+{
+       uint32_t mcr_reg, data;
+       int i, size;
+
+       /* Save MCR */
+       mcr_reg = qspi_read32(bank, QSPI_MCR);
+       /* Reconfigure MCR */
+       qspi_write32(bank, QSPI_MCR, QSPI_MCR_CLR_RXF_MASK | 
QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+       /* USE IPS */
+       qspi_write32(bank, QSPI_RBCT, 1 << 8);
+
+       while (count > 0) {
+               /* Select the right block */
+               qspi_write32(bank, QSPI_SFAR, bank->base + offset);
+
+               size = (count > RX_BUFFER_SIZE) ? RX_BUFFER_SIZE : count;
+
+               /* select the LUT command target */
+               qspi_write32(bank, QSPI_IPCR, (SEQID_FAST_READ << 24));
+               /* wait for the command to finish */
+               while (qspi_read32(bank, QSPI_SR) & QSPI_SR_BUSY)
+                       ;
+
+               offset += size;
+               count -= size;
+
+               i = 0;
+               while ((RX_BUFFER_SIZE >= size) && (size > 0)) {
+                       data = qspi_read32(bank, QSPI_RBDR_BASE + i * 
sizeof(uint32_t));
+                       if (size < (int)sizeof(data))
+                               memcpy(buffer, &data, size);
+                       else
+                               memcpy(buffer, &data, sizeof(data));
+                       buffer += sizeof(data);
+                       size -= sizeof(data);
+                       i++;
+               }
+               qspi_write32(bank, QSPI_MCR, qspi_read32(bank, QSPI_MCR) | 
QSPI_MCR_CLR_RXF_MASK);
+       }
+
+       /* restore MCR */
+       qspi_write32(bank, QSPI_MCR, mcr_reg);
+}
+
+static int nxpqspi_flash_read(struct flash_bank *bank, uint8_t *buffer, 
uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct nxpqspi_flash_bank *info = bank->driver_priv;
+       int retval = ERROR_OK;
+
+       LOG_INFO("Reading 0x%08" PRIx32 " bytes from offset 0x%08" PRIx32, 
count, offset);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!info->probed) {
+               LOG_ERROR("Flash bank not probed");
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       //qspi_set_lut(bank);
+       qspi_op_read(bank, buffer, offset, count);
+       
+       return retval;
+}
+
+static int nxpqspi_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct nxpqspi_flash_bank *info = bank->driver_priv;
+       uint32_t id = 0;
+       int retval;
+       struct flash_sector *sectors;
+
+       /* If we've already probed, we should be fine to skip this time. */
+       if (info->probed)
+               return ERROR_OK;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       info->probed = 0;
+       info->bank_num = bank->bank_number;
+
+       /* Set up the LUT table */
+       qspi_set_lut(bank);
+
+       /* Read flash JEDEC ID */
+       retval = nxpqspi_read_id(bank, &id);
+       if (retval != ERROR_OK)
+               return retval;
+
+       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;
+
+       /* create and fill sectors array */
+       bank->num_sectors = info->dev->size_in_bytes / info->dev->sectorsize;
+       sectors = malloc(sizeof(struct flash_sector) * 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 * info->dev->sectorsize;
+               sectors[sector].size = info->dev->sectorsize;
+               sectors[sector].is_erased = -1;
+               sectors[sector].is_protected = 0;
+       }
+
+       bank->sectors = sectors;
+       info->probed = 1;
+
+       return ERROR_OK;
+}
+
+static int nxpqspi_auto_probe(struct flash_bank *bank)
+{
+       struct nxpqspi_flash_bank *info = bank->driver_priv;
+       if (info->probed)
+               return ERROR_OK;
+       return nxpqspi_probe(bank);
+}
+
+static int nxpqspi_flash_erase_check(struct flash_bank *bank)
+{
+       /* Not implemented yet */
+       return ERROR_OK;
+}
+
+static int nxpqspi_protect_check(struct flash_bank *bank)
+{
+       /* Not implemented yet */
+       return ERROR_OK;
+}
+
+int nxpqspi_get_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct nxpqspi_flash_bank *info = bank->driver_priv;
+
+       if (!info->probed) {
+               snprintf(buf, buf_size,
+                       "\nQSPI flash bank not probed yet\n");
+               return ERROR_OK;
+       }
+
+       snprintf(buf, buf_size, "\nQSPI flash information:\n"
+               "  Device \'%s\' ID 0x%08" PRIx32 "\n",
+               info->dev->name, info->dev->device_id);
+
+       return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(nxpqspi_flash_bank_command)
+{
+       struct nxpqspi_flash_bank *info;
+
+       if (CMD_ARGC < 7)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       info = malloc(sizeof(struct nxpqspi_flash_bank));
+       if (!info) {
+               LOG_ERROR("not enough memory");
+               return ERROR_FAIL;
+       }
+
+       /* Get QSPI controller register map base address */
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->reg_base);
+       LOG_INFO("reg_base = 0x%08" PRIx32, info->reg_base);
+       bank->driver_priv = info;
+       info->probed = 0;
+
+       return ERROR_OK;
+}
+
+struct flash_driver nxpqspi_flash = {
+       .name                   = "nxpqspi",
+       .flash_bank_command     = nxpqspi_flash_bank_command,
+       .erase                  = nxpqspi_flash_erase,
+       .protect                = NULL,
+       .write                  = nxpqspi_flash_write,
+       .read                   = nxpqspi_flash_read,
+       .probe                  = nxpqspi_probe,
+       .auto_probe             = nxpqspi_auto_probe,
+       .erase_check            = nxpqspi_flash_erase_check,
+       .protect_check          = nxpqspi_protect_check,
+       .info                   = nxpqspi_get_info,
+};
diff --git a/src/flash/nor/nxpqspi.h b/src/flash/nor/nxpqspi.h
new file mode 100644
index 0000000..10383d8
--- /dev/null
+++ b/src/flash/nor/nxpqspi.h
@@ -0,0 +1,90 @@
+#pragma once
+
+#define QSPI_BASE              0x1550000
+#define QSPI_MCR               (QSPI_BASE + 0x000)
+#define QSPI_MCR_END_CFD_SHIFT 2
+#define QSPI_MCR_END_CFD_MASK  (3 << QSPI_MCR_END_CFD_SHIFT)
+#define QSPI_MCR_END_CFD_LE    (1 << QSPI_MCR_END_CFD_SHIFT)
+#define QSPI_MCR_CLR_RXF_SHIFT 10
+#define QSPI_MCR_CLR_RXF_MASK  (1 << QSPI_MCR_CLR_RXF_SHIFT)
+#define QSPI_MCR_CLR_TXF_SHIFT 11
+#define QSPI_MCR_CLR_TXF_MASK  (1 << QSPI_MCR_CLR_TXF_SHIFT)
+#define QSPI_MCR_RESERVED_SHIFT        16
+#define QSPI_MCR_RESERVED_MASK (0xf << QSPI_MCR_RESERVED_SHIFT)
+#define QSPI_IPCR              (QSPI_BASE + 0x008)
+#define QSPI_FLSHCR            (QSPI_BASE + 0x00c)
+#define QSPI_BUF0CR            (QSPI_BASE + 0x010)
+#define QSPI_BUF1CR            (QSPI_BASE + 0x014)
+#define QSPI_BUF2CR            (QSPI_BASE + 0x018)
+#define QSPI_BUF3CR            (QSPI_BASE + 0x01c)
+#define QSPI_SFAR              (QSPI_BASE + 0x100)
+#define QSPI_RBSR              (QSPI_BASE + 0x10c)
+#define QSPI_RBCT              (QSPI_BASE + 0x110)
+#define QSPI_TBDR              (QSPI_BASE + 0x154)
+#define QSPI_SR                        (QSPI_BASE + 0x15c)
+#define QSPI_SR_BUSY           (1 << 0)
+#define QSPI_RBDR_BASE         (QSPI_BASE + 0x200)
+#define QSPI_LUTKEY            (QSPI_BASE + 0x300)
+#define LUT_KEY_VALUE          0x5AF05AF0
+#define QSPI_LCKCR             (QSPI_BASE + 0x304)
+#define QSPI_LCKCR_LOCK                0x1
+#define QSPI_LCKCR_UNLOCK      0x2
+#define QSPI_LUT_BASE          (QSPI_BASE + 0x310)
+
+#define SEQID_WREN             1
+#define SEQID_FAST_READ                2
+#define SEQID_RDSR             3
+#define SEQID_SE               4
+#define SEQID_CHIP_ERASE       5
+#define SEQID_PP               6
+#define SEQID_RDID             7
+#define SEQID_BE_4K            8
+#define SEQID_BRRD             9
+#define SEQID_BRWR             10
+#define SEQID_RDEAR            11
+#define SEQID_WREAR            12
+#define SEQID_WRAR             13
+#define SEQID_RDAR             14
+
+/* QSPI commands */
+#define QSPI_CMD_PP            0x02    /* Page Program (up to 256 byte) */
+#define QSPI_CMD_PP_4B         0x12
+#define QSPI_CMD_RDSR          0x05    /* Read status register */
+#define QSPI_CMD_WREN          0x06    /* Write Enable */
+#define QSPI_CMD_FAST_READ             0x0b    /* Read data bytes (high 
frequency) */
+#define QSPI_CMD_FAST_READ_4B  0x0c
+#define QSPI_CMD_BE_4K         0x20    /* 4K erase */
+#define QSPI_CMD_CHIP_ERASE    0xc7    /* Erase whole flash chip */
+#define QSPI_CMD_SE            0xd8    /* Sector erase (usually 64 KiB) */
+#define QSPI_CMD_SE_4B         0xdc
+#define QSPI_CMD_RDID          0x9f    /* Read JEDEC ID */
+#define QSPI_CMD_WRAR          0x71
+#define QSPI_CMD_RDAR          0x65
+
+
+#define OPRND0_SHIFT           0
+#define OPRND0(x)              ((x) << OPRND0_SHIFT)
+#define PAD0_SHIFT             8
+#define PAD0(x)                        ((x) << PAD0_SHIFT)
+#define INSTR0_SHIFT           10
+#define INSTR0(x)              ((x) << INSTR0_SHIFT)
+#define OPRND1_SHIFT           16
+#define OPRND1(x)              ((x) << OPRND1_SHIFT)
+#define PAD1_SHIFT             24
+#define PAD1(x)                        ((x) << PAD1_SHIFT)
+#define INSTR1_SHIFT           26
+#define INSTR1(x)              ((x) << INSTR1_SHIFT)
+
+#define LUT_CMD                        1
+#define LUT_ADDR               2
+#define LUT_DUMMY              3
+#define LUT_READ               7
+#define LUT_WRITE              8
+#define LUT_PAD1               0
+#define LUT_PAD2               1
+#define LUT_PAD3               2
+
+#define ADDR24BIT              0x18
+#define ADDR32BIT              0x20
+#define TX_BUFFER_SIZE         0x40
+#define RX_BUFFER_SIZE         0x80
diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c
index 6501fbc..9e23905 100644
--- a/src/flash/nor/spi.c
+++ b/src/flash/nor/spi.c
@@ -78,5 +78,6 @@ const struct flash_device flash_devices[] = {
        FLASH_ID("gd gd25q16c",    0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 
0x200000),
        FLASH_ID("gd gd25q32c",    0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 
0x400000),
        FLASH_ID("gd gd25q128c",   0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 
0x1000000),
+       FLASH_ID("cyp s25fs512s",   0xdc, 0xc7, 0x0102204d, 0x100, 0x40000, 
0x4000000),
        FLASH_ID(NULL,             0,    0,        0,          0,     0,       
0)
 };

-- 

------------------------------------------------------------------------------
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to