summaryrefslogtreecommitdiff
path: root/fw/fe310/eos/soc
diff options
context:
space:
mode:
authorUros Majstorovic <majstor@majstor.org>2022-05-13 12:45:53 +0200
committerUros Majstorovic <majstor@majstor.org>2022-05-13 12:45:53 +0200
commit412a8f99928beff605805807b0f07f6bf8d0a965 (patch)
tree366f1768ddfd32960c5d26ca3fba14e82c3b571e /fw/fe310/eos/soc
parent9ccb4db8d59ec9dab33ee8617d462f21a8bb4fa8 (diff)
code rename
Diffstat (limited to 'fw/fe310/eos/soc')
-rw-r--r--fw/fe310/eos/soc/i2c.c145
-rw-r--r--fw/fe310/eos/soc/i2c.h13
-rw-r--r--fw/fe310/eos/soc/i2s.c477
-rw-r--r--fw/fe310/eos/soc/i2s.h38
-rw-r--r--fw/fe310/eos/soc/i2s_def.h8
-rw-r--r--fw/fe310/eos/soc/i2s_priv.h8
-rw-r--r--fw/fe310/eos/soc/interrupt.c75
-rw-r--r--fw/fe310/eos/soc/interrupt.h13
-rw-r--r--fw/fe310/eos/soc/net.c602
-rw-r--r--fw/fe310/eos/soc/net.h47
-rw-r--r--fw/fe310/eos/soc/pwr.c133
-rw-r--r--fw/fe310/eos/soc/pwr.h25
-rw-r--r--fw/fe310/eos/soc/spi.c350
-rw-r--r--fw/fe310/eos/soc/spi.h28
-rw-r--r--fw/fe310/eos/soc/spi_cfg.h37
-rw-r--r--fw/fe310/eos/soc/spi_dev.c97
-rw-r--r--fw/fe310/eos/soc/spi_dev.h19
-rw-r--r--fw/fe310/eos/soc/spi_priv.h8
-rw-r--r--fw/fe310/eos/soc/timer.c137
-rw-r--r--fw/fe310/eos/soc/timer.h23
-rw-r--r--fw/fe310/eos/soc/trap_entry.S554
-rw-r--r--fw/fe310/eos/soc/uart.c114
-rw-r--r--fw/fe310/eos/soc/uart.h24
23 files changed, 2975 insertions, 0 deletions
diff --git a/fw/fe310/eos/soc/i2c.c b/fw/fe310/eos/soc/i2c.c
new file mode 100644
index 0000000..a507af1
--- /dev/null
+++ b/fw/fe310/eos/soc/i2c.c
@@ -0,0 +1,145 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "prci_driver.h"
+
+#include "eos.h"
+#include "i2s.h"
+#include "i2c.h"
+
+int eos_i2c_init(uint8_t wakeup_cause) {
+ eos_i2c_speed(EOS_I2C_SPEED);
+ // eos_i2c_start();
+
+ return EOS_OK;
+}
+
+void eos_i2c_start(void) {
+ I2C0_REGB(I2C_CONTROL) |= I2C_CONTROL_EN;
+ GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_I2C0_MASK;
+ GPIO_REG(GPIO_IOF_EN) |= IOF0_I2C0_MASK;
+}
+
+void eos_i2c_stop(void) {
+ GPIO_REG(GPIO_IOF_EN) &= ~IOF0_I2C0_MASK;
+ I2C0_REGB(I2C_CONTROL) &= ~I2C_CONTROL_EN;
+}
+
+void eos_i2c_speed(uint32_t baud_rate) {
+ unsigned long clock_rate = PRCI_get_cpu_freq();
+ uint16_t prescaler = (clock_rate / (baud_rate * 5)) - 1;
+
+ I2C0_REGB(I2C_PRESCALE_LOW) = prescaler & 0xFF;
+ I2C0_REGB(I2C_PRESCALE_HIGH) = (prescaler >> 8) & 0xFF;
+}
+
+
+static int i2c_read(uint8_t cmd) {
+ I2C0_REGB(I2C_COMMAND) = I2C_CMD_READ | cmd;
+ while (I2C0_REGB(I2C_STATUS) & I2C_STATUS_TIP);
+
+ return I2C0_REGB(I2C_RECEIVE);
+}
+
+static int i2c_write(uint8_t cmd, uint8_t b) {
+ I2C0_REGB(I2C_TRANSMIT) = b;
+ I2C0_REGB(I2C_COMMAND) = I2C_CMD_WRITE | cmd;
+ while (I2C0_REGB(I2C_STATUS) & I2C_STATUS_TIP);
+
+ if (I2C0_REGB(I2C_STATUS) & I2C_STATUS_RXACK) return EOS_ERR;
+ return EOS_OK;
+}
+
+static int i2c_addr(uint8_t addr, uint8_t rw_flag) {
+ return i2c_write(I2C_CMD_START, ((addr & 0x7F) << 1) | (rw_flag & 0x1));
+}
+
+int eos_i2c_read8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len) {
+ int rv;
+ int i;
+
+ rv = i2c_addr(addr, I2C_WRITE);
+ if (rv) return rv;
+
+ rv = i2c_write(0, reg);
+ if (rv) return rv;
+
+ rv = i2c_addr(addr, I2C_READ);
+ if (rv) return rv;
+
+ for (i=0; i<len; i++) {
+ rv = i2c_read(i == (len - 1) ? (I2C_CMD_ACK | I2C_CMD_STOP) : 0); /* Set NACK to end read, and generate STOP condition */
+ if (rv < 0) return rv;
+
+ buffer[i] = (uint8_t)rv;
+ }
+
+ return EOS_OK;
+}
+
+int eos_i2c_read16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len) {
+ int rv;
+ int i;
+
+ rv = i2c_addr(addr, I2C_WRITE);
+ if (rv) return rv;
+
+ rv = i2c_write(0, reg >> 8);
+ if (rv) return rv;
+
+ rv = i2c_write(0, reg & 0xff);
+ if (rv) return rv;
+
+ rv = i2c_addr(addr, I2C_READ);
+ if (rv) return rv;
+
+ for (i=0; i<len; i++) {
+ rv = i2c_read(i == (len - 1) ? (I2C_CMD_ACK | I2C_CMD_STOP) : 0); /* Set NACK to end read, and generate STOP condition */
+ if (rv < 0) return rv;
+
+ buffer[i] = (uint8_t)rv;
+ }
+
+ return EOS_OK;
+}
+
+int eos_i2c_write8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len) {
+ int rv;
+ int i;
+
+ rv = i2c_addr(addr, I2C_WRITE);
+ if (rv) return rv;
+
+ rv = i2c_write(0, reg);
+ if (rv) return rv;
+
+ for (i=0; i<len; i++) {
+ rv = i2c_write(i == (len - 1) ? I2C_CMD_STOP : 0, buffer[i]);
+ if (rv) return rv;
+ }
+
+ return EOS_OK;
+}
+
+int eos_i2c_write16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len) {
+ int rv;
+ int i;
+
+ rv = i2c_addr(addr, I2C_WRITE);
+ if (rv) return rv;
+
+ rv = i2c_write(0, reg >> 8);
+ if (rv) return rv;
+
+ rv = i2c_write(0, reg & 0xff);
+ if (rv) return rv;
+
+ for (i=0; i<len; i++) {
+ rv = i2c_write(i == (len - 1) ? I2C_CMD_STOP : 0, buffer[i]);
+ if (rv) return rv;
+ }
+
+ return EOS_OK;
+}
diff --git a/fw/fe310/eos/soc/i2c.h b/fw/fe310/eos/soc/i2c.h
new file mode 100644
index 0000000..20d3dc7
--- /dev/null
+++ b/fw/fe310/eos/soc/i2c.h
@@ -0,0 +1,13 @@
+#include <stdint.h>
+
+#define EOS_I2C_SPEED 100000
+
+int eos_i2c_init(uint8_t wakeup_cause);
+int eos_i2c_run(uint8_t wakeup_cause);
+void eos_i2c_start(void);
+void eos_i2c_stop(void);
+void eos_i2c_speed(uint32_t baud_rate);
+int eos_i2c_read8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len);
+int eos_i2c_read16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len);
+int eos_i2c_write8(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t len);
+int eos_i2c_write16(uint8_t addr, uint16_t reg, uint8_t *buffer, uint16_t len);
diff --git a/fw/fe310/eos/soc/i2s.c b/fw/fe310/eos/soc/i2s.c
new file mode 100644
index 0000000..9cc9d9c
--- /dev/null
+++ b/fw/fe310/eos/soc/i2s.c
@@ -0,0 +1,477 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "prci_driver.h"
+
+#include "eos.h"
+#include "interrupt.h"
+#include "event.h"
+
+#include "board.h"
+
+#include "i2s.h"
+#include "i2s_priv.h"
+
+#define I2S_REG_CK(o) _REG32(I2S_CTRL_ADDR_CK, o)
+#define I2S_REG_WS_MIC(o) _REG32(I2S_CTRL_ADDR_WS_MIC, o)
+#define I2S_REG_WS_SPK(o) _REG32(I2S_CTRL_ADDR_WS_SPK, o)
+
+#define I2S_PIN_PWM ((1 << I2S_PIN_CK) | (1 << I2S_PIN_CK_SW) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK))
+
+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
+
+#define EOS_ABUF_IDX_MASK(IDX, SIZE) ((IDX) & ((SIZE) - 1))
+
+EOSABuf i2s_mic_buf;
+EOSABuf i2s_spk_buf;
+
+static eos_i2s_handler_t i2s_mic_handler = NULL;
+static eos_i2s_handler_t i2s_spk_handler = NULL;
+static uint32_t i2s_clk_period;
+static uint8_t i2s_mic_volume = 0; /* 0 - 8 */
+static uint8_t i2s_spk_volume = 16; /* 0 - 16 */
+
+uint32_t _eos_i2s_drvr[] = {
+ 0, /* I2S_MIC_BUF */
+ 0, /* I2S_SPK_BUF */
+ EOS_I2S_FMT_PCM16, /* I2S_FMT */
+ EOS_I2S_MODE_STEREO, /* I2S_MODE */
+ 0, /* I2S_MIC_WM */
+ 0, /* I2S_SPK_WM */
+ 0, /* I2S_MIC_EVT */
+ 0, /* I2S_SPK_EVT */
+ 0, /* I2S_MIC_CMP2 */
+ 0, /* I2S_MIC_CMP3 */
+ 0, /* I2S_SAMPLE */
+};
+
+#define I2S_MIC_BUF 0
+#define I2S_SPK_BUF 1
+#define I2S_FMT 2
+#define I2S_MODE 3
+#define I2S_MIC_WM 4
+#define I2S_SPK_WM 5
+#define I2S_MIC_EVT 6
+#define I2S_SPK_EVT 7
+#define I2S_MIC_CMP2 8
+#define I2S_MIC_CMP3 9
+#define I2S_SAMPLE 10
+
+static void _abuf_init(EOSABuf *buf, uint8_t *array, uint16_t size) {
+ buf->idx_r = 0;
+ buf->idx_w = 0;
+ buf->size = size;
+ buf->array = array;
+}
+
+static int _abuf_push8(EOSABuf *buf, uint8_t sample) {
+ if ((uint16_t)(buf->idx_w - buf->idx_r) == buf->size) return EOS_ERR_FULL;
+
+ buf->array[EOS_ABUF_IDX_MASK(buf->idx_w, buf->size)] = sample;
+ buf->idx_w++;
+ return EOS_OK;
+}
+
+static int _abuf_push16(EOSABuf *buf, uint16_t sample) {
+ if ((uint16_t)(buf->idx_w - buf->idx_r) == buf->size) return EOS_ERR_FULL;
+
+ buf->array[EOS_ABUF_IDX_MASK(buf->idx_w, buf->size)] = sample >> 8;
+ buf->array[EOS_ABUF_IDX_MASK(buf->idx_w + 1, buf->size)] = sample & 0xFF;
+ buf->idx_w += 2;
+ return EOS_OK;
+}
+
+static int _abuf_pop8(EOSABuf *buf, uint8_t *sample) {
+ if (buf->idx_r == buf->idx_w) {
+ return EOS_ERR_EMPTY;
+ } else {
+ *sample = buf->array[EOS_ABUF_IDX_MASK(buf->idx_r, buf->size)];
+ buf->idx_r++;
+ return EOS_OK;
+ }
+}
+
+static int _abuf_pop16(EOSABuf *buf, uint16_t *sample) {
+ if (buf->idx_r == buf->idx_w) {
+ return EOS_ERR_EMPTY;
+ } else {
+ *sample = buf->array[EOS_ABUF_IDX_MASK(buf->idx_r, buf->size)] << 8;
+ *sample |= buf->array[EOS_ABUF_IDX_MASK(buf->idx_r + 1, buf->size)];
+ buf->idx_r += 2;
+ return EOS_OK;
+ }
+}
+
+static void _abuf_flush(EOSABuf *buf) {
+ buf->idx_r = 0;
+ buf->idx_w = 0;
+}
+
+static uint16_t _abuf_len(EOSABuf *buf) {
+ return buf->idx_w - buf->idx_r;
+}
+
+static void i2s_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
+ switch(type & ~EOS_EVT_MASK) {
+ case EOS_I2S_ETYPE_MIC:
+ if (i2s_mic_handler) {
+ i2s_mic_handler(type);
+ clear_csr(mstatus, MSTATUS_MIE);
+ _eos_i2s_drvr[I2S_MIC_EVT] = 1;
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+ break;
+
+ case EOS_I2S_ETYPE_SPK:
+ if (i2s_spk_handler) {
+ i2s_spk_handler(type);
+ clear_csr(mstatus, MSTATUS_MIE);
+ _eos_i2s_drvr[I2S_SPK_EVT] = 1;
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+ break;
+
+ default:
+ eos_evtq_bad_handler(type, buffer, len);
+ break;
+ }
+}
+
+#define PLIC_PRIORITY 0x0C000000
+
+static void i2s_cmp_set(void) {
+ int c = 7; /* interrupt will trigger c i2s clocks before spk ws */
+ int spk_ws_offset = i2s_spk_volume - 16 + i2s_mic_volume;
+ volatile uint32_t *p = (uint32_t *)PLIC_PRIORITY+I2S_IRQ_SD_ID;
+
+ /* interrupt trigger - will start with left channel */
+ if (spk_ws_offset - c < 0) {
+ I2S_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * (64 + spk_ws_offset - c);
+ } else {
+ I2S_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * (spk_ws_offset - c);
+ }
+
+ /* disable interrupt for this cycle */
+ *p = 0;
+
+ /* empty buffers */
+ // i2s_mic_buf.idx_r = i2s_mic_buf.idx_w;
+ // i2s_spk_buf.idx_w = i2s_spk_buf.idx_r;
+
+ /* adjust spk ws relative to mic ws */
+ if (spk_ws_offset <= 0) {
+ spk_ws_offset += 32;
+ GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS_SPK);
+ } else {
+ GPIO_REG(GPIO_OUTPUT_XOR) |= (1 << I2S_PIN_WS_SPK);
+ }
+ I2S_REG_WS_SPK(PWM_CMP1) = i2s_clk_period * spk_ws_offset;
+ I2S_REG_WS_SPK(PWM_CMP2) = i2s_clk_period * (32 + spk_ws_offset);
+
+ /* mic cmp2 relative to interrupt trigger */
+ _eos_i2s_drvr[I2S_MIC_CMP2] = (17 + c - i2s_spk_volume) * i2s_clk_period; /* (17 + c - i2s_spk_volume) == (1 + i2s_mic_volume) - (spk_ws_offset - c) */
+ _eos_i2s_drvr[I2S_MIC_CMP3] = 16 * i2s_clk_period;
+}
+
+extern void _eos_i2s_start_pwm(void);
+
+int eos_i2s_init(uint8_t wakeup_cause) {
+ eos_evtq_set_handler(EOS_EVT_I2S, i2s_handle_evt);
+
+ I2S_REG_CK(PWM_CFG) = 0;
+ I2S_REG_WS_MIC(PWM_CFG) = 0;
+ I2S_REG_WS_SPK(PWM_CFG) = 0;
+
+ eos_i2s_init_mux();
+
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_CK_SW);
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << I2S_PIN_CK_SR);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_CK_SW);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_CK_SW);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_CK_SR);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_CK_SR);
+
+ return EOS_OK;
+}
+
+void eos_i2s_init_mux(void) {
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~((1 << I2S_PIN_CK) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK));
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_CK);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_CK);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_WS_MIC);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_WS_MIC);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_WS_SPK);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_WS_SPK);
+
+ GPIO_REG(GPIO_INPUT_EN) |= (1 << I2S_PIN_SD_IN);
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD_IN);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_SD_OUT);
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD_OUT);
+}
+
+void eos_i2s_start(uint32_t sample_rate) {
+ i2s_clk_period = ((PRCI_get_cpu_freq() / (sample_rate * 64)) & ~I2S_PWM_SCALE_CK_MASK) + 1;
+
+ GPIO_REG(GPIO_INPUT_EN) |= (1 << I2S_PIN_SD_IN);
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD_IN);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_SD_OUT);
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD_OUT);
+
+ I2S_REG_CK(PWM_CMP0) = i2s_clk_period >> I2S_PWM_SCALE_CK;
+ I2S_REG_CK(PWM_CMP1) = I2S_REG_CK(PWM_CMP0) / 2;
+ I2S_REG_CK(PWM_CMP2) = 0;
+ I2S_REG_CK(PWM_CMP3) = 0;
+
+ I2S_REG_WS_MIC(PWM_CMP0) = i2s_clk_period * 64 - 1;
+ I2S_REG_WS_MIC(PWM_CMP1) = i2s_clk_period * 32;
+
+ I2S_REG_WS_SPK(PWM_CMP0) = i2s_clk_period * 64 - 1;
+ i2s_cmp_set();
+
+ I2S_REG_CK(PWM_COUNT) = 0;
+ I2S_REG_WS_MIC(PWM_COUNT) = 0;
+ I2S_REG_WS_SPK(PWM_COUNT) = i2s_clk_period / 2;
+
+ if (i2s_mic_buf.array && i2s_mic_buf.size) {
+ _eos_i2s_drvr[I2S_MIC_BUF] = (uint32_t)&i2s_mic_buf;
+ if (_eos_i2s_drvr[I2S_MIC_WM] == 0) {
+ _eos_i2s_drvr[I2S_MIC_WM] = i2s_mic_buf.size / 2;
+ }
+ }
+ if (i2s_spk_buf.array && i2s_spk_buf.size) {
+ _eos_i2s_drvr[I2S_SPK_BUF] = (uint32_t)&i2s_spk_buf;
+ if (_eos_i2s_drvr[I2S_SPK_WM] == 0) {
+ _eos_i2s_drvr[I2S_SPK_WM] = i2s_spk_buf.size / 2;
+ }
+ }
+ if (i2s_mic_handler) _eos_i2s_drvr[I2S_MIC_EVT] = 1;
+ if (i2s_spk_handler) _eos_i2s_drvr[I2S_SPK_EVT] = 1;
+
+ eos_intr_set_priority(I2S_IRQ_SD_ID, IRQ_PRIORITY_I2S_SD);
+ eos_intr_set_priority(I2S_IRQ_WS_ID, IRQ_PRIORITY_I2S_WS);
+ eos_intr_enable(I2S_IRQ_SD_ID);
+ eos_intr_enable(I2S_IRQ_WS_ID);
+
+ _eos_i2s_start_pwm();
+ /*
+ I2S_REG_CK(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | I2S_PWM_SCALE_CK;
+ I2S_REG_WS_MIC(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP2GANG;
+ I2S_REG_WS_SPK(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP1GANG;
+ */
+
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_WS_MIC);
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_WS_MIC);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_WS_MIC);
+
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_CK_SR);
+ GPIO_REG(GPIO_IOF_SEL) |= I2S_PIN_PWM;
+ GPIO_REG(GPIO_IOF_EN) |= I2S_PIN_PWM;
+}
+
+void eos_i2s_stop(void) {
+ I2S_REG_CK(PWM_CFG) = 0;
+ I2S_REG_WS_MIC(PWM_CFG) = 0;
+ I2S_REG_WS_SPK(PWM_CFG) = 0;
+ I2S_REG_CK(PWM_COUNT) = 0;
+ I2S_REG_WS_MIC(PWM_COUNT) = 0;
+ I2S_REG_WS_SPK(PWM_COUNT) = 0;
+
+ _eos_i2s_drvr[I2S_MIC_BUF] = 0;
+ _eos_i2s_drvr[I2S_MIC_EVT] = 0;
+ _eos_i2s_drvr[I2S_MIC_WM] = 0;
+
+ _eos_i2s_drvr[I2S_SPK_BUF] = 0;
+ _eos_i2s_drvr[I2S_SPK_EVT] = 0;
+ _eos_i2s_drvr[I2S_SPK_WM] = 0;
+
+ eos_intr_disable(I2S_IRQ_WS_ID);
+ eos_intr_disable(I2S_IRQ_SD_ID);
+
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_CK_SW);
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << I2S_PIN_CK_SR);
+
+ GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS_SPK);
+ GPIO_REG(GPIO_IOF_EN) &= ~I2S_PIN_PWM;
+
+ eos_i2s_mic_set_wm(0);
+ eos_i2s_spk_set_wm(0);
+}
+
+int eos_i2s_running(void) {
+ return !!(GPIO_REG(GPIO_IOF_EN) & (1 << I2S_PIN_CK));
+}
+
+void eos_i2s_set_fmt(unsigned char fmt) {
+ _eos_i2s_drvr[I2S_FMT] = fmt;
+}
+
+void eos_i2s_set_mode(unsigned char mode) {
+ _eos_i2s_drvr[I2S_MODE] = mode;
+}
+
+void eos_i2s_mic_init(uint8_t *mic_arr, uint16_t mic_arr_size) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ _abuf_init(&i2s_mic_buf, mic_arr, mic_arr_size);
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_i2s_mic_set_handler(eos_i2s_handler_t wm_handler) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ i2s_mic_handler = wm_handler;
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_i2s_mic_set_wm(uint16_t wm) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ _eos_i2s_drvr[I2S_MIC_WM] = wm;
+ set_csr(mstatus, MSTATUS_MIE);
+
+}
+
+uint16_t eos_i2s_mic_len(void) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ uint16_t ret = _abuf_len(&i2s_mic_buf);
+ set_csr(mstatus, MSTATUS_MIE);
+ return ret;
+}
+
+uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize) {
+ uint16_t i;
+ uint16_t _ssize = 0;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ _ssize = MIN(ssize, _abuf_len(&i2s_mic_buf));
+ set_csr(mstatus, MSTATUS_MIE);
+
+ for (i=0; i<_ssize; i++) {
+ sample[i] = i2s_mic_buf.array[EOS_ABUF_IDX_MASK(i2s_mic_buf.idx_r + i, i2s_mic_buf.size)];
+ }
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ i2s_mic_buf.idx_r += _ssize;
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return _ssize;
+}
+
+int eos_i2s_mic_pop8(uint8_t *sample) {
+ int ret;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ ret = _abuf_pop8(&i2s_mic_buf, sample);
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return ret;
+}
+
+int eos_i2s_mic_pop16(uint16_t *sample) {
+ int ret;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ ret = _abuf_pop16(&i2s_mic_buf, sample);
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return ret;
+}
+
+int eos_i2s_mic_vol_get(void) {
+ return i2s_mic_volume;
+}
+
+void eos_i2s_mic_vol_set(int vol) {
+ if ((vol < 0) || (vol > 8)) return;
+
+ i2s_mic_volume = vol;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ i2s_cmp_set();
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_i2s_spk_init(uint8_t *spk_arr, uint16_t spk_arr_size) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ _abuf_init(&i2s_spk_buf, spk_arr, spk_arr_size);
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_i2s_spk_set_handler(eos_i2s_handler_t wm_handler) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ i2s_spk_handler = wm_handler;
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_i2s_spk_set_wm(uint16_t wm) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ _eos_i2s_drvr[I2S_SPK_WM] = wm;
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+uint16_t eos_i2s_spk_len(void) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ uint16_t ret = _abuf_len(&i2s_spk_buf);
+ set_csr(mstatus, MSTATUS_MIE);
+ return ret;
+}
+
+uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize) {
+ uint16_t i;
+ uint16_t _ssize = 0;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ _ssize = MIN(ssize, i2s_spk_buf.size - _abuf_len(&i2s_spk_buf));
+ set_csr(mstatus, MSTATUS_MIE);
+
+ for (i=0; i<_ssize; i++) {
+ i2s_spk_buf.array[EOS_ABUF_IDX_MASK(i2s_spk_buf.idx_w + i, i2s_spk_buf.size)] = sample[i];
+ }
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ i2s_spk_buf.idx_w += _ssize;
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return _ssize;
+}
+
+int eos_i2s_spk_push8(uint8_t sample) {
+ int ret;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ ret = _abuf_push8(&i2s_spk_buf, sample);
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return ret;
+}
+
+int eos_i2s_spk_push16(uint16_t sample) {
+ int ret;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ ret = _abuf_push16(&i2s_spk_buf, sample);
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return ret;
+}
+
+int eos_i2s_spk_vol_get(void) {
+ return i2s_spk_volume;
+}
+
+void eos_i2s_spk_vol_set(int vol) {
+ if ((vol < 0) || (vol > 16)) return;
+
+ i2s_spk_volume = vol;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ i2s_cmp_set();
+ set_csr(mstatus, MSTATUS_MIE);
+}
diff --git a/fw/fe310/eos/soc/i2s.h b/fw/fe310/eos/soc/i2s.h
new file mode 100644
index 0000000..81b4ade
--- /dev/null
+++ b/fw/fe310/eos/soc/i2s.h
@@ -0,0 +1,38 @@
+#include <stdint.h>
+
+#include "i2s_def.h"
+
+typedef struct EOSABuf {
+ uint16_t idx_r;
+ uint16_t idx_w;
+ uint16_t size;
+ uint8_t *array;
+} EOSABuf;
+
+typedef void (*eos_i2s_handler_t) (unsigned char);
+
+int eos_i2s_init(uint8_t wakeup_cause);
+void eos_i2s_init_mux(void);
+void eos_i2s_start(uint32_t sample_rate);
+void eos_i2s_stop(void);
+int eos_i2s_running(void);
+void eos_i2s_set_fmt(unsigned char fmt);
+void eos_i2s_set_mode(unsigned char mode);
+void eos_i2s_mic_init(uint8_t *mic_arr, uint16_t mic_arr_size);
+void eos_i2s_mic_set_handler(eos_i2s_handler_t wm_handler);
+void eos_i2s_mic_set_wm(uint16_t wm);
+uint16_t eos_i2s_mic_len(void);
+uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize);
+int eos_i2s_mic_pop8(uint8_t *sample);
+int eos_i2s_mic_pop16(uint16_t *sample);
+int eos_i2s_mic_vol_get(void);
+void eos_i2s_mic_vol_set(int vol);
+void eos_i2s_spk_init(uint8_t *mic_arr, uint16_t mic_arr_size);
+void eos_i2s_spk_set_handler(eos_i2s_handler_t wm_handler);
+void eos_i2s_spk_set_wm(uint16_t wm);
+uint16_t eos_i2s_spk_len(void);
+uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize);
+int eos_i2s_spk_push8(uint8_t sample);
+int eos_i2s_spk_push16(uint16_t sample);
+int eos_i2s_spk_vol_get(void);
+void eos_i2s_spk_vol_set(int vol);
diff --git a/fw/fe310/eos/soc/i2s_def.h b/fw/fe310/eos/soc/i2s_def.h
new file mode 100644
index 0000000..3529be1
--- /dev/null
+++ b/fw/fe310/eos/soc/i2s_def.h
@@ -0,0 +1,8 @@
+#define EOS_I2S_FMT_PCM16 0
+#define EOS_I2S_FMT_ALAW 1
+
+#define EOS_I2S_MODE_STEREO 0
+#define EOS_I2S_MODE_MONO 1
+
+#define EOS_I2S_ETYPE_MIC 1
+#define EOS_I2S_ETYPE_SPK 2
diff --git a/fw/fe310/eos/soc/i2s_priv.h b/fw/fe310/eos/soc/i2s_priv.h
new file mode 100644
index 0000000..25237c3
--- /dev/null
+++ b/fw/fe310/eos/soc/i2s_priv.h
@@ -0,0 +1,8 @@
+#define I2S_PWM_SCALE_CK 2
+#define I2S_PWM_SCALE_CK_MASK 0x0003
+
+/* asm */
+#define I2S_ABUF_OFF_IDXR 0
+#define I2S_ABUF_OFF_IDXW 2
+#define I2S_ABUF_OFF_SIZE 4
+#define I2S_ABUF_OFF_ARRAY 8
diff --git a/fw/fe310/eos/soc/interrupt.c b/fw/fe310/eos/soc/interrupt.c
new file mode 100644
index 0000000..dab6fab
--- /dev/null
+++ b/fw/fe310/eos/soc/interrupt.c
@@ -0,0 +1,75 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "plic_driver.h"
+
+#include "eos.h"
+#include "interrupt.h"
+
+// Global Instance data for the PLIC
+// for use by the PLIC Driver.
+static plic_instance_t plic;
+
+static eos_intr_handler_t ext_interrupt_handler[PLIC_NUM_INTERRUPTS];
+
+uintptr_t eos_intr_handle(uintptr_t int_num) {
+ if ((int_num >=1) && (int_num <= PLIC_NUM_INTERRUPTS) && (ext_interrupt_handler[int_num-1])) {
+ ext_interrupt_handler[int_num-1]();
+ } else {
+ printf("INTR ERROR:%d\n", int_num);
+ exit(int_num);
+ }
+ return int_num;
+}
+
+int eos_intr_init(uint8_t wakeup_cause) {
+ for (int i = 0; i < PLIC_NUM_INTERRUPTS; i++){
+ ext_interrupt_handler[i] = NULL;
+ }
+
+ /**************************************************************************
+ * Set up the PLIC
+ **************************************************************************/
+ PLIC_init(&plic,
+ PLIC_CTRL_ADDR,
+ PLIC_NUM_INTERRUPTS,
+ PLIC_NUM_PRIORITIES);
+
+ // Enable Global (PLIC) interrupts.
+ set_csr(mie, MIP_MEIP);
+
+ // Enable all interrupts
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return EOS_OK;
+}
+
+void eos_intr_set(uint8_t int_num, uint8_t priority, eos_intr_handler_t handler) {
+ ext_interrupt_handler[int_num-1] = handler;
+ PLIC_set_priority(&plic, int_num, priority);
+ PLIC_enable_interrupt(&plic, int_num);
+}
+
+void eos_intr_set_handler(uint8_t int_num, eos_intr_handler_t handler) {
+ ext_interrupt_handler[int_num-1] = handler;
+}
+
+void eos_intr_set_priority(uint8_t int_num, uint8_t priority) {
+ PLIC_set_priority(&plic, int_num, priority);
+}
+
+void eos_intr_enable(uint8_t int_num) {
+ PLIC_enable_interrupt(&plic, int_num);
+}
+
+void eos_intr_disable(uint8_t int_num) {
+ PLIC_disable_interrupt(&plic, int_num);
+}
+
+void eos_intr_mask(uint8_t priority) {
+ PLIC_set_threshold(&plic, priority);
+}
diff --git a/fw/fe310/eos/soc/interrupt.h b/fw/fe310/eos/soc/interrupt.h
new file mode 100644
index 0000000..a239934
--- /dev/null
+++ b/fw/fe310/eos/soc/interrupt.h
@@ -0,0 +1,13 @@
+#include <stdint.h>
+
+#include "irq_def.h"
+
+typedef void (*eos_intr_handler_t) (void);
+
+int eos_intr_init(uint8_t wakeup_cause);
+void eos_intr_set(uint8_t int_num, uint8_t priority, eos_intr_handler_t handler);
+void eos_intr_set_handler(uint8_t int_num, eos_intr_handler_t handler);
+void eos_intr_set_priority(uint8_t int_num, uint8_t priority);
+void eos_intr_enable(uint8_t int_num);
+void eos_intr_disable(uint8_t int_num);
+void eos_intr_mask(uint8_t priority); \ No newline at end of file
diff --git a/fw/fe310/eos/soc/net.c b/fw/fe310/eos/soc/net.c
new file mode 100644
index 0000000..33b71c2
--- /dev/null
+++ b/fw/fe310/eos/soc/net.c
@@ -0,0 +1,602 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "msgq.h"
+#include "interrupt.h"
+#include "event.h"
+#include "timer.h"
+#include "pwr.h"
+
+#include "board.h"
+
+#include "spi.h"
+#include "spi_priv.h"
+#include "spi_dev.h"
+
+#include "net.h"
+
+#define NET_SIZE_HDR 3
+#define NET_STATE_FLAG_RUN 0x01
+#define NET_STATE_FLAG_INIT 0x02
+#define NET_STATE_FLAG_XCHG 0x04
+#define NET_STATE_FLAG_ONEW 0x10
+#define NET_STATE_FLAG_SYNC 0x20
+#define NET_STATE_FLAG_RTS 0x40
+#define NET_STATE_FLAG_CTS 0x80
+
+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
+
+static EOSBufQ net_buf_q;
+static unsigned char *net_bufq_array[EOS_NET_SIZE_BUFQ];
+static unsigned char net_bufq_buffer[EOS_NET_SIZE_BUFQ][EOS_NET_SIZE_BUF];
+
+static EOSMsgQ net_send_q;
+static EOSMsgItem net_sndq_array[EOS_NET_SIZE_BUFQ];
+
+static volatile uint8_t net_state_flags = 0;
+static unsigned char net_state_type = 0;
+static uint32_t net_state_len_tx = 0;
+static uint32_t net_state_len_rx = 0;
+unsigned char *net_state_buf = NULL;
+
+static uint8_t net_state_next_cnt = 0;
+static unsigned char *net_state_next_buf = NULL;
+
+static eos_evt_handler_t net_handler[EOS_NET_MAX_MTYPE];
+static uint16_t net_wrapper_acq[EOS_EVT_MAX_EVT];
+static uint16_t net_flags_acq[EOS_EVT_MAX_EVT];
+
+static int net_xchg_sleep(void) {
+ int i;
+ int rv = EOS_OK;
+ volatile uint32_t x = 0;
+ net_state_flags &= ~NET_STATE_FLAG_CTS;
+
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+
+ SPI1_REG(SPI_REG_TXFIFO) = 0xFF;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ if (x & 0xFF) rv = EOS_ERR_BUSY;
+
+ for (i=0; i<7; i++) {
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = 0;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ }
+
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+
+ return rv;
+}
+
+static void net_xchg_wake(void) {
+ int i;
+ volatile uint32_t x = 0;
+ net_state_flags &= ~NET_STATE_FLAG_CTS;
+
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+
+ for (i=0; i<8; i++) {
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = 0;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ }
+
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+}
+
+static void net_xchg_reset(void) {
+ volatile uint32_t x = 0;
+ net_state_flags &= ~NET_STATE_FLAG_CTS;
+
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+
+ SPI1_REG(SPI_REG_TXFIFO) = 0;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+}
+
+static void net_xchg_start(unsigned char type, unsigned char *buffer, uint16_t len) {
+ net_state_flags &= ~NET_STATE_FLAG_CTS;
+ net_state_flags |= (NET_STATE_FLAG_INIT | NET_STATE_FLAG_XCHG);
+
+ if (net_state_next_cnt && (net_state_next_buf == NULL)) type |= EOS_NET_MTYPE_FLAG_ONEW;
+ if (type & EOS_NET_MTYPE_FLAG_ONEW) net_state_flags |= NET_STATE_FLAG_ONEW;
+
+ net_state_type = type;
+ net_state_len_tx = len;
+ net_state_len_rx = 0;
+ net_state_buf = buffer;
+
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+ SPI1_REG(SPI_REG_TXFIFO) = type;
+ SPI1_REG(SPI_REG_TXFIFO) = (len >> 8) & 0xFF;
+ SPI1_REG(SPI_REG_TXFIFO) = (len & 0xFF);
+ SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(2);
+ SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM;
+}
+
+static int net_xchg_next(unsigned char *_buffer) {
+ unsigned char type;
+ unsigned char *buffer = NULL;
+ uint16_t len;
+ int ret = _buffer ? 1 : 0;
+
+ eos_msgq_pop(&net_send_q, &type, &buffer, &len);
+ if (type) {
+ net_xchg_start(type, buffer, len);
+ } else if (net_state_flags & NET_STATE_FLAG_RTS) {
+ if (_buffer) {
+ buffer = _buffer;
+ ret = 0;
+ } else {
+ buffer = eos_bufq_pop(&net_buf_q);
+ }
+ if (buffer) net_xchg_start(0, buffer, 0);
+ }
+
+ return ret;
+}
+
+static void net_handle_xchg(void) {
+ volatile uint32_t r1, r2, r3;
+ uint32_t len;
+
+ if (net_state_flags & NET_STATE_FLAG_INIT) {
+ net_state_flags &= ~NET_STATE_FLAG_INIT;
+
+ r1 = SPI1_REG(SPI_REG_RXFIFO);
+ r2 = SPI1_REG(SPI_REG_RXFIFO);
+ r3 = SPI1_REG(SPI_REG_RXFIFO);
+
+ if (net_state_flags & NET_STATE_FLAG_ONEW) {
+ r1 = 0;
+ r2 = 0;
+ r3 = 0;
+ }
+
+ net_state_type = (r1 & 0xFF);
+ net_state_len_rx = (r2 & 0xFF) << 8;
+ net_state_len_rx |= (r3 & 0xFF);
+ len = MAX(net_state_len_tx, net_state_len_rx);
+
+ if (len > EOS_NET_MTU) {
+ net_state_flags &= ~NET_STATE_FLAG_XCHG;
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+ SPI1_REG(SPI_REG_IE) = 0x0;
+ return;
+ }
+
+ // esp32 dma workaraund
+ if (len < 8 - NET_SIZE_HDR) {
+ len = 8 - NET_SIZE_HDR;
+ } else if ((len + NET_SIZE_HDR) % 4 != 0) {
+ len = ((len + NET_SIZE_HDR)/4 + 1) * 4 - NET_SIZE_HDR;
+ }
+
+ _eos_spi_xchg_init(net_state_buf, len, 0);
+ SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_WM);
+ SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM;
+ return;
+ }
+
+ eos_spi_handle_xchg();
+ if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_AUTO) { // exchange done
+ if (!(net_state_flags & NET_STATE_FLAG_SYNC)) {
+ if (net_state_type) {
+ int r = eos_evtq_push_isr(EOS_EVT_NET | net_state_type, net_state_buf, net_state_len_rx);
+ if (r) eos_bufq_push(&net_buf_q, net_state_buf);
+ } else if (((net_state_flags & NET_STATE_FLAG_ONEW) || net_state_next_cnt) && (net_state_next_buf == NULL)) {
+ net_state_next_buf = net_state_buf;
+ } else {
+ eos_bufq_push(&net_buf_q, net_state_buf);
+ }
+ }
+ net_state_flags &= ~(NET_STATE_FLAG_ONEW | NET_STATE_FLAG_XCHG);
+ }
+}
+
+static void net_handle_cts(void) {
+ GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS);
+ net_state_flags |= NET_STATE_FLAG_CTS;
+
+ if (net_state_flags & NET_STATE_FLAG_RUN) {
+ net_xchg_next(NULL);
+ }
+}
+
+static void net_handle_rts(void) {
+ uint32_t rts_offset = (1 << NET_PIN_RTS);
+
+ if (GPIO_REG(GPIO_RISE_IP) & rts_offset) {
+ GPIO_REG(GPIO_RISE_IP) = rts_offset;
+ net_state_flags |= NET_STATE_FLAG_RTS;
+ if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) {
+ net_xchg_reset();
+ }
+ } else if (GPIO_REG(GPIO_FALL_IP) & rts_offset) {
+ GPIO_REG(GPIO_FALL_IP) = rts_offset;
+ net_state_flags &= ~NET_STATE_FLAG_RTS;
+ }
+}
+
+static void net_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
+ unsigned char idx = (type & ~EOS_EVT_MASK) - 1;
+
+ if (idx < EOS_NET_MAX_MTYPE) {
+ net_handler[idx](type, buffer, len);
+ } else {
+ eos_net_bad_handler(type, buffer, len);
+ }
+}
+
+static int net_acquire(unsigned char reserved) {
+ int ret = 0;
+
+ if (reserved) {
+ while (!ret) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (net_state_next_buf) {
+ ret = 1;
+ net_state_next_cnt--;
+ } else {
+ asm volatile ("wfi");
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+ } else {
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (net_state_next_buf == NULL) net_state_next_buf = eos_bufq_pop(&net_buf_q);
+ ret = (net_state_next_buf != NULL);
+ if (!ret) net_state_next_cnt++;
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+ return ret;
+}
+
+static void evt_handler_wrapper(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char idx, uint16_t flag) {
+ int ok;
+
+ ok = net_acquire(net_wrapper_acq[idx] & flag);
+ if (ok) {
+ eos_evtq_get_handler(type)(type, buffer, len);
+ eos_net_release();
+ net_wrapper_acq[idx] &= ~flag;
+ } else {
+ net_wrapper_acq[idx] |= flag;
+ eos_evtq_push(type, buffer, len);
+ }
+}
+
+static void evt_handler(unsigned char type, unsigned char *buffer, uint16_t len) {
+ unsigned char idx = (type & EOS_EVT_MASK) >> 4;
+
+ if (idx && (idx <= EOS_EVT_MAX_EVT)) {
+ uint16_t flag = (uint16_t)1 << (type & ~EOS_EVT_MASK);
+
+ idx--;
+ if (flag & net_flags_acq[idx]) {
+ evt_handler_wrapper(type, buffer, len, idx, flag);
+ } else {
+ eos_evtq_get_handler(type)(type, buffer, len);
+ }
+ } else {
+ eos_evtq_bad_handler(type, buffer, len);
+ }
+}
+
+static void net_pause(void) {
+ net_state_flags &= ~NET_STATE_FLAG_RUN;
+}
+
+static void net_resume(void) {
+ net_state_flags |= NET_STATE_FLAG_RUN;
+ if (net_state_flags & NET_STATE_FLAG_CTS) {
+ net_xchg_next(NULL);
+ }
+}
+
+static void net_start(void) {
+ eos_intr_set_handler(INT_SPI1_BASE, net_handle_xchg);
+ SPI1_REG(SPI_REG_SCKDIV) = eos_spi_div(EOS_SPI_DEV_NET);
+ SPI1_REG(SPI_REG_CSID) = eos_spi_csid(EOS_SPI_DEV_NET);
+}
+
+static void net_stop(void) {
+ eos_intr_set_handler(INT_SPI1_BASE, NULL);
+}
+
+int eos_net_init(uint8_t wakeup_cause) {
+ int i;
+
+ eos_msgq_init(&net_send_q, net_sndq_array, EOS_NET_SIZE_BUFQ);
+ eos_bufq_init(&net_buf_q, net_bufq_array, EOS_NET_SIZE_BUFQ);
+ for (i=0; i<EOS_NET_SIZE_BUFQ; i++) {
+ eos_bufq_push(&net_buf_q, net_bufq_buffer[i]);
+ }
+
+ for (i=0; i<EOS_NET_MAX_MTYPE; i++) {
+ net_handler[i] = eos_net_bad_handler;
+ }
+ eos_evtq_set_handler(0, evt_handler);
+ eos_evtq_set_handler(EOS_EVT_NET, net_handle_evt);
+
+ GPIO_REG(GPIO_INPUT_EN) |= (1 << NET_PIN_CTS);
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << NET_PIN_CTS);
+
+ GPIO_REG(GPIO_RISE_IE) |= (1 << NET_PIN_CTS);
+ eos_intr_set(INT_GPIO_BASE + NET_PIN_CTS, IRQ_PRIORITY_NET_CTS, net_handle_cts);
+
+ GPIO_REG(GPIO_INPUT_EN) |= (1 << NET_PIN_RTS);
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << NET_PIN_RTS);
+
+ GPIO_REG(GPIO_RISE_IE) |= (1 << NET_PIN_RTS);
+ GPIO_REG(GPIO_FALL_IE) |= (1 << NET_PIN_RTS);
+ eos_intr_set(INT_GPIO_BASE + NET_PIN_RTS, IRQ_PRIORITY_NET_RTS, net_handle_rts);
+
+ /* set initial state */
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (GPIO_REG(GPIO_INPUT_VAL) & (1 << NET_PIN_CTS)) net_state_flags |= NET_STATE_FLAG_CTS;
+ if (GPIO_REG(GPIO_INPUT_VAL) & (1 << NET_PIN_RTS)) net_state_flags |= NET_STATE_FLAG_RTS;
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return EOS_OK;
+}
+
+int eos_net_run(uint8_t wakeup_cause) {
+ net_start();
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (wakeup_cause != EOS_PWR_WAKE_RST) {
+ if (wakeup_cause != EOS_PWR_WAKE_BTN) {
+ net_xchg_wake();
+ }
+ if (!(net_state_flags & NET_STATE_FLAG_CTS)) {
+ while (!(GPIO_REG(GPIO_RISE_IP) & (1 << NET_PIN_CTS))) {
+ asm volatile ("wfi");
+ }
+ GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS);
+ }
+ net_xchg_reset();
+ }
+ net_resume();
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return EOS_OK;
+}
+
+void eos_net_start(void) {
+ net_start();
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ net_resume();
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_net_stop(void) {
+ uint8_t done = 0;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (net_state_flags & NET_STATE_FLAG_RUN) {
+ net_state_flags &= ~NET_STATE_FLAG_RUN;
+ done = !(net_state_flags & NET_STATE_FLAG_XCHG);
+ } else {
+ done = 1;
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+
+ while (!done) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ done = !(net_state_flags & NET_STATE_FLAG_XCHG);
+ if (!done) asm volatile ("wfi");
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+ net_stop();
+}
+
+int eos_net_sleep(uint32_t timeout) {
+ volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ uint64_t then_ms = timeout + *mtime * 1000 / EOS_TIMER_RTC_FREQ;
+ uint8_t done = 0;
+ int rv = EOS_OK;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (!(net_state_flags & NET_STATE_FLAG_RUN)) rv = EOS_ERR;
+ set_csr(mstatus, MSTATUS_MIE);
+
+ if (rv) return rv;
+
+ do {
+ if (*mtime * 1000 / EOS_TIMER_RTC_FREQ > then_ms) return EOS_ERR_TIMEOUT;
+ clear_csr(mstatus, MSTATUS_MIE);
+ eos_evtq_flush_isr();
+ done = (eos_msgq_len(&net_send_q) == 0);
+ done = done && (!(net_state_flags & NET_STATE_FLAG_RTS) && (net_state_flags & NET_STATE_FLAG_CTS));
+ if (done) done = (net_xchg_sleep() == EOS_OK);
+ if (!done) {
+ asm volatile ("wfi");
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+ } while (!done);
+
+ while (!(GPIO_REG(GPIO_RISE_IP) & (1 << NET_PIN_CTS))) {
+ if (*mtime * 1000 / EOS_TIMER_RTC_FREQ > then_ms) {
+ rv = EOS_ERR_TIMEOUT;
+ break;
+ }
+ asm volatile ("wfi");
+ }
+
+ if (!rv) {
+ GPIO_REG(GPIO_RISE_IP) = (1 << NET_PIN_CTS);
+ net_state_flags &= ~NET_STATE_FLAG_RUN;
+ }
+
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return rv;
+}
+
+void eos_net_bad_handler(unsigned char type, unsigned char *buffer, uint16_t len) {
+ eos_evtq_bad_handler(type, buffer, len);
+ if (buffer) eos_net_free(buffer, 0);
+}
+
+void eos_net_set_handler(unsigned char mtype, eos_evt_handler_t handler) {
+ if (handler == NULL) handler = eos_net_bad_handler;
+ if (mtype && (mtype <= EOS_NET_MAX_MTYPE)) net_handler[mtype - 1] = handler;
+}
+
+void eos_net_acquire_for_evt(unsigned char type, char acq) {
+ unsigned char idx = (type & EOS_EVT_MASK) >> 4;
+ uint16_t flag = type & ~EOS_EVT_MASK ? (uint16_t)1 << (type & ~EOS_EVT_MASK) : 0xFFFF;
+
+ if (idx && (idx <= EOS_EVT_MAX_EVT)) {
+ idx--;
+ net_flags_acq[idx] &= ~flag;
+ if (acq) net_flags_acq[idx] |= flag;
+ }
+}
+
+void eos_net_acquire(void) {
+ unsigned char acq = net_acquire(0);
+ if (!acq) net_acquire(1);
+}
+
+void eos_net_release(void) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (!net_state_next_cnt && net_state_next_buf) {
+ eos_bufq_push(&net_buf_q, net_state_next_buf);
+ net_state_next_buf = NULL;
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+unsigned char *eos_net_alloc(void) {
+ unsigned char *ret = NULL;
+
+ while (!ret) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (net_state_next_buf) {
+ ret = net_state_next_buf;
+ net_state_next_buf = NULL;
+ } else {
+ asm volatile ("wfi");
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+
+ return ret;
+}
+
+void eos_net_free(unsigned char *buffer, unsigned char more) {
+ uint8_t do_release = 1;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ if ((more || net_state_next_cnt) && (net_state_next_buf == NULL)) {
+ net_state_next_buf = buffer;
+ } else {
+ if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) {
+ do_release = net_xchg_next(buffer);
+ }
+ if (do_release) {
+ eos_bufq_push(&net_buf_q, buffer);
+ }
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+static int net_xchg(unsigned char *type, unsigned char *buffer, uint16_t *len, unsigned char flags) {
+ int rv = EOS_OK;
+ int _sync = 0;
+ unsigned char _type = *type;
+ uint16_t _len = *len;
+ uint8_t spi_dev = EOS_SPI_DEV_NET;
+
+ if (flags & EOS_NET_FLAG_ONEW) _type |= EOS_NET_MTYPE_FLAG_ONEW;
+ if (flags & EOS_NET_FLAG_REPL) _type |= EOS_NET_MTYPE_FLAG_REPL;
+ if (flags & EOS_NET_FLAG_SYNC) _sync = 1;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ if ((flags & EOS_NET_FLAG_ONEW) && !(net_state_flags & NET_STATE_FLAG_RUN)) _sync = 1;
+
+ if (_sync && !(net_state_flags & NET_STATE_FLAG_RUN)) {
+ int _rv;
+
+ set_csr(mstatus, MSTATUS_MIE);
+ spi_dev = eos_spi_dev();
+ _rv = eos_spi_deselect();
+ if (_rv) return _rv;
+ clear_csr(mstatus, MSTATUS_MIE);
+ }
+
+ if (_sync) {
+ net_pause();
+ while (!(net_state_flags & NET_STATE_FLAG_CTS)) {
+ asm volatile ("wfi");
+ set_csr(mstatus, MSTATUS_MIE);
+ clear_csr(mstatus, MSTATUS_MIE);
+ }
+ if (flags & EOS_NET_FLAG_SYNC) {
+ net_state_flags |= NET_STATE_FLAG_SYNC;
+ }
+ net_xchg_start(_type, buffer, _len);
+ if (flags & EOS_NET_FLAG_SYNC) {
+ if (flags & EOS_NET_FLAG_REPL) {
+ while (!(net_state_flags & NET_STATE_FLAG_CTS)) {
+ asm volatile ("wfi");
+ set_csr(mstatus, MSTATUS_MIE);
+ clear_csr(mstatus, MSTATUS_MIE);
+ }
+ net_xchg_start(0, buffer, 0);
+ }
+ while (net_state_flags & NET_STATE_FLAG_XCHG) {
+ asm volatile ("wfi");
+ set_csr(mstatus, MSTATUS_MIE);
+ clear_csr(mstatus, MSTATUS_MIE);
+ }
+ net_state_flags &= ~NET_STATE_FLAG_SYNC;
+ *type = net_state_type;
+ *len = net_state_len_rx;
+ }
+ net_resume();
+ } else {
+ if ((net_state_flags & NET_STATE_FLAG_RUN) && (net_state_flags & NET_STATE_FLAG_CTS)) {
+ net_xchg_start(_type, buffer, _len);
+ } else {
+ rv = eos_msgq_push(&net_send_q, _type, buffer, _len);
+ if (rv) eos_bufq_push(&net_buf_q, buffer);
+ }
+ }
+
+ set_csr(mstatus, MSTATUS_MIE);
+ if (spi_dev != EOS_SPI_DEV_NET) eos_spi_select(spi_dev);
+
+ return rv;
+}
+
+int eos_net_xchg(unsigned char *type, unsigned char *buffer, uint16_t *len) {
+ return net_xchg(type, buffer, len, (EOS_NET_FLAG_ONEW | EOS_NET_FLAG_SYNC | EOS_NET_FLAG_REPL));
+}
+
+int eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len) {
+ return net_xchg(&type, buffer, &len, (EOS_NET_FLAG_ONEW | EOS_NET_FLAG_SYNC));
+}
+
+int eos_net_send_async(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char more) {
+ return net_xchg(&type, buffer, &len, more ? EOS_NET_FLAG_ONEW : 0);
+}
+
+int _eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char async, unsigned char more) {
+ if (async) {
+ eos_net_send_async(type, buffer, len, more);
+ } else {
+ eos_net_send(type, buffer, len);
+ }
+}
diff --git a/fw/fe310/eos/soc/net.h b/fw/fe310/eos/soc/net.h
new file mode 100644
index 0000000..79caf4b
--- /dev/null
+++ b/fw/fe310/eos/soc/net.h
@@ -0,0 +1,47 @@
+#include <stdint.h>
+#include "event.h"
+
+/* common */
+#define EOS_NET_MTU 1500
+#define EOS_NET_SIZE_BUF EOS_NET_MTU
+
+#define EOS_NET_MTYPE_SOCK 1
+#define EOS_NET_MTYPE_RNG 3
+#define EOS_NET_MTYPE_POWER 4
+
+#define EOS_NET_MTYPE_WIFI 5
+#define EOS_NET_MTYPE_CELL 6
+#define EOS_NET_MTYPE_SIP 7
+#define EOS_NET_MTYPE_APP 8
+
+#define EOS_NET_MAX_MTYPE 8
+
+#define EOS_NET_MTYPE_FLAG_ONEW 0x40
+#define EOS_NET_MTYPE_FLAG_REPL 0x80
+#define EOS_NET_MTYPE_FLAG_MASK 0xc0
+
+/* fe310 specific */
+#define EOS_NET_SIZE_BUFQ 2
+
+#define EOS_NET_FLAG_ONEW 0x1
+#define EOS_NET_FLAG_SYNC 0x2
+#define EOS_NET_FLAG_REPL 0x4
+
+int eos_net_init(uint8_t wakeup_cause);
+int eos_net_run(uint8_t wakeup_cause);
+void eos_net_start(void);
+void eos_net_stop(void);
+int eos_net_sleep(uint32_t timeout);
+
+void eos_net_bad_handler(unsigned char type, unsigned char *buffer, uint16_t len);
+void eos_net_set_handler(unsigned char type, eos_evt_handler_t handler);
+void eos_net_acquire_for_evt(unsigned char type, char acq);
+
+void eos_net_acquire(void);
+void eos_net_release(void);
+unsigned char *eos_net_alloc(void);
+void eos_net_free(unsigned char *buffer, unsigned char more);
+int eos_net_xchg(unsigned char *type, unsigned char *buffer, uint16_t *len);
+int eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len);
+int eos_net_send_async(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char more);
+int _eos_net_send(unsigned char type, unsigned char *buffer, uint16_t len, unsigned char async, unsigned char more);
diff --git a/fw/fe310/eos/soc/pwr.c b/fw/fe310/eos/soc/pwr.c
new file mode 100644
index 0000000..802e593
--- /dev/null
+++ b/fw/fe310/eos/soc/pwr.c
@@ -0,0 +1,133 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "event.h"
+#include "timer.h"
+#include "spi.h"
+#include "spi_dev.h"
+#include "net.h"
+#include "lcd.h"
+#include "eve/eve.h"
+
+#include "pwr.h"
+
+#define PWR_RTC_SCALE 15
+#define PWR_RTC_SFREQ (EOS_TIMER_RTC_FREQ >> PWR_RTC_SCALE)
+
+static eos_evt_handler_t evt_handler[EOS_PWR_MAX_MTYPE];
+static unsigned char power_btn_down;
+
+int eos_pwr_init(uint8_t wakeup_cause) {
+ AON_REG(AON_PMUKEY) = 0x51F15E;
+ AON_REG(AON_PMUIE) = 0x5;
+
+ AON_REG(AON_RTCCMP) = 0xFFFFFFFF;
+ AON_REG(AON_RTCCFG) = PWR_RTC_SCALE;
+ AON_REG(AON_RTCHI) = 0;
+ AON_REG(AON_RTCLO) = 0;
+
+ return EOS_OK;
+}
+
+uint8_t eos_pwr_wakeup_cause(void) {
+ return AON_REG(AON_PMUCAUSE) & 0xff;
+}
+
+uint8_t eos_pwr_reset_cause(void) {
+ return (AON_REG(AON_PMUCAUSE) >> 8) & 0xff;
+}
+
+int eos_pwr_sleep(void) {
+ int rv;
+
+ rv = eos_lcd_sleep();
+ if (rv) return rv;
+
+ eos_spi_select(EOS_SPI_DEV_EVE);
+ eve_pwr_sleep();
+ eos_spi_deselect();
+
+ rv = eos_net_sleep(1000);
+ if (rv) return rv;
+
+ AON_REG(AON_PMUKEY) = 0x51F15E;
+ AON_REG(AON_PMUSLEEP) = 1;
+
+ return EOS_OK;
+}
+
+void eos_pwr_wake_at(uint32_t msec) {
+ uint32_t pmuie;
+
+ AON_REG(AON_RTCCFG) |= AON_RTCCFG_ENALWAYS;
+ AON_REG(AON_RTCCMP) = msec * PWR_RTC_SFREQ / 1000;
+
+ pmuie = AON_REG(AON_PMUIE) | 0x2;
+ AON_REG(AON_PMUKEY) = 0x51F15E;
+ AON_REG(AON_PMUIE) = pmuie;
+}
+
+void eos_pwr_wake_disable(void) {
+ uint32_t pmuie;
+
+ AON_REG(AON_RTCCMP) = 0xFFFFFFFF;
+ AON_REG(AON_RTCCFG) &= ~AON_RTCCFG_ENALWAYS;
+ AON_REG(AON_RTCHI) = 0;
+ AON_REG(AON_RTCLO) = 0;
+
+ pmuie = AON_REG(AON_PMUIE) & ~0x2;
+ AON_REG(AON_PMUKEY) = 0x51F15E;
+ AON_REG(AON_PMUIE) = pmuie;
+}
+
+static void pwr_handle_msg(unsigned char type, unsigned char *buffer, uint16_t len) {
+ unsigned char mtype;
+
+ if ((buffer == NULL) || (len < 1)) {
+ eos_net_bad_handler(type, buffer, len);
+ return;
+ }
+
+ mtype = buffer[0];
+ if ((mtype < EOS_PWR_MAX_MTYPE) && evt_handler[mtype]) {
+ evt_handler[mtype](mtype, buffer, len);
+ } else {
+ eos_net_bad_handler(type, buffer, len);
+ }
+}
+
+static void pwr_handle_btn(unsigned char type, unsigned char *buffer, uint16_t len) {
+ unsigned char level = buffer[1];
+
+ eos_net_free(buffer, 0);
+ if (!level) {
+ power_btn_down = 1;
+ return;
+ }
+ if (!power_btn_down) return;
+
+ eos_pwr_sleep();
+}
+
+void eos_pwr_netinit(void) {
+ int i;
+
+ for (i=0; i<EOS_PWR_MAX_MTYPE; i++) {
+ evt_handler[i] = NULL;
+ }
+ eos_net_set_handler(EOS_NET_MTYPE_POWER, pwr_handle_msg);
+ eos_pwr_set_handler(EOS_PWR_MTYPE_BUTTON, pwr_handle_btn);
+}
+
+void eos_pwr_set_handler(unsigned char mtype, eos_evt_handler_t handler) {
+ if (mtype < EOS_PWR_MAX_MTYPE) evt_handler[mtype] = handler;
+}
+
+eos_evt_handler_t eos_pwr_get_handler(unsigned char mtype) {
+ if (mtype < EOS_PWR_MAX_MTYPE) return evt_handler[mtype];
+ return NULL;
+}
diff --git a/fw/fe310/eos/soc/pwr.h b/fw/fe310/eos/soc/pwr.h
new file mode 100644
index 0000000..264436b
--- /dev/null
+++ b/fw/fe310/eos/soc/pwr.h
@@ -0,0 +1,25 @@
+#include <stdint.h>
+#include "event.h"
+
+#define EOS_PWR_MTYPE_BUTTON 1
+
+#define EOS_PWR_MAX_MTYPE 2
+
+#define EOS_PWR_WAKE_RST 0
+#define EOS_PWR_WAKE_RTC 1
+#define EOS_PWR_WAKE_BTN 2
+
+#define EOS_PWR_RST_PWRON 0
+#define EOS_PWR_RST_EXT 1
+#define EOS_PWR_RST_WDOG 2
+
+int eos_pwr_init(uint8_t wakeup_cause);
+uint8_t eos_pwr_wakeup_cause(void);
+uint8_t eos_pwr_reset_cause(void);
+int eos_pwr_sleep(void);
+void eos_pwr_wake_at(uint32_t msec);
+void eos_pwr_wake_disable(void);
+
+void eos_pwr_netinit(void);
+void eos_pwr_set_handler(unsigned char mtype, eos_evt_handler_t handler);
+eos_evt_handler_t eos_pwr_get_handler(unsigned char mtype); \ No newline at end of file
diff --git a/fw/fe310/eos/soc/spi.c b/fw/fe310/eos/soc/spi.c
new file mode 100644
index 0000000..05c9448
--- /dev/null
+++ b/fw/fe310/eos/soc/spi.c
@@ -0,0 +1,350 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "msgq.h"
+#include "interrupt.h"
+#include "event.h"
+
+#include "board.h"
+
+#include "spi.h"
+#include "spi_priv.h"
+
+#define SPI_MODE0 0x00
+#define SPI_MODE1 0x01
+#define SPI_MODE2 0x02
+#define SPI_MODE3 0x03
+
+#define SPI_FLAG_XCHG 0x10
+
+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
+
+static uint8_t spi_cspin;
+static volatile uint8_t spi_state_flags;
+static unsigned char spi_evt;
+static unsigned char spi_in_xchg;
+
+static uint32_t spi_state_len = 0;
+static uint32_t spi_state_idx_tx = 0;
+static uint32_t spi_state_idx_rx = 0;
+static unsigned char *spi_state_buf = NULL;
+
+static eos_evt_handler_t evt_handler[EOS_SPI_MAX_EVT];
+
+static void spi_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
+ unsigned char idx = (type & ~EOS_EVT_MASK) - 1;
+ if (idx < EOS_SPI_MAX_EVT) {
+ evt_handler[idx](type, buffer, len);
+ } else {
+ eos_evtq_bad_handler(type, buffer, len);
+ }
+}
+
+int eos_spi_init(uint8_t wakeup_cause) {
+ int i;
+
+ for (i=0; i<EOS_SPI_MAX_EVT; i++) {
+ evt_handler[i] = eos_evtq_bad_handler;
+ }
+ eos_evtq_set_handler(EOS_EVT_SPI, spi_handle_evt);
+ eos_intr_set(INT_SPI1_BASE, IRQ_PRIORITY_SPI_XCHG, NULL);
+
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << IOF_SPI1_SCK);
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << IOF_SPI1_MOSI);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << IOF_SPI1_SCK);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << IOF_SPI1_SCK);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << IOF_SPI1_MOSI);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << IOF_SPI1_MOSI);
+
+ GPIO_REG(GPIO_INPUT_EN) |= (1 << IOF_SPI1_MISO);
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << IOF_SPI1_MISO);
+
+ SPI1_REG(SPI_REG_SCKMODE) = SPI_MODE0;
+ SPI1_REG(SPI_REG_FMT) = SPI_FMT_PROTO(SPI_PROTO_S) |
+ SPI_FMT_ENDIAN(SPI_ENDIAN_MSB) |
+ SPI_FMT_DIR(SPI_DIR_RX) |
+ SPI_FMT_LEN(8);
+
+ GPIO_REG(GPIO_IOF_SEL) &= ~SPI_IOF_MASK;
+ GPIO_REG(GPIO_IOF_EN) |= SPI_IOF_MASK;
+
+ // There is no way here to change the CS polarity.
+ // SPI1_REG(SPI_REG_CSDEF) = 0xFFFF;
+ return EOS_OK;
+}
+
+void eos_spi_start(uint16_t div, uint8_t csid, uint8_t cspin, unsigned char evt) {
+ spi_state_flags = 0;
+ spi_evt = evt;
+ SPI1_REG(SPI_REG_SCKDIV) = div;
+ SPI1_REG(SPI_REG_CSID) = csid;
+ if (csid != SPI_CSID_NONE) {
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+ } else {
+ spi_cspin = cspin;
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_OFF;
+ }
+ eos_intr_set_handler(INT_SPI1_BASE, eos_spi_handle_xchg);
+}
+
+void eos_spi_stop(void) {
+ eos_spi_flush();
+ eos_intr_set_handler(INT_SPI1_BASE, NULL);
+ spi_evt = 0;
+}
+
+void eos_spi_set_handler(unsigned char evt, eos_evt_handler_t handler) {
+ if (handler == NULL) handler = eos_evtq_bad_handler;
+ if (evt && (evt <= EOS_SPI_MAX_EVT)) evt_handler[evt - 1] = handler;
+}
+
+void _eos_spi_xchg_init(unsigned char *buffer, uint16_t len, uint8_t flags) {
+ spi_state_flags &= 0xF0;
+ spi_state_flags |= (SPI_FLAG_XCHG | flags);
+ spi_state_buf = buffer;
+ spi_state_len = len;
+ spi_state_idx_tx = 0;
+ spi_state_idx_rx = 0;
+}
+
+static void spi_xchg_finish(void) {
+ uint8_t done = 0;
+
+ while (!done) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ done = !(spi_state_flags & SPI_FLAG_XCHG);
+ if (!done) asm volatile ("wfi");
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+ spi_in_xchg = 0;
+}
+
+void eos_spi_xchg(unsigned char *buffer, uint16_t len, uint8_t flags) {
+ if (spi_in_xchg) spi_xchg_finish();
+
+ spi_in_xchg = 1;
+ _eos_spi_xchg_init(buffer, len, flags);
+
+ eos_spi_cs_set();
+ SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_WM);
+ SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM;
+}
+
+void eos_spi_handle_xchg(void) {
+ int i;
+ uint16_t sz_chunk = MIN(spi_state_len - spi_state_idx_tx, SPI_SIZE_CHUNK);
+
+ for (i=0; i<sz_chunk; i++) {
+ volatile uint32_t x = SPI1_REG(SPI_REG_TXFIFO);
+ if (x & SPI_TXFIFO_FULL) break;
+ SPI1_REG(SPI_REG_TXFIFO) = spi_state_buf[spi_state_idx_tx+i];
+ }
+ spi_state_idx_tx += i;
+
+ for (i=0; i<spi_state_idx_tx - spi_state_idx_rx; i++) {
+ volatile uint32_t x = SPI1_REG(SPI_REG_RXFIFO);
+ if (x & SPI_RXFIFO_EMPTY) break;
+ spi_state_buf[spi_state_idx_rx+i] = x & 0xFF;
+ }
+ spi_state_idx_rx += i;
+
+ if (spi_state_idx_tx == spi_state_len) {
+ if ((spi_state_idx_rx == spi_state_len) || (spi_state_flags & EOS_SPI_FLAG_TX)) {
+ spi_state_flags &= ~SPI_FLAG_XCHG;
+ if (!(spi_state_flags & EOS_SPI_FLAG_MORE)) eos_spi_cs_clear();
+ SPI1_REG(SPI_REG_IE) = 0x0;
+ if (spi_evt) eos_evtq_push_isr(EOS_EVT_SPI | spi_evt, spi_state_buf, spi_state_len);
+ } else {
+ SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(MIN(spi_state_len - spi_state_idx_rx - 1, SPI_SIZE_WM - 1));
+ SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM;
+ }
+ }
+}
+
+void eos_spi_cs_set(void) {
+ /* cs low */
+ if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) {
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << spi_cspin);
+ } else {
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+ }
+}
+
+void eos_spi_cs_clear(void) {
+ /* cs high */
+ if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) {
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << spi_cspin);
+ } else {
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+ }
+}
+
+uint8_t eos_spi_xchg8(uint8_t data, uint8_t flags) {
+ volatile uint32_t x = 0;
+ uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
+
+ spi_state_flags &= 0xF0;
+ spi_state_flags |= flags;
+
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = data;
+
+ if (rx) {
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ }
+
+ return x & 0xFF;
+}
+
+uint16_t eos_spi_xchg16(uint16_t data, uint8_t flags) {
+ volatile uint32_t x = 0;
+ uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
+ uint16_t r = 0;
+
+ spi_state_flags &= 0xF0;
+ spi_state_flags |= flags;
+
+ if (flags & EOS_SPI_FLAG_BSWAP) {
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF);
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF00) >> 8;
+ } else {
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF00) >> 8;
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF);
+ }
+
+ if (rx) {
+ if (flags & EOS_SPI_FLAG_BSWAP) {
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF);
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 8;
+ } else {
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 8;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF);
+ }
+ }
+
+ return r;
+}
+
+uint32_t eos_spi_xchg24(uint32_t data, uint8_t flags) {
+ volatile uint32_t x = 0;
+ uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
+ uint32_t r = 0;
+
+ spi_state_flags &= 0xF0;
+ spi_state_flags |= flags;
+
+ if (flags & EOS_SPI_FLAG_BSWAP) {
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
+ } else {
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
+ }
+
+ if (rx) {
+ if (flags & EOS_SPI_FLAG_BSWAP) {
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF);
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 8;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 16;
+ } else {
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 16;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 8;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF);
+ }
+ }
+
+ return r;
+}
+
+uint32_t eos_spi_xchg32(uint32_t data, uint8_t flags) {
+ volatile uint32_t x = 0;
+ uint8_t rx = !(flags & EOS_SPI_FLAG_TX);
+ uint32_t r = 0;
+
+ spi_state_flags &= 0xF0;
+ spi_state_flags |= flags;
+
+ if (flags & EOS_SPI_FLAG_BSWAP) {
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF000000) >> 24;
+ } else {
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0xFF000000) >> 24;
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x00FF0000) >> 16;
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x0000FF00) >> 8;
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = (data & 0x000000FF);
+ }
+
+ if (rx) {
+ if (flags & EOS_SPI_FLAG_BSWAP) {
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF);
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 8;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 16;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 24;
+ } else {
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 24;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 16;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF) << 8;
+ while ((x = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ r |= (x & 0xFF);
+ }
+ }
+
+ return r;
+}
+
+void eos_spi_flush(void) {
+ volatile uint32_t x = 0;
+
+ if (spi_in_xchg) spi_xchg_finish();
+
+ SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(1);
+ while (!x) {
+ if (SPI1_REG(SPI_REG_IP) & SPI_IP_TXWM) x = SPI1_REG(SPI_REG_RXFIFO) & SPI_RXFIFO_EMPTY;
+ }
+}
diff --git a/fw/fe310/eos/soc/spi.h b/fw/fe310/eos/soc/spi.h
new file mode 100644
index 0000000..a23a235
--- /dev/null
+++ b/fw/fe310/eos/soc/spi.h
@@ -0,0 +1,28 @@
+#include <stdint.h>
+#include "event.h"
+
+#define EOS_SPI_FLAG_TX 0x01
+#define EOS_SPI_FLAG_MORE 0x02
+#define EOS_SPI_FLAG_BSWAP 0x04
+
+#define EOS_SPI_EVT_SDC 1
+#define EOS_SPI_EVT_CAM 2
+
+#define EOS_SPI_MAX_EVT 2
+
+int eos_spi_init(uint8_t wakeup_cause);
+void eos_spi_start(uint16_t div, uint8_t csid, uint8_t cspin, unsigned char evt);
+void eos_spi_stop(void);
+void eos_spi_set_handler(unsigned char evt, eos_evt_handler_t handler);
+
+void _eos_spi_xchg_init(unsigned char *buffer, uint16_t len, uint8_t flags);
+void eos_spi_xchg(unsigned char *buffer, uint16_t len, uint8_t flags);
+void eos_spi_handle_xchg(void);
+
+void eos_spi_cs_set(void);
+void eos_spi_cs_clear(void);
+uint8_t eos_spi_xchg8(uint8_t data, uint8_t flags);
+uint16_t eos_spi_xchg16(uint16_t data, uint8_t flags);
+uint32_t eos_spi_xchg24(uint32_t data, uint8_t flags);
+uint32_t eos_spi_xchg32(uint32_t data, uint8_t flags);
+void eos_spi_flush(void);
diff --git a/fw/fe310/eos/soc/spi_cfg.h b/fw/fe310/eos/soc/spi_cfg.h
new file mode 100644
index 0000000..84ab8bb
--- /dev/null
+++ b/fw/fe310/eos/soc/spi_cfg.h
@@ -0,0 +1,37 @@
+#include <stdint.h>
+
+#define EOS_SPI_MAX_DEV 4
+
+typedef struct {
+ uint16_t div;
+ uint8_t csid;
+ uint8_t cspin;
+ unsigned char evt;
+} SPIConfig;
+
+static const SPIConfig spi_cfg[EOS_SPI_MAX_DEV] = {
+ { // DEV_NET
+ .div = SPI_DIV_NET,
+ .csid = SPI_CSID_NET,
+ .cspin = SPI_CSPIN_NET,
+ .evt = 0, // Not SPI event
+ },
+ { // DEV_EVE
+ .div = SPI_DIV_EVE,
+ .csid = SPI_CSID_EVE,
+ .cspin = SPI_CSPIN_EVE,
+ .evt = 0,
+ },
+ { // DEV_SDC
+ .div = SPI_DIV_SDC,
+ .csid = SPI_CSID_SDC,
+ .cspin = SPI_CSPIN_SDC,
+ .evt = EOS_SPI_EVT_SDC,
+ },
+ { // DEV_CAM
+ .div = SPI_DIV_CAM,
+ .csid = SPI_CSID_CAM,
+ .cspin = SPI_CSPIN_CAM,
+ .evt = EOS_SPI_EVT_CAM,
+ },
+};
diff --git a/fw/fe310/eos/soc/spi_dev.c b/fw/fe310/eos/soc/spi_dev.c
new file mode 100644
index 0000000..c0c21b0
--- /dev/null
+++ b/fw/fe310/eos/soc/spi_dev.c
@@ -0,0 +1,97 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "msgq.h"
+#include "interrupt.h"
+#include "event.h"
+
+#include "board.h"
+
+#include "net.h"
+#include "spi.h"
+#include "spi_priv.h"
+#include "spi_cfg.h"
+#include "spi_dev.h"
+
+static uint8_t spi_dev;
+static uint8_t spi_lock;
+static uint16_t spi_div[EOS_SPI_MAX_DEV];
+
+int eos_spi_dev_init(uint8_t wakeup_cause) {
+ int i;
+
+ for (i=0; i<EOS_SPI_MAX_DEV; i++) {
+ spi_div[i] = spi_cfg[i].div;
+ if (spi_cfg[i].cspin != SPI_CSPIN_NONE) {
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << spi_cfg[i].cspin);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << spi_cfg[i].cspin);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << spi_cfg[i].cspin);
+ }
+ }
+
+ return EOS_OK;
+}
+
+int eos_spi_select(unsigned char dev) {
+ if (spi_lock) return EOS_ERR_BUSY;
+
+ if (spi_dev == EOS_SPI_DEV_NET) {
+ eos_net_stop();
+ } else {
+ eos_spi_stop();
+ }
+
+ spi_dev = dev;
+ if (dev == EOS_SPI_DEV_NET) {
+ eos_net_start();
+ } else {
+ eos_spi_start(spi_div[dev], spi_cfg[dev].csid, spi_cfg[dev].cspin, spi_cfg[dev].evt);
+ }
+
+ return EOS_OK;
+}
+
+int eos_spi_deselect(void) {
+ if (spi_lock) return EOS_ERR_BUSY;
+ if (spi_dev == EOS_SPI_DEV_NET) return EOS_ERR;
+
+ eos_spi_stop();
+
+ spi_dev = EOS_SPI_DEV_NET;
+ eos_net_start();
+
+ return EOS_OK;
+}
+
+uint8_t eos_spi_dev(void) {
+ return spi_dev;
+}
+
+uint16_t eos_spi_div(unsigned char dev) {
+ return spi_div[dev];
+}
+
+uint8_t eos_spi_csid(unsigned char dev) {
+ return spi_cfg[dev].csid;
+}
+
+uint8_t eos_spi_cspin(unsigned char dev) {
+ return spi_cfg[dev].cspin;
+}
+
+void eos_spi_lock(void) {
+ spi_lock = 1;
+}
+
+void eos_spi_unlock(void) {
+ spi_lock = 0;
+}
+
+void eos_spi_set_div(unsigned char dev, uint16_t div) {
+ spi_div[dev] = div;
+}
diff --git a/fw/fe310/eos/soc/spi_dev.h b/fw/fe310/eos/soc/spi_dev.h
new file mode 100644
index 0000000..e801f7e
--- /dev/null
+++ b/fw/fe310/eos/soc/spi_dev.h
@@ -0,0 +1,19 @@
+#include <stdint.h>
+
+#define EOS_SPI_DEV_NET 0
+#define EOS_SPI_DEV_EVE 1
+#define EOS_SPI_DEV_SDC 2
+#define EOS_SPI_DEV_CAM 3
+
+int eos_spi_dev_init(uint8_t wakeup_cause);
+int eos_spi_select(unsigned char dev);
+int eos_spi_deselect(void);
+
+uint8_t eos_spi_dev(void);
+uint16_t eos_spi_div(unsigned char dev);
+uint8_t eos_spi_csid(unsigned char dev);
+uint8_t eos_spi_cspin(unsigned char dev);
+
+void eos_spi_lock(void);
+void eos_spi_unlock(void);
+void eos_spi_set_div(unsigned char dev, uint16_t div);
diff --git a/fw/fe310/eos/soc/spi_priv.h b/fw/fe310/eos/soc/spi_priv.h
new file mode 100644
index 0000000..72c2dae
--- /dev/null
+++ b/fw/fe310/eos/soc/spi_priv.h
@@ -0,0 +1,8 @@
+#include <stdint.h>
+
+#define SPI_CSID_NONE 1
+#define SPI_CSPIN_NONE 0xff
+
+/* DO NOT TOUCH THEESE */
+#define SPI_SIZE_CHUNK 4
+#define SPI_SIZE_WM 2
diff --git a/fw/fe310/eos/soc/timer.c b/fw/fe310/eos/soc/timer.c
new file mode 100644
index 0000000..91861a3
--- /dev/null
+++ b/fw/fe310/eos/soc/timer.c
@@ -0,0 +1,137 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "msgq.h"
+#include "event.h"
+#include "timer.h"
+
+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
+
+static eos_timer_handler_t timer_handler[EOS_TIMER_MAX_ETYPE + 1];
+static uint64_t timer_next[EOS_TIMER_MAX_ETYPE + 1];
+
+static void timer_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
+ unsigned char idx = (type & ~EOS_EVT_MASK);
+
+ if (idx && (idx <= EOS_TIMER_MAX_ETYPE) && timer_handler[idx]) {
+ timer_handler[idx](type);
+ } else {
+ eos_evtq_bad_handler(type, buffer, len);
+ }
+}
+
+void _eos_timer_handle(void) {
+ int i;
+ volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+ uint64_t now = *mtime;
+ uint64_t next = 0;
+
+ for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
+ if (timer_next[i] && (timer_next[i] <= now)) {
+ timer_next[i] = 0;
+ if (i == 0) {
+ timer_handler[0](0);
+ } else {
+ eos_evtq_push_isr(EOS_EVT_TIMER | i, NULL, 0);
+ }
+ }
+ next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]);
+ }
+ *mtimecmp = next;
+ if (*mtimecmp == 0) clear_csr(mie, MIP_MTIP);
+}
+
+int eos_timer_init(uint8_t wakeup_cause) {
+ int i;
+ uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+
+ clear_csr(mie, MIP_MTIP);
+ *mtimecmp = 0;
+ for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
+ timer_next[i] = 0;
+ timer_handler[i] = NULL;
+ }
+ eos_evtq_set_handler(EOS_EVT_TIMER, timer_handle_evt);
+
+ return EOS_OK;
+}
+
+void eos_timer_set_handler(unsigned char evt, eos_timer_handler_t handler) {
+ uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+
+ if (!evt && (*mtimecmp != 0)) clear_csr(mie, MIP_MTIP);
+ timer_handler[evt] = handler;
+ if (!evt && (*mtimecmp != 0)) set_csr(mie, MIP_MTIP);
+}
+
+uint32_t eos_timer_get(unsigned char evt) {
+ volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+ uint64_t now;
+ uint32_t ret;
+
+ if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP);
+ now = *mtime;
+ if (timer_next[evt]) {
+ ret = (timer_next[evt] > now) ? (timer_next[evt] - now) * 1000 / EOS_TIMER_RTC_FREQ : 0;
+ } else {
+ ret = EOS_TIMER_NONE;
+ }
+ if (*mtimecmp != 0) set_csr(mie, MIP_MTIP);
+
+ return ret;
+}
+
+void eos_timer_set(unsigned char evt, uint32_t msec) {
+ int i;
+ volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+ uint64_t tick = *mtime + msec * (uint64_t)EOS_TIMER_RTC_FREQ / 1000;
+ uint64_t next = 0;
+
+ if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP);
+ timer_next[evt] = tick;
+ for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
+ next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]);
+ }
+ *mtimecmp = next;
+ if (*mtimecmp != 0) set_csr(mie, MIP_MTIP);
+}
+
+void eos_timer_clear(unsigned char evt) {
+ int i;
+ uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+ uint64_t next = 0;
+
+ if (*mtimecmp != 0) clear_csr(mie, MIP_MTIP);
+ if (timer_next[evt]) {
+ timer_next[evt] = 0;
+ for (i=0; i<=EOS_TIMER_MAX_ETYPE; i++) {
+ next = next && timer_next[i] ? MIN(next, timer_next[i]) : (next ? next : timer_next[i]);
+ }
+ *mtimecmp = next;
+ }
+ if (*mtimecmp != 0) set_csr(mie, MIP_MTIP);
+}
+
+void eos_time_sleep(uint32_t msec) {
+ volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ uint64_t mtime0 = *mtime;
+
+ while ((*mtime - mtime0) < (msec * EOS_TIMER_RTC_FREQ / 1000 + 1));
+}
+
+uint64_t eos_time_get_tick(void) {
+ volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ return *mtime;
+}
+
+uint32_t eos_time_delta_ms(uint32_t tick) {
+ return ((uint32_t)eos_time_get_tick() - tick) * 1000 / EOS_TIMER_RTC_FREQ;
+}
diff --git a/fw/fe310/eos/soc/timer.h b/fw/fe310/eos/soc/timer.h
new file mode 100644
index 0000000..0309454
--- /dev/null
+++ b/fw/fe310/eos/soc/timer.h
@@ -0,0 +1,23 @@
+#include <stdint.h>
+
+#define EOS_TIMER_ETYPE_UI 1
+#define EOS_TIMER_ETYPE_ECP 2
+#define EOS_TIMER_ETYPE_USER 4
+
+#define EOS_TIMER_MAX_ETYPE 4
+
+#define EOS_TIMER_NONE -1
+#define EOS_TIMER_RTC_FREQ 32768
+
+typedef void (*eos_timer_handler_t) (unsigned char);
+
+int eos_timer_init(uint8_t wakeup_cause);
+void eos_timer_set_handler(unsigned char evt, eos_timer_handler_t handler);
+
+uint32_t eos_timer_get(unsigned char evt);
+void eos_timer_set(unsigned char evt, uint32_t msec);
+void eos_timer_clear(unsigned char evt);
+
+void eos_time_sleep(uint32_t msec);
+uint64_t eos_time_get_tick(void);
+uint32_t eos_time_delta_ms(uint32_t tick);
diff --git a/fw/fe310/eos/soc/trap_entry.S b/fw/fe310/eos/soc/trap_entry.S
new file mode 100644
index 0000000..fb2b121
--- /dev/null
+++ b/fw/fe310/eos/soc/trap_entry.S
@@ -0,0 +1,554 @@
+#include "encoding.h"
+#include "sifive/bits.h"
+
+#define MCAUSE_INT 0x80000000
+#define MCAUSE_EXT (MCAUSE_INT | IRQ_M_EXT)
+#define MCAUSE_TIMER (MCAUSE_INT | IRQ_M_TIMER)
+
+#define PLIC_PRIORITY 0x0C000000
+#define PLIC_THRESHOLD 0x0C200000
+#define PLIC_CLAIM 0x0C200004
+
+#define PWM0_CTRL_ADDR 0x10015000
+#define PWM1_CTRL_ADDR 0x10025000
+#define PWM2_CTRL_ADDR 0x10035000
+#include "sifive/devices/pwm.h"
+
+#define GPIO_CTRL_ADDR 0x10012000
+#include "sifive/devices/gpio.h"
+
+#define SPI0_CTRL_ADDR 0x10014000
+#define SPI1_CTRL_ADDR 0x10024000
+#include "sifive/devices/spi.h"
+
+#define INT_PWM0_BASE 40
+#define INT_PWM1_BASE 44
+#define INT_PWM2_BASE 48
+
+#define I2S_MIC_BUF (0*4)
+#define I2S_SPK_BUF (1*4)
+#define I2S_FMT (2*4)
+#define I2S_MODE (3*4)
+#define I2S_MIC_WM (4*4)
+#define I2S_SPK_WM (5*4)
+#define I2S_MIC_EVT (6*4)
+#define I2S_SPK_EVT (7*4)
+#define I2S_MIC_CMP2 (8*4)
+#define I2S_MIC_CMP3 (9*4)
+#define I2S_SAMPLE (10*4)
+
+#include "board.h"
+#include "irq_def.h"
+#include "evt_def.h"
+#include "i2s_def.h"
+#include "i2s_priv.h"
+#include "msgq_priv.h"
+
+ .section .data.entry
+ .align 4
+
+.global eos_trap_entry
+eos_trap_entry:
+ addi sp, sp, -12*REGBYTES
+ STORE x8, 0*REGBYTES(sp)
+ STORE x9, 1*REGBYTES(sp)
+ STORE x18, 2*REGBYTES(sp)
+ STORE x19, 3*REGBYTES(sp)
+ STORE x20, 4*REGBYTES(sp)
+ STORE x21, 5*REGBYTES(sp)
+ STORE x22, 6*REGBYTES(sp)
+ STORE x23, 7*REGBYTES(sp)
+ STORE x24, 8*REGBYTES(sp) # format: 0 - PCM16; 1 - ALAW
+ STORE x25, 9*REGBYTES(sp) # mode: 0 - stereo; 1 - mono
+ STORE x26, 10*REGBYTES(sp) # channel: 0 - left; 1 - right
+ STORE x27, 11*REGBYTES(sp) # _eos_event_q addr
+
+ csrr x8, mcause
+ li x18, MCAUSE_EXT
+ bne x8, x18, handle_intr
+ li x18, PLIC_CLAIM
+ lw x9, 0(x18)
+ li x18, I2S_IRQ_WS_ID
+ beq x9, x18, i2s_handle_ws
+ li x18, I2S_IRQ_SD_ID
+ beq x9, x18, i2s_handle_sd
+ j handle_intr
+
+evtq_push:
+ la x9, _eos_event_q
+ lbu x18, MSGQ_OFF_IDXR(x9)
+ lbu x19, MSGQ_OFF_IDXW(x9)
+ lbu x20, MSGQ_OFF_SIZE(x9)
+
+ sub x18, x19, x18
+ andi x18, x18, 0xff
+ beq x18, x20, 0f
+
+ addi x20, x20, -1
+ and x20, x20, x19
+ li x18, MSGQ_ITEM_SIZE
+ mul x20, x20, x18
+ lw x21, MSGQ_OFF_ARRAY(x9)
+ add x21, x21, x20
+
+ addi x19, x19, 1
+ sb x19, MSGQ_OFF_IDXW(x9)
+ jalr x0, x22
+
+0:
+ mv x20, x0
+ jalr x0, x21
+
+i2s_handle_sd:
+ li x8, I2S_CTRL_ADDR_WS_SPK
+ lw x18, PWM_COUNT(x8)
+ lw x19, PWM_CMP3(x8)
+
+ # exit if too early
+ bltu x18, x19, i2s_sd_exit
+
+ la x27, _eos_i2s_drvr
+
+ # move CMPs for next channel and store channel bit to x26
+ lw x20, I2S_MIC_CMP2(x27)
+ lw x21, I2S_MIC_CMP3(x27) # 16-bit period
+
+ add x23, x19, x20
+ add x24, x23, x21
+ slli x20, x21, 1 # 32-bit period
+ slli x21, x20, 1 # 64-bit period
+ bltu x24, x21, 0f
+ neg x21, x21
+ add x23, x23, x21
+ add x24, x24, x21
+0:
+ li x26, 0
+ bltu x23, x20, 0f
+ li x26, 1
+0:
+ bltu x19, x20, 0f
+ neg x20, x20
+ li x18, PLIC_PRIORITY
+ sw x0, 4*I2S_IRQ_SD_ID(x18)
+0:
+ add x19, x19, x20
+
+ li x9, I2S_CTRL_ADDR_WS_MIC
+ sw x19, PWM_CMP3(x8)
+ sw x23, PWM_CMP2(x9)
+ sw x24, PWM_CMP3(x9)
+
+ lw x24, I2S_FMT(x27)
+ lw x25, I2S_MODE(x27)
+
+i2s_abuf_pop:
+ and x8, x25, x26
+ beqz x8, 0f
+
+ lw x8, I2S_SAMPLE(x27)
+ j i2s_sd_xchg
+0:
+ # pop from spk buf -> x8
+ lw x9, I2S_SPK_BUF(x27)
+ beqz x9, i2s_sd_xchg
+ lhu x18, I2S_ABUF_OFF_IDXR(x9)
+ lhu x19, I2S_ABUF_OFF_IDXW(x9)
+ lhu x20, I2S_ABUF_OFF_SIZE(x9)
+
+ beq x18, x19, 2f
+
+ addi x20, x20, -1
+ and x20, x20, x18
+ lw x21, I2S_ABUF_OFF_ARRAY(x9)
+ add x21, x21, x20
+ beqz x24, 0f
+ lbu x8, 0(x21)
+ addi x18, x18, 1
+ j 1f
+0:
+ lb x8, 0(x21)
+ lbu x20, 1(x21)
+ slli x8, x8, 8
+ or x8, x8, x20
+ addi x18, x18, 2
+1:
+ sh x18, I2S_ABUF_OFF_IDXR(x9)
+
+2:
+ li x21, 0xffff
+ sub x18, x19, x18
+ and x18, x18, x21
+
+ # check for push to event queue
+ lw x9, I2S_SPK_WM(x27)
+ bgtu x18, x9, i2s_decode
+
+ lw x9, I2S_SPK_EVT(x27)
+ beqz x9, i2s_decode
+ sw x0, I2S_SPK_EVT(x27)
+
+ # push to event queue
+ jal x22, evtq_push
+ beqz x21, i2s_decode
+ li x18, (EOS_EVT_I2S | EOS_I2S_ETYPE_SPK)
+ sb x18, MSGQ_ITEM_OFF_TYPE(x21)
+
+i2s_decode:
+ beqz x24, 3f
+ # aLaw decode -> x8
+ xori x8, x8, 0x55
+ andi x9, x8, 0x80
+ beqz x9, 0f
+ li x9, 1
+ slli x9, x9, 7
+ not x9, x9
+ and x8, x8, x9
+ li x9, -1
+0:
+ andi x18, x8, 0xf0
+ srli x18, x18, 4
+ addi x18, x18, 4
+
+ li x19, 4
+ beq x18, x19, 1f
+
+ andi x8, x8, 0x0f
+ addi x19, x18, -4
+ sll x8, x8, x19
+
+ li x19, 1
+ sll x19, x19, x18
+ or x8, x8, x19
+
+ li x19, 1
+ addi x18, x18, -5
+ sll x19, x19, x18
+ or x8, x8, x19
+ j 2f
+1:
+ slli x8, x8, 1
+ ori x8, x8, 1
+2:
+ beqz x9, 3f
+ mul x8, x8, x9
+3:
+ beqz x25, i2s_sd_xchg
+ sw x8, I2S_SAMPLE(x27)
+
+i2s_sd_xchg:
+ # read/write shift reg: x8 -> sr -> x8
+ li x18, GPIO_CTRL_ADDR
+ li x19, (0x1 << I2S_PIN_SD_IN)
+ li x20, (0x1 << I2S_PIN_SD_OUT)
+ li x21, (0x1 << I2S_PIN_CK_SR)
+ lw x22, GPIO_OUTPUT_VAL(x18)
+
+ lw x9, GPIO_OUTPUT_EN(x18)
+ or x9, x9, x20
+ sw x9, GPIO_OUTPUT_EN(x18)
+
+ not x20, x20
+ xor x22, x22, x21
+
+ li x23, 16
+0:
+ # write bit
+ li x9, 1
+ slli x9, x9, 15
+ and x9, x8, x9
+ slli x8, x8, 1
+#if I2S_PIN_SD_OUT > 15
+ slli x9, x9, (I2S_PIN_SD_OUT - 15)
+#else
+ srli x9, x9, (15 - I2S_PIN_SD_OUT)
+#endif
+ and x22, x22, x20
+ or x22, x22, x9
+
+ # read bit
+ lw x9, GPIO_INPUT_VAL(x18)
+ and x9, x9, x19
+ srli x9, x9, I2S_PIN_SD_IN
+ or x8, x8, x9
+
+ # 74HC595 ck low (I2S_PIN_CK_SR high)
+ xor x22, x22, x21
+ sw x22, GPIO_OUTPUT_VAL(x18)
+
+ # idle
+ li x9, I2S_IDLE_CYCLES
+1:
+ addi x9, x9, -1
+ bnez x9, 1b
+
+ # 74HC595 ck high (I2S_PIN_CK_SR low)
+ xor x22, x22, x21
+ sw x22, GPIO_OUTPUT_VAL(x18)
+
+ addi x23, x23, -1
+ bnez x23, 0b
+
+ # idle
+ li x9, I2S_IDLE_CYCLES
+1:
+ addi x9, x9, -1
+ bnez x9, 1b
+
+ # 74HC595 ck low (I2S_PIN_CK_SR high)
+ xor x22, x22, x21
+ sw x22, GPIO_OUTPUT_VAL(x18)
+
+ lw x9, GPIO_OUTPUT_EN(x18)
+ and x9, x9, x20
+ sw x9, GPIO_OUTPUT_EN(x18)
+
+ slli x8, x8, 16
+ srai x8, x8, 16
+
+i2s_encode:
+ beqz x24, i2s_abuf_push
+ # aLaw encode -> x8
+ li x18, 0x800
+ li x19, 7
+ bgez x8, 0f
+ neg x8, x8
+ lui x9, 0x80000
+ or x8, x8, x9
+0:
+ and x9, x8, x18
+ beq x9, x18, 1f
+ beqz x19, 1f
+ srli x18, x18, 1
+ addi x19, x19, -1
+ j 0b
+1:
+ mv x9, x19
+ bnez x9, 2f
+ addi x9, x9, 1
+2:
+ sra x8, x8, x9
+ li x9, 0x8000000f
+ and x8, x8, x9
+ slli x19, x19, 4
+ or x8, x8, x19
+ bgez x8, 3f
+ ori x8, x8, 0x80
+3:
+ xori x8, x8, 0x55
+ andi x8, x8, 0xff
+
+i2s_abuf_push:
+ # check channel
+ # bnez x26, i2s_sd_exit
+
+ # push to mic buf
+ lw x9, I2S_MIC_BUF(x27)
+ beqz x9, i2s_sd_exit
+ lhu x18, I2S_ABUF_OFF_IDXR(x9)
+ lhu x19, I2S_ABUF_OFF_IDXW(x9)
+ lhu x20, I2S_ABUF_OFF_SIZE(x9)
+ li x21, 0xffff
+
+ sub x18, x19, x18
+ and x18, x18, x21
+ beq x18, x20, 2f
+
+ addi x20, x20, -1
+ and x20, x20, x19
+ lw x21, I2S_ABUF_OFF_ARRAY(x9)
+ add x21, x21, x20
+ beqz x24, 0f
+ sb x8, 0(x21)
+ addi x19, x19, 1
+ addi x18, x18, 1
+ j 1f
+0:
+ sb x8, 1(x21)
+ srli x8, x8, 8
+ sb x8, 0(x21)
+ addi x19, x19, 2
+ addi x18, x18, 2
+1:
+ sh x19, I2S_ABUF_OFF_IDXW(x9)
+
+2:
+ # check for push to event queue
+ lw x9, I2S_MIC_WM(x27)
+ bltu x18, x9, i2s_sd_exit
+
+ lw x9, I2S_MIC_EVT(x27)
+ beqz x9, i2s_sd_exit
+ sw x0, I2S_MIC_EVT(x27)
+
+ # push to event queue
+ jal x22, evtq_push
+ beqz x21, i2s_sd_exit
+ li x18, (EOS_EVT_I2S | EOS_I2S_ETYPE_MIC)
+ sb x18, MSGQ_ITEM_OFF_TYPE(x21)
+
+i2s_sd_exit:
+ # complete
+ li x18, I2S_IRQ_SD_ID
+ li x19, PLIC_CLAIM
+ sw x18, 0(x19)
+
+ # exit
+ j trap_exit_data
+
+i2s_handle_ws:
+ # enable sd irq
+ li x18, PLIC_PRIORITY
+ li x19, IRQ_PRIORITY_I2S_SD
+ sw x19, 4*I2S_IRQ_SD_ID(x18)
+
+ # complete
+ li x18, I2S_IRQ_WS_ID
+ li x19, PLIC_CLAIM
+ sw x18, 0(x19)
+
+ # exit
+ j trap_exit_data
+
+.global _eos_i2s_start_pwm
+_eos_i2s_start_pwm:
+ addi sp, sp, -8*REGBYTES
+ STORE x8, 0*REGBYTES(sp)
+ STORE x9, 1*REGBYTES(sp)
+ STORE x18, 2*REGBYTES(sp)
+ STORE x19, 3*REGBYTES(sp)
+ STORE x20, 4*REGBYTES(sp)
+ STORE x21, 5*REGBYTES(sp)
+ STORE x22, 6*REGBYTES(sp)
+ STORE x23, 7*REGBYTES(sp)
+
+ li x18, I2S_CTRL_ADDR_CK
+ li x19, I2S_CTRL_ADDR_WS_MIC
+ li x20, I2S_CTRL_ADDR_WS_SPK
+ li x21, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | I2S_PWM_SCALE_CK
+ li x22, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP2GANG
+ li x23, PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP1GANG
+ sw x21, PWM_CFG(x18)
+ sw x22, PWM_CFG(x19)
+ sw x23, PWM_CFG(x20)
+
+ LOAD x8, 0*REGBYTES(sp)
+ LOAD x9, 1*REGBYTES(sp)
+ LOAD x18, 2*REGBYTES(sp)
+ LOAD x19, 3*REGBYTES(sp)
+ LOAD x20, 4*REGBYTES(sp)
+ LOAD x21, 5*REGBYTES(sp)
+ LOAD x22, 6*REGBYTES(sp)
+ LOAD x23, 7*REGBYTES(sp)
+ addi sp, sp, 8*REGBYTES
+
+ ret
+
+trap_exit_data:
+ # Remain in M-mode after mret
+ li x18, MSTATUS_MPP
+ csrs mstatus, x18
+
+ LOAD x8, 0*REGBYTES(sp)
+ LOAD x9, 1*REGBYTES(sp)
+ LOAD x18, 2*REGBYTES(sp)
+ LOAD x19, 3*REGBYTES(sp)
+ LOAD x20, 4*REGBYTES(sp)
+ LOAD x21, 5*REGBYTES(sp)
+ LOAD x22, 6*REGBYTES(sp)
+ LOAD x23, 7*REGBYTES(sp)
+ LOAD x24, 8*REGBYTES(sp)
+ LOAD x25, 9*REGBYTES(sp)
+ LOAD x26, 10*REGBYTES(sp)
+ LOAD x27, 11*REGBYTES(sp)
+ addi sp, sp, 12*REGBYTES
+
+ mret
+
+handle_intr:
+ lui x18, %hi(trap_entry_text)
+ addi x18, x18, %lo(trap_entry_text)
+ jalr x0, x18
+
+ .section .text.entry
+ .align 4
+
+trap_entry_text:
+ addi sp, sp, -20*REGBYTES
+
+ STORE x1, 0*REGBYTES(sp)
+ STORE x2, 1*REGBYTES(sp)
+ STORE x3, 2*REGBYTES(sp)
+ STORE x4, 3*REGBYTES(sp)
+ STORE x5, 4*REGBYTES(sp)
+ STORE x6, 5*REGBYTES(sp)
+ STORE x7, 6*REGBYTES(sp)
+ STORE x10, 7*REGBYTES(sp)
+ STORE x11, 8*REGBYTES(sp)
+ STORE x12, 9*REGBYTES(sp)
+ STORE x13, 10*REGBYTES(sp)
+ STORE x14, 11*REGBYTES(sp)
+ STORE x15, 12*REGBYTES(sp)
+ STORE x16, 13*REGBYTES(sp)
+ STORE x17, 14*REGBYTES(sp)
+ STORE x28, 15*REGBYTES(sp)
+ STORE x29, 16*REGBYTES(sp)
+ STORE x30, 17*REGBYTES(sp)
+ STORE x31, 18*REGBYTES(sp)
+
+ li x18, MCAUSE_TIMER
+ beq x8, x18, handle_timer
+ li x18, MCAUSE_EXT
+ beq x8, x18, handle_ext
+ mv a0, x8
+ call _exit
+
+handle_timer:
+ call _eos_timer_handle
+ j trap_exit_text
+
+handle_ext:
+ mv a0, x9
+ call eos_intr_handle
+ li x18, PLIC_CLAIM
+ sw a0, 0(x18)
+
+trap_exit_text:
+ # Remain in M-mode after mret
+ li t0, MSTATUS_MPP
+ csrs mstatus, t0
+
+ LOAD x1, 0*REGBYTES(sp)
+ LOAD x2, 1*REGBYTES(sp)
+ LOAD x3, 2*REGBYTES(sp)
+ LOAD x4, 3*REGBYTES(sp)
+ LOAD x5, 4*REGBYTES(sp)
+ LOAD x6, 5*REGBYTES(sp)
+ LOAD x7, 6*REGBYTES(sp)
+ LOAD x10, 7*REGBYTES(sp)
+ LOAD x11, 8*REGBYTES(sp)
+ LOAD x12, 9*REGBYTES(sp)
+ LOAD x13, 10*REGBYTES(sp)
+ LOAD x14, 11*REGBYTES(sp)
+ LOAD x15, 12*REGBYTES(sp)
+ LOAD x16, 13*REGBYTES(sp)
+ LOAD x17, 14*REGBYTES(sp)
+ LOAD x28, 15*REGBYTES(sp)
+ LOAD x29, 16*REGBYTES(sp)
+ LOAD x30, 17*REGBYTES(sp)
+ LOAD x31, 18*REGBYTES(sp)
+
+ LOAD x8, 20*REGBYTES(sp)
+ LOAD x9, 21*REGBYTES(sp)
+ LOAD x18, 22*REGBYTES(sp)
+ LOAD x19, 23*REGBYTES(sp)
+ LOAD x20, 24*REGBYTES(sp)
+ LOAD x21, 25*REGBYTES(sp)
+ LOAD x22, 26*REGBYTES(sp)
+ LOAD x23, 27*REGBYTES(sp)
+ LOAD x24, 28*REGBYTES(sp)
+ LOAD x25, 29*REGBYTES(sp)
+ LOAD x26, 30*REGBYTES(sp)
+ LOAD x27, 31*REGBYTES(sp)
+
+ addi sp, sp, 32*REGBYTES
+ mret
diff --git a/fw/fe310/eos/soc/uart.c b/fw/fe310/eos/soc/uart.c
new file mode 100644
index 0000000..30f76d9
--- /dev/null
+++ b/fw/fe310/eos/soc/uart.c
@@ -0,0 +1,114 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "prci_driver.h"
+
+#include "eos.h"
+#include "interrupt.h"
+#include "event.h"
+
+#include "uart.h"
+
+static eos_uart_handler_t uart_handler[EOS_UART_MAX_ETYPE];
+
+static void uart_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) {
+ unsigned char idx = (type & ~EOS_EVT_MASK) - 1;
+
+ if ((idx < EOS_UART_MAX_ETYPE) && uart_handler[idx]) {
+ uart_handler[idx](type);
+ } else {
+ eos_evtq_bad_handler(type, buffer, len);
+ }
+}
+
+static void uart_handle_intr(void) {
+ if (UART0_REG(UART_REG_IP) & UART_IP_TXWM) {
+ UART0_REG(UART_REG_IE) &= ~UART_IP_TXWM;
+ eos_evtq_push_isr(EOS_EVT_UART | EOS_UART_ETYPE_TX, NULL, 0);
+ }
+ if (UART0_REG(UART_REG_IP) & UART_IP_RXWM) {
+ UART0_REG(UART_REG_IE) &= ~UART_IP_RXWM;
+ eos_evtq_push_isr(EOS_EVT_UART | EOS_UART_ETYPE_RX, NULL, 0);
+ }
+}
+
+int eos_uart_init(uint8_t wakeup_cause) {
+ int i;
+
+ for (i=0; i<EOS_UART_MAX_ETYPE; i++) {
+ uart_handler[i] = NULL;
+ }
+ eos_evtq_set_handler(EOS_EVT_UART, uart_handle_evt);
+ eos_intr_set(INT_UART0_BASE, IRQ_PRIORITY_UART, uart_handle_intr);
+
+ UART0_REG(UART_REG_TXCTRL) |= UART_TXEN;
+ UART0_REG(UART_REG_RXCTRL) |= UART_RXEN;
+
+ eos_uart_speed(EOS_UART_SPEED);
+ eos_uart_start();
+
+ return EOS_OK;
+}
+
+void eos_uart_start(void) {
+ GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_UART0_MASK;
+ GPIO_REG(GPIO_IOF_EN) |= IOF0_UART0_MASK;
+}
+
+void eos_uart_stop(void) {
+ GPIO_REG(GPIO_IOF_EN) &= ~IOF0_UART0_MASK;
+}
+
+void eos_uart_speed(uint32_t baud_rate) {
+ UART0_REG(UART_REG_DIV) = PRCI_get_cpu_freq() / baud_rate - 1;
+}
+
+void eos_uart_set_handler(unsigned char type, eos_uart_handler_t handler) {
+ if (type && (type <= EOS_UART_MAX_ETYPE)) uart_handler[type - 1] = handler;
+}
+
+void eos_uart_txwm_set(uint8_t wm) {
+ UART0_REG(UART_REG_TXCTRL) &= ~UART_TXWM(0xFFFF);
+ UART0_REG(UART_REG_TXCTRL) |= UART_TXWM(wm);
+ UART0_REG(UART_REG_IE) |= UART_IP_TXWM;
+}
+
+void eos_uart_txwm_clear(void) {
+ UART0_REG(UART_REG_IE) &= ~UART_IP_TXWM;
+}
+
+void eos_uart_rxwm_set(uint8_t wm) {
+ UART0_REG(UART_REG_RXCTRL) &= ~UART_RXWM(0xFFFF);
+ UART0_REG(UART_REG_RXCTRL) |= UART_RXWM(wm);
+ UART0_REG(UART_REG_IE) |= UART_IP_RXWM;
+}
+
+void eos_uart_rxwm_clear(void) {
+ UART0_REG(UART_REG_IE) &= ~UART_IP_RXWM;
+}
+
+int eos_uart_putc(int c, char b) {
+ if (b) {
+ while (UART0_REG(UART_REG_TXFIFO) & 0x80000000);
+ UART0_REG(UART_REG_TXFIFO) = c & 0xff;
+ } else {
+ if (UART0_REG(UART_REG_TXFIFO) & 0x80000000) return EOS_ERR_FULL;
+ UART0_REG(UART_REG_TXFIFO) = c & 0xff;
+ }
+ return EOS_OK;
+}
+
+int eos_uart_getc(char b) {
+ volatile uint32_t r;
+
+ if (b) {
+ while ((r = UART0_REG(UART_REG_RXFIFO)) & 0x80000000);
+ } else {
+ r = UART0_REG(UART_REG_RXFIFO);
+ if (r & 0x80000000) return EOS_ERR_EMPTY;
+ }
+ return r & 0xff;
+} \ No newline at end of file
diff --git a/fw/fe310/eos/soc/uart.h b/fw/fe310/eos/soc/uart.h
new file mode 100644
index 0000000..94999e6
--- /dev/null
+++ b/fw/fe310/eos/soc/uart.h
@@ -0,0 +1,24 @@
+#include <stdint.h>
+
+#define EOS_UART_ETYPE_TX 1
+#define EOS_UART_ETYPE_RX 2
+
+#define EOS_UART_MAX_ETYPE 2
+
+#define EOS_UART_SPEED 115200
+
+typedef void (*eos_uart_handler_t) (unsigned char);
+
+int eos_uart_init(uint8_t wakeup_cause);
+void eos_uart_start(void);
+void eos_uart_stop(void);
+void eos_uart_speed(uint32_t baud_rate);
+
+void eos_uart_set_handler(unsigned char type, eos_uart_handler_t handler);
+
+void eos_uart_txwm_set(uint8_t wm);
+void eos_uart_txwm_clear(void);
+void eos_uart_rxwm_set(uint8_t wm);
+void eos_uart_rxwm_clear(void);
+int eos_uart_putc(int c, char b);
+int eos_uart_getc(char b); \ No newline at end of file