mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-12 00:00:00 +00:00
dmaengine: omap: add support for cyclic DMA
Add support for cyclic DMA to the OMAP DMA engine driver. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
7c836bc7f9
commit
3a774ea91a
@ -33,6 +33,7 @@ struct omap_chan {
|
|||||||
|
|
||||||
struct dma_slave_config cfg;
|
struct dma_slave_config cfg;
|
||||||
unsigned dma_sig;
|
unsigned dma_sig;
|
||||||
|
bool cyclic;
|
||||||
|
|
||||||
int dma_ch;
|
int dma_ch;
|
||||||
struct omap_desc *desc;
|
struct omap_desc *desc;
|
||||||
@ -138,11 +139,15 @@ static void omap_dma_callback(int ch, u16 status, void *data)
|
|||||||
spin_lock_irqsave(&c->vc.lock, flags);
|
spin_lock_irqsave(&c->vc.lock, flags);
|
||||||
d = c->desc;
|
d = c->desc;
|
||||||
if (d) {
|
if (d) {
|
||||||
if (++c->sgidx < d->sglen) {
|
if (!c->cyclic) {
|
||||||
omap_dma_start_sg(c, d, c->sgidx);
|
if (++c->sgidx < d->sglen) {
|
||||||
|
omap_dma_start_sg(c, d, c->sgidx);
|
||||||
|
} else {
|
||||||
|
omap_dma_start_desc(c);
|
||||||
|
vchan_cookie_complete(&d->vd);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
omap_dma_start_desc(c);
|
vchan_cyclic_callback(&d->vd);
|
||||||
vchan_cookie_complete(&d->vd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&c->vc.lock, flags);
|
spin_unlock_irqrestore(&c->vc.lock, flags);
|
||||||
@ -358,6 +363,79 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
|
|||||||
return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
|
return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dma_async_tx_descriptor *omap_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 dir, void *context)
|
||||||
|
{
|
||||||
|
struct omap_chan *c = to_omap_dma_chan(chan);
|
||||||
|
enum dma_slave_buswidth dev_width;
|
||||||
|
struct omap_desc *d;
|
||||||
|
dma_addr_t dev_addr;
|
||||||
|
unsigned es, sync_type;
|
||||||
|
u32 burst;
|
||||||
|
|
||||||
|
if (dir == DMA_DEV_TO_MEM) {
|
||||||
|
dev_addr = c->cfg.src_addr;
|
||||||
|
dev_width = c->cfg.src_addr_width;
|
||||||
|
burst = c->cfg.src_maxburst;
|
||||||
|
sync_type = OMAP_DMA_SRC_SYNC;
|
||||||
|
} else if (dir == DMA_MEM_TO_DEV) {
|
||||||
|
dev_addr = c->cfg.dst_addr;
|
||||||
|
dev_width = c->cfg.dst_addr_width;
|
||||||
|
burst = c->cfg.dst_maxburst;
|
||||||
|
sync_type = OMAP_DMA_DST_SYNC;
|
||||||
|
} else {
|
||||||
|
dev_err(chan->device->dev, "%s: bad direction?\n", __func__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bus width translates to the element size (ES) */
|
||||||
|
switch (dev_width) {
|
||||||
|
case DMA_SLAVE_BUSWIDTH_1_BYTE:
|
||||||
|
es = OMAP_DMA_DATA_TYPE_S8;
|
||||||
|
break;
|
||||||
|
case DMA_SLAVE_BUSWIDTH_2_BYTES:
|
||||||
|
es = OMAP_DMA_DATA_TYPE_S16;
|
||||||
|
break;
|
||||||
|
case DMA_SLAVE_BUSWIDTH_4_BYTES:
|
||||||
|
es = OMAP_DMA_DATA_TYPE_S32;
|
||||||
|
break;
|
||||||
|
default: /* not reached */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now allocate and setup the descriptor. */
|
||||||
|
d = kzalloc(sizeof(*d) + sizeof(d->sg[0]), GFP_ATOMIC);
|
||||||
|
if (!d)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
d->dir = dir;
|
||||||
|
d->dev_addr = dev_addr;
|
||||||
|
d->fi = burst;
|
||||||
|
d->es = es;
|
||||||
|
d->sync_mode = OMAP_DMA_SYNC_PACKET;
|
||||||
|
d->sync_type = sync_type;
|
||||||
|
d->periph_port = OMAP_DMA_PORT_MPUI;
|
||||||
|
d->sg[0].addr = buf_addr;
|
||||||
|
d->sg[0].en = period_len / es_bytes[es];
|
||||||
|
d->sg[0].fn = buf_len / period_len;
|
||||||
|
d->sglen = 1;
|
||||||
|
|
||||||
|
if (!c->cyclic) {
|
||||||
|
c->cyclic = true;
|
||||||
|
omap_dma_link_lch(c->dma_ch, c->dma_ch);
|
||||||
|
omap_enable_dma_irq(c->dma_ch, OMAP_DMA_FRAME_IRQ);
|
||||||
|
omap_disable_dma_irq(c->dma_ch, OMAP_DMA_BLOCK_IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cpu_class_is_omap1()) {
|
||||||
|
omap_set_dma_src_burst_mode(c->dma_ch, OMAP_DMA_DATA_BURST_16);
|
||||||
|
omap_set_dma_dest_burst_mode(c->dma_ch, OMAP_DMA_DATA_BURST_16);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vchan_tx_prep(&c->vc, &d->vd, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
|
||||||
|
}
|
||||||
|
|
||||||
static int omap_dma_slave_config(struct omap_chan *c, struct dma_slave_config *cfg)
|
static int omap_dma_slave_config(struct omap_chan *c, struct dma_slave_config *cfg)
|
||||||
{
|
{
|
||||||
if (cfg->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
|
if (cfg->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
|
||||||
@ -392,6 +470,11 @@ static int omap_dma_terminate_all(struct omap_chan *c)
|
|||||||
omap_stop_dma(c->dma_ch);
|
omap_stop_dma(c->dma_ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->cyclic) {
|
||||||
|
c->cyclic = false;
|
||||||
|
omap_dma_unlink_lch(c->dma_ch, c->dma_ch);
|
||||||
|
}
|
||||||
|
|
||||||
vchan_get_all_descriptors(&c->vc, &head);
|
vchan_get_all_descriptors(&c->vc, &head);
|
||||||
spin_unlock_irqrestore(&c->vc.lock, flags);
|
spin_unlock_irqrestore(&c->vc.lock, flags);
|
||||||
vchan_dma_desc_free_list(&c->vc, &head);
|
vchan_dma_desc_free_list(&c->vc, &head);
|
||||||
@ -484,11 +567,13 @@ static int omap_dma_probe(struct platform_device *pdev)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
|
dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
|
||||||
|
dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
|
||||||
od->ddev.device_alloc_chan_resources = omap_dma_alloc_chan_resources;
|
od->ddev.device_alloc_chan_resources = omap_dma_alloc_chan_resources;
|
||||||
od->ddev.device_free_chan_resources = omap_dma_free_chan_resources;
|
od->ddev.device_free_chan_resources = omap_dma_free_chan_resources;
|
||||||
od->ddev.device_tx_status = omap_dma_tx_status;
|
od->ddev.device_tx_status = omap_dma_tx_status;
|
||||||
od->ddev.device_issue_pending = omap_dma_issue_pending;
|
od->ddev.device_issue_pending = omap_dma_issue_pending;
|
||||||
od->ddev.device_prep_slave_sg = omap_dma_prep_slave_sg;
|
od->ddev.device_prep_slave_sg = omap_dma_prep_slave_sg;
|
||||||
|
od->ddev.device_prep_dma_cyclic = omap_dma_prep_dma_cyclic;
|
||||||
od->ddev.device_control = omap_dma_control;
|
od->ddev.device_control = omap_dma_control;
|
||||||
od->ddev.dev = &pdev->dev;
|
od->ddev.dev = &pdev->dev;
|
||||||
INIT_LIST_HEAD(&od->ddev.channels);
|
INIT_LIST_HEAD(&od->ddev.channels);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user