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 <jukkax@ssrc.tii.ae>
This commit is contained in:
parent
186b11c941
commit
fd3f0b7dd9
1 changed files with 116 additions and 30 deletions
|
@ -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 (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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue