Commit ec7b3f53 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 5acefdc2 09b6636c
...@@ -111,7 +111,7 @@ patternProperties: ...@@ -111,7 +111,7 @@ patternProperties:
spi-rx-bus-width: spi-rx-bus-width:
allOf: allOf:
- $ref: /schemas/types.yaml#/definitions/uint32 - $ref: /schemas/types.yaml#/definitions/uint32
- enum: [ 1, 2, 4 ] - enum: [ 1, 2, 4, 8 ]
- default: 1 - default: 1
description: description:
Bus width to the SPI bus used for MISO. Bus width to the SPI bus used for MISO.
...@@ -123,7 +123,7 @@ patternProperties: ...@@ -123,7 +123,7 @@ patternProperties:
spi-tx-bus-width: spi-tx-bus-width:
allOf: allOf:
- $ref: /schemas/types.yaml#/definitions/uint32 - $ref: /schemas/types.yaml#/definitions/uint32
- enum: [ 1, 2, 4 ] - enum: [ 1, 2, 4, 8 ]
- default: 1 - default: 1
description: description:
Bus width to the SPI bus used for MOSI. Bus width to the SPI bus used for MOSI.
......
...@@ -172,9 +172,11 @@ static inline u32 rx_max(struct dw_spi *dws) ...@@ -172,9 +172,11 @@ static inline u32 rx_max(struct dw_spi *dws)
static void dw_writer(struct dw_spi *dws) static void dw_writer(struct dw_spi *dws)
{ {
u32 max = tx_max(dws); u32 max;
u16 txw = 0; u16 txw = 0;
spin_lock(&dws->buf_lock);
max = tx_max(dws);
while (max--) { while (max--) {
/* Set the tx word if the transfer's original "tx" is not null */ /* Set the tx word if the transfer's original "tx" is not null */
if (dws->tx_end - dws->len) { if (dws->tx_end - dws->len) {
...@@ -186,13 +188,16 @@ static void dw_writer(struct dw_spi *dws) ...@@ -186,13 +188,16 @@ static void dw_writer(struct dw_spi *dws)
dw_write_io_reg(dws, DW_SPI_DR, txw); dw_write_io_reg(dws, DW_SPI_DR, txw);
dws->tx += dws->n_bytes; dws->tx += dws->n_bytes;
} }
spin_unlock(&dws->buf_lock);
} }
static void dw_reader(struct dw_spi *dws) static void dw_reader(struct dw_spi *dws)
{ {
u32 max = rx_max(dws); u32 max;
u16 rxw; u16 rxw;
spin_lock(&dws->buf_lock);
max = rx_max(dws);
while (max--) { while (max--) {
rxw = dw_read_io_reg(dws, DW_SPI_DR); rxw = dw_read_io_reg(dws, DW_SPI_DR);
/* Care rx only if the transfer's original "rx" is not null */ /* Care rx only if the transfer's original "rx" is not null */
...@@ -204,6 +209,7 @@ static void dw_reader(struct dw_spi *dws) ...@@ -204,6 +209,7 @@ static void dw_reader(struct dw_spi *dws)
} }
dws->rx += dws->n_bytes; dws->rx += dws->n_bytes;
} }
spin_unlock(&dws->buf_lock);
} }
static void int_error_stop(struct dw_spi *dws, const char *msg) 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, ...@@ -276,18 +282,20 @@ static int dw_spi_transfer_one(struct spi_controller *master,
{ {
struct dw_spi *dws = spi_controller_get_devdata(master); struct dw_spi *dws = spi_controller_get_devdata(master);
struct chip_data *chip = spi_get_ctldata(spi); struct chip_data *chip = spi_get_ctldata(spi);
unsigned long flags;
u8 imask = 0; u8 imask = 0;
u16 txlevel = 0; u16 txlevel = 0;
u32 cr0; u32 cr0;
int ret; int ret;
dws->dma_mapped = 0; dws->dma_mapped = 0;
spin_lock_irqsave(&dws->buf_lock, flags);
dws->tx = (void *)transfer->tx_buf; dws->tx = (void *)transfer->tx_buf;
dws->tx_end = dws->tx + transfer->len; dws->tx_end = dws->tx + transfer->len;
dws->rx = transfer->rx_buf; dws->rx = transfer->rx_buf;
dws->rx_end = dws->rx + transfer->len; dws->rx_end = dws->rx + transfer->len;
dws->len = transfer->len; dws->len = transfer->len;
spin_unlock_irqrestore(&dws->buf_lock, flags);
spi_enable_chip(dws, 0); spi_enable_chip(dws, 0);
...@@ -471,6 +479,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -471,6 +479,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
dws->type = SSI_MOTO_SPI; dws->type = SSI_MOTO_SPI;
dws->dma_inited = 0; dws->dma_inited = 0;
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
spin_lock_init(&dws->buf_lock);
spi_controller_set_devdata(master, dws); spi_controller_set_devdata(master, dws);
......
...@@ -119,6 +119,7 @@ struct dw_spi { ...@@ -119,6 +119,7 @@ struct dw_spi {
size_t len; size_t len;
void *tx; void *tx;
void *tx_end; void *tx_end;
spinlock_t buf_lock;
void *rx; void *rx;
void *rx_end; void *rx_end;
int dma_mapped; int dma_mapped;
......
...@@ -185,6 +185,7 @@ struct fsl_dspi { ...@@ -185,6 +185,7 @@ struct fsl_dspi {
struct spi_transfer *cur_transfer; struct spi_transfer *cur_transfer;
struct spi_message *cur_msg; struct spi_message *cur_msg;
struct chip_data *cur_chip; struct chip_data *cur_chip;
size_t progress;
size_t len; size_t len;
const void *tx; const void *tx;
void *rx; void *rx;
...@@ -586,21 +587,14 @@ static void dspi_tcfq_write(struct fsl_dspi *dspi) ...@@ -586,21 +587,14 @@ static void dspi_tcfq_write(struct fsl_dspi *dspi)
dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT; dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
if (dspi->devtype_data->xspi_mode && dspi->bits_per_word > 16) { if (dspi->devtype_data->xspi_mode && dspi->bits_per_word > 16) {
/* Write two TX FIFO entries first, and then the corresponding /* Write the CMD FIFO entry first, and then the two
* CMD FIFO entry. * corresponding TX FIFO entries.
*/ */
u32 data = dspi_pop_tx(dspi); 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); cmd_fifo_write(dspi);
tx_fifo_write(dspi, data & 0xFFFF);
tx_fifo_write(dspi, data >> 16);
} else { } else {
/* Write one entry to both TX FIFO and CMD FIFO /* Write one entry to both TX FIFO and CMD FIFO
* simultaneously. * simultaneously.
...@@ -658,7 +652,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi) ...@@ -658,7 +652,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
u32 spi_tcr; u32 spi_tcr;
spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer, 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 /* Get transfer counter (in number of SPI transfers). It was
* reset to 0 when transfer(s) were started. * reset to 0 when transfer(s) were started.
...@@ -667,6 +661,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi) ...@@ -667,6 +661,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr); spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
/* Update total number of bytes that were transferred */ /* Update total number of bytes that were transferred */
msg->actual_length += spi_tcnt * dspi->bytes_per_word; msg->actual_length += spi_tcnt * dspi->bytes_per_word;
dspi->progress += spi_tcnt;
trans_mode = dspi->devtype_data->trans_mode; trans_mode = dspi->devtype_data->trans_mode;
if (trans_mode == DSPI_EOQ_MODE) if (trans_mode == DSPI_EOQ_MODE)
...@@ -679,7 +674,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi) ...@@ -679,7 +674,7 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
return 0; return 0;
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer, spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
dspi->tx, !dspi->irq); dspi->progress, !dspi->irq);
if (trans_mode == DSPI_EOQ_MODE) if (trans_mode == DSPI_EOQ_MODE)
dspi_eoq_write(dspi); dspi_eoq_write(dspi);
...@@ -768,6 +763,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, ...@@ -768,6 +763,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
dspi->rx = transfer->rx_buf; dspi->rx = transfer->rx_buf;
dspi->rx_end = dspi->rx + transfer->len; dspi->rx_end = dspi->rx + transfer->len;
dspi->len = transfer->len; dspi->len = transfer->len;
dspi->progress = 0;
/* Validated transfer specific frame size (defaults applied) */ /* Validated transfer specific frame size (defaults applied) */
dspi->bits_per_word = transfer->bits_per_word; dspi->bits_per_word = transfer->bits_per_word;
if (transfer->bits_per_word <= 8) if (transfer->bits_per_word <= 8)
...@@ -789,7 +785,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, ...@@ -789,7 +785,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
SPI_CTARE_DTCP(1)); SPI_CTARE_DTCP(1));
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer, spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
dspi->tx, !dspi->irq); dspi->progress, !dspi->irq);
trans_mode = dspi->devtype_data->trans_mode; trans_mode = dspi->devtype_data->trans_mode;
switch (trans_mode) { switch (trans_mode) {
......
...@@ -290,25 +290,32 @@ static void uniphier_spi_recv(struct uniphier_spi_priv *priv) ...@@ -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; 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 = readl(priv->base + SSI_FC);
val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK); val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK);
val |= FIELD_PREP(SSI_FC_TXFTH_MASK, fifo_threshold); val |= FIELD_PREP(SSI_FC_TXFTH_MASK, SSI_FIFO_DEPTH - threshold);
val |= FIELD_PREP(SSI_FC_RXFTH_MASK, fifo_threshold); val |= FIELD_PREP(SSI_FC_RXFTH_MASK, threshold);
writel(val, priv->base + SSI_FC); writel(val, priv->base + SSI_FC);
}
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_bytes--) while (fill_words--)
uniphier_spi_send(priv); uniphier_spi_send(priv);
} }
......
...@@ -1499,8 +1499,7 @@ static void spi_pump_messages(struct kthread_work *work) ...@@ -1499,8 +1499,7 @@ static void spi_pump_messages(struct kthread_work *work)
* advances its @tx buffer pointer monotonically. * advances its @tx buffer pointer monotonically.
* @ctlr: Pointer to the spi_controller structure of the driver * @ctlr: Pointer to the spi_controller structure of the driver
* @xfer: Pointer to the transfer being timestamped * @xfer: Pointer to the transfer being timestamped
* @tx: Pointer to the current word within the xfer->tx_buf that the driver is * @progress: How many words (not bytes) have been transferred so far
* preparing to transmit right now.
* @irqs_off: If true, will disable IRQs and preemption for the duration of the * @irqs_off: If true, will disable IRQs and preemption for the duration of the
* transfer, for less jitter in time measurement. Only compatible * transfer, for less jitter in time measurement. Only compatible
* with PIO drivers. If true, must follow up with * with PIO drivers. If true, must follow up with
...@@ -1510,21 +1509,19 @@ static void spi_pump_messages(struct kthread_work *work) ...@@ -1510,21 +1509,19 @@ static void spi_pump_messages(struct kthread_work *work)
*/ */
void spi_take_timestamp_pre(struct spi_controller *ctlr, void spi_take_timestamp_pre(struct spi_controller *ctlr,
struct spi_transfer *xfer, 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) if (!xfer->ptp_sts)
return; return;
if (xfer->timestamped_pre) if (xfer->timestamped_pre)
return; return;
if (tx < (xfer->tx_buf + xfer->ptp_sts_word_pre * bytes_per_word)) if (progress < xfer->ptp_sts_word_pre)
return; return;
/* Capture the resolution of the timestamp */ /* 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; xfer->timestamped_pre = true;
...@@ -1546,23 +1543,20 @@ EXPORT_SYMBOL_GPL(spi_take_timestamp_pre); ...@@ -1546,23 +1543,20 @@ EXPORT_SYMBOL_GPL(spi_take_timestamp_pre);
* timestamped. * timestamped.
* @ctlr: Pointer to the spi_controller structure of the driver * @ctlr: Pointer to the spi_controller structure of the driver
* @xfer: Pointer to the transfer being timestamped * @xfer: Pointer to the transfer being timestamped
* @tx: Pointer to the current word within the xfer->tx_buf that the driver has * @progress: How many words (not bytes) have been transferred so far
* just transmitted.
* @irqs_off: If true, will re-enable IRQs and preemption for the local CPU. * @irqs_off: If true, will re-enable IRQs and preemption for the local CPU.
*/ */
void spi_take_timestamp_post(struct spi_controller *ctlr, void spi_take_timestamp_post(struct spi_controller *ctlr,
struct spi_transfer *xfer, 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) if (!xfer->ptp_sts)
return; return;
if (xfer->timestamped_post) if (xfer->timestamped_post)
return; return;
if (tx < (xfer->tx_buf + xfer->ptp_sts_word_post * bytes_per_word)) if (progress < xfer->ptp_sts_word_post)
return; return;
ptp_read_system_postts(xfer->ptp_sts); ptp_read_system_postts(xfer->ptp_sts);
...@@ -1573,7 +1567,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr, ...@@ -1573,7 +1567,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr,
} }
/* Capture the resolution of the timestamp */ /* 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; xfer->timestamped_post = true;
} }
......
...@@ -689,10 +689,10 @@ extern void spi_finalize_current_transfer(struct spi_controller *ctlr); ...@@ -689,10 +689,10 @@ extern void spi_finalize_current_transfer(struct spi_controller *ctlr);
/* Helper calls for driver to timestamp transfer */ /* Helper calls for driver to timestamp transfer */
void spi_take_timestamp_pre(struct spi_controller *ctlr, void spi_take_timestamp_pre(struct spi_controller *ctlr,
struct spi_transfer *xfer, 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, void spi_take_timestamp_post(struct spi_controller *ctlr,
struct spi_transfer *xfer, 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 */ /* the spi driver core manages memory for the spi_controller classdev */
extern struct spi_controller *__spi_alloc_controller(struct device *host, extern struct spi_controller *__spi_alloc_controller(struct device *host,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment