]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00170447 MX6Q: Fix CSI SMFC cannot disable normally
authorEven Xu <Feng.Xu@freescale.com>
Fri, 16 Dec 2011 03:09:27 +0000 (11:09 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:33:39 +0000 (08:33 +0200)
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 <b21019@freescale.com>
drivers/mxc/ipu3/ipu_capture.c
drivers/mxc/ipu3/ipu_common.c
drivers/mxc/ipu3/ipu_prv.h

index ff738453004558ca30ea34d1eefd263a2428483c..e35d1b53016ce545847d7d6425ec6c9011cfb065 100644 (file)
@@ -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);
+}
index e7713199abcbfe99eab243fbe187a54544a54c7c..40297a8718af1a4fe48e2883531b919792e266a4 100644 (file)
@@ -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)] &&
index 42060c954a1f998029fba47850c6a0e5868eb8e3..68cb87a910fa36b0f571f6571523e995a37e5bbc 100644 (file)
@@ -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]);