]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
spi: zynqmp_gqspi: Fix write issue at low frequencies
authorAshok Reddy Soma <ashok.reddy.soma@xilinx.com>
Mon, 6 Sep 2021 05:17:32 +0000 (23:17 -0600)
committerMichal Simek <michal.simek@xilinx.com>
Tue, 7 Sep 2021 09:40:40 +0000 (11:40 +0200)
With automode and current implementation we are seeing write issues at
low frequencies below 15Mhz. Make below changes to fix the issue.

1. Switch genfifo start mode to manual start mode from auto start
2. Remove dummy genfifo entry in zynqmp_qspi_chipselect() which was
   incorrectly added in the past
3. Enable and poll for Gen_FIFO_Empty interrupt status in place of
   Gen_FIFO_not_full. Since manual mode is enabled write to genfifo first
   and then wait for the Gen_FIFO_Empty interrupt status.
4. Enable and poll for TX_FIFO_Empty after Tx data is filled in FIFO in
   zynqmp_qspi_fill_tx_fifo(). Remove genfifo manual start before txfifo
   fill.

Note: Adding this patch in a state which was intensively tested. There is
likely no need to enable interrupts. But this chagne will be done in a
separate patch.

Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/spi/zynqmp_gqspi.c

index 21cb2c0784b0d162ec46a09ff49a334757fc4f07..c04de703f479b3bd88ae8c58e33141403ff8ac1f 100644 (file)
@@ -42,6 +42,7 @@
  */
 #define GQSPI_IXR_TXNFULL_MASK         0x00000004 /* QSPI TX FIFO Overflow */
 #define GQSPI_IXR_TXFULL_MASK          0x00000008 /* QSPI TX FIFO is full */
+#define GQSPI_IXR_TXFIFOEMPTY_MASK     0x00000100 /* QSPI TX FIFO is Empty */
 #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 */
@@ -250,12 +251,9 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi_priv *priv)
        config_reg = readl(&regs->confr);
        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);
+       if (!priv->io_mode)
                config_reg |= GQSPI_CONFIG_DMA_MODE;
-       }
 
        writel(config_reg, &regs->confr);
 
@@ -300,6 +298,8 @@ static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv,
        u32 config_reg, ier;
        int ret = 0;
 
+       writel(gqspi_fifo_reg, &regs->genfifo);
+
        config_reg = readl(&regs->confr);
        /* Manual start if needed */
        config_reg |= GQSPI_STRT_GEN_FIFO;
@@ -307,16 +307,14 @@ static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv,
 
        /* Enable interrupts */
        ier = readl(&regs->ier);
-       ier |= GQSPI_IXR_GFNFULL_MASK;
+       ier |= GQSPI_IXR_GFEMTY_MASK;
        writel(ier, &regs->ier);
 
        /* Wait until the fifo is not full to write the new command */
-       ret = wait_for_bit_le32(&regs->isr, GQSPI_IXR_GFNFULL_MASK, 1,
+       ret = wait_for_bit_le32(&regs->isr, GQSPI_IXR_GFEMTY_MASK, 1,
                                GQSPI_TIMEOUT, 1);
        if (ret)
                printf("%s Timeout\n", __func__);
-
-       writel(gqspi_fifo_reg, &regs->genfifo);
 }
 
 static void zynqmp_qspi_chipselect(struct zynqmp_qspi_priv *priv, int is_on)
@@ -340,9 +338,6 @@ 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);
 }
 
@@ -519,7 +514,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, config_reg, ier;
+       u32 data, ier;
        int ret = 0;
        struct zynqmp_qspi_regs *regs = priv->regs;
        u32 *buf = (u32 *)priv->tx_buf;
@@ -528,16 +523,10 @@ static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size)
        debug("TxFIFO: 0x%x, size: 0x%x\n", readl(&regs->isr),
              size);
 
-       config_reg = readl(&regs->confr);
-       /* Manual start if needed */
-       if (config_reg & GQSPI_GEN_FIFO_STRT_MOD) {
-               config_reg |= GQSPI_STRT_GEN_FIFO;
-               writel(config_reg, &regs->confr);
-               /* Enable interrupts */
-               ier = readl(&regs->ier);
-               ier |= GQSPI_IXR_ALL_MASK;
-               writel(ier, &regs->ier);
-       }
+       /* Enable interrupts */
+       ier = readl(&regs->ier);
+       ier |= GQSPI_IXR_ALL_MASK | GQSPI_IXR_TXFIFOEMPTY_MASK;
+       writel(ier, &regs->ier);
 
        while (size) {
                ret = wait_for_bit_le32(&regs->isr, GQSPI_IXR_TXNFULL_MASK, 1,
@@ -574,6 +563,13 @@ static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size)
                }
        }
 
+       ret = wait_for_bit_le32(&regs->isr, GQSPI_IXR_TXFIFOEMPTY_MASK, 1,
+                               GQSPI_TIMEOUT, 1);
+       if (ret) {
+               printf("%s: Timeout\n", __func__);
+               return ret;
+       }
+
        priv->tx_buf += len;
        return 0;
 }