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 | 
