This is an automated email from Gerrit.

"Travis Lowe <tml...@gmail.com>" just uploaded a new patch set to Gerrit, which 
you can find at https://review.openocd.org/c/openocd/+/8147

-- gerrit

commit ce54f02c4f972901758ce354c7c2a2708d8a34dd
Author: Travis Lowe <tml...@gmail.com>
Date:   Wed Nov 29 13:27:37 2023 -0600

    flash/nor/lpc313x-spi: add external SPI NOR flashloader
    
    Adding flashloader for an external flash device connected to
    LPC3131 SPI interface
    
    Change-Id: Ie3a5ca7c401a9e8b80d02a25981e7009b147a26b
    Signed-off-by: Travis Lowe <tml...@gmail.com>

diff --git a/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_read.S 
b/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_read.S
new file mode 100644
index 0000000000..bc4fb33b72
--- /dev/null
+++ b/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_read.S
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*input parameters:
+    r0 - byte count (decremented on each SPI transfer)
+    r1 - head (write) pointer (incremented on byte read and reset remotely by 
code in openOCD)
+    r2 - tail (read) pointer
+
+    clobbered registers (reused after initial input):
+    r3 - chip_select
+    r4 - command address
+    r5 - command length
+    r6 - circular FIFO start address
+    r7 - circular FIFO end address
+*/
+
+#include "../../../../src/flash/nor/lpc313x-spi/lpc313x_spi.h"
+
+    .text
+       .arm
+       .syntax unified
+    .global _begin
+
+
+_begin:                                      /*Store local variables */
+
+    ldr r8, #init_complete_flag_address       /*if init previously completed, 
continue reading bytes */
+    ldr r9, magic_number
+    cmp r8, r9
+    beq data_transfer_continue
+
+    str r3, #chip_sel
+    str r4, #command_address
+    str r5, #command_length
+    str r6, #fifo_start_address
+    str r7, #fifo_end_address
+
+    ldr r7, =SPI_CONFIG                             /* load SPI_CONFIG 
register address into r7 */
+    ldr r8, [r7]
+    mov r9, #SPI_CONFIG_SPI_ENABLE_BIT_MASK         /* load SPI ENABLE bit 
mask into r9 */
+    orr r8, r8, r9                                  /* r8 = SPI_CONFIG | 
SPI_CONFIG_SPI_ENABLE_BIT_MASK */
+    str r8, [r7]                                    /* write enable bit in SPI 
CONFIG register. */
+    bl set_chip_select_high
+    nop
+    bl set_chip_select_low
+    bl flush_spi_rx_fifo
+    b flush_spi_tx_fifo
+
+
+
+    .func _set_chip_select_low
+set_chip_select_low:
+    ldr r7, chip_sel
+    @ ldr r7, [r7]
+    cmp r7, #0                          @ if cs == 0
+    beq set_cs_0_low
+    cmp r7, #1                          @ if cs == 1
+    beq set_cs_1_low
+    cmp r7, #2                          @ if cs == 2
+    beq set_cs_2_low
+
+set_cs_0_low:
+    ldr r7, =IOCONFIG_SPI_MODE_1_SET                @ load mode 1 register 
address
+    mov r8, #IOCONFIG_SPI_CS_0_BITMASK              @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_SPI_MODE_0_CLEAR              @ load mode 0 register 
address
+    mov r8, #IOCONFIG_SPI_CS_0_BITMASK              @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_low_done
+set_cs_1_low:
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_1_SET        @ load mode 1 register 
address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_1_BITMASK      @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_0_CLEAR      @ load mode 0 register 
address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_1_BITMASK      @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_low_done
+set_cs_2_low:
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_1_SET        @ load mode 1 register 
address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_2_BITMASK      @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_0_CLEAR      @ load mode 0 register 
address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_2_BITMASK      @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_low_done
+set_cs_low_done:
+    mov pc, lr
+    .endfunc
+
+    .func _set_chip_select_high
+set_chip_select_high:
+    ldr r7, chip_sel
+    cmp r7, #0                          @ if cs == 0
+    beq set_cs_0_high
+    cmp r7, #1                          @ if cs == 1
+    beq set_cs_1_high
+    cmp r7, #2                          @ if cs == 2
+    beq set_cs_2_high
+
+set_cs_0_high:
+    ldr r7, =IOCONFIG_SPI_MODE_1_SET                @ load first mode 1 
register address
+    mov r8, #IOCONFIG_SPI_CS_0_BITMASK              @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_SPI_MODE_0_SET                @ load second mode 0 
register address
+    mov r8, #IOCONFIG_SPI_CS_0_BITMASK              @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_high_done
+set_cs_1_high:
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_1_SET        @ load first mode 1 
register address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_1_BITMASK      @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_0_SET        @ load second mode 0 
register address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_1_BITMASK      @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_high_done
+set_cs_2_high:
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_1_SET        @ load first mode 1 
register address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_2_BITMASK      @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_0_SET        @ load second mode 0 
register address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_2_BITMASK      @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_high_done
+set_cs_high_done:
+    mov pc, lr
+    .endfunc
+
+    .func _flush_spi_rx_fifo
+flush_spi_rx_fifo:
+    ldr r3, =SPI_FIFO_DATA
+    ldr r4, =SPI_STATUS
+flush_loop:
+    ldr r5, [r3]        /*read spi fifo */
+    ldr r5, [r4]        /*Read spi status register */
+    mov r6, #SPI_STATUS_RX_FIFO_EMPTY_BIT_MASK
+    ands r5, r5, r6
+    beq flush_loop      /*keep reading fifo until its empty */
+    mov pc, lr
+    .endfunc
+
+flush_spi_tx_fifo:
+    ldr r3, =SPI_TX_FIFO_FLUSH
+    mov r4, #1
+    str r4, [r3]
+
+
+send_command:
+    ldr r3, command_address
+    ldr r4, command_length
+    ldr r5, =SPI_FIFO_DATA
+    ldr r6, =SPI_STATUS
+command_loop:
+    cmp r4, #0
+    beq data_transfer
+command_check_ready_for_write:                 /*wait until spi fifo register 
can be written*/
+    ldr r7, [r6]
+    mov r8, #SPI_STATUS_TX_FIFO_FULL_BIT_MASK
+    ands r7, r7, r8
+    bne command_check_ready_for_write
+command_byte_write:
+    ldrb r9, [r3]                                   /* load byte to be written 
into r9 */
+    strb r9, [r5]
+
+command_wait_for_spi:
+    ldr r7, [r6]
+    mov r8, #SPI_STATUS_BUSY_BIT_MASK
+    ands r7, r7, r8
+    bne command_wait_for_spi
+command_check_ready_for_read:               /*wait until spi fifo register can 
be read*/
+    ldr r7, [r6]
+    mov r8, #SPI_STATUS_RX_FIFO_EMPTY_BIT_MASK
+    ands r7, r7, r8
+    bne command_check_ready_for_read
+command_byte_read:                         /*dummy fifo read */
+    ldrb r7, [r5]
+
+    add  r3, r3, #1                                 /* increment address 
pointer */
+    sub  r4, r4, #1                                 /* decrement byte count */
+    b command_loop
+
+data_transfer:
+    bl flush_spi_rx_fifo
+data_transfer_continue:
+    bl set_chip_select_low
+    ldr r3, fifo_start_address
+    ldr r4, fifo_end_address
+    ldr r5, =SPI_STATUS
+    ldr r6, =SPI_FIFO_DATA
+data_transfer_loop:
+    cmp r0, #0                                      /*if byte count == 0 
branch to done */
+    beq done
+check_fifo_full:
+    cmp r1, r4                        /*compare head with fifo end address */
+    bne check_head_plus_one           /*if head != fifo end, branch to 
check_head_plus_one */
+    cmp r2, r3                        /*if head == fifo end, check if tail == 
fifo start */
+    beq fifo_full                     /*if tail == fifo start, fifo is full */
+    b data_check_ready_for_write
+check_head_plus_one:                  /* checking if head +1 == tail */
+    add r7, r1, #1                    /* get head + 1 */
+    cmp r2, r7                        /* if head + 1 == tail, fifo is full */
+    beq fifo_full
+
+data_check_ready_for_write:                 /*wait until spi fifo register can 
be written*/
+    ldr r7, [r5]
+    mov r8, #SPI_STATUS_TX_FIFO_FULL_BIT_MASK
+    ands r7, r7, r8
+    bne data_check_ready_for_write
+byte_write:
+    mov r7, #0                           /*write a zero to spi*/
+    strb r7, [r6]
+wait_for_spi:
+    ldr r7, [r5]
+    mov r8, #SPI_STATUS_BUSY_BIT_MASK
+    ands r7, r7, r8
+    bne wait_for_spi
+data_check_ready_for_read:      /*wait until spi fifo register can be read*/
+    ldr r7, [r5]
+    mov r8, #SPI_STATUS_RX_FIFO_EMPTY_BIT_MASK
+    ands r7, r7, r8
+    bne data_check_ready_for_read
+byte_read:
+    ldrb r7, [r6]
+    strb r7, [r1]
+    sub  r0, r0, #1                      /*decrement byte count */
+
+increment_head:
+    cmp r1, r4                        /*check head against end  */
+    bne increment_head_plus_one       /*if head != fifo end, branch to 
check_head_plus_one */
+    ldr r1, fifo_start_address        /*else, set head to fifo start */
+    b data_transfer_loop
+increment_head_plus_one:
+    add r1, r1, #1                    /*else increment head and continue 
writing fifo with spi data */
+    b data_transfer_loop                    /*branch to start of loop */
+
+
+fifo_full:
+    ldr r7, magic_number /*magic number */
+    str r7, #init_complete_flag_address
+    bkpt #0
+
+done:
+    ldr r7, magic_number /*magic number */
+    str r7, #init_complete_flag_address
+    bl set_chip_select_high
+    bkpt #1
+
+done_error:
+    bl set_chip_select_high
+    bkpt #2
+
+.align 4
+chip_sel:
+    .word 0
+command_address:
+    .space 8, 0xff
+command_length:
+    .word 0
+fifo_start_address:
+    .word 0
+fifo_end_address:
+    .word 0
+init_complete_flag_address:
+    .space 4, 0xff
+magic_number:
+    .short 0xDEED
diff --git a/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_read.inc 
b/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_read.inc
new file mode 100644
index 0000000000..8ae5140444
--- /dev/null
+++ b/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_read.inc
@@ -0,0 +1,46 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0x90,0x82,0x9f,0xe5,0x90,0x92,0x9f,0xe5,0x09,0x00,0x58,0xe1,0x6c,0x00,0x00,0x0a,
+0x68,0x32,0x8f,0xe5,0x68,0x42,0x8f,0xe5,0x6c,0x52,0x8f,0xe5,0x6c,0x62,0x8f,0xe5,
+0x6c,0x72,0x8f,0xe5,0x74,0x72,0x9f,0xe5,0x00,0x80,0x97,0xe5,0x01,0x90,0xa0,0xe3,
+0x09,0x80,0x88,0xe1,0x00,0x80,0x87,0xe5,0x20,0x00,0x00,0xeb,0x00,0x00,0xa0,0xe1,
+0x01,0x00,0x00,0xeb,0x3a,0x00,0x00,0xeb,0x41,0x00,0x00,0xea,0x2c,0x72,0x9f,0xe5,
+0x00,0x00,0x57,0xe3,0x03,0x00,0x00,0x0a,0x01,0x00,0x57,0xe3,0x08,0x00,0x00,0x0a,
+0x02,0x00,0x57,0xe3,0x0d,0x00,0x00,0x0a,0x34,0x72,0x9f,0xe5,0x10,0x80,0xa0,0xe3,
+0x00,0x80,0x87,0xe5,0x2c,0x72,0x9f,0xe5,0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,
+0x0d,0x00,0x00,0xea,0x20,0x72,0x9f,0xe5,0x08,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,
+0x18,0x72,0x9f,0xe5,0x08,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,0x06,0x00,0x00,0xea,
+0x04,0x72,0x9f,0xe5,0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,0xfc,0x71,0x9f,0xe5,
+0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,0xff,0xff,0xff,0xea,0x0e,0xf0,0xa0,0xe1,
+0xb8,0x71,0x9f,0xe5,0x00,0x00,0x57,0xe3,0x03,0x00,0x00,0x0a,0x01,0x00,0x57,0xe3,
+0x08,0x00,0x00,0x0a,0x02,0x00,0x57,0xe3,0x0d,0x00,0x00,0x0a,0xc0,0x71,0x9f,0xe5,
+0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,0xc4,0x71,0x9f,0xe5,0x10,0x80,0xa0,0xe3,
+0x00,0x80,0x87,0xe5,0x0d,0x00,0x00,0xea,0xac,0x71,0x9f,0xe5,0x08,0x80,0xa0,0xe3,
+0x00,0x80,0x87,0xe5,0xac,0x71,0x9f,0xe5,0x08,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,
+0x06,0x00,0x00,0xea,0x90,0x71,0x9f,0xe5,0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,
+0x90,0x71,0x9f,0xe5,0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,0xff,0xff,0xff,0xea,
+0x0e,0xf0,0xa0,0xe1,0x80,0x31,0x9f,0xe5,0x80,0x41,0x9f,0xe5,0x00,0x50,0x93,0xe5,
+0x00,0x50,0x94,0xe5,0x04,0x60,0xa0,0xe3,0x06,0x50,0x15,0xe0,0xfa,0xff,0xff,0x0a,
+0x0e,0xf0,0xa0,0xe1,0x68,0x31,0x9f,0xe5,0x01,0x40,0xa0,0xe3,0x00,0x40,0x83,0xe5,
+0x1c,0x31,0x9f,0xe5,0x20,0x41,0x9f,0xe5,0x4c,0x51,0x9f,0xe5,0x4c,0x61,0x9f,0xe5,
+0x00,0x00,0x54,0xe3,0x11,0x00,0x00,0x0a,0x00,0x70,0x96,0xe5,0x02,0x80,0xa0,0xe3,
+0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,0x00,0x90,0xd3,0xe5,0x00,0x90,0xc5,0xe5,
+0x00,0x70,0x96,0xe5,0x10,0x80,0xa0,0xe3,0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,
+0x00,0x70,0x96,0xe5,0x04,0x80,0xa0,0xe3,0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,
+0x00,0x70,0xd5,0xe5,0x01,0x30,0x83,0xe2,0x01,0x40,0x44,0xe2,0xeb,0xff,0xff,0xea,
+0xdb,0xff,0xff,0xeb,0xa0,0xff,0xff,0xeb,0xc0,0x30,0x9f,0xe5,0xc0,0x40,0x9f,0xe5,
+0xe8,0x50,0x9f,0xe5,0xe0,0x60,0x9f,0xe5,0x00,0x00,0x50,0xe3,0x21,0x00,0x00,0x0a,
+0x04,0x00,0x51,0xe1,0x02,0x00,0x00,0x1a,0x03,0x00,0x52,0xe1,0x1a,0x00,0x00,0x0a,
+0x02,0x00,0x00,0xea,0x01,0x70,0x81,0xe2,0x07,0x00,0x52,0xe1,0x16,0x00,0x00,0x0a,
+0x00,0x70,0x95,0xe5,0x02,0x80,0xa0,0xe3,0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,
+0x00,0x70,0xa0,0xe3,0x00,0x70,0xc6,0xe5,0x00,0x70,0x95,0xe5,0x10,0x80,0xa0,0xe3,
+0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,0x00,0x70,0x95,0xe5,0x04,0x80,0xa0,0xe3,
+0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,0x00,0x70,0xd6,0xe5,0x00,0x70,0xc1,0xe5,
+0x01,0x00,0x40,0xe2,0x04,0x00,0x51,0xe1,0x01,0x00,0x00,0x1a,0x3c,0x10,0x9f,0xe5,
+0xe0,0xff,0xff,0xea,0x01,0x10,0x81,0xe2,0xde,0xff,0xff,0xea,0x38,0x70,0x9f,0xe5,
+0x30,0x70,0x8f,0xe5,0x70,0x00,0x20,0xe1,0x2c,0x70,0x9f,0xe5,0x24,0x70,0x8f,0xe5,
+0x92,0xff,0xff,0xeb,0x71,0x00,0x20,0xe1,0x90,0xff,0xff,0xeb,0x72,0x00,0x20,0xe1,
+0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xed,0xde,0x00,0x00,
+0x00,0x20,0x00,0x15,0x64,0x32,0x00,0x13,0x58,0x32,0x00,0x13,0x64,0x30,0x00,0x13,
+0x58,0x30,0x00,0x13,0x54,0x32,0x00,0x13,0x54,0x30,0x00,0x13,0x0c,0x20,0x00,0x15,
+0x1c,0x20,0x00,0x15,0x08,0x20,0x00,0x15,
diff --git a/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_write.S 
b/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_write.S
new file mode 100644
index 0000000000..66ba05705a
--- /dev/null
+++ b/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_write.S
@@ -0,0 +1,241 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*input parameters:
+    r0 - byte count (decremented on each SPI transfer)
+    r1 - head (write) pointer
+    r2 - tail (read) pointer (incremented on byte write and reset remotely by 
code in openOCD)
+
+    clobbered registers (reused after initial input):
+    r3 - chip_select
+    r4 - command address
+    r5 - command length
+    r6 - circular FIFO start address
+    r7 - circular FIFO end address
+*/
+
+#include "../../../../src/flash/nor/lpc313x-spi/lpc313x_spi.h"
+    .text
+       .arm
+       .syntax unified
+    .global _begin
+
+
+_begin:                                      /*Store local variables */
+
+    str r3, #chip_sel
+    str r4, #command_address
+    str r5, #command_length
+    str r6, #fifo_start_address
+    str r7, #fifo_end_address
+
+    ldr r7, =SPI_CONFIG                             /* load SPI_CONFIG 
register address into r7 */
+    ldr r8, [r7]
+    mov r9, #SPI_CONFIG_SPI_ENABLE_BIT_MASK         /* load SPI ENABLE bit 
mask into r9 */
+    orr r8, r8, r9                                  /* r8 = SPI_CONFIG | 
SPI_CONFIG_SPI_ENABLE_BIT_MASK */
+    str r8, [r7]                                    /* write enable bit in SPI 
CONFIG register. */
+    bl set_chip_select_high
+    nop
+    bl set_chip_select_low
+    bl flush_spi_rx_fifo
+    b flush_spi_tx_fifo
+
+
+
+    .func _set_chip_select_low
+set_chip_select_low:
+    ldr r7, chip_sel
+    @ ldr r7, [r7]
+    cmp r7, #0                          @ if cs == 0
+    beq set_cs_0_low
+    cmp r7, #1                          @ if cs == 1
+    beq set_cs_1_low
+    cmp r7, #2                          @ if cs == 2
+    beq set_cs_2_low
+
+set_cs_0_low:
+    ldr r7, =IOCONFIG_SPI_MODE_1_SET                @ load mode 1 register 
address
+    mov r8, #IOCONFIG_SPI_CS_0_BITMASK              @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_SPI_MODE_0_CLEAR              @ load mode 0 register 
address
+    mov r8, #IOCONFIG_SPI_CS_0_BITMASK              @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_low_done
+set_cs_1_low:
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_1_SET        @ load mode 1 register 
address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_1_BITMASK      @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_0_CLEAR      @ load mode 0 register 
address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_1_BITMASK      @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_low_done
+set_cs_2_low:
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_1_SET        @ load mode 1 register 
address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_2_BITMASK      @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_0_CLEAR      @ load mode 0 register 
address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_2_BITMASK      @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_low_done
+set_cs_low_done:
+    mov pc, lr
+    .endfunc
+
+    .func _set_chip_select_high
+set_chip_select_high:
+    ldr r7, chip_sel
+    cmp r7, #0                          @ if cs == 0
+    beq set_cs_0_high
+    cmp r7, #1                          @ if cs == 1
+    beq set_cs_1_high
+    cmp r7, #2                          @ if cs == 2
+    beq set_cs_2_high
+
+set_cs_0_high:
+    ldr r7, =IOCONFIG_SPI_MODE_1_SET                @ load first mode 1 
register address
+    mov r8, #IOCONFIG_SPI_CS_0_BITMASK              @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_SPI_MODE_0_SET                @ load second mode 0 
register address
+    mov r8, #IOCONFIG_SPI_CS_0_BITMASK              @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_high_done
+set_cs_1_high:
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_1_SET        @ load first mode 1 
register address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_1_BITMASK      @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_0_SET        @ load second mode 0 
register address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_1_BITMASK      @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_high_done
+set_cs_2_high:
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_1_SET        @ load first mode 1 
register address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_2_BITMASK      @ modify mode 1 bytes to 
write
+    str r8, [r7]                                    @ write mode 1 bytes in 
register
+    ldr r7, =IOCONFIG_EBI_I2STX_0_MODE_0_SET        @ load second mode 0 
register address
+    mov r8, #IOCONFIG_EBI_I2STX_0_CS_2_BITMASK      @ modify mode 0 bytes to 
write
+    str r8, [r7]                                    @ write mode 0 bytes in 
register
+    b set_cs_high_done
+set_cs_high_done:
+    mov pc, lr
+    .endfunc
+
+    .func _flush_spi_rx_fifo
+flush_spi_rx_fifo:
+    ldr r3, =SPI_FIFO_DATA
+    ldr r4, =SPI_STATUS
+flush_loop:
+    ldr r5, [r3]        /*read spi fifo */
+    ldr r5, [r4]        /*Read spi status register */
+    mov r6, #SPI_STATUS_RX_FIFO_EMPTY_BIT_MASK
+    ands r5, r5, r6
+    beq flush_loop      /*keep reading fifo until its empty */
+    mov pc, lr
+    .endfunc
+
+flush_spi_tx_fifo:
+    ldr r3, =SPI_TX_FIFO_FLUSH
+    mov r4, #1
+    str r4, [r3]
+
+
+send_command:
+    ldr r3, command_address
+    ldr r4, command_length
+    ldr r5, =SPI_FIFO_DATA
+    ldr r6, =SPI_STATUS
+command_loop:
+    cmp r4, #0
+    beq data_transfer
+command_check_ready_for_write:                 /*wait until spi fifo register 
can be written*/
+    ldr r7, [r6]
+    mov r8, #SPI_STATUS_TX_FIFO_FULL_BIT_MASK
+    ands r7, r7, r8
+    bne command_check_ready_for_write
+command_byte_write:
+    ldrb r9, [r3]                                   /* load byte to be written 
into r9 */
+    strb r9, [r5]
+
+command_wait_for_spi:
+    ldr r7, [r6]
+    mov r8, #SPI_STATUS_BUSY_BIT_MASK
+    ands r7, r7, r8
+    bne command_wait_for_spi
+command_check_ready_for_read:               /*wait until spi fifo register can 
be read*/
+    ldr r7, [r6]
+    mov r8, #SPI_STATUS_RX_FIFO_EMPTY_BIT_MASK
+    ands r7, r7, r8
+    bne command_check_ready_for_read
+command_byte_read:                         /*dummy fifo read */
+    ldrb r7, [r5]
+
+    add  r3, r3, #1                                 /* increment address 
pointer */
+    sub  r4, r4, #1                                 /* decrement byte count */
+    b command_loop
+
+data_transfer:
+    bl flush_spi_rx_fifo
+data_transfer_continue:
+    ldr r3, fifo_start_address
+    ldr r4, fifo_end_address
+    ldr r5, =SPI_STATUS
+    ldr r6, =SPI_FIFO_DATA
+data_transfer_loop:
+    cmp r0, #0                                      /*if byte count == 0 
branch to done */
+    beq done
+check_fifo_empty:
+    cmp r2, r1                        /*compare tail with head */
+    beq fifo_empty                    /*if tail == head, fifo is empty */
+
+data_check_ready_for_write:                 /*wait until spi fifo register can 
be written*/
+    ldr r7, [r5]
+    mov r8, #SPI_STATUS_TX_FIFO_FULL_BIT_MASK
+    ands r7, r7, r8
+    bne data_check_ready_for_write
+byte_write:
+    ldr r7, [r2]
+    strb r7, [r6]
+wait_for_spi:
+    ldr r7, [r5]
+    mov r8, #SPI_STATUS_BUSY_BIT_MASK
+    ands r7, r7, r8
+    bne wait_for_spi
+data_check_ready_for_read:      /*wait until spi fifo register can be read*/
+    ldr r7, [r5]
+    mov r8, #SPI_STATUS_RX_FIFO_EMPTY_BIT_MASK
+    ands r7, r7, r8
+    bne data_check_ready_for_read
+byte_read:
+    ldrb r7, [r6]
+    sub  r0, r0, #1                      /*decrement byte count */
+
+increment_tail:
+    cmp r2, r4                        /*check tail against end  */
+    bne increment_tail_plus_one       /*if tail != fifo end, branch to 
increment_tail_plus_one */
+    ldr r2, fifo_start_address        /*else, set tail to fifo start */
+    b data_transfer_loop
+increment_tail_plus_one:
+    add r2, r2, #1                    /*else increment tail and continue 
writing fifo with spi data */
+    b data_transfer_loop                    /*branch to start of loop */
+
+
+fifo_empty:
+    bkpt #0
+
+done:
+    bl set_chip_select_high
+    bkpt #1
+
+done_error:
+    bl set_chip_select_high
+    bkpt #2
+
+.align 4
+chip_sel:
+    .word 0
+command_address:
+    .space 8, 0xff
+command_length:
+    .word 0
+fifo_start_address:
+    .word 0
+fifo_end_address:
+    .word 0
diff --git a/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_write.inc 
b/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_write.inc
new file mode 100644
index 0000000000..80930c33b0
--- /dev/null
+++ b/contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_write.inc
@@ -0,0 +1,41 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0x38,0x32,0x8f,0xe5,0x38,0x42,0x8f,0xe5,0x3c,0x52,0x8f,0xe5,0x3c,0x62,0x8f,0xe5,
+0x3c,0x72,0x8f,0xe5,0x3c,0x72,0x9f,0xe5,0x00,0x80,0x97,0xe5,0x01,0x90,0xa0,0xe3,
+0x09,0x80,0x88,0xe1,0x00,0x80,0x87,0xe5,0x20,0x00,0x00,0xeb,0x00,0x00,0xa0,0xe1,
+0x01,0x00,0x00,0xeb,0x3a,0x00,0x00,0xeb,0x41,0x00,0x00,0xea,0xfc,0x71,0x9f,0xe5,
+0x00,0x00,0x57,0xe3,0x03,0x00,0x00,0x0a,0x01,0x00,0x57,0xe3,0x08,0x00,0x00,0x0a,
+0x02,0x00,0x57,0xe3,0x0d,0x00,0x00,0x0a,0xfc,0x71,0x9f,0xe5,0x10,0x80,0xa0,0xe3,
+0x00,0x80,0x87,0xe5,0xf4,0x71,0x9f,0xe5,0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,
+0x0d,0x00,0x00,0xea,0xe8,0x71,0x9f,0xe5,0x08,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,
+0xe0,0x71,0x9f,0xe5,0x08,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,0x06,0x00,0x00,0xea,
+0xcc,0x71,0x9f,0xe5,0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,0xc4,0x71,0x9f,0xe5,
+0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,0xff,0xff,0xff,0xea,0x0e,0xf0,0xa0,0xe1,
+0x88,0x71,0x9f,0xe5,0x00,0x00,0x57,0xe3,0x03,0x00,0x00,0x0a,0x01,0x00,0x57,0xe3,
+0x08,0x00,0x00,0x0a,0x02,0x00,0x57,0xe3,0x0d,0x00,0x00,0x0a,0x88,0x71,0x9f,0xe5,
+0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,0x8c,0x71,0x9f,0xe5,0x10,0x80,0xa0,0xe3,
+0x00,0x80,0x87,0xe5,0x0d,0x00,0x00,0xea,0x74,0x71,0x9f,0xe5,0x08,0x80,0xa0,0xe3,
+0x00,0x80,0x87,0xe5,0x74,0x71,0x9f,0xe5,0x08,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,
+0x06,0x00,0x00,0xea,0x58,0x71,0x9f,0xe5,0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,
+0x58,0x71,0x9f,0xe5,0x10,0x80,0xa0,0xe3,0x00,0x80,0x87,0xe5,0xff,0xff,0xff,0xea,
+0x0e,0xf0,0xa0,0xe1,0x48,0x31,0x9f,0xe5,0x48,0x41,0x9f,0xe5,0x00,0x50,0x93,0xe5,
+0x00,0x50,0x94,0xe5,0x04,0x60,0xa0,0xe3,0x06,0x50,0x15,0xe0,0xfa,0xff,0xff,0x0a,
+0x0e,0xf0,0xa0,0xe1,0x30,0x31,0x9f,0xe5,0x01,0x40,0xa0,0xe3,0x00,0x40,0x83,0xe5,
+0xec,0x30,0x9f,0xe5,0xf0,0x40,0x9f,0xe5,0x14,0x51,0x9f,0xe5,0x14,0x61,0x9f,0xe5,
+0x00,0x00,0x54,0xe3,0x11,0x00,0x00,0x0a,0x00,0x70,0x96,0xe5,0x02,0x80,0xa0,0xe3,
+0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,0x00,0x90,0xd3,0xe5,0x00,0x90,0xc5,0xe5,
+0x00,0x70,0x96,0xe5,0x10,0x80,0xa0,0xe3,0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,
+0x00,0x70,0x96,0xe5,0x04,0x80,0xa0,0xe3,0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,
+0x00,0x70,0xd5,0xe5,0x01,0x30,0x83,0xe2,0x01,0x40,0x44,0xe2,0xeb,0xff,0xff,0xea,
+0xdb,0xff,0xff,0xeb,0x94,0x30,0x9f,0xe5,0x94,0x40,0x9f,0xe5,0xb4,0x50,0x9f,0xe5,
+0xac,0x60,0x9f,0xe5,0x00,0x00,0x50,0xe3,0x18,0x00,0x00,0x0a,0x01,0x00,0x52,0xe1,
+0x15,0x00,0x00,0x0a,0x00,0x70,0x95,0xe5,0x02,0x80,0xa0,0xe3,0x08,0x70,0x17,0xe0,
+0xfb,0xff,0xff,0x1a,0x00,0x70,0x92,0xe5,0x00,0x70,0xc6,0xe5,0x00,0x70,0x95,0xe5,
+0x10,0x80,0xa0,0xe3,0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,0x00,0x70,0x95,0xe5,
+0x04,0x80,0xa0,0xe3,0x08,0x70,0x17,0xe0,0xfb,0xff,0xff,0x1a,0x00,0x70,0xd6,0xe5,
+0x01,0x00,0x40,0xe2,0x04,0x00,0x52,0xe1,0x01,0x00,0x00,0x1a,0x2c,0x20,0x9f,0xe5,
+0xe7,0xff,0xff,0xea,0x01,0x20,0x82,0xe2,0xe5,0xff,0xff,0xea,0x70,0x00,0x20,0xe1,
+0x9e,0xff,0xff,0xeb,0x71,0x00,0x20,0xe1,0x9c,0xff,0xff,0xeb,0x72,0x00,0x20,0xe1,
+0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x15,0x64,0x32,0x00,0x13,
+0x58,0x32,0x00,0x13,0x64,0x30,0x00,0x13,0x58,0x30,0x00,0x13,0x54,0x32,0x00,0x13,
+0x54,0x30,0x00,0x13,0x0c,0x20,0x00,0x15,0x1c,0x20,0x00,0x15,0x08,0x20,0x00,0x15,
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 38c8970456..b9dfb5f183 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -6122,6 +6122,59 @@ flash bank $_FLASHNAME lpcspifi 0x14000000 0 0 0 
$_TARGETNAME
 
 @end deffn
 
+@deffn {Flash Driver} {lpc313x-spi}
+@cindex NXP LPC313x SPI Flash Interface
+@cindex lpc313x-spi
+This driver adds support for an external NOR flash device connected
+to the LPC313x's SPI interface.
+
+The config command only requires the @var{driver_option} parameter
+after the @var{target} to choose the chip select (a single value
+from 0 - 2). All other parameters are ignored, and the flash size
+and layout are configured by the driver:
+
+@example
+flash bank $_FLASHNAME lpc313x-spi 0 0 0 0 $_TARGETNAME 0
+@end example
+
+
+There are three additional utility commands:
+@deffn {Command} {lpc313x-spi device_erase} bank_id
+Issuing this command will erase the entire flash device.
+
+See below example for erasing a device on bank 0:
+@example
+lpc313x-spi device_erase 0
+@end example
+@end deffn
+
+@deffn {Command} {lpc313x-spi command_write} bank_id cmd_count cmd_byte[0] .. 
cmd_byte[cmd_count -1] data_count data_byte[0] .. data byte[data_count-1]
+Issuing this command allows writing a series of command and data bytes
+to the external memory device. Useful for testing specific commands
+from the data sheet.
+
+See below example for writing four command bytes and writing one data
+byte for a device on bank 0:
+@example
+lpc313x-spi command_write 0 4 0x0 0x5 4 3 1 0x2
+@end example
+
+@end deffn
+
+@deffn {Command} {lpc313x-spi command_read} bank_id cmd_count cmd_byte[0] .. 
cmd_byte[cmd_count -1] read_count
+Issuing this command allows reading a series of data bytes from the
+external memory device after issuing a series of command bytes.
+
+See below example for reading four data bytes after issuing one command
+byte for a device on bank 0.
+@example
+lpc313x-spi command_read 0 1 0x9f 4
+@end example
+
+@end deffn
+
+@end deffn
+
 @deffn {Flash Driver} {stmsmi}
 @cindex STMicroelectronics Serial Memory Interface
 @cindex SMI
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 534a7a804e..36652658a6 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -11,6 +11,8 @@ noinst_LTLIBRARIES += %D%/libocdflashnor.la
 NOR_DRIVERS = \
        %D%/aduc702x.c \
        %D%/aducm360.c \
+       %D%/lpc313x-spi/adesto_spi_flash_device.c \
+       %D%/lpc313x-spi/alt_spi_flash_device.c \
        %D%/ambiqmicro.c \
        %D%/at91sam4.c \
        %D%/at91sam4l.c \
@@ -39,6 +41,7 @@ NOR_DRIVERS = \
        %D%/lpc2000.c \
        %D%/lpc288x.c \
        %D%/lpc2900.c \
+       %D%/lpc313x-spi/lpc313x_spi.c \
        %D%/lpcspifi.c \
        %D%/max32xxx.c \
        %D%/mdr.c \
@@ -82,6 +85,7 @@ NOR_DRIVERS = \
        %D%/xmc4xxx.c
 
 NORHEADERS = \
+       %D%/lpc313x-spi/alt_spi_flash_device.h \
        %D%/core.h \
        %D%/cc3220sf.h \
        %D%/bluenrg-x.h \
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index a63b72c8fa..bf0a554d02 100644
--- a/src/flash/nor/driver.h
+++ b/src/flash/nor/driver.h
@@ -267,6 +267,7 @@ extern const struct flash_driver kinetis_ke_flash;
 extern const struct flash_driver lpc2000_flash;
 extern const struct flash_driver lpc288x_flash;
 extern const struct flash_driver lpc2900_flash;
+extern const struct flash_driver lpc313x_spi_flash;
 extern const struct flash_driver lpcspifi_flash;
 extern const struct flash_driver max32xxx_flash;
 extern const struct flash_driver mdr_flash;
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 3157bd3292..d4c16f00fd 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -44,6 +44,7 @@ static const struct flash_driver * const flash_drivers[] = {
        &lpc2000_flash,
        &lpc288x_flash,
        &lpc2900_flash,
+       &lpc313x_spi_flash,
        &lpcspifi_flash,
        &max32xxx_flash,
        &mdr_flash,
diff --git a/src/flash/nor/lpc313x-spi/adesto_spi_flash_device.c 
b/src/flash/nor/lpc313x-spi/adesto_spi_flash_device.c
new file mode 100644
index 0000000000..4d021ef5bc
--- /dev/null
+++ b/src/flash/nor/lpc313x-spi/adesto_spi_flash_device.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include "alt_spi_flash_device.h"
+
+
+
+int32_t adesto_build_read_page_command(struct alt_spi_flash_device * const 
asfd,
+                       struct flash_command *command, uint32_t address)
+{
+       command->command_bytes[0] = 0x03;
+       command->command_length = 4;
+       uint32_t page_address = address / asfd->page_size_bytes;
+       uint32_t byte_address = address % asfd->page_size_bytes;
+
+       switch (asfd->page_size_bytes) {
+               case 528:
+                       command->command_bytes[1] = page_address >> 6;
+                       command->command_bytes[2] = page_address << 2 | 
((byte_address >> 8) & 0x3);
+                       command->command_bytes[3] = byte_address & 0xFF;
+                       break;
+               default:
+                       command->command_bytes[1] = address >> 16;
+                       command->command_bytes[2] = address >> 8;
+                       command->command_bytes[3] = address & 0xFF;
+       }
+       return 0;
+};
+
+int32_t adesto_build_write_page_cmd(struct alt_spi_flash_device * const asfd,
+                       struct flash_command *command, uint32_t address)
+{
+       command->command_bytes[0] = 0x82;
+       command->command_length = 4;
+       uint32_t page_address = address / asfd->page_size_bytes;
+       uint32_t byte_address = address % asfd->page_size_bytes;
+
+       switch (asfd->page_size_bytes) {
+               case 528:
+                       command->command_bytes[1] = page_address >> 6;
+                       command->command_bytes[2] = (page_address << 2) | 
((byte_address >> 8) & 0x3);
+                       command->command_bytes[3] = byte_address & 0xFF;
+                       break;
+               default:
+                       command->command_bytes[1] = address >> 16;
+                       command->command_bytes[2] = address >> 8;
+                       command->command_bytes[3] = address & 0xFF;
+       }
+       return 0;
+
+};
+
+int32_t adesto_16megabit_build_erase_page_cmd(struct alt_spi_flash_device * 
const asfd,
+                       struct flash_command *command, uint32_t address)
+{
+       command->command_bytes[0] = 0x81;
+       command->command_length = 4;
+
+       switch (asfd->page_size_bytes) {
+               case 512:
+                       command->command_bytes[1] = (address & 0xf80) >> 7;
+                       command->command_bytes[2] = (address & 0x7f) << 1;
+                       command->command_bytes[3] = 0x00;
+                       return ERROR_OK;
+
+               case 528:
+                       command->command_bytes[1] = (address & 0xfc0) >> 6;
+                       command->command_bytes[2] = (address & 0x3f) << 2;
+                       command->command_bytes[3] = 0x00;
+                       return ERROR_OK;
+               default:
+                       return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+};
+
+int32_t adesto_32megabit_build_erase_page_cmd(struct alt_spi_flash_device * 
const asfd,
+                       struct flash_command *command, uint32_t address)
+{
+       command->command_bytes[0] = 0x81;
+       command->command_length = 4;
+
+       switch (asfd->page_size_bytes) {
+               case 512:
+                       command->command_bytes[1] = (address & 0x1f8) >> 3;
+                       command->command_bytes[2] = (address & 0x7) << 5;
+                       command->command_bytes[3] = 0x00;
+                       return ERROR_OK;
+
+               case 528:
+                       command->command_bytes[1] = (address & 0x1fc0) >> 6;
+                       command->command_bytes[2] = (address & 0x3f) << 2;
+                       command->command_bytes[3] = 0x00;
+                       return ERROR_OK;
+               default:
+                       return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+};
+
+int32_t adesto_16megabit_build_erase_sector_cmd(struct alt_spi_flash_device * 
const asfd,
+                       struct flash_command *command, uint32_t address)
+{
+       command->command_bytes[0] = 0x7C;
+       command->command_length = 4;
+
+       switch (asfd->page_size_bytes) {
+               case 512:
+                       switch (address) {
+                               case 0: /*sector 0a*/
+                               case 1: /*sector 0b*/
+                                       command->command_bytes[1] = (address & 
0x1f0) >> 4;
+                                       command->command_bytes[2] = (address & 
0xf) << 4;
+                                       command->command_bytes[3] = 0x00;
+                                       return ERROR_OK;
+                               case 2 ... 16: /*sectors 1 - 15*/
+                                       command->command_bytes[1] = ((address - 
1) & 0xf) << 1;
+                                       command->command_bytes[2] = 0x00;
+                                       command->command_bytes[3] = 0x00;
+                                       return ERROR_OK;
+                               default:
+                                       return ERROR_FLASH_OPER_UNSUPPORTED;
+                       }
+               case 528:
+                       switch (address) {
+                               case 0: /*sector 0a*/
+                               case 1: /*sector 0b*/
+                                       command->command_bytes[1] = (address & 
0x1f8) >> 3;
+                                       command->command_bytes[2] = (address & 
7) << 5;
+                                       command->command_bytes[3] = 0x00;
+                                       return ERROR_OK;
+                               case 2 ... 16: /*sectors 1 - 15*/
+                                       command->command_bytes[1] = ((address - 
1) & 0xf) << 2;
+                                       command->command_bytes[2] = 0x00;
+                                       command->command_bytes[3] = 0x00;
+                                       return ERROR_OK;
+                               default:
+                                       return ERROR_FLASH_OPER_UNSUPPORTED;
+                       }
+               default:
+                       return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+};
+
+int32_t adesto_32megabit_build_erase_sector_cmd(struct alt_spi_flash_device * 
const asfd,
+                       struct flash_command *command, uint32_t address)
+{
+       command->command_bytes[0] = 0x7C;
+       command->command_length = 4;
+
+       switch (asfd->page_size_bytes) {
+               case 512:
+                       switch (address) {
+                               case 0: /*sector 0a*/
+                               case 1: /*sector 0b*/
+                                       command->command_bytes[1] = (address & 
0x3f0) >> 4;
+                                       command->command_bytes[2] = (address & 
0xf) << 4;
+                                       command->command_bytes[3] = 0x00;
+                                       return ERROR_OK;
+                               case 2 ... 64: /*sectors 1 - 63*/
+                                       command->command_bytes[1] = (address - 
1) & 0x3f;
+                                       command->command_bytes[2] = 0x00;
+                                       command->command_bytes[3] = 0x00;
+                                       return ERROR_OK;
+                               default:
+                                       return ERROR_FLASH_OPER_UNSUPPORTED;
+                       }
+               case 528:
+                       switch (address) {
+                               case 0: /*sector 0a*/
+                               case 1: /*sector 0b*/
+                                       command->command_bytes[1] = (address & 
0x3f8) >> 3;
+                                       command->command_bytes[2] = (address & 
7) << 5;
+                                       command->command_bytes[3] = 0x00;
+                                       return ERROR_OK;
+                               case 2 ... 64: /*sectors 1 - 63*/
+                                       command->command_bytes[1] = ((address - 
1) & 0x3f) << 1;
+                                       command->command_bytes[2] = 0x00;
+                                       command->command_bytes[3] = 0x00;
+                                       return ERROR_OK;
+                               default:
+                                       return ERROR_FLASH_OPER_UNSUPPORTED;
+                       }
+               default:
+                       return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+};
+
+int32_t adesto_build_erase_device_cmd(struct flash_command *command)
+{
+       command->command_bytes[0] = 0xC7;
+       command->command_bytes[1] = 0x94;
+       command->command_bytes[2] = 0x80;
+       command->command_bytes[3] = 0x9A;
+       command->command_length = 4;
+       return 0;
+};
+
+int32_t adesto_build_protect_cmd(struct flash_command *command)
+{
+       command->command_bytes[0] = 0x3D;
+       command->command_bytes[1] = 0x2A;
+       command->command_bytes[2] = 0x7F;
+       command->command_bytes[3] = 0xA9;
+       command->command_length = 4;
+       return 0;
+};
+
+int32_t adesto_build_status_cmd(struct flash_command *command)
+{
+       command->command_bytes[0] = 0xD7;
+       command->command_length = 1;
+       return 0;
+};
+
+int32_t adesto_16megabit_build_memory_map(struct alt_spi_flash_device * const 
asfd,
+                       struct flash_bank *bank)
+{
+       struct flash_sector *sectors = NULL;
+
+       bank->size = get_flash_device_size_bytes(asfd);
+       bank->num_sectors = get_flash_device_sector_count(asfd);
+
+       sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+       if (!sectors) {
+               LOG_ERROR("not enough memory");
+               return ERROR_FAIL;
+       }
+
+       for (unsigned int sector_index = 0; sector_index < bank->num_sectors; 
sector_index++) {
+               if (sector_index == 0) { /*Sector 0a*/
+                       sectors[0].size = 8 * asfd->page_size_bytes;
+                       sectors[0].offset = 0;
+               } else if (sector_index == 1) {  /*Sector 0b*/
+                       sectors[1].size = 248 * asfd->page_size_bytes;
+                       sectors[1].offset = sectors[0].size;
+               } else {
+                       sectors[sector_index].size = 
get_flash_device_sector_size_bytes(asfd);
+                       sectors[sector_index].offset = sector_index * 
sectors[sector_index].size;
+               }
+               sectors[sector_index].is_erased = -1;
+               sectors[sector_index].is_protected = 0;
+       }
+       bank->sectors = sectors;
+       return 0;
+       }
+
+int32_t adesto_32megabit_build_memory_map(struct alt_spi_flash_device * const 
asfd,
+                       struct flash_bank *bank)
+{
+       struct flash_sector *sectors = NULL;
+
+       bank->size = get_flash_device_size_bytes(asfd);
+       bank->num_sectors = get_flash_device_sector_count(asfd);
+
+       sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+       if (!sectors) {
+               LOG_ERROR("not enough memory");
+               return ERROR_FAIL;
+       }
+
+       for (unsigned int sector_index = 0; sector_index < bank->num_sectors; 
sector_index++) {
+               if (sector_index == 0) { /*Sector 0a*/
+                       sectors[0].size = 8 * asfd->page_size_bytes;
+                       sectors[0].offset = 0;
+               } else if (sector_index == 1) {  /*Sector 0b*/
+                       sectors[0].size = 120 * asfd->page_size_bytes;
+                       sectors[0].offset = sectors[0].size;
+               } else {
+                       sectors[sector_index].size = 
get_flash_device_sector_size_bytes(asfd);
+                       sectors[sector_index].offset = sector_index * 
sectors[sector_index].size;
+               }
+               sectors[sector_index].is_erased = -1;
+               sectors[sector_index].is_protected = 0;
+       }
+       bank->sectors = sectors;
+       return 0;
+}
+
+struct alt_spi_flash_device adesto16megabit_spi_flash_device = {
+       .build_read_page_cmd = adesto_build_read_page_command,
+       .build_write_page_cmd = adesto_build_write_page_cmd,
+       .build_erase_page_cmd = adesto_16megabit_build_erase_page_cmd,
+       .build_erase_sector_cmd = adesto_16megabit_build_erase_sector_cmd,
+       .build_erase_device_cmd = adesto_build_erase_device_cmd,
+       .build_protect_cmd = adesto_build_protect_cmd,
+       .build_status_cmd = adesto_build_status_cmd,
+       .build_memory_map = adesto_16megabit_build_memory_map,
+       .device_name = "AT45DB16 16Mb",
+       .device_id = 0x0000261f,
+       .page_size_bytes = 0, /*device must be queried for page size of 512 or 
528*/
+       .page_count = 4096,
+       .block_count = 512,
+       .block_page_count = 8,
+       .sector_count = 17, /*sector 0 is split into 2 sectors (a and b)*/
+       .sector_page_count = 256
+
+};
+
+struct alt_spi_flash_device adesto32megabit_spi_flash_device = {
+       .build_read_page_cmd = adesto_build_read_page_command,
+       .build_write_page_cmd = adesto_build_write_page_cmd,
+       .build_erase_page_cmd = adesto_32megabit_build_erase_page_cmd,
+       .build_erase_sector_cmd = adesto_32megabit_build_erase_sector_cmd,
+       .build_erase_device_cmd = adesto_build_erase_device_cmd,
+       .build_protect_cmd = adesto_build_protect_cmd,
+       .build_status_cmd = adesto_build_status_cmd,
+       .build_memory_map = adesto_32megabit_build_memory_map,
+       .device_name = "AT45DB32 32Mb",
+       .device_id = 0x0000271f,
+       .page_size_bytes = 0, /*device must be queried for page size of 512 or 
528*/
+       .page_count = 8192,
+       .block_count = 1024,
+       .block_page_count = 8,
+       .sector_count = 65, /*sector 0 is split into 2 sectors (a and b)*/
+       .sector_page_count = 128
+
+};
+
diff --git a/src/flash/nor/lpc313x-spi/alt_spi_flash_device.c 
b/src/flash/nor/lpc313x-spi/alt_spi_flash_device.c
new file mode 100644
index 0000000000..8fc03813ae
--- /dev/null
+++ b/src/flash/nor/lpc313x-spi/alt_spi_flash_device.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*Alternate SPI flash device structurs. Use when device commands are longer 
than a single byte (see spi.c)*/
+
+
+#include "alt_spi_flash_device.h"
+#include "stddef.h"
+
+
+static const struct alt_spi_flash_device * const alt_spi_flash_devices[] = {
+       &adesto16megabit_spi_flash_device,
+       &adesto32megabit_spi_flash_device
+};
+
+const struct alt_spi_flash_device *find_flash_device_by_id(const uint32_t id)
+{
+       for (unsigned int i = 0; i < (sizeof(*alt_spi_flash_devices) / 
(sizeof(struct alt_spi_flash_device *))); i++) {
+               if ((id & 0xFFFF) == alt_spi_flash_devices[i]->device_id) 
/*ignore MLC code and version*/
+                       return alt_spi_flash_devices[i];
+       }
+       return NULL;
+}
+
+uint32_t get_flash_device_size_bytes(const struct alt_spi_flash_device *device)
+{
+       return device->page_size_bytes * device->page_count;
+}
+
+uint32_t get_flash_device_sector_count(const struct alt_spi_flash_device 
*device)
+{
+       return device->sector_count;
+};
+
+uint32_t get_flash_device_sector_size_bytes(const struct alt_spi_flash_device 
*device)
+{
+       return device->sector_page_count * device->page_size_bytes;
+}
diff --git a/src/flash/nor/lpc313x-spi/alt_spi_flash_device.h 
b/src/flash/nor/lpc313x-spi/alt_spi_flash_device.h
new file mode 100644
index 0000000000..338b2c8dbd
--- /dev/null
+++ b/src/flash/nor/lpc313x-spi/alt_spi_flash_device.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/*Alternate SPI flash device structure when commands are longer than a single 
byte (see spi.c)*/
+
+
+#ifndef OPENOCD_FLASH_NOR_ALT_SPI_FLASH_DEVICE_H
+#define OPENOCD_FLASH_NOR_ALT_SPI_FLASH_DEVICE_H
+
+#include <stdint.h>
+#include "flash/nor/imp.h"
+
+#define DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES 8
+#define ADESTO_FLASH_STATUS_RDY_BUSY_MASK              0x80
+#define ADESTO_FLASH_PAGE_SIZE_MASK                            0x01
+#define SPIFLASH_RESUME_FROM_DEEP_POWER_DOWN   0xAB
+
+struct flash_command {
+       uint8_t *command_bytes; // sequence of bytes for command
+       uint8_t command_length; // count of command bytes
+};
+
+struct flash_status {
+       uint8_t status_1;
+       uint8_t status_2;
+};
+
+struct alt_spi_flash_device {
+       int32_t (*build_read_page_cmd)(struct alt_spi_flash_device * const asfd,
+                               struct flash_command *command, uint32_t 
address);
+       int32_t (*build_write_page_cmd)(struct alt_spi_flash_device * const 
asfd,
+                               struct flash_command *command, uint32_t 
address);
+       int32_t (*build_erase_page_cmd)(struct alt_spi_flash_device * const 
asfd,
+                               struct flash_command *command, uint32_t 
address);
+       int32_t (*build_erase_sector_cmd)(struct alt_spi_flash_device * const 
asfd,
+                               struct flash_command *command, uint32_t 
sector_address);
+       int32_t (*build_erase_device_cmd)(struct flash_command *command);
+       int32_t (*build_protect_cmd)(struct flash_command *command);
+       int32_t (*build_status_cmd)(struct flash_command *command);
+       int32_t (*build_memory_map)(struct alt_spi_flash_device * const asfd, 
struct flash_bank *bank);
+       const char *device_name;
+       uint32_t device_id;
+       uint32_t page_size_bytes;
+       uint32_t page_count;
+       uint32_t block_count;
+       uint32_t block_page_count;
+       uint32_t sector_count;
+       uint32_t sector_page_count;
+};
+
+
+const struct alt_spi_flash_device *find_flash_device_by_id(const uint32_t id);
+uint32_t get_flash_device_size_bytes(const struct alt_spi_flash_device 
*device);
+uint32_t get_flash_device_sector_count(const struct alt_spi_flash_device 
*device);
+uint32_t get_flash_device_sector_size_bytes(const struct alt_spi_flash_device 
*device);
+
+extern struct alt_spi_flash_device adesto16megabit_spi_flash_device;
+extern struct alt_spi_flash_device adesto32megabit_spi_flash_device;
+
+
+#endif
diff --git a/src/flash/nor/lpc313x-spi/lpc313x_spi.c 
b/src/flash/nor/lpc313x-spi/lpc313x_spi.c
new file mode 100644
index 0000000000..06bda22773
--- /dev/null
+++ b/src/flash/nor/lpc313x-spi/lpc313x_spi.c
@@ -0,0 +1,1499 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "../imp.h"
+#include <helper/binarybuffer.h>
+#include <helper/bits.h>
+#include <helper/time_support.h>
+#include <target/algorithm.h>
+#include <target/arm926ejs.h>
+#include <target/image.h>
+#include "flash/nor/spi.h"
+#include "lpc313x_spi.h"
+#include "alt_spi_flash_device.h"
+
+#define MAX_FIFO_SIZE 528
+
+struct lpc313x_private_driver {
+       bool probed;
+       char devname[32];
+       bool is_legacy_adesto_device;
+       struct alt_spi_flash_device alt_nor_flash_device; // legacy AT45DB161D 
device not supported in spi.c
+       struct flash_device nor_flash_device;
+       uint32_t chip_select; /* a value from 0-2 used to pick chip select of 
lpc313x SPI peripheral*/
+};
+
+FLASH_BANK_COMMAND_HANDLER(lpc313x_spi_flash_bank_command)
+{
+       struct lpc313x_private_driver *lpc313x_flash_bank;
+       uint32_t chip_select;
+
+       LOG_DEBUG("%s", __func__);
+
+       if (CMD_ARGC < 7) {
+               LOG_ERROR("Argument for chip select is missing");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], chip_select);
+
+       if (chip_select > 2) {
+               LOG_ERROR("Argument for chip select must be 0, 1, or 2");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       lpc313x_flash_bank = malloc(sizeof(struct lpc313x_private_driver));
+       if (!lpc313x_flash_bank) {
+               LOG_ERROR("not enough memory");
+               return ERROR_FAIL;
+       }
+
+       bank->driver_priv = lpc313x_flash_bank;
+       lpc313x_flash_bank->probed = false;
+       lpc313x_flash_bank->chip_select = chip_select;
+
+       LOG_DEBUG("Using SPI chip select %d", chip_select);
+
+       return ERROR_OK;
+}
+
+struct LPC313X_SPI_CONFIG_REG spi_config_from_u32(uint32_t word)
+{
+       struct LPC313X_SPI_CONFIG_REG config_reg = {0};
+       config_reg.inter_slave_delay = (word & 
SPI_CONFIG_INTER_SLAVE_DELAY_BIT_MASK) >> 16;
+       config_reg.update_enable = (word & SPI_CONFIG_UPDATE_ENABLE_BIT_MASK) 
>> 7;
+       config_reg.software_reset = (word & SPI_CONFIG_SOFTWARE_RESET_BIT_MASK) 
>> 6;
+       config_reg.slave_disable = (word & SPI_CONFIG_SLAVE_DISABLE_BIT_MASK) 
>> 4;
+       config_reg.transmit_mode = (word & SPI_CONFIG_TX_MODE_BIT_MASK) >> 3;
+       config_reg.loopback_mode = (word & SPI_CONFIG_LOOPBACK_MODE_BIT_MASK) 
>> 2;
+       config_reg.mass_slave_mode = (word & SPI_CONFIG_MAST_SLV_MODE_BIT_MASK) 
>> 1;
+       config_reg.spi_enable = (word & SPI_CONFIG_SPI_ENABLE_BIT_MASK);
+
+       return config_reg;
+}
+
+uint32_t u32_from_spi_config(struct LPC313X_SPI_CONFIG_REG config_reg)
+{
+       return (config_reg.inter_slave_delay << 16
+                       | (config_reg.update_enable & 0x1) << 7
+                       | (config_reg.software_reset & 0x1) << 6
+                       | (config_reg.slave_disable & 0x1) << 4
+                       | (config_reg.transmit_mode & 0x1) << 3
+                       | (config_reg.loopback_mode & 0x1) << 2
+                       | (config_reg.mass_slave_mode & 0x1) << 1
+                       | (config_reg.spi_enable & 0x1));
+}
+
+uint32_t u32_from_spi_slave_settings1(struct LPC313X_SPI_SLAVE_SETTINGS1_REG 
slave_settings1_reg)
+{
+       return (slave_settings1_reg.inter_transfer_delay << 24
+                       | slave_settings1_reg.number_words << 16
+                       | slave_settings1_reg.clock_divisor1 << 8
+                       | slave_settings1_reg.clock_divisor2);
+}
+
+uint32_t u32_from_spi_slave_settings2(struct LPC313X_SPI_SLAVE_SETTINGS2_REG 
slave_settings2_reg)
+{
+       return ((slave_settings2_reg.pre_post_chip_select_delay & 0x1F) << 9
+                       | (slave_settings2_reg.chip_select_value & 0x1) << 8
+                       | (slave_settings2_reg.transfer_format & 0x1) << 7
+                       | (slave_settings2_reg.serial_clock_polarity & 1) << 6
+                       | (slave_settings2_reg.serial_clock_phase & 0x1) << 5
+                       | (slave_settings2_reg.word_size & 0x1F));
+}
+
+uint32_t u32_from_spi_slave_enable(struct LPC313X_SPI_SLAVE_ENABLE_REG 
slave_en_reg)
+{
+       return ((slave_en_reg.slave_enable_3 & 0x3) << 4
+                       | (slave_en_reg.slave_enable_2 & 0x3) << 2
+                       | (slave_en_reg.slave_enable_1 & 0x3));
+}
+
+static int set_cs_low(struct target *target, uint32_t chip_select)
+{
+       switch (chip_select) {
+       case 0:
+               /*Set Mode 1 bit*/
+               if (target_write_u32(target, IOCONFIG_SPI_MODE_1_SET, 
IOCONFIG_SPI_CS_0_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               /*Clear MODE 0 bit*/
+               if (target_write_u32(target, IOCONFIG_SPI_MODE_0_CLEAR, 
IOCONFIG_SPI_CS_0_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               break;
+       case 1:
+               /*Set Mode 1 bit*/
+               if (target_write_u32(target, IOCONFIG_EBI_I2STX_0_MODE_1_SET, 
IOCONFIG_EBI_I2STX_0_CS_1_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               /*Clear MODE 0 bit*/
+               if (target_write_u32(target, IOCONFIG_EBI_I2STX_0_MODE_0_CLEAR, 
IOCONFIG_EBI_I2STX_0_CS_1_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               break;
+       case 2:
+               /*Set Mode 1 bit*/
+               if (target_write_u32(target, IOCONFIG_EBI_I2STX_0_MODE_1_SET, 
IOCONFIG_EBI_I2STX_0_CS_2_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               /*Clear MODE 0 bit*/
+               if (target_write_u32(target, IOCONFIG_EBI_I2STX_0_MODE_0_CLEAR, 
IOCONFIG_EBI_I2STX_0_CS_2_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               break;
+       default:
+               return ERROR_COMMAND_NOTFOUND;
+       }
+
+       return ERROR_OK;
+}
+
+static int set_cs_high(struct target *target, uint32_t chip_select)
+{
+       switch (chip_select) {
+       case 0:
+               /*Set Mode 1 bit*/
+               if (target_write_u32(target, IOCONFIG_SPI_MODE_1_SET, 
IOCONFIG_SPI_CS_0_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               /*Set MODE 0 bit*/
+               if (target_write_u32(target, IOCONFIG_SPI_MODE_0_SET, 
IOCONFIG_SPI_CS_0_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               break;
+       case 1:
+               /*Set Mode 1 bit*/
+               if (target_write_u32(target, IOCONFIG_EBI_I2STX_0_MODE_1_SET, 
IOCONFIG_EBI_I2STX_0_CS_1_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               /*Set MODE 0 bit*/
+               if (target_write_u32(target, IOCONFIG_EBI_I2STX_0_MODE_0_SET, 
IOCONFIG_EBI_I2STX_0_CS_1_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               break;
+       case 2:
+               /*Set Mode 1 bit*/
+               if (target_write_u32(target, IOCONFIG_EBI_I2STX_0_MODE_1_SET, 
IOCONFIG_EBI_I2STX_0_CS_2_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               /*Set MODE 0 bit*/
+               if (target_write_u32(target, IOCONFIG_EBI_I2STX_0_MODE_0_SET, 
IOCONFIG_EBI_I2STX_0_CS_2_BITMASK) != ERROR_OK)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               break;
+       default:
+               return ERROR_COMMAND_NOTFOUND;
+       }
+
+       return ERROR_OK;
+}
+
+
+static int lpc313x_spi_command_read(struct flash_bank *bank, uint8_t *buffer,
+                                                                       struct 
flash_command *spi_flash_command, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct lpc313x_private_driver *lpc313x_driver = bank->driver_priv;
+
+       struct working_area *target_ram;
+       struct reg_param reg_params[8];
+       struct arm_algorithm armv5_info;
+       int return_value;
+       uint32_t available_ram_bytes = 0;
+       uint32_t code_size_bytes = 0;
+       uint32_t fifo_size_bytes = 0;
+       uint32_t total_ram_bytes_needed = 0;
+
+       static const uint8_t lpc313x_spi_flash_read_code[] = {
+#include 
"../../../../contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_read.inc"
+       };
+
+       code_size_bytes = sizeof(lpc313x_spi_flash_read_code);
+       fifo_size_bytes = (count < MAX_FIFO_SIZE) ? count : MAX_FIFO_SIZE;
+       total_ram_bytes_needed = code_size_bytes + 
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES + fifo_size_bytes;
+
+       available_ram_bytes = target_get_working_area_avail(target);
+       if (available_ram_bytes < total_ram_bytes_needed) {
+               LOG_ERROR("not enough processor RAM available for page writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       int32_t alloc_return_value = target_alloc_working_area_try(target, 
total_ram_bytes_needed, &target_ram);
+       if (alloc_return_value != ERROR_OK) {
+               LOG_ERROR("allocating working area failed with error code: %d", 
alloc_return_value);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       };
+
+       uint32_t spi_command_bytes_address = target_ram->address + 
code_size_bytes;
+       uint32_t fifo_start_address = spi_command_bytes_address + 
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES;
+       uint32_t fifo_end_address = fifo_start_address + fifo_size_bytes;
+
+       /* write flashloader to ram of target */
+       return_value = target_write_buffer(target, target_ram->address,
+                                                                          
code_size_bytes, lpc313x_spi_flash_read_code);
+       if (return_value != ERROR_OK)
+               return ERROR_TARGET_FAILURE;
+
+       /* write spi read command to ram of target */
+       return_value = target_write_buffer(target, spi_command_bytes_address,
+                                                                          
spi_flash_command->command_length, spi_flash_command->command_bytes);
+       if (return_value != ERROR_OK)
+               return ERROR_TARGET_FAILURE;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       armv5_info.common_magic = ARM_COMMON_MAGIC;
+       armv5_info.core_mode = ARM_MODE_SYS;
+       armv5_info.core_state = ARM_STATE_ARM;
+
+       /*initialize register values*/
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* byte transfer 
count */
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* head (write) 
pointer */
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* tail (read) 
pointer */
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* chip select */
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* command address 
*/
+       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT); /* command length 
*/
+       init_reg_param(&reg_params[6], "r6", 32, PARAM_OUT); /* FIFO start 
address */
+       init_reg_param(&reg_params[7], "r7", 32, PARAM_OUT); /* FIFO end 
address */
+
+       buf_set_u32(reg_params[1].value, 0, 32, fifo_start_address);
+       buf_set_u32(reg_params[3].value, 0, 32, lpc313x_driver->chip_select);
+       buf_set_u32(reg_params[4].value, 0, 32, spi_command_bytes_address);
+       buf_set_u32(reg_params[5].value, 0, 32, 
spi_flash_command->command_length);
+       buf_set_u32(reg_params[6].value, 0, 32, fifo_start_address);
+       buf_set_u32(reg_params[7].value, 0, 32, fifo_end_address);
+
+       uint32_t read_bytes_remaining = count;
+       uint32_t read_size_bytes = 0;
+
+       do {
+               if (read_bytes_remaining <= MAX_FIFO_SIZE) {
+                       read_size_bytes = read_bytes_remaining;
+                       buf_set_u32(reg_params[0].value, 0, 32, 
read_size_bytes);
+               } else {
+                       read_size_bytes = MAX_FIFO_SIZE;
+                       /*slight oversize will prevent the cs from being 
released in flashloader*/
+                       buf_set_u32(reg_params[0].value, 0, 32, read_size_bytes 
+ 1);
+               }
+
+               /*reset tail pointer to head (FIFO empty)*/
+               buf_set_u32(reg_params[2].value, 0, 32, fifo_start_address);
+
+               return_value = target_run_algorithm(target,
+                       0, NULL,
+                       ARRAY_SIZE(reg_params), reg_params,
+                       target_ram->address,
+                       0,
+                       10000,
+                       &armv5_info);
+
+               if (return_value != ERROR_OK) {
+                       return_value = ERROR_TARGET_FAILURE;
+                       goto end_command_read;
+               }
+
+               if (target_read_buffer(target, fifo_start_address, 
read_size_bytes, buffer) != ERROR_OK) {
+                       return_value = ERROR_TARGET_FAILURE;
+                       goto end_command_read;
+               }
+
+               buffer += read_size_bytes;
+               read_bytes_remaining -= read_size_bytes;
+
+       } while (read_bytes_remaining != 0);
+
+       if (return_value != ERROR_OK)
+               return ERROR_TARGET_FAILURE;
+
+end_command_read:
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+       destroy_reg_param(&reg_params[5]);
+       destroy_reg_param(&reg_params[6]);
+       destroy_reg_param(&reg_params[7]);
+       target_free_working_area(target, target_ram);
+
+       return return_value;
+}
+
+static int lpc313x_spi_get_status(struct flash_bank *bank, struct flash_status 
*fstatus)
+{
+       struct lpc313x_private_driver *lpc313x_driver = bank->driver_priv;
+       struct flash_command spi_flash_command;
+       int return_value;
+
+       /*Build command*/
+       spi_flash_command.command_bytes = 
malloc(DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES);
+       if (!spi_flash_command.command_bytes) {
+               return_value = ERROR_FAIL;
+               goto end_status;
+       }
+
+       spi_flash_command.command_length = 0;
+       if (lpc313x_driver->is_legacy_adesto_device) {
+               
lpc313x_driver->alt_nor_flash_device.build_status_cmd(&spi_flash_command);
+       } else {
+               *spi_flash_command.command_bytes = 0xd7;
+               spi_flash_command.command_length = 1;
+       }
+
+       uint8_t buff[2];
+
+       if (lpc313x_spi_command_read(bank, &buff[0], &spi_flash_command, 2) != 
ERROR_OK) {
+               return_value = ERROR_FLASH_OPERATION_FAILED;
+               goto end_status;
+       }
+
+       return_value = ERROR_OK;
+       fstatus->status_1 = buff[0];
+       fstatus->status_2 = buff[1];
+end_status:
+       if (spi_flash_command.command_bytes)
+               free(spi_flash_command.command_bytes);
+
+       return return_value;
+}
+
+static int device_is_busy(struct flash_bank *bank, bool *is_busy)
+{
+       struct flash_status fl_status = {0};
+       int return_value = lpc313x_spi_get_status(bank, &fl_status);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       *is_busy = (fl_status.status_1 & ADESTO_FLASH_STATUS_RDY_BUSY_MASK) == 
0;
+       return ERROR_OK;
+};
+
+static int get_page_size(struct flash_bank *bank, uint16_t *page_size)
+{
+       struct flash_status fl_status = {0};
+       int return_value = lpc313x_spi_get_status(bank, &fl_status);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       if ((fl_status.status_1 & ADESTO_FLASH_PAGE_SIZE_MASK) == 
ADESTO_FLASH_PAGE_SIZE_MASK)
+               *page_size = 512;
+       else
+               *page_size = 528;
+
+       return ERROR_OK;
+};
+
+
+
+static int lpc313x_spi_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct lpc313x_private_driver *lpc313x_driver = bank->driver_priv;
+       uint32_t temp_register = 0;
+       const struct flash_device *flash_devicep = NULL;
+       const struct alt_spi_flash_device *alt_flash_devicep = NULL;
+       int return_value = ERROR_FAIL;
+
+       /* invalidate all flash device info */
+       if (lpc313x_driver->probed && bank->sectors)
+               free(bank->sectors);
+       bank->size = 0;
+       bank->num_sectors = 0;
+       bank->sectors = NULL;
+       lpc313x_driver->probed = false;
+       memset(&lpc313x_driver->nor_flash_device, 0, 
sizeof(lpc313x_driver->nor_flash_device));
+       lpc313x_driver->nor_flash_device.name = "unknown";
+
+       /* Set GPIO PINS to SPI peripheral (except chip select)*/
+
+       /*Write SPI MODE 0 set register to connect all SPI pins to SPI module*/
+       return_value = target_write_u32(target, IOCONFIG_SPI_MODE_0_SET, 0xF);
+       if (return_value != ERROR_OK)
+               return return_value;
+       /*Write SPI MODE 1 CLEAR register to connect all SPI pins to SPI 
module*/
+       return_value = target_write_u32(target, IOCONFIG_SPI_MODE_1_CLEAR, 0xF);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+
+
+       /* reset SPI module */
+       return_value = target_read_u32(target, SPI_CONFIG, &temp_register);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       struct LPC313X_SPI_CONFIG_REG spi_config_register = 
spi_config_from_u32(temp_register);
+       spi_config_register.software_reset = 0x1;
+       spi_config_register.spi_enable = 0x0;
+       return_value = target_write_u32(target, SPI_CONFIG, 
u32_from_spi_config(spi_config_register));
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       /* Write slave settings registers */
+       /*serial clock = spi_base clock/(clock_divisor2 *(1 + clock_divisor1))*/
+       /*serial clock = 12MHz/(2 *(1 + 0)) = 6 MHz*/
+
+       uint32_t slave_settings1_register_address = SPI_SLAVE0_SETTINGS1;
+       uint32_t slave_settings2_register_address = SPI_SLAVE0_SETTINGS2;
+
+       switch (lpc313x_driver->chip_select) {
+       case 1:
+               slave_settings1_register_address = SPI_SLAVE1_SETTINGS1;
+               slave_settings2_register_address = SPI_SLAVE1_SETTINGS2;
+               break;
+       case 2:
+               slave_settings1_register_address = SPI_SLAVE2_SETTINGS1;
+               slave_settings2_register_address = SPI_SLAVE2_SETTINGS2;
+               break;
+       case 0:
+       default:
+               slave_settings1_register_address = SPI_SLAVE0_SETTINGS1;
+               slave_settings2_register_address = SPI_SLAVE0_SETTINGS2;
+       }
+
+       struct LPC313X_SPI_SLAVE_SETTINGS1_REG slave_settings1 = 
{.inter_transfer_delay = 1,
+                                                                               
                                           .number_words = 0,
+                                                                               
                                           .clock_divisor1 = 0,
+                                                                               
                                           .clock_divisor2 = 2};
+       return_value = target_write_u32(target,
+                                       slave_settings1_register_address,
+                                       
u32_from_spi_slave_settings1(slave_settings1));
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       struct LPC313X_SPI_SLAVE_SETTINGS2_REG slave_settings2 = 
{.pre_post_chip_select_delay = 0,
+                                                                               
                                           .chip_select_value = 0,
+                                                                               
                                           .transfer_format = 0,
+                                                                               
                                           .serial_clock_polarity = 0,
+                                                                               
                                           .serial_clock_phase = 0,
+                                                                               
                                           .word_size = 8 - 1};
+
+       return_value = target_write_u32(target,
+                                       slave_settings2_register_address,
+                                       
u32_from_spi_slave_settings2(slave_settings2));
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       struct LPC313X_SPI_SLAVE_ENABLE_REG slave_enable_register = 
{.slave_enable_1 = 0x01,
+                                                                               
                                                 .slave_enable_2 = 0x00,
+                                                                               
                                                 .slave_enable_3 = 0x00};
+       return_value = target_write_u32(target, SPI_SLAVE_ENABLE, 
u32_from_spi_slave_enable(slave_enable_register));
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       /*Enable SPI peripheral*/
+       return_value = target_read_u32(target, SPI_CONFIG, &temp_register);
+       if (return_value != ERROR_OK)
+               return return_value;
+       spi_config_register = spi_config_from_u32(temp_register);
+       spi_config_register.spi_enable = 1;
+
+       return_value = target_write_u32(target, SPI_CONFIG, 
u32_from_spi_config(spi_config_register));
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       // Enable chip select
+       if (set_cs_low(target, lpc313x_driver->chip_select) != ERROR_OK)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       /*Power up from deep power down mode*/
+       return_value = target_write_u32(target, SPI_FIFO_DATA, 
SPIFLASH_RESUME_FROM_DEEP_POWER_DOWN);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       // Toggle chip select
+       if (set_cs_high(target, lpc313x_driver->chip_select) != ERROR_OK)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       usleep(100);
+
+       if (set_cs_low(target, lpc313x_driver->chip_select) != ERROR_OK)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       /*poll busy*/
+       bool is_spi_busy = true;
+       uint16_t retry_count = 0;
+       do {
+               return_value = target_read_u32(target, SPI_STATUS, 
&temp_register);
+               if (return_value != ERROR_OK)
+                       return return_value;
+               is_spi_busy = (temp_register & SPI_STATUS_BUSY_BIT_MASK) ? true 
: false;
+               if (is_spi_busy)
+                       LOG_DEBUG("SPI is busy");
+
+       } while (is_spi_busy && retry_count++ < 1000);
+
+       if (is_spi_busy)
+               return ERROR_FLASH_BUSY;
+
+       /*Dummy read byte that was shifted in with write*/
+       return_value = target_read_u32(target, SPI_FIFO_DATA, &temp_register);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       /*Read Device ID from NOR device*/
+
+       /*Write the send ID command into SPI fifo*/
+       return_value = target_write_u32(target, SPI_FIFO_DATA, 
SPIFLASH_READ_ID);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       return_value = target_write_u32(target, SPI_FIFO_DATA, 0);
+       if (return_value != ERROR_OK)
+               return return_value;
+       return_value = target_write_u32(target, SPI_FIFO_DATA, 0);
+       if (return_value != ERROR_OK)
+               return return_value;
+       return_value = target_write_u32(target, SPI_FIFO_DATA, 0);
+       if (return_value != ERROR_OK)
+               return return_value;
+       return_value = target_write_u32(target, SPI_FIFO_DATA, 0);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       /*poll busy*/
+       retry_count = 0;
+       do {
+               return_value = target_read_u32(target, SPI_STATUS, 
&temp_register);
+               if (return_value != ERROR_OK)
+                       return return_value;
+
+               is_spi_busy = (temp_register & SPI_STATUS_BUSY_BIT_MASK) ? true 
: false;
+               if (is_spi_busy)
+                       LOG_DEBUG("SPI is busy");
+
+       } while (is_spi_busy && retry_count++ < 1000);
+
+       if (is_spi_busy)
+               return ERROR_FLASH_BUSY;
+
+       /*Read back 4 bytes from the SPI device*/
+
+       /*Dummy read byte that was shifted in with write*/
+       return_value = target_read_u32(target, SPI_FIFO_DATA, &temp_register);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       temp_register = 0;
+       uint32_t id_word = 0;
+       for (uint8_t byte_count = 0; byte_count <= 3; byte_count++) {
+               return_value = target_read_u32(target, SPI_FIFO_DATA, 
&temp_register);
+               if (return_value != ERROR_OK)
+                       return return_value;
+               id_word |= (temp_register & 0xFF) << (8 * byte_count);
+       }
+
+       // Disable chip select
+       if (set_cs_high(target, lpc313x_driver->chip_select) != ERROR_OK)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       LOG_DEBUG("SPI flash device id: %08x", id_word);
+
+       if ((id_word & 0xFF) == 0x1f) { // try to match legacy adesto spi flash 
device.
+
+               alt_flash_devicep = find_flash_device_by_id(id_word);
+               if (alt_flash_devicep) {
+                       lpc313x_driver->is_legacy_adesto_device = true;
+                       memcpy(&lpc313x_driver->alt_nor_flash_device, 
alt_flash_devicep, sizeof(struct alt_spi_flash_device));
+
+                       uint16_t page_size = 0;
+                       if (get_page_size(bank, &page_size) != ERROR_OK)
+                               return ERROR_FLASH_BANK_INVALID;
+
+                       lpc313x_driver->alt_nor_flash_device.page_size_bytes = 
page_size;
+
+                       
lpc313x_driver->alt_nor_flash_device.build_memory_map(&lpc313x_driver->alt_nor_flash_device,
 bank);
+
+                       LOG_DEBUG("flash device: \'%s\' id = 0x%06" PRIx32 " 
size = %" PRIu32 " KiB",
+                                         
lpc313x_driver->alt_nor_flash_device.device_name,
+                                         
lpc313x_driver->alt_nor_flash_device.device_id,
+                                         bank->size / 1024);
+                       lpc313x_driver->probed = true;
+                       return ERROR_OK;
+               }
+       }
+
+       /* Match read device ID with known spi flash devices */
+       for (flash_devicep = flash_devices; id_word && flash_devicep->name; 
flash_devicep++) {
+               if (flash_devicep->device_id == id_word) {
+                       memcpy(&lpc313x_driver->nor_flash_device, 
flash_devicep, sizeof(lpc313x_driver->nor_flash_device));
+                       if (flash_devicep->size_in_bytes / 1024)
+                               LOG_INFO("flash device: \'%s\' id = 0x%06" 
PRIx32 " size = %" PRIu32
+                                                " KiB",
+                                                flash_devicep->name, id_word, 
flash_devicep->size_in_bytes / 1024);
+                       else
+                               LOG_INFO("flash device: \'%s\' id = 0x%06" 
PRIx32 " size = %" PRIu32
+                                                " B",
+                                                flash_devicep->name, id_word, 
flash_devicep->size_in_bytes);
+                       return ERROR_OK;
+               }
+       }
+       LOG_DEBUG("Device id %08x is not supported", id_word);
+       return ERROR_FLASH_BANK_INVALID;
+}
+
+static int lpc313x_spi_auto_probe(struct flash_bank *bank)
+{
+       struct lpc313x_private_driver *lpc313x_driver = bank->driver_priv;
+       if (lpc313x_driver->probed)
+               return ERROR_OK;
+
+       lpc313x_spi_probe(bank);
+       return ERROR_OK;
+}
+
+static int lpc313x_spi_read(struct flash_bank *bank, uint8_t *buffer,
+                                                       uint32_t offset, 
uint32_t count)
+{
+       struct flash_command spi_flash_command;
+       struct lpc313x_private_driver *lpc313x_driver = bank->driver_priv;
+       int return_value;
+
+       /*Build command*/
+       spi_flash_command.command_bytes = 
malloc(DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES);
+       spi_flash_command.command_length = 0;
+       if (lpc313x_driver->is_legacy_adesto_device) {
+               
lpc313x_driver->alt_nor_flash_device.build_read_page_cmd(&lpc313x_driver->alt_nor_flash_device,
+                                                &spi_flash_command, offset);
+       } else {
+               *spi_flash_command.command_bytes = 
lpc313x_driver->nor_flash_device.read_cmd;
+               spi_flash_command.command_length = 1;
+       }
+
+       bool is_device_busy = true;
+       do {
+               if (device_is_busy(bank, &is_device_busy) != ERROR_OK) {
+                       return_value = ERROR_FAIL;
+                       goto end_read;
+               }
+       } while (is_device_busy);
+
+       if (!lpc313x_driver->probed) {
+               return_value = ERROR_FLASH_BANK_NOT_PROBED;
+               goto end_read;
+       }
+
+       return_value = lpc313x_spi_command_read(bank, buffer, 
&spi_flash_command, count);
+
+end_read:
+       free(spi_flash_command.command_bytes);
+       return return_value;
+}
+
+static int lpc313x_spi_paged_write(struct flash_bank *bank, const uint8_t 
*buffer,
+                                                        uint32_t offset, 
uint32_t count)
+{
+       struct target *target = bank->target;
+       struct lpc313x_private_driver *lpc313x_driver = bank->driver_priv;
+       struct alt_spi_flash_device *alt_nor_device = 
&lpc313x_driver->alt_nor_flash_device;
+       struct flash_command spi_flash_command;
+       struct working_area *target_ram;
+       struct reg_param reg_params[8];
+       struct arm_algorithm armv5_info;
+       int return_value;
+       uint32_t available_ram_bytes = 0;
+       uint32_t code_size_bytes = 0;
+       uint32_t fifo_size_bytes = 0;
+       uint32_t total_ram_bytes_needed = 0;
+       uint8_t *write_buffer = NULL;
+
+       static const uint8_t lpc313x_spi_flash_write_code[] = {
+#include 
"../../../../contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_write.inc"
+       };
+
+       if (!lpc313x_driver->probed)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       /*Build command*/
+       spi_flash_command.command_bytes = 
malloc(DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES);
+       spi_flash_command.command_length = 0;
+       uint32_t page_size = alt_nor_device->page_size_bytes;
+
+       if (lpc313x_driver->is_legacy_adesto_device) {
+               alt_nor_device->build_write_page_cmd(alt_nor_device, 
&spi_flash_command, offset);
+       } else {
+               *spi_flash_command.command_bytes = 
lpc313x_driver->nor_flash_device.pprog_cmd;
+               spi_flash_command.command_length = 1;
+       }
+
+       code_size_bytes = sizeof(lpc313x_spi_flash_write_code);
+       fifo_size_bytes = page_size;
+       total_ram_bytes_needed = code_size_bytes +
+                                                        
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES +
+                                                        fifo_size_bytes;
+
+       available_ram_bytes = target_get_working_area_avail(target);
+       if (available_ram_bytes < total_ram_bytes_needed) {
+               LOG_ERROR("not enough processor RAM available for page writes");
+               return_value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto end_write2;
+       }
+
+       int32_t alloc_return_value = target_alloc_working_area_try(target, 
total_ram_bytes_needed, &target_ram);
+       if (alloc_return_value != ERROR_OK) {
+               LOG_ERROR("allocating working area failed with error code: %d", 
alloc_return_value);
+               return_value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto end_write2;
+       };
+
+       uint32_t spi_command_bytes_address = target_ram->address + 
code_size_bytes;
+       uint32_t fifo_start_address = spi_command_bytes_address + 
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES;
+       uint32_t fifo_end_address = fifo_start_address + fifo_size_bytes;
+
+       /* write flashloader to ram of target */
+       if (target_write_buffer(target, target_ram->address, code_size_bytes, 
lpc313x_spi_flash_write_code) != ERROR_OK) {
+               return_value = ERROR_TARGET_FAILURE;
+               goto end_write2;
+       }
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return_value = ERROR_TARGET_NOT_HALTED;
+               goto end_write2;
+       }
+
+       armv5_info.common_magic = ARM_COMMON_MAGIC;
+       armv5_info.core_mode = ARM_MODE_SYS;
+       armv5_info.core_state = ARM_STATE_ARM;
+
+       /*initialize register values*/
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* byte transfer 
count */
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* head (write) 
pointer */
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* tail (read) 
pointer */
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* chip select */
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* command address 
*/
+       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT); /* command length 
*/
+       init_reg_param(&reg_params[6], "r6", 32, PARAM_OUT); /* FIFO start 
address */
+       init_reg_param(&reg_params[7], "r7", 32, PARAM_OUT); /* FIFO end 
address */
+
+       buf_set_u32(reg_params[2].value, 0, 32, fifo_start_address);
+       buf_set_u32(reg_params[3].value, 0, 32, lpc313x_driver->chip_select);
+
+       buf_set_u32(reg_params[6].value, 0, 32, fifo_start_address);
+       buf_set_u32(reg_params[7].value, 0, 32, fifo_end_address);
+
+       uint32_t write_bytes_remaining = count;
+       uint32_t write_size_bytes = 0;
+       write_buffer = malloc(page_size);
+       bool is_device_busy = true;
+       uint32_t page_index = 0;
+       uint32_t byte_offset = 0;
+       uint32_t bytes_available = 0;
+
+       do {
+               do {
+                       if (device_is_busy(bank, &is_device_busy) != ERROR_OK) {
+                               return_value = ERROR_FAIL;
+                               goto end_write;
+                       }
+               } while (is_device_busy);
+
+               page_index = offset / page_size;
+               byte_offset = offset % page_size;
+               bytes_available = page_size - byte_offset;
+
+               if (write_bytes_remaining >= bytes_available)
+                       write_size_bytes = bytes_available;
+               else
+                       write_size_bytes = write_bytes_remaining;
+
+               if (write_size_bytes < page_size) {// partial page write. need 
to read-modify-write.
+                       return_value = lpc313x_spi_read(bank, write_buffer,
+                                               page_index * page_size, 
page_size); // read entire page into write buffer
+                       if (return_value != ERROR_OK)
+                               goto end_write;
+               }
+
+               memcpy(write_buffer + byte_offset, buffer, write_size_bytes); 
// modify page write buffer with new data bytes
+
+               
lpc313x_driver->alt_nor_flash_device.build_write_page_cmd(&lpc313x_driver->alt_nor_flash_device,
+                                               &spi_flash_command, page_index 
* page_size);
+
+               buf_set_u32(reg_params[0].value, 0, 32, page_size);
+               buf_set_u32(reg_params[1].value, 0, 32, fifo_start_address + 
page_size); /*set head pointer to end of data*/
+               buf_set_u32(reg_params[4].value, 0, 32, 
spi_command_bytes_address);
+               buf_set_u32(reg_params[5].value, 0, 32, 
spi_flash_command.command_length);
+
+               /* write spi write command to ram of target */
+               if (target_write_buffer(target, spi_command_bytes_address,
+                                                               
spi_flash_command.command_length, spi_flash_command.command_bytes) != ERROR_OK) 
{
+                       return_value = ERROR_TARGET_FAILURE;
+                       goto end_write;
+               }
+
+               if (target_write_buffer(target, fifo_start_address, page_size, 
write_buffer) != ERROR_OK) {
+                       return_value = ERROR_TARGET_FAILURE;
+                       goto end_write;
+               }
+
+               return_value = target_run_algorithm(target,
+                       0, NULL,
+                       ARRAY_SIZE(reg_params), reg_params,
+                       target_ram->address,
+                       0,
+                       10000,
+                       &armv5_info);
+
+               if (return_value != ERROR_OK) {
+                       return_value = ERROR_TARGET_FAILURE;
+                       goto end_write;
+               }
+
+               offset += write_size_bytes;
+               buffer += write_size_bytes;
+               write_bytes_remaining -= write_size_bytes;
+
+       } while (write_bytes_remaining != 0);
+
+end_write:
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+       destroy_reg_param(&reg_params[5]);
+       destroy_reg_param(&reg_params[6]);
+       destroy_reg_param(&reg_params[7]);
+       target_free_working_area(target, target_ram);
+end_write2:
+       free(spi_flash_command.command_bytes);
+       if (write_buffer)
+               free(write_buffer);
+
+       return return_value;
+}
+
+static int lpc313x_spi_command_write(struct flash_bank *bank, const uint8_t 
*buffer,
+                                                        struct flash_command 
*spi_flash_command, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct lpc313x_private_driver *lpc313x_driver = bank->driver_priv;
+       int return_value;
+       struct working_area *target_ram = NULL;
+       struct reg_param reg_params[8];
+       struct arm_algorithm armv5_info;
+       uint32_t available_ram_bytes = 0;
+       uint32_t code_size_bytes = 0;
+       uint32_t fifo_size_bytes = 0;
+       uint32_t total_ram_bytes_needed = 0;
+       uint8_t *write_buffer = NULL;
+
+       static const uint8_t lpc313x_spi_flash_write_code[] = {
+#include 
"../../../../contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_write.inc"
+       };
+
+       if (!lpc313x_driver->probed)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       bool is_device_busy = true;
+       do {
+               if (device_is_busy(bank, &is_device_busy) != ERROR_OK) {
+                       return_value = ERROR_FAIL;
+                       goto end_write;
+               }
+       } while (is_device_busy);
+
+       code_size_bytes = sizeof(lpc313x_spi_flash_write_code);
+       fifo_size_bytes = count;
+       total_ram_bytes_needed = code_size_bytes +
+                                                        
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES +
+                                                        fifo_size_bytes;
+
+       available_ram_bytes = target_get_working_area_avail(target);
+       if (available_ram_bytes < total_ram_bytes_needed) {
+               LOG_ERROR("not enough processor RAM available for page writes");
+               return_value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto end_write2;
+       }
+
+       int32_t alloc_return_value = target_alloc_working_area_try(target, 
total_ram_bytes_needed, &target_ram);
+       if (alloc_return_value != ERROR_OK) {
+               LOG_ERROR("allocating working area failed with error code: %d", 
alloc_return_value);
+               return_value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto end_write2;
+       };
+
+       uint32_t spi_command_bytes_address = target_ram->address + 
code_size_bytes;
+       uint32_t fifo_start_address = spi_command_bytes_address + 
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES;
+       uint32_t fifo_end_address = fifo_start_address + fifo_size_bytes;
+
+       /* write flashloader to ram of target */
+       if (target_write_buffer(target, target_ram->address, code_size_bytes, 
lpc313x_spi_flash_write_code) != ERROR_OK) {
+               return_value = ERROR_TARGET_FAILURE;
+               goto end_write2;
+       }
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return_value = ERROR_TARGET_NOT_HALTED;
+               goto end_write2;
+       }
+
+
+       armv5_info.common_magic = ARM_COMMON_MAGIC;
+       armv5_info.core_mode = ARM_MODE_SYS;
+       armv5_info.core_state = ARM_STATE_ARM;
+
+       /*initialize register values*/
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* byte transfer 
count */
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* head (write) 
pointer */
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* tail (read) 
pointer */
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* chip select */
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* command address 
*/
+       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT); /* command length 
*/
+       init_reg_param(&reg_params[6], "r6", 32, PARAM_OUT); /* FIFO start 
address */
+       init_reg_param(&reg_params[7], "r7", 32, PARAM_OUT); /* FIFO end 
address */
+
+       buf_set_u32(reg_params[0].value, 0, 32, count);
+       buf_set_u32(reg_params[1].value, 0, 32, fifo_start_address + count);
+       buf_set_u32(reg_params[2].value, 0, 32, fifo_start_address);
+       buf_set_u32(reg_params[3].value, 0, 32, lpc313x_driver->chip_select);
+       buf_set_u32(reg_params[4].value, 0, 32, spi_command_bytes_address);
+       buf_set_u32(reg_params[5].value, 0, 32, 
spi_flash_command->command_length);
+       buf_set_u32(reg_params[6].value, 0, 32, fifo_start_address);
+       buf_set_u32(reg_params[7].value, 0, 32, fifo_end_address);
+
+
+       /* write spi write command to ram of target */
+       if (target_write_buffer(target, spi_command_bytes_address,
+                                                       
spi_flash_command->command_length, spi_flash_command->command_bytes) != 
ERROR_OK) {
+               return_value = ERROR_TARGET_FAILURE;
+               goto end_write;
+       }
+
+       /* write data to ram of target*/
+       if (target_write_buffer(target, fifo_start_address, count, buffer) != 
ERROR_OK) {
+               return_value = ERROR_TARGET_FAILURE;
+               goto end_write;
+       }
+
+       return_value = target_run_algorithm(target,
+               0, NULL,
+               ARRAY_SIZE(reg_params), reg_params,
+               target_ram->address,
+               0,
+               10000,
+               &armv5_info);
+
+       if (return_value != ERROR_OK)
+               return_value = ERROR_TARGET_FAILURE;
+
+end_write:
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+       destroy_reg_param(&reg_params[5]);
+       destroy_reg_param(&reg_params[6]);
+       destroy_reg_param(&reg_params[7]);
+       target_free_working_area(target, target_ram);
+
+end_write2:
+       if (write_buffer)
+               free(write_buffer);
+
+       return return_value;
+}
+
+static int lpc313x_spi_verify(struct flash_bank *bank, const uint8_t *buffer,
+                                                         uint32_t offset, 
uint32_t count)
+{
+       uint32_t crc32_file = 0;
+       uint32_t crc32_flash = 0;
+       int result = ERROR_FAIL;
+
+       if (image_calculate_checksum(buffer, count, &crc32_file) != ERROR_OK)
+               return ERROR_FAIL;
+
+       /*Read count bytes at offset from lpc313x spi device*/
+
+       uint8_t *read_buff = malloc(sizeof(uint8_t) * count);
+       if (!read_buff)
+               return ERROR_FAIL;
+
+       if (lpc313x_spi_read(bank, read_buff, offset, count) != ERROR_OK) {
+               result = ERROR_FAIL;
+               goto finish;
+       }
+
+       if (image_calculate_checksum(read_buff, count, &crc32_flash) != 
ERROR_OK) {
+               result = ERROR_FAIL;
+               goto finish;
+       }
+
+       if (crc32_file == crc32_flash)
+               result = ERROR_OK;
+
+finish:
+       if (read_buff)
+               free(read_buff);
+
+       return result;
+}
+
+static int lpc313x_spi_erase_sector(struct flash_bank *bank, uint32_t 
sector_index)
+{
+       struct target *target = bank->target;
+       struct lpc313x_private_driver *lpc313x_driver = bank->driver_priv;
+       struct flash_command spi_flash_command;
+       struct working_area *target_ram;
+       struct reg_param reg_params[8];
+       struct arm_algorithm armv5_info;
+       int return_value = -1;
+       uint32_t available_ram_bytes = 0;
+       uint32_t code_size_bytes = 0;
+       uint32_t fifo_size_bytes = 0;
+       uint32_t total_ram_bytes_needed = 0;
+
+       static const uint8_t lpc313x_spi_flash_write_code[] = {
+#include 
"../../../../contrib/loaders/flash/lpc313x-spi/lpc313x_spi_flash_write.inc"
+       };
+
+       /*Build command*/
+       spi_flash_command.command_bytes = 
malloc(DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES);
+       spi_flash_command.command_length = 0;
+       uint32_t page_size = 
lpc313x_driver->alt_nor_flash_device.page_size_bytes;
+
+       if (lpc313x_driver->is_legacy_adesto_device) {
+               
lpc313x_driver->alt_nor_flash_device.build_erase_sector_cmd(&lpc313x_driver->alt_nor_flash_device,
+                       &spi_flash_command, sector_index);
+       } else {
+               *spi_flash_command.command_bytes = 
lpc313x_driver->nor_flash_device.erase_cmd;
+               spi_flash_command.command_length = 1;
+       }
+
+       code_size_bytes = sizeof(lpc313x_spi_flash_write_code);
+       fifo_size_bytes = page_size;
+       total_ram_bytes_needed = code_size_bytes + 
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES + fifo_size_bytes;
+
+       available_ram_bytes = target_get_working_area_avail(target);
+       if (available_ram_bytes < total_ram_bytes_needed) {
+               LOG_ERROR("not enough processor RAM available for page writes");
+               return_value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto end_erase3;
+       }
+
+       int32_t alloc_return_value = target_alloc_working_area_try(target, 
total_ram_bytes_needed, &target_ram);
+       if (alloc_return_value != ERROR_OK) {
+               LOG_ERROR("allocating working area failed with error code: %d", 
alloc_return_value);
+               return_value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto end_erase3;
+       }
+
+       uint32_t spi_command_bytes_address = target_ram->address + 
code_size_bytes;
+       uint32_t fifo_start_address = spi_command_bytes_address + 
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES;
+       uint32_t fifo_end_address = fifo_start_address + fifo_size_bytes;
+
+       /* write flashloader to ram of target */
+       return_value = target_write_buffer(target, target_ram->address,
+                                                                          
code_size_bytes, lpc313x_spi_flash_write_code);
+       if (return_value != ERROR_OK)
+               goto end_erase;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return_value = ERROR_TARGET_NOT_HALTED;
+               goto end_erase2;
+       }
+
+       armv5_info.common_magic = ARM_COMMON_MAGIC;
+       armv5_info.core_mode = ARM_MODE_SYS;
+       armv5_info.core_state = ARM_STATE_ARM;
+
+       /*initialize register values*/
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* byte transfer 
count */
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* head (write) 
pointer */
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* tail (read) 
pointer */
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* chip select */
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* command address 
*/
+       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT); /* command length 
*/
+       init_reg_param(&reg_params[6], "r6", 32, PARAM_OUT); /* FIFO start 
address */
+       init_reg_param(&reg_params[7], "r7", 32, PARAM_OUT); /* FIFO end 
address */
+
+       buf_set_u32(reg_params[2].value, 0, 32, fifo_start_address);
+       buf_set_u32(reg_params[3].value, 0, 32, lpc313x_driver->chip_select);
+
+       buf_set_u32(reg_params[6].value, 0, 32, fifo_start_address);
+       buf_set_u32(reg_params[7].value, 0, 32, fifo_end_address);
+
+       bool is_device_busy = true;
+
+       do {
+               if (device_is_busy(bank, &is_device_busy) != ERROR_OK) {
+                       return_value = ERROR_FAIL;
+                       goto end_erase;
+               }
+       } while (is_device_busy);
+
+       buf_set_u32(reg_params[0].value, 0, 32, 0);
+       buf_set_u32(reg_params[1].value, 0, 32, fifo_start_address + 
page_size); /*set head pointer to end of data*/
+       buf_set_u32(reg_params[4].value, 0, 32, spi_command_bytes_address);
+       buf_set_u32(reg_params[5].value, 0, 32, 
spi_flash_command.command_length);
+
+       /* write spi write command to ram of target */
+       if (target_write_buffer(target, spi_command_bytes_address,
+                                                       
spi_flash_command.command_length, spi_flash_command.command_bytes) != ERROR_OK) 
{
+               return_value = ERROR_TARGET_FAILURE;
+               goto end_erase;
+       };
+
+       return_value = target_run_algorithm(target,
+               0, NULL,
+               ARRAY_SIZE(reg_params), reg_params,
+               target_ram->address,
+               0,
+               10000,
+               &armv5_info);
+
+end_erase:
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+       destroy_reg_param(&reg_params[5]);
+end_erase2:
+       target_free_working_area(target, target_ram);
+end_erase3:
+       free(spi_flash_command.command_bytes);
+
+       return return_value;
+}
+
+static int lpc313x_spi_erase(struct flash_bank *bank, unsigned int first, 
unsigned int last)
+{
+       struct target *target = bank->target;
+       struct lpc313x_private_driver *lpc313x_driver = bank->driver_priv;
+       int return_value = -1;
+       unsigned int sector_index;
+
+       if (!lpc313x_driver->probed)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (last < first || last >= bank->num_sectors) {
+               LOG_ERROR("Flash sector invalid");
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       for (sector_index = first; sector_index <= last; sector_index++) {
+               if (bank->sectors[sector_index].is_protected) {
+                       LOG_ERROR("Flash sector %u protected", sector_index);
+                       return ERROR_FLASH_PROTECTED;
+               }
+       }
+
+       for (sector_index = first; sector_index <= last; sector_index++) {
+               return_value = lpc313x_spi_erase_sector(bank, sector_index);
+               if (return_value != ERROR_OK)
+                       break;
+               alive_sleep(10);
+               keep_alive();
+       }
+
+       if (return_value != ERROR_OK)
+               LOG_ERROR("Flash sector_erase failed on sector %u", 
sector_index);
+
+       return return_value;
+}
+
+static int lpc313x_spi_protect(struct flash_bank *bank, int set,
+                                                          unsigned int first, 
unsigned int last)
+{
+       unsigned int sector;
+       LOG_INFO("Called LPC SPI Protect");
+       for (sector = first; sector <= last; sector++)
+               bank->sectors[sector].is_protected = set;
+
+       if (set)
+               LOG_WARNING("setting soft protection only, not related to 
flash's hardware write protection");
+
+       return ERROR_OK;
+}
+
+static int lpc313x_spi_protect_check(struct flash_bank *bank)
+{
+       /* Nothing to do. Protection is only handled in SW. */
+       return ERROR_OK;
+}
+
+/* Check whether flash is blank */
+static int lpc313x_spi_blank_check(struct flash_bank *bank)
+{
+       LOG_INFO("Called LPC SPI blank check");
+       return ERROR_OK;
+}
+
+static int get_lpc313x_driver(struct flash_bank *bank, struct 
command_invocation *cmd)
+{
+       struct lpc313x_private_driver *lpc313x_driver = bank->driver_priv;
+
+       if (!(lpc313x_driver->probed)) {
+               command_print_sameline(cmd, "\n lpc313x spi flash bank not 
probed yet\n");
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       command_print_sameline(cmd, "\'%s\' device id = 0x%x"
+                       ", flash size = %d %sB\n(page size = %d"
+                       ", sector size = %d %sB)",
+                       lpc313x_driver->devname,
+                       lpc313x_driver->alt_nor_flash_device.device_id,
+                       bank->size / 4096 ? bank->size / 1024 : bank->size,
+                       bank->size / 4096 ? "Ki" : "",
+                       lpc313x_driver->alt_nor_flash_device.page_size_bytes,
+                       
get_flash_device_sector_size_bytes(&lpc313x_driver->alt_nor_flash_device) / 
4096 ?
+                       
get_flash_device_sector_size_bytes(&lpc313x_driver->alt_nor_flash_device) / 
1024 :
+                       
get_flash_device_sector_size_bytes(&lpc313x_driver->alt_nor_flash_device),
+
+                       
get_flash_device_sector_size_bytes(&lpc313x_driver->alt_nor_flash_device) / 
4096 ? "Ki" : "");
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(lpc313x_spi_handle_device_erase_command)
+{
+       struct target *target = NULL;
+       struct flash_bank *bank;
+       struct lpc313x_private_driver *lpc313x_flash_bank;
+       struct flash_command spi_flash_command;
+       uint8_t buffer[1];
+       int return_value;
+
+       LOG_DEBUG("%s", __func__);
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       return_value = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+       lpc313x_flash_bank = bank->driver_priv;
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (!(lpc313x_flash_bank->probed)) {
+               LOG_ERROR("Flash bank not probed");
+               return ERROR_FLASH_BANK_NOT_PROBED;
+       }
+
+       spi_flash_command.command_bytes = 
malloc(DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES);
+
+       if (!(lpc313x_flash_bank->is_legacy_adesto_device)) {
+               if (lpc313x_flash_bank->nor_flash_device.chip_erase_cmd == 
0x00) {
+                       LOG_ERROR("device erase not supported");
+                       return_value = ERROR_FLASH_BANK_NOT_PROBED;
+                       goto device_erase_end;
+               }
+               *spi_flash_command.command_bytes = 
lpc313x_flash_bank->nor_flash_device.chip_erase_cmd;
+               spi_flash_command.command_length = 1;
+       } else {
+               
lpc313x_flash_bank->alt_nor_flash_device.build_erase_device_cmd(&spi_flash_command);
+       }
+
+       return_value = lpc313x_spi_command_write(bank, buffer, 
&spi_flash_command, 0);
+
+       bool is_device_busy = true;
+       do {
+               keep_alive();
+               if (device_is_busy(bank, &is_device_busy) != ERROR_OK) {
+                       return_value = ERROR_FAIL;
+                       break;
+               }
+               sleep(1); /*TODO sleep less than 1 second.*/
+       } while (is_device_busy);
+
+device_erase_end:
+       free(spi_flash_command.command_bytes);
+       return return_value;
+}
+
+COMMAND_HANDLER(lpc313x_spi_handle_write_cmd)
+{
+       struct flash_bank *bank;
+       struct flash_command spi_flash_command;
+       int return_value;
+       int bank_index = 0;
+       unsigned int argv_position = 0;
+       unsigned int command_count = 0;
+       unsigned int data_count = 0;
+       uint8_t *data_buffer;
+
+       if (cmd->argc < 3) {
+               LOG_ERROR("Need more arguments for write command");
+               LOG_ERROR(" bank command_count command_byte[0] ... "
+                       "command_byte[command_count] data_count databyte[0] ... 
databyte[N]");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[argv_position++], bank_index);
+
+       return_value = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+
+       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[argv_position++], command_count);
+
+       if ((cmd->argc - argv_position) < command_count || command_count > 
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES) {
+               LOG_INFO("command count invalid. Arguments should match command 
count."
+                       "Choose a number between 1 - %d", 
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       uint8_t command_bytes[command_count];
+
+       for (unsigned int i = 0; i < command_count; i++)
+               COMMAND_PARSE_NUMBER(u8, cmd->argv[argv_position++], 
command_bytes[i]);
+
+       spi_flash_command.command_bytes = &command_bytes[0];
+       spi_flash_command.command_length = command_count;
+
+       if (cmd->argc > argv_position + 1) {
+               COMMAND_PARSE_NUMBER(uint, CMD_ARGV[argv_position++], 
data_count);
+
+               if ((cmd->argc - argv_position) < data_count) {
+                       LOG_INFO("data count invalid. number of arguments 
should match data count.");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
+
+               data_buffer = malloc(data_count * sizeof(uint8_t));
+
+               for (unsigned int i = 0; i < data_count; i++)
+                       COMMAND_PARSE_NUMBER(u8, cmd->argv[argv_position++], 
*(data_buffer + i));
+
+       } else {
+               data_buffer = malloc(sizeof(uint8_t)); /*Get rid of warning.*/
+       }
+
+       return_value = lpc313x_spi_command_write(bank, data_buffer, 
&spi_flash_command, data_count);
+
+       if (data_buffer)
+               free(data_buffer);
+
+       return return_value;
+}
+
+COMMAND_HANDLER(lpc313x_spi_handle_read_cmd)
+{
+       struct flash_bank *bank = NULL;
+       struct target *target = NULL;
+       struct flash_command spi_flash_command;
+       int return_value;
+       unsigned int bank_index = 0;
+       unsigned int command_count = 0;
+       unsigned int data_count = 0;
+       uint8_t *data_buffer = NULL;
+       int argv_position = 0;
+
+       if (cmd->argc < 3) {
+               LOG_ERROR("Need more arguments for read command");
+               LOG_ERROR(" bank_id command_count cmd_byte[s] read_count");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[argv_position++], bank_index);
+       return_value = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (return_value != ERROR_OK)
+               return return_value;
+
+
+       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[argv_position++], command_count);
+       if ((cmd->argc - argv_position) < command_count || command_count > 
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES) {
+               LOG_INFO("command count invalid. Arguments should match command 
count."
+                       "Choose a number between 1 - %d", 
DEFAULT_MAX_FLASH_COMMAND_LENGTH_BYTES);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       uint8_t command_bytes[command_count];
+
+       for (unsigned int i = 0; i < command_count; i++)
+               COMMAND_PARSE_NUMBER(u8, cmd->argv[argv_position++], 
command_bytes[i]);
+
+       spi_flash_command.command_bytes = &command_bytes[0];
+       spi_flash_command.command_length = command_count;
+
+
+       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[argv_position++], data_count);
+
+       if (data_count > 0) {
+               data_buffer = malloc(data_count * sizeof(uint8_t));
+               if (!data_buffer) {
+                       return_value = ERROR_FAIL;
+                       goto end;
+               }
+       }
+
+       return_value = lpc313x_spi_command_read(bank, data_buffer, 
&spi_flash_command, data_count);
+       if (return_value != ERROR_OK)
+               goto end;
+
+       target = bank->target;
+       target_handle_md_output(CMD, target, 0, 1, data_count, data_buffer);
+
+end:
+       if (data_buffer)
+               free(data_buffer);
+
+       return return_value;
+}
+
+static const struct command_registration lpc313x_spi_exec_command_handlers[] = 
{
+       {
+               .name = "device_erase",
+               .handler = lpc313x_spi_handle_device_erase_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Erase entire flash device.",
+       },
+       {
+               .name = "command_write",
+               .handler = lpc313x_spi_handle_write_cmd,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id cmd_count [command_bytes] data_count [data 
bytes]",
+               .help = "Write command byte[s] followed by optional data 
byte[s].",
+       },
+       {
+               .name = "command_read",
+               .handler = lpc313x_spi_handle_read_cmd,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id cmd_byte[s] read_count",
+               .help = " Write command byte[s] and optionally read back 
byte[s].",
+       },
+       COMMAND_REGISTRATION_DONE};
+
+static const struct command_registration lpc313x_spi_command_handlers[] = {
+       {
+               .name = "lpc313x-spi",
+               .mode = COMMAND_ANY,
+               .help = "lpc313x-spi flash command group",
+               .usage = "",
+               .chain = lpc313x_spi_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE};
+
+const struct flash_driver lpc313x_spi_flash = {
+       .name = "lpc313x-spi",
+       .usage = "NOR flash driver via SPI interface for LPC313x cpu",
+       .commands = lpc313x_spi_command_handlers,
+       .flash_bank_command = lpc313x_spi_flash_bank_command,
+       .erase = lpc313x_spi_erase,
+       .protect = lpc313x_spi_protect,
+       .write = lpc313x_spi_paged_write,
+       .read = lpc313x_spi_read,
+       .verify = lpc313x_spi_verify,
+       .probe = lpc313x_spi_probe,
+       .erase_check = lpc313x_spi_blank_check,
+       .protect_check = lpc313x_spi_protect_check,
+       .info = get_lpc313x_driver,
+       .auto_probe = lpc313x_spi_auto_probe,
+       .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/lpc313x-spi/lpc313x_spi.h 
b/src/flash/nor/lpc313x-spi/lpc313x_spi.h
new file mode 100644
index 0000000000..5a4bb7c7fc
--- /dev/null
+++ b/src/flash/nor/lpc313x-spi/lpc313x_spi.h
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2023 by Travis Lowe                                     *
+ *   tml...@gmail.com                                                      *
+ ***************************************************************************/
+
+#ifndef OPENOCD_FLASH_NOR_LPC313X_SPI_H
+#define OPENOCD_FLASH_NOR_LPC313X_SPI_H
+
+
+
+
+#define CGU_CLOCK_SWITCHBOX_BASE       0x13004000
+
+#define CGU_SCR_10     CGU_CLOCK_SWITCHBOX_BASE + 0x28 // SPI_CLK_BASE Switch 
Configuration Register
+#define CGU_FS1_10     CGU_CLOCK_SWITCHBOX_BASE + 0x58 // SPI_CLK_BASE 
Frequency Select Register 1
+#define CGU_FS2_10     CGU_CLOCK_SWITCHBOX_BASE + 0x88 // SPI_CLK_BASE 
Frequency Select Register 2
+#define CGU_SSR_10     CGU_CLOCK_SWITCHBOX_BASE + 0xB8 // SPI_CLK_BASE Switch 
Status Register
+
+#define CGU_PCR_56     CGU_CLOCK_SWITCHBOX_BASE + 0x1A0 // SPI_PCLK Power 
Control Register
+#define CGU_PCR_57     CGU_CLOCK_SWITCHBOX_BASE + 0x1A4 // SPI_PCLK_GATED 
Power Control Register
+#define CGU_PCR_89     CGU_CLOCK_SWITCHBOX_BASE + 0x224 // SPI_CLK Power 
Control Register
+#define CGU_PCR_90     CGU_CLOCK_SWITCHBOX_BASE + 0x228 // SPI_CLK_GATED Power 
Control Register
+
+#define CGU_PSR_56     CGU_CLOCK_SWITCHBOX_BASE + 0x310 // SPI_PCLK Power 
Status Register
+#define CGU_PSR_57     CGU_CLOCK_SWITCHBOX_BASE + 0x314 // SPI_PCLK_GATED 
Power Status Register
+#define CGU_PSR_89     CGU_CLOCK_SWITCHBOX_BASE + 0x394 // SPI_CLK Power 
Status Register
+#define CGU_PSR_90     CGU_CLOCK_SWITCHBOX_BASE + 0x398 // SPI_CLK_GATED Power 
Status Register
+
+#define CGU_ESR_56     CGU_CLOCK_SWITCHBOX_BASE + 0x480 // SPI_PCLK Enable 
Select and Enable Register
+#define CGU_ESR_57     CGU_CLOCK_SWITCHBOX_BASE + 0x484 // SPI_PCLK_GATED 
Enable Select and Enable Register
+#define CGU_ESR_87
+#define CGU_ESR_88
+
+#define SPI_BASE 0x15002000
+
+#define SPI_CONFIG              (SPI_BASE)
+#define SPI_SLAVE_ENABLE               (SPI_BASE + 0x04)
+#define SPI_TX_FIFO_FLUSH              (SPI_BASE + 0x08)
+#define SPI_FIFO_DATA                  (SPI_BASE + 0x0C)
+#define SPI_NHP_POP                            (SPI_BASE + 0x10)
+#define SPI_NHP_MODE                   (SPI_BASE + 0x14)
+#define SPI_DMA_SETTINGS               (SPI_BASE + 0x18)
+#define SPI_STATUS                             (SPI_BASE + 0x1C)
+#define SPI_HW_INFO                            (SPI_BASE + 0x20)
+
+#define SPI_SLAVE0_SETTINGS1   (SPI_BASE + 0x24)
+#define SPI_SLAVE0_SETTINGS2   (SPI_BASE + 0x28)
+#define SPI_SLAVE1_SETTINGS1   (SPI_BASE + 0x2C)
+#define SPI_SLAVE1_SETTINGS2   (SPI_BASE + 0x30)
+#define SPI_SLAVE2_SETTINGS1   (SPI_BASE + 0x34)
+#define SPI_SLAVE2_SETTINGS2   (SPI_BASE + 0x38)
+
+#define SPI_INT_THRESHOLD              (SPI_BASE + 0xFD4)
+#define SPI_INT_CLR_ENABLE             (SPI_BASE + 0xFD8)
+#define SPI_INT_SET_ENABLE             (SPI_BASE + 0xFDC)
+#define SPI_INT_STATUS                 (SPI_BASE + 0xFE0)
+#define SPI_INT_ENABLE                 (SPI_BASE + 0xFE4)
+#define SPI_INT_CLR_STATUS             (SPI_BASE + 0xFE8)
+#define SPI_INT_SET_STATUS             (SPI_BASE + 0xFEC)
+
+/*SPI CONFIG register bit masks*/
+#define SPI_CONFIG_INTER_SLAVE_DELAY_BIT_MASK           0xFFFF0000
+#define SPI_CONFIG_UPDATE_ENABLE_BIT_MASK               0x00000080
+#define SPI_CONFIG_SOFTWARE_RESET_BIT_MASK              0x00000040
+#define SPI_CONFIG_SLAVE_DISABLE_BIT_MASK               0x00000010
+#define SPI_CONFIG_TX_MODE_BIT_MASK                     0x00000008
+#define SPI_CONFIG_LOOPBACK_MODE_BIT_MASK               0x00000004
+#define SPI_CONFIG_MAST_SLV_MODE_BIT_MASK               0x00000002
+#define SPI_CONFIG_SPI_ENABLE_BIT_MASK                  0x00000001
+
+/*SPI SLAVE ENABLE register bit mask*/
+#define SPI_SLAVE_ENABLE_3_BIT_MASK                     0x00000030
+#define SPI_SLAVE_ENABLE_2_BIT_MASK                     0x0000000C
+#define SPI_SLAVE_ENABLE_1_BIT_MASK                     0x00000003
+
+/*SPI SLAVE SETTINGS 1 register bit masks*/
+#define SPI_SLAVE_SETTINGS1_INTER_TX_DELAY_BIT_MASK    0xFF000000
+#define SPI_SLAVE_SETTINGS1_NUM_OF_WORDS_BIT_MASK      0x00FF0000
+#define SPI_SLAVE_SETTINGS1_CLK_DIVISOR1_BIT_MASK      0x0000FF00
+#define SPI_SLAVE_SETTINGS1_CLK_DIVISOR2_BIT_MASK      0x000000FF
+
+/*SPI SLAVE SETTINGS 2 register bit masks*/
+#define SPI_SLAVE_SETTINGS2_PRE_POST_DELAY_BIT_MASK    0x0001FE00
+#define SPI_SLAVE_SETTINGS2_CHIP_SEL_VAL_BIT_MASK      0x00000100
+#define SPI_SLAVE_SETTINGS2_TRANSFER_FORMAT_BIT_MASK   0x00000080
+#define SPI_SLAVE_SETTINGS2_SCLK_POLARITY_BIT_MASK     0x00000040
+#define SPI_SLAVE_SETTINGS2_SCLK_PHASE_BIT_MASK        0x00000020
+#define SPI_SLAVE_SETTINGS2_WORD_SIZE_BIT_MASK         0x0000001F
+
+/*SPI STATUS register bit masks*/
+#define SPI_STATUS_SMS_MODE_BUSY_BIT_MASK               0x00000020
+#define SPI_STATUS_BUSY_BIT_MASK                        0x00000010
+#define SPI_STATUS_RX_FIFO_FULL_BIT_MASK                0x00000008
+#define SPI_STATUS_RX_FIFO_EMPTY_BIT_MASK               0x00000004
+#define SPI_STATUS_TX_FIFO_FULL_BIT_MASK                0x00000002
+#define SPI_STATUS_TX_FIFO_EMPTY_BIT_MASK               0x00000001
+
+
+// GPIO mode bits (UM10314 pg. 309)
+/*--------------------------------------------------------------*/
+/*  Mode 1 bit  |   Mode 0 bit  |   Operation                   */
+/*--------------------------------------------------------------*/
+/*      0       |       0       | input- output driver disabled */
+/*--------------------------------------------------------------*/
+/*      0       |       1       | output controlled by device   */
+/*--------------------------------------------------------------*/
+/*      1       |       0       | output driven low             */
+/*--------------------------------------------------------------*/
+/*      1       |       1       | output driven high            */
+/*--------------------------------------------------------------*/
+
+/* IO CONFIG registers for chip select 1*/
+#define IOCONFIG_SPI_MODE_0_SET                         0x13003254
+#define IOCONFIG_SPI_MODE_0_CLEAR                       0x13003258
+#define IOCONFIG_SPI_MODE_1_SET                         0x13003264
+#define IOCONFIG_SPI_MODE_1_CLEAR                       0x13003268
+
+/* IO CONFIG registers for chip selects 2 and 3*/
+#define IOCONFIG_EBI_I2STX_0_MODE_0_SET                 0x13003054
+#define IOCONFIG_EBI_I2STX_0_MODE_0_CLEAR               0x13003058
+#define IOCONFIG_EBI_I2STX_0_MODE_1_SET                 0x13003064
+#define IOCONFIG_EBI_I2STX_0_MODE_1_CLEAR               0x13003068
+
+#define IOCONFIG_SPI_CS_0_BITMASK                       0x00000010
+#define IOCONFIG_EBI_I2STX_0_CS_1_BITMASK               0x00000008
+#define IOCONFIG_EBI_I2STX_0_CS_2_BITMASK               0x00000010
+
+
+
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+       struct LPC313X_SPI_CONFIG_REG {
+               uint16_t inter_slave_delay;
+               uint8_t  update_enable;
+               uint8_t  software_reset;
+               uint8_t  slave_disable;
+               uint8_t  transmit_mode;
+               uint8_t  loopback_mode;
+               uint8_t  mass_slave_mode;
+               uint8_t  spi_enable;
+       };
+
+       struct LPC313X_SPI_SLAVE_ENABLE_REG {
+               uint8_t slave_enable_1;
+               uint8_t slave_enable_2;
+               uint8_t slave_enable_3;
+       };
+
+       struct LPC313X_SPI_TX_FIFO_FLUSH_REG {
+               uint8_t tx_fifo_flush;
+       };
+
+       struct LPC313X_SPI_FIFO_DATA_REG {
+               uint16_t fifo_data;
+       };
+
+       struct LPC313X_SPI_NHP_MODE_REG {
+               uint8_t nhp_mode;
+       };
+
+       struct LPC313X_SPI_DMA_SETTING_REG {
+               uint8_t tx_dma_enable;
+               uint8_t rx_dma_enable;
+       };
+
+       struct LPC313X_SPI_STATUS_REG {
+               uint8_t seq_ms_mode_busy; /*Sequential multi-slave mode busy*/
+               uint8_t spi_busy;
+               uint8_t rx_fifo_full;
+               uint8_t rx_fifo_empty;
+               uint8_t tx_fifo_full;
+               uint8_t tx_fifo_empty;
+       };
+
+       struct LPC313X_SPI_HARDWARE_INFO_REG {
+               uint8_t fifo_impl;
+               uint8_t num_slaves;
+               uint8_t tx_fifo_width;
+               uint8_t rx_fifo_width;
+               uint8_t tx_fifo_depth;
+               uint8_t rx_fifo_depth;
+       };
+
+       struct LPC313X_SPI_SLAVE_SETTINGS1_REG {
+               uint8_t inter_transfer_delay;
+               uint8_t number_words;
+               uint8_t clock_divisor2;
+               uint8_t clock_divisor1;
+       };
+
+       struct LPC313X_SPI_SLAVE_SETTINGS2_REG {
+               uint8_t pre_post_chip_select_delay;
+               uint8_t chip_select_value;
+               uint8_t transfer_format;
+               uint8_t serial_clock_polarity;
+               uint8_t serial_clock_phase;
+               uint8_t word_size;
+       };
+#endif
+
+#endif
diff --git a/tcl/board/lpc3131_ext_spi_flash_generic.cfg 
b/tcl/board/lpc3131_ext_spi_flash_generic.cfg
new file mode 100644
index 0000000000..aa5c0f0e31
--- /dev/null
+++ b/tcl/board/lpc3131_ext_spi_flash_generic.cfg
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+adapter driver jlink
+transport select jtag
+jtag_ntrst_delay 1
+
+adapter speed 3000
+adapter srst delay 500
+reset_config trst_and_srst connect_deassert_srst
+
+source [find target/lpc3131.cfg]
+
+
+set _FLASHNAME $_CHIPNAME.flash
+flash bank $_FLASHNAME lpc313x-spi 0 0 0 0 $_TARGETNAME 0
+
+init
+$_TARGETNAME invoke-event reset-init
diff --git a/tcl/target/lpc3131.cfg b/tcl/target/lpc3131.cfg
index 09d698ac6c..1c17634fe4 100644
--- a/tcl/target/lpc3131.cfg
+++ b/tcl/target/lpc3131.cfg
@@ -45,24 +45,24 @@ set lpc313x [ dict create ]
 dict set lpc313x sram0                 0x11028000
 dict set lpc313x sram1                 0x11040000
 dict set lpc313x uart                  0x15001000
-dict set lpc313x cgu                   0x13004000
+dict set lpc313x cgu                      0x13004000
 dict set lpc313x ioconfig              0x13003000
 dict set lpc313x sysconfig             0x13002800
-dict set lpc313x wdt                   0x13002400
+dict set lpc313x wdt                      0x13002400
 
 ##################################################################
 # Target configuration
 ##################################################################
 
 adapter srst delay 1000
-jtag_ntrst_delay 0
+jtag_ntrst_delay 500
 
 set _TARGETNAME $_CHIPNAME.cpu
 target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position 
$_TARGETNAME
 
-$_TARGETNAME invoke-event halted
 
-$_TARGETNAME configure -work-area-phys [dict get $lpc313x sram0] 
-work-area-size 0x30000 -work-area-backup 0
+
+$_TARGETNAME configure -work-area-phys [dict get $lpc313x sram0] 
-work-area-virt [dict get $lpc313x sram0]  -work-area-size 0x30000 
-work-area-backup 0
 
 $_TARGETNAME configure -event reset-init {
        echo "\nRunning reset init script for LPC3131\n"
@@ -75,4 +75,5 @@ $_TARGETNAME configure -event reset-init {
 }
 
 arm7_9 fast_memory_access enable
-arm7_9 dcc_downloads enable
+arm7_9 dcc_downloads disable
+

-- 

Reply via email to