summaryrefslogtreecommitdiff
path: root/fw/fe310/eos/soc/spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw/fe310/eos/soc/spi.c')
-rw-r--r--fw/fe310/eos/soc/spi.c119
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));
}