summaryrefslogtreecommitdiff
path: root/drivers/spi/cadence_qspi.c
diff options
context:
space:
mode:
authorVignesh Raghavendra <vigneshr@ti.com>2020-01-27 10:36:40 +0530
committerJagan Teki <jagan@amarulasolutions.com>2020-01-27 22:27:22 +0530
commitffab212123481aa44f37cd4fdb4476ec15ff98b6 (patch)
treecc80bd2eb97b2d4a241c9f6e42b6299c6c0b905c /drivers/spi/cadence_qspi.c
parentd640772021589214bd7606d481ae1f52fbe62fe6 (diff)
spi: cadence-qspi: Add direct mode support
Add support for Direct Access Controller mode of Cadence QSPI. This allows MMIO access to SPI NOR flash providing better read performance. Direct mode is only exercised if AHB window size is greater than 8MB. Support for flash address remapping is also not supported at the moment and can be added in future. For better performance, driver uses DMA to copy data from flash in direct mode using dma_memcpy(). Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> Tested-by: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com> Acked-by: Jagan Teki <jagan@amarulasolutions.com>
Diffstat (limited to 'drivers/spi/cadence_qspi.c')
-rw-r--r--drivers/spi/cadence_qspi.c40
1 files changed, 23 insertions, 17 deletions
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 86c910a8da..619fff70de 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -13,12 +13,13 @@
#include <spi.h>
#include <spi-mem.h>
#include <linux/errno.h>
+#include <linux/sizes.h>
#include "cadence_qspi.h"
#define CQSPI_STIG_READ 0
#define CQSPI_STIG_WRITE 1
-#define CQSPI_INDIRECT_READ 2
-#define CQSPI_INDIRECT_WRITE 3
+#define CQSPI_READ 2
+#define CQSPI_WRITE 3
static int cadence_spi_write_speed(struct udevice *bus, uint hz)
{
@@ -190,6 +191,7 @@ static int cadence_spi_remove(struct udevice *dev)
static int cadence_spi_set_mode(struct udevice *bus, uint mode)
{
+ struct cadence_spi_platdata *plat = bus->platdata;
struct cadence_spi_priv *priv = dev_get_priv(bus);
/* Disable QSPI */
@@ -198,6 +200,10 @@ static int cadence_spi_set_mode(struct udevice *bus, uint mode)
/* Set SPI mode */
cadence_qspi_apb_set_clk_mode(priv->regbase, mode);
+ /* Enable Direct Access Controller */
+ if (plat->use_dac_mode)
+ cadence_qspi_apb_dac_mode_enable(priv->regbase);
+
/* Enable QSPI */
cadence_qspi_apb_controller_enable(priv->regbase);
@@ -222,12 +228,12 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
if (!op->addr.nbytes)
mode = CQSPI_STIG_READ;
else
- mode = CQSPI_INDIRECT_READ;
+ mode = CQSPI_READ;
} else {
if (!op->addr.nbytes || !op->data.buf.out)
mode = CQSPI_STIG_WRITE;
else
- mode = CQSPI_INDIRECT_WRITE;
+ mode = CQSPI_WRITE;
}
switch (mode) {
@@ -237,19 +243,15 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
case CQSPI_STIG_WRITE:
err = cadence_qspi_apb_command_write(base, op);
break;
- case CQSPI_INDIRECT_READ:
- err = cadence_qspi_apb_indirect_read_setup(plat, op);
- if (!err) {
- err = cadence_qspi_apb_indirect_read_execute
- (plat, op->data.nbytes, op->data.buf.in);
- }
+ case CQSPI_READ:
+ err = cadence_qspi_apb_read_setup(plat, op);
+ if (!err)
+ err = cadence_qspi_apb_read_execute(plat, op);
break;
- case CQSPI_INDIRECT_WRITE:
- err = cadence_qspi_apb_indirect_write_setup(plat, op);
- if (!err) {
- err = cadence_qspi_apb_indirect_write_execute
- (plat, op->data.nbytes, op->data.buf.out);
- }
+ case CQSPI_WRITE:
+ err = cadence_qspi_apb_write_setup(plat, op);
+ if (!err)
+ err = cadence_qspi_apb_write_execute(plat, op);
break;
default:
err = -1;
@@ -267,13 +269,17 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
int ret;
plat->regbase = (void *)devfdt_get_addr_index(bus, 0);
- plat->ahbbase = (void *)devfdt_get_addr_index(bus, 1);
+ plat->ahbbase = (void *)devfdt_get_addr_size_index(bus, 1,
+ &plat->ahbsize);
plat->is_decoded_cs = dev_read_bool(bus, "cdns,is-decoded-cs");
plat->fifo_depth = dev_read_u32_default(bus, "cdns,fifo-depth", 128);
plat->fifo_width = dev_read_u32_default(bus, "cdns,fifo-width", 4);
plat->trigger_address = dev_read_u32_default(bus,
"cdns,trigger-address",
0);
+ /* Use DAC mode only when MMIO window is at least 8M wide */
+ if (plat->ahbsize >= SZ_8M)
+ plat->use_dac_mode = true;
/* All other paramters are embedded in the child node */
subnode = dev_read_first_subnode(bus);