flash/nor/fespi: algorithm, large address, errors

* Move more smarts into the target algorithm code, and rewrite that in C
  so it's easier to understand/maintain.
* Support >24-bit addresses.
* Check for errors.

Change-Id: I3b1a143589fe6defafb8f95820aa682acc9646e7
Signed-off-by: Tim Newsome <tim@sifive.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6679
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
Tim Newsome 2021-11-08 09:26:51 -08:00 committed by Antonio Borneo
parent 15110b2b5b
commit 35f284fe7c
9 changed files with 644 additions and 450 deletions

View File

@ -2,27 +2,50 @@ BIN2C = ../../../../src/helper/bin2char.sh
CROSS_COMPILE ?= riscv64-unknown-elf-
CC=$(CROSS_COMPILE)gcc
OBJCOPY=$(CROSS_COMPILE)objcopy
OBJDUMP=$(CROSS_COMPILE)objdump
RISCV_CC=$(CROSS_COMPILE)gcc
RISCV_OBJCOPY=$(CROSS_COMPILE)objcopy
RISCV_OBJDUMP=$(CROSS_COMPILE)objdump
CFLAGS = -march=rv32i -mabi=ilp32 -x assembler-with-cpp -nostdlib -nostartfiles
CFLAGS = -nostdlib -nostartfiles -Wall -Werror -Os -fPIC -Wunused-result -g
RISCV32_CFLAGS = -march=rv32e -mabi=ilp32e $(CFLAGS)
RISCV64_CFLAGS = -march=rv64i -mabi=lp64 $(CFLAGS)
all: fespi.inc
all: riscv32_fespi.inc riscv64_fespi.inc
.PHONY: clean
%.elf: %.S
$(CC) $(CFLAGS) $< -o $@
# .c -> .o
riscv32_%.o: riscv_%.c
$(RISCV_CC) -c $(RISCV32_CFLAGS) $^ -o $@
%.lst: %.elf
$(OBJDUMP) -S $< > $@
riscv64_%.o: riscv_%.c
$(RISCV_CC) -c $(RISCV64_CFLAGS) $< -o $@
# .S -> .o
riscv32_%.o: riscv_%.S
$(RISCV_CC) -c $(RISCV32_CFLAGS) $^ -o $@
riscv64_%.o: riscv_%.S
$(RISCV_CC) -c $(RISCV64_CFLAGS) $^ -o $@
# .o -> .elf
riscv32_%.elf: riscv32_%.o riscv32_wrapper.o
$(RISCV_CC) -T riscv.lds $(RISCV32_CFLAGS) $^ -o $@
riscv64_%.elf: riscv64_%.o riscv64_wrapper.o
$(RISCV_CC) -T riscv.lds $(RISCV64_CFLAGS) $^ -o $@
# .elf -> .bin
%.bin: %.elf
$(OBJCOPY) -Obinary $< $@
$(RISCV_OBJCOPY) -Obinary $< $@
# .bin -> .inc
%.inc: %.bin
$(BIN2C) < $< > $@
# utility
%.lst: %.elf
$(RISCV_OBJDUMP) -S $< > $@
clean:
-rm -f *.elf *.lst *.bin *.inc
-rm -f *.elf *.o *.lst *.bin *.inc

View File

@ -1,99 +0,0 @@
#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

View File

@ -1,15 +0,0 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x6f,0x00,0xc0,0x01,0x73,0x00,0x10,0x00,0x6f,0x00,0xc0,0x02,0x6f,0x00,0x00,0x05,
0x6f,0x00,0xc0,0x05,0x6f,0x00,0x00,0x07,0x6f,0x00,0x00,0x0a,0x83,0xc2,0x05,0x00,
0x93,0x85,0x15,0x00,0x17,0x03,0x00,0x00,0x13,0x03,0xc3,0xfd,0xb3,0x82,0x62,0x00,
0x67,0x80,0x02,0x00,0x03,0xc3,0x05,0x00,0x93,0x85,0x15,0x00,0x83,0x22,0x85,0x04,
0xe3,0xce,0x02,0xfe,0x83,0xc2,0x05,0x00,0x23,0x24,0x55,0x04,0x93,0x85,0x15,0x00,
0x13,0x03,0xf3,0xff,0xe3,0x44,0x60,0xfe,0x6f,0xf0,0x5f,0xfc,0x83,0x22,0x45,0x07,
0x93,0xf2,0x12,0x00,0xe3,0x8c,0x02,0xfe,0x6f,0xf0,0x5f,0xfb,0x83,0xc2,0x05,0x00,
0xb3,0x82,0xa2,0x00,0x03,0xc3,0x15,0x00,0x93,0x85,0x25,0x00,0x23,0xa0,0x62,0x00,
0x6f,0xf0,0xdf,0xf9,0x13,0x06,0x50,0x00,0xef,0x00,0x80,0x01,0x13,0x06,0x00,0x00,
0xef,0x00,0x00,0x01,0x93,0x72,0x16,0x00,0xe3,0x9a,0x02,0xfe,0x6f,0xf0,0x1f,0xf8,
0x83,0x22,0x85,0x04,0xe3,0xce,0x02,0xfe,0x23,0x24,0xc5,0x04,0x03,0x26,0xc5,0x04,
0xe3,0x4e,0x06,0xfe,0x67,0x80,0x00,0x00,0x83,0x22,0x05,0x04,0x13,0x03,0x70,0xff,
0xb3,0xf2,0x62,0x00,0x03,0xc3,0x05,0x00,0x93,0x85,0x15,0x00,0xb3,0xe2,0x62,0x00,
0x23,0x20,0x55,0x04,0x6f,0xf0,0x9f,0xf4,

View File

@ -0,0 +1,12 @@
OUTPUT_ARCH( "riscv" )
SECTIONS
{
. = 0x12340000;
.text :
{
*(.text.entry)
*(.text)
}
.data : { *(.data) }
}

View File

@ -0,0 +1,51 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x17,0x01,0x00,0x00,0x13,0x01,0xc1,0x31,0xef,0x00,0x80,0x10,0x73,0x00,0x10,0x00,
0x93,0x07,0x90,0x3e,0x93,0x87,0xf7,0xff,0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00,
0x67,0x80,0x00,0x00,0x03,0x27,0x45,0x07,0x13,0x77,0x17,0x00,0xe3,0x04,0x07,0xfe,
0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x93,0x07,0x90,0x3e,0x93,0x87,0xf7,0xff,
0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00,0x67,0x80,0x00,0x00,0x03,0x27,0x85,0x04,
0xe3,0x46,0x07,0xfe,0x23,0x24,0xb5,0x04,0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,
0x83,0x27,0x05,0x04,0x13,0x01,0x41,0xff,0x23,0x22,0x81,0x00,0x23,0x24,0x11,0x00,
0x23,0x20,0x91,0x00,0x93,0xf7,0x77,0xff,0x23,0x20,0xf5,0x04,0x93,0x07,0x20,0x00,
0x23,0x2c,0xf5,0x00,0x93,0x05,0x50,0x00,0x13,0x04,0x05,0x00,0xef,0xf0,0xdf,0xfa,
0x93,0x07,0x90,0x3e,0x63,0x00,0x05,0x02,0x83,0x20,0x81,0x00,0x03,0x24,0x41,0x00,
0x83,0x24,0x01,0x00,0x13,0x01,0xc1,0x00,0x67,0x80,0x00,0x00,0x03,0x27,0xc4,0x04,
0x63,0x5a,0x07,0x00,0x93,0x87,0xf7,0xff,0xe3,0x9a,0x07,0xfe,0x13,0x05,0x10,0x00,
0x6f,0xf0,0x9f,0xfd,0x93,0x04,0x90,0x3e,0x93,0x84,0xf4,0xff,0xe3,0x88,0x04,0xfe,
0x93,0x05,0x00,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xf6,0xe3,0x1e,0x05,0xfa,
0x13,0x07,0x90,0x3e,0x13,0x07,0xf7,0xff,0xe3,0x0a,0x07,0xfc,0x83,0x27,0xc4,0x04,
0xe3,0xca,0x07,0xfe,0x93,0xf7,0x17,0x00,0xe3,0x98,0x07,0xfc,0x23,0x2c,0x04,0x00,
0x83,0x27,0x04,0x04,0x93,0xe7,0x87,0x00,0x23,0x20,0xf4,0x04,0x6f,0xf0,0xdf,0xf8,
0x13,0x01,0x41,0xfd,0x23,0x22,0x81,0x02,0x23,0x20,0x91,0x02,0x23,0x24,0x11,0x02,
0x13,0x04,0x05,0x00,0x23,0x26,0xb1,0x00,0x23,0x28,0xc1,0x00,0x23,0x20,0xd1,0x00,
0x23,0x22,0xe1,0x00,0x23,0x2a,0xf1,0x00,0xef,0xf0,0x9f,0xed,0x93,0x04,0x05,0x00,
0x63,0x16,0x05,0x04,0x83,0x27,0x04,0x06,0x13,0x05,0x04,0x00,0x93,0xf7,0xe7,0xff,
0x23,0x20,0xf4,0x06,0xef,0xf0,0xdf,0xf0,0x93,0x04,0x05,0x00,0x63,0x12,0x05,0x02,
0x83,0x27,0xc1,0x00,0x03,0x27,0x01,0x00,0x93,0x87,0xf7,0xff,0xb3,0xf7,0xe7,0x00,
0x03,0x47,0x41,0x01,0x23,0x2c,0xe1,0x00,0x03,0x27,0x41,0x00,0x63,0x14,0x07,0x02,
0x83,0x27,0x04,0x06,0x93,0xe7,0x17,0x00,0x23,0x20,0xf4,0x06,0x83,0x20,0x81,0x02,
0x03,0x24,0x41,0x02,0x13,0x85,0x04,0x00,0x83,0x24,0x01,0x02,0x13,0x01,0xc1,0x02,
0x67,0x80,0x00,0x00,0x83,0x26,0x41,0x00,0x03,0x27,0x41,0x00,0x23,0x24,0xd1,0x00,
0x83,0x26,0xc1,0x00,0x33,0x07,0xf7,0x00,0x63,0xf6,0xe6,0x00,0xb3,0x87,0xf6,0x40,
0x23,0x24,0xf1,0x00,0x93,0x05,0x60,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xe6,
0x63,0x1e,0x05,0x0c,0x13,0x05,0x04,0x00,0xef,0xf0,0x9f,0xe3,0x63,0x18,0x05,0x0c,
0x83,0x25,0x81,0x01,0x93,0x07,0x20,0x00,0x23,0x2c,0xf4,0x00,0x13,0x05,0x04,0x00,
0xef,0xf0,0x9f,0xe4,0x63,0x1c,0x05,0x0a,0x83,0x27,0x41,0x01,0x93,0xf7,0x07,0x10,
0x63,0x9c,0x07,0x08,0x83,0x27,0x01,0x00,0x13,0x05,0x04,0x00,0x93,0xd5,0x07,0x01,
0x93,0xf5,0xf5,0x0f,0xef,0xf0,0x5f,0xe2,0x63,0x1a,0x05,0x08,0x83,0x27,0x01,0x00,
0x13,0x05,0x04,0x00,0x93,0xd5,0x87,0x00,0x93,0xf5,0xf5,0x0f,0xef,0xf0,0xdf,0xe0,
0x63,0x1e,0x05,0x06,0x83,0x45,0x01,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xdf,
0x63,0x16,0x05,0x06,0x03,0x26,0x01,0x01,0x83,0x27,0x81,0x00,0xb3,0x07,0xf6,0x00,
0x63,0x12,0xf6,0x06,0x13,0x05,0x04,0x00,0x23,0x28,0xc1,0x00,0xef,0xf0,0x5f,0xdb,
0x63,0x16,0x05,0x04,0x23,0x2c,0x04,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xdf,
0x63,0x1e,0x05,0x02,0x83,0x27,0x01,0x00,0x03,0x27,0x81,0x00,0xb3,0x87,0xe7,0x00,
0x23,0x20,0xf1,0x00,0x83,0x27,0x41,0x00,0xb3,0x87,0xe7,0x40,0x23,0x22,0xf1,0x00,
0x93,0x07,0x00,0x00,0x6f,0xf0,0x5f,0xee,0x83,0x27,0x01,0x00,0x13,0x05,0x04,0x00,
0x93,0xd5,0x87,0x01,0xef,0xf0,0x5f,0xd9,0xe3,0x0e,0x05,0xf4,0x93,0x04,0x05,0x00,
0x6f,0xf0,0x1f,0xed,0x83,0x45,0x06,0x00,0x13,0x05,0x04,0x00,0x23,0x2e,0xf1,0x00,
0x23,0x28,0xc1,0x00,0xef,0xf0,0x5f,0xd7,0x03,0x26,0x01,0x01,0x83,0x27,0xc1,0x01,
0x13,0x06,0x16,0x00,0xe3,0x0e,0x05,0xf6,0x6f,0xf0,0x5f,0xfd,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,

View File

@ -0,0 +1,58 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x17,0x01,0x00,0x00,0x13,0x01,0x81,0x38,0xef,0x00,0x40,0x12,0x73,0x00,0x10,0x00,
0x93,0x07,0x90,0x3e,0x9b,0x87,0xf7,0xff,0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00,
0x67,0x80,0x00,0x00,0x03,0x27,0x45,0x07,0x13,0x77,0x17,0x00,0xe3,0x04,0x07,0xfe,
0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x93,0x07,0x90,0x3e,0x9b,0x87,0xf7,0xff,
0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00,0x67,0x80,0x00,0x00,0x03,0x27,0x85,0x04,
0x93,0x16,0x07,0x02,0xe3,0xc4,0x06,0xfe,0x9b,0x85,0x05,0x00,0x23,0x24,0xb5,0x04,
0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x83,0x27,0x05,0x04,0x13,0x01,0x01,0xfe,
0x23,0x38,0x81,0x00,0x9b,0x87,0x07,0x00,0x23,0x3c,0x11,0x00,0x23,0x34,0x91,0x00,
0x93,0xf7,0x77,0xff,0x23,0x20,0xf5,0x04,0x93,0x07,0x20,0x00,0x23,0x2c,0xf5,0x00,
0x93,0x05,0x50,0x00,0x13,0x04,0x05,0x00,0xef,0xf0,0x1f,0xfa,0x93,0x07,0x90,0x3e,
0x63,0x02,0x05,0x02,0x83,0x30,0x81,0x01,0x03,0x34,0x01,0x01,0x83,0x34,0x81,0x00,
0x13,0x01,0x01,0x02,0x67,0x80,0x00,0x00,0x03,0x27,0xc4,0x04,0x93,0x16,0x07,0x02,
0x63,0xda,0x06,0x00,0x9b,0x87,0xf7,0xff,0xe3,0x98,0x07,0xfe,0x13,0x05,0x10,0x00,
0x6f,0xf0,0x5f,0xfd,0x93,0x04,0x90,0x3e,0x9b,0x84,0xf4,0xff,0xe3,0x88,0x04,0xfe,
0x93,0x05,0x00,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xf5,0xe3,0x1c,0x05,0xfa,
0x93,0x07,0x90,0x3e,0x9b,0x87,0xf7,0xff,0xe3,0x8a,0x07,0xfc,0x83,0x26,0xc4,0x04,
0x13,0x96,0x06,0x02,0x1b,0x87,0x06,0x00,0xe3,0x46,0x06,0xfe,0x93,0x77,0x17,0x00,
0xe3,0x94,0x07,0xfc,0x23,0x2c,0x04,0x00,0x83,0x27,0x04,0x04,0x9b,0x87,0x07,0x00,
0x93,0xe7,0x87,0x00,0x23,0x20,0xf4,0x04,0x6f,0xf0,0xdf,0xf7,0x13,0x01,0x01,0xfa,
0x23,0x38,0x81,0x04,0x23,0x34,0x91,0x04,0x23,0x30,0x21,0x05,0x23,0x3c,0x31,0x03,
0x23,0x38,0x41,0x03,0x23,0x34,0x51,0x03,0x23,0x30,0x61,0x03,0x23,0x3c,0x11,0x04,
0x23,0x3c,0x71,0x01,0x23,0x38,0x81,0x01,0x23,0x34,0x91,0x01,0x23,0x30,0xa1,0x01,
0x13,0x04,0x05,0x00,0x93,0x8a,0x05,0x00,0x13,0x0b,0x06,0x00,0x13,0x89,0x06,0x00,
0x13,0x0a,0x07,0x00,0x93,0x89,0x07,0x00,0xef,0xf0,0x9f,0xe9,0x93,0x04,0x05,0x00,
0x63,0x1a,0x05,0x04,0x83,0x27,0x04,0x06,0x13,0x05,0x04,0x00,0x9b,0x87,0x07,0x00,
0x93,0xf7,0xe7,0xff,0x23,0x20,0xf4,0x06,0xef,0xf0,0x1f,0xed,0x93,0x04,0x05,0x00,
0x63,0x12,0x05,0x02,0x9b,0x86,0xfa,0xff,0xb3,0x76,0xd9,0x00,0x93,0xfc,0xf9,0x0f,
0x93,0xf9,0x09,0x10,0x9b,0x86,0x06,0x00,0x13,0x0c,0x20,0x00,0x9b,0x89,0x09,0x00,
0x63,0x18,0x0a,0x04,0x83,0x27,0x04,0x06,0x9b,0x87,0x07,0x00,0x93,0xe7,0x17,0x00,
0x23,0x20,0xf4,0x06,0x83,0x30,0x81,0x05,0x03,0x34,0x01,0x05,0x03,0x39,0x01,0x04,
0x83,0x39,0x81,0x03,0x03,0x3a,0x01,0x03,0x83,0x3a,0x81,0x02,0x03,0x3b,0x01,0x02,
0x83,0x3b,0x81,0x01,0x03,0x3c,0x01,0x01,0x83,0x3c,0x81,0x00,0x03,0x3d,0x01,0x00,
0x13,0x85,0x04,0x00,0x83,0x34,0x81,0x04,0x13,0x01,0x01,0x06,0x67,0x80,0x00,0x00,
0xbb,0x07,0xda,0x00,0x93,0x0b,0x0a,0x00,0x63,0xf4,0xfa,0x00,0xbb,0x8b,0xda,0x40,
0x93,0x05,0x60,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xe1,0x63,0x1a,0x05,0x0a,
0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xdd,0x63,0x14,0x05,0x0a,0x23,0x2c,0x84,0x01,
0x93,0x85,0x0c,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xdf,0x63,0x1a,0x05,0x08,
0x63,0x90,0x09,0x08,0x9b,0x55,0x09,0x01,0x93,0xf5,0xf5,0x0f,0x13,0x05,0x04,0x00,
0xef,0xf0,0x9f,0xdd,0x63,0x1e,0x05,0x06,0x9b,0x55,0x89,0x00,0x93,0xf5,0xf5,0x0f,
0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xdc,0x63,0x14,0x05,0x06,0x93,0x75,0xf9,0x0f,
0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xdb,0x63,0x1c,0x05,0x04,0x13,0x0d,0x00,0x00,
0x9b,0x07,0x0d,0x00,0x63,0xea,0x77,0x05,0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xd7,
0x63,0x10,0x05,0x04,0x23,0x2c,0x04,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xdb,
0x63,0x18,0x05,0x02,0x93,0x97,0x0b,0x02,0x93,0xd7,0x07,0x02,0x33,0x0b,0xfb,0x00,
0x3b,0x09,0x79,0x01,0x3b,0x0a,0x7a,0x41,0x93,0x06,0x00,0x00,0x6f,0xf0,0x5f,0xef,
0x9b,0x55,0x89,0x01,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xd6,0xe3,0x0c,0x05,0xf6,
0x93,0x04,0x05,0x00,0x6f,0xf0,0x1f,0xee,0xb3,0x07,0xab,0x01,0x83,0xc5,0x07,0x00,
0x13,0x05,0x04,0x00,0x13,0x0d,0x1d,0x00,0xef,0xf0,0x1f,0xd4,0xe3,0x0a,0x05,0xf8,
0x6f,0xf0,0x1f,0xfe,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,321 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "../../../../src/flash/nor/spi.h"
/* Register offsets */
#define FESPI_REG_SCKDIV 0x00
#define FESPI_REG_SCKMODE 0x04
#define FESPI_REG_CSID 0x10
#define FESPI_REG_CSDEF 0x14
#define FESPI_REG_CSMODE 0x18
#define FESPI_REG_DCSSCK 0x28
#define FESPI_REG_DSCKCS 0x2a
#define FESPI_REG_DINTERCS 0x2c
#define FESPI_REG_DINTERXFR 0x2e
#define FESPI_REG_FMT 0x40
#define FESPI_REG_TXFIFO 0x48
#define FESPI_REG_RXFIFO 0x4c
#define FESPI_REG_TXCTRL 0x50
#define FESPI_REG_RXCTRL 0x54
#define FESPI_REG_FCTRL 0x60
#define FESPI_REG_FFMT 0x64
#define FESPI_REG_IE 0x70
#define FESPI_REG_IP 0x74
/* Fields */
#define FESPI_SCK_POL 0x1
#define FESPI_SCK_PHA 0x2
#define FESPI_FMT_PROTO(x) ((x) & 0x3)
#define FESPI_FMT_ENDIAN(x) (((x) & 0x1) << 2)
#define FESPI_FMT_DIR(x) (((x) & 0x1) << 3)
#define FESPI_FMT_LEN(x) (((x) & 0xf) << 16)
/* TXCTRL register */
#define FESPI_TXWM(x) ((x) & 0xffff)
/* RXCTRL register */
#define FESPI_RXWM(x) ((x) & 0xffff)
#define FESPI_IP_TXWM 0x1
#define FESPI_IP_RXWM 0x2
#define FESPI_FCTRL_EN 0x1
#define FESPI_INSN_CMD_EN 0x1
#define FESPI_INSN_ADDR_LEN(x) (((x) & 0x7) << 1)
#define FESPI_INSN_PAD_CNT(x) (((x) & 0xf) << 4)
#define FESPI_INSN_CMD_PROTO(x) (((x) & 0x3) << 8)
#define FESPI_INSN_ADDR_PROTO(x) (((x) & 0x3) << 10)
#define FESPI_INSN_DATA_PROTO(x) (((x) & 0x3) << 12)
#define FESPI_INSN_CMD_CODE(x) (((x) & 0xff) << 16)
#define FESPI_INSN_PAD_CODE(x) (((x) & 0xff) << 24)
/* Values */
#define FESPI_CSMODE_AUTO 0
#define FESPI_CSMODE_HOLD 2
#define FESPI_CSMODE_OFF 3
#define FESPI_DIR_RX 0
#define FESPI_DIR_TX 1
#define FESPI_PROTO_S 0
#define FESPI_PROTO_D 1
#define FESPI_PROTO_Q 2
#define FESPI_ENDIAN_MSB 0
#define FESPI_ENDIAN_LSB 1
/* Timeouts we use, in number of status checks. */
#define TIMEOUT 1000
/* #define DEBUG to make the return error codes provide enough information to
* reconstruct the stack from where the error occurred. This is not enabled
* usually to reduce the program size. */
#ifdef DEBUG
#define ERROR_STACK(x) (x)
#define ERROR_FESPI_TXWM_WAIT 0x10
#define ERROR_FESPI_TX 0x100
#define ERROR_FESPI_RX 0x1000
#define ERROR_FESPI_WIP 0x50000
#else
#define ERROR_STACK(x) 0
#define ERROR_FESPI_TXWM_WAIT 1
#define ERROR_FESPI_TX 1
#define ERROR_FESPI_RX 1
#define ERROR_FESPI_WIP 1
#endif
#define ERROR_OK 0
static int fespi_txwm_wait(volatile uint32_t *ctrl_base);
static void fespi_disable_hw_mode(volatile uint32_t *ctrl_base);
static void fespi_enable_hw_mode(volatile uint32_t *ctrl_base);
static int fespi_wip(volatile uint32_t *ctrl_base);
static int fespi_write_buffer(volatile uint32_t *ctrl_base,
const uint8_t *buffer, unsigned offset, unsigned len,
uint32_t flash_info);
/* Can set bits 3:0 in result. */
/* flash_info contains:
* bits 7:0 -- pprog_cmd
* bit 8 -- 0 means send 3 bytes after pprog_cmd, 1 means send 4 bytes
* after pprog_cmd
*/
int flash_fespi(volatile uint32_t *ctrl_base, uint32_t page_size,
const uint8_t *buffer, unsigned offset, uint32_t count,
uint32_t flash_info)
{
int result;
result = fespi_txwm_wait(ctrl_base);
if (result != ERROR_OK)
return result | ERROR_STACK(0x1);
/* Disable Hardware accesses*/
fespi_disable_hw_mode(ctrl_base);
/* poll WIP */
result = fespi_wip(ctrl_base);
if (result != ERROR_OK) {
result |= ERROR_STACK(0x2);
goto err;
}
/* Assume page_size is a power of two so we don't need the modulus code. */
uint32_t page_offset = offset & (page_size - 1);
/* central part, aligned words */
while (count > 0) {
uint32_t cur_count;
/* clip block at page boundary */
if (page_offset + count > page_size)
cur_count = page_size - page_offset;
else
cur_count = count;
result = fespi_write_buffer(ctrl_base, buffer, offset, cur_count, flash_info);
if (result != ERROR_OK) {
result |= ERROR_STACK(0x3);
goto err;
}
page_offset = 0;
buffer += cur_count;
offset += cur_count;
count -= cur_count;
}
err:
/* Switch to HW mode before return to prompt */
fespi_enable_hw_mode(ctrl_base);
return result;
}
static uint32_t fespi_read_reg(volatile uint32_t *ctrl_base, unsigned address)
{
return ctrl_base[address / 4];
}
static void fespi_write_reg(volatile uint32_t *ctrl_base, unsigned address, uint32_t value)
{
ctrl_base[address / 4] = value;
}
static void fespi_disable_hw_mode(volatile uint32_t *ctrl_base)
{
uint32_t fctrl = fespi_read_reg(ctrl_base, FESPI_REG_FCTRL);
fespi_write_reg(ctrl_base, FESPI_REG_FCTRL, fctrl & ~FESPI_FCTRL_EN);
}
static void fespi_enable_hw_mode(volatile uint32_t *ctrl_base)
{
uint32_t fctrl = fespi_read_reg(ctrl_base, FESPI_REG_FCTRL);
fespi_write_reg(ctrl_base, FESPI_REG_FCTRL, fctrl | FESPI_FCTRL_EN);
}
/* Can set bits 7:4 in result. */
static int fespi_txwm_wait(volatile uint32_t *ctrl_base)
{
unsigned timeout = TIMEOUT;
while (timeout--) {
uint32_t ip = fespi_read_reg(ctrl_base, FESPI_REG_IP);
if (ip & FESPI_IP_TXWM)
return ERROR_OK;
}
return ERROR_FESPI_TXWM_WAIT;
}
static void fespi_set_dir(volatile uint32_t *ctrl_base, bool dir)
{
uint32_t fmt = fespi_read_reg(ctrl_base, FESPI_REG_FMT);
fespi_write_reg(ctrl_base, FESPI_REG_FMT,
(fmt & ~(FESPI_FMT_DIR(0xFFFFFFFF))) | FESPI_FMT_DIR(dir));
}
/* Can set bits 11:8 in result. */
static int fespi_tx(volatile uint32_t *ctrl_base, uint8_t in)
{
unsigned timeout = TIMEOUT;
while (timeout--) {
uint32_t txfifo = fespi_read_reg(ctrl_base, FESPI_REG_TXFIFO);
if (!(txfifo >> 31)) {
fespi_write_reg(ctrl_base, FESPI_REG_TXFIFO, in);
return ERROR_OK;
}
}
return ERROR_FESPI_TX;
}
/* Can set bits 15:12 in result. */
static int fespi_rx(volatile uint32_t *ctrl_base, uint8_t *out)
{
unsigned timeout = TIMEOUT;
while (timeout--) {
uint32_t value = fespi_read_reg(ctrl_base, FESPI_REG_RXFIFO);
if (!(value >> 31)) {
if (out)
*out = value & 0xff;
return ERROR_OK;
}
}
return ERROR_FESPI_RX;
}
/* Can set bits 19:16 in result. */
static int fespi_wip(volatile uint32_t *ctrl_base)
{
fespi_set_dir(ctrl_base, FESPI_DIR_RX);
fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
int result = fespi_tx(ctrl_base, SPIFLASH_READ_STATUS);
if (result != ERROR_OK)
return result | ERROR_STACK(0x10000);
result = fespi_rx(ctrl_base, NULL);
if (result != ERROR_OK)
return result | ERROR_STACK(0x20000);
unsigned timeout = TIMEOUT;
while (timeout--) {
result = fespi_tx(ctrl_base, 0);
if (result != ERROR_OK)
return result | ERROR_STACK(0x30000);
uint8_t rx;
result = fespi_rx(ctrl_base, &rx);
if (result != ERROR_OK)
return result | ERROR_STACK(0x40000);
if ((rx & SPIFLASH_BSY_BIT) == 0) {
fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
fespi_set_dir(ctrl_base, FESPI_DIR_TX);
return ERROR_OK;
}
}
return ERROR_FESPI_WIP;
}
/* Can set bits 23:20 in result. */
static int fespi_write_buffer(volatile uint32_t *ctrl_base,
const uint8_t *buffer, unsigned offset, unsigned len,
uint32_t flash_info)
{
int result = fespi_tx(ctrl_base, SPIFLASH_WRITE_ENABLE);
if (result != ERROR_OK)
return result | ERROR_STACK(0x100000);
result = fespi_txwm_wait(ctrl_base);
if (result != ERROR_OK)
return result | ERROR_STACK(0x200000);
fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
result = fespi_tx(ctrl_base, flash_info & 0xff);
if (result != ERROR_OK)
return result | ERROR_STACK(0x300000);
if (flash_info & 0x100) {
result = fespi_tx(ctrl_base, offset >> 24);
if (result != ERROR_OK)
return result | ERROR_STACK(0x400000);
}
result = fespi_tx(ctrl_base, offset >> 16);
if (result != ERROR_OK)
return result | ERROR_STACK(0x400000);
result = fespi_tx(ctrl_base, offset >> 8);
if (result != ERROR_OK)
return result | ERROR_STACK(0x500000);
result = fespi_tx(ctrl_base, offset);
if (result != ERROR_OK)
return result | ERROR_STACK(0x600000);
for (unsigned i = 0; i < len; i++) {
result = fespi_tx(ctrl_base, buffer[i]);
if (result != ERROR_OK)
return result | ERROR_STACK(0x700000);
}
result = fespi_txwm_wait(ctrl_base);
if (result != ERROR_OK)
return result | ERROR_STACK(0x800000);
fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
result = fespi_wip(ctrl_base);
if (result != ERROR_OK)
return result | ERROR_STACK(0x900000);
return ERROR_OK;
}

View File

@ -0,0 +1,22 @@
#if __riscv_xlen == 64
# define LREG ld
# define SREG sd
# define REGBYTES 8
#else
# define LREG lw
# define SREG sw
# define REGBYTES 4
#endif
.section .text.entry
.global _start
_start:
lla sp, stack_end
jal flash_fespi
ebreak
.section .data
.balign REGBYTES
stack:
.fill 16, REGBYTES, 0x8675309
stack_end:

View File

@ -337,6 +337,11 @@ static int fespi_erase_sector(struct flash_bank *bank, int sector)
if (retval != ERROR_OK)
return retval;
sector = bank->sectors[sector].offset;
if (bank->size > 0x1000000) {
retval = fespi_tx(bank, sector >> 24);
if (retval != ERROR_OK)
return retval;
}
retval = fespi_tx(bank, sector >> 16);
if (retval != ERROR_OK)
return retval;
@ -435,32 +440,38 @@ static int fespi_protect(struct flash_bank *bank, int set,
static int slow_fespi_write_buffer(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t len)
{
struct fespi_flash_bank *fespi_info = bank->driver_priv;
uint32_t ii;
if (offset & 0xFF000000) {
LOG_ERROR("FESPI interface does not support greater than 3B addressing, can't write to offset 0x%" PRIx32,
offset);
return ERROR_FAIL;
}
/* TODO!!! assert that len < page size */
fespi_tx(bank, SPIFLASH_WRITE_ENABLE);
fespi_txwm_wait(bank);
if (fespi_tx(bank, SPIFLASH_WRITE_ENABLE) != ERROR_OK)
return ERROR_FAIL;
if (fespi_txwm_wait(bank) != ERROR_OK)
return ERROR_FAIL;
if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD) != ERROR_OK)
return ERROR_FAIL;
fespi_tx(bank, SPIFLASH_PAGE_PROGRAM);
if (fespi_tx(bank, fespi_info->dev->pprog_cmd) != ERROR_OK)
return ERROR_FAIL;
fespi_tx(bank, offset >> 16);
fespi_tx(bank, offset >> 8);
fespi_tx(bank, offset);
if (bank->size > 0x1000000 && fespi_tx(bank, offset >> 24) != ERROR_OK)
return ERROR_FAIL;
if (fespi_tx(bank, offset >> 16) != ERROR_OK)
return ERROR_FAIL;
if (fespi_tx(bank, offset >> 8) != ERROR_OK)
return ERROR_FAIL;
if (fespi_tx(bank, offset) != ERROR_OK)
return ERROR_FAIL;
for (ii = 0; ii < len; ii++)
fespi_tx(bank, buffer[ii]);
for (ii = 0; ii < len; ii++) {
if (fespi_tx(bank, buffer[ii]) != ERROR_OK)
return ERROR_FAIL;
}
fespi_txwm_wait(bank);
if (fespi_txwm_wait(bank) != ERROR_OK)
return ERROR_FAIL;
if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO) != ERROR_OK)
return ERROR_FAIL;
@ -470,273 +481,24 @@ static int slow_fespi_write_buffer(struct flash_bank *bank,
return ERROR_OK;
}
static const uint8_t algorithm_bin[] = {
#include "../../../contrib/loaders/flash/fespi/fespi.inc"
};
#define STEP_EXIT 4
#define STEP_TX 8
#define STEP_TXWM_WAIT 12
#define STEP_WRITE_REG 16
#define STEP_WIP_WAIT 20
#define STEP_SET_DIR 24
#define STEP_NOP 0xff
struct algorithm_steps {
unsigned size;
unsigned used;
uint8_t **steps;
static const uint8_t riscv32_bin[] = {
#include "../../../contrib/loaders/flash/fespi/riscv32_fespi.inc"
};
static struct algorithm_steps *as_new(void)
{
struct algorithm_steps *as = calloc(1, sizeof(struct algorithm_steps));
as->size = 8;
as->steps = malloc(as->size * sizeof(as->steps[0]));
return as;
}
static struct algorithm_steps *as_delete(struct algorithm_steps *as)
{
for (unsigned step = 0; step < as->used; step++) {
free(as->steps[step]);
as->steps[step] = NULL;
}
free(as->steps);
free(as);
return NULL;
}
static int as_empty(struct algorithm_steps *as)
{
for (unsigned s = 0; s < as->used; s++) {
if (as->steps[s][0] != STEP_NOP)
return 0;
}
return 1;
}
/* Return size of compiled program. */
static unsigned as_compile(struct algorithm_steps *as, uint8_t *target,
unsigned target_size)
{
unsigned offset = 0;
bool finish_early = false;
for (unsigned s = 0; s < as->used && !finish_early; s++) {
unsigned bytes_left = target_size - offset;
switch (as->steps[s][0]) {
case STEP_NOP:
break;
case STEP_TX:
{
unsigned size = as->steps[s][1];
if (size + 3 > bytes_left) {
finish_early = true;
break;
}
memcpy(target + offset, as->steps[s], size + 2);
offset += size + 2;
break;
}
case STEP_WRITE_REG:
if (bytes_left < 4) {
finish_early = true;
break;
}
memcpy(target + offset, as->steps[s], 3);
offset += 3;
break;
case STEP_SET_DIR:
if (bytes_left < 3) {
finish_early = true;
break;
}
memcpy(target + offset, as->steps[s], 2);
offset += 2;
break;
case STEP_TXWM_WAIT:
case STEP_WIP_WAIT:
if (bytes_left < 2) {
finish_early = true;
break;
}
memcpy(target + offset, as->steps[s], 1);
offset += 1;
break;
default:
assert(0);
}
if (!finish_early)
as->steps[s][0] = STEP_NOP;
}
assert(offset + 1 <= target_size);
target[offset++] = STEP_EXIT;
LOG_DEBUG("%d-byte program:", offset);
for (unsigned i = 0; i < offset;) {
char buf[80];
for (unsigned x = 0; i < offset && x < 16; x++, i++)
sprintf(buf + x*3, "%02x ", target[i]);
LOG_DEBUG("%s", buf);
}
return offset;
}
static void as_add_step(struct algorithm_steps *as, uint8_t *step)
{
if (as->used == as->size) {
as->size *= 2;
as->steps = realloc(as->steps, sizeof(as->steps[0]) * as->size);
LOG_DEBUG("Increased size to 0x%x", as->size);
}
as->steps[as->used] = step;
as->used++;
}
static void as_add_tx(struct algorithm_steps *as, unsigned count, const uint8_t *data)
{
LOG_DEBUG("count=%d", count);
while (count > 0) {
unsigned step_count = MIN(count, 255);
uint8_t *step = malloc(step_count + 2);
step[0] = STEP_TX;
step[1] = step_count;
memcpy(step + 2, data, step_count);
as_add_step(as, step);
data += step_count;
count -= step_count;
}
}
static void as_add_tx1(struct algorithm_steps *as, uint8_t byte)
{
uint8_t data[1];
data[0] = byte;
as_add_tx(as, 1, data);
}
static void as_add_write_reg(struct algorithm_steps *as, uint8_t offset, uint8_t data)
{
uint8_t *step = malloc(3);
step[0] = STEP_WRITE_REG;
step[1] = offset;
step[2] = data;
as_add_step(as, step);
}
static void as_add_txwm_wait(struct algorithm_steps *as)
{
uint8_t *step = malloc(1);
step[0] = STEP_TXWM_WAIT;
as_add_step(as, step);
}
static void as_add_wip_wait(struct algorithm_steps *as)
{
uint8_t *step = malloc(1);
step[0] = STEP_WIP_WAIT;
as_add_step(as, step);
}
static void as_add_set_dir(struct algorithm_steps *as, bool dir)
{
uint8_t *step = malloc(2);
step[0] = STEP_SET_DIR;
step[1] = FESPI_FMT_DIR(dir);
as_add_step(as, step);
}
/* This should write something less than or equal to a page.*/
static int steps_add_buffer_write(struct algorithm_steps *as,
const uint8_t *buffer, uint32_t chip_offset, uint32_t len)
{
if (chip_offset & 0xFF000000) {
LOG_ERROR("FESPI interface does not support greater than 3B addressing, can't write to offset 0x%" PRIx32,
chip_offset);
return ERROR_FAIL;
}
as_add_tx1(as, SPIFLASH_WRITE_ENABLE);
as_add_txwm_wait(as);
as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
uint8_t setup[] = {
SPIFLASH_PAGE_PROGRAM,
chip_offset >> 16,
chip_offset >> 8,
chip_offset,
};
as_add_tx(as, sizeof(setup), setup);
as_add_tx(as, len, buffer);
as_add_txwm_wait(as);
as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
/* fespi_wip() */
as_add_set_dir(as, FESPI_DIR_RX);
as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
as_add_wip_wait(as);
as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
as_add_set_dir(as, FESPI_DIR_TX);
return ERROR_OK;
}
static int steps_execute(struct algorithm_steps *as,
struct flash_bank *bank, struct working_area *algorithm_wa,
struct working_area *data_wa)
{
struct target *target = bank->target;
struct fespi_flash_bank *fespi_info = bank->driver_priv;
uint32_t ctrl_base = fespi_info->ctrl_base;
int xlen = riscv_xlen(target);
struct reg_param reg_params[2];
init_reg_param(&reg_params[0], "a0", xlen, PARAM_OUT);
init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
buf_set_u64(reg_params[0].value, 0, xlen, ctrl_base);
buf_set_u64(reg_params[1].value, 0, xlen, data_wa->address);
int retval = ERROR_OK;
while (!as_empty(as)) {
keep_alive();
uint8_t *data_buf = malloc(data_wa->size);
unsigned bytes = as_compile(as, data_buf, data_wa->size);
retval = target_write_buffer(target, data_wa->address, bytes,
data_buf);
free(data_buf);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to write data to " TARGET_ADDR_FMT ": %d",
data_wa->address, retval);
goto exit;
}
retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
algorithm_wa->address, algorithm_wa->address + 4,
10000, NULL);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d",
algorithm_wa->address, retval);
goto exit;
}
}
exit:
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[0]);
return retval;
}
static const uint8_t riscv64_bin[] = {
#include "../../../contrib/loaders/flash/fespi/riscv64_fespi.inc"
};
static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
struct fespi_flash_bank *fespi_info = bank->driver_priv;
uint32_t cur_count, page_size, page_offset;
uint32_t cur_count, page_size;
int retval = ERROR_OK;
LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
__func__, offset, count);
LOG_DEBUG("bank->size=0x%x offset=0x%08" PRIx32 " count=0x%08" PRIx32,
bank->size, offset, count);
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@ -761,80 +523,142 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
}
}
struct working_area *algorithm_wa;
if (target_alloc_working_area(target, sizeof(algorithm_bin),
&algorithm_wa) != ERROR_OK) {
LOG_WARNING("Couldn't allocate %zd-byte working area.",
sizeof(algorithm_bin));
algorithm_wa = NULL;
unsigned int xlen = riscv_xlen(target);
struct working_area *algorithm_wa = NULL;
struct working_area *data_wa = NULL;
const uint8_t *bin;
size_t bin_size;
if (xlen == 32) {
bin = riscv32_bin;
bin_size = sizeof(riscv32_bin);
} else {
bin = riscv64_bin;
bin_size = sizeof(riscv64_bin);
}
unsigned data_wa_size = 0;
if (target_alloc_working_area(target, bin_size, &algorithm_wa) == ERROR_OK) {
retval = target_write_buffer(target, algorithm_wa->address,
sizeof(algorithm_bin), algorithm_bin);
bin_size, bin);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d",
algorithm_wa->address, retval);
target_free_working_area(target, algorithm_wa);
algorithm_wa = NULL;
}
}
struct working_area *data_wa = NULL;
unsigned data_wa_size = 2 * count;
while (1) {
if (data_wa_size < 128) {
LOG_WARNING("Couldn't allocate data working area.");
target_free_working_area(target, algorithm_wa);
algorithm_wa = NULL;
} else {
data_wa_size = MIN(target_get_working_area_avail(target), count);
if (data_wa_size < 128) {
LOG_WARNING("Couldn't allocate data working area.");
target_free_working_area(target, algorithm_wa);
algorithm_wa = NULL;
} else if (target_alloc_working_area(target, data_wa_size, &data_wa) != ERROR_OK) {
target_free_working_area(target, algorithm_wa);
algorithm_wa = NULL;
}
}
if (target_alloc_working_area_try(target, data_wa_size, &data_wa) ==
ERROR_OK) {
break;
}
data_wa_size /= 2;
} else {
LOG_WARNING("Couldn't allocate %zd-byte working area.", bin_size);
algorithm_wa = NULL;
}
/* If no valid page_size, use reasonable default. */
page_size = fespi_info->dev->pagesize ?
fespi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
fespi_txwm_wait(bank);
if (algorithm_wa) {
struct reg_param reg_params[6];
init_reg_param(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
init_reg_param(&reg_params[2], "a2", xlen, PARAM_OUT);
init_reg_param(&reg_params[3], "a3", xlen, PARAM_OUT);
init_reg_param(&reg_params[4], "a4", xlen, PARAM_OUT);
init_reg_param(&reg_params[5], "a5", xlen, PARAM_OUT);
/* Disable Hardware accesses*/
if (fespi_disable_hw_mode(bank) != ERROR_OK)
return ERROR_FAIL;
while (count > 0) {
cur_count = MIN(count, data_wa_size);
buf_set_u64(reg_params[0].value, 0, xlen, fespi_info->ctrl_base);
buf_set_u64(reg_params[1].value, 0, xlen, page_size);
buf_set_u64(reg_params[2].value, 0, xlen, data_wa->address);
buf_set_u64(reg_params[3].value, 0, xlen, offset);
buf_set_u64(reg_params[4].value, 0, xlen, cur_count);
buf_set_u64(reg_params[5].value, 0, xlen,
fespi_info->dev->pprog_cmd | (bank->size > 0x1000000 ? 0x100 : 0));
struct algorithm_steps *as = as_new();
retval = target_write_buffer(target, data_wa->address, cur_count,
buffer);
if (retval != ERROR_OK) {
LOG_DEBUG("Failed to write %d bytes to " TARGET_ADDR_FMT ": %d",
cur_count, data_wa->address, retval);
goto err;
}
/* poll WIP */
retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT);
if (retval != ERROR_OK)
goto err;
LOG_DEBUG("write(ctrl_base=0x%" TARGET_PRIxADDR ", page_size=0x%x, "
"address=0x%" TARGET_PRIxADDR ", offset=0x%" PRIx32
", count=0x%" PRIx32 "), buffer=%02x %02x %02x %02x %02x %02x ..." PRIx32,
fespi_info->ctrl_base, page_size, data_wa->address, offset, cur_count,
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
retval = target_run_algorithm(target, 0, NULL,
ARRAY_SIZE(reg_params), reg_params,
algorithm_wa->address, 0, cur_count * 2, NULL);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d",
algorithm_wa->address, retval);
goto err;
}
page_offset = offset % page_size;
/* central part, aligned words */
while (count > 0) {
/* clip block at page boundary */
if (page_offset + count > page_size)
cur_count = page_size - page_offset;
else
cur_count = count;
uint64_t algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen);
if (algorithm_result != 0) {
LOG_ERROR("Algorithm returned error %" PRId64, algorithm_result);
retval = ERROR_FAIL;
goto err;
}
if (algorithm_wa)
retval = steps_add_buffer_write(as, buffer, offset, cur_count);
else
retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count);
buffer += cur_count;
offset += cur_count;
count -= cur_count;
}
target_free_working_area(target, data_wa);
target_free_working_area(target, algorithm_wa);
} else {
fespi_txwm_wait(bank);
/* Disable Hardware accesses*/
if (fespi_disable_hw_mode(bank) != ERROR_OK)
return ERROR_FAIL;
/* poll WIP */
retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT);
if (retval != ERROR_OK)
goto err;
page_offset = 0;
buffer += cur_count;
offset += cur_count;
count -= cur_count;
uint32_t page_offset = offset % page_size;
/* central part, aligned words */
while (count > 0) {
/* clip block at page boundary */
if (page_offset + count > page_size)
cur_count = page_size - page_offset;
else
cur_count = count;
retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count);
if (retval != ERROR_OK)
goto err;
page_offset = 0;
buffer += cur_count;
offset += cur_count;
count -= cur_count;
}
/* Switch to HW mode before return to prompt */
if (fespi_enable_hw_mode(bank) != ERROR_OK)
return ERROR_FAIL;
}
if (algorithm_wa)
retval = steps_execute(as, bank, algorithm_wa, data_wa);
return ERROR_OK;
err:
if (algorithm_wa) {
@ -842,11 +666,10 @@ err:
target_free_working_area(target, algorithm_wa);
}
as_delete(as);
/* Switch to HW mode before return to prompt */
if (fespi_enable_hw_mode(bank) != ERROR_OK)
return ERROR_FAIL;
return retval;
}
@ -976,8 +799,6 @@ static int fespi_probe(struct flash_bank *bank)
if (bank->size <= (1UL << 16))
LOG_WARNING("device needs 2-byte addresses - not implemented");
if (bank->size > (1UL << 24))
LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
/* if no sectors, treat whole bank as single sector */
sectorsize = fespi_info->dev->sectorsize ?