summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
authorVignesh R <vigneshr@ti.com>2016-12-21 10:42:32 +0530
committerJagan Teki <jagan@openedev.com>2017-01-04 16:38:12 +0100
commit57897c13de03ac0136d64641a3eab526c6810387 (patch)
tree1449b0c095cc64911392faf76b8e86a8e194feee /drivers/spi
parent87f5f5417fc897df0b05826b408f0f4b7d2ee388 (diff)
spi: cadence_qspi_apb: Use 32 bit indirect write transaction when possible
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>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/cadence_qspi_apb.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index df6a91fc9f..5d5b6f0d35 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -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;
}