diff options
Diffstat (limited to 'fw/fe310/eos/soc/spi.c')
-rw-r--r-- | fw/fe310/eos/soc/spi.c | 119 |
1 files changed, 77 insertions, 42 deletions
diff --git a/fw/fe310/eos/soc/spi.c b/fw/fe310/eos/soc/spi.c index 1806f50..64a057b 100644 --- a/fw/fe310/eos/soc/spi.c +++ b/fw/fe310/eos/soc/spi.c @@ -3,13 +3,16 @@ #include "encoding.h" #include "platform.h" +#include "board.h" #include "eos.h" +#include "log.h" #include "msgq.h" #include "interrupt.h" #include "event.h" -#include "board.h" +#include "dev/egpio.h" +#include "dev/egpio_priv.h" #include "spi.h" #include "spi_priv.h" @@ -21,15 +24,12 @@ #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; @@ -40,6 +40,7 @@ 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 { @@ -47,7 +48,7 @@ static void spi_handle_evt(unsigned char type, unsigned char *buffer, uint16_t l } } -int eos_spi_init(uint8_t wakeup_cause) { +int eos_spi_init(void) { int i; for (i=0; i<EOS_SPI_MAX_EVT; i++) { @@ -63,31 +64,31 @@ int eos_spi_init(uint8_t wakeup_cause) { 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); + /* CS assert to SCK: 1 clock cycles + SCK to CS deassert: 0 clock cycles */ + SPI1_REG(SPI_REG_DCSSCK) = 0x01; + + GPIO_REG(GPIO_OUTPUT_XOR) |= SPI_IOF_CSXOR; eos_spi_enable(); return EOS_OK; } -void eos_spi_configure(uint16_t div, int8_t csid, int8_t cspin, unsigned char evt) { +void eos_spi_configure(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; - if (csid != -1) { - SPI1_REG(SPI_REG_CSID) = csid; + 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_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) { +void eos_spi_start(uint16_t div, uint8_t csid, uint8_t cspin, unsigned char evt) { eos_spi_configure(div, csid, cspin, evt); eos_intr_set_handler(INT_SPI1_BASE, eos_spi_handle_xchg); } @@ -126,7 +127,7 @@ void _eos_spi_xchg_init(unsigned char *buffer, uint16_t len, uint8_t flags) { } static void spi_wait4xchg(void) { - uint8_t done = 0; + int done = 0; while (!done) { clear_csr(mstatus, MSTATUS_MIE); @@ -134,23 +135,25 @@ static void spi_wait4xchg(void) { 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_wait4xchg(); +int eos_spi_xchg(unsigned char *buffer, uint16_t len, uint8_t flags) { + if (!spi_evt) return EOS_ERR; + + spi_wait4xchg(); - spi_in_xchg = 1; _eos_spi_xchg_init(buffer, len, flags); - eos_spi_cs_set(); + eos_spi_set_cs(); SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_WM); SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM; + + return EOS_OK; } void eos_spi_handle_xchg(void) { - int i; uint16_t sz_chunk = MIN(spi_state_len - spi_state_idx_tx, SPI_SIZE_CHUNK); + int i; for (i=0; i<sz_chunk; i++) { volatile uint32_t x = SPI1_REG(SPI_REG_TXFIFO); @@ -174,10 +177,18 @@ void eos_spi_handle_xchg(void) { SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(1); return; } - 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); + SPI1_REG(SPI_REG_IE) = 0; + if (!(spi_state_flags & EOS_SPI_FLAG_MORE)) eos_spi_clear_cs(); + + /* clear SPI_FLAG_XCHG flag and all of EOS_SPI_FLAG_* */ + spi_state_flags &= (~SPI_FLAG_XCHG & 0xF0); + + if (spi_evt) { + int rv; + + rv = eos_evtq_push_isr(EOS_EVT_SPI | spi_evt, spi_state_buf, spi_state_len); + if (rv) EOS_LOG(EOS_LOG_ERR, "SPI XCHG EVTQ PUSH ERR:%d\n", rv); + } } 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; @@ -185,23 +196,40 @@ void eos_spi_handle_xchg(void) { } } -void eos_spi_cs_set(void) { - /* cs low */ +int eos_spi_get_cs(void) { if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) { - clear_csr(mstatus, MSTATUS_MIE); - GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << spi_cspin); - set_csr(mstatus, MSTATUS_MIE); + if (spi_cspin & SPI_CSFLAG_EGPIO) { + return !eos_egpio_get_val(spi_cspin & ~SPI_CSFLAG_EGPIO); + } else { + return !(GPIO_REG(GPIO_OUTPUT_VAL) & (1 << spi_cspin)); + } + } else { + return (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_HOLD); + } +} + +void eos_spi_set_cs(void) { + /* cs low */ + if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) { + if (spi_cspin & SPI_CSFLAG_EGPIO) { + eos_egpio_set_val(spi_cspin & ~SPI_CSFLAG_EGPIO, 0); + } else { + 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 */ +/* can be called from interrupt handler */ +void eos_spi_clear_cs(void) { + /* cs high */ if (SPI1_REG(SPI_REG_CSMODE) == SPI_CSMODE_OFF) { - clear_csr(mstatus, MSTATUS_MIE); - GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << spi_cspin); - set_csr(mstatus, MSTATUS_MIE); + if (spi_cspin & SPI_CSFLAG_EGPIO) { + eos_egpio_set_val(spi_cspin & ~SPI_CSFLAG_EGPIO, 1); + } else { + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << spi_cspin); + } } else { SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; } @@ -360,11 +388,18 @@ uint32_t eos_spi_xchg32(uint32_t data, uint8_t flags) { } void eos_spi_flush(void) { - if (spi_in_xchg) { - spi_wait4xchg(); - } else { - SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(1); - while (!(SPI1_REG(SPI_REG_IP) & SPI_IP_TXWM)); - while (!(SPI1_REG(SPI_REG_RXFIFO) & SPI_RXFIFO_EMPTY)); - } + uint32_t mcycle_start, mcycle_wait; + + spi_wait4xchg(); + + SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(1); + while (!(SPI1_REG(SPI_REG_IP) & SPI_IP_TXWM)); + + /* wait for last frame to be transmitted: 9 spi clock cycles */ + mcycle_wait = 9*2*((SPI1_REG(SPI_REG_SCKDIV) & 0xFFF)+1); + mcycle_start = read_csr(mcycle); + + while ((read_csr(mcycle) - mcycle_start) < mcycle_wait); + + while (!(SPI1_REG(SPI_REG_RXFIFO) & SPI_RXFIFO_EMPTY)); } |