From 35f284fe7c51d29768156cfec172152d2539d98a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 8 Nov 2021 09:26:51 -0800 Subject: [PATCH] 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 Reviewed-on: https://review.openocd.org/c/openocd/+/6679 Tested-by: jenkins Reviewed-by: Tomas Vanek --- contrib/loaders/flash/fespi/Makefile | 45 +- contrib/loaders/flash/fespi/fespi.S | 99 ---- contrib/loaders/flash/fespi/fespi.inc | 15 - contrib/loaders/flash/fespi/riscv.lds | 12 + contrib/loaders/flash/fespi/riscv32_fespi.inc | 51 ++ contrib/loaders/flash/fespi/riscv64_fespi.inc | 58 +++ contrib/loaders/flash/fespi/riscv_fespi.c | 321 ++++++++++++ contrib/loaders/flash/fespi/riscv_wrapper.S | 22 + src/flash/nor/fespi.c | 475 ++++++------------ 9 files changed, 646 insertions(+), 452 deletions(-) delete mode 100644 contrib/loaders/flash/fespi/fespi.S delete mode 100644 contrib/loaders/flash/fespi/fespi.inc create mode 100644 contrib/loaders/flash/fespi/riscv.lds create mode 100644 contrib/loaders/flash/fespi/riscv32_fespi.inc create mode 100644 contrib/loaders/flash/fespi/riscv64_fespi.inc create mode 100644 contrib/loaders/flash/fespi/riscv_fespi.c create mode 100644 contrib/loaders/flash/fespi/riscv_wrapper.S diff --git a/contrib/loaders/flash/fespi/Makefile b/contrib/loaders/flash/fespi/Makefile index 4d2ab51d76..edecf0a729 100644 --- a/contrib/loaders/flash/fespi/Makefile +++ b/contrib/loaders/flash/fespi/Makefile @@ -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 diff --git a/contrib/loaders/flash/fespi/fespi.S b/contrib/loaders/flash/fespi/fespi.S deleted file mode 100644 index d68e65ef81..0000000000 --- a/contrib/loaders/flash/fespi/fespi.S +++ /dev/null @@ -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 diff --git a/contrib/loaders/flash/fespi/fespi.inc b/contrib/loaders/flash/fespi/fespi.inc deleted file mode 100644 index 768bdc5981..0000000000 --- a/contrib/loaders/flash/fespi/fespi.inc +++ /dev/null @@ -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, diff --git a/contrib/loaders/flash/fespi/riscv.lds b/contrib/loaders/flash/fespi/riscv.lds new file mode 100644 index 0000000000..77fe0e5582 --- /dev/null +++ b/contrib/loaders/flash/fespi/riscv.lds @@ -0,0 +1,12 @@ +OUTPUT_ARCH( "riscv" ) + +SECTIONS +{ + . = 0x12340000; + .text : + { + *(.text.entry) + *(.text) + } + .data : { *(.data) } +} diff --git a/contrib/loaders/flash/fespi/riscv32_fespi.inc b/contrib/loaders/flash/fespi/riscv32_fespi.inc new file mode 100644 index 0000000000..44e04482fd --- /dev/null +++ b/contrib/loaders/flash/fespi/riscv32_fespi.inc @@ -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, diff --git a/contrib/loaders/flash/fespi/riscv64_fespi.inc b/contrib/loaders/flash/fespi/riscv64_fespi.inc new file mode 100644 index 0000000000..97a860fe32 --- /dev/null +++ b/contrib/loaders/flash/fespi/riscv64_fespi.inc @@ -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, diff --git a/contrib/loaders/flash/fespi/riscv_fespi.c b/contrib/loaders/flash/fespi/riscv_fespi.c new file mode 100644 index 0000000000..b6164330d3 --- /dev/null +++ b/contrib/loaders/flash/fespi/riscv_fespi.c @@ -0,0 +1,321 @@ +#include +#include +#include + +#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; +} diff --git a/contrib/loaders/flash/fespi/riscv_wrapper.S b/contrib/loaders/flash/fespi/riscv_wrapper.S new file mode 100644 index 0000000000..4f632a76ec --- /dev/null +++ b/contrib/loaders/flash/fespi/riscv_wrapper.S @@ -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: diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index 150e91a1c4..11da818547 100644 --- a/src/flash/nor/fespi.c +++ b/src/flash/nor/fespi.c @@ -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(®_params[0], "a0", xlen, PARAM_OUT); - init_reg_param(®_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(®_params[1]); - destroy_reg_param(®_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; - } - if (target_alloc_working_area_try(target, data_wa_size, &data_wa) == - ERROR_OK) { - break; + } 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; + } } - - 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(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "a2", xlen, PARAM_OUT); + init_reg_param(®_params[3], "a3", xlen, PARAM_OUT); + init_reg_param(®_params[4], "a4", xlen, PARAM_OUT); + init_reg_param(®_params[5], "a5", xlen, PARAM_OUT); + + 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)); + + 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; + } + + 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; + } + + 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; + } + + buffer += cur_count; + offset += cur_count; + count -= cur_count; + } - /* Disable Hardware accesses*/ - if (fespi_disable_hw_mode(bank) != ERROR_OK) - return ERROR_FAIL; + target_free_working_area(target, data_wa); + target_free_working_area(target, algorithm_wa); - struct algorithm_steps *as = as_new(); + } else { + fespi_txwm_wait(bank); - /* poll WIP */ - retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT); - if (retval != ERROR_OK) - 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; - - if (algorithm_wa) - retval = steps_add_buffer_write(as, buffer, offset, cur_count); - else - retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count); + /* 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 ? -- 2.30.2