aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/ipu
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2011-08-25 12:26:53 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-11-03 16:28:33 -0400
commit1d3564d91f94d0b598304eb6ebe3b83a83176f7a (patch)
tree585a122d4ca32f02d65cb24267c5570842567e95 /drivers/dma/ipu
parent2d86401c2cbfce9f99b08ba168bdb60b2eb7796e (diff)
[media] dmaengine: ipu-idmac: add support for the DMA_PAUSE control
To support multi-size buffers in the mx3_camera V4L2 driver we have to be able to stop DMA on a channel without releasing descriptors and completely halting the hardware. Use the DMA_PAUSE control to implement this mode. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Acked-by: Vinod Koul <vinod.koul@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/dma/ipu')
-rw-r--r--drivers/dma/ipu/ipu_idmac.c65
1 files changed, 42 insertions, 23 deletions
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c
index 6815905a772f..ddc2a1331822 100644
--- a/drivers/dma/ipu/ipu_idmac.c
+++ b/drivers/dma/ipu/ipu_idmac.c
@@ -1307,6 +1307,7 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
1307 ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) { 1307 ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) {
1308 callback = descnew->txd.callback; 1308 callback = descnew->txd.callback;
1309 callback_param = descnew->txd.callback_param; 1309 callback_param = descnew->txd.callback_param;
1310 list_del_init(&descnew->list);
1310 spin_unlock(&ichan->lock); 1311 spin_unlock(&ichan->lock);
1311 if (callback) 1312 if (callback)
1312 callback(callback_param); 1313 callback(callback_param);
@@ -1428,39 +1429,58 @@ static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
1428{ 1429{
1429 struct idmac_channel *ichan = to_idmac_chan(chan); 1430 struct idmac_channel *ichan = to_idmac_chan(chan);
1430 struct idmac *idmac = to_idmac(chan->device); 1431 struct idmac *idmac = to_idmac(chan->device);
1432 struct ipu *ipu = to_ipu(idmac);
1433 struct list_head *list, *tmp;
1431 unsigned long flags; 1434 unsigned long flags;
1432 int i; 1435 int i;
1433 1436
1434 /* Only supports DMA_TERMINATE_ALL */ 1437 switch (cmd) {
1435 if (cmd != DMA_TERMINATE_ALL) 1438 case DMA_PAUSE:
1436 return -ENXIO; 1439 spin_lock_irqsave(&ipu->lock, flags);
1440 ipu_ic_disable_task(ipu, chan->chan_id);
1437 1441
1438 ipu_disable_channel(idmac, ichan, 1442 /* Return all descriptors into "prepared" state */
1439 ichan->status >= IPU_CHANNEL_ENABLED); 1443 list_for_each_safe(list, tmp, &ichan->queue)
1444 list_del_init(list);
1440 1445
1441 tasklet_disable(&to_ipu(idmac)->tasklet); 1446 ichan->sg[0] = NULL;
1447 ichan->sg[1] = NULL;
1442 1448
1443 /* ichan->queue is modified in ISR, have to spinlock */ 1449 spin_unlock_irqrestore(&ipu->lock, flags);
1444 spin_lock_irqsave(&ichan->lock, flags);
1445 list_splice_init(&ichan->queue, &ichan->free_list);
1446 1450
1447 if (ichan->desc) 1451 ichan->status = IPU_CHANNEL_INITIALIZED;
1448 for (i = 0; i < ichan->n_tx_desc; i++) { 1452 break;
1449 struct idmac_tx_desc *desc = ichan->desc + i; 1453 case DMA_TERMINATE_ALL:
1450 if (list_empty(&desc->list)) 1454 ipu_disable_channel(idmac, ichan,
1451 /* Descriptor was prepared, but not submitted */ 1455 ichan->status >= IPU_CHANNEL_ENABLED);
1452 list_add(&desc->list, &ichan->free_list);
1453 1456
1454 async_tx_clear_ack(&desc->txd); 1457 tasklet_disable(&ipu->tasklet);
1455 }
1456 1458
1457 ichan->sg[0] = NULL; 1459 /* ichan->queue is modified in ISR, have to spinlock */
1458 ichan->sg[1] = NULL; 1460 spin_lock_irqsave(&ichan->lock, flags);
1459 spin_unlock_irqrestore(&ichan->lock, flags); 1461 list_splice_init(&ichan->queue, &ichan->free_list);
1460 1462
1461 tasklet_enable(&to_ipu(idmac)->tasklet); 1463 if (ichan->desc)
1464 for (i = 0; i < ichan->n_tx_desc; i++) {
1465 struct idmac_tx_desc *desc = ichan->desc + i;
1466 if (list_empty(&desc->list))
1467 /* Descriptor was prepared, but not submitted */
1468 list_add(&desc->list, &ichan->free_list);
1462 1469
1463 ichan->status = IPU_CHANNEL_INITIALIZED; 1470 async_tx_clear_ack(&desc->txd);
1471 }
1472
1473 ichan->sg[0] = NULL;
1474 ichan->sg[1] = NULL;
1475 spin_unlock_irqrestore(&ichan->lock, flags);
1476
1477 tasklet_enable(&ipu->tasklet);
1478
1479 ichan->status = IPU_CHANNEL_INITIALIZED;
1480 break;
1481 default:
1482 return -ENOSYS;
1483 }
1464 1484
1465 return 0; 1485 return 0;
1466} 1486}
@@ -1663,7 +1683,6 @@ static void __exit ipu_idmac_exit(struct ipu *ipu)
1663 struct idmac_channel *ichan = ipu->channel + i; 1683 struct idmac_channel *ichan = ipu->channel + i;
1664 1684
1665 idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL, 0); 1685 idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL, 0);
1666 idmac_prep_slave_sg(&ichan->dma_chan, NULL, 0, DMA_NONE, 0);
1667 } 1686 }
1668 1687
1669 dma_async_device_unregister(&idmac->dma); 1688 dma_async_device_unregister(&idmac->dma);