aboutsummaryrefslogtreecommitdiff
path: root/contrib/loaders/flash/fespi/fespi.S
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2018-11-06 10:40:02 -0800
committerGitHub <noreply@github.com>2018-11-06 10:40:02 -0800
commit93de2c955cece02c4b67368d5210e79e5d9b3f5a (patch)
tree3af1d569ead569c157eee39f2091724f88ba6855 /contrib/loaders/flash/fespi/fespi.S
parent626df7d04bfe31edaf854e980b3d112d07b4d8fb (diff)
downloadriscv-openocd-93de2c955cece02c4b67368d5210e79e5d9b3f5a.zip
riscv-openocd-93de2c955cece02c4b67368d5210e79e5d9b3f5a.tar.gz
riscv-openocd-93de2c955cece02c4b67368d5210e79e5d9b3f5a.tar.bz2
Clean up fespi flashing code (#313)v20181030
* WIP upstream review feedback. See http://openocd.zylin.com/#/c/4656/ The main change is to get rid of macros that contain a return statement. Change-Id: Iff79a8aa7c40ee04a8d1f07d973f9b29d4899d5c * Remove unaligned head/tail code. From inspection it's not clear to me that this is necessary at all. I've been unable to make a test case that results in anything besides a 4-byte aligned flash to happen. Sections that aren't multiples of 4 are common, and appear to work fine. Change-Id: Idb6109ca015ae06b9d8f16bd883f9c8f5c51087d * Move fespi native code into contrib/loaders As suggested by http://openocd.zylin.com/#/c/4656/ Change-Id: I275012aa8a1ef6a0e8a2ec8ebe8643d87de24407 * Reenable hw mode if errors happen without it. Change-Id: I1220033c13d02e8a441992bd6daa0ec3b5acbfca * Default flash to not protected. Requested by upstream review. Change-Id: I61753bd9909d7f21ef6624037a865072c18bd1d8
Diffstat (limited to 'contrib/loaders/flash/fespi/fespi.S')
-rw-r--r--contrib/loaders/flash/fespi/fespi.S99
1 files changed, 99 insertions, 0 deletions
diff --git a/contrib/loaders/flash/fespi/fespi.S b/contrib/loaders/flash/fespi/fespi.S
new file mode 100644
index 0000000..d68e65e
--- /dev/null
+++ b/contrib/loaders/flash/fespi/fespi.S
@@ -0,0 +1,99 @@
+#define SPIFLASH_READ_STATUS 0x05 // Read Status Register
+#define SPIFLASH_BSY_BIT 0x00000001 // WIP Bit of SPI SR on SMI SR
+
+// Register offsets
+#define FESPI_REG_FMT 0x40
+#define FESPI_REG_TXFIFO 0x48
+#define FESPI_REG_RXFIFO 0x4c
+#define FESPI_REG_IP 0x74
+
+// Fields
+#define FESPI_IP_TXWM 0x1
+#define FESPI_FMT_DIR(x) (((x) & 0x1) << 3)
+
+// To enter, jump to the start of command_table (ie. offset 0).
+// a0 - FESPI base address
+// a1 - start address of buffer
+
+// The buffer contains a "program" in byte sequences. The first byte in a
+// sequence determines the operation. Some operation will read more data from
+// the program, while some will not. The operation byte is the offset into
+// command_table, so eg. 4 means exit, 8 means transmit, and so on.
+
+ .global _start
+_start:
+command_table:
+ j main // 0
+ ebreak // 4
+ j tx // 8
+ j txwm_wait // 12
+ j write_reg // 16
+ j wip_wait // 20
+ j set_dir // 24
+
+// Execute the program.
+main:
+ lbu t0, 0(a1)
+ addi a1, a1, 1
+ la t1, command_table
+ add t0, t0, t1
+ jr t0
+
+// Read 1 byte the contains the number of bytes to transmit. Then read those
+// bytes from the program and transmit them one by one.
+tx:
+ lbu t1, 0(a1) // read number of bytes to transmit
+ addi a1, a1, 1
+1: lw t0, FESPI_REG_TXFIFO(a0) // wait for FIFO clear
+ bltz t0, 1b
+ lbu t0, 0(a1) // Load byte to write
+ sw t0, FESPI_REG_TXFIFO(a0)
+ addi a1, a1, 1
+ addi t1, t1, -1
+ bgtz t1, 1b
+ j main
+
+// Wait until TXWM is set.
+txwm_wait:
+1: lw t0, FESPI_REG_IP(a0)
+ andi t0, t0, FESPI_IP_TXWM
+ beqz t0, 1b
+ j main
+
+// Read 1 byte that contains the offset of the register to write, and 1 byte
+// that contains the data to write.
+write_reg:
+ lbu t0, 0(a1) // read register to write
+ add t0, t0, a0
+ lbu t1, 1(a1) // read value to write
+ addi a1, a1, 2
+ sw t1, 0(t0)
+ j main
+
+wip_wait:
+ li a2, SPIFLASH_READ_STATUS
+ jal txrx_byte
+ // discard first result
+1: li a2, 0
+ jal txrx_byte
+ andi t0, a2, SPIFLASH_BSY_BIT
+ bnez t0, 1b
+ j main
+
+txrx_byte: // transmit the byte in a2, receive a bit into a2
+ lw t0, FESPI_REG_TXFIFO(a0) // wait for FIFO clear
+ bltz t0, txrx_byte
+ sw a2, FESPI_REG_TXFIFO(a0)
+1: lw a2, FESPI_REG_RXFIFO(a0)
+ bltz a2, 1b
+ ret
+
+set_dir:
+ lw t0, FESPI_REG_FMT(a0)
+ li t1, ~(FESPI_FMT_DIR(0xFFFFFFFF))
+ and t0, t0, t1
+ lbu t1, 0(a1) // read value to OR in
+ addi a1, a1, 1
+ or t0, t0, t1
+ sw t0, FESPI_REG_FMT(a0)
+ j main