diff --git a/arch/risc-v/src/mpfs/mpfs_corespi.c b/arch/risc-v/src/mpfs/mpfs_corespi.c index 08c497ee0d12a..a64f8ef241951 100644 --- a/arch/risc-v/src/mpfs/mpfs_corespi.c +++ b/arch/risc-v/src/mpfs/mpfs_corespi.c @@ -613,10 +613,21 @@ static void mpfs_spi_setbits(struct spi_dev_s *dev, int nbits) /* Bitwidth is selected when the SPI block is being fabricated */ - if (nbits != priv->config->nbits) + if (nbits != priv->nbits) { - spierr("Changing SPI bitwidth not supported\n"); - DEBUGPANIC(); + /* If configured frame length is even multiple of requested, + * we simulate wider frames by sending multiple shorter ones + */ + + if (nbits % priv->config->nbits == 0) + { + priv->nbits = nbits; + } + else + { + spierr("SPI bitwidth %d is not supported\n", nbits); + DEBUGPANIC(); + } } } @@ -722,6 +733,52 @@ static int mpfs_spi_sem_waitdone(struct mpfs_spi_priv_s *priv) return nxsem_tickwait_uninterruptible(&priv->sem_isr, USEC2TICK(timeout)); } +/**************************************************************************** + * Name: mpfs_spi_write_tx8 + * + * Description: + * Fill up the TX fifo with one word in configured size frames + * + * Input Parameters: + * priv - SPI private state data + * nframes - Number of 8-bit data per word + * last - true if this is the last word of the transfer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void mpfs_spi_write_tx8(struct mpfs_spi_priv_s *priv, + unsigned nframes, + bool last) +{ + uint8_t *data8 = (uint8_t *)priv->txbuf; + unsigned pos = priv->tx_pos++; + + /* Calculate octet position in the tx-buffer */ + + pos *= nframes; + + /* Write all but last 8-bit data */ + + while (--nframes > 0) + { + putreg32((uint32_t)data8[pos + nframes], MPFS_SPI_TX_DATA); + } + + /* Write the last 8-bit data */ + + if (last) + { + putreg32((uint32_t)data8[pos], MPFS_SPI_TX_LAST); + } + else + { + putreg32((uint32_t)data8[pos], MPFS_SPI_TX_DATA); + } +} + /**************************************************************************** * Name: mpfs_spi_load_tx_fifo * @@ -730,7 +787,6 @@ static int mpfs_spi_sem_waitdone(struct mpfs_spi_priv_s *priv) * * Input Parameters: * priv - SPI private state data - * txbuffer - A pointer to the buffer of data to be sent * nwords - the length of data that to be exchanged in units of words. * The wordsize is determined by the number of bits-per-word * selected for the SPI interface. If nbits <= 8, the data is @@ -743,34 +799,34 @@ static int mpfs_spi_sem_waitdone(struct mpfs_spi_priv_s *priv) ****************************************************************************/ static void mpfs_spi_load_tx_fifo(struct mpfs_spi_priv_s *priv, - const void *txbuffer, uint32_t nwords) { uint16_t *data16; - uint8_t *data8; int i; + unsigned frames_per_word; DEBUGASSERT(nwords > 0); - data16 = (uint16_t *)txbuffer; - data8 = (uint8_t *)txbuffer; + data16 = (uint16_t *)priv->txbuf; + frames_per_word = priv->nbits / priv->config->nbits; - if (!txbuffer) + if (!priv->txbuf) { - for (i = 0; i < nwords - 1; i++) + for (i = 0; i < nwords * frames_per_word - 1; i++) { putreg32(0, MPFS_SPI_TX_DATA); } putreg32(0, MPFS_SPI_TX_LAST); + priv->tx_pos += nwords; } - else if (priv->nbits == 8) + else if (priv->config->nbits == 8) { for (i = 0; i < nwords - 1; i++) { - putreg32((uint32_t)data8[priv->tx_pos++], MPFS_SPI_TX_DATA); + mpfs_spi_write_tx8(priv, frames_per_word, false); } - putreg32((uint32_t)data8[priv->tx_pos++], MPFS_SPI_TX_LAST); + mpfs_spi_write_tx8(priv, frames_per_word, true); } else { @@ -783,6 +839,39 @@ static void mpfs_spi_load_tx_fifo(struct mpfs_spi_priv_s *priv, } } +/**************************************************************************** + * Name: mpfs_spi_read_rx8 + * + * Description: + * Read one word from RX fifo in configured size frames + * + * Input Parameters: + * priv - SPI private state data + * nframes - Number of 8-bit data per word + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void mpfs_spi_read_rx8(struct mpfs_spi_priv_s *priv, + unsigned nframes) +{ + uint8_t *data8 = (uint8_t *)priv->rxbuf; + unsigned pos = priv->rx_pos++; + + /* Calculate octet position in the rx-buffer */ + + pos *= nframes; + + /* Read all octets for of the word */ + + while (nframes-- > 0) + { + data8[pos + nframes] = getreg32(MPFS_SPI_RX_DATA); + } +} + /**************************************************************************** * Name: mpfs_spi_unload_rx_fifo * @@ -792,7 +881,6 @@ static void mpfs_spi_load_tx_fifo(struct mpfs_spi_priv_s *priv, * * Input Parameters: * priv - SPI private state data - * txbuffer - A pointer to the buffer of data for receiving data * nwords - the length of data that to be exchanged in units of words. * * Returned Value: @@ -801,36 +889,34 @@ static void mpfs_spi_load_tx_fifo(struct mpfs_spi_priv_s *priv, ****************************************************************************/ static void mpfs_spi_unload_rx_fifo(struct mpfs_spi_priv_s *priv, - void *rxbuffer, uint32_t nwords) { uint16_t *data16; - uint8_t *data8; int i; + unsigned frames_per_word; DEBUGASSERT(nwords > 0); - data16 = (uint16_t *)rxbuffer; - data8 = (uint8_t *)rxbuffer; - - if (!rxbuffer) + if (!priv->rxbuf) { modifyreg32(MPFS_SPI_COMMAND, 0, MPFS_SPI_RXFIFORST); } - else if (priv->nbits == 8) + else if (mpfs_spi_config.nbits == 8) { + frames_per_word = priv->nbits / priv->config->nbits; for (i = 0; i < nwords - 1; i++) { - data8[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); + mpfs_spi_read_rx8(priv, frames_per_word); } if (mpfs_rx_wait_last_frame(priv) == 0) { - data8[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); + mpfs_spi_read_rx8(priv, frames_per_word); } } - else if (priv->nbits == 16) + else { + data16 = (uint16_t *)priv->rxbuf; for (i = 0; i < nwords - 1; i++) { data16[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); @@ -907,11 +993,11 @@ static void mpfs_spi_irq_exchange(struct mpfs_spi_priv_s *priv, if (nwords > priv->fifosize) { - mpfs_spi_load_tx_fifo(priv, txbuffer, priv->fifolevel); + mpfs_spi_load_tx_fifo(priv, priv->fifolevel); } else { - mpfs_spi_load_tx_fifo(priv, txbuffer, nwords); + mpfs_spi_load_tx_fifo(priv, nwords); } /* Enable TX, RX, underrun and overflow interrupts */ @@ -1305,11 +1391,11 @@ static int mpfs_spi_irq(int cpuint, void *context, void *arg) if (remaining <= priv->fifosize) { - mpfs_spi_unload_rx_fifo(priv, priv->rxbuf, remaining); + mpfs_spi_unload_rx_fifo(priv, remaining); } else { - mpfs_spi_unload_rx_fifo(priv, priv->rxbuf, priv->fifolevel); + mpfs_spi_unload_rx_fifo(priv, priv->fifolevel); } remaining = priv->txwords - priv->tx_pos; @@ -1325,11 +1411,11 @@ static int mpfs_spi_irq(int cpuint, void *context, void *arg) { if (remaining <= priv->fifosize) { - mpfs_spi_load_tx_fifo(priv, priv->txbuf, remaining); + mpfs_spi_load_tx_fifo(priv, remaining); } else { - mpfs_spi_load_tx_fifo(priv, priv->txbuf, priv->fifolevel); + mpfs_spi_load_tx_fifo(priv, priv->fifolevel); } } }