diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index e1c3841c82de..ddc622e589b0 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -465,6 +465,9 @@ struct mdss_mdp_ctl { u32 vsync_cnt; u32 underrun_cnt; + struct work_struct cpu_pm_work; + int autorefresh_frame_cnt; + u16 width; u16 height; u16 border_x_off; @@ -1910,6 +1913,7 @@ int mdss_mdp_ctl_cmd_set_autorefresh(struct mdss_mdp_ctl *ctl, int frame_cnt); int mdss_mdp_ctl_cmd_get_autorefresh(struct mdss_mdp_ctl *ctl); int mdss_mdp_enable_panel_disable_mode(struct msm_fb_data_type *mfd, bool disable_panel); +void mdss_mdp_ctl_event_timer(void *data); int mdss_mdp_pp_get_version(struct mdp_pp_feature_version *version); int mdss_mdp_layer_pre_commit_cwb(struct msm_fb_data_type *mfd, struct mdp_layer_commit_v1 *commit); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 9ed44937efe6..c92f33cf743b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -22,6 +22,7 @@ #include #include +#include #include "mdss_fb.h" #include "mdss_mdp.h" #include "mdss_mdp_trace.h" @@ -2681,12 +2682,122 @@ int mdss_mdp_block_mixer_destroy(struct mdss_mdp_mixer *mixer) return 0; } +int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl, + ktime_t *wakeup_time) +{ + struct mdss_panel_info *pinfo; + u64 clk_rate; + u32 clk_period; + u32 current_line, total_line; + u32 time_of_line, time_to_vsync, adjust_line_ns; + + ktime_t current_time = ktime_get(); + + if (!ctl->ops.read_line_cnt_fnc) + return -EINVAL; + + pinfo = &ctl->panel_data->panel_info; + if (!pinfo) + return -ENODEV; + + clk_rate = mdss_mdp_get_pclk_rate(ctl); + + clk_rate = DIV_ROUND_UP_ULL(clk_rate, 1000); /* in kHz */ + if (!clk_rate) + return -EINVAL; + + /* + * calculate clk_period as pico second to maintain good + * accuracy with high pclk rate and this number is in 17 bit + * range. + */ + clk_period = DIV_ROUND_UP_ULL(1000000000, clk_rate); + if (!clk_period) + return -EINVAL; + + time_of_line = (pinfo->lcdc.h_back_porch + + pinfo->lcdc.h_front_porch + + pinfo->lcdc.h_pulse_width + + pinfo->xres) * clk_period; + + time_of_line /= 1000; /* in nano second */ + if (!time_of_line) + return -EINVAL; + + current_line = ctl->ops.read_line_cnt_fnc(ctl); + + total_line = pinfo->lcdc.v_back_porch + + pinfo->lcdc.v_front_porch + + pinfo->lcdc.v_pulse_width + + pinfo->yres; + + if (current_line >= total_line) + time_to_vsync = time_of_line * total_line; + else + time_to_vsync = time_of_line * (total_line - current_line); + + if (pinfo->adjust_timer_delay_ms) { + adjust_line_ns = pinfo->adjust_timer_delay_ms + * 1000000; /* convert to ns */ + + /* Ignore large values of adjust_line_ns\ */ + if (time_to_vsync > adjust_line_ns) + time_to_vsync -= adjust_line_ns; + } + + if (!time_to_vsync) + return -EINVAL; + + *wakeup_time = ktime_add_ns(current_time, time_to_vsync); + + pr_debug("clk_rate=%lldkHz clk_period=%d cur_line=%d tot_line=%d\n", + clk_rate, clk_period, current_line, total_line); + pr_debug("time_to_vsync=%d current_time=%d wakeup_time=%d\n", + time_to_vsync, (int)ktime_to_ms(current_time), + (int)ktime_to_ms(*wakeup_time)); + + return 0; +} + +static void __cpu_pm_work_handler(struct work_struct *work) +{ + struct mdss_mdp_ctl *ctl = + container_of(work, typeof(*ctl), cpu_pm_work); + ktime_t wakeup_time; + struct mdss_overlay_private *mdp5_data; + + if (!ctl) + return; + + if (mdss_mdp_display_wakeup_time(ctl, &wakeup_time)) + return; + + mdp5_data = mfd_to_mdp5_data(ctl->mfd); + activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time); +} + +void mdss_mdp_ctl_event_timer(void *data) +{ + struct mdss_overlay_private *mdp5_data = + (struct mdss_overlay_private *)data; + struct mdss_mdp_ctl *ctl = mdp5_data->ctl; + + if (mdp5_data->cpu_pm_hdl && ctl && ctl->autorefresh_frame_cnt) + schedule_work(&ctl->cpu_pm_work); +} + int mdss_mdp_ctl_cmd_set_autorefresh(struct mdss_mdp_ctl *ctl, int frame_cnt) { int ret = 0; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd); if (ctl->panel_data->panel_info.type == MIPI_CMD_PANEL) { ret = mdss_mdp_cmd_set_autorefresh_mode(ctl, frame_cnt); + if (!ret) { + ctl->autorefresh_frame_cnt = frame_cnt; + if (frame_cnt) + mdss_mdp_ctl_event_timer(mdp5_data); + } } else { pr_err("Mode not supported for this panel\n"); ret = -EINVAL; @@ -3824,6 +3935,7 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata, ctl->intf_type = MDSS_INTF_DSI; ctl->opmode = MDSS_MDP_CTL_OP_CMD_MODE; ctl->ops.start_fnc = mdss_mdp_cmd_start; + INIT_WORK(&ctl->cpu_pm_work, __cpu_pm_work_handler); break; case DTV_PANEL: ctl->is_video_mode = true; @@ -5408,83 +5520,6 @@ exit: return ret; } -int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl, - ktime_t *wakeup_time) -{ - struct mdss_panel_info *pinfo; - u64 clk_rate; - u32 clk_period; - u32 current_line, total_line; - u32 time_of_line, time_to_vsync, adjust_line_ns; - - ktime_t current_time = ktime_get(); - - if (!ctl->ops.read_line_cnt_fnc) - return -ENOSYS; - - pinfo = &ctl->panel_data->panel_info; - if (!pinfo) - return -ENODEV; - - clk_rate = mdss_mdp_get_pclk_rate(ctl); - - clk_rate = DIV_ROUND_UP_ULL(clk_rate, 1000); /* in kHz */ - if (!clk_rate) - return -EINVAL; - - /* - * calculate clk_period as pico second to maintain good - * accuracy with high pclk rate and this number is in 17 bit - * range. - */ - clk_period = DIV_ROUND_UP_ULL(1000000000, clk_rate); - if (!clk_period) - return -EINVAL; - - time_of_line = (pinfo->lcdc.h_back_porch + - pinfo->lcdc.h_front_porch + - pinfo->lcdc.h_pulse_width + - pinfo->xres) * clk_period; - - time_of_line /= 1000; /* in nano second */ - if (!time_of_line) - return -EINVAL; - - current_line = ctl->ops.read_line_cnt_fnc(ctl); - - total_line = pinfo->lcdc.v_back_porch + - pinfo->lcdc.v_front_porch + - pinfo->lcdc.v_pulse_width + - pinfo->yres; - - if (current_line > total_line) - return -EINVAL; - - time_to_vsync = time_of_line * (total_line - current_line); - - if (pinfo->adjust_timer_delay_ms) { - adjust_line_ns = pinfo->adjust_timer_delay_ms - * 1000000; /* convert to ns */ - - /* Ignore large values of adjust_line_ns\ */ - if (time_to_vsync > adjust_line_ns) - time_to_vsync -= adjust_line_ns; - } - - if (!time_to_vsync) - return -EINVAL; - - *wakeup_time = ktime_add_ns(current_time, time_to_vsync); - - pr_debug("clk_rate=%lldkHz clk_period=%d cur_line=%d tot_line=%d\n", - clk_rate, clk_period, current_line, total_line); - pr_debug("time_to_vsync=%d current_time=%d wakeup_time=%d\n", - time_to_vsync, (int)ktime_to_ms(current_time), - (int)ktime_to_ms(*wakeup_time)); - - return 0; -} - int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl) { int ret; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 664850a1a617..2a65c276fb9e 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -6082,8 +6082,8 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) /* Adding event timer only for primary panel */ if ((mfd->index == 0) && (mfd->panel_info->type != WRITEBACK_PANEL)) { - mdp5_data->cpu_pm_hdl = add_event_timer(mdss_irq->irq, NULL, - (void *)mdp5_data); + mdp5_data->cpu_pm_hdl = add_event_timer(mdss_irq->irq, + mdss_mdp_ctl_event_timer, (void *)mdp5_data); if (!mdp5_data->cpu_pm_hdl) pr_warn("%s: unable to add event timer\n", __func__); }