spi: Fixes for v6.7

A few bigger things here, the main one being that there were changes to
 the atmel driver in this cycle which made it possible to kill transfers
 being used for filesystem I/O which turned out to be very disruptive,
 the series of patches here undoes that and hardens things up further.
 
 There's also a few smaller driver specific changes, the main one being
 to revert a change that duplicted delays.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmWASuIACgkQJNaLcl1U
 h9BEJQf/S3NWQvQPZ+k3YofQuvepPx7LfBDwJXcfHFqXXabjeNHZfQyftrWpik3s
 KAGqRhZdQyw8Q2aMiL8/2uXPf8uihuZNoVEbMNd2IHHE2q7uIRdR92E1sf912VaO
 T5yQPfVAJo6PthaSYAPGyhsPTPbvSWwgh1sMkHAdfITTKPHniQWVb9Bt1k+S0c6b
 xerBN/Jg9nX5+2WgnfA9fznD8+o0H+MF9bSudmDqdCjgXr59bmJccZHm/aasU0zq
 ELaqbYt2sTIpiRmvkuTWQ2dGrNdnuCQOkP3OFvzAsF4JCWUADPtFtMi1HHIkygdK
 q+L/M55OvJdUsXHLAtlqMEWW7ne2ZA==
 =l4ac
 -----END PGP SIGNATURE-----

Merge tag 'spi-fix-v6.7-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:
 "A few bigger things here, the main one being that there were changes
  to the atmel driver in this cycle which made it possible to kill
  transfers being used for filesystem I/O which turned out to be very
  disruptive, the series of patches here undoes that and hardens things
  up further.

  There's also a few smaller driver specific changes, the main one being
  to revert a change that duplicted delays"

* tag 'spi-fix-v6.7-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: atmel: Fix clock issue when using devices with different polarities
  spi: spi-imx: correctly configure burst length when using dma
  spi: cadence: revert "Add SPI transfer delays"
  spi: atmel: Prevent spi transfers from being killed
  spi: atmel: Drop unused defines
  spi: atmel: Do not cancel a transfer upon any signal
This commit is contained in:
Linus Torvalds 2023-12-18 10:59:57 -08:00
commit 26d6084791
3 changed files with 96 additions and 15 deletions

View File

@ -22,6 +22,7 @@
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/iopoll.h>
#include <trace/events/spi.h>
/* SPI register offsets */
@ -233,9 +234,6 @@
*/
#define DMA_MIN_BYTES 16
#define SPI_DMA_MIN_TIMEOUT (msecs_to_jiffies(1000))
#define SPI_DMA_TIMEOUT_PER_10K (msecs_to_jiffies(4))
#define AUTOSUSPEND_TIMEOUT 2000
struct atmel_spi_caps {
@ -279,6 +277,7 @@ struct atmel_spi {
bool keep_cs;
u32 fifo_size;
bool last_polarity;
u8 native_cs_free;
u8 native_cs_for_gpio;
};
@ -291,6 +290,22 @@ struct atmel_spi_device {
#define SPI_MAX_DMA_XFER 65535 /* true for both PDC and DMA */
#define INVALID_DMA_ADDRESS 0xffffffff
/*
* This frequency can be anything supported by the controller, but to avoid
* unnecessary delay, the highest possible frequency is chosen.
*
* This frequency is the highest possible which is not interfering with other
* chip select registers (see Note for Serial Clock Bit Rate configuration in
* Atmel-11121F-ATARM-SAMA5D3-Series-Datasheet_02-Feb-16, page 1283)
*/
#define DUMMY_MSG_FREQUENCY 0x02
/*
* 8 bits is the minimum data the controller is capable of sending.
*
* This message can be anything as it should not be treated by any SPI device.
*/
#define DUMMY_MSG 0xAA
/*
* Version 2 of the SPI controller has
* - CR.LASTXFER
@ -304,6 +319,43 @@ static bool atmel_spi_is_v2(struct atmel_spi *as)
return as->caps.is_spi2;
}
/*
* Send a dummy message.
*
* This is sometimes needed when using a CS GPIO to force clock transition when
* switching between devices with different polarities.
*/
static void atmel_spi_send_dummy(struct atmel_spi *as, struct spi_device *spi, int chip_select)
{
u32 status;
u32 csr;
/*
* Set a clock frequency to allow sending message on SPI bus.
* The frequency here can be anything, but is needed for
* the controller to send the data.
*/
csr = spi_readl(as, CSR0 + 4 * chip_select);
csr = SPI_BFINS(SCBR, DUMMY_MSG_FREQUENCY, csr);
spi_writel(as, CSR0 + 4 * chip_select, csr);
/*
* Read all data coming from SPI bus, needed to be able to send
* the message.
*/
spi_readl(as, RDR);
while (spi_readl(as, SR) & SPI_BIT(RDRF)) {
spi_readl(as, RDR);
cpu_relax();
}
spi_writel(as, TDR, DUMMY_MSG);
readl_poll_timeout_atomic(as->regs + SPI_SR, status,
(status & SPI_BIT(TXEMPTY)), 1, 1000);
}
/*
* Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
* they assume that spi slave device state will not change on deselect, so
@ -320,11 +372,17 @@ static bool atmel_spi_is_v2(struct atmel_spi *as)
* Master on Chip Select 0.") No workaround exists for that ... so for
* nCS0 on that chip, we (a) don't use the GPIO, (b) can't support CS_HIGH,
* and (c) will trigger that first erratum in some cases.
*
* When changing the clock polarity, the SPI controller waits for the next
* transmission to enforce the default clock state. This may be an issue when
* using a GPIO as Chip Select: the clock level is applied only when the first
* packet is sent, once the CS has already been asserted. The workaround is to
* avoid this by sending a first (dummy) message before toggling the CS state.
*/
static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
{
struct atmel_spi_device *asd = spi->controller_state;
bool new_polarity;
int chip_select;
u32 mr;
@ -353,6 +411,25 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
}
mr = spi_readl(as, MR);
/*
* Ensures the clock polarity is valid before we actually
* assert the CS to avoid spurious clock edges to be
* processed by the spi devices.
*/
if (spi_get_csgpiod(spi, 0)) {
new_polarity = (asd->csr & SPI_BIT(CPOL)) != 0;
if (new_polarity != as->last_polarity) {
/*
* Need to disable the GPIO before sending the dummy
* message because it is already set by the spi core.
*/
gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), 0);
atmel_spi_send_dummy(as, spi, chip_select);
as->last_polarity = new_polarity;
gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), 1);
}
}
} else {
u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
int i;
@ -1336,12 +1413,10 @@ static int atmel_spi_one_transfer(struct spi_controller *host,
}
dma_timeout = msecs_to_jiffies(spi_controller_xfer_timeout(host, xfer));
ret_timeout = wait_for_completion_interruptible_timeout(&as->xfer_completion,
dma_timeout);
if (ret_timeout <= 0) {
dev_err(&spi->dev, "spi transfer %s\n",
!ret_timeout ? "timeout" : "canceled");
as->done_status = ret_timeout < 0 ? ret_timeout : -EIO;
ret_timeout = wait_for_completion_timeout(&as->xfer_completion, dma_timeout);
if (!ret_timeout) {
dev_err(&spi->dev, "spi transfer timeout\n");
as->done_status = -EIO;
}
if (as->done_status)

View File

@ -451,7 +451,6 @@ static int cdns_transfer_one(struct spi_controller *ctlr,
udelay(10);
cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0);
spi_transfer_delay_exec(transfer);
cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT);
return transfer->len;

View File

@ -659,11 +659,18 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
ctrl |= (spi_imx->target_burst * 8 - 1)
<< MX51_ECSPI_CTRL_BL_OFFSET;
else {
if (spi_imx->count >= 512)
ctrl |= 0xFFF << MX51_ECSPI_CTRL_BL_OFFSET;
else
ctrl |= (spi_imx->count * spi_imx->bits_per_word - 1)
if (spi_imx->usedma) {
ctrl |= (spi_imx->bits_per_word *
spi_imx_bytes_per_word(spi_imx->bits_per_word) - 1)
<< MX51_ECSPI_CTRL_BL_OFFSET;
} else {
if (spi_imx->count >= MX51_ECSPI_CTRL_MAX_BURST)
ctrl |= (MX51_ECSPI_CTRL_MAX_BURST - 1)
<< MX51_ECSPI_CTRL_BL_OFFSET;
else
ctrl |= (spi_imx->count * spi_imx->bits_per_word - 1)
<< MX51_ECSPI_CTRL_BL_OFFSET;
}
}
/* set clock speed */