linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers
@ 2017-06-14  5:52 Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 01/18] spi: qup: Enable chip select support Varadarajan Narayanan
                   ` (16 more replies)
  0 siblings, 17 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA
  Cc: Varadarajan Narayanan

v1:
	This series fixes some existing issues in the code for both
	interrupt and dma mode. Patches 1 - 11 are the fixes.
	Random failures/timeout are observed without these fixes.
	Also, the current driver does not support block transfers > 64K
	and the driver quietly fails. Patches 12 - 18 add support for this
	in both interrupt and dma mode.

	The entire series has been tested on ipq4019 with
	SPI-NOR flash for block sizes > 64k.

Varadarajan Narayanan (18):
  spi: qup: Enable chip select support
  spi: qup: Setup DMA mode correctly
  spi: qup: Add completion timeout for dma mode
  spi: qup: Add completion timeout for fifo/block mode
  spi: qup: Place the QUP in run mode before DMA transactions
  spi: qup: Fix error handling in spi_qup_prep_sg
  spi: qup: Fix transaction done signaling
  spi: qup: Handle v1 dma completion differently
  spi: qup: Do block sized read/write in block mode
  spi: qup: Fix DMA mode interrupt handling
  spi: qup: properly detect extra interrupts
  spi: qup: refactor spi_qup_io_config into two functions
  spi: qup: call io_config in mode specific function
  spi: qup: allow block mode to generate multiple transactions
  spi: qup: refactor spi_qup_prep_sg
  spi: qup: allow multiple DMA transactions per spi xfer
  spi: qup: Ensure done detection
  spi: qup: support for qup v1 dma

 .../devicetree/bindings/spi/qcom,spi-qup.txt       |   6 +
 drivers/spi/spi-qup.c                              | 639 +++++++++++++++------
 2 files changed, 462 insertions(+), 183 deletions(-)

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 01/18] spi: qup: Enable chip select support
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  9:47   ` Stanimir Varbanov
  2017-08-08 11:18   ` Applied "spi: qup: Enable chip select support" to the spi tree Mark Brown
       [not found] ` <1497419551-21834-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
                   ` (15 subsequent siblings)
  16 siblings, 2 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan, Sham Muthayyan

Enable chip select support for QUP versions later than v1

Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 1bfa889..c0d4def 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -750,6 +750,24 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
 	return ret;
 }
 
+static void spi_qup_set_cs(struct spi_device *spi, bool val)
+{
+	struct spi_qup *controller;
+	u32 spi_ioc;
+	u32 spi_ioc_orig;
+
+	controller = spi_master_get_devdata(spi->master);
+	spi_ioc = readl_relaxed(controller->base + SPI_IO_CONTROL);
+	spi_ioc_orig = spi_ioc;
+	if (!val)
+		spi_ioc |= SPI_IO_C_FORCE_CS;
+	else
+		spi_ioc &= ~SPI_IO_C_FORCE_CS;
+
+	if (spi_ioc != spi_ioc_orig)
+		writel_relaxed(spi_ioc, controller->base + SPI_IO_CONTROL);
+}
+
 static int spi_qup_probe(struct platform_device *pdev)
 {
 	struct spi_master *master;
@@ -846,6 +864,9 @@ static int spi_qup_probe(struct platform_device *pdev)
 	if (of_device_is_compatible(dev->of_node, "qcom,spi-qup-v1.1.1"))
 		controller->qup_v1 = 1;
 
+	if (!controller->qup_v1)
+		master->set_cs = spi_qup_set_cs;
+
 	spin_lock_init(&controller->lock);
 	init_completion(&controller->done);
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 02/18] spi: qup: Setup DMA mode correctly
       [not found] ` <1497419551-21834-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2017-06-14  5:52   ` Varadarajan Narayanan
  2017-08-08 11:18     ` Applied "spi: qup: Setup DMA mode correctly" to the spi tree Mark Brown
  2017-06-14  5:52   ` [PATCH 06/18] spi: qup: Fix error handling in spi_qup_prep_sg Varadarajan Narayanan
  1 sibling, 1 reply; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA
  Cc: Varadarajan Narayanan

To operate in DMA mode, the buffer should be aligned and
the size of the transfer should be a multiple of block size
(for v1). And the no. of words being transferred should
be programmed in the count registers appropriately.

Signed-off-by: Andy Gross <andy.gross-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
 drivers/spi/spi-qup.c | 118 +++++++++++++++++++++++---------------------------
 1 file changed, 55 insertions(+), 63 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index c0d4def..abe799b 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -149,11 +149,18 @@ struct spi_qup {
 	int			rx_bytes;
 	int			qup_v1;
 
-	int			use_dma;
+	int			mode;
 	struct dma_slave_config	rx_conf;
 	struct dma_slave_config	tx_conf;
 };
 
+static inline bool spi_qup_is_dma_xfer(int mode)
+{
+	if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM)
+		return true;
+
+	return false;
+}
 
 static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
 {
@@ -424,7 +431,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 		error = -EIO;
 	}
 
-	if (!controller->use_dma) {
+	if (!spi_qup_is_dma_xfer(controller->mode)) {
 		if (opflags & QUP_OP_IN_SERVICE_FLAG)
 			spi_qup_fifo_read(controller, xfer);
 
@@ -443,34 +450,11 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static u32
-spi_qup_get_mode(struct spi_master *master, struct spi_transfer *xfer)
-{
-	struct spi_qup *qup = spi_master_get_devdata(master);
-	u32 mode;
-
-	qup->w_size = 4;
-
-	if (xfer->bits_per_word <= 8)
-		qup->w_size = 1;
-	else if (xfer->bits_per_word <= 16)
-		qup->w_size = 2;
-
-	qup->n_words = xfer->len / qup->w_size;
-
-	if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
-		mode = QUP_IO_M_MODE_FIFO;
-	else
-		mode = QUP_IO_M_MODE_BLOCK;
-
-	return mode;
-}
-
 /* set clock freq ... bits per word */
 static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 {
 	struct spi_qup *controller = spi_master_get_devdata(spi->master);
-	u32 config, iomode, mode, control;
+	u32 config, iomode, control;
 	int ret, n_words;
 
 	if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
@@ -491,25 +475,30 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 		return -EIO;
 	}
 
-	mode = spi_qup_get_mode(spi->master, xfer);
+	controller->w_size = DIV_ROUND_UP(xfer->bits_per_word, 8);
+	controller->n_words = xfer->len / controller->w_size;
 	n_words = controller->n_words;
 
-	if (mode == QUP_IO_M_MODE_FIFO) {
+	if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
+
+		controller->mode = QUP_IO_M_MODE_FIFO;
+
 		writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
 		writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
 		/* must be zero for FIFO */
 		writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
 		writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
-	} else if (!controller->use_dma) {
+	} else if (spi->master->can_dma &&
+		   spi->master->can_dma(spi->master, spi, xfer) &&
+		   spi->master->cur_msg_mapped) {
+
+		controller->mode = QUP_IO_M_MODE_BAM;
+
 		writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
 		writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
 		/* must be zero for BLOCK and BAM */
 		writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
 		writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
-	} else {
-		mode = QUP_IO_M_MODE_BAM;
-		writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
-		writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
 
 		if (!controller->qup_v1) {
 			void __iomem *input_cnt;
@@ -528,19 +517,28 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 
 			writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
 		}
+	} else {
+
+		controller->mode = QUP_IO_M_MODE_BLOCK;
+
+		writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
+		writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+		/* must be zero for BLOCK and BAM */
+		writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+		writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
 	}
 
 	iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
 	/* Set input and output transfer mode */
 	iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
 
-	if (!controller->use_dma)
+	if (!spi_qup_is_dma_xfer(controller->mode))
 		iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
 	else
 		iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
 
-	iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
-	iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+	iomode |= (controller->mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+	iomode |= (controller->mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
 
 	writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
 
@@ -581,7 +579,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 	config |= xfer->bits_per_word - 1;
 	config |= QUP_CONFIG_SPI_MODE;
 
-	if (controller->use_dma) {
+	if (spi_qup_is_dma_xfer(controller->mode)) {
 		if (!xfer->tx_buf)
 			config |= QUP_CONFIG_NO_OUTPUT;
 		if (!xfer->rx_buf)
@@ -599,7 +597,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 		 * status change in BAM mode
 		 */
 
-		if (mode == QUP_IO_M_MODE_BAM)
+		if (spi_qup_is_dma_xfer(controller->mode))
 			mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG;
 
 		writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK);
@@ -633,7 +631,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	controller->tx_bytes = 0;
 	spin_unlock_irqrestore(&controller->lock, flags);
 
-	if (controller->use_dma)
+	if (spi_qup_is_dma_xfer(controller->mode))
 		ret = spi_qup_do_dma(master, xfer);
 	else
 		ret = spi_qup_do_pio(master, xfer);
@@ -641,14 +639,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	if (ret)
 		goto exit;
 
-	if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
-		dev_warn(controller->dev, "cannot set EXECUTE state\n");
-		goto exit;
-	}
-
-	if (!wait_for_completion_timeout(&controller->done, timeout))
-		ret = -ETIMEDOUT;
-
 exit:
 	spi_qup_set_state(controller, QUP_STATE_RESET);
 	spin_lock_irqsave(&controller->lock, flags);
@@ -657,7 +647,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
 		ret = controller->error;
 	spin_unlock_irqrestore(&controller->lock, flags);
 
-	if (ret && controller->use_dma)
+	if (ret && spi_qup_is_dma_xfer(controller->mode))
 		spi_qup_dma_terminate(master, xfer);
 
 	return ret;
@@ -668,26 +658,28 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
 {
 	struct spi_qup *qup = spi_master_get_devdata(master);
 	size_t dma_align = dma_get_cache_alignment();
-	u32 mode;
-
-	qup->use_dma = 0;
+	int n_words;
 
-	if (xfer->rx_buf && (xfer->len % qup->in_blk_sz ||
-	    IS_ERR_OR_NULL(master->dma_rx) ||
-	    !IS_ALIGNED((size_t)xfer->rx_buf, dma_align)))
-		return false;
+	if (xfer->rx_buf) {
+		if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) ||
+		    IS_ERR_OR_NULL(master->dma_rx))
+			return false;
+		if (qup->qup_v1 && (xfer->len % qup->in_blk_sz))
+			return false;
+	}
 
-	if (xfer->tx_buf && (xfer->len % qup->out_blk_sz ||
-	    IS_ERR_OR_NULL(master->dma_tx) ||
-	    !IS_ALIGNED((size_t)xfer->tx_buf, dma_align)))
-		return false;
+	if (xfer->tx_buf) {
+		if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) ||
+		    IS_ERR_OR_NULL(master->dma_tx))
+			return false;
+		if (qup->qup_v1 && (xfer->len % qup->out_blk_sz))
+			return false;
+	}
 
-	mode = spi_qup_get_mode(master, xfer);
-	if (mode == QUP_IO_M_MODE_FIFO)
+	n_words = xfer->len / DIV_ROUND_UP(xfer->bits_per_word, 8);
+	if (n_words <= (qup->in_fifo_sz / sizeof(u32)))
 		return false;
 
-	qup->use_dma = 1;
-
 	return true;
 }
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 03/18] spi: qup: Add completion timeout for dma mode
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 01/18] spi: qup: Enable chip select support Varadarajan Narayanan
       [not found] ` <1497419551-21834-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 04/18] spi: qup: Add completion timeout for fifo/block mode Varadarajan Narayanan
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan

Use different 'completion' structures to track the completion
of DMA Tx/Rx and PIO.

Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 41 ++++++++++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 17 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index abe799b..272e48e 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -142,6 +142,8 @@ struct spi_qup {
 
 	struct spi_transfer	*xfer;
 	struct completion	done;
+	struct completion	txc;
+	struct completion	rxc;
 	int			error;
 	int			w_size;	/* bytes per SPI word */
 	int			n_words;
@@ -283,16 +285,13 @@ static void spi_qup_fifo_write(struct spi_qup *controller,
 
 static void spi_qup_dma_done(void *data)
 {
-	struct spi_qup *qup = data;
-
-	complete(&qup->done);
+	complete(data);
 }
 
 static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
 			   enum dma_transfer_direction dir,
-			   dma_async_tx_callback callback)
+			   dma_async_tx_callback callback, void *data)
 {
-	struct spi_qup *qup = spi_master_get_devdata(master);
 	unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
 	struct dma_async_tx_descriptor *desc;
 	struct scatterlist *sgl;
@@ -315,7 +314,7 @@ static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
 		return -EINVAL;
 
 	desc->callback = callback;
-	desc->callback_param = qup;
+	desc->callback_param = data;
 
 	cookie = dmaengine_submit(desc);
 
@@ -333,16 +332,12 @@ static void spi_qup_dma_terminate(struct spi_master *master,
 
 static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
 {
-	dma_async_tx_callback rx_done = NULL, tx_done = NULL;
+	struct spi_qup *qup = spi_master_get_devdata(master);
 	int ret;
 
-	if (xfer->rx_buf)
-		rx_done = spi_qup_dma_done;
-	else if (xfer->tx_buf)
-		tx_done = spi_qup_dma_done;
-
 	if (xfer->rx_buf) {
-		ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done);
+		ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM,
+					spi_qup_dma_done, &qup->rxc);
 		if (ret)
 			return ret;
 
@@ -350,13 +345,20 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
 	}
 
 	if (xfer->tx_buf) {
-		ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
+		ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV,
+					spi_qup_dma_done, &qup->txc);
 		if (ret)
 			return ret;
 
 		dma_async_issue_pending(master->dma_tx);
 	}
 
+	if (xfer->rx_buf && !wait_for_completion_timeout(&qup->rxc, timeout))
+		return -ETIMEDOUT;
+
+	if (xfer->tx_buf && !wait_for_completion_timeout(&qup->txc, timeout))
+		return -ETIMEDOUT;
+
 	return 0;
 }
 
@@ -622,7 +624,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
 	timeout = 100 * msecs_to_jiffies(timeout);
 
-	reinit_completion(&controller->done);
 
 	spin_lock_irqsave(&controller->lock, flags);
 	controller->xfer     = xfer;
@@ -631,10 +632,14 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	controller->tx_bytes = 0;
 	spin_unlock_irqrestore(&controller->lock, flags);
 
-	if (spi_qup_is_dma_xfer(controller->mode))
+	if (spi_qup_is_dma_xfer(controller->mode)) {
+		reinit_completion(&controller->rxc);
+		reinit_completion(&controller->txc);
 		ret = spi_qup_do_dma(master, xfer);
-	else
+	} else {
+		reinit_completion(&controller->done);
 		ret = spi_qup_do_pio(master, xfer);
+	}
 
 	if (ret)
 		goto exit;
@@ -860,6 +865,8 @@ static int spi_qup_probe(struct platform_device *pdev)
 		master->set_cs = spi_qup_set_cs;
 
 	spin_lock_init(&controller->lock);
+	init_completion(&controller->rxc);
+	init_completion(&controller->txc);
 	init_completion(&controller->done);
 
 	iomode = readl_relaxed(base + QUP_IO_M_MODES);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 04/18] spi: qup: Add completion timeout for fifo/block mode
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (2 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 03/18] spi: qup: Add completion timeout for dma mode Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 05/18] spi: qup: Place the QUP in run mode before DMA transactions Varadarajan Narayanan
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan

Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 272e48e..d3ccf53 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -330,7 +330,8 @@ static void spi_qup_dma_terminate(struct spi_master *master,
 		dmaengine_terminate_all(master->dma_rx);
 }
 
-static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
+static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
+			  unsigned long timeout)
 {
 	struct spi_qup *qup = spi_master_get_devdata(master);
 	int ret;
@@ -362,7 +363,8 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
 	return 0;
 }
 
-static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
+static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
+			  unsigned long timeout)
 {
 	struct spi_qup *qup = spi_master_get_devdata(master);
 	int ret;
@@ -381,6 +383,9 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
 
 	spi_qup_fifo_write(qup, xfer);
 
+	if (!wait_for_completion_timeout(&qup->done, timeout))
+		return -ETIMEDOUT;
+
 	return 0;
 }
 
@@ -624,7 +629,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
 	timeout = 100 * msecs_to_jiffies(timeout);
 
-
 	spin_lock_irqsave(&controller->lock, flags);
 	controller->xfer     = xfer;
 	controller->error    = 0;
@@ -635,10 +639,10 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	if (spi_qup_is_dma_xfer(controller->mode)) {
 		reinit_completion(&controller->rxc);
 		reinit_completion(&controller->txc);
-		ret = spi_qup_do_dma(master, xfer);
+		ret = spi_qup_do_dma(master, xfer, timeout);
 	} else {
 		reinit_completion(&controller->done);
-		ret = spi_qup_do_pio(master, xfer);
+		ret = spi_qup_do_pio(master, xfer, timeout);
 	}
 
 	if (ret)
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 05/18] spi: qup: Place the QUP in run mode before DMA transactions
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (3 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 04/18] spi: qup: Add completion timeout for fifo/block mode Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 07/18] spi: qup: Fix transaction done signaling Varadarajan Narayanan
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan

Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index d3ccf53..363bd43 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -336,6 +336,14 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
 	struct spi_qup *qup = spi_master_get_devdata(master);
 	int ret;
 
+	/* before issuing the descriptors, set the QUP to run */
+	ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+	if (ret) {
+		dev_warn(qup->dev, "%s(%d): cannot set RUN state\n",
+				__func__, __LINE__);
+		return ret;
+	}
+
 	if (xfer->rx_buf) {
 		ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM,
 					spi_qup_dma_done, &qup->rxc);
@@ -371,18 +379,24 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
 
 	ret = spi_qup_set_state(qup, QUP_STATE_RUN);
 	if (ret) {
-		dev_warn(qup->dev, "cannot set RUN state\n");
+		dev_warn(qup->dev, "%s(%d): cannot set RUN state\n");
 		return ret;
 	}
 
 	ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
 	if (ret) {
-		dev_warn(qup->dev, "cannot set PAUSE state\n");
+		dev_warn(qup->dev, "%s(%d): cannot set PAUSE state\n");
 		return ret;
 	}
 
 	spi_qup_fifo_write(qup, xfer);
 
+	ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+	if (ret) {
+		dev_warn(qup->dev, "%s(%d): cannot set RUN state\n");
+		return ret;
+	}
+
 	if (!wait_for_completion_timeout(&qup->done, timeout))
 		return -ETIMEDOUT;
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 06/18] spi: qup: Fix error handling in spi_qup_prep_sg
       [not found] ` <1497419551-21834-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
  2017-06-14  5:52   ` [PATCH 02/18] spi: qup: Setup DMA mode correctly Varadarajan Narayanan
@ 2017-06-14  5:52   ` Varadarajan Narayanan
  1 sibling, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA
  Cc: Varadarajan Narayanan

Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
 drivers/spi/spi-qup.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 363bd43..2124815 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -310,8 +310,8 @@ static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
 	}
 
 	desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
-	if (!desc)
-		return -EINVAL;
+	if (IS_ERR_OR_NULL(desc))
+		return desc ? PTR_ERR(desc) : -EINVAL;
 
 	desc->callback = callback;
 	desc->callback_param = data;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 07/18] spi: qup: Fix transaction done signaling
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (4 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 05/18] spi: qup: Place the QUP in run mode before DMA transactions Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  7:13   ` Sricharan R
  2017-06-14  5:52 ` [PATCH 08/18] spi: qup: Handle v1 dma completion differently Varadarajan Narayanan
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan

Wait to signal done until we get all of the interrupts we are expecting
to get for a transaction.  If we don't wait for the input done flag, we
can be inbetween transactions when the done flag comes in and this can
mess up the next transaction.

Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 2124815..7c22ee4 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -465,7 +465,8 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 	controller->xfer = xfer;
 	spin_unlock_irqrestore(&controller->lock, flags);
 
-	if (controller->rx_bytes == xfer->len || error)
+	if ((controller->rx_bytes == xfer->len &&
+		(opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
 		complete(&controller->done);
 
 	return IRQ_HANDLED;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 08/18] spi: qup: Handle v1 dma completion differently
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (5 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 07/18] spi: qup: Fix transaction done signaling Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
       [not found]   ` <1497419551-21834-9-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
  2017-06-14  5:52 ` [PATCH 09/18] spi: qup: Do block sized read/write in block mode Varadarajan Narayanan
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan

Do not assign i/o completion callbacks while running
on v1 of QUP.

Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 7c22ee4..0f6a4c7 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -334,6 +334,7 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
 			  unsigned long timeout)
 {
 	struct spi_qup *qup = spi_master_get_devdata(master);
+	dma_async_tx_callback done = qup->qup_v1 ? NULL : spi_qup_dma_done;
 	int ret;
 
 	/* before issuing the descriptors, set the QUP to run */
@@ -346,7 +347,7 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
 
 	if (xfer->rx_buf) {
 		ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM,
-					spi_qup_dma_done, &qup->rxc);
+					done, &qup->rxc);
 		if (ret)
 			return ret;
 
@@ -355,7 +356,7 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
 
 	if (xfer->tx_buf) {
 		ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV,
-					spi_qup_dma_done, &qup->txc);
+					done, &qup->txc);
 		if (ret)
 			return ret;
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 09/18] spi: qup: Do block sized read/write in block mode
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (6 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 08/18] spi: qup: Handle v1 dma completion differently Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 10/18] spi: qup: Fix DMA mode interrupt handling Varadarajan Narayanan
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan

This patch corrects the behavior of the BLOCK
transactions.  During block transactions, the controller
must be read/written to in block size transactions.

Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 151 +++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 119 insertions(+), 32 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 0f6a4c7..872de28 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -82,6 +82,8 @@
 #define QUP_IO_M_MODE_BAM		3
 
 /* QUP_OPERATIONAL fields */
+#define QUP_OP_IN_BLOCK_READ_REQ	BIT(13)
+#define QUP_OP_OUT_BLOCK_WRITE_REQ	BIT(12)
 #define QUP_OP_MAX_INPUT_DONE_FLAG	BIT(11)
 #define QUP_OP_MAX_OUTPUT_DONE_FLAG	BIT(10)
 #define QUP_OP_IN_SERVICE_FLAG		BIT(9)
@@ -156,6 +158,13 @@ struct spi_qup {
 	struct dma_slave_config	tx_conf;
 };
 
+static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag)
+{
+	u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
+	return (opflag & flag) != 0;
+}
+
 static inline bool spi_qup_is_dma_xfer(int mode)
 {
 	if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM)
@@ -216,29 +225,26 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
 	return 0;
 }
 
-static void spi_qup_fifo_read(struct spi_qup *controller,
-			    struct spi_transfer *xfer)
+static void spi_qup_read_from_fifo(struct spi_qup *controller,
+	struct spi_transfer *xfer, u32 num_words)
 {
 	u8 *rx_buf = xfer->rx_buf;
-	u32 word, state;
-	int idx, shift, w_size;
+	int i, shift, num_bytes;
+	u32 word;
 
-	w_size = controller->w_size;
-
-	while (controller->rx_bytes < xfer->len) {
-
-		state = readl_relaxed(controller->base + QUP_OPERATIONAL);
-		if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
-			break;
+	for (; num_words; num_words--) {
 
 		word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
 
+		num_bytes = min_t(int, xfer->len - controller->rx_bytes,
+					controller->w_size);
+
 		if (!rx_buf) {
-			controller->rx_bytes += w_size;
+			controller->rx_bytes += num_bytes;
 			continue;
 		}
 
-		for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
+		for (i = 0; i < num_bytes; i++, controller->rx_bytes++) {
 			/*
 			 * The data format depends on bytes per SPI word:
 			 *  4 bytes: 0x12345678
@@ -246,38 +252,80 @@ static void spi_qup_fifo_read(struct spi_qup *controller,
 			 *  1 byte : 0x00000012
 			 */
 			shift = BITS_PER_BYTE;
-			shift *= (w_size - idx - 1);
+			shift *= (controller->w_size - i - 1);
 			rx_buf[controller->rx_bytes] = word >> shift;
 		}
 	}
 }
 
-static void spi_qup_fifo_write(struct spi_qup *controller,
+static void spi_qup_read(struct spi_qup *controller,
 			    struct spi_transfer *xfer)
 {
-	const u8 *tx_buf = xfer->tx_buf;
-	u32 word, state, data;
-	int idx, w_size;
+	u32 remainder, words_per_block, num_words;
+	bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+
+	remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
+				 controller->w_size);
+	words_per_block = controller->in_blk_sz >> 2;
+
+	do {
+		/* ACK by clearing service flag */
+		writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+			       controller->base + QUP_OPERATIONAL);
+
+		if (is_block_mode) {
+			num_words = (remainder > words_per_block) ?
+					words_per_block : remainder;
+		} else {
+			if (!spi_qup_is_flag_set(controller,
+						 QUP_OP_IN_FIFO_NOT_EMPTY))
+				break;
 
-	w_size = controller->w_size;
+			num_words = 1;
+		}
 
-	while (controller->tx_bytes < xfer->len) {
+		/* read up to the maximum transfer size available */
+		spi_qup_read_from_fifo(controller, xfer, num_words);
 
-		state = readl_relaxed(controller->base + QUP_OPERATIONAL);
-		if (state & QUP_OP_OUT_FIFO_FULL)
+		remainder -= num_words;
+
+		/* if block mode, check to see if next block is available */
+		if (is_block_mode && !spi_qup_is_flag_set(controller,
+					QUP_OP_IN_BLOCK_READ_REQ))
 			break;
 
+	} while (remainder);
+
+	/*
+	 * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
+	 * mode reads, it has to be cleared again at the very end
+	 */
+	if (is_block_mode && spi_qup_is_flag_set(controller,
+				QUP_OP_MAX_INPUT_DONE_FLAG))
+		writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+			       controller->base + QUP_OPERATIONAL);
+
+}
+
+static void spi_qup_write_to_fifo(struct spi_qup *controller,
+	struct spi_transfer *xfer, u32 num_words)
+{
+	const u8 *tx_buf = xfer->tx_buf;
+	int i, num_bytes;
+	u32 word, data;
+
+	for (; num_words; num_words--) {
 		word = 0;
-		for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
 
-			if (!tx_buf) {
-				controller->tx_bytes += w_size;
-				break;
+		num_bytes = min_t(int, xfer->len - controller->tx_bytes,
+				    controller->w_size);
+		if (tx_buf)
+			for (i = 0; i < num_bytes; i++) {
+				data = tx_buf[controller->tx_bytes + i];
+				word |= data << (BITS_PER_BYTE * (3 - i));
 			}
 
-			data = tx_buf[controller->tx_bytes];
-			word |= data << (BITS_PER_BYTE * (3 - idx));
-		}
+		controller->tx_bytes += num_bytes;
 
 		writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
 	}
@@ -288,6 +336,44 @@ static void spi_qup_dma_done(void *data)
 	complete(data);
 }
 
+static void spi_qup_write(struct spi_qup *controller,
+			    struct spi_transfer *xfer)
+{
+	bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+	u32 remainder, words_per_block, num_words;
+
+	remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
+				 controller->w_size);
+	words_per_block = controller->out_blk_sz >> 2;
+
+	do {
+		/* ACK by clearing service flag */
+		writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
+			       controller->base + QUP_OPERATIONAL);
+
+		if (is_block_mode) {
+			num_words = (remainder > words_per_block) ?
+				words_per_block : remainder;
+		} else {
+			if (spi_qup_is_flag_set(controller,
+						QUP_OP_OUT_FIFO_FULL))
+				break;
+
+			num_words = 1;
+		}
+
+		spi_qup_write_to_fifo(controller, xfer, num_words);
+
+		remainder -= num_words;
+
+		/* if block mode, check to see if next block is available */
+		if (is_block_mode && !spi_qup_is_flag_set(controller,
+					QUP_OP_OUT_BLOCK_WRITE_REQ))
+			break;
+
+	} while (remainder);
+}
+
 static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
 			   enum dma_transfer_direction dir,
 			   dma_async_tx_callback callback, void *data)
@@ -390,7 +476,8 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
 		return ret;
 	}
 
-	spi_qup_fifo_write(qup, xfer);
+	if (qup->mode == QUP_IO_M_MODE_FIFO)
+		spi_qup_write(qup, xfer);
 
 	ret = spi_qup_set_state(qup, QUP_STATE_RUN);
 	if (ret) {
@@ -455,10 +542,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 
 	if (!spi_qup_is_dma_xfer(controller->mode)) {
 		if (opflags & QUP_OP_IN_SERVICE_FLAG)
-			spi_qup_fifo_read(controller, xfer);
+			spi_qup_read(controller, xfer);
 
 		if (opflags & QUP_OP_OUT_SERVICE_FLAG)
-			spi_qup_fifo_write(controller, xfer);
+			spi_qup_write(controller, xfer);
 	}
 
 	spin_lock_irqsave(&controller->lock, flags);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 10/18] spi: qup: Fix DMA mode interrupt handling
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (7 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 09/18] spi: qup: Do block sized read/write in block mode Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  7:21   ` Sricharan R
  2017-06-14  5:52 ` [PATCH 11/18] spi: qup: properly detect extra interrupts Varadarajan Narayanan
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan

This is needed for v1, where the i/o completion is not
handled in the dma driver.

Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 872de28..bd53e82 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -510,9 +510,9 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 
 	writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
 	writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
-	writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
 
 	if (!xfer) {
+		writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
 		dev_err_ratelimited(controller->dev, "unexpected irq %08x %08x %08x\n",
 				    qup_err, spi_err, opflags);
 		return IRQ_HANDLED;
@@ -540,7 +540,15 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 		error = -EIO;
 	}
 
-	if (!spi_qup_is_dma_xfer(controller->mode)) {
+	if (spi_qup_is_dma_xfer(controller->mode)) {
+		writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
+		if (opflags & QUP_OP_IN_SERVICE_FLAG &&
+		    opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
+			complete(&controller->rxc);
+		if (opflags & QUP_OP_OUT_SERVICE_FLAG &&
+		    opflags & QUP_OP_MAX_OUTPUT_DONE_FLAG)
+			complete(&controller->txc);
+	} else {
 		if (opflags & QUP_OP_IN_SERVICE_FLAG)
 			spi_qup_read(controller, xfer);
 
@@ -553,6 +561,9 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 	controller->xfer = xfer;
 	spin_unlock_irqrestore(&controller->lock, flags);
 
+	/* re-read opflags as flags may have changed due to actions above */
+	opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
 	if ((controller->rx_bytes == xfer->len &&
 		(opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
 		complete(&controller->done);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 11/18] spi: qup: properly detect extra interrupts
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (8 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 10/18] spi: qup: Fix DMA mode interrupt handling Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
       [not found]   ` <1497419551-21834-12-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
  2017-06-14  5:52 ` [PATCH 12/18] spi: qup: refactor spi_qup_io_config into two functions Varadarajan Narayanan
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan, Matthew McClintock

It's possible for a SPI transaction to complete and get another
interrupt and have it processed on the same spi_transfer before the
transfer_one can set it to NULL.

This masks unexpected interrupts, so let's set the spi_transfer to
NULL in the interrupt once the transaction is done. So we can
properly detect these bad interrupts and print warning messages.

Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index bd53e82..1a2a9d9 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -496,13 +496,13 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 	struct spi_qup *controller = dev_id;
 	struct spi_transfer *xfer;
 	u32 opflags, qup_err, spi_err;
-	unsigned long flags;
 	int error = 0;
+	bool done = 0;
 
-	spin_lock_irqsave(&controller->lock, flags);
+	spin_lock(&controller->lock);
 	xfer = controller->xfer;
 	controller->xfer = NULL;
-	spin_unlock_irqrestore(&controller->lock, flags);
+	spin_unlock(&controller->lock);
 
 	qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
 	spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
@@ -556,16 +556,19 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 			spi_qup_write(controller, xfer);
 	}
 
-	spin_lock_irqsave(&controller->lock, flags);
-	controller->error = error;
-	controller->xfer = xfer;
-	spin_unlock_irqrestore(&controller->lock, flags);
-
 	/* re-read opflags as flags may have changed due to actions above */
 	opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
 
 	if ((controller->rx_bytes == xfer->len &&
 		(opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
+		done = true;
+
+	spin_lock(&controller->lock);
+	controller->error = error;
+	controller->xfer = done ? NULL : xfer;
+	spin_unlock(&controller->lock);
+
+	if (done)
 		complete(&controller->done);
 
 	return IRQ_HANDLED;
@@ -765,7 +768,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
 exit:
 	spi_qup_set_state(controller, QUP_STATE_RESET);
 	spin_lock_irqsave(&controller->lock, flags);
-	controller->xfer = NULL;
 	if (!ret)
 		ret = controller->error;
 	spin_unlock_irqrestore(&controller->lock, flags);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 12/18] spi: qup: refactor spi_qup_io_config into two functions
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (9 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 11/18] spi: qup: properly detect extra interrupts Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 13/18] spi: qup: call io_config in mode specific function Varadarajan Narayanan
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan, Matthew McClintock

This is in preparation for handling transactions larger than
64K-1 bytes in block mode, which is currently unsupported and
quietly fails.

We need to break these into two functions 1) prep is
called once per spi_message and 2) io_config is called
once per spi-qup bus transaction

This is just refactoring, there should be no functional
change

Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 109 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 67 insertions(+), 42 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 1a2a9d9..c023dc1 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -574,12 +574,11 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-/* set clock freq ... bits per word */
-static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
+/* set clock freq ... bits per word, determine mode */
+static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
 {
 	struct spi_qup *controller = spi_master_get_devdata(spi->master);
-	u32 config, iomode, control;
-	int ret, n_words;
+	int ret;
 
 	if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
 		dev_err(controller->dev, "too big size for loopback %d > %d\n",
@@ -594,32 +593,59 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 		return -EIO;
 	}
 
-	if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
-		dev_err(controller->dev, "cannot set RESET state\n");
-		return -EIO;
-	}
-
 	controller->w_size = DIV_ROUND_UP(xfer->bits_per_word, 8);
 	controller->n_words = xfer->len / controller->w_size;
-	n_words = controller->n_words;
-
-	if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
 
+	if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32)))
 		controller->mode = QUP_IO_M_MODE_FIFO;
+	else if (spi->master->can_dma &&
+		 spi->master->can_dma(spi->master, spi, xfer) &&
+		 spi->master->cur_msg_mapped)
+		controller->mode = QUP_IO_M_MODE_BAM;
+	else
+		controller->mode = QUP_IO_M_MODE_BLOCK;
+
+	return 0;
+}
+
+/* prep qup for another spi transaction of specific type */
+static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
+{
+	struct spi_qup *controller = spi_master_get_devdata(spi->master);
+	u32 config, iomode, control;
+	unsigned long flags;
+
+	spin_lock_irqsave(&controller->lock, flags);
+	controller->xfer     = xfer;
+	controller->error    = 0;
+	controller->rx_bytes = 0;
+	controller->tx_bytes = 0;
+	spin_unlock_irqrestore(&controller->lock, flags);
+
+
+	if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
+		dev_err(controller->dev, "cannot set RESET state\n");
+		return -EIO;
+	}
 
-		writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
-		writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
+	switch (controller->mode) {
+	case QUP_IO_M_MODE_FIFO:
+		reinit_completion(&controller->done);
+		writel_relaxed(controller->n_words,
+			       controller->base + QUP_MX_READ_CNT);
+		writel_relaxed(controller->n_words,
+			       controller->base + QUP_MX_WRITE_CNT);
 		/* must be zero for FIFO */
 		writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
 		writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
-	} else if (spi->master->can_dma &&
-		   spi->master->can_dma(spi->master, spi, xfer) &&
-		   spi->master->cur_msg_mapped) {
-
-		controller->mode = QUP_IO_M_MODE_BAM;
-
-		writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
-		writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+		break;
+	case QUP_IO_M_MODE_BAM:
+		reinit_completion(&controller->txc);
+		reinit_completion(&controller->rxc);
+		writel_relaxed(controller->n_words,
+			       controller->base + QUP_MX_INPUT_CNT);
+		writel_relaxed(controller->n_words,
+			       controller->base + QUP_MX_OUTPUT_CNT);
 		/* must be zero for BLOCK and BAM */
 		writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
 		writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
@@ -637,19 +663,25 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 			if (xfer->tx_buf)
 				writel_relaxed(0, input_cnt);
 			else
-				writel_relaxed(n_words, input_cnt);
+				writel_relaxed(controller->n_words, input_cnt);
 
 			writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
 		}
-	} else {
-
-		controller->mode = QUP_IO_M_MODE_BLOCK;
-
-		writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
-		writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+		break;
+	case QUP_IO_M_MODE_BLOCK:
+		reinit_completion(&controller->done);
+		writel_relaxed(controller->n_words,
+			       controller->base + QUP_MX_INPUT_CNT);
+		writel_relaxed(controller->n_words,
+			       controller->base + QUP_MX_OUTPUT_CNT);
 		/* must be zero for BLOCK and BAM */
 		writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
 		writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
+		break;
+	default:
+		dev_err(controller->dev, "unknown mode = %d\n",
+				controller->mode);
+		return -EIO;
 	}
 
 	iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
@@ -738,6 +770,10 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	unsigned long timeout, flags;
 	int ret = -EIO;
 
+	ret = spi_qup_io_prep(spi, xfer);
+	if (ret)
+		return ret;
+
 	ret = spi_qup_io_config(spi, xfer);
 	if (ret)
 		return ret;
@@ -746,21 +782,10 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
 	timeout = 100 * msecs_to_jiffies(timeout);
 
-	spin_lock_irqsave(&controller->lock, flags);
-	controller->xfer     = xfer;
-	controller->error    = 0;
-	controller->rx_bytes = 0;
-	controller->tx_bytes = 0;
-	spin_unlock_irqrestore(&controller->lock, flags);
-
-	if (spi_qup_is_dma_xfer(controller->mode)) {
-		reinit_completion(&controller->rxc);
-		reinit_completion(&controller->txc);
+	if (spi_qup_is_dma_xfer(controller->mode))
 		ret = spi_qup_do_dma(master, xfer, timeout);
-	} else {
-		reinit_completion(&controller->done);
+	else
 		ret = spi_qup_do_pio(master, xfer, timeout);
-	}
 
 	if (ret)
 		goto exit;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 13/18] spi: qup: call io_config in mode specific function
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (10 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 12/18] spi: qup: refactor spi_qup_io_config into two functions Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 14/18] spi: qup: allow block mode to generate multiple transactions Varadarajan Narayanan
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan, Matthew McClintock

DMA transactions should only only need to call io_config only once, but
block mode might call it several times to setup several transactions so
it can handle reads/writes larger than the max size per transaction, so
we move the call to the do_ functions.

This is just refactoring, there should be no functional change

Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index c023dc1..f085e36 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -158,6 +158,8 @@ struct spi_qup {
 	struct dma_slave_config	tx_conf;
 };
 
+static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer);
+
 static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag)
 {
 	u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL);
@@ -416,13 +418,18 @@ static void spi_qup_dma_terminate(struct spi_master *master,
 		dmaengine_terminate_all(master->dma_rx);
 }
 
-static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
+static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
 			  unsigned long timeout)
 {
+	struct spi_master *master = spi->master;
 	struct spi_qup *qup = spi_master_get_devdata(master);
 	dma_async_tx_callback done = qup->qup_v1 ? NULL : spi_qup_dma_done;
 	int ret;
 
+	ret = spi_qup_io_config(spi, xfer);
+	if (ret)
+		return ret;
+
 	/* before issuing the descriptors, set the QUP to run */
 	ret = spi_qup_set_state(qup, QUP_STATE_RUN);
 	if (ret) {
@@ -458,12 +465,17 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
 	return 0;
 }
 
-static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
+static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
 			  unsigned long timeout)
 {
+	struct spi_master *master = spi->master;
 	struct spi_qup *qup = spi_master_get_devdata(master);
 	int ret;
 
+	ret = spi_qup_io_config(spi, xfer);
+	if (ret)
+		return ret;
+
 	ret = spi_qup_set_state(qup, QUP_STATE_RUN);
 	if (ret) {
 		dev_warn(qup->dev, "%s(%d): cannot set RUN state\n");
@@ -774,18 +786,14 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	if (ret)
 		return ret;
 
-	ret = spi_qup_io_config(spi, xfer);
-	if (ret)
-		return ret;
-
 	timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
 	timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
 	timeout = 100 * msecs_to_jiffies(timeout);
 
 	if (spi_qup_is_dma_xfer(controller->mode))
-		ret = spi_qup_do_dma(master, xfer, timeout);
+		ret = spi_qup_do_dma(spi, xfer, timeout);
 	else
-		ret = spi_qup_do_pio(master, xfer, timeout);
+		ret = spi_qup_do_pio(spi, xfer, timeout);
 
 	if (ret)
 		goto exit;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 14/18] spi: qup: allow block mode to generate multiple transactions
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (11 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 13/18] spi: qup: call io_config in mode specific function Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 15/18] spi: qup: refactor spi_qup_prep_sg Varadarajan Narayanan
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan, Matthew McClintock

This let's you write more to the SPI bus than 64K-1 which is important
if the block size of a SPI device is >= 64K or some other device wants
to do something larger.

This has the benefit of completely removing spi_message from the spi-qup
transactions

Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 127 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 80 insertions(+), 47 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index f085e36..02d4e10 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -120,7 +120,7 @@
 
 #define SPI_NUM_CHIPSELECTS		4
 
-#define SPI_MAX_DMA_XFER		(SZ_64K - 64)
+#define SPI_MAX_XFER			(SZ_64K - 64)
 
 /* high speed mode is when bus rate is greater then 26MHz */
 #define SPI_HS_MIN_RATE			26000000
@@ -151,6 +151,8 @@ struct spi_qup {
 	int			n_words;
 	int			tx_bytes;
 	int			rx_bytes;
+	const u8		*tx_buf;
+	u8			*rx_buf;
 	int			qup_v1;
 
 	int			mode;
@@ -175,6 +177,12 @@ static inline bool spi_qup_is_dma_xfer(int mode)
 	return false;
 }
 
+/* get's the transaction size length */
+static inline unsigned int spi_qup_len(struct spi_qup *controller)
+{
+	return controller->n_words * controller->w_size;
+}
+
 static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
 {
 	u32 opstate = readl_relaxed(controller->base + QUP_STATE);
@@ -227,10 +235,9 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
 	return 0;
 }
 
-static void spi_qup_read_from_fifo(struct spi_qup *controller,
-	struct spi_transfer *xfer, u32 num_words)
+static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words)
 {
-	u8 *rx_buf = xfer->rx_buf;
+	u8 *rx_buf = controller->rx_buf;
 	int i, shift, num_bytes;
 	u32 word;
 
@@ -238,8 +245,9 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller,
 
 		word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
 
-		num_bytes = min_t(int, xfer->len - controller->rx_bytes,
-					controller->w_size);
+		num_bytes = min_t(int, spi_qup_len(controller) -
+				       controller->rx_bytes,
+				       controller->w_size);
 
 		if (!rx_buf) {
 			controller->rx_bytes += num_bytes;
@@ -260,13 +268,12 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller,
 	}
 }
 
-static void spi_qup_read(struct spi_qup *controller,
-			    struct spi_transfer *xfer)
+static void spi_qup_read(struct spi_qup *controller)
 {
 	u32 remainder, words_per_block, num_words;
 	bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
 
-	remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
+	remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->rx_bytes,
 				 controller->w_size);
 	words_per_block = controller->in_blk_sz >> 2;
 
@@ -287,7 +294,7 @@ static void spi_qup_read(struct spi_qup *controller,
 		}
 
 		/* read up to the maximum transfer size available */
-		spi_qup_read_from_fifo(controller, xfer, num_words);
+		spi_qup_read_from_fifo(controller, num_words);
 
 		remainder -= num_words;
 
@@ -309,18 +316,18 @@ static void spi_qup_read(struct spi_qup *controller,
 
 }
 
-static void spi_qup_write_to_fifo(struct spi_qup *controller,
-	struct spi_transfer *xfer, u32 num_words)
+static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words)
 {
-	const u8 *tx_buf = xfer->tx_buf;
+	const u8 *tx_buf = controller->tx_buf;
 	int i, num_bytes;
 	u32 word, data;
 
 	for (; num_words; num_words--) {
 		word = 0;
 
-		num_bytes = min_t(int, xfer->len - controller->tx_bytes,
-				    controller->w_size);
+		num_bytes = min_t(int, spi_qup_len(controller) -
+				       controller->tx_bytes,
+				       controller->w_size);
 		if (tx_buf)
 			for (i = 0; i < num_bytes; i++) {
 				data = tx_buf[controller->tx_bytes + i];
@@ -338,13 +345,12 @@ static void spi_qup_dma_done(void *data)
 	complete(data);
 }
 
-static void spi_qup_write(struct spi_qup *controller,
-			    struct spi_transfer *xfer)
+static void spi_qup_write(struct spi_qup *controller)
 {
 	bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
 	u32 remainder, words_per_block, num_words;
 
-	remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
+	remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->tx_bytes,
 				 controller->w_size);
 	words_per_block = controller->out_blk_sz >> 2;
 
@@ -364,7 +370,7 @@ static void spi_qup_write(struct spi_qup *controller,
 			num_words = 1;
 		}
 
-		spi_qup_write_to_fifo(controller, xfer, num_words);
+		spi_qup_write_to_fifo(controller, num_words);
 
 		remainder -= num_words;
 
@@ -470,36 +476,62 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
 {
 	struct spi_master *master = spi->master;
 	struct spi_qup *qup = spi_master_get_devdata(master);
-	int ret;
+	int ret, n_words, iterations, offset = 0;
 
-	ret = spi_qup_io_config(spi, xfer);
-	if (ret)
-		return ret;
+	n_words = qup->n_words;
+	iterations = n_words / SPI_MAX_XFER; /* round down */
+	qup->rx_buf = xfer->rx_buf;
+	qup->tx_buf = xfer->tx_buf;
 
-	ret = spi_qup_set_state(qup, QUP_STATE_RUN);
-	if (ret) {
-		dev_warn(qup->dev, "%s(%d): cannot set RUN state\n");
-		return ret;
-	}
+	do {
+		if (iterations)
+			qup->n_words = SPI_MAX_XFER;
+		else
+			qup->n_words = n_words % SPI_MAX_XFER;
 
-	ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
-	if (ret) {
-		dev_warn(qup->dev, "%s(%d): cannot set PAUSE state\n");
-		return ret;
-	}
+		if (qup->tx_buf && offset)
+			qup->tx_buf = xfer->tx_buf + offset * SPI_MAX_XFER;
 
-	if (qup->mode == QUP_IO_M_MODE_FIFO)
-		spi_qup_write(qup, xfer);
+		if (qup->rx_buf && offset)
+			qup->rx_buf = xfer->rx_buf + offset * SPI_MAX_XFER;
 
-	ret = spi_qup_set_state(qup, QUP_STATE_RUN);
-	if (ret) {
-		dev_warn(qup->dev, "%s(%d): cannot set RUN state\n");
-		return ret;
-	}
+		/*
+		 * if the transaction is small enough, we need
+		 * to fallback to FIFO mode
+		 */
+		if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
+			qup->mode = QUP_IO_M_MODE_FIFO;
 
-	if (!wait_for_completion_timeout(&qup->done, timeout))
-		return -ETIMEDOUT;
+		ret = spi_qup_io_config(spi, xfer);
+		if (ret)
+			return ret;
+
+		ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+		if (ret) {
+			dev_warn(qup->dev, "cannot set RUN state\n");
+			return ret;
+		}
+
+		ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
+		if (ret) {
+			dev_warn(qup->dev, "cannot set PAUSE state\n");
+			return ret;
+		}
+
+		if (qup->mode == QUP_IO_M_MODE_FIFO)
+			spi_qup_write(qup);
+
+		ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+		if (ret) {
+			dev_warn(qup->dev, "cannot set RUN state\n");
+			return ret;
+		}
+
+		if (!wait_for_completion_timeout(&qup->done, timeout))
+			return -ETIMEDOUT;
 
+		offset++;
+	} while (iterations--);
 	return 0;
 }
 
@@ -562,16 +594,16 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 			complete(&controller->txc);
 	} else {
 		if (opflags & QUP_OP_IN_SERVICE_FLAG)
-			spi_qup_read(controller, xfer);
+			spi_qup_read(controller);
 
 		if (opflags & QUP_OP_OUT_SERVICE_FLAG)
-			spi_qup_write(controller, xfer);
+			spi_qup_write(controller);
 	}
 
 	/* re-read opflags as flags may have changed due to actions above */
 	opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
 
-	if ((controller->rx_bytes == xfer->len &&
+	if ((controller->rx_bytes == spi_qup_len(controller) &&
 		(opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
 		done = true;
 
@@ -787,7 +819,8 @@ static int spi_qup_transfer_one(struct spi_master *master,
 		return ret;
 
 	timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
-	timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
+	timeout = DIV_ROUND_UP(min_t(unsigned long, SPI_MAX_XFER,
+				     xfer->len) * 8, timeout);
 	timeout = 100 * msecs_to_jiffies(timeout);
 
 	if (spi_qup_is_dma_xfer(controller->mode))
@@ -992,7 +1025,7 @@ static int spi_qup_probe(struct platform_device *pdev)
 	master->dev.of_node = pdev->dev.of_node;
 	master->auto_runtime_pm = true;
 	master->dma_alignment = dma_get_cache_alignment();
-	master->max_dma_len = SPI_MAX_DMA_XFER;
+	master->max_dma_len = SPI_MAX_XFER;
 
 	platform_set_drvdata(pdev, master);
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 15/18] spi: qup: refactor spi_qup_prep_sg
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (12 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 14/18] spi: qup: allow block mode to generate multiple transactions Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 16/18] spi: qup: allow multiple DMA transactions per spi xfer Varadarajan Narayanan
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan, Matthew McClintock

Take specific sgl and nent to be prepared.  This is in
preparation for splitting DMA into multiple transacations, this
contains no code changes just refactoring.

Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 25 ++++++++++---------------
 1 file changed, 10 insertions(+), 15 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 02d4e10..b65a6a4 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -382,26 +382,19 @@ static void spi_qup_write(struct spi_qup *controller)
 	} while (remainder);
 }
 
-static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
-			   enum dma_transfer_direction dir,
+static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
+			   unsigned int nents, enum dma_transfer_direction dir,
 			   dma_async_tx_callback callback, void *data)
 {
 	unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
 	struct dma_async_tx_descriptor *desc;
-	struct scatterlist *sgl;
 	struct dma_chan *chan;
 	dma_cookie_t cookie;
-	unsigned int nents;
 
-	if (dir == DMA_MEM_TO_DEV) {
+	if (dir == DMA_MEM_TO_DEV)
 		chan = master->dma_tx;
-		nents = xfer->tx_sg.nents;
-		sgl = xfer->tx_sg.sgl;
-	} else {
+	else
 		chan = master->dma_rx;
-		nents = xfer->rx_sg.nents;
-		sgl = xfer->rx_sg.sgl;
-	}
 
 	desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
 	if (IS_ERR_OR_NULL(desc))
@@ -445,8 +438,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	}
 
 	if (xfer->rx_buf) {
-		ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM,
-					done, &qup->rxc);
+		ret = spi_qup_prep_sg(master, xfer->rx_sg.sgl,
+				      xfer->rx_sg.nents, DMA_DEV_TO_MEM,
+				      done, &qup->rxc);
 		if (ret)
 			return ret;
 
@@ -454,8 +448,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	}
 
 	if (xfer->tx_buf) {
-		ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV,
-					done, &qup->txc);
+		ret = spi_qup_prep_sg(master, xfer->tx_sg.sgl,
+				      xfer->tx_sg.nents, DMA_MEM_TO_DEV,
+				      done, &qup->txc);
 		if (ret)
 			return ret;
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 16/18] spi: qup: allow multiple DMA transactions per spi xfer
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (13 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 15/18] spi: qup: refactor spi_qup_prep_sg Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 17/18] spi: qup: Ensure done detection Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 18/18] spi: qup: support for qup v1 dma Varadarajan Narayanan
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan, Matthew McClintock

Much like the block mode changes, we are breaking up DMA transactions
into 64K chunks so we can reset the QUP engine.

Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 105 ++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 77 insertions(+), 28 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index b65a6a4..35e12ba 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -417,51 +417,100 @@ static void spi_qup_dma_terminate(struct spi_master *master,
 		dmaengine_terminate_all(master->dma_rx);
 }
 
+static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max,
+				     u32 *nents)
+{
+	struct scatterlist *sg;
+	u32 total = 0;
+
+	*nents = 0;
+
+	for (sg = sgl; sg; sg = sg_next(sg)) {
+		unsigned int len = sg_dma_len(sg);
+
+		/* check for overflow as well as limit */
+		if (((total + len) < total) || ((total + len) > max))
+			break;
+
+		total += len;
+		(*nents)++;
+	}
+
+	return total;
+}
+
 static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
 			  unsigned long timeout)
 {
 	struct spi_master *master = spi->master;
 	struct spi_qup *qup = spi_master_get_devdata(master);
 	dma_async_tx_callback done = qup->qup_v1 ? NULL : spi_qup_dma_done;
+	struct scatterlist *tx_sgl, *rx_sgl;
 	int ret;
 
-	ret = spi_qup_io_config(spi, xfer);
-	if (ret)
-		return ret;
+	rx_sgl = xfer->rx_sg.sgl;
+	tx_sgl = xfer->tx_sg.sgl;
 
-	/* before issuing the descriptors, set the QUP to run */
-	ret = spi_qup_set_state(qup, QUP_STATE_RUN);
-	if (ret) {
-		dev_warn(qup->dev, "%s(%d): cannot set RUN state\n",
-				__func__, __LINE__);
-		return ret;
-	}
+	do {
+		u32 rx_nents, tx_nents;
+
+		if (rx_sgl)
+			qup->n_words = spi_qup_sgl_get_nents_len(rx_sgl,
+					SPI_MAX_XFER, &rx_nents) / qup->w_size;
+		if (tx_sgl)
+			qup->n_words = spi_qup_sgl_get_nents_len(tx_sgl,
+					SPI_MAX_XFER, &tx_nents) / qup->w_size;
+		if (!qup->n_words)
+			return -EIO;
 
-	if (xfer->rx_buf) {
-		ret = spi_qup_prep_sg(master, xfer->rx_sg.sgl,
-				      xfer->rx_sg.nents, DMA_DEV_TO_MEM,
-				      done, &qup->rxc);
+		ret = spi_qup_io_config(spi, xfer);
 		if (ret)
 			return ret;
 
-		dma_async_issue_pending(master->dma_rx);
-	}
-
-	if (xfer->tx_buf) {
-		ret = spi_qup_prep_sg(master, xfer->tx_sg.sgl,
-				      xfer->tx_sg.nents, DMA_MEM_TO_DEV,
-				      done, &qup->txc);
-		if (ret)
+		/* before issuing the descriptors, set the QUP to run */
+		ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+		if (ret) {
+			dev_warn(qup->dev, "cannot set RUN state\n");
 			return ret;
+		}
 
-		dma_async_issue_pending(master->dma_tx);
-	}
+		if (rx_sgl) {
+			ret = spi_qup_prep_sg(master, rx_sgl, rx_nents,
+					      DMA_DEV_TO_MEM, done,
+					      &qup->rxc);
+			if (ret)
+				return ret;
+			dma_async_issue_pending(master->dma_rx);
+		}
+
+		if (tx_sgl) {
+			ret = spi_qup_prep_sg(master, tx_sgl, tx_nents,
+					      DMA_MEM_TO_DEV, done,
+					      &qup->txc);
+			if (ret)
+				return ret;
+
+			dma_async_issue_pending(master->dma_tx);
+		}
+
+		if (rx_sgl &&
+		    !wait_for_completion_timeout(&qup->rxc, timeout)) {
+			pr_emerg(" rx timed out\n");
+			return -ETIMEDOUT;
+		}
+
+		if (tx_sgl &&
+		    !wait_for_completion_timeout(&qup->txc, timeout)) {
+			pr_emerg(" tx timed out\n");
+			return -ETIMEDOUT;
+		}
 
-	if (xfer->rx_buf && !wait_for_completion_timeout(&qup->rxc, timeout))
-		return -ETIMEDOUT;
+		for (; rx_sgl && rx_nents--; rx_sgl = sg_next(rx_sgl))
+			;
+		for (; tx_sgl && tx_nents--; tx_sgl = sg_next(tx_sgl))
+			;
 
-	if (xfer->tx_buf && !wait_for_completion_timeout(&qup->txc, timeout))
-		return -ETIMEDOUT;
+	} while (rx_sgl || tx_sgl);
 
 	return 0;
 }
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 17/18] spi: qup: Ensure done detection
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (14 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 16/18] spi: qup: allow multiple DMA transactions per spi xfer Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  2017-06-14  5:52 ` [PATCH 18/18] spi: qup: support for qup v1 dma Varadarajan Narayanan
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan, Andy Gross, Abhishek Sahu

This patch fixes an issue where a SPI transaction has completed, but the
done condition is missed.  This occurs because at the time of interrupt the
MAX_INPUT_DONE_FLAG is not asserted.  However, in the process of reading
blocks of data from the FIFO, the last portion of data comes in.

The opflags read at the beginning of the irq handler no longer matches the
current opflag state.  To get around this condition, the block read
function should update the opflags so that done detection is correct after
the return.

Signed-off-by: Andy Gross <agross@codeaurora.org>
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 drivers/spi/spi-qup.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 35e12ba..4ef9301 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -268,7 +268,7 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words)
 	}
 }
 
-static void spi_qup_read(struct spi_qup *controller)
+static void spi_qup_read(struct spi_qup *controller, u32 *opflags)
 {
 	u32 remainder, words_per_block, num_words;
 	bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
@@ -307,10 +307,12 @@ static void spi_qup_read(struct spi_qup *controller)
 
 	/*
 	 * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
-	 * mode reads, it has to be cleared again at the very end
+	 * reads, it has to be cleared again at the very end.  However, be sure
+	 * to refresh opflags value because MAX_INPUT_DONE_FLAG may now be
+	 * present and this is used to determine if transaction is complete
 	 */
-	if (is_block_mode && spi_qup_is_flag_set(controller,
-				QUP_OP_MAX_INPUT_DONE_FLAG))
+	*opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
+	if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
 		writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
 			       controller->base + QUP_OPERATIONAL);
 
@@ -638,7 +640,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 			complete(&controller->txc);
 	} else {
 		if (opflags & QUP_OP_IN_SERVICE_FLAG)
-			spi_qup_read(controller);
+			spi_qup_read(controller, &opflags);
 
 		if (opflags & QUP_OP_OUT_SERVICE_FLAG)
 			spi_qup_write(controller);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 18/18] spi: qup: support for qup v1 dma
  2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
                   ` (15 preceding siblings ...)
  2017-06-14  5:52 ` [PATCH 17/18] spi: qup: Ensure done detection Varadarajan Narayanan
@ 2017-06-14  5:52 ` Varadarajan Narayanan
  16 siblings, 0 replies; 34+ messages in thread
From: Varadarajan Narayanan @ 2017-06-14  5:52 UTC (permalink / raw)
  To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
	linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
  Cc: Varadarajan Narayanan, Abhishek Sahu

Currently the QUP Version v1 does not work with DMA so added
the support for the same.

1. It uses ADM DMA which requires TX and RX CRCI
2. DMA channel initialization need to be done after setting
   block size for having valid values in maxburst
3. QUP mode should be DMOV instead of BAM.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
 .../devicetree/bindings/spi/qcom,spi-qup.txt       |  6 ++++
 drivers/spi/spi-qup.c                              | 35 +++++++++++++++++-----
 2 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
index 5c09077..e754181 100644
--- a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
+++ b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
@@ -38,6 +38,12 @@ Optional properties:
 - dma-names:    Names for the dma channels, if present. There must be at
                 least one channel named "tx" for transmit and named "rx" for
                 receive.
+- qcom,tx-crci: Identificator for Client Rate Control Interface (CRCI) to be
+		used with TX DMA channel. Required when using DMA for
+		transmission with QUP Version 1 i.e qcom,spi-qup-v1.1.1.
+- qcom,rx-crci: Identificator for Client Rate Control Interface (CRCI) to be
+		used with RX DMA channel. Required when using DMA for
+		receiving with QUP Version 1 i.e qcom,spi-qup-v1.1.1.
 
 SPI slave nodes must be children of the SPI master node and can contain
 properties described in Documentation/devicetree/bindings/spi/spi-bus.txt
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 4ef9301..10666e7 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -691,7 +691,8 @@ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
 	else if (spi->master->can_dma &&
 		 spi->master->can_dma(spi->master, spi, xfer) &&
 		 spi->master->cur_msg_mapped)
-		controller->mode = QUP_IO_M_MODE_BAM;
+		controller->mode = controller->qup_v1 ? QUP_IO_M_MODE_DMOV :
+							QUP_IO_M_MODE_BAM;
 	else
 		controller->mode = QUP_IO_M_MODE_BLOCK;
 
@@ -730,6 +731,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 		writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
 		break;
 	case QUP_IO_M_MODE_BAM:
+	case QUP_IO_M_MODE_DMOV:
 		reinit_completion(&controller->txc);
 		reinit_completion(&controller->rxc);
 		writel_relaxed(controller->n_words,
@@ -934,6 +936,7 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
 	struct dma_slave_config *rx_conf = &spi->rx_conf,
 				*tx_conf = &spi->tx_conf;
 	struct device *dev = spi->dev;
+	u32 tx_crci = 0, rx_crci = 0;
 	int ret;
 
 	/* allocate dma resources, if available */
@@ -947,16 +950,34 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
 		goto err_tx;
 	}
 
+	if (spi->qup_v1) {
+		ret = of_property_read_u32(dev->of_node, "qcom,tx-crci",
+					   &tx_crci);
+		if (ret) {
+			dev_err(dev, "missing property qcom,tx-crci\n");
+			goto err;
+		}
+
+		ret = of_property_read_u32(dev->of_node, "qcom,rx-crci",
+					   &rx_crci);
+		if (ret) {
+			dev_err(dev, "missing property qcom,rx-crci\n");
+			goto err;
+		}
+	}
+
 	/* set DMA parameters */
 	rx_conf->direction = DMA_DEV_TO_MEM;
 	rx_conf->device_fc = 1;
 	rx_conf->src_addr = base + QUP_INPUT_FIFO;
 	rx_conf->src_maxburst = spi->in_blk_sz;
+	rx_conf->slave_id = rx_crci;
 
 	tx_conf->direction = DMA_MEM_TO_DEV;
 	tx_conf->device_fc = 1;
 	tx_conf->dst_addr = base + QUP_OUTPUT_FIFO;
 	tx_conf->dst_maxburst = spi->out_blk_sz;
+	tx_conf->slave_id = tx_crci;
 
 	ret = dmaengine_slave_config(master->dma_rx, rx_conf);
 	if (ret) {
@@ -1083,12 +1104,6 @@ static int spi_qup_probe(struct platform_device *pdev)
 	controller->cclk = cclk;
 	controller->irq = irq;
 
-	ret = spi_qup_init_dma(master, res->start);
-	if (ret == -EPROBE_DEFER)
-		goto error;
-	else if (!ret)
-		master->can_dma = spi_qup_can_dma;
-
 	/* set v1 flag if device is version 1 */
 	if (of_device_is_compatible(dev->of_node, "qcom,spi-qup-v1.1.1"))
 		controller->qup_v1 = 1;
@@ -1125,6 +1140,12 @@ static int spi_qup_probe(struct platform_device *pdev)
 		 controller->in_blk_sz, controller->in_fifo_sz,
 		 controller->out_blk_sz, controller->out_fifo_sz);
 
+	ret = spi_qup_init_dma(master, res->start);
+	if (ret == -EPROBE_DEFER)
+		goto error;
+	else if (!ret)
+		master->can_dma = spi_qup_can_dma;
+
 	writel_relaxed(1, base + QUP_SW_RESET);
 
 	ret = spi_qup_set_state(controller, QUP_STATE_RESET);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* Re: [PATCH 07/18] spi: qup: Fix transaction done signaling
  2017-06-14  5:52 ` [PATCH 07/18] spi: qup: Fix transaction done signaling Varadarajan Narayanan
@ 2017-06-14  7:13   ` Sricharan R
       [not found]     ` <4b81a4c7-b85c-a35d-15fb-4aaaec3c7e8c-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
  0 siblings, 1 reply; 34+ messages in thread
From: Sricharan R @ 2017-06-14  7:13 UTC (permalink / raw)
  To: Varadarajan Narayanan, broonie, robh+dt, mark.rutland,
	andy.gross, david.brown, linux-spi, devicetree, linux-kernel,
	linux-arm-msm, linux-soc

Hi Varada,

On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
> Wait to signal done until we get all of the interrupts we are expecting
> to get for a transaction.  If we don't wait for the input done flag, we
> can be inbetween transactions when the done flag comes in and this can
> mess up the next transaction.
> 
> Signed-off-by: Andy Gross <andy.gross@linaro.org>
> Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
> ---
>  drivers/spi/spi-qup.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
> index 2124815..7c22ee4 100644
> --- a/drivers/spi/spi-qup.c
> +++ b/drivers/spi/spi-qup.c
> @@ -465,7 +465,8 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>  	controller->xfer = xfer;
>  	spin_unlock_irqrestore(&controller->lock, flags);
>  
> -	if (controller->rx_bytes == xfer->len || error)
> +	if ((controller->rx_bytes == xfer->len &&
> +		(opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)

 Not sure why we need this additional check, because having read all the
 bytes implies transfer complete (or) why not just check only for
 QUP_OP_MAX_INPUT_DONE_FLAG ?

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* Re: [PATCH 08/18] spi: qup: Handle v1 dma completion differently
       [not found]   ` <1497419551-21834-9-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2017-06-14  7:15     ` Sricharan R
       [not found]       ` <a0e499a7-8f89-96d6-9463-c2b3f774cd6d-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
  0 siblings, 1 reply; 34+ messages in thread
From: Sricharan R @ 2017-06-14  7:15 UTC (permalink / raw)
  To: Varadarajan Narayanan, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	andy.gross-QSEj5FYQhm4dnm+yROfE0A,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA

Hi Varada,

On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
> Do not assign i/o completion callbacks while running
> on v1 of QUP.
> 
> Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
>  drivers/spi/spi-qup.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
> index 7c22ee4..0f6a4c7 100644
> --- a/drivers/spi/spi-qup.c
> +++ b/drivers/spi/spi-qup.c
> @@ -334,6 +334,7 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
>  			  unsigned long timeout)
>  {
>  	struct spi_qup *qup = spi_master_get_devdata(master);
> +	dma_async_tx_callback done = qup->qup_v1 ? NULL : spi_qup_dma_done;
>  	int ret;
>  
>  	/* before issuing the descriptors, set the QUP to run */
> @@ -346,7 +347,7 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
>  
>  	if (xfer->rx_buf) {
>  		ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM,
> -					spi_qup_dma_done, &qup->rxc);
> +					done, &qup->rxc);
>  		if (ret)
>  			return ret;
>  
> @@ -355,7 +356,7 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
>  
>  	if (xfer->tx_buf) {
>  		ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV,
> -					spi_qup_dma_done, &qup->txc);
> +					done, &qup->txc);
>  		if (ret)
>  			return ret;
>  
> 

 Not sure why we cannot use dma callback for V1 ?

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 10/18] spi: qup: Fix DMA mode interrupt handling
  2017-06-14  5:52 ` [PATCH 10/18] spi: qup: Fix DMA mode interrupt handling Varadarajan Narayanan
@ 2017-06-14  7:21   ` Sricharan R
       [not found]     ` <66ba7dfb-6ff3-884e-6db0-8d5191f87c93-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
  0 siblings, 1 reply; 34+ messages in thread
From: Sricharan R @ 2017-06-14  7:21 UTC (permalink / raw)
  To: Varadarajan Narayanan, broonie, robh+dt, mark.rutland,
	andy.gross, david.brown, linux-spi, devicetree, linux-kernel,
	linux-arm-msm, linux-soc

Hi Varada,

On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
> This is needed for v1, where the i/o completion is not
> handled in the dma driver.
> 
> Signed-off-by: Andy Gross <andy.gross@linaro.org>
> Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
> ---
>  drivers/spi/spi-qup.c | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
> index 872de28..bd53e82 100644
> --- a/drivers/spi/spi-qup.c
> +++ b/drivers/spi/spi-qup.c
> @@ -510,9 +510,9 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>  
>  	writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
>  	writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
> -	writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
>  
>  	if (!xfer) {
> +		writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);

 This does look correct to remove acknowledging the QUP in normal case and
  do it conditionally only when xfer = NULL.

>  		dev_err_ratelimited(controller->dev, "unexpected irq %08x %08x %08x\n",
>  				    qup_err, spi_err, opflags);
>  		return IRQ_HANDLED;
> @@ -540,7 +540,15 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>  		error = -EIO;
>  	}
>  
> -	if (!spi_qup_is_dma_xfer(controller->mode)) {
> +	if (spi_qup_is_dma_xfer(controller->mode)) {
> +		writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
> +		if (opflags & QUP_OP_IN_SERVICE_FLAG &&
> +		    opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
> +			complete(&controller->rxc);
> +		if (opflags & QUP_OP_OUT_SERVICE_FLAG &&
> +		    opflags & QUP_OP_MAX_OUTPUT_DONE_FLAG)
> +			complete(&controller->txc);
> +	} else {

 Is this because in patch #8 that we do not populate the dma callback
 for v1. If that is done, this should not be required at all, as the
 complete would be signalled from the dma callback.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* Re: [PATCH 11/18] spi: qup: properly detect extra interrupts
       [not found]   ` <1497419551-21834-12-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2017-06-14  7:27     ` Sricharan R
  2017-06-14 19:59       ` Andy Gross
  0 siblings, 1 reply; 34+ messages in thread
From: Sricharan R @ 2017-06-14  7:27 UTC (permalink / raw)
  To: Varadarajan Narayanan, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	andy.gross-QSEj5FYQhm4dnm+yROfE0A,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA
  Cc: Matthew McClintock

Hi Varada,

On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
> It's possible for a SPI transaction to complete and get another
> interrupt and have it processed on the same spi_transfer before the
> transfer_one can set it to NULL.
> 
> This masks unexpected interrupts, so let's set the spi_transfer to
> NULL in the interrupt once the transaction is done. So we can
> properly detect these bad interrupts and print warning messages.
> 
> Signed-off-by: Matthew McClintock <mmcclint-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
>  drivers/spi/spi-qup.c | 20 +++++++++++---------
>  1 file changed, 11 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
> index bd53e82..1a2a9d9 100644
> --- a/drivers/spi/spi-qup.c
> +++ b/drivers/spi/spi-qup.c
> @@ -496,13 +496,13 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>  	struct spi_qup *controller = dev_id;
>  	struct spi_transfer *xfer;
>  	u32 opflags, qup_err, spi_err;
> -	unsigned long flags;
>  	int error = 0;
> +	bool done = 0;
>  
> -	spin_lock_irqsave(&controller->lock, flags);
> +	spin_lock(&controller->lock);
>  	xfer = controller->xfer;
>  	controller->xfer = NULL;
> -	spin_unlock_irqrestore(&controller->lock, flags);
> +	spin_unlock(&controller->lock);

 Why change the locking here ?

>  
>  	qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
>  	spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
> @@ -556,16 +556,19 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>  			spi_qup_write(controller, xfer);
>  	}
>  
> -	spin_lock_irqsave(&controller->lock, flags);
> -	controller->error = error;
> -	controller->xfer = xfer;
> -	spin_unlock_irqrestore(&controller->lock, flags);
> -
>  	/* re-read opflags as flags may have changed due to actions above */
>  	opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
>  
>  	if ((controller->rx_bytes == xfer->len &&
>  		(opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
> +		done = true;
> +
> +	spin_lock(&controller->lock);
> +	controller->error = error;
> +	controller->xfer = done ? NULL : xfer;
> +	spin_unlock(&controller->lock);
> +
> +	if (done)
>  		complete(&controller->done);
>  
  Its not clear, why the driver is setting the controller->xfer = NULL
  and restoring it inside the irq. This patch seems to fix things on
  top of that.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 01/18] spi: qup: Enable chip select support
  2017-06-14  5:52 ` [PATCH 01/18] spi: qup: Enable chip select support Varadarajan Narayanan
@ 2017-06-14  9:47   ` Stanimir Varbanov
  2017-08-08 11:18   ` Applied "spi: qup: Enable chip select support" to the spi tree Mark Brown
  1 sibling, 0 replies; 34+ messages in thread
From: Stanimir Varbanov @ 2017-06-14  9:47 UTC (permalink / raw)
  To: Varadarajan Narayanan, broonie, robh+dt, mark.rutland,
	andy.gross, david.brown, linux-spi, devicetree, linux-kernel,
	linux-arm-msm, linux-soc
  Cc: Sham Muthayyan

Hi,

On 06/14/2017 08:52 AM, Varadarajan Narayanan wrote:
> Enable chip select support for QUP versions later than v1

Could you be more descriptive here because in the git history of the
driver there is a commit "4a8573abe965115bc5b064401fd669b74e985258 spi:
qup: Remove chip select function" which removes chip select
functionality. So this patch leads to a situation where we use gpio cs
for qup_v1 and not for next versions!?

> 
> Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
> Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
> ---
>  drivers/spi/spi-qup.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)

<snip>

-- 
regards,
Stan

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

* Re: [PATCH 07/18] spi: qup: Fix transaction done signaling
       [not found]     ` <4b81a4c7-b85c-a35d-15fb-4aaaec3c7e8c-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2017-06-14 19:51       ` Andy Gross
       [not found]         ` <20170614195155.GB32733-5taXn+FmohyKb9UB7mSz9QC/G2K4zDHf@public.gmane.org>
  0 siblings, 1 reply; 34+ messages in thread
From: Andy Gross @ 2017-06-14 19:51 UTC (permalink / raw)
  To: Sricharan R
  Cc: Varadarajan Narayanan, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA

On Wed, Jun 14, 2017 at 12:43:43PM +0530, Sricharan R wrote:
> Hi Varada,
> 
> On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
> > Wait to signal done until we get all of the interrupts we are expecting
> > to get for a transaction.  If we don't wait for the input done flag, we
> > can be inbetween transactions when the done flag comes in and this can
> > mess up the next transaction.
> > 
> > Signed-off-by: Andy Gross <andy.gross-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> > ---
> >  drivers/spi/spi-qup.c | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
> > index 2124815..7c22ee4 100644
> > --- a/drivers/spi/spi-qup.c
> > +++ b/drivers/spi/spi-qup.c
> > @@ -465,7 +465,8 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
> >  	controller->xfer = xfer;
> >  	spin_unlock_irqrestore(&controller->lock, flags);
> >  
> > -	if (controller->rx_bytes == xfer->len || error)
> > +	if ((controller->rx_bytes == xfer->len &&
> > +		(opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
> 
>  Not sure why we need this additional check, because having read all the
>  bytes implies transfer complete (or) why not just check only for
>  QUP_OP_MAX_INPUT_DONE_FLAG ?

So you can receive an interrupt for the last data without it having also
signalled the INPUT_DONE.  That means you'd have one more IRQ come in and if you
don't wait for that, you could start up the next transaction and have an irq
come in that screws up that transaction.

It might be sufficient to just wait for the INPUT_DONE_FLAG.  That cannot be
signalled unless the rx_bytes == xfer->len.

Regards,

Andy
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 08/18] spi: qup: Handle v1 dma completion differently
       [not found]       ` <a0e499a7-8f89-96d6-9463-c2b3f774cd6d-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2017-06-14 19:53         ` Andy Gross
  0 siblings, 0 replies; 34+ messages in thread
From: Andy Gross @ 2017-06-14 19:53 UTC (permalink / raw)
  To: Sricharan R
  Cc: Varadarajan Narayanan, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA

On Wed, Jun 14, 2017 at 12:45:51PM +0530, Sricharan R wrote:
> Hi Varada,
> 
> On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
> > Do not assign i/o completion callbacks while running
> > on v1 of QUP.
> > 
> > Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> > ---
> >  drivers/spi/spi-qup.c | 5 +++--
> >  1 file changed, 3 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
> > index 7c22ee4..0f6a4c7 100644
> > --- a/drivers/spi/spi-qup.c
> > +++ b/drivers/spi/spi-qup.c
> > @@ -334,6 +334,7 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
> >  			  unsigned long timeout)
> >  {
> >  	struct spi_qup *qup = spi_master_get_devdata(master);
> > +	dma_async_tx_callback done = qup->qup_v1 ? NULL : spi_qup_dma_done;
> >  	int ret;
> >  
> >  	/* before issuing the descriptors, set the QUP to run */
> > @@ -346,7 +347,7 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
> >  
> >  	if (xfer->rx_buf) {
> >  		ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM,
> > -					spi_qup_dma_done, &qup->rxc);
> > +					done, &qup->rxc);
> >  		if (ret)
> >  			return ret;
> >  
> > @@ -355,7 +356,7 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
> >  
> >  	if (xfer->tx_buf) {
> >  		ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV,
> > -					spi_qup_dma_done, &qup->txc);
> > +					done, &qup->txc);
> >  		if (ret)
> >  			return ret;
> >  
> > 
> 
>  Not sure why we cannot use dma callback for V1 ?

V1 is for ADMA.  V2+ is BAM.  We only needed the callback for BAM


Regards,

Andy
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 11/18] spi: qup: properly detect extra interrupts
  2017-06-14  7:27     ` Sricharan R
@ 2017-06-14 19:59       ` Andy Gross
       [not found]         ` <20170614195953.GD32733-5taXn+FmohyKb9UB7mSz9QC/G2K4zDHf@public.gmane.org>
  2017-06-15  5:27         ` Sricharan R
  0 siblings, 2 replies; 34+ messages in thread
From: Andy Gross @ 2017-06-14 19:59 UTC (permalink / raw)
  To: Sricharan R
  Cc: Varadarajan Narayanan, broonie, robh+dt, mark.rutland,
	david.brown, linux-spi, devicetree, linux-kernel, linux-arm-msm,
	linux-soc, Matthew McClintock

On Wed, Jun 14, 2017 at 12:57:25PM +0530, Sricharan R wrote:
> Hi Varada,
> 
> On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
> > It's possible for a SPI transaction to complete and get another
> > interrupt and have it processed on the same spi_transfer before the
> > transfer_one can set it to NULL.
> > 
> > This masks unexpected interrupts, so let's set the spi_transfer to
> > NULL in the interrupt once the transaction is done. So we can
> > properly detect these bad interrupts and print warning messages.
> > 
> > Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
> > Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
> > ---
> >  drivers/spi/spi-qup.c | 20 +++++++++++---------
> >  1 file changed, 11 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
> > index bd53e82..1a2a9d9 100644
> > --- a/drivers/spi/spi-qup.c
> > +++ b/drivers/spi/spi-qup.c
> > @@ -496,13 +496,13 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
> >  	struct spi_qup *controller = dev_id;
> >  	struct spi_transfer *xfer;
> >  	u32 opflags, qup_err, spi_err;
> > -	unsigned long flags;
> >  	int error = 0;
> > +	bool done = 0;
> >  
> > -	spin_lock_irqsave(&controller->lock, flags);
> > +	spin_lock(&controller->lock);
> >  	xfer = controller->xfer;
> >  	controller->xfer = NULL;
> > -	spin_unlock_irqrestore(&controller->lock, flags);
> > +	spin_unlock(&controller->lock);
> 
>  Why change the locking here ?
> 
> >  
> >  	qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
> >  	spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
> > @@ -556,16 +556,19 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
> >  			spi_qup_write(controller, xfer);
> >  	}
> >  
> > -	spin_lock_irqsave(&controller->lock, flags);
> > -	controller->error = error;
> > -	controller->xfer = xfer;
> > -	spin_unlock_irqrestore(&controller->lock, flags);
> > -
> >  	/* re-read opflags as flags may have changed due to actions above */
> >  	opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
> >  
> >  	if ((controller->rx_bytes == xfer->len &&
> >  		(opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
> > +		done = true;
> > +
> > +	spin_lock(&controller->lock);
> > +	controller->error = error;
> > +	controller->xfer = done ? NULL : xfer;
> > +	spin_unlock(&controller->lock);
> > +
> > +	if (done)
> >  		complete(&controller->done);
> >  
>   Its not clear, why the driver is setting the controller->xfer = NULL
>   and restoring it inside the irq. This patch seems to fix things on
>   top of that.

I think the original intent was to make sure that the irqhandler knew that there
was no outstanding transaction.  This begs the question of why that would ever
be necessary.  I think it would suffice to rework all of that to remove that
behavior and perhaps enable/disable the irq as we need to during transactions.

I've never been a fan of the controller->xfer being set to NULL.


Regards,

Andy

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

* Re: [PATCH 10/18] spi: qup: Fix DMA mode interrupt handling
       [not found]     ` <66ba7dfb-6ff3-884e-6db0-8d5191f87c93-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
@ 2017-06-14 20:06       ` Andy Gross
  2017-06-15  5:52         ` Sricharan R
  0 siblings, 1 reply; 34+ messages in thread
From: Andy Gross @ 2017-06-14 20:06 UTC (permalink / raw)
  To: Sricharan R
  Cc: Varadarajan Narayanan, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA

On Wed, Jun 14, 2017 at 12:51:11PM +0530, Sricharan R wrote:
> Hi Varada,
> 
> On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
> > This is needed for v1, where the i/o completion is not
> > handled in the dma driver.
> > 
> > Signed-off-by: Andy Gross <andy.gross-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> > ---
> >  drivers/spi/spi-qup.c | 15 +++++++++++++--
> >  1 file changed, 13 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
> > index 872de28..bd53e82 100644
> > --- a/drivers/spi/spi-qup.c
> > +++ b/drivers/spi/spi-qup.c
> > @@ -510,9 +510,9 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
> >  
> >  	writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
> >  	writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
> > -	writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
> >  
> >  	if (!xfer) {
> > +		writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
> 
>  This does look correct to remove acknowledging the QUP in normal case and
>   do it conditionally only when xfer = NULL.

This is to probably mask the issue of getting erroneous/spurious IRQs.

> 
> >  		dev_err_ratelimited(controller->dev, "unexpected irq %08x %08x %08x\n",
> >  				    qup_err, spi_err, opflags);
> >  		return IRQ_HANDLED;
> > @@ -540,7 +540,15 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
> >  		error = -EIO;
> >  	}
> >  
> > -	if (!spi_qup_is_dma_xfer(controller->mode)) {
> > +	if (spi_qup_is_dma_xfer(controller->mode)) {
> > +		writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
> > +		if (opflags & QUP_OP_IN_SERVICE_FLAG &&
> > +		    opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
> > +			complete(&controller->rxc);
> > +		if (opflags & QUP_OP_OUT_SERVICE_FLAG &&
> > +		    opflags & QUP_OP_MAX_OUTPUT_DONE_FLAG)
> > +			complete(&controller->txc);
> > +	} else {
> 
>  Is this because in patch #8 that we do not populate the dma callback
>  for v1. If that is done, this should not be required at all, as the
>  complete would be signalled from the dma callback.

I believe that is true.  There shouldn't be any IRQs for DMA enabled
transactions (at least BAM-dma).
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 11/18] spi: qup: properly detect extra interrupts
       [not found]         ` <20170614195953.GD32733-5taXn+FmohyKb9UB7mSz9QC/G2K4zDHf@public.gmane.org>
@ 2017-06-14 21:51           ` Matthew McClintock
  0 siblings, 0 replies; 34+ messages in thread
From: Matthew McClintock @ 2017-06-14 21:51 UTC (permalink / raw)
  To: Andy Gross
  Cc: Sricharan R, Varadarajan Narayanan,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, david.brown-QSEj5FYQhm4dnm+yROfE0A,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA

On Wed, Jun 14, 2017 at 2:59 PM, Andy Gross <andy.gross-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> On Wed, Jun 14, 2017 at 12:57:25PM +0530, Sricharan R wrote:
>> Hi Varada,
>>
>> On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
>> > It's possible for a SPI transaction to complete and get another
>> > interrupt and have it processed on the same spi_transfer before the
>> > transfer_one can set it to NULL.
>> >
>> > This masks unexpected interrupts, so let's set the spi_transfer to
>> > NULL in the interrupt once the transaction is done. So we can
>> > properly detect these bad interrupts and print warning messages.
>> >
>> > Signed-off-by: Matthew McClintock <mmcclint-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>> > Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>> > ---
>> >  drivers/spi/spi-qup.c | 20 +++++++++++---------
>> >  1 file changed, 11 insertions(+), 9 deletions(-)
>> >
>> > diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
>> > index bd53e82..1a2a9d9 100644
>> > --- a/drivers/spi/spi-qup.c
>> > +++ b/drivers/spi/spi-qup.c
>> > @@ -496,13 +496,13 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>> >     struct spi_qup *controller = dev_id;
>> >     struct spi_transfer *xfer;
>> >     u32 opflags, qup_err, spi_err;
>> > -   unsigned long flags;
>> >     int error = 0;
>> > +   bool done = 0;
>> >
>> > -   spin_lock_irqsave(&controller->lock, flags);
>> > +   spin_lock(&controller->lock);
>> >     xfer = controller->xfer;
>> >     controller->xfer = NULL;
>> > -   spin_unlock_irqrestore(&controller->lock, flags);
>> > +   spin_unlock(&controller->lock);
>>
>>  Why change the locking here ?
>>
>> >
>> >     qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
>> >     spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
>> > @@ -556,16 +556,19 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>> >                     spi_qup_write(controller, xfer);
>> >     }
>> >
>> > -   spin_lock_irqsave(&controller->lock, flags);
>> > -   controller->error = error;
>> > -   controller->xfer = xfer;
>> > -   spin_unlock_irqrestore(&controller->lock, flags);
>> > -
>> >     /* re-read opflags as flags may have changed due to actions above */
>> >     opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
>> >
>> >     if ((controller->rx_bytes == xfer->len &&
>> >             (opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
>> > +           done = true;
>> > +
>> > +   spin_lock(&controller->lock);
>> > +   controller->error = error;
>> > +   controller->xfer = done ? NULL : xfer;
>> > +   spin_unlock(&controller->lock);
>> > +
>> > +   if (done)
>> >             complete(&controller->done);
>> >
>>   Its not clear, why the driver is setting the controller->xfer = NULL
>>   and restoring it inside the irq. This patch seems to fix things on
>>   top of that.
>
> I think the original intent was to make sure that the irqhandler knew that there
> was no outstanding transaction.  This begs the question of why that would ever
> be necessary.  I think it would suffice to rework all of that to remove that
> behavior and perhaps enable/disable the irq as we need to during transactions.
>
> I've never been a fan of the controller->xfer being set to NULL.

Also, this patch presumably fixes an issue seen on Dakota SoCs,
doesn't add or remote the NULL bits.

-M
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 07/18] spi: qup: Fix transaction done signaling
       [not found]         ` <20170614195155.GB32733-5taXn+FmohyKb9UB7mSz9QC/G2K4zDHf@public.gmane.org>
@ 2017-06-15  5:14           ` Sricharan R
  0 siblings, 0 replies; 34+ messages in thread
From: Sricharan R @ 2017-06-15  5:14 UTC (permalink / raw)
  To: Andy Gross
  Cc: Varadarajan Narayanan, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA

Hi Andy,

On 6/15/2017 1:21 AM, Andy Gross wrote:
> On Wed, Jun 14, 2017 at 12:43:43PM +0530, Sricharan R wrote:
>> Hi Varada,
>>
>> On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
>>> Wait to signal done until we get all of the interrupts we are expecting
>>> to get for a transaction.  If we don't wait for the input done flag, we
>>> can be inbetween transactions when the done flag comes in and this can
>>> mess up the next transaction.
>>>
>>> Signed-off-by: Andy Gross <andy.gross-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>>> Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>>> ---
>>>  drivers/spi/spi-qup.c | 3 ++-
>>>  1 file changed, 2 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
>>> index 2124815..7c22ee4 100644
>>> --- a/drivers/spi/spi-qup.c
>>> +++ b/drivers/spi/spi-qup.c
>>> @@ -465,7 +465,8 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>>>  	controller->xfer = xfer;
>>>  	spin_unlock_irqrestore(&controller->lock, flags);
>>>  
>>> -	if (controller->rx_bytes == xfer->len || error)
>>> +	if ((controller->rx_bytes == xfer->len &&
>>> +		(opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
>>
>>  Not sure why we need this additional check, because having read all the
>>  bytes implies transfer complete (or) why not just check only for
>>  QUP_OP_MAX_INPUT_DONE_FLAG ?
> 
> So you can receive an interrupt for the last data without it having also
> signalled the INPUT_DONE.  That means you'd have one more IRQ come in and if you
> don't wait for that, you could start up the next transaction and have an irq
> come in that screws up that transaction.
> 
> It might be sufficient to just wait for the INPUT_DONE_FLAG.  That cannot be
> signalled unless the rx_bytes == xfer->len.
> 

 Right, that should simply it little bit.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 11/18] spi: qup: properly detect extra interrupts
  2017-06-14 19:59       ` Andy Gross
       [not found]         ` <20170614195953.GD32733-5taXn+FmohyKb9UB7mSz9QC/G2K4zDHf@public.gmane.org>
@ 2017-06-15  5:27         ` Sricharan R
  1 sibling, 0 replies; 34+ messages in thread
From: Sricharan R @ 2017-06-15  5:27 UTC (permalink / raw)
  To: Andy Gross
  Cc: Varadarajan Narayanan, broonie, robh+dt, mark.rutland,
	david.brown, linux-spi, devicetree, linux-kernel, linux-arm-msm,
	linux-soc, Matthew McClintock

Hi Andy,

On 6/15/2017 1:29 AM, Andy Gross wrote:
> On Wed, Jun 14, 2017 at 12:57:25PM +0530, Sricharan R wrote:
>> Hi Varada,
>>
>> On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
>>> It's possible for a SPI transaction to complete and get another
>>> interrupt and have it processed on the same spi_transfer before the
>>> transfer_one can set it to NULL.
>>>
>>> This masks unexpected interrupts, so let's set the spi_transfer to
>>> NULL in the interrupt once the transaction is done. So we can
>>> properly detect these bad interrupts and print warning messages.
>>>
>>> Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
>>> Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
>>> ---
>>>  drivers/spi/spi-qup.c | 20 +++++++++++---------
>>>  1 file changed, 11 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
>>> index bd53e82..1a2a9d9 100644
>>> --- a/drivers/spi/spi-qup.c
>>> +++ b/drivers/spi/spi-qup.c
>>> @@ -496,13 +496,13 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>>>  	struct spi_qup *controller = dev_id;
>>>  	struct spi_transfer *xfer;
>>>  	u32 opflags, qup_err, spi_err;
>>> -	unsigned long flags;
>>>  	int error = 0;
>>> +	bool done = 0;
>>>  
>>> -	spin_lock_irqsave(&controller->lock, flags);
>>> +	spin_lock(&controller->lock);
>>>  	xfer = controller->xfer;
>>>  	controller->xfer = NULL;
>>> -	spin_unlock_irqrestore(&controller->lock, flags);
>>> +	spin_unlock(&controller->lock);
>>
>>  Why change the locking here ?
>>
>>>  
>>>  	qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
>>>  	spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
>>> @@ -556,16 +556,19 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>>>  			spi_qup_write(controller, xfer);
>>>  	}
>>>  
>>> -	spin_lock_irqsave(&controller->lock, flags);
>>> -	controller->error = error;
>>> -	controller->xfer = xfer;
>>> -	spin_unlock_irqrestore(&controller->lock, flags);
>>> -
>>>  	/* re-read opflags as flags may have changed due to actions above */
>>>  	opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
>>>  
>>>  	if ((controller->rx_bytes == xfer->len &&
>>>  		(opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
>>> +		done = true;
>>> +
>>> +	spin_lock(&controller->lock);
>>> +	controller->error = error;
>>> +	controller->xfer = done ? NULL : xfer;
>>> +	spin_unlock(&controller->lock);
>>> +
>>> +	if (done)
>>>  		complete(&controller->done);
>>>  
>>   Its not clear, why the driver is setting the controller->xfer = NULL
>>   and restoring it inside the irq. This patch seems to fix things on
>>   top of that.
> 
> I think the original intent was to make sure that the irqhandler knew that there
> was no outstanding transaction.  This begs the question of why that would ever
> be necessary.  I think it would suffice to rework all of that to remove that
> behavior and perhaps enable/disable the irq as we need to during transactions.
> 
> I've never been a fan of the controller->xfer being set to NULL.

 Agree, that part needs fixing in the original code. Also patch #10 changing the
 behavior to acknowledge the interrupts only when its spurious does not look
 correct. Trying to fix the original should simplify or avoid the spurious case
 itself.

Regards,
 Sricharan 

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* Re: [PATCH 10/18] spi: qup: Fix DMA mode interrupt handling
  2017-06-14 20:06       ` Andy Gross
@ 2017-06-15  5:52         ` Sricharan R
  0 siblings, 0 replies; 34+ messages in thread
From: Sricharan R @ 2017-06-15  5:52 UTC (permalink / raw)
  To: Andy Gross
  Cc: Varadarajan Narayanan, broonie, robh+dt, mark.rutland,
	david.brown, linux-spi, devicetree, linux-kernel, linux-arm-msm,
	linux-soc

Hi Andy,

On 6/15/2017 1:36 AM, Andy Gross wrote:
> On Wed, Jun 14, 2017 at 12:51:11PM +0530, Sricharan R wrote:
>> Hi Varada,
>>
>> On 6/14/2017 11:22 AM, Varadarajan Narayanan wrote:
>>> This is needed for v1, where the i/o completion is not
>>> handled in the dma driver.
>>>
>>> Signed-off-by: Andy Gross <andy.gross@linaro.org>
>>> Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
>>> ---
>>>  drivers/spi/spi-qup.c | 15 +++++++++++++--
>>>  1 file changed, 13 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
>>> index 872de28..bd53e82 100644
>>> --- a/drivers/spi/spi-qup.c
>>> +++ b/drivers/spi/spi-qup.c
>>> @@ -510,9 +510,9 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>>>  
>>>  	writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
>>>  	writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
>>> -	writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
>>>  
>>>  	if (!xfer) {
>>> +		writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
>>
>>  This does look correct to remove acknowledging the QUP in normal case and
>>   do it conditionally only when xfer = NULL.
> 
> This is to probably mask the issue of getting erroneous/spurious IRQs.
> 

 hmm, now the QUP_OPERATIONAL is not written to acknowledge the interrupts in
 normal case seems to be wrong.

>>
>>>  		dev_err_ratelimited(controller->dev, "unexpected irq %08x %08x %08x\n",
>>>  				    qup_err, spi_err, opflags);
>>>  		return IRQ_HANDLED;
>>> @@ -540,7 +540,15 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
>>>  		error = -EIO;
>>>  	}
>>>  
>>> -	if (!spi_qup_is_dma_xfer(controller->mode)) {
>>> +	if (spi_qup_is_dma_xfer(controller->mode)) {
>>> +		writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
>>> +		if (opflags & QUP_OP_IN_SERVICE_FLAG &&
>>> +		    opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
>>> +			complete(&controller->rxc);
>>> +		if (opflags & QUP_OP_OUT_SERVICE_FLAG &&
>>> +		    opflags & QUP_OP_MAX_OUTPUT_DONE_FLAG)
>>> +			complete(&controller->txc);
>>> +	} else {
>>
>>  Is this because in patch #8 that we do not populate the dma callback
>>  for v1. If that is done, this should not be required at all, as the
>>  complete would be signalled from the dma callback.
> 
> I believe that is true.  There shouldn't be any IRQs for DMA enabled
> transactions (at least BAM-dma).

 yeah, the above hunk looks like is ADM specific, not sure why ADM cannot
 work with dma callbacks.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

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

* Applied "spi: qup: Setup DMA mode correctly" to the spi tree
  2017-06-14  5:52   ` [PATCH 02/18] spi: qup: Setup DMA mode correctly Varadarajan Narayanan
@ 2017-08-08 11:18     ` Mark Brown
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Brown @ 2017-08-08 11:18 UTC (permalink / raw)
  To: Varadarajan Narayanan
  Cc: Andy Gross, Mark Brown, broonie, robh+dt, mark.rutland,
	andy.gross, david.brown, linux-spi, devicetree, linux-kernel,
	linux-arm-msm, linux-soc, linux-spi

The patch

   spi: qup: Setup DMA mode correctly

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 32ecab999f80370e5853cb907aa053ec4d64f86f Mon Sep 17 00:00:00 2001
From: Varadarajan Narayanan <varada@codeaurora.org>
Date: Fri, 28 Jul 2017 12:22:49 +0530
Subject: [PATCH] spi: qup: Setup DMA mode correctly

To operate in DMA mode, the buffer should be aligned and
the size of the transfer should be a multiple of block size
(for v1). And the no. of words being transferred should
be programmed in the count registers appropriately.

Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-qup.c | 118 +++++++++++++++++++++++---------------------------
 1 file changed, 55 insertions(+), 63 deletions(-)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index c0d4defc1c13..abe799bbc67f 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -149,11 +149,18 @@ struct spi_qup {
 	int			rx_bytes;
 	int			qup_v1;
 
-	int			use_dma;
+	int			mode;
 	struct dma_slave_config	rx_conf;
 	struct dma_slave_config	tx_conf;
 };
 
+static inline bool spi_qup_is_dma_xfer(int mode)
+{
+	if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM)
+		return true;
+
+	return false;
+}
 
 static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
 {
@@ -424,7 +431,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 		error = -EIO;
 	}
 
-	if (!controller->use_dma) {
+	if (!spi_qup_is_dma_xfer(controller->mode)) {
 		if (opflags & QUP_OP_IN_SERVICE_FLAG)
 			spi_qup_fifo_read(controller, xfer);
 
@@ -443,34 +450,11 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static u32
-spi_qup_get_mode(struct spi_master *master, struct spi_transfer *xfer)
-{
-	struct spi_qup *qup = spi_master_get_devdata(master);
-	u32 mode;
-
-	qup->w_size = 4;
-
-	if (xfer->bits_per_word <= 8)
-		qup->w_size = 1;
-	else if (xfer->bits_per_word <= 16)
-		qup->w_size = 2;
-
-	qup->n_words = xfer->len / qup->w_size;
-
-	if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
-		mode = QUP_IO_M_MODE_FIFO;
-	else
-		mode = QUP_IO_M_MODE_BLOCK;
-
-	return mode;
-}
-
 /* set clock freq ... bits per word */
 static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 {
 	struct spi_qup *controller = spi_master_get_devdata(spi->master);
-	u32 config, iomode, mode, control;
+	u32 config, iomode, control;
 	int ret, n_words;
 
 	if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
@@ -491,25 +475,30 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 		return -EIO;
 	}
 
-	mode = spi_qup_get_mode(spi->master, xfer);
+	controller->w_size = DIV_ROUND_UP(xfer->bits_per_word, 8);
+	controller->n_words = xfer->len / controller->w_size;
 	n_words = controller->n_words;
 
-	if (mode == QUP_IO_M_MODE_FIFO) {
+	if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
+
+		controller->mode = QUP_IO_M_MODE_FIFO;
+
 		writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
 		writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
 		/* must be zero for FIFO */
 		writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
 		writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
-	} else if (!controller->use_dma) {
+	} else if (spi->master->can_dma &&
+		   spi->master->can_dma(spi->master, spi, xfer) &&
+		   spi->master->cur_msg_mapped) {
+
+		controller->mode = QUP_IO_M_MODE_BAM;
+
 		writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
 		writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
 		/* must be zero for BLOCK and BAM */
 		writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
 		writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
-	} else {
-		mode = QUP_IO_M_MODE_BAM;
-		writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
-		writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
 
 		if (!controller->qup_v1) {
 			void __iomem *input_cnt;
@@ -528,19 +517,28 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 
 			writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
 		}
+	} else {
+
+		controller->mode = QUP_IO_M_MODE_BLOCK;
+
+		writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
+		writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+		/* must be zero for BLOCK and BAM */
+		writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+		writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
 	}
 
 	iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
 	/* Set input and output transfer mode */
 	iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
 
-	if (!controller->use_dma)
+	if (!spi_qup_is_dma_xfer(controller->mode))
 		iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
 	else
 		iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
 
-	iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
-	iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+	iomode |= (controller->mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+	iomode |= (controller->mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
 
 	writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
 
@@ -581,7 +579,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 	config |= xfer->bits_per_word - 1;
 	config |= QUP_CONFIG_SPI_MODE;
 
-	if (controller->use_dma) {
+	if (spi_qup_is_dma_xfer(controller->mode)) {
 		if (!xfer->tx_buf)
 			config |= QUP_CONFIG_NO_OUTPUT;
 		if (!xfer->rx_buf)
@@ -599,7 +597,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
 		 * status change in BAM mode
 		 */
 
-		if (mode == QUP_IO_M_MODE_BAM)
+		if (spi_qup_is_dma_xfer(controller->mode))
 			mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG;
 
 		writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK);
@@ -633,7 +631,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	controller->tx_bytes = 0;
 	spin_unlock_irqrestore(&controller->lock, flags);
 
-	if (controller->use_dma)
+	if (spi_qup_is_dma_xfer(controller->mode))
 		ret = spi_qup_do_dma(master, xfer);
 	else
 		ret = spi_qup_do_pio(master, xfer);
@@ -641,14 +639,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
 	if (ret)
 		goto exit;
 
-	if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
-		dev_warn(controller->dev, "cannot set EXECUTE state\n");
-		goto exit;
-	}
-
-	if (!wait_for_completion_timeout(&controller->done, timeout))
-		ret = -ETIMEDOUT;
-
 exit:
 	spi_qup_set_state(controller, QUP_STATE_RESET);
 	spin_lock_irqsave(&controller->lock, flags);
@@ -657,7 +647,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
 		ret = controller->error;
 	spin_unlock_irqrestore(&controller->lock, flags);
 
-	if (ret && controller->use_dma)
+	if (ret && spi_qup_is_dma_xfer(controller->mode))
 		spi_qup_dma_terminate(master, xfer);
 
 	return ret;
@@ -668,26 +658,28 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
 {
 	struct spi_qup *qup = spi_master_get_devdata(master);
 	size_t dma_align = dma_get_cache_alignment();
-	u32 mode;
-
-	qup->use_dma = 0;
+	int n_words;
 
-	if (xfer->rx_buf && (xfer->len % qup->in_blk_sz ||
-	    IS_ERR_OR_NULL(master->dma_rx) ||
-	    !IS_ALIGNED((size_t)xfer->rx_buf, dma_align)))
-		return false;
+	if (xfer->rx_buf) {
+		if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) ||
+		    IS_ERR_OR_NULL(master->dma_rx))
+			return false;
+		if (qup->qup_v1 && (xfer->len % qup->in_blk_sz))
+			return false;
+	}
 
-	if (xfer->tx_buf && (xfer->len % qup->out_blk_sz ||
-	    IS_ERR_OR_NULL(master->dma_tx) ||
-	    !IS_ALIGNED((size_t)xfer->tx_buf, dma_align)))
-		return false;
+	if (xfer->tx_buf) {
+		if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) ||
+		    IS_ERR_OR_NULL(master->dma_tx))
+			return false;
+		if (qup->qup_v1 && (xfer->len % qup->out_blk_sz))
+			return false;
+	}
 
-	mode = spi_qup_get_mode(master, xfer);
-	if (mode == QUP_IO_M_MODE_FIFO)
+	n_words = xfer->len / DIV_ROUND_UP(xfer->bits_per_word, 8);
+	if (n_words <= (qup->in_fifo_sz / sizeof(u32)))
 		return false;
 
-	qup->use_dma = 1;
-
 	return true;
 }
 
-- 
2.13.2

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

* Applied "spi: qup: Enable chip select support" to the spi tree
  2017-06-14  5:52 ` [PATCH 01/18] spi: qup: Enable chip select support Varadarajan Narayanan
  2017-06-14  9:47   ` Stanimir Varbanov
@ 2017-08-08 11:18   ` Mark Brown
  1 sibling, 0 replies; 34+ messages in thread
From: Mark Brown @ 2017-08-08 11:18 UTC (permalink / raw)
  To: Varadarajan Narayanan
  Cc: Sham Muthayyan, Mark Brown, broonie, robh+dt, mark.rutland,
	andy.gross, david.brown, linux-spi, devicetree, linux-kernel,
	linux-arm-msm, linux-soc, Sham Muthayyan, linux-spi

The patch

   spi: qup: Enable chip select support

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From b702b9fb393ed1c19ab3ecb1552757522c982746 Mon Sep 17 00:00:00 2001
From: Varadarajan Narayanan <varada@codeaurora.org>
Date: Fri, 28 Jul 2017 12:22:48 +0530
Subject: [PATCH] spi: qup: Enable chip select support

Enable chip select support for QUP versions later than v1. The
chip select support was broken in QUP version 1. Hence the chip
select support was removed earlier in an earlier commit
(4a8573abe "spi: qup: Remove chip select function"). Since the
chip select support is functional in recent versions of QUP,
re-enabling it for QUP versions later than v1.

Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-qup.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 1bfa889b8427..c0d4defc1c13 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -750,6 +750,24 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
 	return ret;
 }
 
+static void spi_qup_set_cs(struct spi_device *spi, bool val)
+{
+	struct spi_qup *controller;
+	u32 spi_ioc;
+	u32 spi_ioc_orig;
+
+	controller = spi_master_get_devdata(spi->master);
+	spi_ioc = readl_relaxed(controller->base + SPI_IO_CONTROL);
+	spi_ioc_orig = spi_ioc;
+	if (!val)
+		spi_ioc |= SPI_IO_C_FORCE_CS;
+	else
+		spi_ioc &= ~SPI_IO_C_FORCE_CS;
+
+	if (spi_ioc != spi_ioc_orig)
+		writel_relaxed(spi_ioc, controller->base + SPI_IO_CONTROL);
+}
+
 static int spi_qup_probe(struct platform_device *pdev)
 {
 	struct spi_master *master;
@@ -846,6 +864,9 @@ static int spi_qup_probe(struct platform_device *pdev)
 	if (of_device_is_compatible(dev->of_node, "qcom,spi-qup-v1.1.1"))
 		controller->qup_v1 = 1;
 
+	if (!controller->qup_v1)
+		master->set_cs = spi_qup_set_cs;
+
 	spin_lock_init(&controller->lock);
 	init_completion(&controller->done);
 
-- 
2.13.2

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

end of thread, other threads:[~2017-08-08 11:18 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-14  5:52 [PATCH 00/18] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 01/18] spi: qup: Enable chip select support Varadarajan Narayanan
2017-06-14  9:47   ` Stanimir Varbanov
2017-08-08 11:18   ` Applied "spi: qup: Enable chip select support" to the spi tree Mark Brown
     [not found] ` <1497419551-21834-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2017-06-14  5:52   ` [PATCH 02/18] spi: qup: Setup DMA mode correctly Varadarajan Narayanan
2017-08-08 11:18     ` Applied "spi: qup: Setup DMA mode correctly" to the spi tree Mark Brown
2017-06-14  5:52   ` [PATCH 06/18] spi: qup: Fix error handling in spi_qup_prep_sg Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 03/18] spi: qup: Add completion timeout for dma mode Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 04/18] spi: qup: Add completion timeout for fifo/block mode Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 05/18] spi: qup: Place the QUP in run mode before DMA transactions Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 07/18] spi: qup: Fix transaction done signaling Varadarajan Narayanan
2017-06-14  7:13   ` Sricharan R
     [not found]     ` <4b81a4c7-b85c-a35d-15fb-4aaaec3c7e8c-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2017-06-14 19:51       ` Andy Gross
     [not found]         ` <20170614195155.GB32733-5taXn+FmohyKb9UB7mSz9QC/G2K4zDHf@public.gmane.org>
2017-06-15  5:14           ` Sricharan R
2017-06-14  5:52 ` [PATCH 08/18] spi: qup: Handle v1 dma completion differently Varadarajan Narayanan
     [not found]   ` <1497419551-21834-9-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2017-06-14  7:15     ` Sricharan R
     [not found]       ` <a0e499a7-8f89-96d6-9463-c2b3f774cd6d-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2017-06-14 19:53         ` Andy Gross
2017-06-14  5:52 ` [PATCH 09/18] spi: qup: Do block sized read/write in block mode Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 10/18] spi: qup: Fix DMA mode interrupt handling Varadarajan Narayanan
2017-06-14  7:21   ` Sricharan R
     [not found]     ` <66ba7dfb-6ff3-884e-6db0-8d5191f87c93-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2017-06-14 20:06       ` Andy Gross
2017-06-15  5:52         ` Sricharan R
2017-06-14  5:52 ` [PATCH 11/18] spi: qup: properly detect extra interrupts Varadarajan Narayanan
     [not found]   ` <1497419551-21834-12-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2017-06-14  7:27     ` Sricharan R
2017-06-14 19:59       ` Andy Gross
     [not found]         ` <20170614195953.GD32733-5taXn+FmohyKb9UB7mSz9QC/G2K4zDHf@public.gmane.org>
2017-06-14 21:51           ` Matthew McClintock
2017-06-15  5:27         ` Sricharan R
2017-06-14  5:52 ` [PATCH 12/18] spi: qup: refactor spi_qup_io_config into two functions Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 13/18] spi: qup: call io_config in mode specific function Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 14/18] spi: qup: allow block mode to generate multiple transactions Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 15/18] spi: qup: refactor spi_qup_prep_sg Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 16/18] spi: qup: allow multiple DMA transactions per spi xfer Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 17/18] spi: qup: Ensure done detection Varadarajan Narayanan
2017-06-14  5:52 ` [PATCH 18/18] spi: qup: support for qup v1 dma Varadarajan Narayanan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).