summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPratyush Yadav <p.yadav@ti.com>2024-03-09 01:33:52 +0530
committerPraneeth Bajjuri <praneeth@ti.com>2024-03-11 13:51:58 -0500
commite29174df9a8042a26e8898bc46d12961174e9229 (patch)
tree123715f76d8759e8e2f93e6891d7ff2a2acef36f
parent2d7226230b41a3f722a2b7951d220a906257a320 (diff)
spi: cadence-quadspi: do not use memcpy_fromio() on 8D-8D-8D ops
In 8D-8D-8D mode an odd number of bytes cannot be read from the flash since they would result in half a cycle being left over. memcpy_fromio() makes no guarantees of access width size. On arm64 it is a mix of 1-byte and 8-bytes accesses. On arm it is just 1-byte accesses. memcpy_fromio() cannot be trusted when 8D-8D-8D reads are involved. Instead, explicitly perfrom memcpy from the IO space for 8D-8D-8D ops by making sure no odd-length accesses are performed. Since this controller can be used on both arm and arm64 platforms, only 4-byte reads are used to make sure the same code works on both platforms. Signed-off-by: Pratyush Yadav <p.yadav@ti.com> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
-rw-r--r--drivers/spi/spi-cadence-quadspi.c42
1 files changed, 41 insertions, 1 deletions
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index b81a60581889..7b89bcf20960 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -2011,6 +2011,46 @@ err_unmap:
return ret;
}
+static void cqspi_memcpy_fromio(const struct spi_mem_op *op, void *to,
+ const void __iomem *from, size_t count)
+{
+ if (op->data.buswidth == 8 && op->data.dtr) {
+ /*
+ * 8D-8D-8D ops with odd length should be rejected by
+ * supports_op() so no need to worry about that.
+ */
+ while (count && !IS_ALIGNED((unsigned long)from, 4)) {
+ *(u16 *)to = __raw_readw(from);
+ from += 2;
+ to += 2;
+ count -= 2;
+ }
+
+ /*
+ * The controller can work with both 32-bit and 64-bit
+ * platforms. 32-bit platforms won't have a readq. So use a
+ * readl instead.
+ */
+ while (count >= 4) {
+ *(u32 *)to = __raw_readl(from);
+ from += 4;
+ to += 4;
+ count -= 4;
+ }
+
+ while (count) {
+ *(u16 *)to = __raw_readw(from);
+ from += 2;
+ to += 2;
+ count -= 2;
+ }
+
+ return;
+ }
+
+ memcpy_fromio(to, from, count);
+}
+
static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata,
const struct spi_mem_op *op)
{
@@ -2023,7 +2063,7 @@ static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata,
int ret;
if (!cqspi->rx_chan || !virt_addr_valid(buf)) {
- memcpy_fromio(buf, cqspi->ahb_base + from, len);
+ cqspi_memcpy_fromio(op, buf, cqspi->ahb_base + from, len);
return 0;
}