mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 06:12:08 +00:00
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:
commit
ec7b3f5372
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user