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(®_params[0], "r0", 32, PARAM_OUT); /* byte transfer count */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* head (write) pointer */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* tail (read) pointer */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* chip select */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* command address */ + init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* command length */ + init_reg_param(®_params[6], "r6", 32, PARAM_OUT); /* FIFO start address */ + init_reg_param(®_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(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); + destroy_reg_param(®_params[6]); + destroy_reg_param(®_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(®_params[0], "r0", 32, PARAM_OUT); /* byte transfer count */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* head (write) pointer */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* tail (read) pointer */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* chip select */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* command address */ + init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* command length */ + init_reg_param(®_params[6], "r6", 32, PARAM_OUT); /* FIFO start address */ + init_reg_param(®_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(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); + destroy_reg_param(®_params[6]); + destroy_reg_param(®_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(®_params[0], "r0", 32, PARAM_OUT); /* byte transfer count */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* head (write) pointer */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* tail (read) pointer */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* chip select */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* command address */ + init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* command length */ + init_reg_param(®_params[6], "r6", 32, PARAM_OUT); /* FIFO start address */ + init_reg_param(®_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(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); + destroy_reg_param(®_params[6]); + destroy_reg_param(®_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(®_params[0], "r0", 32, PARAM_OUT); /* byte transfer count */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* head (write) pointer */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* tail (read) pointer */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* chip select */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* command address */ + init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* command length */ + init_reg_param(®_params[6], "r6", 32, PARAM_OUT); /* FIFO start address */ + init_reg_param(®_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(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_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 + --