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>
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 86c910a..619fff7 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_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 @@
 	/* 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 @@
 		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 @@
 	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 @@
 	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);