summaryrefslogtreecommitdiff
path: root/drivers/media/platform/omap3isp/ispccdc.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2014-06-10 09:41:57 -0300
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-08-21 15:25:16 -0500
commit93456527b4488510d87a523028b3bb73dfdd7669 (patch)
tree88554f4c19fdc522bcf91c651e05027af273a721 /drivers/media/platform/omap3isp/ispccdc.c
parentfd93c10afe383d7c28b5edffa29f92b6dae55191 (diff)
[media] omap3isp: ccdc: Fix freeze when a short frame is received
In BT.656 mode the synchronization signals are generated by the CCDC from the embedded sync codes. The VD0 and VD1 interrupts are thus only triggered when the CCDC is enabled, unlike external sync mode where the line counter runs even when the CCDC is stopped. We can't disable the CCDC at VD1 time, as no VD0 interrupt would be generated for a short frame, which would result in the CCDC being stopped and no VD interrupt generated anymore. The CCDC is stopped from the VD0 interrupt handler instead for BT.656. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Tested-by: Enrico Butera <ebutera@users.sourceforge.net> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/platform/omap3isp/ispccdc.c')
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 112bced5af99..ff2ea2bf31e4 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -1647,10 +1647,27 @@ static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)
atomic_inc(&pipe->frame_number);
}
+ /* Emulate a VD1 interrupt for BT.656 mode, as we can't stop the CCDC in
+ * the VD1 interrupt handler in that mode without risking a CCDC stall
+ * if a short frame is received.
+ */
+ if (ccdc->bt656) {
+ spin_lock_irqsave(&ccdc->lock, flags);
+ if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+ ccdc->output & CCDC_OUTPUT_MEMORY) {
+ if (ccdc->lsc.state != LSC_STATE_STOPPED)
+ __ccdc_lsc_enable(ccdc, 0);
+ __ccdc_enable(ccdc, 0);
+ }
+ ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1);
+ spin_unlock_irqrestore(&ccdc->lock, flags);
+ }
+
if (ccdc->output & CCDC_OUTPUT_MEMORY)
restart = ccdc_isr_buffer(ccdc);
spin_lock_irqsave(&ccdc->lock, flags);
+
if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
spin_unlock_irqrestore(&ccdc->lock, flags);
return;
@@ -1672,6 +1689,18 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
{
unsigned long flags;
+ /* In BT.656 mode the synchronization signals are generated by the CCDC
+ * from the embedded sync codes. The VD0 and VD1 interrupts are thus
+ * only triggered when the CCDC is enabled, unlike external sync mode
+ * where the line counter runs even when the CCDC is stopped. We can't
+ * disable the CCDC at VD1 time, as no VD0 interrupt would be generated
+ * for a short frame, which would result in the CCDC being stopped and
+ * no VD interrupt generated anymore. The CCDC is stopped from the VD0
+ * interrupt handler instead for BT.656.
+ */
+ if (ccdc->bt656)
+ return;
+
spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
/*