public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Eric Anholt <eric@anholt.net>
To: linux-rpi-kernel@lists.infradead.org
Cc: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org,
	Stephen Warren <swarren@wwwdotorg.org>,
	Lee Jones <lee@kernel.org>, Vinod Koul <vinod.koul@intel.com>,
	dmaengine@vger.kernel.org, Martin Sperl <kernel@martin.sperl.org>,
	Eric Anholt <eric@anholt.net>
Subject: [PATCH 6/8] dmaengine: bcm2835: limit max length based on channel type
Date: Wed, 16 Mar 2016 12:25:00 -0700	[thread overview]
Message-ID: <1458156302-4359-7-git-send-email-eric@anholt.net> (raw)
In-Reply-To: <1458156302-4359-1-git-send-email-eric@anholt.net>

From: Martin Sperl <kernel@martin.sperl.org>

The bcm2835 dma system has 2 basic types of dma-channels:
* "normal" channels
* "light" channels

Lite channels are limited in several aspects:
* internal data-structure is 128 bit (not 256)
* does not support BCM2835_DMA_TDMODE (2D)
* DMA length register is limited to 16 bit.
  so 0-65535 (not 0-65536 as mentioned in the official datasheet)
* BCM2835_DMA_S/D_IGNORE are not supported

The detection of the type of mode is implemented by looking at
the LITE bit in the DEBUG register for each channel.
This allows automatic detection.

Based on this the maximum block size is set to (64K - 4) or to 1G
and this limit is honored during generation of control block
chains. The effect is that when a LITE channel is used more
control blocks are used to do the same transfer (compared
to a normal channel).

As there are several sources/target DREQS that are 32 bit wide
we need to have the transfer to be a multiple of 4 as this would
break the transfer otherwise.

This is why the limit of (64K - 4) was chosen over the
alternative of (64K - 4K).

Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Eric Anholt <eric@anholt.net>
---
 drivers/dma/bcm2835-dma.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 4db0e23..59c5ef3 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -81,6 +81,8 @@ struct bcm2835_chan {
 
 	void __iomem *chan_base;
 	int irq_number;
+
+	bool is_lite_channel;
 };
 
 struct bcm2835_desc {
@@ -169,6 +171,16 @@ struct bcm2835_desc {
 #define BCM2835_DMA_CHAN(n)	((n) << 8) /* Base address */
 #define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
 
+/* the max dma length for different channels */
+#define MAX_DMA_LEN SZ_1G
+#define MAX_LITE_DMA_LEN (SZ_64K - 4)
+
+static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
+{
+	/* lite and normal channels have different max frame length */
+	return c->is_lite_channel ? MAX_LITE_DMA_LEN : MAX_DMA_LEN;
+}
+
 /* how many frames of max_len size do we need to transfer len bytes */
 static inline size_t bcm2835_dma_frames_for_length(size_t len,
 						   size_t max_len)
@@ -217,8 +229,10 @@ static void bcm2835_dma_create_cb_set_length(
 	size_t *total_len,
 	u32 finalextrainfo)
 {
-	/* set the length */
-	control_block->length = len;
+	size_t max_len = bcm2835_dma_max_frame_length(chan);
+
+	/* set the length taking lite-channel limitations into account */
+	control_block->length = min_t(u32, len, max_len);
 
 	/* finished if we have no period_length */
 	if (!period_len)
@@ -544,6 +558,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
 	dma_addr_t src, dst;
 	u32 info = BCM2835_DMA_WAIT_RESP;
 	u32 extra = BCM2835_DMA_INT_EN;
+	size_t max_len = bcm2835_dma_max_frame_length(c);
 	size_t frames;
 
 	/* Grab configuration */
@@ -586,7 +601,10 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
 	}
 
 	/* calculate number of frames */
-	frames = DIV_ROUND_UP(buf_len, period_len);
+	frames = /* number of periods */
+		 DIV_ROUND_UP(buf_len, period_len) *
+		 /* number of frames per period */
+		 bcm2835_dma_frames_for_length(period_len, max_len);
 
 	/*
 	 * allocate the CB chain
@@ -685,6 +703,11 @@ static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq)
 	c->ch = chan_id;
 	c->irq_number = irq;
 
+	/* check in DEBUG register if this is a LITE channel */
+	if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
+		BCM2835_DMA_DEBUG_LITE)
+		c->is_lite_channel = true;
+
 	return 0;
 }
 
-- 
2.7.0

  parent reply	other threads:[~2016-03-16 19:25 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-16 19:24 [PATCH 0/8 v4] bcm2835 DMA slave support Eric Anholt
2016-03-16 19:24 ` [PATCH 1/8] dmaengine: bcm2835: set residue_granularity field Eric Anholt
2016-03-16 19:24 ` [PATCH 2/8] dmaengine: bcm2835: remove unnecessary masking of dma channels Eric Anholt
2016-03-16 19:24 ` [PATCH 3/8] dmaengine: bcm2835: add additional defines for DMA-registers Eric Anholt
2016-03-16 19:24 ` [PATCH 4/8] dmaengine: bcm2835: move cyclic member from bcm2835_chan into bcm2835_desc Eric Anholt
2016-03-16 19:24 ` [PATCH 5/8] dmaengine: bcm2835: move controlblock chain generation into separate method Eric Anholt
2016-03-16 19:25 ` Eric Anholt [this message]
2016-03-16 19:25 ` [PATCH 7/8] dmaengine: bcm2835: add slave_sg support to bcm2835-dma Eric Anholt
2016-03-16 19:25 ` [PATCH 8/8] dmaengine: bcm2835: add dma_memcopy " Eric Anholt
2016-03-17 10:22 ` [PATCH 0/8 v4] bcm2835 DMA slave support Martin Sperl
2016-03-17 13:17 ` Martin Sperl
2016-04-05 18:03 ` Vinod Koul

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1458156302-4359-7-git-send-email-eric@anholt.net \
    --to=eric@anholt.net \
    --cc=dmaengine@vger.kernel.org \
    --cc=kernel@martin.sperl.org \
    --cc=lee@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rpi-kernel@lists.infradead.org \
    --cc=swarren@wwwdotorg.org \
    --cc=vinod.koul@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox