spi: Fixes for v5.5

A small collection of fixes here, one to make the newly added PTP
 timestamping code more accurate, a few driver fixes and a fix for the
 core DT binding to document the fact that we support eight wire buses.
 -----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAl4TMdwTHGJyb29uaWVA
 a2VybmVsLm9yZwAKCRAk1otyXVSH0M5UB/9w0mzrmuaJzctm3Jm8LiCIjJoZ0woQ
 chgbhm2C/I6idENxdUhaJ1YZMI6NkmJKpJy5tQ/QH4MnbOVT/vHIEmIsRYO0vYoF
 ApERJLia8da1OpiJlPTbsg3eUXVNmPMVeAkq5MgKSflaIjV6Ejc0FRWmgDYvzhu9
 xkCsptAF7MYPUuHdBcjXPscSf1/w+FdDy8VYncEluyJ0NpGDU64N/XdTwRmsG8QW
 BxA1jPPKi445NsC+OV8SFfNZbeEXG2iSEBPvp4tMGtd0TiIp3UNLTRzMstEFE6SD
 hCzL9fQEzUgHD+B0vLmccyy0HR0phk6813jf9KeToAjAxKtf5XhQajW+
 =Ad4n
 -----END PGP SIGNATURE-----

Merge tag 'spi-fix-v5.5-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:
 "A small collection of fixes here, one to make the newly added PTP
  timestamping code more accurate, a few driver fixes and a fix for the
  core DT binding to document the fact that we support eight wire buses"

* tag 'spi-fix-v5.5-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: Document Octal mode as valid SPI bus width
  spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls
  spi: spi-fsl-dspi: Fix 16-bit word order in 32-bit XSPI mode
  spi: Don't look at TX buffer for PTP system timestamping
  spi: uniphier: Fix FIFO threshold
This commit is contained in:
Linus Torvalds 2020-01-06 12:34:44 -08:00
commit ec7b3f5372
7 changed files with 54 additions and 47 deletions

View File

@ -111,7 +111,7 @@ patternProperties:
spi-rx-bus-width:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [ 1, 2, 4 ]
- enum: [ 1, 2, 4, 8 ]
- default: 1
description:
Bus width to the SPI bus used for MISO.
@ -123,7 +123,7 @@ patternProperties:
spi-tx-bus-width:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [ 1, 2, 4 ]
- enum: [ 1, 2, 4, 8 ]
- default: 1
description:
Bus width to the SPI bus used for MOSI.

View File

@ -172,9 +172,11 @@ static inline u32 rx_max(struct dw_spi *dws)
static void dw_writer(struct dw_spi *dws)
{
u32 max = tx_max(dws);
u32 max;
u16 txw = 0;
spin_lock(&dws->buf_lock);
max = tx_max(dws);
while (max--) {
/* Set the tx word if the transfer's original "tx" is not null */
if (dws->tx_end - dws->len) {
@ -186,13 +188,16 @@ static void dw_writer(struct dw_spi *dws)
dw_write_io_reg(dws, DW_SPI_DR, txw);
dws->tx += dws->n_bytes;
}
spin_unlock(&dws->buf_lock);
}
static void dw_reader(struct dw_spi *dws)
{
u32 max = rx_max(dws);
u32 max;
u16 rxw;
spin_lock(&dws->buf_lock);
max = rx_max(dws);
while (max--) {
rxw = dw_read_io_reg(dws, DW_SPI_DR);
/* Care rx only if the transfer's original "rx" is not null */
@ -204,6 +209,7 @@ static void dw_reader(struct dw_spi *dws)
}
dws->rx += dws->n_bytes;
}
spin_unlock(&dws->buf_lock);
}
static void int_error_stop(struct dw_spi *dws, const char *msg)
@ -276,18 +282,20 @@ static int dw_spi_transfer_one(struct spi_controller *master,
{
struct dw_spi *dws = spi_controller_get_devdata(master);
struct chip_data *chip = spi_get_ctldata(spi);
unsigned long flags;
u8 imask = 0;
u16 txlevel = 0;
u32 cr0;
int ret;
dws->dma_mapped = 0;
spin_lock_irqsave(&dws->buf_lock, flags);
dws->tx = (void *)transfer->tx_buf;
dws->tx_end = dws->tx + transfer->len;
dws->rx = transfer->rx_buf;
dws->rx_end = dws->rx + transfer->len;
dws->len = transfer->len;
spin_unlock_irqrestore(&dws->buf_lock, flags);
spi_enable_chip(dws, 0);
@ -471,6 +479,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
dws->type = SSI_MOTO_SPI;
dws->dma_inited = 0;
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
spin_lock_init(&dws->buf_lock);
spi_controller_set_devdata(master, dws);

View File

@ -119,6 +119,7 @@ struct dw_spi {
size_t len;
void *tx;
void *tx_end;
spinlock_t buf_lock;
void *rx;
void *rx_end;
int dma_mapped;

View File

@ -185,6 +185,7 @@ struct fsl_dspi {
struct spi_transfer *cur_transfer;
struct spi_message *cur_msg;
struct chip_data *cur_chip;
size_t progress;
size_t len;
const void *tx;
void *rx;
@ -586,21 +587,14 @@ static void dspi_tcfq_write(struct fsl_dspi *dspi)
dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
if (dspi->devtype_data->xspi_mode && dspi->bits_per_word > 16) {
/* Write two TX FIFO entries first, and then the corresponding
* CMD FIFO entry.
/* Write the CMD FIFO entry first, and then the two
* corresponding TX FIFO entries.
*/
u32 data = dspi_pop_tx(dspi);
if (dspi->cur_chip->ctar_val & SPI_CTAR_LSBFE) {
/* LSB */
tx_fifo_write(dspi, data & 0xFFFF);
tx_fifo_write(dspi, data >> 16);
} else {
/* MSB */
tx_fifo_write(dspi, data >> 16);
tx_fifo_write(dspi, data & 0xFFFF);
}
cmd_fifo_write(dspi);
tx_fifo_write(dspi, data & 0xFFFF);
tx_fifo_write(dspi, data >> 16);
} else {
/* Write one entry to both TX FIFO and CMD FIFO
* simultaneously.
@ -658,7 +652,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
u32 spi_tcr;
spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer,
dspi->tx - dspi->bytes_per_word, !dspi->irq);
dspi->progress, !dspi->irq);
/* Get transfer counter (in number of SPI transfers). It was
* reset to 0 when transfer(s) were started.
@ -667,6 +661,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
/* Update total number of bytes that were transferred */
msg->actual_length += spi_tcnt * dspi->bytes_per_word;
dspi->progress += spi_tcnt;
trans_mode = dspi->devtype_data->trans_mode;
if (trans_mode == DSPI_EOQ_MODE)
@ -679,7 +674,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
return 0;
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
dspi->tx, !dspi->irq);
dspi->progress, !dspi->irq);
if (trans_mode == DSPI_EOQ_MODE)
dspi_eoq_write(dspi);
@ -768,6 +763,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
dspi->rx = transfer->rx_buf;
dspi->rx_end = dspi->rx + transfer->len;
dspi->len = transfer->len;
dspi->progress = 0;
/* Validated transfer specific frame size (defaults applied) */
dspi->bits_per_word = transfer->bits_per_word;
if (transfer->bits_per_word <= 8)
@ -789,7 +785,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
SPI_CTARE_DTCP(1));
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
dspi->tx, !dspi->irq);
dspi->progress, !dspi->irq);
trans_mode = dspi->devtype_data->trans_mode;
switch (trans_mode) {

View File

@ -290,25 +290,32 @@ static void uniphier_spi_recv(struct uniphier_spi_priv *priv)
}
}
static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv)
static void uniphier_spi_set_fifo_threshold(struct uniphier_spi_priv *priv,
unsigned int threshold)
{
unsigned int fifo_threshold, fill_bytes;
u32 val;
fifo_threshold = DIV_ROUND_UP(priv->rx_bytes,
bytes_per_word(priv->bits_per_word));
fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH);
fill_bytes = fifo_threshold - (priv->rx_bytes - priv->tx_bytes);
/* set fifo threshold */
val = readl(priv->base + SSI_FC);
val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK);
val |= FIELD_PREP(SSI_FC_TXFTH_MASK, fifo_threshold);
val |= FIELD_PREP(SSI_FC_RXFTH_MASK, fifo_threshold);
val |= FIELD_PREP(SSI_FC_TXFTH_MASK, SSI_FIFO_DEPTH - threshold);
val |= FIELD_PREP(SSI_FC_RXFTH_MASK, threshold);
writel(val, priv->base + SSI_FC);
}
while (fill_bytes--)
static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv)
{
unsigned int fifo_threshold, fill_words;
unsigned int bpw = bytes_per_word(priv->bits_per_word);
fifo_threshold = DIV_ROUND_UP(priv->rx_bytes, bpw);
fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH);
uniphier_spi_set_fifo_threshold(priv, fifo_threshold);
fill_words = fifo_threshold -
DIV_ROUND_UP(priv->rx_bytes - priv->tx_bytes, bpw);
while (fill_words--)
uniphier_spi_send(priv);
}

View File

@ -1499,8 +1499,7 @@ static void spi_pump_messages(struct kthread_work *work)
* advances its @tx buffer pointer monotonically.
* @ctlr: Pointer to the spi_controller structure of the driver
* @xfer: Pointer to the transfer being timestamped
* @tx: Pointer to the current word within the xfer->tx_buf that the driver is
* preparing to transmit right now.
* @progress: How many words (not bytes) have been transferred so far
* @irqs_off: If true, will disable IRQs and preemption for the duration of the
* transfer, for less jitter in time measurement. Only compatible
* with PIO drivers. If true, must follow up with
@ -1510,21 +1509,19 @@ static void spi_pump_messages(struct kthread_work *work)
*/
void spi_take_timestamp_pre(struct spi_controller *ctlr,
struct spi_transfer *xfer,
const void *tx, bool irqs_off)
size_t progress, bool irqs_off)
{
u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8);
if (!xfer->ptp_sts)
return;
if (xfer->timestamped_pre)
return;
if (tx < (xfer->tx_buf + xfer->ptp_sts_word_pre * bytes_per_word))
if (progress < xfer->ptp_sts_word_pre)
return;
/* Capture the resolution of the timestamp */
xfer->ptp_sts_word_pre = (tx - xfer->tx_buf) / bytes_per_word;
xfer->ptp_sts_word_pre = progress;
xfer->timestamped_pre = true;
@ -1546,23 +1543,20 @@ EXPORT_SYMBOL_GPL(spi_take_timestamp_pre);
* timestamped.
* @ctlr: Pointer to the spi_controller structure of the driver
* @xfer: Pointer to the transfer being timestamped
* @tx: Pointer to the current word within the xfer->tx_buf that the driver has
* just transmitted.
* @progress: How many words (not bytes) have been transferred so far
* @irqs_off: If true, will re-enable IRQs and preemption for the local CPU.
*/
void spi_take_timestamp_post(struct spi_controller *ctlr,
struct spi_transfer *xfer,
const void *tx, bool irqs_off)
size_t progress, bool irqs_off)
{
u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8);
if (!xfer->ptp_sts)
return;
if (xfer->timestamped_post)
return;
if (tx < (xfer->tx_buf + xfer->ptp_sts_word_post * bytes_per_word))
if (progress < xfer->ptp_sts_word_post)
return;
ptp_read_system_postts(xfer->ptp_sts);
@ -1573,7 +1567,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr,
}
/* Capture the resolution of the timestamp */
xfer->ptp_sts_word_post = (tx - xfer->tx_buf) / bytes_per_word;
xfer->ptp_sts_word_post = progress;
xfer->timestamped_post = true;
}

View File

@ -689,10 +689,10 @@ extern void spi_finalize_current_transfer(struct spi_controller *ctlr);
/* Helper calls for driver to timestamp transfer */
void spi_take_timestamp_pre(struct spi_controller *ctlr,
struct spi_transfer *xfer,
const void *tx, bool irqs_off);
size_t progress, bool irqs_off);
void spi_take_timestamp_post(struct spi_controller *ctlr,
struct spi_transfer *xfer,
const void *tx, bool irqs_off);
size_t progress, bool irqs_off);
/* the spi driver core manages memory for the spi_controller classdev */
extern struct spi_controller *__spi_alloc_controller(struct device *host,