All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs
@ 2019-11-19 10:13 Vignesh Raghavendra
  2019-11-19 10:13 ` [U-Boot] [PATCH v2 1/2] spi: cadence_qspi: Move to spi-mem framework Vignesh Raghavendra
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Vignesh Raghavendra @ 2019-11-19 10:13 UTC (permalink / raw)
  To: u-boot

First patch moves driver over to spi-mem framework and implement
spi_mem_ops. This is require to support more SPI Flash opcodes like SFDP
parsing etc. Series is in prepartion to add Octal mode for support for
the same driver to support OSPI version of the controller.

Second patch adds DAC mode that provide memory mapped access to flash.
This greatly increases the read throughput.

Tested with mt25qu512 flash and s25fl512 flash

Note: Depends on [1][2] that adds stubs for dma_memcpy() to be used on
platforms without CONFIG_DMA enabled.

[1]http://patchwork.ozlabs.org/patch/1195557/
[2]http://patchwork.ozlabs.org/patch/1195556/


Vignesh Raghavendra (2):
  spi: cadence_qspi: Move to spi-mem framework
  spi: cadence-qspi: Add direct mode support

 drivers/spi/cadence_qspi.c     | 148 +++++++++++---------------
 drivers/spi/cadence_qspi.h     |  24 +++--
 drivers/spi/cadence_qspi_apb.c | 185 ++++++++++++++++-----------------
 3 files changed, 164 insertions(+), 193 deletions(-)

-- 
2.24.0

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v2 1/2] spi: cadence_qspi: Move to spi-mem framework
  2019-11-19 10:13 [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs Vignesh Raghavendra
@ 2019-11-19 10:13 ` Vignesh Raghavendra
  2020-01-17 15:51   ` Simon Goldschmidt
  2019-11-19 10:13 ` [U-Boot] [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support Vignesh Raghavendra
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Vignesh Raghavendra @ 2019-11-19 10:13 UTC (permalink / raw)
  To: u-boot

Current Cadence QSPI driver has few limitations. It assumes all read
operations to be in Quad mode and thus does not support SFDP parsing.
Also, adding support for new mode such as Octal mode would not be
possible with current configuration. Therefore move the driver over to spi-mem
framework. This has added advantage that driver can be used to support
SPI NAND memories too.
Hence, move driver over to new spi-mem APIs.

Please note that this gets rid of mode bit setting done when
CONFIG_SPL_SPI_XIP is defined as there does not seem to be any user to
that config option.

Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
---
v2: No change

 drivers/spi/cadence_qspi.c     | 136 +++++++++++++--------------------
 drivers/spi/cadence_qspi.h     |   9 +--
 drivers/spi/cadence_qspi_apb.c | 124 ++++++++----------------------
 3 files changed, 91 insertions(+), 178 deletions(-)

diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index e2e54cd27723..673a2e9a6c4c 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -10,6 +10,7 @@
 #include <malloc.h>
 #include <reset.h>
 #include <spi.h>
+#include <spi-mem.h>
 #include <linux/errno.h>
 #include "cadence_qspi.h"
 
@@ -34,12 +35,21 @@ static int cadence_spi_write_speed(struct udevice *bus, uint hz)
 	return 0;
 }
 
+static int cadence_spi_read_id(void *reg_base, u8 len, u8 *idcode)
+{
+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x9F, 1),
+					  SPI_MEM_OP_NO_ADDR,
+					  SPI_MEM_OP_NO_DUMMY,
+					  SPI_MEM_OP_DATA_IN(len, idcode, 1));
+
+	return cadence_qspi_apb_command_read(reg_base, &op);
+}
+
 /* Calibration sequence to determine the read data capture delay register */
 static int spi_calibration(struct udevice *bus, uint hz)
 {
 	struct cadence_spi_priv *priv = dev_get_priv(bus);
 	void *base = priv->regbase;
-	u8 opcode_rdid = 0x9F;
 	unsigned int idcode = 0, temp = 0;
 	int err = 0, i, range_lo = -1, range_hi = -1;
 
@@ -53,8 +63,7 @@ static int spi_calibration(struct udevice *bus, uint hz)
 	cadence_qspi_apb_controller_enable(base);
 
 	/* read the ID which will be our golden value */
-	err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
-		3, (u8 *)&idcode);
+	err = cadence_spi_read_id(base, 3, (u8 *)&idcode);
 	if (err) {
 		puts("SF: Calibration failed (read)\n");
 		return err;
@@ -73,8 +82,7 @@ static int spi_calibration(struct udevice *bus, uint hz)
 		cadence_qspi_apb_controller_enable(base);
 
 		/* issue a RDID to get the ID value */
-		err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
-			3, (u8 *)&temp);
+		err = cadence_spi_read_id(base, 3, (u8 *)&temp);
 		if (err) {
 			puts("SF: Calibration failed (read)\n");
 			return err;
@@ -195,96 +203,56 @@ static int cadence_spi_set_mode(struct udevice *bus, uint mode)
 	return 0;
 }
 
-static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen,
-			    const void *dout, void *din, unsigned long flags)
+static int cadence_spi_mem_exec_op(struct spi_slave *spi,
+				   const struct spi_mem_op *op)
 {
-	struct udevice *bus = dev->parent;
+	struct udevice *bus = spi->dev->parent;
 	struct cadence_spi_platdata *plat = bus->platdata;
 	struct cadence_spi_priv *priv = dev_get_priv(bus);
-	struct dm_spi_slave_platdata *dm_plat = dev_get_parent_platdata(dev);
 	void *base = priv->regbase;
-	u8 *cmd_buf = priv->cmd_buf;
-	size_t data_bytes;
 	int err = 0;
-	u32 mode = CQSPI_STIG_WRITE;
-
-	if (flags & SPI_XFER_BEGIN) {
-		/* copy command to local buffer */
-		priv->cmd_len = bitlen / 8;
-		memcpy(cmd_buf, dout, priv->cmd_len);
-	}
-
-	if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) {
-		/* if start and end bit are set, the data bytes is 0. */
-		data_bytes = 0;
-	} else {
-		data_bytes = bitlen / 8;
-	}
-	debug("%s: len=%zu [bytes]\n", __func__, data_bytes);
+	u32 mode;
 
 	/* Set Chip select */
-	cadence_qspi_apb_chipselect(base, spi_chip_select(dev),
+	cadence_qspi_apb_chipselect(base, spi_chip_select(spi->dev),
 				    plat->is_decoded_cs);
 
-	if ((flags & SPI_XFER_END) || (flags == 0)) {
-		if (priv->cmd_len == 0) {
-			printf("QSPI: Error, command is empty.\n");
-			return -1;
-		}
-
-		if (din && data_bytes) {
-			/* read */
-			/* Use STIG if no address. */
-			if (!CQSPI_IS_ADDR(priv->cmd_len))
-				mode = CQSPI_STIG_READ;
-			else
-				mode = CQSPI_INDIRECT_READ;
-		} else if (dout && !(flags & SPI_XFER_BEGIN)) {
-			/* write */
-			if (!CQSPI_IS_ADDR(priv->cmd_len))
-				mode = CQSPI_STIG_WRITE;
-			else
-				mode = CQSPI_INDIRECT_WRITE;
-		}
-
-		switch (mode) {
-		case CQSPI_STIG_READ:
-			err = cadence_qspi_apb_command_read(
-				base, priv->cmd_len, cmd_buf,
-				data_bytes, din);
+	if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) {
+		if (!op->addr.nbytes)
+			mode = CQSPI_STIG_READ;
+		else
+			mode = CQSPI_INDIRECT_READ;
+	} else {
+		if (!op->addr.nbytes || !op->data.buf.out)
+			mode = CQSPI_STIG_WRITE;
+		else
+			mode = CQSPI_INDIRECT_WRITE;
+	}
 
+	switch (mode) {
+	case CQSPI_STIG_READ:
+		err = cadence_qspi_apb_command_read(base, op);
 		break;
-		case CQSPI_STIG_WRITE:
-			err = cadence_qspi_apb_command_write(base,
-				priv->cmd_len, cmd_buf,
-				data_bytes, dout);
+	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,
-				priv->cmd_len, dm_plat->mode, cmd_buf);
-			if (!err) {
-				err = cadence_qspi_apb_indirect_read_execute
-				(plat, data_bytes, din);
-			}
-		break;
-		case CQSPI_INDIRECT_WRITE:
-			err = cadence_qspi_apb_indirect_write_setup
-				(plat, priv->cmd_len, dm_plat->mode, cmd_buf);
-			if (!err) {
-				err = cadence_qspi_apb_indirect_write_execute
-				(plat, data_bytes, dout);
-			}
-		break;
-		default:
-			err = -1;
-			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);
 		}
-
-		if (flags & SPI_XFER_END) {
-			/* clear command buffer */
-			memset(cmd_buf, 0, sizeof(priv->cmd_buf));
-			priv->cmd_len = 0;
+		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);
 		}
+		break;
+	default:
+		err = -1;
+		break;
 	}
 
 	return err;
@@ -332,10 +300,14 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
 	return 0;
 }
 
+static const struct spi_controller_mem_ops cadence_spi_mem_ops = {
+	.exec_op = cadence_spi_mem_exec_op,
+};
+
 static const struct dm_spi_ops cadence_spi_ops = {
-	.xfer		= cadence_spi_xfer,
 	.set_speed	= cadence_spi_set_speed,
 	.set_mode	= cadence_spi_set_mode,
+	.mem_ops	= &cadence_spi_mem_ops,
 	/*
 	 * cs_info is not needed, since we require all chip selects to be
 	 * in the device tree explicitly
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index 20cceca239f8..e655b027d788 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -54,17 +54,16 @@ void cadence_qspi_apb_controller_enable(void *reg_base_addr);
 void cadence_qspi_apb_controller_disable(void *reg_base_addr);
 
 int cadence_qspi_apb_command_read(void *reg_base_addr,
-	unsigned int cmdlen, const u8 *cmdbuf, unsigned int rxlen, u8 *rxbuf);
+				  const struct spi_mem_op *op);
 int cadence_qspi_apb_command_write(void *reg_base_addr,
-	unsigned int cmdlen, const u8 *cmdbuf,
-	unsigned int txlen,  const u8 *txbuf);
+				   const struct spi_mem_op *op);
 
 int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
-	unsigned int cmdlen, unsigned int rx_width, const u8 *cmdbuf);
+	const struct spi_mem_op *op);
 int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
 	unsigned int rxlen, u8 *rxbuf);
 int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
-	unsigned int cmdlen, unsigned int tx_width, const u8 *cmdbuf);
+	const struct spi_mem_op *op);
 int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
 	unsigned int txlen, const u8 *txbuf);
 
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index 55a7501913a8..8dd0495dfcf4 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 <spi-mem.h>
 #include <malloc.h>
 #include "cadence_qspi.h"
 
@@ -172,19 +173,6 @@
 	(((readl(reg_base + CQSPI_REG_SDRAMLEVEL)) >>	\
 	CQSPI_REG_SDRAMLEVEL_WR_LSB) & CQSPI_REG_SDRAMLEVEL_WR_MASK)
 
-static unsigned int cadence_qspi_apb_cmd2addr(const unsigned char *addr_buf,
-	unsigned int addr_width)
-{
-	unsigned int addr;
-
-	addr = (addr_buf[0] << 16) | (addr_buf[1] << 8) | addr_buf[2];
-
-	if (addr_width == 4)
-		addr = (addr << 8) | addr_buf[3];
-
-	return addr;
-}
-
 void cadence_qspi_apb_controller_enable(void *reg_base)
 {
 	unsigned int reg;
@@ -433,21 +421,20 @@ static int cadence_qspi_apb_exec_flash_cmd(void *reg_base,
 }
 
 /* For command RDID, RDSR. */
-int cadence_qspi_apb_command_read(void *reg_base,
-	unsigned int cmdlen, const u8 *cmdbuf, unsigned int rxlen,
-	u8 *rxbuf)
+int cadence_qspi_apb_command_read(void *reg_base, const struct spi_mem_op *op)
 {
 	unsigned int reg;
 	unsigned int read_len;
 	int status;
+	unsigned int rxlen = op->data.nbytes;
+	void *rxbuf = op->data.buf.in;
 
-	if (!cmdlen || rxlen > CQSPI_STIG_DATA_LEN_MAX || rxbuf == NULL) {
-		printf("QSPI: Invalid input arguments cmdlen %d rxlen %d\n",
-		       cmdlen, rxlen);
+	if (rxlen > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
+		printf("QSPI: Invalid input arguments rxlen %u\n", rxlen);
 		return -EINVAL;
 	}
 
-	reg = cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+	reg = op->cmd.opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
 
 	reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
 
@@ -475,34 +462,30 @@ int cadence_qspi_apb_command_read(void *reg_base,
 }
 
 /* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */
-int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen,
-	const u8 *cmdbuf, unsigned int txlen,  const u8 *txbuf)
+int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op)
 {
 	unsigned int reg = 0;
-	unsigned int addr_value;
 	unsigned int wr_data;
 	unsigned int wr_len;
+	unsigned int txlen = op->data.nbytes;
+	const void *txbuf = op->data.buf.out;
+	u32 addr;
+
+	/* Reorder address to SPI bus order if only transferring address */
+	if (!txlen) {
+		addr = cpu_to_be32(op->addr.val);
+		if (op->addr.nbytes == 3)
+			addr >>= 8;
+		txbuf = &addr;
+		txlen = op->addr.nbytes;
+	}
 
-	if (!cmdlen || cmdlen > 5 || txlen > 8 || cmdbuf == NULL) {
-		printf("QSPI: Invalid input arguments cmdlen %d txlen %d\n",
-		       cmdlen, txlen);
+	if (txlen > CQSPI_STIG_DATA_LEN_MAX) {
+		printf("QSPI: Invalid input arguments txlen %u\n", txlen);
 		return -EINVAL;
 	}
 
-	reg |= cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
-
-	if (cmdlen == 4 || cmdlen == 5) {
-		/* Command with address */
-		reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
-		/* Number of bytes to write. */
-		reg |= ((cmdlen - 2) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
-			<< CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
-		/* Get address */
-		addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1],
-			cmdlen >= 5 ? 4 : 3);
-
-		writel(addr_value, reg_base + CQSPI_REG_CMDADDRESS);
-	}
+	reg |= op->cmd.opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
 
 	if (txlen) {
 		/* writing data = yes */
@@ -530,61 +513,32 @@ int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen,
 
 /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
 int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
-	unsigned int cmdlen, unsigned int rx_width, const u8 *cmdbuf)
+	const struct spi_mem_op *op)
 {
 	unsigned int reg;
 	unsigned int rd_reg;
-	unsigned int addr_value;
 	unsigned int dummy_clk;
-	unsigned int dummy_bytes;
-	unsigned int addr_bytes;
-
-	/*
-	 * Identify addr_byte. All NOR flash device drivers are using fast read
-	 * which always expecting 1 dummy byte, 1 cmd byte and 3/4 addr byte.
-	 * With that, the length is in value of 5 or 6. Only FRAM chip from
-	 * ramtron using normal read (which won't need dummy byte).
-	 * Unlikely NOR flash using normal read due to performance issue.
-	 */
-	if (cmdlen >= 5)
-		/* to cater fast read where cmd + addr + dummy */
-		addr_bytes = cmdlen - 2;
-	else
-		/* for normal read (only ramtron as of now) */
-		addr_bytes = cmdlen - 1;
+	unsigned int dummy_bytes = op->dummy.nbytes;
 
 	/* Setup the indirect trigger address */
 	writel(plat->trigger_address,
 	       plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
 
 	/* Configure the opcode */
-	rd_reg = cmdbuf[0] << CQSPI_REG_RD_INSTR_OPCODE_LSB;
+	rd_reg = op->cmd.opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
 
-	if (rx_width & SPI_RX_QUAD)
+	if (op->data.buswidth == 4)
 		/* Instruction and address at DQ0, data at DQ0-3. */
 		rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
 
-	/* Get address */
-	addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes);
-	writel(addr_value, plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
+	writel(op->addr.val, plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
 
-	/* The remaining lenght is dummy bytes. */
-	dummy_bytes = cmdlen - addr_bytes - 1;
 	if (dummy_bytes) {
 		if (dummy_bytes > CQSPI_DUMMY_BYTES_MAX)
 			dummy_bytes = CQSPI_DUMMY_BYTES_MAX;
 
-		rd_reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
-#if defined(CONFIG_SPL_SPI_XIP) && defined(CONFIG_SPL_BUILD)
-		writel(0x0, plat->regbase + CQSPI_REG_MODE_BIT);
-#else
-		writel(0xFF, plat->regbase + CQSPI_REG_MODE_BIT);
-#endif
-
 		/* Convert to clock cycles. */
 		dummy_clk = dummy_bytes * CQSPI_DUMMY_CLKS_PER_BYTE;
-		/* Need to minus the mode byte (8 clocks). */
-		dummy_clk -= CQSPI_DUMMY_CLKS_PER_BYTE;
 
 		if (dummy_clk)
 			rd_reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
@@ -596,7 +550,7 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
 	/* set device size */
 	reg = readl(plat->regbase + CQSPI_REG_SIZE);
 	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
-	reg |= (addr_bytes - 1);
+	reg |= (op->addr.nbytes - 1);
 	writel(reg, plat->regbase + CQSPI_REG_SIZE);
 	return 0;
 }
@@ -687,35 +641,23 @@ failrd:
 
 /* Opcode + Address (3/4 bytes) */
 int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
-	unsigned int cmdlen, unsigned int tx_width, const u8 *cmdbuf)
+	const struct spi_mem_op *op)
 {
 	unsigned int reg;
-	unsigned int addr_bytes = cmdlen > 4 ? 4 : 3;
 
-	if (cmdlen < 4 || cmdbuf == NULL) {
-		printf("QSPI: Invalid input argument, len %d cmdbuf %p\n",
-		       cmdlen, cmdbuf);
-		return -EINVAL;
-	}
 	/* Setup the indirect trigger address */
 	writel(plat->trigger_address,
 	       plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
 
 	/* Configure the opcode */
-	reg = cmdbuf[0] << CQSPI_REG_WR_INSTR_OPCODE_LSB;
-
-	if (tx_width & SPI_TX_QUAD)
-		reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB;
-
+	reg = op->cmd.opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
 	writel(reg, plat->regbase + CQSPI_REG_WR_INSTR);
 
-	/* Setup write address. */
-	reg = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes);
-	writel(reg, plat->regbase + CQSPI_REG_INDIRECTWRSTARTADDR);
+	writel(op->addr.val, plat->regbase + CQSPI_REG_INDIRECTWRSTARTADDR);
 
 	reg = readl(plat->regbase + CQSPI_REG_SIZE);
 	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
-	reg |= (addr_bytes - 1);
+	reg |= (op->addr.nbytes - 1);
 	writel(reg, plat->regbase + CQSPI_REG_SIZE);
 	return 0;
 }
-- 
2.24.0

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support
  2019-11-19 10:13 [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs Vignesh Raghavendra
  2019-11-19 10:13 ` [U-Boot] [PATCH v2 1/2] spi: cadence_qspi: Move to spi-mem framework Vignesh Raghavendra
@ 2019-11-19 10:13 ` Vignesh Raghavendra
  2020-01-17 12:51   ` Simon Goldschmidt
  2019-11-19 20:37 ` [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs Simon Goldschmidt
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Vignesh Raghavendra @ 2019-11-19 10:13 UTC (permalink / raw)
  To: u-boot

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>
---
v2: Add DMA support and update commit message

 drivers/spi/cadence_qspi.c     | 40 ++++++++++++---------
 drivers/spi/cadence_qspi.h     | 19 +++++-----
 drivers/spi/cadence_qspi_apb.c | 65 +++++++++++++++++++++++++++++-----
 3 files changed, 91 insertions(+), 33 deletions(-)

diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 673a2e9a6c4c..6c98cbf39ae4 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -12,12 +12,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)
 {
@@ -189,6 +190,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 */
@@ -197,6 +199,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);
 
@@ -221,12 +227,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) {
@@ -236,19 +242,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;
@@ -264,13 +266,17 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
 	ofnode subnode;
 
 	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);
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index e655b027d788..619f0bed8efd 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -23,6 +23,8 @@ struct cadence_spi_platdata {
 	u32		fifo_depth;
 	u32		fifo_width;
 	u32		trigger_address;
+	fdt_addr_t	ahbsize;
+	bool		use_dac_mode;
 
 	/* Flash parameters */
 	u32		page_size;
@@ -52,20 +54,21 @@ struct cadence_spi_priv {
 void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat);
 void cadence_qspi_apb_controller_enable(void *reg_base_addr);
 void cadence_qspi_apb_controller_disable(void *reg_base_addr);
+void cadence_qspi_apb_dac_mode_enable(void *reg_base);
 
 int cadence_qspi_apb_command_read(void *reg_base_addr,
 				  const struct spi_mem_op *op);
 int cadence_qspi_apb_command_write(void *reg_base_addr,
 				   const struct spi_mem_op *op);
 
-int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
-	const struct spi_mem_op *op);
-int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
-	unsigned int rxlen, u8 *rxbuf);
-int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
-	const struct spi_mem_op *op);
-int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
-	unsigned int txlen, const u8 *txbuf);
+int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
+				const struct spi_mem_op *op);
+int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
+				  const struct spi_mem_op *op);
+int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
+				 const struct spi_mem_op *op);
+int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
+				   const struct spi_mem_op *op);
 
 void cadence_qspi_apb_chipselect(void *reg_base,
 	unsigned int chip_select, unsigned int decoder_enable);
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index 8dd0495dfcf4..a0e14f93e020 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -27,6 +27,7 @@
 
 #include <common.h>
 #include <asm/io.h>
+#include <dma.h>
 #include <linux/errno.h>
 #include <wait_bit.h>
 #include <spi.h>
@@ -189,6 +190,15 @@ void cadence_qspi_apb_controller_disable(void *reg_base)
 	writel(reg, reg_base + CQSPI_REG_CONFIG);
 }
 
+void cadence_qspi_apb_dac_mode_enable(void *reg_base)
+{
+	unsigned int reg;
+
+	reg = readl(reg_base + CQSPI_REG_CONFIG);
+	reg |= CQSPI_REG_CONFIG_DIRECT;
+	writel(reg, reg_base + CQSPI_REG_CONFIG);
+}
+
 /* Return 1 if idle, otherwise return 0 (busy). */
 static unsigned int cadence_qspi_wait_idle(void *reg_base)
 {
@@ -512,8 +522,8 @@ int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op)
 }
 
 /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
-int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
-	const struct spi_mem_op *op)
+int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
+				const struct spi_mem_op *op)
 {
 	unsigned int reg;
 	unsigned int rd_reg;
@@ -577,8 +587,9 @@ static int cadence_qspi_wait_for_data(struct cadence_spi_platdata *plat)
 	return -ETIMEDOUT;
 }
 
-int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
-	unsigned int n_rx, u8 *rxbuf)
+static int
+cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
+				       unsigned int n_rx, u8 *rxbuf)
 {
 	unsigned int remaining = n_rx;
 	unsigned int bytes_to_read = 0;
@@ -639,9 +650,29 @@ failrd:
 	return ret;
 }
 
+int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
+				  const struct spi_mem_op *op)
+{
+	u32 from = op->addr.val;
+	void *buf = op->data.buf.in;
+	size_t len = op->data.nbytes;
+
+	if (plat->use_dac_mode && (from + len < plat->ahbsize)) {
+		if (len < 256 ||
+		    dma_memcpy(buf, plat->ahbbase + from, len) < 0) {
+			memcpy_fromio(buf, plat->ahbbase + from, len);
+		}
+		if (!cadence_qspi_wait_idle(plat->regbase))
+			return -EIO;
+		return 0;
+	}
+
+	return cadence_qspi_apb_indirect_read_execute(plat, len, buf);
+}
+
 /* Opcode + Address (3/4 bytes) */
-int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
-	const struct spi_mem_op *op)
+int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
+				 const struct spi_mem_op *op)
 {
 	unsigned int reg;
 
@@ -662,8 +693,9 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
 	return 0;
 }
 
-int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
-	unsigned int n_tx, const u8 *txbuf)
+static int
+cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
+					unsigned int n_tx, const u8 *txbuf)
 {
 	unsigned int page_size = plat->page_size;
 	unsigned int remaining = n_tx;
@@ -735,6 +767,23 @@ failwr:
 	return ret;
 }
 
+int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
+				   const struct spi_mem_op *op)
+{
+	u32 to = op->addr.val;
+	const void *buf = op->data.buf.out;
+	size_t len = op->data.nbytes;
+
+	if (plat->use_dac_mode && (to + len < plat->ahbsize)) {
+		memcpy_toio(plat->ahbbase + to, buf, len);
+		if (!cadence_qspi_wait_idle(plat->regbase))
+			return -EIO;
+		return 0;
+	}
+
+	return cadence_qspi_apb_indirect_write_execute(plat, len, buf);
+}
+
 void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
 {
 	unsigned int reg;
-- 
2.24.0

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs
  2019-11-19 10:13 [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs Vignesh Raghavendra
  2019-11-19 10:13 ` [U-Boot] [PATCH v2 1/2] spi: cadence_qspi: Move to spi-mem framework Vignesh Raghavendra
  2019-11-19 10:13 ` [U-Boot] [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support Vignesh Raghavendra
@ 2019-11-19 20:37 ` Simon Goldschmidt
  2020-01-14 15:02 ` Vignesh Raghavendra
  2020-01-20  4:39 ` Vignesh Raghavendra
  4 siblings, 0 replies; 15+ messages in thread
From: Simon Goldschmidt @ 2019-11-19 20:37 UTC (permalink / raw)
  To: u-boot

On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@ti.com> wrote:
>
> First patch moves driver over to spi-mem framework and implement
> spi_mem_ops. This is require to support more SPI Flash opcodes like SFDP
> parsing etc. Series is in prepartion to add Octal mode for support for
> the same driver to support OSPI version of the controller.
>
> Second patch adds DAC mode that provide memory mapped access to flash.
> This greatly increases the read throughput.
>
> Tested with mt25qu512 flash and s25fl512 flash
>
> Note: Depends on [1][2] that adds stubs for dma_memcpy() to be used on
> platforms without CONFIG_DMA enabled.
>
> [1]http://patchwork.ozlabs.org/patch/1195557/
> [2]http://patchwork.ozlabs.org/patch/1195556/
>
>
> Vignesh Raghavendra (2):
>   spi: cadence_qspi: Move to spi-mem framework
>   spi: cadence-qspi: Add direct mode support

I really got to find the time to test this on socfpga gen5, sorry for
failing yet.

Regards,
Simon

>
>  drivers/spi/cadence_qspi.c     | 148 +++++++++++---------------
>  drivers/spi/cadence_qspi.h     |  24 +++--
>  drivers/spi/cadence_qspi_apb.c | 185 ++++++++++++++++-----------------
>  3 files changed, 164 insertions(+), 193 deletions(-)
>
> --
> 2.24.0
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs
  2019-11-19 10:13 [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs Vignesh Raghavendra
                   ` (2 preceding siblings ...)
  2019-11-19 20:37 ` [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs Simon Goldschmidt
@ 2020-01-14 15:02 ` Vignesh Raghavendra
  2020-01-14 16:06   ` Simon Goldschmidt
  2020-01-20  4:39 ` Vignesh Raghavendra
  4 siblings, 1 reply; 15+ messages in thread
From: Vignesh Raghavendra @ 2020-01-14 15:02 UTC (permalink / raw)
  To: u-boot

Hi,

On 11/19/2019 3:43 PM, Vignesh Raghavendra wrote:
> First patch moves driver over to spi-mem framework and implement
> spi_mem_ops. This is require to support more SPI Flash opcodes like SFDP
> parsing etc. Series is in prepartion to add Octal mode for support for
> the same driver to support OSPI version of the controller.
> 
> Second patch adds DAC mode that provide memory mapped access to flash.
> This greatly increases the read throughput.
> 
> Tested with mt25qu512 flash and s25fl512 flash
> 
> Note: Depends on [1][2] that adds stubs for dma_memcpy() to be used on
> platforms without CONFIG_DMA enabled.
> 
> [1]http://patchwork.ozlabs.org/patch/1195557/
> [2]http://patchwork.ozlabs.org/patch/1195556/
> 

Gentle ping... This has been in the ML for quite sometime. Could this be
considered for this merge window?

Regards
Vignesh

> 
> Vignesh Raghavendra (2):
>   spi: cadence_qspi: Move to spi-mem framework
>   spi: cadence-qspi: Add direct mode support
> 
>  drivers/spi/cadence_qspi.c     | 148 +++++++++++---------------
>  drivers/spi/cadence_qspi.h     |  24 +++--
>  drivers/spi/cadence_qspi_apb.c | 185 ++++++++++++++++-----------------
>  3 files changed, 164 insertions(+), 193 deletions(-)
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs
  2020-01-14 15:02 ` Vignesh Raghavendra
@ 2020-01-14 16:06   ` Simon Goldschmidt
  0 siblings, 0 replies; 15+ messages in thread
From: Simon Goldschmidt @ 2020-01-14 16:06 UTC (permalink / raw)
  To: u-boot

Vignesh Raghavendra <vigneshr@ti.com> schrieb am Di., 14. Jan. 2020, 16:03:

> Hi,
>
> On 11/19/2019 3:43 PM, Vignesh Raghavendra wrote:
> > First patch moves driver over to spi-mem framework and implement
> > spi_mem_ops. This is require to support more SPI Flash opcodes like SFDP
> > parsing etc. Series is in prepartion to add Octal mode for support for
> > the same driver to support OSPI version of the controller.
> >
> > Second patch adds DAC mode that provide memory mapped access to flash.
> > This greatly increases the read throughput.
> >
> > Tested with mt25qu512 flash and s25fl512 flash
> >
> > Note: Depends on [1][2] that adds stubs for dma_memcpy() to be used on
> > platforms without CONFIG_DMA enabled.
> >
> > [1]http://patchwork.ozlabs.org/patch/1195557/
> > [2]http://patchwork.ozlabs.org/patch/1195556/
> >
>
> Gentle ping... This has been in the ML for quite sometime. Could this be
> considered for this merge window?
>

Oh, sorry. I'll take that as a reminder to test remaining things tomorrow.

Regards,
Simon


> Regards
> Vignesh
>
> >
> > Vignesh Raghavendra (2):
> >   spi: cadence_qspi: Move to spi-mem framework
> >   spi: cadence-qspi: Add direct mode support
> >
> >  drivers/spi/cadence_qspi.c     | 148 +++++++++++---------------
> >  drivers/spi/cadence_qspi.h     |  24 +++--
> >  drivers/spi/cadence_qspi_apb.c | 185 ++++++++++++++++-----------------
> >  3 files changed, 164 insertions(+), 193 deletions(-)
> >
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support
  2019-11-19 10:13 ` [U-Boot] [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support Vignesh Raghavendra
@ 2020-01-17 12:51   ` Simon Goldschmidt
  2020-01-17 13:02     ` Vignesh Raghavendra
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Goldschmidt @ 2020-01-17 12:51 UTC (permalink / raw)
  To: u-boot

On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@ti.com> wrote:
>
> 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().

This v2 doesn't compile for socfpa as dma_memcpy() isn't available. Since direct
mode isn't used on that platform (due to your 8MB check), dma_memcpy() is not
required, but still it doesn't link as this is a runtime decision.

Regards,
Simon

>
> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
> ---
> v2: Add DMA support and update commit message
>
>  drivers/spi/cadence_qspi.c     | 40 ++++++++++++---------
>  drivers/spi/cadence_qspi.h     | 19 +++++-----
>  drivers/spi/cadence_qspi_apb.c | 65 +++++++++++++++++++++++++++++-----
>  3 files changed, 91 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
> index 673a2e9a6c4c..6c98cbf39ae4 100644
> --- a/drivers/spi/cadence_qspi.c
> +++ b/drivers/spi/cadence_qspi.c
> @@ -12,12 +12,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)
>  {
> @@ -189,6 +190,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 */
> @@ -197,6 +199,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);
>
> @@ -221,12 +227,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) {
> @@ -236,19 +242,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;
> @@ -264,13 +266,17 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
>         ofnode subnode;
>
>         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);
> diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
> index e655b027d788..619f0bed8efd 100644
> --- a/drivers/spi/cadence_qspi.h
> +++ b/drivers/spi/cadence_qspi.h
> @@ -23,6 +23,8 @@ struct cadence_spi_platdata {
>         u32             fifo_depth;
>         u32             fifo_width;
>         u32             trigger_address;
> +       fdt_addr_t      ahbsize;
> +       bool            use_dac_mode;
>
>         /* Flash parameters */
>         u32             page_size;
> @@ -52,20 +54,21 @@ struct cadence_spi_priv {
>  void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat);
>  void cadence_qspi_apb_controller_enable(void *reg_base_addr);
>  void cadence_qspi_apb_controller_disable(void *reg_base_addr);
> +void cadence_qspi_apb_dac_mode_enable(void *reg_base);
>
>  int cadence_qspi_apb_command_read(void *reg_base_addr,
>                                   const struct spi_mem_op *op);
>  int cadence_qspi_apb_command_write(void *reg_base_addr,
>                                    const struct spi_mem_op *op);
>
> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
> -       const struct spi_mem_op *op);
> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> -       unsigned int rxlen, u8 *rxbuf);
> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> -       const struct spi_mem_op *op);
> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> -       unsigned int txlen, const u8 *txbuf);
> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
> +                               const struct spi_mem_op *op);
> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
> +                                 const struct spi_mem_op *op);
> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
> +                                const struct spi_mem_op *op);
> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
> +                                  const struct spi_mem_op *op);
>
>  void cadence_qspi_apb_chipselect(void *reg_base,
>         unsigned int chip_select, unsigned int decoder_enable);
> diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
> index 8dd0495dfcf4..a0e14f93e020 100644
> --- a/drivers/spi/cadence_qspi_apb.c
> +++ b/drivers/spi/cadence_qspi_apb.c
> @@ -27,6 +27,7 @@
>
>  #include <common.h>
>  #include <asm/io.h>
> +#include <dma.h>
>  #include <linux/errno.h>
>  #include <wait_bit.h>
>  #include <spi.h>
> @@ -189,6 +190,15 @@ void cadence_qspi_apb_controller_disable(void *reg_base)
>         writel(reg, reg_base + CQSPI_REG_CONFIG);
>  }
>
> +void cadence_qspi_apb_dac_mode_enable(void *reg_base)
> +{
> +       unsigned int reg;
> +
> +       reg = readl(reg_base + CQSPI_REG_CONFIG);
> +       reg |= CQSPI_REG_CONFIG_DIRECT;
> +       writel(reg, reg_base + CQSPI_REG_CONFIG);
> +}
> +
>  /* Return 1 if idle, otherwise return 0 (busy). */
>  static unsigned int cadence_qspi_wait_idle(void *reg_base)
>  {
> @@ -512,8 +522,8 @@ int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op)
>  }
>
>  /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
> -       const struct spi_mem_op *op)
> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
> +                               const struct spi_mem_op *op)
>  {
>         unsigned int reg;
>         unsigned int rd_reg;
> @@ -577,8 +587,9 @@ static int cadence_qspi_wait_for_data(struct cadence_spi_platdata *plat)
>         return -ETIMEDOUT;
>  }
>
> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> -       unsigned int n_rx, u8 *rxbuf)
> +static int
> +cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> +                                      unsigned int n_rx, u8 *rxbuf)
>  {
>         unsigned int remaining = n_rx;
>         unsigned int bytes_to_read = 0;
> @@ -639,9 +650,29 @@ failrd:
>         return ret;
>  }
>
> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
> +                                 const struct spi_mem_op *op)
> +{
> +       u32 from = op->addr.val;
> +       void *buf = op->data.buf.in;
> +       size_t len = op->data.nbytes;
> +
> +       if (plat->use_dac_mode && (from + len < plat->ahbsize)) {
> +               if (len < 256 ||
> +                   dma_memcpy(buf, plat->ahbbase + from, len) < 0) {
> +                       memcpy_fromio(buf, plat->ahbbase + from, len);
> +               }
> +               if (!cadence_qspi_wait_idle(plat->regbase))
> +                       return -EIO;
> +               return 0;
> +       }
> +
> +       return cadence_qspi_apb_indirect_read_execute(plat, len, buf);
> +}
> +
>  /* Opcode + Address (3/4 bytes) */
> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> -       const struct spi_mem_op *op)
> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
> +                                const struct spi_mem_op *op)
>  {
>         unsigned int reg;
>
> @@ -662,8 +693,9 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
>         return 0;
>  }
>
> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> -       unsigned int n_tx, const u8 *txbuf)
> +static int
> +cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> +                                       unsigned int n_tx, const u8 *txbuf)
>  {
>         unsigned int page_size = plat->page_size;
>         unsigned int remaining = n_tx;
> @@ -735,6 +767,23 @@ failwr:
>         return ret;
>  }
>
> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
> +                                  const struct spi_mem_op *op)
> +{
> +       u32 to = op->addr.val;
> +       const void *buf = op->data.buf.out;
> +       size_t len = op->data.nbytes;
> +
> +       if (plat->use_dac_mode && (to + len < plat->ahbsize)) {
> +               memcpy_toio(plat->ahbbase + to, buf, len);
> +               if (!cadence_qspi_wait_idle(plat->regbase))
> +                       return -EIO;
> +               return 0;
> +       }
> +
> +       return cadence_qspi_apb_indirect_write_execute(plat, len, buf);
> +}
> +
>  void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
>  {
>         unsigned int reg;
> --
> 2.24.0
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support
  2020-01-17 12:51   ` Simon Goldschmidt
@ 2020-01-17 13:02     ` Vignesh Raghavendra
  2020-01-17 13:20       ` Simon Goldschmidt
  0 siblings, 1 reply; 15+ messages in thread
From: Vignesh Raghavendra @ 2020-01-17 13:02 UTC (permalink / raw)
  To: u-boot



On 17/01/20 6:21 pm, Simon Goldschmidt wrote:
> On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@ti.com> wrote:
>>
>> 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().
> 
> This v2 doesn't compile for socfpa as dma_memcpy() isn't available. Since direct
> mode isn't used on that platform (due to your 8MB check), dma_memcpy() is not
> required, but still it doesn't link as this is a runtime decision.
> 

Could you try with latest master and make sure it has [1] and [2]
applied? Thanks!

[1]http://patchwork.ozlabs.org/patch/1195557/
[2]http://patchwork.ozlabs.org/patch/1195556/

Regards
Vignesh

> Regards,
> Simon
> 
>>
>> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
>> ---
>> v2: Add DMA support and update commit message
>>
>>  drivers/spi/cadence_qspi.c     | 40 ++++++++++++---------
>>  drivers/spi/cadence_qspi.h     | 19 +++++-----
>>  drivers/spi/cadence_qspi_apb.c | 65 +++++++++++++++++++++++++++++-----
>>  3 files changed, 91 insertions(+), 33 deletions(-)
>>
>> diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
>> index 673a2e9a6c4c..6c98cbf39ae4 100644
>> --- a/drivers/spi/cadence_qspi.c
>> +++ b/drivers/spi/cadence_qspi.c
>> @@ -12,12 +12,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)
>>  {
>> @@ -189,6 +190,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 */
>> @@ -197,6 +199,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);
>>
>> @@ -221,12 +227,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) {
>> @@ -236,19 +242,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;
>> @@ -264,13 +266,17 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
>>         ofnode subnode;
>>
>>         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);
>> diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
>> index e655b027d788..619f0bed8efd 100644
>> --- a/drivers/spi/cadence_qspi.h
>> +++ b/drivers/spi/cadence_qspi.h
>> @@ -23,6 +23,8 @@ struct cadence_spi_platdata {
>>         u32             fifo_depth;
>>         u32             fifo_width;
>>         u32             trigger_address;
>> +       fdt_addr_t      ahbsize;
>> +       bool            use_dac_mode;
>>
>>         /* Flash parameters */
>>         u32             page_size;
>> @@ -52,20 +54,21 @@ struct cadence_spi_priv {
>>  void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat);
>>  void cadence_qspi_apb_controller_enable(void *reg_base_addr);
>>  void cadence_qspi_apb_controller_disable(void *reg_base_addr);
>> +void cadence_qspi_apb_dac_mode_enable(void *reg_base);
>>
>>  int cadence_qspi_apb_command_read(void *reg_base_addr,
>>                                   const struct spi_mem_op *op);
>>  int cadence_qspi_apb_command_write(void *reg_base_addr,
>>                                    const struct spi_mem_op *op);
>>
>> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
>> -       const struct spi_mem_op *op);
>> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
>> -       unsigned int rxlen, u8 *rxbuf);
>> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
>> -       const struct spi_mem_op *op);
>> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
>> -       unsigned int txlen, const u8 *txbuf);
>> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
>> +                               const struct spi_mem_op *op);
>> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
>> +                                 const struct spi_mem_op *op);
>> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
>> +                                const struct spi_mem_op *op);
>> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
>> +                                  const struct spi_mem_op *op);
>>
>>  void cadence_qspi_apb_chipselect(void *reg_base,
>>         unsigned int chip_select, unsigned int decoder_enable);
>> diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
>> index 8dd0495dfcf4..a0e14f93e020 100644
>> --- a/drivers/spi/cadence_qspi_apb.c
>> +++ b/drivers/spi/cadence_qspi_apb.c
>> @@ -27,6 +27,7 @@
>>
>>  #include <common.h>
>>  #include <asm/io.h>
>> +#include <dma.h>
>>  #include <linux/errno.h>
>>  #include <wait_bit.h>
>>  #include <spi.h>
>> @@ -189,6 +190,15 @@ void cadence_qspi_apb_controller_disable(void *reg_base)
>>         writel(reg, reg_base + CQSPI_REG_CONFIG);
>>  }
>>
>> +void cadence_qspi_apb_dac_mode_enable(void *reg_base)
>> +{
>> +       unsigned int reg;
>> +
>> +       reg = readl(reg_base + CQSPI_REG_CONFIG);
>> +       reg |= CQSPI_REG_CONFIG_DIRECT;
>> +       writel(reg, reg_base + CQSPI_REG_CONFIG);
>> +}
>> +
>>  /* Return 1 if idle, otherwise return 0 (busy). */
>>  static unsigned int cadence_qspi_wait_idle(void *reg_base)
>>  {
>> @@ -512,8 +522,8 @@ int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op)
>>  }
>>
>>  /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
>> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
>> -       const struct spi_mem_op *op)
>> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
>> +                               const struct spi_mem_op *op)
>>  {
>>         unsigned int reg;
>>         unsigned int rd_reg;
>> @@ -577,8 +587,9 @@ static int cadence_qspi_wait_for_data(struct cadence_spi_platdata *plat)
>>         return -ETIMEDOUT;
>>  }
>>
>> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
>> -       unsigned int n_rx, u8 *rxbuf)
>> +static int
>> +cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
>> +                                      unsigned int n_rx, u8 *rxbuf)
>>  {
>>         unsigned int remaining = n_rx;
>>         unsigned int bytes_to_read = 0;
>> @@ -639,9 +650,29 @@ failrd:
>>         return ret;
>>  }
>>
>> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
>> +                                 const struct spi_mem_op *op)
>> +{
>> +       u32 from = op->addr.val;
>> +       void *buf = op->data.buf.in;
>> +       size_t len = op->data.nbytes;
>> +
>> +       if (plat->use_dac_mode && (from + len < plat->ahbsize)) {
>> +               if (len < 256 ||
>> +                   dma_memcpy(buf, plat->ahbbase + from, len) < 0) {
>> +                       memcpy_fromio(buf, plat->ahbbase + from, len);
>> +               }
>> +               if (!cadence_qspi_wait_idle(plat->regbase))
>> +                       return -EIO;
>> +               return 0;
>> +       }
>> +
>> +       return cadence_qspi_apb_indirect_read_execute(plat, len, buf);
>> +}
>> +
>>  /* Opcode + Address (3/4 bytes) */
>> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
>> -       const struct spi_mem_op *op)
>> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
>> +                                const struct spi_mem_op *op)
>>  {
>>         unsigned int reg;
>>
>> @@ -662,8 +693,9 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
>>         return 0;
>>  }
>>
>> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
>> -       unsigned int n_tx, const u8 *txbuf)
>> +static int
>> +cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
>> +                                       unsigned int n_tx, const u8 *txbuf)
>>  {
>>         unsigned int page_size = plat->page_size;
>>         unsigned int remaining = n_tx;
>> @@ -735,6 +767,23 @@ failwr:
>>         return ret;
>>  }
>>
>> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
>> +                                  const struct spi_mem_op *op)
>> +{
>> +       u32 to = op->addr.val;
>> +       const void *buf = op->data.buf.out;
>> +       size_t len = op->data.nbytes;
>> +
>> +       if (plat->use_dac_mode && (to + len < plat->ahbsize)) {
>> +               memcpy_toio(plat->ahbbase + to, buf, len);
>> +               if (!cadence_qspi_wait_idle(plat->regbase))
>> +                       return -EIO;
>> +               return 0;
>> +       }
>> +
>> +       return cadence_qspi_apb_indirect_write_execute(plat, len, buf);
>> +}
>> +
>>  void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
>>  {
>>         unsigned int reg;
>> --
>> 2.24.0
>>

-- 
Regards
Vignesh

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support
  2020-01-17 13:02     ` Vignesh Raghavendra
@ 2020-01-17 13:20       ` Simon Goldschmidt
  2020-01-17 15:52         ` Simon Goldschmidt
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Goldschmidt @ 2020-01-17 13:20 UTC (permalink / raw)
  To: u-boot

On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigneshr@ti.com> wrote:
>
>
>
> On 17/01/20 6:21 pm, Simon Goldschmidt wrote:
> > On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@ti.com> wrote:
> >>
> >> 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().
> >
> > This v2 doesn't compile for socfpa as dma_memcpy() isn't available. Since direct
> > mode isn't used on that platform (due to your 8MB check), dma_memcpy() is not
> > required, but still it doesn't link as this is a runtime decision.
> >
>
> Could you try with latest master and make sure it has [1] and [2]
> applied? Thanks!
>
> [1]http://patchwork.ozlabs.org/patch/1195557/
> [2]http://patchwork.ozlabs.org/patch/1195556/

Right, Tom merged that yesterday. Compiles now, sorry for the noise.

Regards,
Simon

>
> Regards
> Vignesh
>
> > Regards,
> > Simon
> >
> >>
> >> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
> >> ---
> >> v2: Add DMA support and update commit message
> >>
> >>  drivers/spi/cadence_qspi.c     | 40 ++++++++++++---------
> >>  drivers/spi/cadence_qspi.h     | 19 +++++-----
> >>  drivers/spi/cadence_qspi_apb.c | 65 +++++++++++++++++++++++++++++-----
> >>  3 files changed, 91 insertions(+), 33 deletions(-)
> >>
> >> diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
> >> index 673a2e9a6c4c..6c98cbf39ae4 100644
> >> --- a/drivers/spi/cadence_qspi.c
> >> +++ b/drivers/spi/cadence_qspi.c
> >> @@ -12,12 +12,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)
> >>  {
> >> @@ -189,6 +190,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 */
> >> @@ -197,6 +199,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);
> >>
> >> @@ -221,12 +227,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) {
> >> @@ -236,19 +242,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;
> >> @@ -264,13 +266,17 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
> >>         ofnode subnode;
> >>
> >>         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);
> >> diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
> >> index e655b027d788..619f0bed8efd 100644
> >> --- a/drivers/spi/cadence_qspi.h
> >> +++ b/drivers/spi/cadence_qspi.h
> >> @@ -23,6 +23,8 @@ struct cadence_spi_platdata {
> >>         u32             fifo_depth;
> >>         u32             fifo_width;
> >>         u32             trigger_address;
> >> +       fdt_addr_t      ahbsize;
> >> +       bool            use_dac_mode;
> >>
> >>         /* Flash parameters */
> >>         u32             page_size;
> >> @@ -52,20 +54,21 @@ struct cadence_spi_priv {
> >>  void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat);
> >>  void cadence_qspi_apb_controller_enable(void *reg_base_addr);
> >>  void cadence_qspi_apb_controller_disable(void *reg_base_addr);
> >> +void cadence_qspi_apb_dac_mode_enable(void *reg_base);
> >>
> >>  int cadence_qspi_apb_command_read(void *reg_base_addr,
> >>                                   const struct spi_mem_op *op);
> >>  int cadence_qspi_apb_command_write(void *reg_base_addr,
> >>                                    const struct spi_mem_op *op);
> >>
> >> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
> >> -       const struct spi_mem_op *op);
> >> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> >> -       unsigned int rxlen, u8 *rxbuf);
> >> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> >> -       const struct spi_mem_op *op);
> >> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> >> -       unsigned int txlen, const u8 *txbuf);
> >> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
> >> +                               const struct spi_mem_op *op);
> >> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
> >> +                                 const struct spi_mem_op *op);
> >> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
> >> +                                const struct spi_mem_op *op);
> >> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
> >> +                                  const struct spi_mem_op *op);
> >>
> >>  void cadence_qspi_apb_chipselect(void *reg_base,
> >>         unsigned int chip_select, unsigned int decoder_enable);
> >> diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
> >> index 8dd0495dfcf4..a0e14f93e020 100644
> >> --- a/drivers/spi/cadence_qspi_apb.c
> >> +++ b/drivers/spi/cadence_qspi_apb.c
> >> @@ -27,6 +27,7 @@
> >>
> >>  #include <common.h>
> >>  #include <asm/io.h>
> >> +#include <dma.h>
> >>  #include <linux/errno.h>
> >>  #include <wait_bit.h>
> >>  #include <spi.h>
> >> @@ -189,6 +190,15 @@ void cadence_qspi_apb_controller_disable(void *reg_base)
> >>         writel(reg, reg_base + CQSPI_REG_CONFIG);
> >>  }
> >>
> >> +void cadence_qspi_apb_dac_mode_enable(void *reg_base)
> >> +{
> >> +       unsigned int reg;
> >> +
> >> +       reg = readl(reg_base + CQSPI_REG_CONFIG);
> >> +       reg |= CQSPI_REG_CONFIG_DIRECT;
> >> +       writel(reg, reg_base + CQSPI_REG_CONFIG);
> >> +}
> >> +
> >>  /* Return 1 if idle, otherwise return 0 (busy). */
> >>  static unsigned int cadence_qspi_wait_idle(void *reg_base)
> >>  {
> >> @@ -512,8 +522,8 @@ int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op)
> >>  }
> >>
> >>  /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
> >> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
> >> -       const struct spi_mem_op *op)
> >> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
> >> +                               const struct spi_mem_op *op)
> >>  {
> >>         unsigned int reg;
> >>         unsigned int rd_reg;
> >> @@ -577,8 +587,9 @@ static int cadence_qspi_wait_for_data(struct cadence_spi_platdata *plat)
> >>         return -ETIMEDOUT;
> >>  }
> >>
> >> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> >> -       unsigned int n_rx, u8 *rxbuf)
> >> +static int
> >> +cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> >> +                                      unsigned int n_rx, u8 *rxbuf)
> >>  {
> >>         unsigned int remaining = n_rx;
> >>         unsigned int bytes_to_read = 0;
> >> @@ -639,9 +650,29 @@ failrd:
> >>         return ret;
> >>  }
> >>
> >> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
> >> +                                 const struct spi_mem_op *op)
> >> +{
> >> +       u32 from = op->addr.val;
> >> +       void *buf = op->data.buf.in;
> >> +       size_t len = op->data.nbytes;
> >> +
> >> +       if (plat->use_dac_mode && (from + len < plat->ahbsize)) {
> >> +               if (len < 256 ||
> >> +                   dma_memcpy(buf, plat->ahbbase + from, len) < 0) {
> >> +                       memcpy_fromio(buf, plat->ahbbase + from, len);
> >> +               }
> >> +               if (!cadence_qspi_wait_idle(plat->regbase))
> >> +                       return -EIO;
> >> +               return 0;
> >> +       }
> >> +
> >> +       return cadence_qspi_apb_indirect_read_execute(plat, len, buf);
> >> +}
> >> +
> >>  /* Opcode + Address (3/4 bytes) */
> >> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> >> -       const struct spi_mem_op *op)
> >> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
> >> +                                const struct spi_mem_op *op)
> >>  {
> >>         unsigned int reg;
> >>
> >> @@ -662,8 +693,9 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> >>         return 0;
> >>  }
> >>
> >> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> >> -       unsigned int n_tx, const u8 *txbuf)
> >> +static int
> >> +cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> >> +                                       unsigned int n_tx, const u8 *txbuf)
> >>  {
> >>         unsigned int page_size = plat->page_size;
> >>         unsigned int remaining = n_tx;
> >> @@ -735,6 +767,23 @@ failwr:
> >>         return ret;
> >>  }
> >>
> >> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
> >> +                                  const struct spi_mem_op *op)
> >> +{
> >> +       u32 to = op->addr.val;
> >> +       const void *buf = op->data.buf.out;
> >> +       size_t len = op->data.nbytes;
> >> +
> >> +       if (plat->use_dac_mode && (to + len < plat->ahbsize)) {
> >> +               memcpy_toio(plat->ahbbase + to, buf, len);
> >> +               if (!cadence_qspi_wait_idle(plat->regbase))
> >> +                       return -EIO;
> >> +               return 0;
> >> +       }
> >> +
> >> +       return cadence_qspi_apb_indirect_write_execute(plat, len, buf);
> >> +}
> >> +
> >>  void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
> >>  {
> >>         unsigned int reg;
> >> --
> >> 2.24.0
> >>
>
> --
> Regards
> Vignesh

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 1/2] spi: cadence_qspi: Move to spi-mem framework
  2019-11-19 10:13 ` [U-Boot] [PATCH v2 1/2] spi: cadence_qspi: Move to spi-mem framework Vignesh Raghavendra
@ 2020-01-17 15:51   ` Simon Goldschmidt
  0 siblings, 0 replies; 15+ messages in thread
From: Simon Goldschmidt @ 2020-01-17 15:51 UTC (permalink / raw)
  To: u-boot

On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@ti.com> wrote:
>
> Current Cadence QSPI driver has few limitations. It assumes all read
> operations to be in Quad mode and thus does not support SFDP parsing.
> Also, adding support for new mode such as Octal mode would not be
> possible with current configuration. Therefore move the driver over to spi-mem
> framework. This has added advantage that driver can be used to support
> SPI NAND memories too.
> Hence, move driver over to new spi-mem APIs.
>
> Please note that this gets rid of mode bit setting done when
> CONFIG_SPL_SPI_XIP is defined as there does not seem to be any user to
> that config option.
>
> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>

Tested on socfpga_gen5:
Tested-by: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>

> ---
> v2: No change
>
>  drivers/spi/cadence_qspi.c     | 136 +++++++++++++--------------------
>  drivers/spi/cadence_qspi.h     |   9 +--
>  drivers/spi/cadence_qspi_apb.c | 124 ++++++++----------------------
>  3 files changed, 91 insertions(+), 178 deletions(-)
>
> diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
> index e2e54cd27723..673a2e9a6c4c 100644
> --- a/drivers/spi/cadence_qspi.c
> +++ b/drivers/spi/cadence_qspi.c
> @@ -10,6 +10,7 @@
>  #include <malloc.h>
>  #include <reset.h>
>  #include <spi.h>
> +#include <spi-mem.h>
>  #include <linux/errno.h>
>  #include "cadence_qspi.h"
>
> @@ -34,12 +35,21 @@ static int cadence_spi_write_speed(struct udevice *bus, uint hz)
>         return 0;
>  }
>
> +static int cadence_spi_read_id(void *reg_base, u8 len, u8 *idcode)
> +{
> +       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x9F, 1),
> +                                         SPI_MEM_OP_NO_ADDR,
> +                                         SPI_MEM_OP_NO_DUMMY,
> +                                         SPI_MEM_OP_DATA_IN(len, idcode, 1));
> +
> +       return cadence_qspi_apb_command_read(reg_base, &op);
> +}
> +
>  /* Calibration sequence to determine the read data capture delay register */
>  static int spi_calibration(struct udevice *bus, uint hz)
>  {
>         struct cadence_spi_priv *priv = dev_get_priv(bus);
>         void *base = priv->regbase;
> -       u8 opcode_rdid = 0x9F;
>         unsigned int idcode = 0, temp = 0;
>         int err = 0, i, range_lo = -1, range_hi = -1;
>
> @@ -53,8 +63,7 @@ static int spi_calibration(struct udevice *bus, uint hz)
>         cadence_qspi_apb_controller_enable(base);
>
>         /* read the ID which will be our golden value */
> -       err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
> -               3, (u8 *)&idcode);
> +       err = cadence_spi_read_id(base, 3, (u8 *)&idcode);
>         if (err) {
>                 puts("SF: Calibration failed (read)\n");
>                 return err;
> @@ -73,8 +82,7 @@ static int spi_calibration(struct udevice *bus, uint hz)
>                 cadence_qspi_apb_controller_enable(base);
>
>                 /* issue a RDID to get the ID value */
> -               err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
> -                       3, (u8 *)&temp);
> +               err = cadence_spi_read_id(base, 3, (u8 *)&temp);
>                 if (err) {
>                         puts("SF: Calibration failed (read)\n");
>                         return err;
> @@ -195,96 +203,56 @@ static int cadence_spi_set_mode(struct udevice *bus, uint mode)
>         return 0;
>  }
>
> -static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen,
> -                           const void *dout, void *din, unsigned long flags)
> +static int cadence_spi_mem_exec_op(struct spi_slave *spi,
> +                                  const struct spi_mem_op *op)
>  {
> -       struct udevice *bus = dev->parent;
> +       struct udevice *bus = spi->dev->parent;
>         struct cadence_spi_platdata *plat = bus->platdata;
>         struct cadence_spi_priv *priv = dev_get_priv(bus);
> -       struct dm_spi_slave_platdata *dm_plat = dev_get_parent_platdata(dev);
>         void *base = priv->regbase;
> -       u8 *cmd_buf = priv->cmd_buf;
> -       size_t data_bytes;
>         int err = 0;
> -       u32 mode = CQSPI_STIG_WRITE;
> -
> -       if (flags & SPI_XFER_BEGIN) {
> -               /* copy command to local buffer */
> -               priv->cmd_len = bitlen / 8;
> -               memcpy(cmd_buf, dout, priv->cmd_len);
> -       }
> -
> -       if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) {
> -               /* if start and end bit are set, the data bytes is 0. */
> -               data_bytes = 0;
> -       } else {
> -               data_bytes = bitlen / 8;
> -       }
> -       debug("%s: len=%zu [bytes]\n", __func__, data_bytes);
> +       u32 mode;
>
>         /* Set Chip select */
> -       cadence_qspi_apb_chipselect(base, spi_chip_select(dev),
> +       cadence_qspi_apb_chipselect(base, spi_chip_select(spi->dev),
>                                     plat->is_decoded_cs);
>
> -       if ((flags & SPI_XFER_END) || (flags == 0)) {
> -               if (priv->cmd_len == 0) {
> -                       printf("QSPI: Error, command is empty.\n");
> -                       return -1;
> -               }
> -
> -               if (din && data_bytes) {
> -                       /* read */
> -                       /* Use STIG if no address. */
> -                       if (!CQSPI_IS_ADDR(priv->cmd_len))
> -                               mode = CQSPI_STIG_READ;
> -                       else
> -                               mode = CQSPI_INDIRECT_READ;
> -               } else if (dout && !(flags & SPI_XFER_BEGIN)) {
> -                       /* write */
> -                       if (!CQSPI_IS_ADDR(priv->cmd_len))
> -                               mode = CQSPI_STIG_WRITE;
> -                       else
> -                               mode = CQSPI_INDIRECT_WRITE;
> -               }
> -
> -               switch (mode) {
> -               case CQSPI_STIG_READ:
> -                       err = cadence_qspi_apb_command_read(
> -                               base, priv->cmd_len, cmd_buf,
> -                               data_bytes, din);
> +       if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) {
> +               if (!op->addr.nbytes)
> +                       mode = CQSPI_STIG_READ;
> +               else
> +                       mode = CQSPI_INDIRECT_READ;
> +       } else {
> +               if (!op->addr.nbytes || !op->data.buf.out)
> +                       mode = CQSPI_STIG_WRITE;
> +               else
> +                       mode = CQSPI_INDIRECT_WRITE;
> +       }
>
> +       switch (mode) {
> +       case CQSPI_STIG_READ:
> +               err = cadence_qspi_apb_command_read(base, op);
>                 break;
> -               case CQSPI_STIG_WRITE:
> -                       err = cadence_qspi_apb_command_write(base,
> -                               priv->cmd_len, cmd_buf,
> -                               data_bytes, dout);
> +       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,
> -                               priv->cmd_len, dm_plat->mode, cmd_buf);
> -                       if (!err) {
> -                               err = cadence_qspi_apb_indirect_read_execute
> -                               (plat, data_bytes, din);
> -                       }
> -               break;
> -               case CQSPI_INDIRECT_WRITE:
> -                       err = cadence_qspi_apb_indirect_write_setup
> -                               (plat, priv->cmd_len, dm_plat->mode, cmd_buf);
> -                       if (!err) {
> -                               err = cadence_qspi_apb_indirect_write_execute
> -                               (plat, data_bytes, dout);
> -                       }
> -               break;
> -               default:
> -                       err = -1;
> -                       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);
>                 }
> -
> -               if (flags & SPI_XFER_END) {
> -                       /* clear command buffer */
> -                       memset(cmd_buf, 0, sizeof(priv->cmd_buf));
> -                       priv->cmd_len = 0;
> +               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);
>                 }
> +               break;
> +       default:
> +               err = -1;
> +               break;
>         }
>
>         return err;
> @@ -332,10 +300,14 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
>         return 0;
>  }
>
> +static const struct spi_controller_mem_ops cadence_spi_mem_ops = {
> +       .exec_op = cadence_spi_mem_exec_op,
> +};
> +
>  static const struct dm_spi_ops cadence_spi_ops = {
> -       .xfer           = cadence_spi_xfer,
>         .set_speed      = cadence_spi_set_speed,
>         .set_mode       = cadence_spi_set_mode,
> +       .mem_ops        = &cadence_spi_mem_ops,
>         /*
>          * cs_info is not needed, since we require all chip selects to be
>          * in the device tree explicitly
> diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
> index 20cceca239f8..e655b027d788 100644
> --- a/drivers/spi/cadence_qspi.h
> +++ b/drivers/spi/cadence_qspi.h
> @@ -54,17 +54,16 @@ void cadence_qspi_apb_controller_enable(void *reg_base_addr);
>  void cadence_qspi_apb_controller_disable(void *reg_base_addr);
>
>  int cadence_qspi_apb_command_read(void *reg_base_addr,
> -       unsigned int cmdlen, const u8 *cmdbuf, unsigned int rxlen, u8 *rxbuf);
> +                                 const struct spi_mem_op *op);
>  int cadence_qspi_apb_command_write(void *reg_base_addr,
> -       unsigned int cmdlen, const u8 *cmdbuf,
> -       unsigned int txlen,  const u8 *txbuf);
> +                                  const struct spi_mem_op *op);
>
>  int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
> -       unsigned int cmdlen, unsigned int rx_width, const u8 *cmdbuf);
> +       const struct spi_mem_op *op);
>  int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
>         unsigned int rxlen, u8 *rxbuf);
>  int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> -       unsigned int cmdlen, unsigned int tx_width, const u8 *cmdbuf);
> +       const struct spi_mem_op *op);
>  int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
>         unsigned int txlen, const u8 *txbuf);
>
> diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
> index 55a7501913a8..8dd0495dfcf4 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 <spi-mem.h>
>  #include <malloc.h>
>  #include "cadence_qspi.h"
>
> @@ -172,19 +173,6 @@
>         (((readl(reg_base + CQSPI_REG_SDRAMLEVEL)) >>   \
>         CQSPI_REG_SDRAMLEVEL_WR_LSB) & CQSPI_REG_SDRAMLEVEL_WR_MASK)
>
> -static unsigned int cadence_qspi_apb_cmd2addr(const unsigned char *addr_buf,
> -       unsigned int addr_width)
> -{
> -       unsigned int addr;
> -
> -       addr = (addr_buf[0] << 16) | (addr_buf[1] << 8) | addr_buf[2];
> -
> -       if (addr_width == 4)
> -               addr = (addr << 8) | addr_buf[3];
> -
> -       return addr;
> -}
> -
>  void cadence_qspi_apb_controller_enable(void *reg_base)
>  {
>         unsigned int reg;
> @@ -433,21 +421,20 @@ static int cadence_qspi_apb_exec_flash_cmd(void *reg_base,
>  }
>
>  /* For command RDID, RDSR. */
> -int cadence_qspi_apb_command_read(void *reg_base,
> -       unsigned int cmdlen, const u8 *cmdbuf, unsigned int rxlen,
> -       u8 *rxbuf)
> +int cadence_qspi_apb_command_read(void *reg_base, const struct spi_mem_op *op)
>  {
>         unsigned int reg;
>         unsigned int read_len;
>         int status;
> +       unsigned int rxlen = op->data.nbytes;
> +       void *rxbuf = op->data.buf.in;
>
> -       if (!cmdlen || rxlen > CQSPI_STIG_DATA_LEN_MAX || rxbuf == NULL) {
> -               printf("QSPI: Invalid input arguments cmdlen %d rxlen %d\n",
> -                      cmdlen, rxlen);
> +       if (rxlen > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
> +               printf("QSPI: Invalid input arguments rxlen %u\n", rxlen);
>                 return -EINVAL;
>         }
>
> -       reg = cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
> +       reg = op->cmd.opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
>
>         reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
>
> @@ -475,34 +462,30 @@ int cadence_qspi_apb_command_read(void *reg_base,
>  }
>
>  /* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */
> -int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen,
> -       const u8 *cmdbuf, unsigned int txlen,  const u8 *txbuf)
> +int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op)
>  {
>         unsigned int reg = 0;
> -       unsigned int addr_value;
>         unsigned int wr_data;
>         unsigned int wr_len;
> +       unsigned int txlen = op->data.nbytes;
> +       const void *txbuf = op->data.buf.out;
> +       u32 addr;
> +
> +       /* Reorder address to SPI bus order if only transferring address */
> +       if (!txlen) {
> +               addr = cpu_to_be32(op->addr.val);
> +               if (op->addr.nbytes == 3)
> +                       addr >>= 8;
> +               txbuf = &addr;
> +               txlen = op->addr.nbytes;
> +       }
>
> -       if (!cmdlen || cmdlen > 5 || txlen > 8 || cmdbuf == NULL) {
> -               printf("QSPI: Invalid input arguments cmdlen %d txlen %d\n",
> -                      cmdlen, txlen);
> +       if (txlen > CQSPI_STIG_DATA_LEN_MAX) {
> +               printf("QSPI: Invalid input arguments txlen %u\n", txlen);
>                 return -EINVAL;
>         }
>
> -       reg |= cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
> -
> -       if (cmdlen == 4 || cmdlen == 5) {
> -               /* Command with address */
> -               reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
> -               /* Number of bytes to write. */
> -               reg |= ((cmdlen - 2) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
> -                       << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
> -               /* Get address */
> -               addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1],
> -                       cmdlen >= 5 ? 4 : 3);
> -
> -               writel(addr_value, reg_base + CQSPI_REG_CMDADDRESS);
> -       }
> +       reg |= op->cmd.opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
>
>         if (txlen) {
>                 /* writing data = yes */
> @@ -530,61 +513,32 @@ int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen,
>
>  /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
>  int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
> -       unsigned int cmdlen, unsigned int rx_width, const u8 *cmdbuf)
> +       const struct spi_mem_op *op)
>  {
>         unsigned int reg;
>         unsigned int rd_reg;
> -       unsigned int addr_value;
>         unsigned int dummy_clk;
> -       unsigned int dummy_bytes;
> -       unsigned int addr_bytes;
> -
> -       /*
> -        * Identify addr_byte. All NOR flash device drivers are using fast read
> -        * which always expecting 1 dummy byte, 1 cmd byte and 3/4 addr byte.
> -        * With that, the length is in value of 5 or 6. Only FRAM chip from
> -        * ramtron using normal read (which won't need dummy byte).
> -        * Unlikely NOR flash using normal read due to performance issue.
> -        */
> -       if (cmdlen >= 5)
> -               /* to cater fast read where cmd + addr + dummy */
> -               addr_bytes = cmdlen - 2;
> -       else
> -               /* for normal read (only ramtron as of now) */
> -               addr_bytes = cmdlen - 1;
> +       unsigned int dummy_bytes = op->dummy.nbytes;
>
>         /* Setup the indirect trigger address */
>         writel(plat->trigger_address,
>                plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
>
>         /* Configure the opcode */
> -       rd_reg = cmdbuf[0] << CQSPI_REG_RD_INSTR_OPCODE_LSB;
> +       rd_reg = op->cmd.opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
>
> -       if (rx_width & SPI_RX_QUAD)
> +       if (op->data.buswidth == 4)
>                 /* Instruction and address at DQ0, data at DQ0-3. */
>                 rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
>
> -       /* Get address */
> -       addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes);
> -       writel(addr_value, plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
> +       writel(op->addr.val, plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
>
> -       /* The remaining lenght is dummy bytes. */
> -       dummy_bytes = cmdlen - addr_bytes - 1;
>         if (dummy_bytes) {
>                 if (dummy_bytes > CQSPI_DUMMY_BYTES_MAX)
>                         dummy_bytes = CQSPI_DUMMY_BYTES_MAX;
>
> -               rd_reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
> -#if defined(CONFIG_SPL_SPI_XIP) && defined(CONFIG_SPL_BUILD)
> -               writel(0x0, plat->regbase + CQSPI_REG_MODE_BIT);
> -#else
> -               writel(0xFF, plat->regbase + CQSPI_REG_MODE_BIT);
> -#endif
> -
>                 /* Convert to clock cycles. */
>                 dummy_clk = dummy_bytes * CQSPI_DUMMY_CLKS_PER_BYTE;
> -               /* Need to minus the mode byte (8 clocks). */
> -               dummy_clk -= CQSPI_DUMMY_CLKS_PER_BYTE;
>
>                 if (dummy_clk)
>                         rd_reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
> @@ -596,7 +550,7 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
>         /* set device size */
>         reg = readl(plat->regbase + CQSPI_REG_SIZE);
>         reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
> -       reg |= (addr_bytes - 1);
> +       reg |= (op->addr.nbytes - 1);
>         writel(reg, plat->regbase + CQSPI_REG_SIZE);
>         return 0;
>  }
> @@ -687,35 +641,23 @@ failrd:
>
>  /* Opcode + Address (3/4 bytes) */
>  int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> -       unsigned int cmdlen, unsigned int tx_width, const u8 *cmdbuf)
> +       const struct spi_mem_op *op)
>  {
>         unsigned int reg;
> -       unsigned int addr_bytes = cmdlen > 4 ? 4 : 3;
>
> -       if (cmdlen < 4 || cmdbuf == NULL) {
> -               printf("QSPI: Invalid input argument, len %d cmdbuf %p\n",
> -                      cmdlen, cmdbuf);
> -               return -EINVAL;
> -       }
>         /* Setup the indirect trigger address */
>         writel(plat->trigger_address,
>                plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
>
>         /* Configure the opcode */
> -       reg = cmdbuf[0] << CQSPI_REG_WR_INSTR_OPCODE_LSB;
> -
> -       if (tx_width & SPI_TX_QUAD)
> -               reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB;
> -
> +       reg = op->cmd.opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
>         writel(reg, plat->regbase + CQSPI_REG_WR_INSTR);
>
> -       /* Setup write address. */
> -       reg = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes);
> -       writel(reg, plat->regbase + CQSPI_REG_INDIRECTWRSTARTADDR);
> +       writel(op->addr.val, plat->regbase + CQSPI_REG_INDIRECTWRSTARTADDR);
>
>         reg = readl(plat->regbase + CQSPI_REG_SIZE);
>         reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
> -       reg |= (addr_bytes - 1);
> +       reg |= (op->addr.nbytes - 1);
>         writel(reg, plat->regbase + CQSPI_REG_SIZE);
>         return 0;
>  }
> --
> 2.24.0
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support
  2020-01-17 13:20       ` Simon Goldschmidt
@ 2020-01-17 15:52         ` Simon Goldschmidt
  2020-01-26 16:43           ` Jagan Teki
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Goldschmidt @ 2020-01-17 15:52 UTC (permalink / raw)
  To: u-boot

On Fri, Jan 17, 2020 at 2:20 PM Simon Goldschmidt
<simon.k.r.goldschmidt@gmail.com> wrote:
>
> On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigneshr@ti.com> wrote:
> >
> >
> >
> > On 17/01/20 6:21 pm, Simon Goldschmidt wrote:
> > > On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@ti.com> wrote:
> > >>
> > >> 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().
> > >
> > > This v2 doesn't compile for socfpa as dma_memcpy() isn't available. Since direct
> > > mode isn't used on that platform (due to your 8MB check), dma_memcpy() is not
> > > required, but still it doesn't link as this is a runtime decision.
> > >
> >
> > Could you try with latest master and make sure it has [1] and [2]
> > applied? Thanks!
> >
> > [1]http://patchwork.ozlabs.org/patch/1195557/
> > [2]http://patchwork.ozlabs.org/patch/1195556/
>
> Right, Tom merged that yesterday. Compiles now, sorry for the noise.

Tested on socfpga_gen5 (due to the platform layout, this test only says
it still works in indirect mode - direct mode is not activated on socfgpa):

Tested-by: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>

>
> Regards,
> Simon
>
> >
> > Regards
> > Vignesh
> >
> > > Regards,
> > > Simon
> > >
> > >>
> > >> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
> > >> ---
> > >> v2: Add DMA support and update commit message
> > >>
> > >>  drivers/spi/cadence_qspi.c     | 40 ++++++++++++---------
> > >>  drivers/spi/cadence_qspi.h     | 19 +++++-----
> > >>  drivers/spi/cadence_qspi_apb.c | 65 +++++++++++++++++++++++++++++-----
> > >>  3 files changed, 91 insertions(+), 33 deletions(-)
> > >>
> > >> diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
> > >> index 673a2e9a6c4c..6c98cbf39ae4 100644
> > >> --- a/drivers/spi/cadence_qspi.c
> > >> +++ b/drivers/spi/cadence_qspi.c
> > >> @@ -12,12 +12,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)
> > >>  {
> > >> @@ -189,6 +190,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 */
> > >> @@ -197,6 +199,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);
> > >>
> > >> @@ -221,12 +227,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) {
> > >> @@ -236,19 +242,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;
> > >> @@ -264,13 +266,17 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
> > >>         ofnode subnode;
> > >>
> > >>         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);
> > >> diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
> > >> index e655b027d788..619f0bed8efd 100644
> > >> --- a/drivers/spi/cadence_qspi.h
> > >> +++ b/drivers/spi/cadence_qspi.h
> > >> @@ -23,6 +23,8 @@ struct cadence_spi_platdata {
> > >>         u32             fifo_depth;
> > >>         u32             fifo_width;
> > >>         u32             trigger_address;
> > >> +       fdt_addr_t      ahbsize;
> > >> +       bool            use_dac_mode;
> > >>
> > >>         /* Flash parameters */
> > >>         u32             page_size;
> > >> @@ -52,20 +54,21 @@ struct cadence_spi_priv {
> > >>  void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat);
> > >>  void cadence_qspi_apb_controller_enable(void *reg_base_addr);
> > >>  void cadence_qspi_apb_controller_disable(void *reg_base_addr);
> > >> +void cadence_qspi_apb_dac_mode_enable(void *reg_base);
> > >>
> > >>  int cadence_qspi_apb_command_read(void *reg_base_addr,
> > >>                                   const struct spi_mem_op *op);
> > >>  int cadence_qspi_apb_command_write(void *reg_base_addr,
> > >>                                    const struct spi_mem_op *op);
> > >>
> > >> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
> > >> -       const struct spi_mem_op *op);
> > >> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> > >> -       unsigned int rxlen, u8 *rxbuf);
> > >> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> > >> -       const struct spi_mem_op *op);
> > >> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> > >> -       unsigned int txlen, const u8 *txbuf);
> > >> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
> > >> +                               const struct spi_mem_op *op);
> > >> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
> > >> +                                 const struct spi_mem_op *op);
> > >> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
> > >> +                                const struct spi_mem_op *op);
> > >> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
> > >> +                                  const struct spi_mem_op *op);
> > >>
> > >>  void cadence_qspi_apb_chipselect(void *reg_base,
> > >>         unsigned int chip_select, unsigned int decoder_enable);
> > >> diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
> > >> index 8dd0495dfcf4..a0e14f93e020 100644
> > >> --- a/drivers/spi/cadence_qspi_apb.c
> > >> +++ b/drivers/spi/cadence_qspi_apb.c
> > >> @@ -27,6 +27,7 @@
> > >>
> > >>  #include <common.h>
> > >>  #include <asm/io.h>
> > >> +#include <dma.h>
> > >>  #include <linux/errno.h>
> > >>  #include <wait_bit.h>
> > >>  #include <spi.h>
> > >> @@ -189,6 +190,15 @@ void cadence_qspi_apb_controller_disable(void *reg_base)
> > >>         writel(reg, reg_base + CQSPI_REG_CONFIG);
> > >>  }
> > >>
> > >> +void cadence_qspi_apb_dac_mode_enable(void *reg_base)
> > >> +{
> > >> +       unsigned int reg;
> > >> +
> > >> +       reg = readl(reg_base + CQSPI_REG_CONFIG);
> > >> +       reg |= CQSPI_REG_CONFIG_DIRECT;
> > >> +       writel(reg, reg_base + CQSPI_REG_CONFIG);
> > >> +}
> > >> +
> > >>  /* Return 1 if idle, otherwise return 0 (busy). */
> > >>  static unsigned int cadence_qspi_wait_idle(void *reg_base)
> > >>  {
> > >> @@ -512,8 +522,8 @@ int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op)
> > >>  }
> > >>
> > >>  /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
> > >> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
> > >> -       const struct spi_mem_op *op)
> > >> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
> > >> +                               const struct spi_mem_op *op)
> > >>  {
> > >>         unsigned int reg;
> > >>         unsigned int rd_reg;
> > >> @@ -577,8 +587,9 @@ static int cadence_qspi_wait_for_data(struct cadence_spi_platdata *plat)
> > >>         return -ETIMEDOUT;
> > >>  }
> > >>
> > >> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> > >> -       unsigned int n_rx, u8 *rxbuf)
> > >> +static int
> > >> +cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> > >> +                                      unsigned int n_rx, u8 *rxbuf)
> > >>  {
> > >>         unsigned int remaining = n_rx;
> > >>         unsigned int bytes_to_read = 0;
> > >> @@ -639,9 +650,29 @@ failrd:
> > >>         return ret;
> > >>  }
> > >>
> > >> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
> > >> +                                 const struct spi_mem_op *op)
> > >> +{
> > >> +       u32 from = op->addr.val;
> > >> +       void *buf = op->data.buf.in;
> > >> +       size_t len = op->data.nbytes;
> > >> +
> > >> +       if (plat->use_dac_mode && (from + len < plat->ahbsize)) {
> > >> +               if (len < 256 ||
> > >> +                   dma_memcpy(buf, plat->ahbbase + from, len) < 0) {
> > >> +                       memcpy_fromio(buf, plat->ahbbase + from, len);
> > >> +               }
> > >> +               if (!cadence_qspi_wait_idle(plat->regbase))
> > >> +                       return -EIO;
> > >> +               return 0;
> > >> +       }
> > >> +
> > >> +       return cadence_qspi_apb_indirect_read_execute(plat, len, buf);
> > >> +}
> > >> +
> > >>  /* Opcode + Address (3/4 bytes) */
> > >> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> > >> -       const struct spi_mem_op *op)
> > >> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
> > >> +                                const struct spi_mem_op *op)
> > >>  {
> > >>         unsigned int reg;
> > >>
> > >> @@ -662,8 +693,9 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> > >>         return 0;
> > >>  }
> > >>
> > >> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> > >> -       unsigned int n_tx, const u8 *txbuf)
> > >> +static int
> > >> +cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> > >> +                                       unsigned int n_tx, const u8 *txbuf)
> > >>  {
> > >>         unsigned int page_size = plat->page_size;
> > >>         unsigned int remaining = n_tx;
> > >> @@ -735,6 +767,23 @@ failwr:
> > >>         return ret;
> > >>  }
> > >>
> > >> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
> > >> +                                  const struct spi_mem_op *op)
> > >> +{
> > >> +       u32 to = op->addr.val;
> > >> +       const void *buf = op->data.buf.out;
> > >> +       size_t len = op->data.nbytes;
> > >> +
> > >> +       if (plat->use_dac_mode && (to + len < plat->ahbsize)) {
> > >> +               memcpy_toio(plat->ahbbase + to, buf, len);
> > >> +               if (!cadence_qspi_wait_idle(plat->regbase))
> > >> +                       return -EIO;
> > >> +               return 0;
> > >> +       }
> > >> +
> > >> +       return cadence_qspi_apb_indirect_write_execute(plat, len, buf);
> > >> +}
> > >> +
> > >>  void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
> > >>  {
> > >>         unsigned int reg;
> > >> --
> > >> 2.24.0
> > >>
> >
> > --
> > Regards
> > Vignesh

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs
  2019-11-19 10:13 [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs Vignesh Raghavendra
                   ` (3 preceding siblings ...)
  2020-01-14 15:02 ` Vignesh Raghavendra
@ 2020-01-20  4:39 ` Vignesh Raghavendra
  4 siblings, 0 replies; 15+ messages in thread
From: Vignesh Raghavendra @ 2020-01-20  4:39 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 19/11/19 3:43 pm, Vignesh Raghavendra wrote:
> First patch moves driver over to spi-mem framework and implement
> spi_mem_ops. This is require to support more SPI Flash opcodes like SFDP
> parsing etc. Series is in prepartion to add Octal mode for support for
> the same driver to support OSPI version of the controller.
> 
> Second patch adds DAC mode that provide memory mapped access to flash.
> This greatly increases the read throughput.
> 
> Tested with mt25qu512 flash and s25fl512 flash
> 

Could you please merge this series?


> Note: Depends on [1][2] that adds stubs for dma_memcpy() to be used on
> platforms without CONFIG_DMA enabled.
> 
> [1]http://patchwork.ozlabs.org/patch/1195557/
> [2]http://patchwork.ozlabs.org/patch/1195556/
> 
> 
> Vignesh Raghavendra (2):
>   spi: cadence_qspi: Move to spi-mem framework
>   spi: cadence-qspi: Add direct mode support
> 
>  drivers/spi/cadence_qspi.c     | 148 +++++++++++---------------
>  drivers/spi/cadence_qspi.h     |  24 +++--
>  drivers/spi/cadence_qspi_apb.c | 185 ++++++++++++++++-----------------
>  3 files changed, 164 insertions(+), 193 deletions(-)
> 

-- 
Regards
Vignesh

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support
  2020-01-17 15:52         ` Simon Goldschmidt
@ 2020-01-26 16:43           ` Jagan Teki
  2020-01-27  5:12             ` Vignesh Raghavendra
  0 siblings, 1 reply; 15+ messages in thread
From: Jagan Teki @ 2020-01-26 16:43 UTC (permalink / raw)
  To: u-boot

On Fri, Jan 17, 2020 at 9:23 PM Simon Goldschmidt
<simon.k.r.goldschmidt@gmail.com> wrote:
>
> On Fri, Jan 17, 2020 at 2:20 PM Simon Goldschmidt
> <simon.k.r.goldschmidt@gmail.com> wrote:
> >
> > On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigneshr@ti.com> wrote:
> > >
> > >
> > >
> > > On 17/01/20 6:21 pm, Simon Goldschmidt wrote:
> > > > On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@ti.com> wrote:
> > > >>
> > > >> 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().
> > > >
> > > > This v2 doesn't compile for socfpa as dma_memcpy() isn't available. Since direct
> > > > mode isn't used on that platform (due to your 8MB check), dma_memcpy() is not
> > > > required, but still it doesn't link as this is a runtime decision.
> > > >
> > >
> > > Could you try with latest master and make sure it has [1] and [2]
> > > applied? Thanks!
> > >
> > > [1]http://patchwork.ozlabs.org/patch/1195557/
> > > [2]http://patchwork.ozlabs.org/patch/1195556/
> >
> > Right, Tom merged that yesterday. Compiles now, sorry for the noise.
>
> Tested on socfpga_gen5 (due to the platform layout, this test only says
> it still works in indirect mode - direct mode is not activated on socfgpa):
>
> Tested-by: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
>
> >
> > Regards,
> > Simon
> >
> > >
> > > Regards
> > > Vignesh
> > >
> > > > Regards,
> > > > Simon
> > > >
> > > >>
> > > >> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
> > > >> ---
> > > >> v2: Add DMA support and update commit message
> > > >>
> > > >>  drivers/spi/cadence_qspi.c     | 40 ++++++++++++---------
> > > >>  drivers/spi/cadence_qspi.h     | 19 +++++-----
> > > >>  drivers/spi/cadence_qspi_apb.c | 65 +++++++++++++++++++++++++++++-----
> > > >>  3 files changed, 91 insertions(+), 33 deletions(-)
> > > >>
> > > >> diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
> > > >> index 673a2e9a6c4c..6c98cbf39ae4 100644
> > > >> --- a/drivers/spi/cadence_qspi.c
> > > >> +++ b/drivers/spi/cadence_qspi.c
> > > >> @@ -12,12 +12,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)
> > > >>  {
> > > >> @@ -189,6 +190,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 */
> > > >> @@ -197,6 +199,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);
> > > >>
> > > >> @@ -221,12 +227,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) {
> > > >> @@ -236,19 +242,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;
> > > >> @@ -264,13 +266,17 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
> > > >>         ofnode subnode;
> > > >>
> > > >>         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);
> > > >> diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
> > > >> index e655b027d788..619f0bed8efd 100644
> > > >> --- a/drivers/spi/cadence_qspi.h
> > > >> +++ b/drivers/spi/cadence_qspi.h
> > > >> @@ -23,6 +23,8 @@ struct cadence_spi_platdata {
> > > >>         u32             fifo_depth;
> > > >>         u32             fifo_width;
> > > >>         u32             trigger_address;
> > > >> +       fdt_addr_t      ahbsize;
> > > >> +       bool            use_dac_mode;
> > > >>
> > > >>         /* Flash parameters */
> > > >>         u32             page_size;
> > > >> @@ -52,20 +54,21 @@ struct cadence_spi_priv {
> > > >>  void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat);
> > > >>  void cadence_qspi_apb_controller_enable(void *reg_base_addr);
> > > >>  void cadence_qspi_apb_controller_disable(void *reg_base_addr);
> > > >> +void cadence_qspi_apb_dac_mode_enable(void *reg_base);
> > > >>
> > > >>  int cadence_qspi_apb_command_read(void *reg_base_addr,
> > > >>                                   const struct spi_mem_op *op);
> > > >>  int cadence_qspi_apb_command_write(void *reg_base_addr,
> > > >>                                    const struct spi_mem_op *op);
> > > >>
> > > >> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
> > > >> -       const struct spi_mem_op *op);
> > > >> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> > > >> -       unsigned int rxlen, u8 *rxbuf);
> > > >> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> > > >> -       const struct spi_mem_op *op);
> > > >> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> > > >> -       unsigned int txlen, const u8 *txbuf);
> > > >> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
> > > >> +                               const struct spi_mem_op *op);
> > > >> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
> > > >> +                                 const struct spi_mem_op *op);
> > > >> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
> > > >> +                                const struct spi_mem_op *op);
> > > >> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
> > > >> +                                  const struct spi_mem_op *op);
> > > >>
> > > >>  void cadence_qspi_apb_chipselect(void *reg_base,
> > > >>         unsigned int chip_select, unsigned int decoder_enable);
> > > >> diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
> > > >> index 8dd0495dfcf4..a0e14f93e020 100644
> > > >> --- a/drivers/spi/cadence_qspi_apb.c
> > > >> +++ b/drivers/spi/cadence_qspi_apb.c
> > > >> @@ -27,6 +27,7 @@
> > > >>
> > > >>  #include <common.h>
> > > >>  #include <asm/io.h>
> > > >> +#include <dma.h>
> > > >>  #include <linux/errno.h>
> > > >>  #include <wait_bit.h>
> > > >>  #include <spi.h>
> > > >> @@ -189,6 +190,15 @@ void cadence_qspi_apb_controller_disable(void *reg_base)
> > > >>         writel(reg, reg_base + CQSPI_REG_CONFIG);
> > > >>  }
> > > >>
> > > >> +void cadence_qspi_apb_dac_mode_enable(void *reg_base)
> > > >> +{
> > > >> +       unsigned int reg;
> > > >> +
> > > >> +       reg = readl(reg_base + CQSPI_REG_CONFIG);
> > > >> +       reg |= CQSPI_REG_CONFIG_DIRECT;
> > > >> +       writel(reg, reg_base + CQSPI_REG_CONFIG);
> > > >> +}
> > > >> +
> > > >>  /* Return 1 if idle, otherwise return 0 (busy). */
> > > >>  static unsigned int cadence_qspi_wait_idle(void *reg_base)
> > > >>  {
> > > >> @@ -512,8 +522,8 @@ int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op)
> > > >>  }
> > > >>
> > > >>  /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
> > > >> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
> > > >> -       const struct spi_mem_op *op)
> > > >> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
> > > >> +                               const struct spi_mem_op *op)
> > > >>  {
> > > >>         unsigned int reg;
> > > >>         unsigned int rd_reg;
> > > >> @@ -577,8 +587,9 @@ static int cadence_qspi_wait_for_data(struct cadence_spi_platdata *plat)
> > > >>         return -ETIMEDOUT;
> > > >>  }
> > > >>
> > > >> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> > > >> -       unsigned int n_rx, u8 *rxbuf)
> > > >> +static int
> > > >> +cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
> > > >> +                                      unsigned int n_rx, u8 *rxbuf)
> > > >>  {
> > > >>         unsigned int remaining = n_rx;
> > > >>         unsigned int bytes_to_read = 0;
> > > >> @@ -639,9 +650,29 @@ failrd:
> > > >>         return ret;
> > > >>  }
> > > >>
> > > >> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat,
> > > >> +                                 const struct spi_mem_op *op)
> > > >> +{
> > > >> +       u32 from = op->addr.val;
> > > >> +       void *buf = op->data.buf.in;
> > > >> +       size_t len = op->data.nbytes;
> > > >> +
> > > >> +       if (plat->use_dac_mode && (from + len < plat->ahbsize)) {
> > > >> +               if (len < 256 ||
> > > >> +                   dma_memcpy(buf, plat->ahbbase + from, len) < 0) {
> > > >> +                       memcpy_fromio(buf, plat->ahbbase + from, len);
> > > >> +               }
> > > >> +               if (!cadence_qspi_wait_idle(plat->regbase))
> > > >> +                       return -EIO;
> > > >> +               return 0;
> > > >> +       }
> > > >> +
> > > >> +       return cadence_qspi_apb_indirect_read_execute(plat, len, buf);
> > > >> +}
> > > >> +
> > > >>  /* Opcode + Address (3/4 bytes) */
> > > >> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> > > >> -       const struct spi_mem_op *op)
> > > >> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
> > > >> +                                const struct spi_mem_op *op)
> > > >>  {
> > > >>         unsigned int reg;
> > > >>
> > > >> @@ -662,8 +693,9 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
> > > >>         return 0;
> > > >>  }
> > > >>
> > > >> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> > > >> -       unsigned int n_tx, const u8 *txbuf)
> > > >> +static int
> > > >> +cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
> > > >> +                                       unsigned int n_tx, const u8 *txbuf)
> > > >>  {
> > > >>         unsigned int page_size = plat->page_size;
> > > >>         unsigned int remaining = n_tx;
> > > >> @@ -735,6 +767,23 @@ failwr:
> > > >>         return ret;
> > > >>  }
> > > >>
> > > >> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
> > > >> +                                  const struct spi_mem_op *op)
> > > >> +{
> > > >> +       u32 to = op->addr.val;
> > > >> +       const void *buf = op->data.buf.out;
> > > >> +       size_t len = op->data.nbytes;
> > > >> +
> > > >> +       if (plat->use_dac_mode && (to + len < plat->ahbsize)) {
> > > >> +               memcpy_toio(plat->ahbbase + to, buf, len);
> > > >> +               if (!cadence_qspi_wait_idle(plat->regbase))
> > > >> +                       return -EIO;
> > > >> +               return 0;
> > > >> +       }
> > > >> +
> > > >> +       return cadence_qspi_apb_indirect_write_execute(plat, len, buf);
> > > >> +}
> > > >> +
> > > >>  void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
> > > >>  {
> > > >>         unsigned int reg;
> > > >> --
> > > >> 2.24.0
> > > >>
> > >

Not apply directly, look like rebase require on top of master?

Jagan.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support
  2020-01-26 16:43           ` Jagan Teki
@ 2020-01-27  5:12             ` Vignesh Raghavendra
  2020-01-27  7:13               ` Jagan Teki
  0 siblings, 1 reply; 15+ messages in thread
From: Vignesh Raghavendra @ 2020-01-27  5:12 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 26/01/20 10:13 pm, Jagan Teki wrote:
> On Fri, Jan 17, 2020 at 9:23 PM Simon Goldschmidt
> <simon.k.r.goldschmidt@gmail.com> wrote:
>>
>> On Fri, Jan 17, 2020 at 2:20 PM Simon Goldschmidt
>> <simon.k.r.goldschmidt@gmail.com> wrote:
>>>
>>> On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigneshr@ti.com> wrote:
[...]

>>>>>>  void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
>>>>>>  {
>>>>>>         unsigned int reg;
>>>>>> --
>>>>>> 2.24.0
>>>>>>
>>>>
> 
> Not apply directly, look like rebase require on top of master?
> 

I have resent the series rebasing on top of latest master:
http://patchwork.ozlabs.org/project/uboot/list/?series=155385




-- 
Regards
Vignesh

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support
  2020-01-27  5:12             ` Vignesh Raghavendra
@ 2020-01-27  7:13               ` Jagan Teki
  0 siblings, 0 replies; 15+ messages in thread
From: Jagan Teki @ 2020-01-27  7:13 UTC (permalink / raw)
  To: u-boot

On Mon, Jan 27, 2020 at 10:42 AM Vignesh Raghavendra <vigneshr@ti.com> wrote:
>
> Hi Jagan,
>
> On 26/01/20 10:13 pm, Jagan Teki wrote:
> > On Fri, Jan 17, 2020 at 9:23 PM Simon Goldschmidt
> > <simon.k.r.goldschmidt@gmail.com> wrote:
> >>
> >> On Fri, Jan 17, 2020 at 2:20 PM Simon Goldschmidt
> >> <simon.k.r.goldschmidt@gmail.com> wrote:
> >>>
> >>> On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigneshr@ti.com> wrote:
> [...]
>
> >>>>>>  void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
> >>>>>>  {
> >>>>>>         unsigned int reg;
> >>>>>> --
> >>>>>> 2.24.0
> >>>>>>
> >>>>
> >
> > Not apply directly, look like rebase require on top of master?
> >
>
> I have resent the series rebasing on top of latest master:
> http://patchwork.ozlabs.org/project/uboot/list/?series=155385

Thanks.

Applied to u-boot-spi/master

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2020-01-27  7:13 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-19 10:13 [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs Vignesh Raghavendra
2019-11-19 10:13 ` [U-Boot] [PATCH v2 1/2] spi: cadence_qspi: Move to spi-mem framework Vignesh Raghavendra
2020-01-17 15:51   ` Simon Goldschmidt
2019-11-19 10:13 ` [U-Boot] [PATCH v2 2/2] spi: cadence-qspi: Add direct mode support Vignesh Raghavendra
2020-01-17 12:51   ` Simon Goldschmidt
2020-01-17 13:02     ` Vignesh Raghavendra
2020-01-17 13:20       ` Simon Goldschmidt
2020-01-17 15:52         ` Simon Goldschmidt
2020-01-26 16:43           ` Jagan Teki
2020-01-27  5:12             ` Vignesh Raghavendra
2020-01-27  7:13               ` Jagan Teki
2019-11-19 20:37 ` [U-Boot] [PATCH v2 0/2] spi: cadence-qspi: Move to spi-mem APIs Simon Goldschmidt
2020-01-14 15:02 ` Vignesh Raghavendra
2020-01-14 16:06   ` Simon Goldschmidt
2020-01-20  4:39 ` Vignesh Raghavendra

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.