diff options
Diffstat (limited to 'drivers/spi/spi-cadence-quadspi.c')
-rw-r--r-- | drivers/spi/spi-cadence-quadspi.c | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 77c3c017b0d6..b3f5a4e3577d 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -29,6 +29,7 @@ #include <linux/sched.h> #include <linux/spi/spi.h> #include <linux/spi/spi-mem.h> +#include <linux/sys_soc.h> #include <linux/timer.h> #define CQSPI_NAME "cadence-qspi" @@ -617,7 +618,7 @@ static int cqspi_phy_calibrate(struct cqspi_flash_pdata *f_pdata, rxhigh.tx = rxlow.tx; rxhigh.read_delay = rxlow.read_delay; - cqspi_find_rx_high(f_pdata, mem, &rxhigh); + ret = cqspi_find_rx_high(f_pdata, mem, &rxhigh); if (ret) goto out; dev_dbg(dev, "rxhigh: RX: %d TX: %d RD: %d\n", rxhigh.rx, rxhigh.tx, @@ -1275,6 +1276,7 @@ static int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata, reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; reg |= (op->addr.nbytes - 1); writel(reg, reg_base + CQSPI_REG_SIZE); + readl(reg_base + CQSPI_REG_SIZE); /* Flush posted write. */ return 0; } @@ -1314,6 +1316,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, reinit_completion(&cqspi->transfer_complete); writel(CQSPI_REG_INDIRECTRD_START_MASK, reg_base + CQSPI_REG_INDIRECTRD); + readl(reg_base + CQSPI_REG_INDIRECTRD); /* Flush posted write. */ while (remaining > 0) { if (!wait_for_completion_timeout(&cqspi->transfer_complete, @@ -1569,6 +1572,7 @@ static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata, reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; reg |= (op->addr.nbytes - 1); writel(reg, reg_base + CQSPI_REG_SIZE); + readl(reg_base + CQSPI_REG_SIZE); /* Flush posted write. */ return 0; } @@ -1594,6 +1598,8 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, reinit_completion(&cqspi->transfer_complete); writel(CQSPI_REG_INDIRECTWR_START_MASK, reg_base + CQSPI_REG_INDIRECTWR); + readl(reg_base + CQSPI_REG_INDIRECTWR); /* Flush posted write. */ + /* * As per 66AK2G02 TRM SPRUHY8F section 11.15.5.3 Indirect Access * Controller programming sequence, couple of cycles of @@ -2006,6 +2012,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) { @@ -2017,8 +2063,8 @@ static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata, u_char *buf = op->data.buf.in; int ret; - if (!cqspi->rx_chan || !virt_addr_valid(buf)) { - memcpy_fromio(buf, cqspi->ahb_base + from, len); + if (!cqspi->rx_chan || !virt_addr_valid(buf) || len <= 16) { + cqspi_memcpy_fromio(op, buf, cqspi->ahb_base + from, len); return 0; } @@ -2412,6 +2458,11 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) return 0; } +static const struct soc_device_attribute k3_soc_devices[] = { + { .family = "AM64X", .revision = "SR1.0" }, + { /* sentinel */ } +}; + static int cqspi_probe(struct platform_device *pdev) { const struct cqspi_driver_platdata *ddata; @@ -2566,7 +2617,7 @@ static int cqspi_probe(struct platform_device *pdev) goto probe_setup_failed; } - if (cqspi->use_direct_mode) { + if (cqspi->use_direct_mode && !soc_device_match(k3_soc_devices)) { ret = cqspi_request_mmap_dma(cqspi); if (ret == -EPROBE_DEFER) goto probe_setup_failed; |