mirror of https://gitee.com/openkylin/linux.git
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: 1c26372e5a
("spi: spi-zynqmp-gqspi: Update driver to use spi-mem framework")
Signed-off-by: Quanyang Wang <quanyang.wang@windriver.com>
Reviewed-by: Amit Kumar Mahapatra <amit.kumar-mahapatra@xilinx.com>
Link: https://lore.kernel.org/r/20210408040223.23134-4-quanyang.wang@windriver.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
a0f65be6e8
commit
8ad07d79bd
|
@ -521,7 +521,7 @@ static void zynqmp_qspi_filltxfifo(struct zynqmp_qspi *xqspi, int size)
|
||||||
{
|
{
|
||||||
u32 count = 0, intermediate;
|
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);
|
memcpy(&intermediate, xqspi->txbuf, 4);
|
||||||
zynqmp_gqspi_write(xqspi, GQSPI_TXD_OFST, intermediate);
|
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_DATA_XFER;
|
||||||
genfifoentry |= GQSPI_GENFIFO_TX;
|
genfifoentry |= GQSPI_GENFIFO_TX;
|
||||||
transfer_len = xqspi->bytes_to_transfer;
|
transfer_len = xqspi->bytes_to_transfer;
|
||||||
} else {
|
} else if (xqspi->rxbuf) {
|
||||||
genfifoentry &= ~GQSPI_GENFIFO_TX;
|
genfifoentry &= ~GQSPI_GENFIFO_TX;
|
||||||
genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
|
genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
|
||||||
genfifoentry |= GQSPI_GENFIFO_RX;
|
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;
|
transfer_len = xqspi->dma_rx_bytes;
|
||||||
else
|
else
|
||||||
transfer_len = xqspi->bytes_to_receive;
|
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);
|
genfifoentry |= zynqmp_qspi_selectspimode(xqspi, nbits);
|
||||||
xqspi->genfifoentry = genfifoentry;
|
xqspi->genfifoentry = genfifoentry;
|
||||||
|
@ -1011,32 +1016,23 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op->dummy.nbytes) {
|
if (op->dummy.nbytes) {
|
||||||
tmpbuf = kzalloc(op->dummy.nbytes, GFP_KERNEL | GFP_DMA);
|
xqspi->txbuf = NULL;
|
||||||
if (!tmpbuf)
|
|
||||||
return -ENOMEM;
|
|
||||||
memset(tmpbuf, 0xff, op->dummy.nbytes);
|
|
||||||
reinit_completion(&xqspi->data_completion);
|
|
||||||
xqspi->txbuf = tmpbuf;
|
|
||||||
xqspi->rxbuf = 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;
|
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);
|
genfifoentry);
|
||||||
zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
|
zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
|
||||||
zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
|
zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
|
||||||
GQSPI_CFG_START_GEN_FIFO_MASK);
|
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) {
|
if (op->data.nbytes) {
|
||||||
|
|
Loading…
Reference in New Issue