Skip to content

Commit

Permalink
arch/risc-v/src/mpfs/mpfs_corespi.c: Add support for multiple bit widths
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
jlaitine committed Dec 11, 2024
1 parent 4d6735f commit 6819583
Showing 1 changed file with 116 additions and 30 deletions.
146 changes: 116 additions & 30 deletions arch/risc-v/src/mpfs/mpfs_corespi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
}

Expand Down Expand Up @@ -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
*
Expand All @@ -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
Expand All @@ -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
{
Expand All @@ -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
*
Expand All @@ -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:
Expand All @@ -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);
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
}
}
Expand Down

0 comments on commit 6819583

Please sign in to comment.