From e483397ef59bf573ba730786bcbebd9c0f481b8c Mon Sep 17 00:00:00 2001 From: Jeonghee Kim Date: Thu, 3 May 2018 18:13:52 +0900 Subject: [PATCH] media: mfc: NAL-Q: add clock control Change-Id: Ia9498ddfeb5a3e02ff328859956db62935d3029d Signed-off-by: Jeonghee Kim --- .../platform/exynos/mfc/s5p_mfc_data_struct.h | 2 +- .../platform/exynos/mfc/s5p_mfc_hwlock.c | 31 +++---- .../media/platform/exynos/mfc/s5p_mfc_irq.c | 6 +- .../media/platform/exynos/mfc/s5p_mfc_nal_q.c | 89 ++++++++++++++++--- .../media/platform/exynos/mfc/s5p_mfc_nal_q.h | 4 + 5 files changed, 100 insertions(+), 32 deletions(-) diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h b/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h index 6864e5e3741e..ea2428195cbc 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h @@ -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; diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c b/drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c index b379f58ddd5a..d609c3b4c712 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c @@ -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); diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_irq.c b/drivers/media/platform/exynos/mfc/s5p_mfc_irq.c index 403fdba16e65..4dcc963d6636 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_irq.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_irq.c @@ -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); diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.c b/drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.c index c6cfc531aa1e..29dbf9c96887 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.c @@ -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) { diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.h b/drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.h index 656896ffe394..f9b14a8ce2f5 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.h @@ -17,6 +17,10 @@ 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); -- 2.20.1