123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- From 690414c3621a694fc4ace6775ae3c11e64da2895 Mon Sep 17 00:00:00 2001
- From: Martin Sperl <kernel@martin.sperl.org>
- Date: Wed, 16 Mar 2016 12:25:00 -0700
- Subject: [PATCH] dmaengine: bcm2835: limit max length based on channel type
- 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>
- Signed-off-by: Vinod Koul <vinod.koul@intel.com>
- ---
- drivers/dma/bcm2835-dma.c | 29 ++++++++++++++++++++++++++---
- 1 file changed, 26 insertions(+), 3 deletions(-)
- --- 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_le
- 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 *b
- 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 *b
- }
-
- /* 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
- 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;
- }
-
|