From eafa1431d4da8000d7a3a04ca8be25926e2edca0 Mon Sep 17 00:00:00 2001 From: Even Xu Date: Fri, 16 Dec 2011 11:09:27 +0800 Subject: [PATCH] ENGR00170447 MX6Q: Fix CSI SMFC cannot disable normally Root cause is: Ipu driver use msleep to wait for smfc idle, msleep isn't a Accurate timer, but CSI SMFC is a real-time channel, so use Interrupt handler to replace msleep. Signed-off-by: Even Xu --- drivers/mxc/ipu3/ipu_capture.c | 53 ++++++++++++++++++++++++++++++++++ drivers/mxc/ipu3/ipu_common.c | 5 +++- drivers/mxc/ipu3/ipu_prv.h | 2 ++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c index ff7384530045..e35d1b53016c 100644 --- a/drivers/mxc/ipu3/ipu_capture.c +++ b/drivers/mxc/ipu3/ipu_capture.c @@ -744,3 +744,56 @@ int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi) err: return retval; } + +/*! + * csi_irq_handler + * + * @param irq interrupt id + * @param dev_id pointer to ipu handler + * + * @return Returns if irq is handled + */ +static irqreturn_t csi_irq_handler(int irq, void *dev_id) +{ + struct ipu_soc *ipu = dev_id; + struct completion *comp = &ipu->csi_comp; + + complete(comp); + return IRQ_HANDLED; +} + +/*! + * _ipu_csi_wait4eof + * + * @param ipu ipu handler + * @param channel IDMAC channel + * + */ +void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel) +{ + int ret; + int irq = 0; + + if (channel == CSI_MEM0) + irq = IPU_IRQ_CSI0_OUT_EOF; + else if (channel == CSI_MEM1) + irq = IPU_IRQ_CSI1_OUT_EOF; + else if (channel == CSI_MEM2) + irq = IPU_IRQ_CSI2_OUT_EOF; + else if (channel == CSI_MEM3) + irq = IPU_IRQ_CSI3_OUT_EOF; + else{ + dev_err(ipu->dev, "Not a CSI SMFC channel\n"); + return; + } + + init_completion(&ipu->csi_comp); + ret = ipu_request_irq(ipu, irq, csi_irq_handler, 0, NULL, ipu); + if (ret < 0) { + dev_err(ipu->dev, "CSI irq %d in use\n", irq); + return; + } + ret = wait_for_completion_timeout(&ipu->csi_comp, msecs_to_jiffies(50)); + ipu_free_irq(ipu, irq, ipu); + dev_dbg(ipu->dev, "CSI stop timeout - %d * 10ms\n", 5 - ret); +} diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index e7713199abcb..40297a8718af 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -2193,7 +2193,10 @@ int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wai } } } - } else if (wait_for_stop) { + } else if ((channel == CSI_MEM0) || (channel == CSI_MEM1) || + (channel == CSI_MEM2) || (channel == CSI_MEM3)) + _ipu_csi_wait4eof(ipu, channel); + else if (wait_for_stop) { while (idma_is_set(ipu, IDMAC_CHA_BUSY, in_dma) || idma_is_set(ipu, IDMAC_CHA_BUSY, out_dma) || (ipu->sec_chan_en[IPU_CHAN_ID(channel)] && diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h index 42060c954a1f..68cb87a910fa 100644 --- a/drivers/mxc/ipu3/ipu_prv.h +++ b/drivers/mxc/ipu3/ipu_prv.h @@ -117,6 +117,7 @@ struct ipu_soc { bool color_key_4rgb; bool dc_swap; struct completion dc_comp; + struct completion csi_comp; /* for power gating */ u32 ipu_conf_reg; @@ -325,6 +326,7 @@ void ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_val uint32_t pix_clk, uint32_t csi); void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi); void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi); +void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel); void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi); void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs); void _ipu_dp_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3]); -- 2.39.5