diff options
Diffstat (limited to 'fw/fe310/eos/soc')
-rw-r--r-- | fw/fe310/eos/soc/Makefile | 20 | ||||
-rw-r--r-- | fw/fe310/eos/soc/i2c.c | 151 | ||||
-rw-r--r-- | fw/fe310/eos/soc/i2c.h | 13 | ||||
-rw-r--r-- | fw/fe310/eos/soc/i2s.c | 392 | ||||
-rw-r--r-- | fw/fe310/eos/soc/i2s.h | 36 | ||||
-rw-r--r-- | fw/fe310/eos/soc/i2s_def.h | 8 | ||||
-rw-r--r-- | fw/fe310/eos/soc/i2s_priv.h | 8 | ||||
-rw-r--r-- | fw/fe310/eos/soc/interrupt.c | 75 | ||||
-rw-r--r-- | fw/fe310/eos/soc/interrupt.h | 13 | ||||
-rw-r--r-- | fw/fe310/eos/soc/pwr.c | 70 | ||||
-rw-r--r-- | fw/fe310/eos/soc/pwr.h | 16 | ||||
-rw-r--r-- | fw/fe310/eos/soc/spi.c | 362 | ||||
-rw-r--r-- | fw/fe310/eos/soc/spi.h | 32 | ||||
-rw-r--r-- | fw/fe310/eos/soc/spi_priv.h | 5 | ||||
-rw-r--r-- | fw/fe310/eos/soc/timer.c | 137 | ||||
-rw-r--r-- | fw/fe310/eos/soc/timer.h | 23 | ||||
-rw-r--r-- | fw/fe310/eos/soc/trap_entry.S | 517 | ||||
-rw-r--r-- | fw/fe310/eos/soc/uart.c | 123 | ||||
-rw-r--r-- | fw/fe310/eos/soc/uart.h | 25 |
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 |