media: mfc: NAL-Q: add clock control
authorJeonghee Kim <jhhhh.kim@samsung.com>
Thu, 3 May 2018 09:13:52 +0000 (18:13 +0900)
committerSunyoung Kang <sy0816.kang@samsung.com>
Tue, 29 May 2018 06:59:18 +0000 (15:59 +0900)
Change-Id: Ia9498ddfeb5a3e02ff328859956db62935d3029d
Signed-off-by: Jeonghee Kim <jhhhh.kim@samsung.com>
drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h
drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c
drivers/media/platform/exynos/mfc/s5p_mfc_irq.c
drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.c
drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.h

index 6864e5e3741eb80f644dd2c3a742eb065c6bebd2..ea2428195cbc5f8140166e5a02a57314317cd63b 100644 (file)
@@ -553,7 +553,6 @@ typedef struct __EncoderOutputStr {
  */
 typedef enum _nal_queue_state {
        NAL_Q_STATE_CREATED = 0,
-       NAL_Q_STATE_INITIALIZED,
        NAL_Q_STATE_STARTED, /* when s5p_mfc_nal_q_start() is called */
        NAL_Q_STATE_STOPPED, /* when s5p_mfc_nal_q_stop() is called */
 } nal_queue_state;
@@ -592,6 +591,7 @@ typedef struct _nal_queue_handle {
        nal_queue_in_handle *nal_q_in_handle;
        nal_queue_out_handle *nal_q_out_handle;
        nal_queue_state nal_q_state;
+       unsigned int nal_q_clk_cnt;
        spinlock_t lock;
        int nal_q_exception;
 } nal_queue_handle;
index b379f58ddd5ae2d8d4b8715d0f01ff871073d0ac..d609c3b4c7125a3941516b3c5c186bdcb892b923 100644 (file)
@@ -643,24 +643,16 @@ static int mfc_nal_q_just_run(struct s5p_mfc_ctx *ctx, int need_cache_flush)
                return ret;
        }
 
-       if (nal_q_handle->nal_q_state != NAL_Q_STATE_STARTED
-                       && nal_q_handle->nal_q_state != NAL_Q_STATE_STOPPED) {
-               mfc_debug(2, "continue_clock_on = %d\n", dev->continue_clock_on);
-               if (!dev->continue_clock_on) {
-                       s5p_mfc_pm_clock_on(dev);
-               } else {
-                       dev->continue_clock_on = false;
-               }
-       }
-
        switch (nal_q_handle->nal_q_state) {
        case NAL_Q_STATE_CREATED:
-               s5p_mfc_nal_q_init(dev, nal_q_handle);
-       case NAL_Q_STATE_INITIALIZED:
                if (s5p_mfc_nal_q_check_enable(dev) == 0) {
                        /* NAL START */
                        ret = 1;
                } else {
+                       s5p_mfc_nal_q_clock_on(dev, nal_q_handle);
+
+                       s5p_mfc_nal_q_init(dev, nal_q_handle);
+
                        /* enable NAL QUEUE */
                        if (need_cache_flush)
                                s5p_mfc_cache_flush(dev, ctx->is_drm);
@@ -668,8 +660,10 @@ static int mfc_nal_q_just_run(struct s5p_mfc_ctx *ctx, int need_cache_flush)
                        mfc_info_ctx("NAL Q: start NAL QUEUE\n");
                        s5p_mfc_nal_q_start(dev, nal_q_handle);
 
-                       if (s5p_mfc_nal_q_enqueue_in_buf(dev, ctx, nal_q_handle->nal_q_in_handle))
+                       if (s5p_mfc_nal_q_enqueue_in_buf(dev, ctx, nal_q_handle->nal_q_in_handle)) {
                                mfc_debug(2, "NAL Q: Failed to enqueue input data\n");
+                               s5p_mfc_nal_q_clock_off(dev, nal_q_handle);
+                       }
 
                        s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
                        if ((s5p_mfc_ctx_ready(ctx) && !ctx->clear_work_bit) ||
@@ -686,6 +680,8 @@ static int mfc_nal_q_just_run(struct s5p_mfc_ctx *ctx, int need_cache_flush)
                }
                break;
        case NAL_Q_STATE_STARTED:
+               s5p_mfc_nal_q_clock_on(dev, nal_q_handle);
+
                if (s5p_mfc_nal_q_check_enable(dev) == 0 ||
                                nal_q_handle->nal_q_exception) {
                        /* disable NAL QUEUE */
@@ -697,14 +693,14 @@ static int mfc_nal_q_just_run(struct s5p_mfc_ctx *ctx, int need_cache_flush)
                                dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_STOP_NAL_Q);
                                call_dop(dev, dump_and_stop_always, dev);
                        }
-                       nal_q_handle->nal_q_exception = 0;
                        ret = 1;
-                       s5p_mfc_pm_clock_on(dev);
                        break;
                } else {
                        /* NAL QUEUE */
-                       if (s5p_mfc_nal_q_enqueue_in_buf(dev, ctx, nal_q_handle->nal_q_in_handle))
+                       if (s5p_mfc_nal_q_enqueue_in_buf(dev, ctx, nal_q_handle->nal_q_in_handle)) {
                                mfc_debug(2, "NAL Q: Failed to enqueue input data\n");
+                               s5p_mfc_nal_q_clock_off(dev, nal_q_handle);
+                       }
 
                        s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
 
@@ -882,14 +878,13 @@ int s5p_mfc_just_run(struct s5p_mfc_dev *dev, int new_ctx_index)
                        return ret;
                }
        }
-#else
+#endif
        mfc_debug(2, "continue_clock_on = %d\n", dev->continue_clock_on);
        if (!dev->continue_clock_on) {
                s5p_mfc_pm_clock_on(dev);
        } else {
                dev->continue_clock_on = false;
        }
-#endif
 
        if (need_cache_flush)
                s5p_mfc_cache_flush(dev, ctx->is_drm);
index 403fdba16e654f4ca873387f1f9adcba211c248a..4dcc963d6636c91de6b7bb258f8d88335e13579d 100644 (file)
@@ -1336,14 +1336,18 @@ static inline int mfc_nal_q_irq(struct s5p_mfc_dev *dev,
                                        &dev->work_bits);
                s5p_mfc_clear_int_sfr();
 
+               if (!nal_q_handle->nal_q_exception)
+                       s5p_mfc_nal_q_clock_off(dev, nal_q_handle);
+
                ret = 0;
                break;
        case S5P_FIMV_R2H_CMD_COMPLETE_QUEUE_RET:
                s5p_mfc_watchdog_stop_tick(dev);
-               s5p_mfc_nal_q_cleanup_queue(dev);
                nal_q_handle->nal_q_state = NAL_Q_STATE_CREATED;
                MFC_TRACE_DEV("** NAL Q state : %d\n", nal_q_handle->nal_q_state);
                mfc_debug(2, "NAL Q: return to created state\n");
+               s5p_mfc_nal_q_cleanup_queue(dev);
+               s5p_mfc_nal_q_cleanup_clock(dev);
                s5p_mfc_clear_int_sfr();
                s5p_mfc_pm_clock_off(dev);
                s5p_mfc_wake_up_dev(dev, reason, err);
index c6cfc531aa1e96c7b7abb46bd5865e0cc7312bba..29dbf9c968876e4c266f24ffbf51bc1331dede52 100644 (file)
@@ -125,6 +125,72 @@ int s5p_mfc_nal_q_check_enable(struct s5p_mfc_dev *dev)
        return 1;
 }
 
+void s5p_mfc_nal_q_clock_on(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
+{
+       unsigned long flags;
+
+       mfc_debug_enter();
+
+       spin_lock_irqsave(&nal_q_handle->lock, flags);
+
+       mfc_debug(2, "NAL Q: continue_clock_on = %d, nal_q_clk_cnt = %d\n",
+                       dev->continue_clock_on, nal_q_handle->nal_q_clk_cnt);
+
+       if (!dev->continue_clock_on && !nal_q_handle->nal_q_clk_cnt)
+               s5p_mfc_pm_clock_on(dev);
+
+       nal_q_handle->nal_q_clk_cnt++;
+       dev->continue_clock_on = false;
+
+       mfc_debug(2, "NAL Q: nal_q_clk_cnt = %d\n", nal_q_handle->nal_q_clk_cnt);
+
+       spin_unlock_irqrestore(&nal_q_handle->lock, flags);
+
+       mfc_debug_leave();
+}
+
+void s5p_mfc_nal_q_clock_off(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
+{
+       unsigned long flags;
+
+       mfc_debug_enter();
+
+       spin_lock_irqsave(&nal_q_handle->lock, flags);
+
+       mfc_debug(2, "NAL Q: nal_q_clk_cnt = %d\n", nal_q_handle->nal_q_clk_cnt);
+
+       if (!nal_q_handle->nal_q_clk_cnt) {
+               mfc_err_dev("NAL Q: nal_q_clk_cnt is already zero.\n");
+               return;
+       }
+
+       nal_q_handle->nal_q_clk_cnt--;
+
+       if (!nal_q_handle->nal_q_clk_cnt)
+               s5p_mfc_pm_clock_off(dev);
+
+       mfc_debug(2, "NAL Q: nal_q_clk_cnt = %d\n", nal_q_handle->nal_q_clk_cnt);
+
+       spin_unlock_irqrestore(&nal_q_handle->lock, flags);
+
+       mfc_debug_leave();
+}
+
+void s5p_mfc_nal_q_cleanup_clock(struct s5p_mfc_dev *dev)
+{
+       unsigned long flags;
+
+       mfc_debug_enter();
+
+       spin_lock_irqsave(&dev->nal_q_handle->lock, flags);
+
+       dev->nal_q_handle->nal_q_clk_cnt = 0;
+
+       spin_unlock_irqrestore(&dev->nal_q_handle->lock, flags);
+
+       mfc_debug_leave();
+}
+
 static int mfc_nal_q_find_ctx(struct s5p_mfc_dev *dev, EncoderOutputStr *pOutputStr)
 {
        int i;
@@ -242,8 +308,8 @@ static int mfc_nal_q_destroy_out_q(struct s5p_mfc_dev *dev,
 }
 
 /*
 * This function should be called after s5p_mfc_alloc_firmware() being called.
 */
+ * This function should be called after s5p_mfc_alloc_firmware() being called.
+ */
 nal_queue_handle *s5p_mfc_nal_q_create(struct s5p_mfc_dev *dev)
 {
        nal_queue_handle *nal_q_handle;
@@ -358,9 +424,6 @@ void s5p_mfc_nal_q_init(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
                s5p_mfc_get_nal_q_info());
 
        nal_q_handle->nal_q_exception = 0;
-       nal_q_handle->nal_q_state = NAL_Q_STATE_INITIALIZED;
-       MFC_TRACE_DEV("** NAL Q state : %d\n", nal_q_handle->nal_q_state);
-       mfc_debug(2, "NAL Q: initialized, state = %d\n", nal_q_handle->nal_q_state);
 
        mfc_debug_leave();
 
@@ -383,7 +446,7 @@ void s5p_mfc_nal_q_start(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle
                return;
        }
 
-       if (nal_q_handle->nal_q_state != NAL_Q_STATE_INITIALIZED) {
+       if (nal_q_handle->nal_q_state != NAL_Q_STATE_CREATED) {
                mfc_err_dev("NAL Q: State is wrong, state: %d\n", nal_q_handle->nal_q_state);
                return;
        }
@@ -473,6 +536,8 @@ void s5p_mfc_nal_q_stop_if_started(struct s5p_mfc_dev *dev)
                return;
        }
 
+       s5p_mfc_nal_q_clock_on(dev, nal_q_handle);
+
        s5p_mfc_nal_q_stop(dev, nal_q_handle);
        mfc_info_dev("NAL Q: stop NAL QUEUE during get hwlock\n");
        if (s5p_mfc_wait_for_done_dev(dev,
@@ -1403,6 +1468,7 @@ static void mfc_nal_q_handle_frame_input(struct s5p_mfc_ctx *ctx, unsigned int e
                dec->remained_size = src_mb->vb.vb2_buf.planes[0].bytesused
                        - dec->consumed;
                dec->has_multiframe = 1;
+               dev->nal_q_handle->nal_q_exception = 1;
 
                MFC_TRACE_CTX("** consumed:%ld, remained:%ld, addr:0x%08llx\n",
                        dec->consumed, dec->remained_size, dec->y_addr_for_pb);
@@ -1631,8 +1697,8 @@ int s5p_mfc_nal_q_handle_out_buf(struct s5p_mfc_dev *dev, EncoderOutputStr *pOut
 }
 
 /*
 * This function should be called in NAL_Q_STATE_INITIALIZED or NAL_Q_STATE_STARTED state.
 */
* This function should be called in NAL_Q_STATE_STARTED state.
+ */
 int s5p_mfc_nal_q_enqueue_in_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
        nal_queue_in_handle *nal_q_in_handle)
 {
@@ -1651,8 +1717,7 @@ int s5p_mfc_nal_q_enqueue_in_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ct
                return -EINVAL;
        }
 
-       if ((nal_q_in_handle->nal_q_handle->nal_q_state != NAL_Q_STATE_INITIALIZED)
-               && (nal_q_in_handle->nal_q_handle->nal_q_state != NAL_Q_STATE_STARTED)) {
+       if (nal_q_in_handle->nal_q_handle->nal_q_state != NAL_Q_STATE_STARTED) {
                mfc_err_dev("NAL Q: State is wrong, state: %d\n",
                                nal_q_in_handle->nal_q_handle->nal_q_state);
                return -EINVAL;
@@ -1724,8 +1789,8 @@ int s5p_mfc_nal_q_enqueue_in_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ct
 }
 
 /*
 * This function should be called in NAL_Q_STATE_STARTED state.
 */
+ * This function should be called in NAL_Q_STATE_STARTED state.
+ */
 EncoderOutputStr *s5p_mfc_nal_q_dequeue_out_buf(struct s5p_mfc_dev *dev,
        nal_queue_out_handle *nal_q_out_handle, unsigned int *reason)
 {
index 656896ffe394ea407a78ea7954aaf62150694d4f..f9b14a8ce2f552d9429970be03e955fede898e4e 100644 (file)
 
 int s5p_mfc_nal_q_check_enable(struct s5p_mfc_dev *dev);
 
+void s5p_mfc_nal_q_clock_on(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
+void s5p_mfc_nal_q_clock_off(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
+void s5p_mfc_nal_q_cleanup_clock(struct s5p_mfc_dev *dev);
+
 nal_queue_handle *s5p_mfc_nal_q_create(struct s5p_mfc_dev *dev);
 int s5p_mfc_nal_q_destroy(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);