Unverified Commit 8ad07d79 authored by Quanyang Wang's avatar Quanyang Wang Committed by Mark Brown
Browse files

spi: spi-zynqmp-gqspi: transmit dummy circles by using the controller's internal functionality



There is a data corruption issue that occurs in the reading operation
(cmd:0x6c) when transmitting common data as dummy circles.

The gqspi controller has the functionality to send dummy clock circles.
When writing data with the fields [receive, transmit, data_xfer] = [0,0,1]
to the Generic FIFO, and configuring the correct SPI mode, the controller
will transmit dummy circles.

So let's switch to hardware dummy cycles transfer to fix this issue.

Fixes: 1c26372e ("spi: spi-zynqmp-gqspi: Update driver to use spi-mem framework")
Signed-off-by: default avatarQuanyang Wang <quanyang.wang@windriver.com>
Reviewed-by: default avatarAmit Kumar Mahapatra <amit.kumar-mahapatra@xilinx.com>
Link: https://lore.kernel.org/r/20210408040223.23134-4-quanyang.wang@windriver.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent a0f65be6
Loading
Loading
Loading
Loading
+18 −22
Original line number Diff line number Diff line
@@ -521,7 +521,7 @@ static void zynqmp_qspi_filltxfifo(struct zynqmp_qspi *xqspi, int size)
{
	u32 count = 0, intermediate;

	while ((xqspi->bytes_to_transfer > 0) && (count < size)) {
	while ((xqspi->bytes_to_transfer > 0) && (count < size) && (xqspi->txbuf)) {
		memcpy(&intermediate, xqspi->txbuf, 4);
		zynqmp_gqspi_write(xqspi, GQSPI_TXD_OFST, intermediate);

@@ -580,7 +580,7 @@ static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits,
		genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
		genfifoentry |= GQSPI_GENFIFO_TX;
		transfer_len = xqspi->bytes_to_transfer;
	} else {
	} else if (xqspi->rxbuf) {
		genfifoentry &= ~GQSPI_GENFIFO_TX;
		genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
		genfifoentry |= GQSPI_GENFIFO_RX;
@@ -588,6 +588,11 @@ static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits,
			transfer_len = xqspi->dma_rx_bytes;
		else
			transfer_len = xqspi->bytes_to_receive;
	} else {
		/* Sending dummy circles here */
		genfifoentry &= ~(GQSPI_GENFIFO_TX | GQSPI_GENFIFO_RX);
		genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
		transfer_len = xqspi->bytes_to_transfer;
	}
	genfifoentry |= zynqmp_qspi_selectspimode(xqspi, nbits);
	xqspi->genfifoentry = genfifoentry;
@@ -1011,32 +1016,23 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
	}

	if (op->dummy.nbytes) {
		tmpbuf = kzalloc(op->dummy.nbytes, GFP_KERNEL | GFP_DMA);
		if (!tmpbuf)
			return -ENOMEM;
		memset(tmpbuf, 0xff, op->dummy.nbytes);
		reinit_completion(&xqspi->data_completion);
		xqspi->txbuf = tmpbuf;
		xqspi->txbuf = NULL;
		xqspi->rxbuf = NULL;
		xqspi->bytes_to_transfer = op->dummy.nbytes;
		/*
		 * xqspi->bytes_to_transfer here represents the dummy circles
		 * which need to be sent.
		 */
		xqspi->bytes_to_transfer = op->dummy.nbytes * 8 / op->dummy.buswidth;
		xqspi->bytes_to_receive = 0;
		zynqmp_qspi_write_op(xqspi, op->dummy.buswidth,
		/*
		 * Using op->data.buswidth instead of op->dummy.buswidth here because
		 * we need to use it to configure the correct SPI mode.
		 */
		zynqmp_qspi_write_op(xqspi, op->data.buswidth,
				     genfifoentry);
		zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
				   zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
				   GQSPI_CFG_START_GEN_FIFO_MASK);
		zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
				   GQSPI_IER_TXEMPTY_MASK |
				   GQSPI_IER_GENFIFOEMPTY_MASK |
				   GQSPI_IER_TXNOT_FULL_MASK);
		if (!wait_for_completion_interruptible_timeout
		    (&xqspi->data_completion, msecs_to_jiffies(1000))) {
			err = -ETIMEDOUT;
			kfree(tmpbuf);
			goto return_err;
		}

		kfree(tmpbuf);
	}

	if (op->data.nbytes) {