[PATCH 0/7] zynqmp_gqspi driver updates

This patch series updates xilinx qspi driver with below fixes/enhancements
- Fix rounding off issue in DMA transfers - Fix DMA transfers to be word aligned - Add support for IO mode - Fix write issues in QSPI single mode - Fix zynqmp tapdelays - Add Versal tapdelays - Update tapdelay for >100Mhz for Versal
This is resend for the people in CC, as i had trouble with my email server earlier.
Ashok Reddy Soma (3): spi: zynqmp_gqspi: Add support for IO mode spi: zynqmp_gqspi: Fix write issues in single mode spi: zynqmp_gqspi: Add tap delays for Versal qspi
Siva Durga Prasad Paladugu (1): spi: zynqmp_gqspi: Fix tap delay values
T Karthik Reddy (1): spi: zynqmp_gqspi: Update tapdelay value
Wojciech Tatarski (2): spi: zynqmp_gqspi: do not round immediate_data field spi: zynqmp_gqspi: DMA transfers should be word aligned
drivers/spi/zynqmp_gqspi.c | 230 +++++++++++++++++++++++++++++-------- 1 file changed, 180 insertions(+), 50 deletions(-)
-- 2.17.1
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

From: Wojciech Tatarski wtatarski@antmicro.com
Immediate_data is 8 bit value in generic FIFO command. When fields data_xfer=1 and exponent=0 this field specifies the absolute number of data bytes to read into the RXFIFO. Values from range 0xfd to 0xff are rounded up to 0x100. It causes overwriting the next bit field which is data_xfer. According to Zynq Ultrascale TRM only DMA transfers should be word aligned. So there is no reason to round up the immediate_data field.
Signed-off-by: Wojciech Tatarski wtatarski@antmicro.com Signed-off-by: Tomasz Gorochowik tgorochowik@antmicro.com Tested-by: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com Signed-off-by: Ashok Reddy Soma ashok.reddy.soma@xilinx.com ---
drivers/spi/zynqmp_gqspi.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index efcbd0557f..3e0dbb2c7b 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -524,7 +524,7 @@ static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv, u32 gen_fifo_cmd, u32 *buf) { u32 addr; - u32 size, len; + u32 size; u32 actuallen = priv->len; int ret = 0; struct zynqmp_qspi_dma_regs *dma_regs = priv->dma_regs; @@ -537,12 +537,7 @@ static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv, flush_dcache_range(addr, addr + size);
while (priv->len) { - len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); - if (!(gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK) && - (len % ARCH_DMA_MINALIGN)) { - gen_fifo_cmd &= ~GENMASK(7, 0); - gen_fifo_cmd |= roundup(len, ARCH_DMA_MINALIGN); - } + 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); -- 2.17.1
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

From: Wojciech Tatarski wtatarski@antmicro.com
According to Zynq Ultrascale TRM all the data transfers are word aligned. So there is no reason to round up size of DMA transfer to ARCH_DMA_MINALIGN (0x40)
Signed-off-by: Wojciech Tatarski wtatarski@antmicro.com Signed-off-by: Tomasz Gorochowik tgorochowik@antmicro.com Tested-by: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com Signed-off-by: Ashok Reddy Soma ashok.reddy.soma@xilinx.com ---
drivers/spi/zynqmp_gqspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index 3e0dbb2c7b..81c5e2b22f 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -530,10 +530,10 @@ static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv, struct zynqmp_qspi_dma_regs *dma_regs = priv->dma_regs;
writel((unsigned long)buf, &dma_regs->dmadst); - writel(roundup(priv->len, ARCH_DMA_MINALIGN), &dma_regs->dmasize); + 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, ARCH_DMA_MINALIGN); + size = roundup(priv->len, GQSPI_DMA_ALIGN); flush_dcache_range(addr, addr + size);
while (priv->len) { -- 2.17.1
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

Add support for device tree "has-io-mode" flag. The driver will be in IO mode when "has-io-mode" is passed from device tree instead of DMA.
Signed-off-by: Ashok Reddy Soma ashok.reddy.soma@xilinx.com ---
drivers/spi/zynqmp_gqspi.c | 140 ++++++++++++++++++++++++++++++++----- 1 file changed, 123 insertions(+), 17 deletions(-)
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index 81c5e2b22f..ae7b70aa57 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -16,11 +16,13 @@ #include <malloc.h> #include <memalign.h> #include <spi.h> +#include <spi_flash.h> #include <ubi_uboot.h> #include <wait_bit.h> #include <dm/device_compat.h> -#include <linux/bitops.h> -#include <linux/err.h> +#include <linux/mtd/spi-nor.h> +#include "../mtd/spi/sf_internal.h" +#include <zynqmp_firmware.h>
#define GQSPI_GFIFO_STRT_MODE_MASK BIT(29) #define GQSPI_CONFIG_MODE_EN_MASK (3 << 30) @@ -38,6 +40,7 @@ #define GQSPI_IXR_TXFULL_MASK 0x00000008 /* QSPI TX FIFO is full */ #define GQSPI_IXR_RXNEMTY_MASK 0x00000010 /* QSPI RX FIFO Not Empty */ #define GQSPI_IXR_GFEMTY_MASK 0x00000080 /* QSPI Generic FIFO Empty */ +#define GQSPI_IXR_GFNFULL_MASK 0x00000200 /* QSPI GENFIFO not full */ #define GQSPI_IXR_ALL_MASK (GQSPI_IXR_TXNFULL_MASK | \ GQSPI_IXR_RXNEMTY_MASK)
@@ -75,6 +78,7 @@
#define GQSPI_GFIFO_SELECT BIT(0) #define GQSPI_FIFO_THRESHOLD 1 +#define GQSPI_GENFIFO_THRESHOLD 31
#define SPI_XFER_ON_BOTH 0 #define SPI_XFER_ON_LOWER 1 @@ -161,6 +165,7 @@ struct zynqmp_qspi_plat { struct zynqmp_qspi_dma_regs *dma_regs; u32 frequency; u32 speed_hz; + unsigned int io_mode; };
struct zynqmp_qspi_priv { @@ -173,8 +178,11 @@ struct zynqmp_qspi_priv { int bytes_to_receive; unsigned int is_inst; unsigned int cs_change:1; + unsigned int io_mode; };
+static u8 last_cmd; + static int zynqmp_qspi_of_to_plat(struct udevice *bus) { struct zynqmp_qspi_plat *plat = dev_get_plat(bus); @@ -186,6 +194,7 @@ static int zynqmp_qspi_of_to_plat(struct udevice *bus) plat->dma_regs = (struct zynqmp_qspi_dma_regs *) (dev_read_addr(bus) + GQSPI_DMA_REG_OFFSET);
+ plat->io_mode = dev_read_bool(bus, "has-io-mode"); return 0; }
@@ -198,14 +207,20 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi_priv *priv) writel(GQSPI_GFIFO_ALL_INT_MASK, ®s->idisr); writel(GQSPI_FIFO_THRESHOLD, ®s->txftr); writel(GQSPI_FIFO_THRESHOLD, ®s->rxftr); + writel(GQSPI_GENFIFO_THRESHOLD, ®s->gqfthr); writel(GQSPI_GFIFO_ALL_INT_MASK, ®s->isr); + writel(0x0, ®s->enbr);
config_reg = readl(®s->confr); - config_reg &= ~(GQSPI_GFIFO_STRT_MODE_MASK | - GQSPI_CONFIG_MODE_EN_MASK); - config_reg |= GQSPI_CONFIG_DMA_MODE | - GQSPI_GFIFO_WP_HOLD | - GQSPI_DFLT_BAUD_RATE_DIV; + config_reg &= ~(GQSPI_CONFIG_MODE_EN_MASK); + config_reg |= GQSPI_GFIFO_WP_HOLD | GQSPI_DFLT_BAUD_RATE_DIV; + if (priv->io_mode) { + config_reg |= GQSPI_GFIFO_STRT_MODE_MASK; + } else { + config_reg &= ~(GQSPI_GFIFO_STRT_MODE_MASK); + config_reg |= GQSPI_CONFIG_DMA_MODE; + } + writel(config_reg, ®s->confr);
writel(GQSPI_ENABLE_ENABLE_MASK, ®s->enbr); @@ -215,8 +230,7 @@ static u32 zynqmp_qspi_bus_select(struct zynqmp_qspi_priv *priv) { u32 gqspi_fifo_reg = 0;
- gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS | - GQSPI_GFIFO_CS_LOWER; + gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS | GQSPI_GFIFO_CS_LOWER;
return gqspi_fifo_reg; } @@ -227,6 +241,7 @@ static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv, struct zynqmp_qspi_regs *regs = priv->regs; int ret = 0;
+ /* Wait until the fifo is not full to write the new command */ ret = wait_for_bit_le32(®s->isr, GQSPI_IXR_GFEMTY_MASK, 1, GQSPI_TIMEOUT, 1); if (ret) @@ -343,6 +358,7 @@ static int zynqmp_qspi_probe(struct udevice *bus)
priv->regs = plat->regs; priv->dma_regs = plat->dma_regs; + priv->io_mode = plat->io_mode;
ret = clk_get_by_index(bus, 0, &clk); if (ret < 0) { @@ -363,7 +379,7 @@ static int zynqmp_qspi_probe(struct udevice *bus) return ret; } plat->frequency = clock; - plat->speed_hz = plat->frequency / 2; + plat->speed_hz = plat->frequency;
/* init the zynq spi hw */ zynqmp_qspi_init_hw(priv); @@ -395,7 +411,7 @@ static int zynqmp_qspi_set_mode(struct udevice *bus, uint mode)
static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size) { - u32 data; + u32 data, config_reg, ier; int ret = 0; struct zynqmp_qspi_regs *regs = priv->regs; u32 *buf = (u32 *)priv->tx_buf; @@ -404,6 +420,17 @@ static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size) debug("TxFIFO: 0x%x, size: 0x%x\n", readl(®s->isr), size);
+ config_reg = readl(®s->confr); + /* Manual start if needed */ + if (config_reg & GQSPI_GEN_FIFO_STRT_MOD) { + config_reg |= GQSPI_STRT_GEN_FIFO; + writel(config_reg, ®s->confr); + /* Enable interrupts */ + ier = readl(®s->ier); + ier |= GQSPI_IXR_ALL_MASK; + writel(ier, ®s->ier); + } + while (size) { ret = wait_for_bit_le32(®s->isr, GQSPI_IXR_TXNFULL_MASK, 1, GQSPI_TIMEOUT, 1); @@ -445,12 +472,20 @@ static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size)
static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv) { + u8 command = 1; u32 gen_fifo_cmd; u32 bytecount = 0;
while (priv->len) { gen_fifo_cmd = zynqmp_qspi_bus_select(priv); - gen_fifo_cmd |= GQSPI_GFIFO_TX | GQSPI_SPI_MODE_SPI; + gen_fifo_cmd |= GQSPI_GFIFO_TX; + + if (command) { + command = 0; + last_cmd = *(u8 *)priv->tx_buf; + } + + gen_fifo_cmd |= GQSPI_SPI_MODE_SPI; gen_fifo_cmd |= *(u8 *)priv->tx_buf; bytecount++; priv->len--; @@ -499,7 +534,10 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) gen_fifo_cmd |= GQSPI_GFIFO_TX | GQSPI_GFIFO_DATA_XFR_MASK;
- gen_fifo_cmd |= GQSPI_SPI_MODE_SPI; + if (last_cmd == SPINOR_OP_PP_1_1_4) + gen_fifo_cmd |= GQSPI_SPI_MODE_QSPI; + else + gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
while (priv->len) { len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); @@ -520,6 +558,66 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) return ret; }
+static int zynqmp_qspi_start_io(struct zynqmp_qspi_priv *priv, + u32 gen_fifo_cmd, u32 *buf) +{ + u32 len; + u32 actuallen = priv->len; + u32 config_reg, ier, isr; + u32 timeout = GQSPI_TIMEOUT; + struct zynqmp_qspi_regs *regs = priv->regs; + u32 last_bits; + u32 *traverse = buf; + + while (priv->len) { + len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); + /* If exponent bit is set, reset immediate to be 2^len */ + if (gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK) + priv->bytes_to_receive = (1 << len); + else + priv->bytes_to_receive = len; + zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd); + /* Manual start */ + config_reg = readl(®s->confr); + config_reg |= GQSPI_STRT_GEN_FIFO; + writel(config_reg, ®s->confr); + /* Enable RX interrupts for IO mode */ + ier = readl(®s->ier); + ier |= GQSPI_IXR_ALL_MASK; + writel(ier, ®s->ier); + while (priv->bytes_to_receive && timeout) { + isr = readl(®s->isr); + if (isr & GQSPI_IXR_RXNEMTY_MASK) { + if (priv->bytes_to_receive >= 4) { + *traverse = readl(®s->drxr); + traverse++; + priv->bytes_to_receive -= 4; + } else { + last_bits = readl(®s->drxr); + memcpy(traverse, &last_bits, + priv->bytes_to_receive); + priv->bytes_to_receive = 0; + } + timeout = GQSPI_TIMEOUT; + } else { + udelay(1); + timeout--; + } + } + + 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 (!timeout) { + printf("IO timeout: %d\n", readl(®s->isr)); + return -1; + } + } + + return 0; +} + static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv, u32 gen_fifo_cmd, u32 *buf) { @@ -572,16 +670,24 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv) gen_fifo_cmd |= GQSPI_GFIFO_RX | GQSPI_GFIFO_DATA_XFR_MASK;
- gen_fifo_cmd |= GQSPI_SPI_MODE_SPI; + if (last_cmd == SPINOR_OP_READ_1_1_4) + gen_fifo_cmd |= GQSPI_SPI_MODE_QSPI; + else if (last_cmd == SPINOR_OP_READ_1_1_2) + gen_fifo_cmd |= GQSPI_SPI_MODE_DUAL_SPI; + else + gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
/* * Check if receive buffer is aligned to 4 byte and length * is multiples of four byte as we are using dma to receive. */ - if (!((unsigned long)priv->rx_buf & (GQSPI_DMA_ALIGN - 1)) && - !(actuallen % GQSPI_DMA_ALIGN)) { + if ((!((unsigned long)priv->rx_buf & (GQSPI_DMA_ALIGN - 1)) && + !(actuallen % GQSPI_DMA_ALIGN)) || priv->io_mode) { buf = (u32 *)priv->rx_buf; - return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf); + if (priv->io_mode) + return zynqmp_qspi_start_io(priv, gen_fifo_cmd, buf); + else + return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf); }
ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len, -- 2.17.1
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
There is no need of read modify write for tapdelay settings ans hence remove the read operations while setting tapdelays. Also, correct tapdelay value settings at 40MHZ by modifying the if check to <= instead of <.
Signed-off-by: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com Signed-off-by: Ashok Reddy Soma ashok.reddy.soma@xilinx.com ---
drivers/spi/zynqmp_gqspi.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index ae7b70aa57..136c20f09e 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -282,24 +282,19 @@ void zynqmp_qspi_set_tapdelay(struct udevice *bus, u32 baudrateval) debug("%s, req_hz:%d, clk_rate:%d, baudrateval:%d\n", __func__, reqhz, clk_rate, baudrateval);
- if (reqhz < GQSPI_FREQ_40MHZ) { - zynqmp_mmio_read(IOU_TAPDLY_BYPASS_OFST, &tapdlybypass); - tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE << - TAP_DLY_BYPASS_LQSPI_RX_SHIFT); + if (reqhz <= GQSPI_FREQ_40MHZ) { + tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << + TAP_DLY_BYPASS_LQSPI_RX_SHIFT; } else if (reqhz <= GQSPI_FREQ_100MHZ) { - zynqmp_mmio_read(IOU_TAPDLY_BYPASS_OFST, &tapdlybypass); - tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE << - TAP_DLY_BYPASS_LQSPI_RX_SHIFT); - lpbkdlyadj = readl(®s->lpbkdly); - lpbkdlyadj |= (GQSPI_LPBK_DLY_ADJ_LPBK_MASK); - datadlyadj = readl(®s->gqspidlyadj); - datadlyadj |= ((GQSPI_USE_DATA_DLY << GQSPI_USE_DATA_DLY_SHIFT) - | (GQSPI_DATA_DLY_ADJ_VALUE << - GQSPI_DATA_DLY_ADJ_SHIFT)); + tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << + TAP_DLY_BYPASS_LQSPI_RX_SHIFT; + lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK; + datadlyadj = (GQSPI_USE_DATA_DLY << GQSPI_USE_DATA_DLY_SHIFT) | + (GQSPI_DATA_DLY_ADJ_VALUE << + GQSPI_DATA_DLY_ADJ_SHIFT); } else if (reqhz <= GQSPI_FREQ_150MHZ) { - lpbkdlyadj = readl(®s->lpbkdly); - lpbkdlyadj |= ((GQSPI_LPBK_DLY_ADJ_LPBK_MASK) | - GQSPI_LPBK_DLY_ADJ_DLY_0); + lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK | + GQSPI_LPBK_DLY_ADJ_DLY_0; }
zynqmp_mmio_write(IOU_TAPDLY_BYPASS_OFST, IOU_TAPDLY_BYPASS_MASK, -- 2.17.1
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

Add dummy write to genfifo register in chipselect.
Enable manual start in zynqmp_qspi_fill_gen_fifo().
Also enable GQSPI_IXR_GFNFULL_MASK and check for it instead of GQSPI_IXR_GFEMTY_MASK.
Signed-off-by: Ashok Reddy Soma ashok.reddy.soma@xilinx.com ---
drivers/spi/zynqmp_gqspi.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index 136c20f09e..f50a7304ea 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -239,10 +239,21 @@ static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv, u32 gqspi_fifo_reg) { struct zynqmp_qspi_regs *regs = priv->regs; + u32 config_reg, ier; int ret = 0;
+ config_reg = readl(®s->confr); + /* Manual start if needed */ + config_reg |= GQSPI_STRT_GEN_FIFO; + writel(config_reg, ®s->confr); + + /* Enable interrupts */ + ier = readl(®s->ier); + ier |= GQSPI_IXR_GFNFULL_MASK; + writel(ier, ®s->ier); + /* Wait until the fifo is not full to write the new command */ - ret = wait_for_bit_le32(®s->isr, GQSPI_IXR_GFEMTY_MASK, 1, + ret = wait_for_bit_le32(®s->isr, GQSPI_IXR_GFNFULL_MASK, 1, GQSPI_TIMEOUT, 1); if (ret) printf("%s Timeout\n", __func__); @@ -265,6 +276,9 @@ static void zynqmp_qspi_chipselect(struct zynqmp_qspi_priv *priv, int is_on)
debug("GFIFO_CMD_CS: 0x%x\n", gqspi_fifo_reg);
+ /* Dummy generic FIFO entry */ + zynqmp_qspi_fill_gen_fifo(priv, 0); + zynqmp_qspi_fill_gen_fifo(priv, gqspi_fifo_reg); }
-- 2.17.1
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

This patch adds tap delays for qspi in Versal platform. Use IS_ENABLED() to address for ZynqMP and Versal and re-align the tapdelays code.
Signed-off-by: Ashok Reddy Soma ashok.reddy.soma@xilinx.com ---
drivers/spi/zynqmp_gqspi.c | 54 ++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 17 deletions(-)
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index f50a7304ea..e9726912b7 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -102,8 +102,10 @@ #define TAP_DLY_BYPASS_LQSPI_RX_VALUE 0x1 #define TAP_DLY_BYPASS_LQSPI_RX_SHIFT 2 #define GQSPI_DATA_DLY_ADJ_OFST 0x000001F8 -#define IOU_TAPDLY_BYPASS_OFST 0xFF180390 +#define IOU_TAPDLY_BYPASS_OFST !IS_ENABLED(CONFIG_ARCH_VERSAL) ? \ + 0xFF180390 : 0xF103003C #define GQSPI_LPBK_DLY_ADJ_LPBK_MASK 0x00000020 +#define GQSPI_FREQ_37_5MHZ 37500000 #define GQSPI_FREQ_40MHZ 40000000 #define GQSPI_FREQ_100MHZ 100000000 #define GQSPI_FREQ_150MHZ 150000000 @@ -296,23 +298,41 @@ void zynqmp_qspi_set_tapdelay(struct udevice *bus, u32 baudrateval) debug("%s, req_hz:%d, clk_rate:%d, baudrateval:%d\n", __func__, reqhz, clk_rate, baudrateval);
- if (reqhz <= GQSPI_FREQ_40MHZ) { - tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << - TAP_DLY_BYPASS_LQSPI_RX_SHIFT; - } else if (reqhz <= GQSPI_FREQ_100MHZ) { - tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << - TAP_DLY_BYPASS_LQSPI_RX_SHIFT; - lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK; - datadlyadj = (GQSPI_USE_DATA_DLY << GQSPI_USE_DATA_DLY_SHIFT) | - (GQSPI_DATA_DLY_ADJ_VALUE << - GQSPI_DATA_DLY_ADJ_SHIFT); - } else if (reqhz <= GQSPI_FREQ_150MHZ) { - lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK | - GQSPI_LPBK_DLY_ADJ_DLY_0; + if (!IS_ENABLED(CONFIG_ARCH_VERSAL)) { + if (reqhz <= GQSPI_FREQ_40MHZ) { + tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << + TAP_DLY_BYPASS_LQSPI_RX_SHIFT; + } else if (reqhz <= GQSPI_FREQ_100MHZ) { + tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << + TAP_DLY_BYPASS_LQSPI_RX_SHIFT; + lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK; + datadlyadj = (GQSPI_USE_DATA_DLY << + GQSPI_USE_DATA_DLY_SHIFT) | + (GQSPI_DATA_DLY_ADJ_VALUE << + GQSPI_DATA_DLY_ADJ_SHIFT); + } else if (reqhz <= GQSPI_FREQ_150MHZ) { + lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK | + GQSPI_LPBK_DLY_ADJ_DLY_0; + } + zynqmp_mmio_write(IOU_TAPDLY_BYPASS_OFST, + IOU_TAPDLY_BYPASS_MASK, tapdlybypass); + } else { + if (reqhz <= GQSPI_FREQ_37_5MHZ) { + tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << + TAP_DLY_BYPASS_LQSPI_RX_SHIFT; + } else if (reqhz <= GQSPI_FREQ_100MHZ) { + tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE << + TAP_DLY_BYPASS_LQSPI_RX_SHIFT; + lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK; + datadlyadj = GQSPI_USE_DATA_DLY << + GQSPI_USE_DATA_DLY_SHIFT; + } else if (reqhz <= GQSPI_FREQ_150MHZ) { + lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK | + (GQSPI_LPBK_DLY_ADJ_DLY_1 << + GQSPI_LPBK_DLY_ADJ_DLY_1_SHIFT); + } + writel(tapdlybypass, IOU_TAPDLY_BYPASS_OFST); } - - zynqmp_mmio_write(IOU_TAPDLY_BYPASS_OFST, IOU_TAPDLY_BYPASS_MASK, - tapdlybypass); writel(lpbkdlyadj, ®s->lpbkdly); writel(datadlyadj, ®s->gqspidlyadj); } -- 2.17.1
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

From: T Karthik Reddy t.karthik.reddy@xilinx.com
Update GQSPI_LPBK_DLY_ADJ_DLY_1 tapdelay value for Versal for frequencies above 100MHz.
Signed-off-by: T Karthik Reddy t.karthik.reddy@xilinx.com Signed-off-by: Ashok Reddy Soma ashok.reddy.soma@xilinx.com ---
drivers/spi/zynqmp_gqspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index e9726912b7..0771541e12 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -92,7 +92,7 @@
#define GQSPI_BAUD_DIV_SHIFT 2 #define GQSPI_LPBK_DLY_ADJ_LPBK_SHIFT 5 -#define GQSPI_LPBK_DLY_ADJ_DLY_1 0x2 +#define GQSPI_LPBK_DLY_ADJ_DLY_1 0x1 #define GQSPI_LPBK_DLY_ADJ_DLY_1_SHIFT 3 #define GQSPI_LPBK_DLY_ADJ_DLY_0 0x3 #define GQSPI_USE_DATA_DLY 0x1 -- 2.17.1
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

On Mon, Jan 18, 2021 at 8:35 PM Ashok Reddy Soma ashok.reddy.soma@xilinx.com wrote:
This patch series updates xilinx qspi driver with below fixes/enhancements
- Fix rounding off issue in DMA transfers
- Fix DMA transfers to be word aligned
- Add support for IO mode
- Fix write issues in QSPI single mode
- Fix zynqmp tapdelays
- Add Versal tapdelays
- Update tapdelay for >100Mhz for Versal
This is resend for the people in CC, as i had trouble with my email server earlier.
Ashok Reddy Soma (3): spi: zynqmp_gqspi: Add support for IO mode spi: zynqmp_gqspi: Fix write issues in single mode spi: zynqmp_gqspi: Add tap delays for Versal qspi
Siva Durga Prasad Paladugu (1): spi: zynqmp_gqspi: Fix tap delay values
T Karthik Reddy (1): spi: zynqmp_gqspi: Update tapdelay value
Wojciech Tatarski (2): spi: zynqmp_gqspi: do not round immediate_data field spi: zynqmp_gqspi: DMA transfers should be word aligned
drivers/spi/zynqmp_gqspi.c | 230 +++++++++++++++++++++++++++++-------- 1 file changed, 180 insertions(+), 50 deletions(-)
+Brandon Maier
participants (2)
-
Ashok Reddy Soma
-
Bin Meng