Valgrind and Clang Static Analyzer have no complaints about this change. Change-Id: I7757615ec52448372bdc57729cdf97c7016d97e8 Signed-off-by: Tim Newsome <tim@sifive.com> Reviewed-on: http://openocd.zylin.com/4656 Tested-by: jenkins Reviewed-by: Philipp Guehring <pg@futureware.at> Reviewed-by: Tomas Vanek <vanekt@fbl.cz>master
@@ -123,12 +123,12 @@ EJTAG, NDS32, XScale, Intel Quark. | |||||
Flash drivers | Flash drivers | ||||
------------- | ------------- | ||||
ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-TSMC, | |||||
FM3, FM4, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI, | |||||
Marvell QSPI, Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP, SiM3x, | |||||
Stellaris, STM32, STMSMI, STR7x, STR9x, nRF51; NAND controllers of | |||||
AT91SAM9, LPC3180, LPC32xx, i.MX31, MXC, NUC910, Orion/Kirkwood, | |||||
S3C24xx, S3C6400, XMC1xxx, XMC4xxx. | |||||
ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-TSMC, FM3, | |||||
FM4, Freedom E SPI, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, | |||||
LPCSPIFI, Marvell QSPI, Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP, | |||||
SiM3x, Stellaris, STM32, STMSMI, STR7x, STR9x, nRF51; NAND controllers of | |||||
AT91SAM9, LPC3180, LPC32xx, i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, | |||||
S3C6400, XMC1xxx, XMC4xxx. | |||||
================== | ================== | ||||
@@ -0,0 +1,28 @@ | |||||
BIN2C = ../../../../src/helper/bin2char.sh | |||||
CROSS_COMPILE ?= riscv64-unknown-elf- | |||||
CC=$(CROSS_COMPILE)gcc | |||||
OBJCOPY=$(CROSS_COMPILE)objcopy | |||||
OBJDUMP=$(CROSS_COMPILE)objdump | |||||
CFLAGS = -march=rv32i -mabi=ilp32 -x assembler-with-cpp -nostdlib -nostartfiles | |||||
all: fespi.inc | |||||
.PHONY: clean | |||||
%.elf: %.S | |||||
$(CC) $(CFLAGS) $< -o $@ | |||||
%.lst: %.elf | |||||
$(OBJDUMP) -S $< > $@ | |||||
%.bin: %.elf | |||||
$(OBJCOPY) -Obinary $< $@ | |||||
%.inc: %.bin | |||||
$(BIN2C) < $< > $@ | |||||
clean: | |||||
-rm -f *.elf *.lst *.bin *.inc |
@@ -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 |
@@ -0,0 +1,15 @@ | |||||
/* 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, |
@@ -5365,6 +5365,17 @@ flash bank flash2 ath79 0x20000000 0 0 0 $_TARGETNAME cs2 | |||||
@end deffn | @end deffn | ||||
@deffn {Flash Driver} fespi | |||||
@cindex Freedom E SPI | |||||
@cindex fespi | |||||
SiFive's Freedom E SPI controller, used in HiFive and other boards. | |||||
@example | |||||
flash bank $_FLASHNAME fespi 0x20000000 0 0 0 $_TARGETNAME | |||||
@end example | |||||
@end deffn | |||||
@subsection Internal Flash (Microcontrollers) | @subsection Internal Flash (Microcontrollers) | ||||
@deffn {Flash Driver} aduc702x | @deffn {Flash Driver} aduc702x | ||||
@@ -27,6 +27,7 @@ NOR_DRIVERS = \ | |||||
%D%/em357.c \ | %D%/em357.c \ | ||||
%D%/esirisc_flash.c \ | %D%/esirisc_flash.c \ | ||||
%D%/faux.c \ | %D%/faux.c \ | ||||
%D%/fespi.c \ | |||||
%D%/fm3.c \ | %D%/fm3.c \ | ||||
%D%/fm4.c \ | %D%/fm4.c \ | ||||
%D%/jtagspi.c \ | %D%/jtagspi.c \ | ||||
@@ -42,6 +42,7 @@ extern struct flash_driver esirisc_flash; | |||||
extern struct flash_driver faux_flash; | extern struct flash_driver faux_flash; | ||||
extern struct flash_driver fm3_flash; | extern struct flash_driver fm3_flash; | ||||
extern struct flash_driver fm4_flash; | extern struct flash_driver fm4_flash; | ||||
extern struct flash_driver fespi_flash; | |||||
extern struct flash_driver jtagspi_flash; | extern struct flash_driver jtagspi_flash; | ||||
extern struct flash_driver kinetis_flash; | extern struct flash_driver kinetis_flash; | ||||
extern struct flash_driver kinetis_ke_flash; | extern struct flash_driver kinetis_ke_flash; | ||||
@@ -109,6 +110,7 @@ static struct flash_driver *flash_drivers[] = { | |||||
&faux_flash, | &faux_flash, | ||||
&fm3_flash, | &fm3_flash, | ||||
&fm4_flash, | &fm4_flash, | ||||
&fespi_flash, | |||||
&jtagspi_flash, | &jtagspi_flash, | ||||
&kinetis_flash, | &kinetis_flash, | ||||
&kinetis_ke_flash, | &kinetis_ke_flash, | ||||