diff mbox series

[U-Boot,v5,2/4] spi: xilinx_spi: Modify transfer logic xilinx_spi_xfer() function

Message ID 1530326720-8648-3-git-send-email-vipul.kumar@xilinx.com
State Accepted
Delegated to: Jagannadha Sutradharudu Teki
Headers show
Series spi:xilinx_spi: Modify xilinx spi driver | expand

Commit Message

Vipul Kumar June 30, 2018, 2:45 a.m. UTC
This patch modify xilinx_spi_xfer() function and add rxfifo() and
txfifo() functions to add the modularity so that these functions
can be used by other functions within the same file.

This patch also added support to read fifo_size from dts.

Signed-off-by: Vipul Kumar <vipul.kumar@xilinx.com>
Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
---
Changes in v5:
- No change
---
 drivers/spi/xilinx_spi.c | 103 +++++++++++++++++++++++++++++++----------------
 1 file changed, 68 insertions(+), 35 deletions(-)
diff mbox series

Patch

diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index cc5ac51..11b7343 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -19,6 +19,7 @@ 
 #include <malloc.h>
 #include <spi.h>
 #include <asm/io.h>
+#include <wait_bit.h>
 
 /*
  * [0]: http://www.xilinx.com/support/documentation
@@ -77,6 +78,8 @@ 
 #define CONFIG_XILINX_SPI_IDLE_VAL	GENMASK(7, 0)
 #endif
 
+#define XILINX_SPISR_TIMEOUT	10000 /* in milliseconds */
+
 /* xilinx spi register set */
 struct xilinx_spi_regs {
 	u32 __space0__[7];
@@ -101,6 +104,7 @@  struct xilinx_spi_priv {
 	struct xilinx_spi_regs *regs;
 	unsigned int freq;
 	unsigned int mode;
+	unsigned int fifo_depth;
 };
 
 static int xilinx_spi_probe(struct udevice *bus)
@@ -110,6 +114,9 @@  static int xilinx_spi_probe(struct udevice *bus)
 
 	priv->regs = (struct xilinx_spi_regs *)devfdt_get_addr(bus);
 
+	priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
+					  "fifo-size", 0);
+
 	writel(SPISSR_RESET_VALUE, &regs->srr);
 
 	return 0;
@@ -157,6 +164,47 @@  static int xilinx_spi_release_bus(struct udevice *dev)
 	return 0;
 }
 
+static u32 xilinx_spi_fill_txfifo(struct udevice *bus, const u8 *txp,
+				  u32 txbytes)
+{
+	struct xilinx_spi_priv *priv = dev_get_priv(bus);
+	struct xilinx_spi_regs *regs = priv->regs;
+	unsigned char d;
+	u32 i = 0;
+
+	while (txbytes && !(readl(&regs->spisr) & SPISR_TX_FULL) &&
+	       i < priv->fifo_depth) {
+		d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL;
+		debug("spi_xfer: tx:%x ", d);
+		/* write out and wait for processing (receive data) */
+		writel(d & SPIDTR_8BIT_MASK, &regs->spidtr);
+		txbytes--;
+		i++;
+	}
+
+	return i;
+}
+
+static u32 xilinx_spi_read_rxfifo(struct udevice *bus, u8 *rxp, u32 rxbytes)
+{
+	struct xilinx_spi_priv *priv = dev_get_priv(bus);
+	struct xilinx_spi_regs *regs = priv->regs;
+	unsigned char d;
+	unsigned int i = 0;
+
+	while (rxbytes && !(readl(&regs->spisr) & SPISR_RX_EMPTY)) {
+		d = readl(&regs->spidrr) & SPIDRR_8BIT_MASK;
+		if (rxp)
+			*rxp++ = d;
+		debug("spi_xfer: rx:%x\n", d);
+		rxbytes--;
+		i++;
+	}
+	debug("Rx_done\n");
+
+	return i;
+}
+
 static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
 			    const void *dout, void *din, unsigned long flags)
 {
@@ -168,8 +216,10 @@  static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
 	unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS;
 	const unsigned char *txp = dout;
 	unsigned char *rxp = din;
-	unsigned rxecount = 17;	/* max. 16 elements in FIFO, leftover 1 */
-	unsigned global_timeout;
+	u32 txbytes = bytes;
+	u32 rxbytes = bytes;
+	u32 reg, count, timeout;
+	int ret;
 
 	debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n",
 	      bus->seq, slave_plat->cs, bitlen, bytes, flags);
@@ -184,48 +234,31 @@  static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
 		goto done;
 	}
 
-	/* empty read buffer */
-	while (rxecount && !(readl(&regs->spisr) & SPISR_RX_EMPTY)) {
-		readl(&regs->spidrr);
-		rxecount--;
-	}
-
-	if (!rxecount) {
-		printf("XILSPI error: Rx buffer not empty\n");
-		return -1;
-	}
-
 	if (flags & SPI_XFER_BEGIN)
 		spi_cs_activate(dev, slave_plat->cs);
 
-	/* at least 1usec or greater, leftover 1 */
-	global_timeout = priv->freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 :
-			(XILSPI_MAX_XFER_BITS * 1000000 / priv->freq) + 1;
 
-	while (bytes--) {
-		unsigned timeout = global_timeout;
-		/* get Tx element from data out buffer and count up */
-		unsigned char d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL;
-		debug("spi_xfer: tx:%x ", d);
+	while (txbytes && rxbytes) {
+		count = xilinx_spi_fill_txfifo(bus, txp, txbytes);
+		reg = readl(&regs->spicr) & ~SPICR_MASTER_INHIBIT;
+		writel(reg, &regs->spicr);
+		txbytes -= count;
+		if (txp)
+			txp += count;
 
-		/* write out and wait for processing (receive data) */
-		writel(d & SPIDTR_8BIT_MASK, &regs->spidtr);
-		while (timeout && readl(&regs->spisr)
-						& SPISR_RX_EMPTY) {
-			timeout--;
-			udelay(1);
-		}
-
-		if (!timeout) {
+		ret = wait_for_bit_le32(&regs->spisr, SPISR_TX_EMPTY, true,
+					XILINX_SPISR_TIMEOUT, false);
+		if (ret < 0) {
 			printf("XILSPI error: Xfer timeout\n");
-			return -1;
+			return ret;
 		}
 
-		/* read Rx element and push into data in buffer */
-		d = readl(&regs->spidrr) & SPIDRR_8BIT_MASK;
+		debug("txbytes:0x%x,txp:0x%p\n", txbytes, txp);
+		count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes);
+		rxbytes -= count;
 		if (rxp)
-			*rxp++ = d;
-		debug("spi_xfer: rx:%x\n", d);
+			rxp += count;
+		debug("rxbytes:0x%x rxp:0x%p\n", rxbytes, rxp);
 	}
 
  done: