aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAshok Reddy Soma2022-08-25 06:59:04 -0600
committerMichal Simek2022-09-13 11:32:48 +0200
commita3d4bfb427fb6e8c9396a744879796231deabc3d (patch)
treea1d814014404a2ae2d9f6fa530b0a9316f4d4271 /drivers
parentd91b0f4a1851f5c7c651c6f6204417035c074a0a (diff)
spi: zynqmp_gqspi: Fix issue of reading more than 32bits length
As the flash sizes are increasing day by day, QSPI can have devices of size > 512MB. In qspi driver we are trying to read all the data at once using DMA. The DMA descriptor destination size is only 29bits long. QSPIDMA_DST_SIZE 0xFF0F0804 BITS: 1:0 Reserved to keep word alignment BITS: 28:2 Number of 4-byte words the DMA will transfer BITS: 31:29 Reserved: Returns 0 when read, writes ignored So we can only transfer data of 0x1FFFFFF0(512MB minus 4bytes) bytes. Anything above will overflow this register and will ignore higher bits above 29 bits. Change the DMA functionality if the requested size is greater than or equal to 512MB to read 256MB chunks. Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma@amd.com> Link: https://lore.kernel.org/r/20220825125906.11581-5-ashok.reddy.soma@amd.com Signed-off-by: Michal Simek <michal.simek@amd.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spi/zynqmp_gqspi.c62
1 files changed, 39 insertions, 23 deletions
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c
index 78a1b487311..d5ccb48fde7 100644
--- a/drivers/spi/zynqmp_gqspi.c
+++ b/drivers/spi/zynqmp_gqspi.c
@@ -22,6 +22,7 @@
#include <dm/device_compat.h>
#include <linux/bitops.h>
#include <linux/err.h>
+#include <linux/sizes.h>
#include <zynqmp_firmware.h>
#define GQSPI_GFIFO_STRT_MODE_MASK BIT(29)
@@ -666,38 +667,53 @@ static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv,
u32 addr;
u32 size;
u32 actuallen = priv->len;
+ u32 totallen = priv->len;
int ret = 0;
struct zynqmp_qspi_dma_regs *dma_regs = priv->dma_regs;
- writel((unsigned long)buf, &dma_regs->dmadst);
- writel(roundup(priv->len, GQSPI_DMA_ALIGN), &dma_regs->dmasize);
- writel(GQSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier);
- addr = (unsigned long)buf;
- size = roundup(priv->len, GQSPI_DMA_ALIGN);
- flush_dcache_range(addr, addr + size);
+ while (totallen) {
+ if (totallen >= SZ_512M)
+ priv->len = SZ_256M;
+ else
+ priv->len = totallen;
- while (priv->len) {
- zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
- zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
+ totallen -= priv->len; /* Save remaining bytes length to read */
+ actuallen = priv->len; /* Actual number of bytes reading */
- debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd);
- }
+ writel((unsigned long)buf, &dma_regs->dmadst);
+ writel(roundup(priv->len, GQSPI_DMA_ALIGN), &dma_regs->dmasize);
+ writel(GQSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier);
+ addr = (unsigned long)buf;
+ size = roundup(priv->len, GQSPI_DMA_ALIGN);
+ flush_dcache_range(addr, addr + size);
- ret = wait_for_bit_le32(&dma_regs->dmaisr, GQSPI_DMA_DST_I_STS_DONE,
- 1, GQSPI_TIMEOUT, 1);
- if (ret) {
- printf("DMA Timeout:0x%x\n", readl(&dma_regs->dmaisr));
- return -ETIMEDOUT;
- }
+ while (priv->len) {
+ zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
+ zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
+
+ debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd);
+ }
+
+ ret = wait_for_bit_le32(&dma_regs->dmaisr,
+ GQSPI_DMA_DST_I_STS_DONE, 1,
+ GQSPI_TIMEOUT, 1);
+ if (ret) {
+ printf("DMA Timeout:0x%x\n", readl(&dma_regs->dmaisr));
+ return -ETIMEDOUT;
+ }
+
+ writel(GQSPI_DMA_DST_I_STS_DONE, &dma_regs->dmaisr);
- writel(GQSPI_DMA_DST_I_STS_DONE, &dma_regs->dmaisr);
+ debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n",
+ (unsigned long)buf, (unsigned long)priv->rx_buf, *buf,
+ actuallen);
- debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n",
- (unsigned long)buf, (unsigned long)priv->rx_buf, *buf,
- actuallen);
+ if (buf != priv->rx_buf)
+ memcpy(priv->rx_buf, buf, actuallen);
- if (buf != priv->rx_buf)
- memcpy(priv->rx_buf, buf, actuallen);
+ buf = (u32 *)((u8 *)buf + actuallen);
+ priv->rx_buf = (u8 *)priv->rx_buf + actuallen;
+ }
return 0;
}