summaryrefslogtreecommitdiff
path: root/fw/fe310/eos/soc
diff options
context:
space:
mode:
Diffstat (limited to 'fw/fe310/eos/soc')
-rw-r--r--fw/fe310/eos/soc/Makefile20
-rw-r--r--fw/fe310/eos/soc/i2c.c151
-rw-r--r--fw/fe310/eos/soc/i2c.h13
-rw-r--r--fw/fe310/eos/soc/i2s.c392
-rw-r--r--fw/fe310/eos/soc/i2s.h36
-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/pwr.c70
-rw-r--r--fw/fe310/eos/soc/pwr.h16
-rw-r--r--fw/fe310/eos/soc/spi.c362
-rw-r--r--fw/fe310/eos/soc/spi.h32
-rw-r--r--fw/fe310/eos/soc/spi_priv.h5
-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.S517
-rw-r--r--fw/fe310/eos/soc/uart.c123
-rw-r--r--fw/fe310/eos/soc/uart.h25
19 files changed, 2026 insertions, 0 deletions
diff --git a/fw/fe310/eos/soc/Makefile b/fw/fe310/eos/soc/Makefile
new file mode 100644
index 0000000..1404c81
--- /dev/null
+++ b/fw/fe310/eos/soc/Makefile
@@ -0,0 +1,20 @@
+include ../../common.mk
+CFLAGS += -I$(bsp_dir)/include -I$(bsp_dir)/drivers
+
+obj = trap_entry.o interrupt.o timer.o pwr.o i2s.o i2c.o uart.o spi.o
+lib = ../../libeos-soc.a
+
+
+%.o: %.c %.h
+ $(CC) $(CFLAGS) -c $<
+
+%.o: %.S
+ $(CC) $(CFLAGS) -c $<
+
+all: $(lib)
+
+$(lib): $(obj)
+ $(AR) rcs $@ $(obj)
+
+clean:
+ rm -f *.o $(lib)
diff --git a/fw/fe310/eos/soc/i2c.c b/fw/fe310/eos/soc/i2c.c
new file mode 100644
index 0000000..553a9bf
--- /dev/null
+++ b/fw/fe310/eos/soc/i2c.c
@@ -0,0 +1,151 @@
+#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_enable();
+
+ return EOS_OK;
+}
+
+void eos_i2c_enable(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_disable(void) {
+ GPIO_REG(GPIO_IOF_EN) &= ~IOF0_I2C0_MASK;
+
+ I2C0_REGB(I2C_CONTROL) &= ~I2C_CONTROL_EN;
+}
+
+int eos_i2c_enabled(void) {
+ return !!(GPIO_REG(GPIO_IOF_EN) & IOF0_I2C0_MASK);
+}
+
+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..5032988
--- /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);
+void eos_i2c_enable(void);
+void eos_i2c_disable(void);
+int eos_i2c_enabled(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..5e5eaa7
--- /dev/null
+++ b/fw/fe310/eos/soc/i2s.c
@@ -0,0 +1,392 @@
+#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 _eos_i2s_mic_buf;
+EOSABuf _eos_i2s_spk_buf;
+uint32_t _eos_i2s_fmt = 0;
+uint32_t _eos_i2s_mic_wm = 0;
+uint32_t _eos_i2s_spk_wm = 0;
+uint32_t _eos_i2s_mic_evt_enable = 0;
+uint32_t _eos_i2s_spk_evt_enable = 0;
+
+static eos_i2s_handler_t i2s_spk_handler = NULL;
+static eos_i2s_handler_t i2s_mic_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 */
+
+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_mic_evt_enable = 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_spk_evt_enable = 1;
+ set_csr(mstatus, MSTATUS_MIE);
+ break;
+ default:
+ eos_evtq_bad_handler(type, buffer, len);
+ break;
+ }
+}
+
+static void _mic_vol_set(uint8_t vol) {
+ I2S_REG_WS_MIC(PWM_CMP2) = i2s_clk_period * (vol + 1);
+ I2S_REG_WS_MIC(PWM_CMP3) = I2S_REG_WS_MIC(PWM_CMP2) + i2s_clk_period * 16;
+}
+
+static void _spk_vol_set(uint8_t vol) {
+ int spk_cmp = vol + i2s_mic_volume - 16;
+
+ if (spk_cmp <= 0) {
+ I2S_REG_WS_SPK(PWM_CMP1) = i2s_clk_period * (32 + spk_cmp);
+ I2S_REG_WS_SPK(PWM_CMP2) = i2s_clk_period * (64 + spk_cmp);
+ I2S_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * 33;
+ GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS_SPK);
+ } else {
+ I2S_REG_WS_SPK(PWM_CMP1) = i2s_clk_period * spk_cmp;
+ I2S_REG_WS_SPK(PWM_CMP2) = i2s_clk_period * (32 + spk_cmp);
+ I2S_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * (33 + spk_cmp);
+ GPIO_REG(GPIO_OUTPUT_XOR) |= (1 << I2S_PIN_WS_SPK);
+ }
+}
+
+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);
+
+ 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, unsigned char fmt) {
+ 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;
+ _mic_vol_set(i2s_mic_volume);
+
+ I2S_REG_WS_SPK(PWM_CMP0) = i2s_clk_period * 64 - 1;
+ _spk_vol_set(i2s_spk_volume);
+
+ I2S_REG_CK(PWM_COUNT) = 0;
+ I2S_REG_WS_MIC(PWM_COUNT) = 0;
+ I2S_REG_WS_SPK(PWM_COUNT) = i2s_clk_period / 2;
+
+ _eos_i2s_fmt = fmt;
+ _eos_i2s_mic_evt_enable = 1;
+ _eos_i2s_spk_evt_enable = 1;
+
+ eos_intr_set_priority(I2S_IRQ_WS_ID, IRQ_PRIORITY_I2S_WS);
+ eos_intr_set_priority(I2S_IRQ_SD_ID, 0);
+ eos_intr_enable(I2S_IRQ_WS_ID);
+ eos_intr_enable(I2S_IRQ_SD_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_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_mic_evt_enable = 0;
+ _eos_i2s_spk_evt_enable = 0;
+ eos_intr_set_priority(I2S_IRQ_WS_ID, 0);
+ eos_intr_set_priority(I2S_IRQ_SD_ID, 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;
+}
+
+int eos_i2s_running(void) {
+ return !!(GPIO_REG(GPIO_IOF_EN) & I2S_PIN_PWM);
+}
+
+void eos_i2s_mic_init(uint8_t *mic_arr, uint16_t mic_arr_size) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ _abuf_init(&_eos_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_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(&_eos_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(&_eos_i2s_mic_buf));
+ set_csr(mstatus, MSTATUS_MIE);
+
+ for (i=0; i<_ssize; i++) {
+ sample[i] = _eos_i2s_mic_buf.array[EOS_ABUF_IDX_MASK(_eos_i2s_mic_buf.idx_r + i, _eos_i2s_mic_buf.size)];
+ }
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ _eos_i2s_mic_buf.idx_r += _ssize;
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return _ssize;
+}
+
+int eos_i2s_mic_pop8(uint8_t *sample) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ int ret = _abuf_pop8(&_eos_i2s_mic_buf, sample);
+ set_csr(mstatus, MSTATUS_MIE);
+ return ret;
+}
+
+int eos_i2s_mic_pop16(uint16_t *sample) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ int ret = _abuf_pop16(&_eos_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);
+ _mic_vol_set(vol);
+ _spk_vol_set(i2s_spk_volume);
+ 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(&_eos_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_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(&_eos_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, _eos_i2s_spk_buf.size - _abuf_len(&_eos_i2s_spk_buf));
+ set_csr(mstatus, MSTATUS_MIE);
+
+ for (i=0; i<_ssize; i++) {
+ _eos_i2s_spk_buf.array[EOS_ABUF_IDX_MASK(_eos_i2s_spk_buf.idx_w + i, _eos_i2s_spk_buf.size)] = sample[i];
+ }
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ _eos_i2s_spk_buf.idx_w += _ssize;
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return _ssize;
+}
+
+int eos_i2s_spk_push8(uint8_t sample) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ int ret = _abuf_push8(&_eos_i2s_spk_buf, sample);
+ set_csr(mstatus, MSTATUS_MIE);
+ return ret;
+}
+
+int eos_i2s_spk_push16(uint16_t sample) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ int ret = _abuf_push16(&_eos_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);
+ _spk_vol_set(vol);
+ 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..f53e183
--- /dev/null
+++ b/fw/fe310/eos/soc/i2s.h
@@ -0,0 +1,36 @@
+#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, unsigned char fmt);
+void eos_i2s_stop(void);
+int eos_i2s_running(void);
+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..c6252b5
--- /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);
diff --git a/fw/fe310/eos/soc/pwr.c b/fw/fe310/eos/soc/pwr.c
new file mode 100644
index 0000000..a2adfd4
--- /dev/null
+++ b/fw/fe310/eos/soc/pwr.c
@@ -0,0 +1,70 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "timer.h"
+#include "dev/net.h"
+
+#include "pwr.h"
+
+#define PWR_RTC_SCALE 15
+#define PWR_RTC_SFREQ (EOS_TIMER_RTC_FREQ >> PWR_RTC_SCALE)
+
+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_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;
+}
diff --git a/fw/fe310/eos/soc/pwr.h b/fw/fe310/eos/soc/pwr.h
new file mode 100644
index 0000000..1a0d17a
--- /dev/null
+++ b/fw/fe310/eos/soc/pwr.h
@@ -0,0 +1,16 @@
+#include <stdint.h>
+
+#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);
diff --git a/fw/fe310/eos/soc/spi.c b/fw/fe310/eos/soc/spi.c
new file mode 100644
index 0000000..2c36109
--- /dev/null
+++ b/fw/fe310/eos/soc/spi.c
@@ -0,0 +1,362 @@
+#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 SPI_CSID_NONE 1
+
+#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_priority(INT_SPI1_BASE, IRQ_PRIORITY_SPI_XCHG);
+
+ 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);
+
+ /* for spi 9bit protocol */
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << IOF_SPI1_SCK);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << IOF_SPI1_MOSI);
+ GPIO_REG(GPIO_INPUT_EN) |= (1 << IOF_SPI1_MISO);
+
+ eos_spi_enable();
+
+ // There is no way here to change the CS polarity.
+ // SPI1_REG(SPI_REG_CSDEF) = 0xFFFF;
+ return EOS_OK;
+}
+
+void eos_spi_configure(uint16_t div, int8_t csid, int8_t cspin, unsigned char evt) {
+ spi_state_flags = 0;
+ spi_evt = evt;
+ SPI1_REG(SPI_REG_SCKDIV) = div;
+ if (csid != -1) {
+ SPI1_REG(SPI_REG_CSID) = csid;
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+ } else {
+ spi_cspin = cspin;
+ SPI1_REG(SPI_REG_CSID) = SPI_CSID_NONE;
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_OFF;
+ }
+}
+
+void eos_spi_start(uint16_t div, int8_t csid, int8_t cspin, unsigned char evt) {
+ eos_spi_configure(div, csid, cspin, evt);
+ 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_enable(void) {
+ eos_intr_enable(INT_SPI1_BASE);
+
+ GPIO_REG(GPIO_IOF_SEL) &= ~SPI_IOF_MASK;
+ GPIO_REG(GPIO_IOF_EN) |= SPI_IOF_MASK;
+}
+
+void eos_spi_disable(void) {
+ GPIO_REG(GPIO_IOF_EN) &= ~SPI_IOF_MASK;
+
+ eos_intr_disable(INT_SPI1_BASE);
+}
+
+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..0c2de4b
--- /dev/null
+++ b/fw/fe310/eos/soc/spi.h
@@ -0,0 +1,32 @@
+#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_configure(uint16_t div, int8_t csid, int8_t cspin, unsigned char evt);
+void eos_spi_start(uint16_t div, int8_t csid, int8_t cspin, unsigned char evt);
+void eos_spi_stop(void);
+void eos_spi_enable(void);
+void eos_spi_disable(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_priv.h b/fw/fe310/eos/soc/spi_priv.h
new file mode 100644
index 0000000..17081a3
--- /dev/null
+++ b/fw/fe310/eos/soc/spi_priv.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+
+/* 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..96024cb
--- /dev/null
+++ b/fw/fe310/eos/soc/trap_entry.S
@@ -0,0 +1,517 @@
+#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
+
+#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, -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)
+
+ 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:
+ # exit if too early
+ li x18, I2S_CTRL_ADDR_WS_SPK
+ lw x8, PWM_COUNT(x18)
+ lw x9, PWM_CMP3(x18)
+ bltu x8, x9, i2s_handle_sd_exit
+
+ # disable sd irq
+ li x18, PLIC_PRIORITY
+ sw x0, 4*I2S_IRQ_SD_ID(x18)
+
+ la x9, _eos_i2s_fmt
+ lw x23, 0(x9)
+
+i2s_abuf_pop:
+ # pop from spk buf -> x8
+ mv x8, x0
+ la x9, _eos_i2s_spk_buf
+ lhu x18, I2S_ABUF_OFF_IDXR(x9)
+ lhu x19, I2S_ABUF_OFF_IDXW(x9)
+ lhu x20, I2S_ABUF_OFF_SIZE(x9)
+
+ beq x18, x19, i2s_handle_sd_xchg
+
+ addi x20, x20, -1
+ and x20, x20, x18
+ lw x21, I2S_ABUF_OFF_ARRAY(x9)
+ add x21, x21, x20
+ beqz x23, 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)
+
+ li x21, 0xffff
+ sub x18, x19, x18
+ and x18, x18, x21
+
+ # check for push to event queue
+ la x9, _eos_i2s_spk_wm
+ lw x20, 0(x9)
+ beqz x20, i2s_decode
+ bgtu x18, x20, i2s_decode
+
+ la x9, _eos_i2s_spk_evt_enable
+ lw x18, 0(x9)
+ beqz x18, i2s_decode
+ sw x0, 0(x9)
+
+ # 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 x23, i2s_handle_sd_xchg
+ # 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, i2s_handle_sd_xchg
+ mul x8, x8, x9
+
+i2s_handle_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)
+
+ # idle
+ li x9, I2S_IDLE_CYCLES
+1:
+ addi x9, x9, -1
+ bnez x9, 1b
+
+ addi x23, x23, -1
+ beqz x23, 2f
+ j 0b
+
+2:
+ # 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
+
+ la x9, _eos_i2s_fmt
+ lw x23, 0(x9)
+
+i2s_encode:
+ beqz x23, 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:
+ # push to mic buf
+ la x9, _eos_i2s_mic_buf
+ 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, i2s_handle_sd_exit
+
+ addi x20, x20, -1
+ and x20, x20, x19
+ lw x21, I2S_ABUF_OFF_ARRAY(x9)
+ add x21, x21, x20
+ beqz x23, 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)
+
+ # check for push to event queue
+ la x9, _eos_i2s_mic_wm
+ lw x20, 0(x9)
+ beqz x20, i2s_handle_sd_exit
+ bltu x18, x20, i2s_handle_sd_exit
+
+ la x9, _eos_i2s_mic_evt_enable
+ lw x18, 0(x9)
+ beqz x18, i2s_handle_sd_exit
+ sw x0, 0(x9)
+
+ # push to event queue
+ jal x22, evtq_push
+ beqz x21, i2s_handle_sd_exit
+ li x18, (EOS_EVT_I2S | EOS_I2S_ETYPE_MIC)
+ sb x18, MSGQ_ITEM_OFF_TYPE(x21)
+
+i2s_handle_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
+
+.global _eos_flash_set
+_eos_flash_set:
+ li a3, SPI0_CTRL_ADDR
+ sw x0, SPI_REG_FCTRL(a3)
+ sw a0, SPI_REG_SCKDIV(a3)
+ sw a1, SPI_REG_FFMT(a3)
+ li a0, 1
+ sw a0, SPI_REG_FCTRL(a3)
+ 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)
+ addi sp, sp, 8*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, -24*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 x24, 15*REGBYTES(sp)
+ STORE x25, 16*REGBYTES(sp)
+ STORE x26, 17*REGBYTES(sp)
+ STORE x27, 18*REGBYTES(sp)
+ STORE x28, 19*REGBYTES(sp)
+ STORE x29, 20*REGBYTES(sp)
+ STORE x30, 21*REGBYTES(sp)
+ STORE x31, 22*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)
+ j trap_exit_text
+
+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 x24, 15*REGBYTES(sp)
+ LOAD x25, 16*REGBYTES(sp)
+ LOAD x26, 17*REGBYTES(sp)
+ LOAD x27, 18*REGBYTES(sp)
+ LOAD x28, 19*REGBYTES(sp)
+ LOAD x29, 20*REGBYTES(sp)
+ LOAD x30, 21*REGBYTES(sp)
+ LOAD x31, 22*REGBYTES(sp)
+
+ LOAD x8, 24*REGBYTES(sp)
+ LOAD x9, 25*REGBYTES(sp)
+ LOAD x18, 26*REGBYTES(sp)
+ LOAD x19, 27*REGBYTES(sp)
+ LOAD x20, 28*REGBYTES(sp)
+ LOAD x21, 29*REGBYTES(sp)
+ LOAD x22, 30*REGBYTES(sp)
+ LOAD x23, 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..589832a
--- /dev/null
+++ b/fw/fe310/eos/soc/uart.c
@@ -0,0 +1,123 @@
+#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 "i2s.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);
+
+ eos_uart_speed(EOS_UART_SPEED);
+
+ eos_uart_enable();
+
+ return EOS_OK;
+}
+
+void eos_uart_enable(void) {
+ UART0_REG(UART_REG_TXCTRL) |= UART_TXEN;
+ UART0_REG(UART_REG_RXCTRL) |= UART_RXEN;
+
+ GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_UART0_MASK;
+ GPIO_REG(GPIO_IOF_EN) |= IOF0_UART0_MASK;
+}
+
+void eos_uart_disable(void) {
+ GPIO_REG(GPIO_IOF_EN) &= ~IOF0_UART0_MASK;
+
+ UART0_REG(UART_REG_TXCTRL) &= ~UART_TXEN;
+ UART0_REG(UART_REG_RXCTRL) &= ~UART_RXEN;
+}
+
+int eos_uart_enabled(void) {
+ return !!(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, int block) {
+ if (block) {
+ 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(int block) {
+ volatile uint32_t r;
+
+ if (block) {
+ 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;
+}
diff --git a/fw/fe310/eos/soc/uart.h b/fw/fe310/eos/soc/uart.h
new file mode 100644
index 0000000..caaf6c6
--- /dev/null
+++ b/fw/fe310/eos/soc/uart.h
@@ -0,0 +1,25 @@
+#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_enable(void);
+void eos_uart_disable(void);
+int eos_uart_enabled(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, int block);
+int eos_uart_getc(int block); \ No newline at end of file