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