spi: cadence_qspi_apb: Use 32 bit indirect write transaction when possible
authorVignesh R <vigneshr@ti.com>
Wed, 21 Dec 2016 05:12:32 +0000 (10:42 +0530)
committerJagan Teki <jagan@openedev.com>
Wed, 4 Jan 2017 15:38:12 +0000 (16:38 +0100)
According to Section 11.15.4.9.2 Indirect Write Controller of K2G SoC
TRM SPRUHY8D[1], the external master is only permitted to issue 32-bit
data interface writes until the last word of an indirect transfer
otherwise indirect writes is known to fails sometimes. So, make sure
that QSPI indirect writes are 32 bit sized except for the last write. If
the txbuf is unaligned then use bounce buffer to avoid data aborts.

So, now that the driver uses bounce_buffer, enable CONFIG_BOUNCE_BUFFER
for all boards that use Cadence QSPI driver.

[1]www.ti.com/lit/ug/spruhy8d/spruhy8d.pdf

Signed-off-by: Vignesh R <vigneshr@ti.com>
Reviewed-by: Marek Vasut <marex@denx.de>
Reviewed-by: Jagan Teki <jagan@openedev.com>
drivers/spi/cadence_qspi_apb.c
include/configs/k2g_evm.h
include/configs/socfpga_common.h
include/configs/stv0991.h

index df6a91fc9f7b66788b565ae60def4cd940479fdb..5d5b6f0d350b6cc58dd196dd0ed9ff361ce7fd6e 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/errno.h>
 #include <wait_bit.h>
 #include <spi.h>
+#include <bouncebuf.h>
 #include "cadence_qspi.h"
 
 #define CQSPI_REG_POLL_US                      1 /* 1us */
@@ -724,6 +725,17 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
        unsigned int remaining = n_tx;
        unsigned int write_bytes;
        int ret;
+       struct bounce_buffer bb;
+       u8 *bb_txbuf;
+
+       /*
+        * Handle non-4-byte aligned accesses via bounce buffer to
+        * avoid data abort.
+        */
+       ret = bounce_buffer_start(&bb, (void *)txbuf, n_tx, GEN_BB_READ);
+       if (ret)
+               return ret;
+       bb_txbuf = bb.bounce_buffer;
 
        /* Configure the indirect read transfer bytes */
        writel(n_tx, plat->regbase + CQSPI_REG_INDIRECTWRBYTES);
@@ -734,11 +746,11 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
 
        while (remaining > 0) {
                write_bytes = remaining > page_size ? page_size : remaining;
-               /* Handle non-4-byte aligned access to avoid data abort. */
-               if (((uintptr_t)txbuf % 4) || (write_bytes % 4))
-                       writesb(plat->ahbbase, txbuf, write_bytes);
-               else
-                       writesl(plat->ahbbase, txbuf, write_bytes >> 2);
+               writesl(plat->ahbbase, bb_txbuf, write_bytes >> 2);
+               if (write_bytes % 4)
+                       writesb(plat->ahbbase,
+                               bb_txbuf + rounddown(write_bytes, 4),
+                               write_bytes % 4);
 
                ret = wait_for_bit("QSPI", plat->regbase + CQSPI_REG_SDRAMLEVEL,
                                   CQSPI_REG_SDRAMLEVEL_WR_MASK <<
@@ -748,7 +760,7 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
                        goto failwr;
                }
 
-               txbuf += write_bytes;
+               bb_txbuf += write_bytes;
                remaining -= write_bytes;
        }
 
@@ -759,6 +771,7 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
                printf("Indirect write completion error (%i)\n", ret);
                goto failwr;
        }
+       bounce_buffer_stop(&bb);
 
        /* Clear indirect completion status */
        writel(CQSPI_REG_INDIRECTWR_DONE,
@@ -769,6 +782,7 @@ failwr:
        /* Cancel the indirect write */
        writel(CQSPI_REG_INDIRECTWR_CANCEL,
               plat->regbase + CQSPI_REG_INDIRECTWR);
+       bounce_buffer_stop(&bb);
        return ret;
 }
 
index e9e69a78053c3899bb5852b6f358f6bffb57c62f..fb8fbe4be44133acfabfe2042b0c940fa6c8aea1 100644 (file)
@@ -77,6 +77,7 @@
 #define CONFIG_CADENCE_QSPI
 #define CONFIG_CQSPI_REF_CLK 384000000
 #define CONFIG_CQSPI_DECODER 0x0
+#define CONFIG_BOUNCE_BUFFER
 #endif
 
 #endif /* __CONFIG_K2G_EVM_H */
index 2c408278774722b4223a8561887d9caf0d760364..31f1338187338d01e500c60e798245151b2e6d00 100644 (file)
@@ -207,6 +207,7 @@ unsigned int cm_get_qspi_controller_clk_hz(void);
 #define CONFIG_CQSPI_REF_CLK           cm_get_qspi_controller_clk_hz()
 #endif
 #define CONFIG_CQSPI_DECODER           0
+#define CONFIG_BOUNCE_BUFFER
 
 /*
  * Designware SPI support
index bfd1bd719285a2c7442967bac302e719274bb2d4..09a3064bd6d61857032daf4ed7025ed5ef79cf63 100644 (file)
@@ -74,6 +74,7 @@
 #ifdef CONFIG_OF_CONTROL               /* QSPI is controlled via DT */
 #define CONFIG_CQSPI_DECODER           0
 #define CONFIG_CQSPI_REF_CLK           ((30/4)/2)*1000*1000
+#define CONFIG_BOUNCE_BUFFER
 
 #endif