summaryrefslogtreecommitdiff
path: root/fw/fe310/eos/dev/flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw/fe310/eos/dev/flash.c')
-rw-r--r--fw/fe310/eos/dev/flash.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/fw/fe310/eos/dev/flash.c b/fw/fe310/eos/dev/flash.c
new file mode 100644
index 0000000..4f017b3
--- /dev/null
+++ b/fw/fe310/eos/dev/flash.c
@@ -0,0 +1,162 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#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);
+}