Loading drivers/video/msm/mdss/mdss_fb.c +10 −2 Original line number Diff line number Diff line Loading @@ -482,6 +482,7 @@ static void __mdss_fb_idle_notify_work(struct work_struct *work) pr_debug("Idle timeout %dms expired!\n", mfd->idle_time); if (mfd->idle_time) sysfs_notify(&mfd->fbi->dev->kobj, NULL, "idle_notify"); mfd->idle_state = MDSS_FB_IDLE; } static ssize_t mdss_fb_get_idle_time(struct device *dev, Loading Loading @@ -1053,9 +1054,13 @@ static int mdss_fb_probe(struct platform_device *pdev) * Register with input driver for a callback for command mode panels. * When there is an input event, mdp clocks will be turned on to reduce * latency when a frame update happens. * Video mode panels are not handled today because clocks are always on. * For video mode panels, idle timeout will be delayed so that userspace * does not get an idle event while new frames are expected. In case of * an idle event, user space tries to fall back to GPU composition which * can lead to increased load when there are new frames. */ if (mfd->panel_info->type == MIPI_CMD_PANEL) if ((mfd->panel_info->type == MIPI_CMD_PANEL) || (mfd->panel_info->type == MIPI_VIDEO_PANEL)) if (mdss_fb_register_input_handler(mfd)) pr_err("failed to register input handler\n"); Loading Loading @@ -2733,6 +2738,8 @@ static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p, msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT))) pr_debug("fb%d: start idle delayed work\n", mfd->index); mfd->idle_state = MDSS_FB_NOT_IDLE; break; case MDP_NOTIFY_FRAME_READY: if (sync_pt_data->async_wait_fences && Loading @@ -2749,6 +2756,7 @@ static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p, mfd->index); if (ret == -ETIME) ret = NOTIFY_BAD; mfd->idle_state = MDSS_FB_IDLE_TIMER_RUNNING; break; case MDP_NOTIFY_FRAME_FLUSHED: pr_debug("%s: frame flushed\n", sync_pt_data->fence_name); Loading drivers/video/msm/mdss/mdss_fb.h +13 −0 Original line number Diff line number Diff line Loading @@ -141,6 +141,18 @@ enum dyn_mode_switch_state { MDSS_MDP_WAIT_FOR_COMMIT, }; /** * enum mdss_fb_idle_state - idle states based on frame updates * @MDSS_FB_NOT_IDLE: Frame updates have started * @MDSS_FB_IDLE_TIMER_RUNNING: Idle timer has been kicked * @MDSS_FB_IDLE: Currently idle */ enum mdss_fb_idle_state { MDSS_FB_NOT_IDLE, MDSS_FB_IDLE_TIMER_RUNNING, MDSS_FB_IDLE }; struct disp_info_type_suspend { int op_enable; int panel_power_state; Loading Loading @@ -257,6 +269,7 @@ struct msm_fb_data_type { struct fb_info *fbi; int idle_time; u32 idle_state; struct delayed_work idle_notify_work; bool validate_pending; Loading drivers/video/msm/mdss/mdss_mdp_intf_video.c +39 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,9 @@ /* Poll time to do recovery during active region */ #define POLL_TIME_USEC_FOR_LN_CNT 500 /* Filter out input events for 1 vsync time after receiving an input event*/ #define INPUT_EVENT_HANDLER_DELAY_USECS 16000 #define MDP_INTR_MASK_INTF_VSYNC(intf_num) \ (1 << (2 * (intf_num - MDSS_MDP_INTF0) + MDSS_MDP_IRQ_INTF_VSYNC)) Loading Loading @@ -1549,6 +1552,41 @@ void mdss_mdp_switch_to_cmd_mode(struct mdss_mdp_ctl *ctl, int prep) mdss_bus_bandwidth_ctrl(false); } static int mdss_mdp_video_early_wake_up(struct mdss_mdp_ctl *ctl) { u64 curr_time; curr_time = ktime_to_us(ktime_get()); if ((curr_time - ctl->last_input_time) < INPUT_EVENT_HANDLER_DELAY_USECS) return 0; ctl->last_input_time = curr_time; /* * If the idle timer is running when input event happens, the timeout * will be delayed by idle_time again to ensure user space does not get * an idle event when new frames are expected. * * It would be nice to have this logic in mdss_fb.c itself by * implementing a new frame notification event. But input event handler * is called from interrupt context and scheduling a work item adds a * lot of latency rendering the input events useless in preventing the * idle time out. */ if (ctl->mfd->idle_state == MDSS_FB_IDLE_TIMER_RUNNING) { if (ctl->mfd->idle_time) mod_delayed_work(system_wq, &ctl->mfd->idle_notify_work, msecs_to_jiffies(ctl->mfd->idle_time)); pr_debug("Delayed idle time\n"); } else { pr_debug("Nothing to done for this state (%d)\n", ctl->mfd->idle_state); } return 0; } int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl) { int intfs_num, ret = 0; Loading @@ -1567,6 +1605,7 @@ int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl) ctl->ops.add_vsync_handler = mdss_mdp_video_add_vsync_handler; ctl->ops.remove_vsync_handler = mdss_mdp_video_remove_vsync_handler; ctl->ops.config_fps_fnc = mdss_mdp_video_config_fps; ctl->ops.early_wake_up_fnc = mdss_mdp_video_early_wake_up; return 0; } Loading Loading
drivers/video/msm/mdss/mdss_fb.c +10 −2 Original line number Diff line number Diff line Loading @@ -482,6 +482,7 @@ static void __mdss_fb_idle_notify_work(struct work_struct *work) pr_debug("Idle timeout %dms expired!\n", mfd->idle_time); if (mfd->idle_time) sysfs_notify(&mfd->fbi->dev->kobj, NULL, "idle_notify"); mfd->idle_state = MDSS_FB_IDLE; } static ssize_t mdss_fb_get_idle_time(struct device *dev, Loading Loading @@ -1053,9 +1054,13 @@ static int mdss_fb_probe(struct platform_device *pdev) * Register with input driver for a callback for command mode panels. * When there is an input event, mdp clocks will be turned on to reduce * latency when a frame update happens. * Video mode panels are not handled today because clocks are always on. * For video mode panels, idle timeout will be delayed so that userspace * does not get an idle event while new frames are expected. In case of * an idle event, user space tries to fall back to GPU composition which * can lead to increased load when there are new frames. */ if (mfd->panel_info->type == MIPI_CMD_PANEL) if ((mfd->panel_info->type == MIPI_CMD_PANEL) || (mfd->panel_info->type == MIPI_VIDEO_PANEL)) if (mdss_fb_register_input_handler(mfd)) pr_err("failed to register input handler\n"); Loading Loading @@ -2733,6 +2738,8 @@ static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p, msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT))) pr_debug("fb%d: start idle delayed work\n", mfd->index); mfd->idle_state = MDSS_FB_NOT_IDLE; break; case MDP_NOTIFY_FRAME_READY: if (sync_pt_data->async_wait_fences && Loading @@ -2749,6 +2756,7 @@ static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p, mfd->index); if (ret == -ETIME) ret = NOTIFY_BAD; mfd->idle_state = MDSS_FB_IDLE_TIMER_RUNNING; break; case MDP_NOTIFY_FRAME_FLUSHED: pr_debug("%s: frame flushed\n", sync_pt_data->fence_name); Loading
drivers/video/msm/mdss/mdss_fb.h +13 −0 Original line number Diff line number Diff line Loading @@ -141,6 +141,18 @@ enum dyn_mode_switch_state { MDSS_MDP_WAIT_FOR_COMMIT, }; /** * enum mdss_fb_idle_state - idle states based on frame updates * @MDSS_FB_NOT_IDLE: Frame updates have started * @MDSS_FB_IDLE_TIMER_RUNNING: Idle timer has been kicked * @MDSS_FB_IDLE: Currently idle */ enum mdss_fb_idle_state { MDSS_FB_NOT_IDLE, MDSS_FB_IDLE_TIMER_RUNNING, MDSS_FB_IDLE }; struct disp_info_type_suspend { int op_enable; int panel_power_state; Loading Loading @@ -257,6 +269,7 @@ struct msm_fb_data_type { struct fb_info *fbi; int idle_time; u32 idle_state; struct delayed_work idle_notify_work; bool validate_pending; Loading
drivers/video/msm/mdss/mdss_mdp_intf_video.c +39 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,9 @@ /* Poll time to do recovery during active region */ #define POLL_TIME_USEC_FOR_LN_CNT 500 /* Filter out input events for 1 vsync time after receiving an input event*/ #define INPUT_EVENT_HANDLER_DELAY_USECS 16000 #define MDP_INTR_MASK_INTF_VSYNC(intf_num) \ (1 << (2 * (intf_num - MDSS_MDP_INTF0) + MDSS_MDP_IRQ_INTF_VSYNC)) Loading Loading @@ -1549,6 +1552,41 @@ void mdss_mdp_switch_to_cmd_mode(struct mdss_mdp_ctl *ctl, int prep) mdss_bus_bandwidth_ctrl(false); } static int mdss_mdp_video_early_wake_up(struct mdss_mdp_ctl *ctl) { u64 curr_time; curr_time = ktime_to_us(ktime_get()); if ((curr_time - ctl->last_input_time) < INPUT_EVENT_HANDLER_DELAY_USECS) return 0; ctl->last_input_time = curr_time; /* * If the idle timer is running when input event happens, the timeout * will be delayed by idle_time again to ensure user space does not get * an idle event when new frames are expected. * * It would be nice to have this logic in mdss_fb.c itself by * implementing a new frame notification event. But input event handler * is called from interrupt context and scheduling a work item adds a * lot of latency rendering the input events useless in preventing the * idle time out. */ if (ctl->mfd->idle_state == MDSS_FB_IDLE_TIMER_RUNNING) { if (ctl->mfd->idle_time) mod_delayed_work(system_wq, &ctl->mfd->idle_notify_work, msecs_to_jiffies(ctl->mfd->idle_time)); pr_debug("Delayed idle time\n"); } else { pr_debug("Nothing to done for this state (%d)\n", ctl->mfd->idle_state); } return 0; } int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl) { int intfs_num, ret = 0; Loading @@ -1567,6 +1605,7 @@ int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl) ctl->ops.add_vsync_handler = mdss_mdp_video_add_vsync_handler; ctl->ops.remove_vsync_handler = mdss_mdp_video_remove_vsync_handler; ctl->ops.config_fps_fnc = mdss_mdp_video_config_fps; ctl->ops.early_wake_up_fnc = mdss_mdp_video_early_wake_up; return 0; } Loading