summaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/ti-vpe/vpdma.c
diff options
context:
space:
mode:
authorNikhil Devshatwar <nikhil.nd@ti.com>2016-11-18 21:20:22 -0200
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2016-11-22 07:20:08 -0200
commitdc12b124353b2b4d8d46b2d0826f4f7905d44612 (patch)
tree6e2f12e683b9211d0c6d81b4c32caed4ac2625d0 /drivers/media/platform/ti-vpe/vpdma.c
parent634271f8f67532d48db6bf0fcacd5423e941bb5e (diff)
downloadop-kernel-dev-dc12b124353b2b4d8d46b2d0826f4f7905d44612.zip
op-kernel-dev-dc12b124353b2b4d8d46b2d0826f4f7905d44612.tar.gz
[media] media: ti-vpe: vpdma: Add abort channel desc and cleanup APIs
Whenever VPDMA processes a data descriptor of a list, it processes it and sets up the channel for the DMA transaction. List manager holds the descriptor in the list until the DMA is complete. If sync_on_channel descriptor, or another descriptor for the same channel is present in the FIFO, list manager keeps them until the current channel is free. When the capture stream is closed suddenly while there are pending descriptors in the FIFO (streamON failed, application killed), it would keep the VPDMA in a busy state. Any further list post would fail with EBUSY. To avoid this, drivers need to stop the current processing list and cleanup all the resources VPDMA has taken and also clear the internal FSM of list manager. The state machine is cleared by issuing channel specific abort descriptor. Therefore, the vpdma_list_cleanup accepts an array of channels for which abort_channel descriptors should be posted. It is driver's responsibility to post for all the channels or the channels which were used in the last context. Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com> Signed-off-by: Benoit Parrot <bparrot@ti.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/platform/ti-vpe/vpdma.c')
-rw-r--r--drivers/media/platform/ti-vpe/vpdma.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c
index 1a01528..7808c9c 100644
--- a/drivers/media/platform/ti-vpe/vpdma.c
+++ b/drivers/media/platform/ti-vpe/vpdma.c
@@ -385,6 +385,56 @@ void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf)
EXPORT_SYMBOL(vpdma_unmap_desc_buf);
/*
+ * Cleanup all pending descriptors of a list
+ * First, stop the current list being processed.
+ * If the VPDMA was busy, this step makes vpdma to accept post lists.
+ * To cleanup the internal FSM, post abort list descriptor for all the
+ * channels from @channels array of size @size.
+ */
+int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num,
+ int *channels, int size)
+{
+ struct vpdma_desc_list abort_list;
+ int i, ret, timeout = 500;
+
+ write_reg(vpdma, VPDMA_LIST_ATTR,
+ (list_num << VPDMA_LIST_NUM_SHFT) |
+ (1 << VPDMA_LIST_STOP_SHFT));
+
+ if (size <= 0 || !channels)
+ return 0;
+
+ ret = vpdma_create_desc_list(&abort_list,
+ size * sizeof(struct vpdma_dtd), VPDMA_LIST_TYPE_NORMAL);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < size; i++)
+ vpdma_add_abort_channel_ctd(&abort_list, channels[i]);
+
+ ret = vpdma_map_desc_buf(vpdma, &abort_list.buf);
+ if (ret)
+ return ret;
+ ret = vpdma_submit_descs(vpdma, &abort_list, list_num);
+ if (ret)
+ return ret;
+
+ while (vpdma_list_busy(vpdma, list_num) && timeout--)
+ ;
+
+ if (timeout == 0) {
+ dev_err(&vpdma->pdev->dev, "Timed out cleaning up VPDMA list\n");
+ return -EBUSY;
+ }
+
+ vpdma_unmap_desc_buf(vpdma, &abort_list.buf);
+ vpdma_free_desc_buf(&abort_list.buf);
+
+ return 0;
+}
+EXPORT_SYMBOL(vpdma_list_cleanup);
+
+/*
* create a descriptor list, the user of this list will append configuration,
* control and data descriptors to this list, this list will be submitted to
* VPDMA. VPDMA's list parser will go through each descriptor and perform the
@@ -629,6 +679,31 @@ void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list,
}
EXPORT_SYMBOL(vpdma_add_sync_on_channel_ctd);
+/*
+ * append an 'abort_channel' type control descriptor to the given descriptor
+ * list, this descriptor aborts any DMA transaction happening using the
+ * specified channel
+ */
+void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list,
+ int chan_num)
+{
+ struct vpdma_ctd *ctd;
+
+ ctd = list->next;
+ WARN_ON((void *)(ctd + 1) > (list->buf.addr + list->buf.size));
+
+ ctd->w0 = 0;
+ ctd->w1 = 0;
+ ctd->w2 = 0;
+ ctd->type_source_ctl = ctd_type_source_ctl(chan_num,
+ CTD_TYPE_ABORT_CHANNEL);
+
+ list->next = ctd + 1;
+
+ dump_ctd(ctd);
+}
+EXPORT_SYMBOL(vpdma_add_abort_channel_ctd);
+
static void dump_dtd(struct vpdma_dtd *dtd)
{
int dir, chan;
OpenPOWER on IntegriCloud