Loading drivers/gpu/drm/msm/msm_drv.h +1 −0 Original line number Diff line number Diff line Loading @@ -147,6 +147,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_ROT_CLK, CRTC_PROP_ROI_V1, CRTC_PROP_SECURITY_LEVEL, CRTC_PROP_IDLE_TIME, /* total # of properties */ CRTC_PROP_COUNT Loading drivers/gpu/drm/msm/sde/sde_crtc.c +72 −3 Original line number Diff line number Diff line Loading @@ -64,6 +64,8 @@ struct sde_crtc_custom_events { static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *ad_irq); static int sde_crtc_idle_interrupt_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *idle_irq); static int sde_crtc_pm_event_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *noirq); Loading @@ -72,6 +74,7 @@ static struct sde_crtc_custom_events custom_events[] = { {DRM_EVENT_AD_BACKLIGHT, sde_cp_ad_interrupt}, {DRM_EVENT_CRTC_POWER, sde_crtc_power_interrupt_handler}, {DRM_EVENT_SDE_POWER, sde_crtc_pm_event_handler}, {DRM_EVENT_IDLE_NOTIFY, sde_crtc_idle_interrupt_handler} }; /* default input fence timeout, in ms */ Loading Loading @@ -1623,7 +1626,8 @@ int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc, if (encoder->crtc != crtc) continue; post_commit &= !sde_encoder_is_cmd_mode(encoder); post_commit &= sde_encoder_check_mode(encoder, MSM_DISPLAY_CAP_VID_MODE); } drm_atomic_crtc_for_each_plane(plane, crtc) { Loading Loading @@ -2493,6 +2497,12 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, if (unlikely(!sde_crtc->num_mixers)) return; /* cancel the idle notify delayed work */ if (sde_encoder_check_mode(sde_crtc->mixers[0].encoder, MSM_DISPLAY_CAP_VID_MODE) && kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work)) SDE_DEBUG("idle notify work cancelled\n"); _sde_crtc_blend_setup(crtc); /* Loading Loading @@ -2522,10 +2532,13 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, struct sde_crtc *sde_crtc; struct drm_device *dev; struct drm_plane *plane; struct msm_drm_private *priv; struct msm_drm_thread *event_thread; unsigned long flags; struct sde_crtc_state *cstate; int idle_time = 0; if (!crtc) { if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid crtc\n"); return; } Loading @@ -2541,6 +2554,15 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(crtc->state); dev = crtc->dev; priv = dev->dev_private; if (crtc->index >= ARRAY_SIZE(priv->event_thread)) { SDE_ERROR("invalid crtc index[%d]\n", crtc->index); return; } event_thread = &priv->event_thread[crtc->index]; idle_time = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_TIME); if (sde_crtc->event) { SDE_DEBUG("already received sde_crtc->event\n"); Loading Loading @@ -2571,6 +2593,15 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, /* wait for acquire fences before anything else is done */ _sde_crtc_wait_for_fences(crtc); /* schedule the idle notify delayed work */ if (idle_time && sde_encoder_check_mode(sde_crtc->mixers[0].encoder, MSM_DISPLAY_CAP_VID_MODE)) { kthread_queue_delayed_work(&event_thread->worker, &sde_crtc->idle_notify_work, msecs_to_jiffies(idle_time)); SDE_DEBUG("schedule idle notify work in %dms\n", idle_time); } if (!cstate->rsc_update) { drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) Loading Loading @@ -3769,6 +3800,9 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, sde_kms->perf.max_core_clk_rate, CRTC_PROP_ROT_CLK); msm_property_install_range(&sde_crtc->property_info, "idle_time", 0x0, 0, U64_MAX, 0, CRTC_PROP_IDLE_TIME); msm_property_install_blob(&sde_crtc->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); Loading Loading @@ -3973,7 +4007,8 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc, */ drm_for_each_encoder(encoder, crtc->dev) { if (encoder->crtc == crtc) is_cmd &= sde_encoder_is_cmd_mode(encoder); is_cmd = sde_encoder_check_mode(encoder, MSM_DISPLAY_CAP_CMD_MODE); } i = msm_property_index(&sde_crtc->property_info, property); Loading Loading @@ -4500,6 +4535,31 @@ static int _sde_crtc_init_events(struct sde_crtc *sde_crtc) return rc; } /* * __sde_crtc_idle_notify_work - signal idle timeout to user space */ static void __sde_crtc_idle_notify_work(struct kthread_work *work) { struct sde_crtc *sde_crtc = container_of(work, struct sde_crtc, idle_notify_work.work); struct drm_crtc *crtc; struct drm_event event; int ret = 0; if (!sde_crtc) { SDE_ERROR("invalid sde crtc\n"); } else { crtc = &sde_crtc->base; event.type = DRM_EVENT_IDLE_NOTIFY; event.length = sizeof(u32); msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, (u8 *)&ret); SDE_DEBUG("crtc[%d]: idle timeout notified\n", crtc->base.id); } } /* initialize crtc */ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) { Loading Loading @@ -4570,6 +4630,9 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) sde_cp_crtc_init(crtc); sde_cp_crtc_install_properties(crtc); kthread_init_delayed_work(&sde_crtc->idle_notify_work, __sde_crtc_idle_notify_work); SDE_DEBUG("%s: successfully initialized crtc\n", sde_crtc->name); return crtc; } Loading Loading @@ -4715,3 +4778,9 @@ static int sde_crtc_pm_event_handler(struct drm_crtc *crtc, bool en, */ return 0; } static int sde_crtc_idle_interrupt_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *irq) { return 0; } drivers/gpu/drm/msm/sde/sde_crtc.h +3 −0 Original line number Diff line number Diff line Loading @@ -204,6 +204,7 @@ struct sde_crtc_event { * @misr_enable : boolean entry indicates misr enable/disable status. * @misr_frame_count : misr frame count provided by client * @misr_data : store misr data before turning off the clocks. * @idle_notify_work: delayed worker to notify idle timeout to user space * @power_event : registered power event handle * @cur_perf : current performance committed to clock/bandwidth driver * @rp_lock : serialization lock for resource pool Loading Loading @@ -264,6 +265,8 @@ struct sde_crtc { u32 misr_frame_count; u32 misr_data[CRTC_DUAL_MIXERS]; struct kthread_delayed_work idle_notify_work; struct sde_power_event *power_event; struct sde_core_perf_params cur_perf; Loading drivers/gpu/drm/msm/sde/sde_encoder.c +2 −2 Original line number Diff line number Diff line Loading @@ -2620,7 +2620,7 @@ static void _sde_encoder_update_master(struct drm_encoder *drm_enc, } } bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc) bool sde_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode) { struct sde_encoder_virt *sde_enc; struct msm_display_info *disp_info; Loading @@ -2633,7 +2633,7 @@ bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc) sde_enc = to_sde_encoder_virt(drm_enc); disp_info = &sde_enc->disp_info; return (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE); return (disp_info->capabilities & mode); } void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) Loading drivers/gpu/drm/msm/sde/sde_encoder.h +3 −2 Original line number Diff line number Diff line Loading @@ -175,11 +175,12 @@ bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc); bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc); /** * sde_encoder_is_cmd_mode - check if it is cmd mode * sde_encoder_check_mode - check if given mode is supported or not * @drm_enc: Pointer to drm encoder object * @mode: Mode to be checked * @Return: true if it is cmd mode */ bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc); bool sde_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode); /** * sde_encoder_init - initialize virtual encoder object Loading Loading
drivers/gpu/drm/msm/msm_drv.h +1 −0 Original line number Diff line number Diff line Loading @@ -147,6 +147,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_ROT_CLK, CRTC_PROP_ROI_V1, CRTC_PROP_SECURITY_LEVEL, CRTC_PROP_IDLE_TIME, /* total # of properties */ CRTC_PROP_COUNT Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +72 −3 Original line number Diff line number Diff line Loading @@ -64,6 +64,8 @@ struct sde_crtc_custom_events { static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *ad_irq); static int sde_crtc_idle_interrupt_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *idle_irq); static int sde_crtc_pm_event_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *noirq); Loading @@ -72,6 +74,7 @@ static struct sde_crtc_custom_events custom_events[] = { {DRM_EVENT_AD_BACKLIGHT, sde_cp_ad_interrupt}, {DRM_EVENT_CRTC_POWER, sde_crtc_power_interrupt_handler}, {DRM_EVENT_SDE_POWER, sde_crtc_pm_event_handler}, {DRM_EVENT_IDLE_NOTIFY, sde_crtc_idle_interrupt_handler} }; /* default input fence timeout, in ms */ Loading Loading @@ -1623,7 +1626,8 @@ int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc, if (encoder->crtc != crtc) continue; post_commit &= !sde_encoder_is_cmd_mode(encoder); post_commit &= sde_encoder_check_mode(encoder, MSM_DISPLAY_CAP_VID_MODE); } drm_atomic_crtc_for_each_plane(plane, crtc) { Loading Loading @@ -2493,6 +2497,12 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, if (unlikely(!sde_crtc->num_mixers)) return; /* cancel the idle notify delayed work */ if (sde_encoder_check_mode(sde_crtc->mixers[0].encoder, MSM_DISPLAY_CAP_VID_MODE) && kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work)) SDE_DEBUG("idle notify work cancelled\n"); _sde_crtc_blend_setup(crtc); /* Loading Loading @@ -2522,10 +2532,13 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, struct sde_crtc *sde_crtc; struct drm_device *dev; struct drm_plane *plane; struct msm_drm_private *priv; struct msm_drm_thread *event_thread; unsigned long flags; struct sde_crtc_state *cstate; int idle_time = 0; if (!crtc) { if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid crtc\n"); return; } Loading @@ -2541,6 +2554,15 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(crtc->state); dev = crtc->dev; priv = dev->dev_private; if (crtc->index >= ARRAY_SIZE(priv->event_thread)) { SDE_ERROR("invalid crtc index[%d]\n", crtc->index); return; } event_thread = &priv->event_thread[crtc->index]; idle_time = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_TIME); if (sde_crtc->event) { SDE_DEBUG("already received sde_crtc->event\n"); Loading Loading @@ -2571,6 +2593,15 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, /* wait for acquire fences before anything else is done */ _sde_crtc_wait_for_fences(crtc); /* schedule the idle notify delayed work */ if (idle_time && sde_encoder_check_mode(sde_crtc->mixers[0].encoder, MSM_DISPLAY_CAP_VID_MODE)) { kthread_queue_delayed_work(&event_thread->worker, &sde_crtc->idle_notify_work, msecs_to_jiffies(idle_time)); SDE_DEBUG("schedule idle notify work in %dms\n", idle_time); } if (!cstate->rsc_update) { drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) Loading Loading @@ -3769,6 +3800,9 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, sde_kms->perf.max_core_clk_rate, CRTC_PROP_ROT_CLK); msm_property_install_range(&sde_crtc->property_info, "idle_time", 0x0, 0, U64_MAX, 0, CRTC_PROP_IDLE_TIME); msm_property_install_blob(&sde_crtc->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); Loading Loading @@ -3973,7 +4007,8 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc, */ drm_for_each_encoder(encoder, crtc->dev) { if (encoder->crtc == crtc) is_cmd &= sde_encoder_is_cmd_mode(encoder); is_cmd = sde_encoder_check_mode(encoder, MSM_DISPLAY_CAP_CMD_MODE); } i = msm_property_index(&sde_crtc->property_info, property); Loading Loading @@ -4500,6 +4535,31 @@ static int _sde_crtc_init_events(struct sde_crtc *sde_crtc) return rc; } /* * __sde_crtc_idle_notify_work - signal idle timeout to user space */ static void __sde_crtc_idle_notify_work(struct kthread_work *work) { struct sde_crtc *sde_crtc = container_of(work, struct sde_crtc, idle_notify_work.work); struct drm_crtc *crtc; struct drm_event event; int ret = 0; if (!sde_crtc) { SDE_ERROR("invalid sde crtc\n"); } else { crtc = &sde_crtc->base; event.type = DRM_EVENT_IDLE_NOTIFY; event.length = sizeof(u32); msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, (u8 *)&ret); SDE_DEBUG("crtc[%d]: idle timeout notified\n", crtc->base.id); } } /* initialize crtc */ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) { Loading Loading @@ -4570,6 +4630,9 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) sde_cp_crtc_init(crtc); sde_cp_crtc_install_properties(crtc); kthread_init_delayed_work(&sde_crtc->idle_notify_work, __sde_crtc_idle_notify_work); SDE_DEBUG("%s: successfully initialized crtc\n", sde_crtc->name); return crtc; } Loading Loading @@ -4715,3 +4778,9 @@ static int sde_crtc_pm_event_handler(struct drm_crtc *crtc, bool en, */ return 0; } static int sde_crtc_idle_interrupt_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *irq) { return 0; }
drivers/gpu/drm/msm/sde/sde_crtc.h +3 −0 Original line number Diff line number Diff line Loading @@ -204,6 +204,7 @@ struct sde_crtc_event { * @misr_enable : boolean entry indicates misr enable/disable status. * @misr_frame_count : misr frame count provided by client * @misr_data : store misr data before turning off the clocks. * @idle_notify_work: delayed worker to notify idle timeout to user space * @power_event : registered power event handle * @cur_perf : current performance committed to clock/bandwidth driver * @rp_lock : serialization lock for resource pool Loading Loading @@ -264,6 +265,8 @@ struct sde_crtc { u32 misr_frame_count; u32 misr_data[CRTC_DUAL_MIXERS]; struct kthread_delayed_work idle_notify_work; struct sde_power_event *power_event; struct sde_core_perf_params cur_perf; Loading
drivers/gpu/drm/msm/sde/sde_encoder.c +2 −2 Original line number Diff line number Diff line Loading @@ -2620,7 +2620,7 @@ static void _sde_encoder_update_master(struct drm_encoder *drm_enc, } } bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc) bool sde_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode) { struct sde_encoder_virt *sde_enc; struct msm_display_info *disp_info; Loading @@ -2633,7 +2633,7 @@ bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc) sde_enc = to_sde_encoder_virt(drm_enc); disp_info = &sde_enc->disp_info; return (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE); return (disp_info->capabilities & mode); } void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) Loading
drivers/gpu/drm/msm/sde/sde_encoder.h +3 −2 Original line number Diff line number Diff line Loading @@ -175,11 +175,12 @@ bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc); bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc); /** * sde_encoder_is_cmd_mode - check if it is cmd mode * sde_encoder_check_mode - check if given mode is supported or not * @drm_enc: Pointer to drm encoder object * @mode: Mode to be checked * @Return: true if it is cmd mode */ bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc); bool sde_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode); /** * sde_encoder_init - initialize virtual encoder object Loading