[COMMON] fimc-is2: move csi dma disable to DMA ISR & modify DMA state.
authorWooyeon Kim <wooy88.kim@samsung.com>
Mon, 8 Apr 2019 07:44:32 +0000 (16:44 +0900)
committerKim Gunho <gunho.kim@samsung.com>
Wed, 7 Aug 2019 12:59:51 +0000 (21:59 +0900)
 - CSIS core start not guerantee CSIS DMA starts.

 PR JIRA ID: CPR-966

Change-Id: Ifadfe55c34c57c30997e8334b45a19daef5a07c6
Signed-off-by: Wooyeon Kim <wooy88.kim@samsung.com>
drivers/media/platform/exynos/fimc-is2/fimc-is-device-csi.h
drivers/media/platform/exynos/fimc-is2/fimc-is-device-csi_v4.c

index baa0bebe0ed17d76357bc580f882323529bc17ae..7d8efa2dfd3ba75aacf141885ee22776420a747a 100644 (file)
@@ -96,6 +96,7 @@ struct fimc_is_device_csi {
        struct work_struct              wq_csis_dma[CSI_VIRTUAL_CH_MAX];
        struct workqueue_struct         *workqueue;
        int                             pre_dma_enable[CSI_VIRTUAL_CH_MAX];
+       int                             cur_dma_enable[CSI_VIRTUAL_CH_MAX];
 
        /* subdev slots for dma */
        struct fimc_is_subdev           *dma_subdev[CSI_VIRTUAL_CH_MAX];
index 0208acaf844726f936645f681fc776e029a0d3b7..1db3380db1433041a0575b004adcfc33ea400ff8 100644 (file)
@@ -258,10 +258,9 @@ static void csis_s_vc_dma_multibuf(struct fimc_is_device_csi *csi)
        }
 }
 
-static void csis_disable_all_vc_dma_buf(struct fimc_is_device_csi *csi)
+static void csis_check_vc_dma_buf(struct fimc_is_device_csi *csi)
 {
        u32 vc;
-       int cur_dma_enable;
        struct fimc_is_framemgr *framemgr;
        struct fimc_is_frame *frame;
        struct fimc_is_subdev *dma_subdev;
@@ -276,12 +275,6 @@ static void csis_disable_all_vc_dma_buf(struct fimc_is_device_csi *csi)
                        test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &dma_subdev->state))
                        continue;
 
-               /* default dma disable */
-               csi_s_output_dma(csi, vc, false);
-
-               /* print infomation DMA on/off */
-               cur_dma_enable = csi_hw_g_output_cur_dma_enable(csi->vc_reg[csi->scm][vc], vc);
-
                framemgr = GET_SUBDEV_FRAMEMGR(dma_subdev);
                framemgr_e_barrier(framemgr, 0);
                if (likely(framemgr)) {
@@ -302,22 +295,26 @@ static void csis_disable_all_vc_dma_buf(struct fimc_is_device_csi *csi)
                         * The invalid state indicates that there is process frame at DMA off.
                         */
                        if (framemgr->queued_count[FS_PROCESS] &&
-                               !csi->pre_dma_enable[vc] && !cur_dma_enable) {
+                               !csi->pre_dma_enable[vc] && !csi->cur_dma_enable[vc]) {
                                csi_s_output_dma(csi, vc, true);
                                minfo("[VC%d] DMA on forcely[P(%d)]\n", csi, vc, framemgr->queued_count[FS_PROCESS]);
                                print_frame_queue(framemgr, FS_PROCESS);
                        }
 
+                       /* print infomation DMA on/off */
                        if (test_bit(CSIS_START_STREAM, &csi->state) &&
-                               csi->pre_dma_enable[vc] != cur_dma_enable) {
+                               csi->pre_dma_enable[vc] != csi->cur_dma_enable[vc]) {
                                minfo("[VC%d][F%d] DMA %s [%d/%d/%d]\n", csi, vc, atomic_read(&csi->fcount),
-                                               (cur_dma_enable ? "on" : "off"),
+                                               (csi->cur_dma_enable[vc] ? "on" : "off"),
                                                framemgr->queued_count[FS_REQUEST],
                                                framemgr->queued_count[FS_PROCESS],
                                                framemgr->queued_count[FS_COMPLETE]);
 
-                               csi->pre_dma_enable[vc] = cur_dma_enable;
+                               csi->pre_dma_enable[vc] = csi->cur_dma_enable[vc];
                        }
+
+                       /* after update pre_dma_disable, clear dma enable state */
+                       csi->cur_dma_enable[vc] = 0;
                } else {
                        merr("[VC%d] framemgr is NULL", csi, vc);
                }
@@ -533,8 +530,8 @@ void tasklet_csis_str_otf(unsigned long data)
        }
 
 trigger_skip:
-       /* disable all virtual channel's dma */
-       csis_disable_all_vc_dma_buf(csi);
+       /* check all virtual channel's dma */
+       csis_check_vc_dma_buf(csi);
        /* re-set internal vc dma if flushed */
        csis_s_vc_dma_multibuf(csi);
 
@@ -563,8 +560,8 @@ void tasklet_csis_str_m2m(unsigned long data)
 #ifdef TASKLET_MSG
        pr_info("S%d\n", fcount);
 #endif
-       /* disable all virtual channel's dma */
-       csis_disable_all_vc_dma_buf(csi);
+       /* check all virtual channel's dma */
+       csis_check_vc_dma_buf(csi);
        /* re-set internal vc dma if flushed */
        csis_s_vc_dma_multibuf(csi);
 
@@ -1083,6 +1080,7 @@ static inline void csi_wq_func_schedule(struct fimc_is_device_csi *csi,
 static irqreturn_t fimc_is_isr_csi_dma(int irq, void *data)
 {
        struct fimc_is_device_csi *csi;
+       int dma_frame_str = 0;
        int dma_frame_end = 0;
        int dma_err_flag = 0;
        u32 dma_err_id[CSI_VIRTUAL_CH_MAX];
@@ -1113,14 +1111,16 @@ static irqreturn_t fimc_is_isr_csi_dma(int irq, void *data)
                dma_err_id[vc] = irq_src.err_id[vc_phys];
                dma_err_flag |= dma_err_id[vc];
 
+               if (irq_src.dma_start)
+                       dma_frame_str |= 1 << vc;
+
                if (irq_src.dma_end)
                        dma_frame_end |= 1 << vc;
        }
 
-       dbg_isr("DE %d %X\n", csi, csi->instance, dma_frame_end);
-
        /* DMA End */
        if (dma_frame_end) {
+               dbg_isr("DE %d %X\n", csi, csi->instance, dma_frame_end);
 #if !defined(SUPPORTED_EARLYBUF_DONE_HW)
                /* VC0 */
                if (csi->dma_subdev[CSI_VIRTUAL_CH_0] && (dma_frame_end & (1 << CSI_VIRTUAL_CH_0))) {
@@ -1153,6 +1153,19 @@ static irqreturn_t fimc_is_isr_csi_dma(int irq, void *data)
                }
        }
 
+       if (dma_frame_str) {
+               dbg_isr("DS %d %X\n", csi, csi->instance, dma_frame_str);
+               for (vc = CSI_VIRTUAL_CH_0; vc < CSI_VIRTUAL_CH_MAX; vc++) {
+                       if (!csi->dma_subdev[vc] ||
+                               !test_bit(FIMC_IS_SUBDEV_OPEN, &csi->dma_subdev[vc]->state) ||
+                               test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &csi->dma_subdev[vc]->state))
+                               continue;
+
+                       /* dma disable if interrupt occured */
+                       csi_s_output_dma(csi, vc, false);
+               }
+       }
+
        /* Check error */
        if (dma_err_flag)
                csi_err_check(csi, dma_err_id);
@@ -1534,6 +1547,7 @@ static int csi_stream_on(struct v4l2_subdev *subdev,
                csi->overflow_cnt = 0;
                csi_s_config_dma(csi, sensor_cfg->output);
                memset(csi->pre_dma_enable, -1, sizeof(csi->pre_dma_enable));
+               memset(csi->cur_dma_enable, -1, sizeof(csi->cur_dma_enable));
 
                /* for multi frame buffer setting for internal vc */
                csis_s_vc_dma_multibuf(csi);
@@ -1885,6 +1899,7 @@ static int csi_s_buffer(struct v4l2_subdev *subdev, void *buf, unsigned int *siz
        } else {
                csi_s_buf_addr(csi, frame, 0, vc);
                csi_s_output_dma(csi, vc, true);
+               csi->cur_dma_enable[vc] = 1;
 
                trans_frame(framemgr, frame, FS_PROCESS);
        }