Loading Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt +26 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,10 @@ Required properties: - reg: Should contain DMA registers location and length. - interrupts: Should contain the DMA interrupts associated to the DMA channels in ascending order. - interrupt-names: Should contain the names of the interrupt in the form "dmaXX". Use "dma-shared-all" for the common interrupt line that is shared by all dma channels. - #dma-cells: Must be <1>, the cell in the dmas property of the client device represents the DREQ number. - brcm,dma-channel-mask: Bit mask representing the channels Loading @@ -34,13 +38,35 @@ dma: dma@7e007000 { <1 24>, <1 25>, <1 26>, /* dma channel 11-14 share one irq */ <1 27>, <1 27>, <1 27>, <1 27>, /* unused shared irq for all channels */ <1 28>; interrupt-names = "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6", "dma7", "dma8", "dma9", "dma10", "dma11", "dma12", "dma13", "dma14", "dma-shared-all"; #dma-cells = <1>; brcm,dma-channel-mask = <0x7f35>; }; DMA clients connected to the BCM2835 DMA controller must use the format described in the dma.txt file, using a two-cell specifier for each channel. Loading arch/arm/boot/dts/bcm283x.dtsi +21 −1 Original line number Diff line number Diff line Loading @@ -47,9 +47,29 @@ <1 24>, <1 25>, <1 26>, /* dma channel 11-14 share one irq */ <1 27>, <1 27>, <1 27>, <1 27>, /* unused shared irq for all channels */ <1 28>; interrupt-names = "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6", "dma7", "dma8", "dma9", "dma10", "dma11", "dma12", "dma13", "dma14", "dma-shared-all"; #dma-cells = <1>; brcm,dma-channel-mask = <0x7f35>; }; Loading drivers/dma/bcm2835-dma.c +474 −130 Original line number Diff line number Diff line Loading @@ -46,6 +46,9 @@ #include "virt-dma.h" #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14 #define BCM2835_DMA_CHAN_NAME_SIZE 8 struct bcm2835_dmadev { struct dma_device ddev; spinlock_t lock; Loading Loading @@ -73,7 +76,6 @@ struct bcm2835_chan { struct list_head node; struct dma_slave_config cfg; bool cyclic; unsigned int dreq; int ch; Loading @@ -82,6 +84,9 @@ struct bcm2835_chan { void __iomem *chan_base; int irq_number; unsigned int irq_flags; bool is_lite_channel; }; struct bcm2835_desc { Loading @@ -89,47 +94,104 @@ struct bcm2835_desc { struct virt_dma_desc vd; enum dma_transfer_direction dir; struct bcm2835_cb_entry *cb_list; unsigned int frames; size_t size; bool cyclic; struct bcm2835_cb_entry cb_list[]; }; #define BCM2835_DMA_CS 0x00 #define BCM2835_DMA_ADDR 0x04 #define BCM2835_DMA_TI 0x08 #define BCM2835_DMA_SOURCE_AD 0x0c #define BCM2835_DMA_DEST_AD 0x10 #define BCM2835_DMA_NEXTCB 0x1C #define BCM2835_DMA_LEN 0x14 #define BCM2835_DMA_STRIDE 0x18 #define BCM2835_DMA_NEXTCB 0x1c #define BCM2835_DMA_DEBUG 0x20 /* DMA CS Control and Status bits */ #define BCM2835_DMA_ACTIVE BIT(0) #define BCM2835_DMA_INT BIT(2) #define BCM2835_DMA_ACTIVE BIT(0) /* activate the DMA */ #define BCM2835_DMA_END BIT(1) /* current CB has ended */ #define BCM2835_DMA_INT BIT(2) /* interrupt status */ #define BCM2835_DMA_DREQ BIT(3) /* DREQ state */ #define BCM2835_DMA_ISPAUSED BIT(4) /* Pause requested or not active */ #define BCM2835_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */ #define BCM2835_DMA_WAITING_FOR_WRITES BIT(6) /* waiting for last * AXI-write to ack */ #define BCM2835_DMA_ERR BIT(8) #define BCM2835_DMA_PRIORITY(x) ((x & 15) << 16) /* AXI priority */ #define BCM2835_DMA_PANIC_PRIORITY(x) ((x & 15) << 20) /* panic priority */ /* current value of TI.BCM2835_DMA_WAIT_RESP */ #define BCM2835_DMA_WAIT_FOR_WRITES BIT(28) #define BCM2835_DMA_DIS_DEBUG BIT(29) /* disable debug pause signal */ #define BCM2835_DMA_ABORT BIT(30) /* Stop current CB, go to next, WO */ #define BCM2835_DMA_RESET BIT(31) /* WO, self clearing */ /* Transfer information bits - also bcm2835_cb.info field */ #define BCM2835_DMA_INT_EN BIT(0) #define BCM2835_DMA_TDMODE BIT(1) /* 2D-Mode */ #define BCM2835_DMA_WAIT_RESP BIT(3) /* wait for AXI-write to be acked */ #define BCM2835_DMA_D_INC BIT(4) #define BCM2835_DMA_D_DREQ BIT(6) #define BCM2835_DMA_D_WIDTH BIT(5) /* 128bit writes if set */ #define BCM2835_DMA_D_DREQ BIT(6) /* enable DREQ for destination */ #define BCM2835_DMA_D_IGNORE BIT(7) /* ignore destination writes */ #define BCM2835_DMA_S_INC BIT(8) #define BCM2835_DMA_S_DREQ BIT(10) #define BCM2835_DMA_PER_MAP(x) ((x) << 16) #define BCM2835_DMA_S_WIDTH BIT(9) /* 128bit writes if set */ #define BCM2835_DMA_S_DREQ BIT(10) /* enable SREQ for source */ #define BCM2835_DMA_S_IGNORE BIT(11) /* ignore source reads - read 0 */ #define BCM2835_DMA_BURST_LENGTH(x) ((x & 15) << 12) #define BCM2835_DMA_PER_MAP(x) ((x & 31) << 16) /* REQ source */ #define BCM2835_DMA_WAIT(x) ((x & 31) << 21) /* add DMA-wait cycles */ #define BCM2835_DMA_NO_WIDE_BURSTS BIT(26) /* no 2 beat write bursts */ /* debug register bits */ #define BCM2835_DMA_DEBUG_LAST_NOT_SET_ERR BIT(0) #define BCM2835_DMA_DEBUG_FIFO_ERR BIT(1) #define BCM2835_DMA_DEBUG_READ_ERR BIT(2) #define BCM2835_DMA_DEBUG_OUTSTANDING_WRITES_SHIFT 4 #define BCM2835_DMA_DEBUG_OUTSTANDING_WRITES_BITS 4 #define BCM2835_DMA_DEBUG_ID_SHIFT 16 #define BCM2835_DMA_DEBUG_ID_BITS 9 #define BCM2835_DMA_DEBUG_STATE_SHIFT 16 #define BCM2835_DMA_DEBUG_STATE_BITS 9 #define BCM2835_DMA_DEBUG_VERSION_SHIFT 25 #define BCM2835_DMA_DEBUG_VERSION_BITS 3 #define BCM2835_DMA_DEBUG_LITE BIT(28) /* shared registers for all dma channels */ #define BCM2835_DMA_INT_STATUS 0xfe0 #define BCM2835_DMA_ENABLE 0xff0 #define BCM2835_DMA_DATA_TYPE_S8 1 #define BCM2835_DMA_DATA_TYPE_S16 2 #define BCM2835_DMA_DATA_TYPE_S32 4 #define BCM2835_DMA_DATA_TYPE_S128 16 #define BCM2835_DMA_BULK_MASK BIT(0) #define BCM2835_DMA_FIQ_MASK (BIT(2) | BIT(3)) /* Valid only for channels 0 - 14, 15 has its own base address */ #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) { return DIV_ROUND_UP(len, max_len); } static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d) { return container_of(d, struct bcm2835_dmadev, ddev); Loading @@ -146,19 +208,209 @@ static inline struct bcm2835_desc *to_bcm2835_dma_desc( return container_of(t, struct bcm2835_desc, vd.tx); } static void bcm2835_dma_desc_free(struct virt_dma_desc *vd) static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc) { struct bcm2835_desc *desc = container_of(vd, struct bcm2835_desc, vd); int i; size_t i; for (i = 0; i < desc->frames; i++) dma_pool_free(desc->c->cb_pool, desc->cb_list[i].cb, desc->cb_list[i].paddr); kfree(desc->cb_list); kfree(desc); } static void bcm2835_dma_desc_free(struct virt_dma_desc *vd) { bcm2835_dma_free_cb_chain( container_of(vd, struct bcm2835_desc, vd)); } static void bcm2835_dma_create_cb_set_length( struct bcm2835_chan *chan, struct bcm2835_dma_cb *control_block, size_t len, size_t period_len, size_t *total_len, u32 finalextrainfo) { 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) return; /* * period_len means: that we need to generate * transfers that are terminating at every * multiple of period_len - this is typically * used to set the interrupt flag in info * which is required during cyclic transfers */ /* have we filled in period_length yet? */ if (*total_len + control_block->length < period_len) return; /* calculate the length that remains to reach period_length */ control_block->length = period_len - *total_len; /* reset total_length for next period */ *total_len = 0; /* add extrainfo bits in info */ control_block->info |= finalextrainfo; } static inline size_t bcm2835_dma_count_frames_for_sg( struct bcm2835_chan *c, struct scatterlist *sgl, unsigned int sg_len) { size_t frames = 0; struct scatterlist *sgent; unsigned int i; size_t plength = bcm2835_dma_max_frame_length(c); for_each_sg(sgl, sgent, sg_len, i) frames += bcm2835_dma_frames_for_length( sg_dma_len(sgent), plength); return frames; } /** * bcm2835_dma_create_cb_chain - create a control block and fills data in * * @chan: the @dma_chan for which we run this * @direction: the direction in which we transfer * @cyclic: it is a cyclic transfer * @info: the default info bits to apply per controlblock * @frames: number of controlblocks to allocate * @src: the src address to assign (if the S_INC bit is set * in @info, then it gets incremented) * @dst: the dst address to assign (if the D_INC bit is set * in @info, then it gets incremented) * @buf_len: the full buffer length (may also be 0) * @period_len: the period length when to apply @finalextrainfo * in addition to the last transfer * this will also break some control-blocks early * @finalextrainfo: additional bits in last controlblock * (or when period_len is reached in case of cyclic) * @gfp: the GFP flag to use for allocation */ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( struct dma_chan *chan, enum dma_transfer_direction direction, bool cyclic, u32 info, u32 finalextrainfo, size_t frames, dma_addr_t src, dma_addr_t dst, size_t buf_len, size_t period_len, gfp_t gfp) { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); size_t len = buf_len, total_len; size_t frame; struct bcm2835_desc *d; struct bcm2835_cb_entry *cb_entry; struct bcm2835_dma_cb *control_block; if (!frames) return NULL; /* allocate and setup the descriptor. */ d = kzalloc(sizeof(*d) + frames * sizeof(struct bcm2835_cb_entry), gfp); if (!d) return NULL; d->c = c; d->dir = direction; d->cyclic = cyclic; /* * Iterate over all frames, create a control block * for each frame and link them together. */ for (frame = 0, total_len = 0; frame < frames; d->frames++, frame++) { cb_entry = &d->cb_list[frame]; cb_entry->cb = dma_pool_alloc(c->cb_pool, gfp, &cb_entry->paddr); if (!cb_entry->cb) goto error_cb; /* fill in the control block */ control_block = cb_entry->cb; control_block->info = info; control_block->src = src; control_block->dst = dst; control_block->stride = 0; control_block->next = 0; /* set up length in control_block if requested */ if (buf_len) { /* calculate length honoring period_length */ bcm2835_dma_create_cb_set_length( c, control_block, len, period_len, &total_len, cyclic ? finalextrainfo : 0); /* calculate new remaining length */ len -= control_block->length; } /* link this the last controlblock */ if (frame) d->cb_list[frame - 1].cb->next = cb_entry->paddr; /* update src and dst and length */ if (src && (info & BCM2835_DMA_S_INC)) src += control_block->length; if (dst && (info & BCM2835_DMA_D_INC)) dst += control_block->length; /* Length of total transfer */ d->size += control_block->length; } /* the last frame requires extra flags */ d->cb_list[d->frames - 1].cb->info |= finalextrainfo; /* detect a size missmatch */ if (buf_len && (d->size != buf_len)) goto error_cb; return d; error_cb: bcm2835_dma_free_cb_chain(d); return NULL; } static void bcm2835_dma_fill_cb_chain_with_sg( struct dma_chan *chan, enum dma_transfer_direction direction, struct bcm2835_cb_entry *cb, struct scatterlist *sgl, unsigned int sg_len) { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); size_t max_len = bcm2835_dma_max_frame_length(c); unsigned int i, len; dma_addr_t addr; struct scatterlist *sgent; for_each_sg(sgl, sgent, sg_len, i) { for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent); len > 0; addr += cb->cb->length, len -= cb->cb->length, cb++) { if (direction == DMA_DEV_TO_MEM) cb->cb->dst = addr; else cb->cb->src = addr; cb->cb->length = min(len, max_len); } } } static int bcm2835_dma_abort(void __iomem *chan_base) { unsigned long cs; Loading Loading @@ -218,6 +470,15 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data) struct bcm2835_desc *d; unsigned long flags; /* check the shared interrupt */ if (c->irq_flags & IRQF_SHARED) { /* check if the interrupt is enabled */ flags = readl(c->chan_base + BCM2835_DMA_CS); /* if not set then we are not the reason for the irq */ if (!(flags & BCM2835_DMA_INT)) return IRQ_NONE; } spin_lock_irqsave(&c->vc.lock, flags); /* Acknowledge interrupt */ Loading @@ -226,12 +487,18 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data) d = c->desc; if (d) { /* TODO Only works for cyclic DMA */ if (d->cyclic) { /* call the cyclic callback */ vchan_cyclic_callback(&d->vd); } /* Keep the DMA engine running */ writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); } else { vchan_cookie_complete(&c->desc->vd); bcm2835_dma_start_desc(c); } } spin_unlock_irqrestore(&c->vc.lock, flags); Loading @@ -252,8 +519,8 @@ static int bcm2835_dma_alloc_chan_resources(struct dma_chan *chan) return -ENOMEM; } return request_irq(c->irq_number, bcm2835_dma_callback, 0, "DMA IRQ", c); return request_irq(c->irq_number, bcm2835_dma_callback, c->irq_flags, "DMA IRQ", c); } static void bcm2835_dma_free_chan_resources(struct dma_chan *chan) Loading Loading @@ -339,8 +606,6 @@ static void bcm2835_dma_issue_pending(struct dma_chan *chan) struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); unsigned long flags; c->cyclic = true; /* Nothing else is implemented */ spin_lock_irqsave(&c->vc.lock, flags); if (vchan_issue_pending(&c->vc) && !c->desc) bcm2835_dma_start_desc(c); Loading @@ -348,122 +613,160 @@ static void bcm2835_dma_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&c->vc.lock, flags); } static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, unsigned long flags) struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy( struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, size_t len, unsigned long flags) { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); enum dma_slave_buswidth dev_width; struct bcm2835_desc *d; dma_addr_t dev_addr; unsigned int es, sync_type; unsigned int frame; int i; u32 info = BCM2835_DMA_D_INC | BCM2835_DMA_S_INC; u32 extra = BCM2835_DMA_INT_EN | BCM2835_DMA_WAIT_RESP; size_t max_len = bcm2835_dma_max_frame_length(c); size_t frames; /* if src, dst or len is not given return with an error */ if (!src || !dst || !len) return NULL; /* calculate number of frames */ frames = bcm2835_dma_frames_for_length(len, max_len); /* allocate the CB chain - this also fills in the pointers */ d = bcm2835_dma_create_cb_chain(chan, DMA_MEM_TO_MEM, false, info, extra, frames, src, dst, len, 0, GFP_KERNEL); if (!d) return NULL; return vchan_tx_prep(&c->vc, &d->vd, flags); } static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags, void *context) { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); struct bcm2835_desc *d; dma_addr_t src = 0, dst = 0; u32 info = BCM2835_DMA_WAIT_RESP; u32 extra = BCM2835_DMA_INT_EN; size_t frames; /* Grab configuration */ if (!is_slave_direction(direction)) { dev_err(chan->device->dev, "%s: bad direction?\n", __func__); dev_err(chan->device->dev, "%s: bad direction?\n", __func__); return NULL; } if (c->dreq != 0) info |= BCM2835_DMA_PER_MAP(c->dreq); if (direction == DMA_DEV_TO_MEM) { dev_addr = c->cfg.src_addr; dev_width = c->cfg.src_addr_width; sync_type = BCM2835_DMA_S_DREQ; if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; src = c->cfg.src_addr; info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC; } else { dev_addr = c->cfg.dst_addr; dev_width = c->cfg.dst_addr_width; sync_type = BCM2835_DMA_D_DREQ; } /* Bus width translates to the element size (ES) */ switch (dev_width) { case DMA_SLAVE_BUSWIDTH_4_BYTES: es = BCM2835_DMA_DATA_TYPE_S32; break; default: if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; dst = c->cfg.dst_addr; info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; } /* Now allocate and setup the descriptor. */ d = kzalloc(sizeof(*d), GFP_NOWAIT); /* count frames in sg list */ frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len); /* allocate the CB chain */ d = bcm2835_dma_create_cb_chain(chan, direction, false, info, extra, frames, src, dst, 0, 0, GFP_KERNEL); if (!d) return NULL; d->c = c; d->dir = direction; d->frames = buf_len / period_len; /* fill in frames with scatterlist pointers */ bcm2835_dma_fill_cb_chain_with_sg(chan, direction, d->cb_list, sgl, sg_len); return vchan_tx_prep(&c->vc, &d->vd, flags); } d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL); if (!d->cb_list) { kfree(d); static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, unsigned long flags) { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); struct bcm2835_desc *d; 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 */ if (!is_slave_direction(direction)) { dev_err(chan->device->dev, "%s: bad direction?\n", __func__); return NULL; } /* Allocate memory for control blocks */ for (i = 0; i < d->frames; i++) { struct bcm2835_cb_entry *cb_entry = &d->cb_list[i]; cb_entry->cb = dma_pool_zalloc(c->cb_pool, GFP_ATOMIC, &cb_entry->paddr); if (!cb_entry->cb) goto error_cb; if (!buf_len) { dev_err(chan->device->dev, "%s: bad buffer length (= 0)\n", __func__); return NULL; } /* * Iterate over all frames, create a control block * for each frame and link them together. * warn if buf_len is not a multiple of period_len - this may leed * to unexpected latencies for interrupts and thus audiable clicks */ for (frame = 0; frame < d->frames; frame++) { struct bcm2835_dma_cb *control_block = d->cb_list[frame].cb; /* Setup adresses */ if (d->dir == DMA_DEV_TO_MEM) { control_block->info = BCM2835_DMA_D_INC; control_block->src = dev_addr; control_block->dst = buf_addr + frame * period_len; } else { control_block->info = BCM2835_DMA_S_INC; control_block->src = buf_addr + frame * period_len; control_block->dst = dev_addr; } /* Enable interrupt */ control_block->info |= BCM2835_DMA_INT_EN; /* Setup synchronization */ if (sync_type != 0) control_block->info |= sync_type; if (buf_len % period_len) dev_warn_once(chan->device->dev, "%s: buffer_length (%zd) is not a multiple of period_len (%zd)\n", __func__, buf_len, period_len); /* Setup DREQ channel */ if (c->dreq != 0) control_block->info |= BCM2835_DMA_PER_MAP(c->dreq); info |= BCM2835_DMA_PER_MAP(c->dreq); /* Length of a frame */ control_block->length = period_len; d->size += control_block->length; if (direction == DMA_DEV_TO_MEM) { if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; src = c->cfg.src_addr; dst = buf_addr; info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC; } else { if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; dst = c->cfg.dst_addr; src = buf_addr; info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; } /* calculate number of frames */ 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); /* * Next block is the next frame. * This DMA engine driver currently only supports cyclic DMA. * Therefore, wrap around at number of frames. * allocate the CB chain * note that we need to use GFP_NOWAIT, as the ALSA i2s dmaengine * implementation calls prep_dma_cyclic with interrupts disabled. */ control_block->next = d->cb_list[((frame + 1) % d->frames)].paddr; } return vchan_tx_prep(&c->vc, &d->vd, flags); error_cb: i--; for (; i >= 0; i--) { struct bcm2835_cb_entry *cb_entry = &d->cb_list[i]; d = bcm2835_dma_create_cb_chain(chan, direction, true, info, extra, frames, src, dst, buf_len, period_len, GFP_NOWAIT); if (!d) return NULL; dma_pool_free(c->cb_pool, cb_entry->cb, cb_entry->paddr); } /* wrap around into a loop */ d->cb_list[d->frames - 1].cb->next = d->cb_list[0].paddr; kfree(d->cb_list); kfree(d); return NULL; return vchan_tx_prep(&c->vc, &d->vd, flags); } static int bcm2835_dma_slave_config(struct dma_chan *chan, Loading Loading @@ -529,7 +832,8 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) return 0; } static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq) static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq, unsigned int irq_flags) { struct bcm2835_chan *c; Loading @@ -544,6 +848,12 @@ static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq) c->chan_base = BCM2835_DMA_CHANIO(d->base, chan_id); c->ch = chan_id; c->irq_number = irq; c->irq_flags = irq_flags; /* 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; } Loading Loading @@ -587,9 +897,11 @@ static int bcm2835_dma_probe(struct platform_device *pdev) struct resource *res; void __iomem *base; int rc; int i; int irq; int i, j; int irq[BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED + 1]; int irq_flags; uint32_t chans_available; char chan_name[BCM2835_DMA_CHAN_NAME_SIZE]; if (!pdev->dev.dma_mask) pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; Loading @@ -615,16 +927,22 @@ static int bcm2835_dma_probe(struct platform_device *pdev) dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask); dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); dma_cap_set(DMA_MEMCPY, od->ddev.cap_mask); od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources; od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources; od->ddev.device_tx_status = bcm2835_dma_tx_status; od->ddev.device_issue_pending = bcm2835_dma_issue_pending; od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic; od->ddev.device_prep_slave_sg = bcm2835_dma_prep_slave_sg; od->ddev.device_prep_dma_memcpy = bcm2835_dma_prep_dma_memcpy; od->ddev.device_config = bcm2835_dma_slave_config; od->ddev.device_terminate_all = bcm2835_dma_terminate_all; od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); od->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | BIT(DMA_MEM_TO_MEM); od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; od->ddev.dev = &pdev->dev; INIT_LIST_HEAD(&od->ddev.channels); spin_lock_init(&od->lock); Loading @@ -640,23 +958,49 @@ static int bcm2835_dma_probe(struct platform_device *pdev) goto err_no_dma; } /* get irqs for each channel that we support */ for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) { /* skip masked out channels */ if (!(chans_available & (1 << i))) { irq[i] = -1; continue; } /* get the named irq */ snprintf(chan_name, sizeof(chan_name), "dma%i", i); irq[i] = platform_get_irq_byname(pdev, chan_name); if (irq[i] >= 0) continue; /* legacy device tree case handling */ dev_warn_once(&pdev->dev, "missing interrupt-names property in device tree - legacy interpretation is used\n"); /* * Do not use the FIQ and BULK channels, * because they are used by the GPU. * in case of channel >= 11 * use the 11th interrupt and that is shared */ chans_available &= ~(BCM2835_DMA_FIQ_MASK | BCM2835_DMA_BULK_MASK); irq[i] = platform_get_irq(pdev, i < 11 ? i : 11); } for (i = 0; i < pdev->num_resources; i++) { irq = platform_get_irq(pdev, i); if (irq < 0) /* get irqs for each channel */ for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) { /* skip channels without irq */ if (irq[i] < 0) continue; /* check if there are other channels that also use this irq */ irq_flags = 0; for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++) if ((i != j) && (irq[j] == irq[i])) { irq_flags = IRQF_SHARED; break; } if (chans_available & (1 << i)) { rc = bcm2835_dma_chan_init(od, i, irq); /* initialize the channel */ rc = bcm2835_dma_chan_init(od, i, irq[i], irq_flags); if (rc) goto err_no_dma; } } dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i); Loading Loading
Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt +26 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,10 @@ Required properties: - reg: Should contain DMA registers location and length. - interrupts: Should contain the DMA interrupts associated to the DMA channels in ascending order. - interrupt-names: Should contain the names of the interrupt in the form "dmaXX". Use "dma-shared-all" for the common interrupt line that is shared by all dma channels. - #dma-cells: Must be <1>, the cell in the dmas property of the client device represents the DREQ number. - brcm,dma-channel-mask: Bit mask representing the channels Loading @@ -34,13 +38,35 @@ dma: dma@7e007000 { <1 24>, <1 25>, <1 26>, /* dma channel 11-14 share one irq */ <1 27>, <1 27>, <1 27>, <1 27>, /* unused shared irq for all channels */ <1 28>; interrupt-names = "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6", "dma7", "dma8", "dma9", "dma10", "dma11", "dma12", "dma13", "dma14", "dma-shared-all"; #dma-cells = <1>; brcm,dma-channel-mask = <0x7f35>; }; DMA clients connected to the BCM2835 DMA controller must use the format described in the dma.txt file, using a two-cell specifier for each channel. Loading
arch/arm/boot/dts/bcm283x.dtsi +21 −1 Original line number Diff line number Diff line Loading @@ -47,9 +47,29 @@ <1 24>, <1 25>, <1 26>, /* dma channel 11-14 share one irq */ <1 27>, <1 27>, <1 27>, <1 27>, /* unused shared irq for all channels */ <1 28>; interrupt-names = "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6", "dma7", "dma8", "dma9", "dma10", "dma11", "dma12", "dma13", "dma14", "dma-shared-all"; #dma-cells = <1>; brcm,dma-channel-mask = <0x7f35>; }; Loading
drivers/dma/bcm2835-dma.c +474 −130 Original line number Diff line number Diff line Loading @@ -46,6 +46,9 @@ #include "virt-dma.h" #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14 #define BCM2835_DMA_CHAN_NAME_SIZE 8 struct bcm2835_dmadev { struct dma_device ddev; spinlock_t lock; Loading Loading @@ -73,7 +76,6 @@ struct bcm2835_chan { struct list_head node; struct dma_slave_config cfg; bool cyclic; unsigned int dreq; int ch; Loading @@ -82,6 +84,9 @@ struct bcm2835_chan { void __iomem *chan_base; int irq_number; unsigned int irq_flags; bool is_lite_channel; }; struct bcm2835_desc { Loading @@ -89,47 +94,104 @@ struct bcm2835_desc { struct virt_dma_desc vd; enum dma_transfer_direction dir; struct bcm2835_cb_entry *cb_list; unsigned int frames; size_t size; bool cyclic; struct bcm2835_cb_entry cb_list[]; }; #define BCM2835_DMA_CS 0x00 #define BCM2835_DMA_ADDR 0x04 #define BCM2835_DMA_TI 0x08 #define BCM2835_DMA_SOURCE_AD 0x0c #define BCM2835_DMA_DEST_AD 0x10 #define BCM2835_DMA_NEXTCB 0x1C #define BCM2835_DMA_LEN 0x14 #define BCM2835_DMA_STRIDE 0x18 #define BCM2835_DMA_NEXTCB 0x1c #define BCM2835_DMA_DEBUG 0x20 /* DMA CS Control and Status bits */ #define BCM2835_DMA_ACTIVE BIT(0) #define BCM2835_DMA_INT BIT(2) #define BCM2835_DMA_ACTIVE BIT(0) /* activate the DMA */ #define BCM2835_DMA_END BIT(1) /* current CB has ended */ #define BCM2835_DMA_INT BIT(2) /* interrupt status */ #define BCM2835_DMA_DREQ BIT(3) /* DREQ state */ #define BCM2835_DMA_ISPAUSED BIT(4) /* Pause requested or not active */ #define BCM2835_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */ #define BCM2835_DMA_WAITING_FOR_WRITES BIT(6) /* waiting for last * AXI-write to ack */ #define BCM2835_DMA_ERR BIT(8) #define BCM2835_DMA_PRIORITY(x) ((x & 15) << 16) /* AXI priority */ #define BCM2835_DMA_PANIC_PRIORITY(x) ((x & 15) << 20) /* panic priority */ /* current value of TI.BCM2835_DMA_WAIT_RESP */ #define BCM2835_DMA_WAIT_FOR_WRITES BIT(28) #define BCM2835_DMA_DIS_DEBUG BIT(29) /* disable debug pause signal */ #define BCM2835_DMA_ABORT BIT(30) /* Stop current CB, go to next, WO */ #define BCM2835_DMA_RESET BIT(31) /* WO, self clearing */ /* Transfer information bits - also bcm2835_cb.info field */ #define BCM2835_DMA_INT_EN BIT(0) #define BCM2835_DMA_TDMODE BIT(1) /* 2D-Mode */ #define BCM2835_DMA_WAIT_RESP BIT(3) /* wait for AXI-write to be acked */ #define BCM2835_DMA_D_INC BIT(4) #define BCM2835_DMA_D_DREQ BIT(6) #define BCM2835_DMA_D_WIDTH BIT(5) /* 128bit writes if set */ #define BCM2835_DMA_D_DREQ BIT(6) /* enable DREQ for destination */ #define BCM2835_DMA_D_IGNORE BIT(7) /* ignore destination writes */ #define BCM2835_DMA_S_INC BIT(8) #define BCM2835_DMA_S_DREQ BIT(10) #define BCM2835_DMA_PER_MAP(x) ((x) << 16) #define BCM2835_DMA_S_WIDTH BIT(9) /* 128bit writes if set */ #define BCM2835_DMA_S_DREQ BIT(10) /* enable SREQ for source */ #define BCM2835_DMA_S_IGNORE BIT(11) /* ignore source reads - read 0 */ #define BCM2835_DMA_BURST_LENGTH(x) ((x & 15) << 12) #define BCM2835_DMA_PER_MAP(x) ((x & 31) << 16) /* REQ source */ #define BCM2835_DMA_WAIT(x) ((x & 31) << 21) /* add DMA-wait cycles */ #define BCM2835_DMA_NO_WIDE_BURSTS BIT(26) /* no 2 beat write bursts */ /* debug register bits */ #define BCM2835_DMA_DEBUG_LAST_NOT_SET_ERR BIT(0) #define BCM2835_DMA_DEBUG_FIFO_ERR BIT(1) #define BCM2835_DMA_DEBUG_READ_ERR BIT(2) #define BCM2835_DMA_DEBUG_OUTSTANDING_WRITES_SHIFT 4 #define BCM2835_DMA_DEBUG_OUTSTANDING_WRITES_BITS 4 #define BCM2835_DMA_DEBUG_ID_SHIFT 16 #define BCM2835_DMA_DEBUG_ID_BITS 9 #define BCM2835_DMA_DEBUG_STATE_SHIFT 16 #define BCM2835_DMA_DEBUG_STATE_BITS 9 #define BCM2835_DMA_DEBUG_VERSION_SHIFT 25 #define BCM2835_DMA_DEBUG_VERSION_BITS 3 #define BCM2835_DMA_DEBUG_LITE BIT(28) /* shared registers for all dma channels */ #define BCM2835_DMA_INT_STATUS 0xfe0 #define BCM2835_DMA_ENABLE 0xff0 #define BCM2835_DMA_DATA_TYPE_S8 1 #define BCM2835_DMA_DATA_TYPE_S16 2 #define BCM2835_DMA_DATA_TYPE_S32 4 #define BCM2835_DMA_DATA_TYPE_S128 16 #define BCM2835_DMA_BULK_MASK BIT(0) #define BCM2835_DMA_FIQ_MASK (BIT(2) | BIT(3)) /* Valid only for channels 0 - 14, 15 has its own base address */ #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) { return DIV_ROUND_UP(len, max_len); } static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d) { return container_of(d, struct bcm2835_dmadev, ddev); Loading @@ -146,19 +208,209 @@ static inline struct bcm2835_desc *to_bcm2835_dma_desc( return container_of(t, struct bcm2835_desc, vd.tx); } static void bcm2835_dma_desc_free(struct virt_dma_desc *vd) static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc) { struct bcm2835_desc *desc = container_of(vd, struct bcm2835_desc, vd); int i; size_t i; for (i = 0; i < desc->frames; i++) dma_pool_free(desc->c->cb_pool, desc->cb_list[i].cb, desc->cb_list[i].paddr); kfree(desc->cb_list); kfree(desc); } static void bcm2835_dma_desc_free(struct virt_dma_desc *vd) { bcm2835_dma_free_cb_chain( container_of(vd, struct bcm2835_desc, vd)); } static void bcm2835_dma_create_cb_set_length( struct bcm2835_chan *chan, struct bcm2835_dma_cb *control_block, size_t len, size_t period_len, size_t *total_len, u32 finalextrainfo) { 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) return; /* * period_len means: that we need to generate * transfers that are terminating at every * multiple of period_len - this is typically * used to set the interrupt flag in info * which is required during cyclic transfers */ /* have we filled in period_length yet? */ if (*total_len + control_block->length < period_len) return; /* calculate the length that remains to reach period_length */ control_block->length = period_len - *total_len; /* reset total_length for next period */ *total_len = 0; /* add extrainfo bits in info */ control_block->info |= finalextrainfo; } static inline size_t bcm2835_dma_count_frames_for_sg( struct bcm2835_chan *c, struct scatterlist *sgl, unsigned int sg_len) { size_t frames = 0; struct scatterlist *sgent; unsigned int i; size_t plength = bcm2835_dma_max_frame_length(c); for_each_sg(sgl, sgent, sg_len, i) frames += bcm2835_dma_frames_for_length( sg_dma_len(sgent), plength); return frames; } /** * bcm2835_dma_create_cb_chain - create a control block and fills data in * * @chan: the @dma_chan for which we run this * @direction: the direction in which we transfer * @cyclic: it is a cyclic transfer * @info: the default info bits to apply per controlblock * @frames: number of controlblocks to allocate * @src: the src address to assign (if the S_INC bit is set * in @info, then it gets incremented) * @dst: the dst address to assign (if the D_INC bit is set * in @info, then it gets incremented) * @buf_len: the full buffer length (may also be 0) * @period_len: the period length when to apply @finalextrainfo * in addition to the last transfer * this will also break some control-blocks early * @finalextrainfo: additional bits in last controlblock * (or when period_len is reached in case of cyclic) * @gfp: the GFP flag to use for allocation */ static struct bcm2835_desc *bcm2835_dma_create_cb_chain( struct dma_chan *chan, enum dma_transfer_direction direction, bool cyclic, u32 info, u32 finalextrainfo, size_t frames, dma_addr_t src, dma_addr_t dst, size_t buf_len, size_t period_len, gfp_t gfp) { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); size_t len = buf_len, total_len; size_t frame; struct bcm2835_desc *d; struct bcm2835_cb_entry *cb_entry; struct bcm2835_dma_cb *control_block; if (!frames) return NULL; /* allocate and setup the descriptor. */ d = kzalloc(sizeof(*d) + frames * sizeof(struct bcm2835_cb_entry), gfp); if (!d) return NULL; d->c = c; d->dir = direction; d->cyclic = cyclic; /* * Iterate over all frames, create a control block * for each frame and link them together. */ for (frame = 0, total_len = 0; frame < frames; d->frames++, frame++) { cb_entry = &d->cb_list[frame]; cb_entry->cb = dma_pool_alloc(c->cb_pool, gfp, &cb_entry->paddr); if (!cb_entry->cb) goto error_cb; /* fill in the control block */ control_block = cb_entry->cb; control_block->info = info; control_block->src = src; control_block->dst = dst; control_block->stride = 0; control_block->next = 0; /* set up length in control_block if requested */ if (buf_len) { /* calculate length honoring period_length */ bcm2835_dma_create_cb_set_length( c, control_block, len, period_len, &total_len, cyclic ? finalextrainfo : 0); /* calculate new remaining length */ len -= control_block->length; } /* link this the last controlblock */ if (frame) d->cb_list[frame - 1].cb->next = cb_entry->paddr; /* update src and dst and length */ if (src && (info & BCM2835_DMA_S_INC)) src += control_block->length; if (dst && (info & BCM2835_DMA_D_INC)) dst += control_block->length; /* Length of total transfer */ d->size += control_block->length; } /* the last frame requires extra flags */ d->cb_list[d->frames - 1].cb->info |= finalextrainfo; /* detect a size missmatch */ if (buf_len && (d->size != buf_len)) goto error_cb; return d; error_cb: bcm2835_dma_free_cb_chain(d); return NULL; } static void bcm2835_dma_fill_cb_chain_with_sg( struct dma_chan *chan, enum dma_transfer_direction direction, struct bcm2835_cb_entry *cb, struct scatterlist *sgl, unsigned int sg_len) { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); size_t max_len = bcm2835_dma_max_frame_length(c); unsigned int i, len; dma_addr_t addr; struct scatterlist *sgent; for_each_sg(sgl, sgent, sg_len, i) { for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent); len > 0; addr += cb->cb->length, len -= cb->cb->length, cb++) { if (direction == DMA_DEV_TO_MEM) cb->cb->dst = addr; else cb->cb->src = addr; cb->cb->length = min(len, max_len); } } } static int bcm2835_dma_abort(void __iomem *chan_base) { unsigned long cs; Loading Loading @@ -218,6 +470,15 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data) struct bcm2835_desc *d; unsigned long flags; /* check the shared interrupt */ if (c->irq_flags & IRQF_SHARED) { /* check if the interrupt is enabled */ flags = readl(c->chan_base + BCM2835_DMA_CS); /* if not set then we are not the reason for the irq */ if (!(flags & BCM2835_DMA_INT)) return IRQ_NONE; } spin_lock_irqsave(&c->vc.lock, flags); /* Acknowledge interrupt */ Loading @@ -226,12 +487,18 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data) d = c->desc; if (d) { /* TODO Only works for cyclic DMA */ if (d->cyclic) { /* call the cyclic callback */ vchan_cyclic_callback(&d->vd); } /* Keep the DMA engine running */ writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); } else { vchan_cookie_complete(&c->desc->vd); bcm2835_dma_start_desc(c); } } spin_unlock_irqrestore(&c->vc.lock, flags); Loading @@ -252,8 +519,8 @@ static int bcm2835_dma_alloc_chan_resources(struct dma_chan *chan) return -ENOMEM; } return request_irq(c->irq_number, bcm2835_dma_callback, 0, "DMA IRQ", c); return request_irq(c->irq_number, bcm2835_dma_callback, c->irq_flags, "DMA IRQ", c); } static void bcm2835_dma_free_chan_resources(struct dma_chan *chan) Loading Loading @@ -339,8 +606,6 @@ static void bcm2835_dma_issue_pending(struct dma_chan *chan) struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); unsigned long flags; c->cyclic = true; /* Nothing else is implemented */ spin_lock_irqsave(&c->vc.lock, flags); if (vchan_issue_pending(&c->vc) && !c->desc) bcm2835_dma_start_desc(c); Loading @@ -348,122 +613,160 @@ static void bcm2835_dma_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&c->vc.lock, flags); } static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, unsigned long flags) struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy( struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, size_t len, unsigned long flags) { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); enum dma_slave_buswidth dev_width; struct bcm2835_desc *d; dma_addr_t dev_addr; unsigned int es, sync_type; unsigned int frame; int i; u32 info = BCM2835_DMA_D_INC | BCM2835_DMA_S_INC; u32 extra = BCM2835_DMA_INT_EN | BCM2835_DMA_WAIT_RESP; size_t max_len = bcm2835_dma_max_frame_length(c); size_t frames; /* if src, dst or len is not given return with an error */ if (!src || !dst || !len) return NULL; /* calculate number of frames */ frames = bcm2835_dma_frames_for_length(len, max_len); /* allocate the CB chain - this also fills in the pointers */ d = bcm2835_dma_create_cb_chain(chan, DMA_MEM_TO_MEM, false, info, extra, frames, src, dst, len, 0, GFP_KERNEL); if (!d) return NULL; return vchan_tx_prep(&c->vc, &d->vd, flags); } static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags, void *context) { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); struct bcm2835_desc *d; dma_addr_t src = 0, dst = 0; u32 info = BCM2835_DMA_WAIT_RESP; u32 extra = BCM2835_DMA_INT_EN; size_t frames; /* Grab configuration */ if (!is_slave_direction(direction)) { dev_err(chan->device->dev, "%s: bad direction?\n", __func__); dev_err(chan->device->dev, "%s: bad direction?\n", __func__); return NULL; } if (c->dreq != 0) info |= BCM2835_DMA_PER_MAP(c->dreq); if (direction == DMA_DEV_TO_MEM) { dev_addr = c->cfg.src_addr; dev_width = c->cfg.src_addr_width; sync_type = BCM2835_DMA_S_DREQ; if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; src = c->cfg.src_addr; info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC; } else { dev_addr = c->cfg.dst_addr; dev_width = c->cfg.dst_addr_width; sync_type = BCM2835_DMA_D_DREQ; } /* Bus width translates to the element size (ES) */ switch (dev_width) { case DMA_SLAVE_BUSWIDTH_4_BYTES: es = BCM2835_DMA_DATA_TYPE_S32; break; default: if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; dst = c->cfg.dst_addr; info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; } /* Now allocate and setup the descriptor. */ d = kzalloc(sizeof(*d), GFP_NOWAIT); /* count frames in sg list */ frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len); /* allocate the CB chain */ d = bcm2835_dma_create_cb_chain(chan, direction, false, info, extra, frames, src, dst, 0, 0, GFP_KERNEL); if (!d) return NULL; d->c = c; d->dir = direction; d->frames = buf_len / period_len; /* fill in frames with scatterlist pointers */ bcm2835_dma_fill_cb_chain_with_sg(chan, direction, d->cb_list, sgl, sg_len); return vchan_tx_prep(&c->vc, &d->vd, flags); } d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL); if (!d->cb_list) { kfree(d); static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, unsigned long flags) { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); struct bcm2835_desc *d; 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 */ if (!is_slave_direction(direction)) { dev_err(chan->device->dev, "%s: bad direction?\n", __func__); return NULL; } /* Allocate memory for control blocks */ for (i = 0; i < d->frames; i++) { struct bcm2835_cb_entry *cb_entry = &d->cb_list[i]; cb_entry->cb = dma_pool_zalloc(c->cb_pool, GFP_ATOMIC, &cb_entry->paddr); if (!cb_entry->cb) goto error_cb; if (!buf_len) { dev_err(chan->device->dev, "%s: bad buffer length (= 0)\n", __func__); return NULL; } /* * Iterate over all frames, create a control block * for each frame and link them together. * warn if buf_len is not a multiple of period_len - this may leed * to unexpected latencies for interrupts and thus audiable clicks */ for (frame = 0; frame < d->frames; frame++) { struct bcm2835_dma_cb *control_block = d->cb_list[frame].cb; /* Setup adresses */ if (d->dir == DMA_DEV_TO_MEM) { control_block->info = BCM2835_DMA_D_INC; control_block->src = dev_addr; control_block->dst = buf_addr + frame * period_len; } else { control_block->info = BCM2835_DMA_S_INC; control_block->src = buf_addr + frame * period_len; control_block->dst = dev_addr; } /* Enable interrupt */ control_block->info |= BCM2835_DMA_INT_EN; /* Setup synchronization */ if (sync_type != 0) control_block->info |= sync_type; if (buf_len % period_len) dev_warn_once(chan->device->dev, "%s: buffer_length (%zd) is not a multiple of period_len (%zd)\n", __func__, buf_len, period_len); /* Setup DREQ channel */ if (c->dreq != 0) control_block->info |= BCM2835_DMA_PER_MAP(c->dreq); info |= BCM2835_DMA_PER_MAP(c->dreq); /* Length of a frame */ control_block->length = period_len; d->size += control_block->length; if (direction == DMA_DEV_TO_MEM) { if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; src = c->cfg.src_addr; dst = buf_addr; info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC; } else { if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; dst = c->cfg.dst_addr; src = buf_addr; info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; } /* calculate number of frames */ 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); /* * Next block is the next frame. * This DMA engine driver currently only supports cyclic DMA. * Therefore, wrap around at number of frames. * allocate the CB chain * note that we need to use GFP_NOWAIT, as the ALSA i2s dmaengine * implementation calls prep_dma_cyclic with interrupts disabled. */ control_block->next = d->cb_list[((frame + 1) % d->frames)].paddr; } return vchan_tx_prep(&c->vc, &d->vd, flags); error_cb: i--; for (; i >= 0; i--) { struct bcm2835_cb_entry *cb_entry = &d->cb_list[i]; d = bcm2835_dma_create_cb_chain(chan, direction, true, info, extra, frames, src, dst, buf_len, period_len, GFP_NOWAIT); if (!d) return NULL; dma_pool_free(c->cb_pool, cb_entry->cb, cb_entry->paddr); } /* wrap around into a loop */ d->cb_list[d->frames - 1].cb->next = d->cb_list[0].paddr; kfree(d->cb_list); kfree(d); return NULL; return vchan_tx_prep(&c->vc, &d->vd, flags); } static int bcm2835_dma_slave_config(struct dma_chan *chan, Loading Loading @@ -529,7 +832,8 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) return 0; } static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq) static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq, unsigned int irq_flags) { struct bcm2835_chan *c; Loading @@ -544,6 +848,12 @@ static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq) c->chan_base = BCM2835_DMA_CHANIO(d->base, chan_id); c->ch = chan_id; c->irq_number = irq; c->irq_flags = irq_flags; /* 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; } Loading Loading @@ -587,9 +897,11 @@ static int bcm2835_dma_probe(struct platform_device *pdev) struct resource *res; void __iomem *base; int rc; int i; int irq; int i, j; int irq[BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED + 1]; int irq_flags; uint32_t chans_available; char chan_name[BCM2835_DMA_CHAN_NAME_SIZE]; if (!pdev->dev.dma_mask) pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; Loading @@ -615,16 +927,22 @@ static int bcm2835_dma_probe(struct platform_device *pdev) dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask); dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); dma_cap_set(DMA_MEMCPY, od->ddev.cap_mask); od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources; od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources; od->ddev.device_tx_status = bcm2835_dma_tx_status; od->ddev.device_issue_pending = bcm2835_dma_issue_pending; od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic; od->ddev.device_prep_slave_sg = bcm2835_dma_prep_slave_sg; od->ddev.device_prep_dma_memcpy = bcm2835_dma_prep_dma_memcpy; od->ddev.device_config = bcm2835_dma_slave_config; od->ddev.device_terminate_all = bcm2835_dma_terminate_all; od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); od->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | BIT(DMA_MEM_TO_MEM); od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; od->ddev.dev = &pdev->dev; INIT_LIST_HEAD(&od->ddev.channels); spin_lock_init(&od->lock); Loading @@ -640,23 +958,49 @@ static int bcm2835_dma_probe(struct platform_device *pdev) goto err_no_dma; } /* get irqs for each channel that we support */ for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) { /* skip masked out channels */ if (!(chans_available & (1 << i))) { irq[i] = -1; continue; } /* get the named irq */ snprintf(chan_name, sizeof(chan_name), "dma%i", i); irq[i] = platform_get_irq_byname(pdev, chan_name); if (irq[i] >= 0) continue; /* legacy device tree case handling */ dev_warn_once(&pdev->dev, "missing interrupt-names property in device tree - legacy interpretation is used\n"); /* * Do not use the FIQ and BULK channels, * because they are used by the GPU. * in case of channel >= 11 * use the 11th interrupt and that is shared */ chans_available &= ~(BCM2835_DMA_FIQ_MASK | BCM2835_DMA_BULK_MASK); irq[i] = platform_get_irq(pdev, i < 11 ? i : 11); } for (i = 0; i < pdev->num_resources; i++) { irq = platform_get_irq(pdev, i); if (irq < 0) /* get irqs for each channel */ for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) { /* skip channels without irq */ if (irq[i] < 0) continue; /* check if there are other channels that also use this irq */ irq_flags = 0; for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++) if ((i != j) && (irq[j] == irq[i])) { irq_flags = IRQF_SHARED; break; } if (chans_available & (1 << i)) { rc = bcm2835_dma_chan_init(od, i, irq); /* initialize the channel */ rc = bcm2835_dma_chan_init(od, i, irq[i], irq_flags); if (rc) goto err_no_dma; } } dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i); Loading