X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=contrib%2Floaders%2Fflash%2Ffespi%2Friscv_fespi.c;fp=contrib%2Floaders%2Fflash%2Ffespi%2Friscv_fespi.c;h=b6164330d3faad5edb82b3f54aae6667f916b0dc;hb=35f284fe7c51d29768156cfec172152d2539d98a;hp=0000000000000000000000000000000000000000;hpb=15110b2b5bf3459d038e6142d151c3856760e387;p=openocd.git 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; +}