#include #include #include "encoding.h" #include "platform.h" #include "eos.h" #include "soc/timer.h" #include "flash.h" #define IDLE_TICKS 10 __attribute__ ((section (".itim.flash"))) static void send(uint8_t data) { while (SPI0_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); SPI0_REG(SPI_REG_TXFIFO) = data; } __attribute__ ((section (".itim.flash"))) static uint8_t xfer(uint8_t data) { volatile uint32_t x = 0; send(data); while ((x = SPI0_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY); return x; } void eos_flash_init(void) { SPI0_REG(SPI_REG_FMT) |= SPI_FMT_DIR(SPI_DIR_TX); SPI0_REG(SPI_REG_TXCTRL) = SPI_TXWM(1); eos_flash_norm(); } __attribute__ ((section (".itim.flash"))) void eos_flash_norm(void) { volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME); uint32_t mtime0; clear_csr(mstatus, MSTATUS_MIE); SPI0_REG(SPI_REG_FCTRL) = 0; SPI0_REG(SPI_REG_SCKDIV) = 3; if (SPI0_REG(SPI_REG_FMT) & SPI_FMT_PROTO(SPI_PROTO_Q)) { send(EOS_FLASH_QPIDI); while (!(SPI0_REG(SPI_REG_IP) & SPI_IP_TXWM)); } SPI0_REG(SPI_REG_FMT) = \ SPI_FMT_PROTO(SPI_PROTO_S) | SPI_FMT_ENDIAN(SPI_ENDIAN_MSB) | SPI_FMT_DIR(SPI_DIR_TX) | SPI_FMT_LEN(8); SPI0_REG(SPI_REG_FFMT) = SPI_INSN_CMD_EN | SPI_INSN_ADDR_LEN(3) | SPI_INSN_PAD_CNT(0) | SPI_INSN_CMD_PROTO(SPI_PROTO_S) | SPI_INSN_ADDR_PROTO(SPI_PROTO_S) | SPI_INSN_DATA_PROTO(SPI_PROTO_S) | SPI_INSN_CMD_CODE(EOS_FLASH_NORD) | SPI_INSN_PAD_CODE(0x00); mtime0 = *mtime; while ((*mtime - mtime0) < IDLE_TICKS); SPI0_REG(SPI_REG_FCTRL) = SPI_FCTRL_EN; set_csr(mstatus, MSTATUS_MIE); } __attribute__ ((section (".itim.flash"))) void eos_flash_fast(void) { volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME); uint32_t mtime0; clear_csr(mstatus, MSTATUS_MIE); SPI0_REG(SPI_REG_FCTRL) = 0; SPI0_REG(SPI_REG_SCKDIV) = 2; if (!(SPI0_REG(SPI_REG_FMT) & SPI_FMT_PROTO(SPI_PROTO_Q))) { send(EOS_FLASH_QPIEN); while (!(SPI0_REG(SPI_REG_IP) & SPI_IP_TXWM)); } SPI0_REG(SPI_REG_FMT) = \ SPI_FMT_PROTO(SPI_PROTO_Q) | SPI_FMT_ENDIAN(SPI_ENDIAN_MSB) | SPI_FMT_DIR(SPI_DIR_TX) | SPI_FMT_LEN(8); SPI0_REG(SPI_REG_FFMT) = SPI_INSN_CMD_EN | SPI_INSN_ADDR_LEN(3) | SPI_INSN_PAD_CNT(6) | SPI_INSN_CMD_PROTO(SPI_PROTO_Q) | SPI_INSN_ADDR_PROTO(SPI_PROTO_Q) | SPI_INSN_DATA_PROTO(SPI_PROTO_Q) | SPI_INSN_CMD_CODE(EOS_FLASH_FRD) | SPI_INSN_PAD_CODE(0x00); mtime0 = *mtime; while ((*mtime - mtime0) < IDLE_TICKS); SPI0_REG(SPI_REG_FCTRL) = SPI_FCTRL_EN; set_csr(mstatus, MSTATUS_MIE); } __attribute__ ((section (".itim.flash"))) void eos_flash_wip(void) { uint8_t status; do { SPI0_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; xfer(EOS_FLASH_RDSR); status = xfer(0); SPI0_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; } while (status & EOS_FLASH_WIP); } __attribute__ ((section (".itim.flash"))) void eos_flash_wren(void) { uint8_t status; xfer(EOS_FLASH_WREN); #if 0 do { SPI0_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; xfer(EOS_FLASH_RDSR); status = xfer(0); SPI0_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; } while (!(status & EOS_FLASH_WEL)); #endif } __attribute__ ((section (".itim.flash"))) void eos_flash_ser(uint32_t addr) { SPI0_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; xfer(EOS_FLASH_SER); xfer(addr >> 16); xfer(addr >> 8); xfer(addr); SPI0_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; } __attribute__ ((section (".itim.flash"))) void eos_flash_pp(uint32_t addr, uint8_t *buf) { int i; SPI0_REG(SPI_REG_FMT) |= SPI_FMT_DIR(SPI_DIR_TX); SPI0_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; send(EOS_FLASH_PP); send(addr >> 16); send(addr >> 8); send(addr); for (i=0; i<256; i++) { send(buf[i]); } while (!(SPI0_REG(SPI_REG_IP) & SPI_IP_TXWM)); SPI0_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; SPI0_REG(SPI_REG_FMT) &= ~SPI_FMT_DIR(SPI_DIR_TX); }