From f29c916b499177c70b320a4de01ddaa2eb8c7bfa Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 10 Dec 2024 11:04:21 +0200 Subject: [PATCH] arch/risc-v/src/mpfs/mpfs_corespi.c: Add support for multiple bit widths The corespi fpga block supports just one frame length, which is defined when the block is instantiated on the FPGA. This adds support for emulating different frame lengths if they are multiples of 8-bit. That is, with 8-bit corespi one can do 8,16 and 24-bit transfers. This is implemented by simply writing several 8-bit frames for a single word when needed. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_corespi.c | 146 ++++++++++++++++++++++------ 1 file changed, 116 insertions(+), 30 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_corespi.c b/arch/risc-v/src/mpfs/mpfs_corespi.c index b7636c953bcb3..9735efdcdf327 100644 --- a/arch/risc-v/src/mpfs/mpfs_corespi.c +++ b/arch/risc-v/src/mpfs/mpfs_corespi.c @@ -611,10 +611,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(); + } } } @@ -720,6 +731,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 * @@ -728,7 +785,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 @@ -741,34 +797,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 { @@ -781,6 +837,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 * @@ -790,7 +879,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: @@ -799,36 +887,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 (priv->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); @@ -905,11 +991,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 */ @@ -1303,11 +1389,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; @@ -1323,11 +1409,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); } } }