Loading drivers/gpu/drm/msm/msm_drv.h +1 −1 Original line number Diff line number Diff line Loading @@ -147,7 +147,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_ROT_CLK, CRTC_PROP_ROI_V1, CRTC_PROP_SECURITY_LEVEL, CRTC_PROP_IDLE_TIME, CRTC_PROP_IDLE_TIMEOUT, /* total # of properties */ CRTC_PROP_COUNT Loading drivers/gpu/drm/msm/sde/sde_crtc.c +79 −74 Original line number Diff line number Diff line Loading @@ -67,13 +67,9 @@ static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm, 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); 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} }; Loading Loading @@ -2026,6 +2022,47 @@ static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts) SDE_ATRACE_END("signal_retire_fence"); } /* _sde_crtc_idle_notify - signal idle timeout to client */ static void _sde_crtc_idle_notify(struct sde_crtc *sde_crtc) { struct drm_crtc *crtc; struct drm_event event; int ret = 0; if (!sde_crtc) { SDE_ERROR("invalid sde crtc\n"); return; } 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); } /* * sde_crtc_handle_event - crtc frame event handle. * This API must manage only non-IRQ context events. */ static bool _sde_crtc_handle_event(struct sde_crtc *sde_crtc, u32 event) { bool event_processed = false; /** * idle events are originated from commit thread and can be processed * in same context */ if (event & SDE_ENCODER_FRAME_EVENT_IDLE) { _sde_crtc_idle_notify(sde_crtc); event_processed = true; } return event_processed; } static void sde_crtc_frame_event_work(struct kthread_work *work) { struct msm_drm_private *priv; Loading Loading @@ -2119,6 +2156,15 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_ATRACE_END("crtc_frame_event"); } /* * sde_crtc_frame_event_cb - crtc frame event callback API. CRTC module * registers this API to encoder for all frame event callbacks like * release_fence, retire_fence, frame_error, frame_done, idle_timeout, * etc. Encoder may call different events from different context - IRQ, * user thread, commit_thread, etc. Each event should be carefully * reviewed and should be processed in proper task context to avoid scheduling * delay or properly manage the irq context's bottom half processing. */ static void sde_crtc_frame_event_cb(void *data, u32 event) { struct drm_crtc *crtc = (struct drm_crtc *)data; Loading @@ -2127,6 +2173,7 @@ static void sde_crtc_frame_event_cb(void *data, u32 event) struct sde_crtc_frame_event *fevent; unsigned long flags; u32 crtc_id; bool event_processed = false; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid parameters\n"); Loading @@ -2139,6 +2186,11 @@ static void sde_crtc_frame_event_cb(void *data, u32 event) SDE_DEBUG("crtc%d\n", crtc->base.id); SDE_EVT32_VERBOSE(DRMID(crtc), event); /* try to process the event in caller context */ event_processed = _sde_crtc_handle_event(sde_crtc, event); if (event_processed) return; spin_lock_irqsave(&sde_crtc->spin_lock, flags); fevent = list_first_entry_or_null(&sde_crtc->frame_event_list, struct sde_crtc_frame_event, list); Loading Loading @@ -2179,6 +2231,24 @@ void sde_crtc_complete_commit(struct drm_crtc *crtc, sde_crtc_secure_ctrl(crtc, true); } /* _sde_crtc_set_idle_timeout - update idle timeout wait duration */ static void _sde_crtc_set_idle_timeout(struct drm_crtc *crtc, u64 val) { struct drm_encoder *encoder; if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } drm_for_each_encoder(encoder, crtc->dev) { if (encoder->crtc != crtc) continue; sde_encoder_set_idle_timeout(encoder, (u32) val); } } /** * _sde_crtc_set_input_fence_timeout - update ns version of in fence timeout * @cstate: Pointer to sde crtc state Loading Loading @@ -2494,12 +2564,6 @@ 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 @@ -2533,7 +2597,6 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, struct msm_drm_thread *event_thread; unsigned long flags; struct sde_crtc_state *cstate; int idle_time = 0; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid crtc\n"); Loading @@ -2559,7 +2622,6 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, } 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 @@ -2590,15 +2652,6 @@ 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 @@ -2992,8 +3045,7 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) struct drm_plane *plane; struct drm_encoder *encoder; struct sde_crtc_mixer *m; struct drm_event event; u32 power_on = 0, i, misr_status; u32 i, misr_status; if (!crtc) { SDE_ERROR("invalid crtc\n"); Loading @@ -3016,12 +3068,6 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) } sde_cp_crtc_post_ipc(crtc); event.type = DRM_EVENT_SDE_POWER; event.length = sizeof(power_on); power_on = 1; msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, (u8 *)&power_on); for (i = 0; i < sde_crtc->num_mixers; ++i) { m = &sde_crtc->mixers[i]; if (!m->hw_lm || !m->hw_lm->ops.setup_misr || Loading Loading @@ -3054,12 +3100,6 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) sde_plane_set_revalidate(plane, true); sde_cp_crtc_suspend(crtc); event.type = DRM_EVENT_SDE_POWER; event.length = sizeof(power_on); power_on = 0; msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, (u8 *)&power_on); break; default: SDE_DEBUG("event:%d not handled\n", event_type); Loading Loading @@ -3805,7 +3845,8 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, CRTC_PROP_ROT_CLK); msm_property_install_range(&sde_crtc->property_info, "idle_time", 0x0, 0, U64_MAX, 0, CRTC_PROP_IDLE_TIME); "idle_timeout", IDLE_TIMEOUT, 0, U64_MAX, 0, CRTC_PROP_IDLE_TIMEOUT); msm_property_install_blob(&sde_crtc->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); Loading Loading @@ -3938,6 +3979,8 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc, cstate->bw_control = true; cstate->bw_split_vote = true; break; case CRTC_PROP_IDLE_TIMEOUT: _sde_crtc_set_idle_timeout(crtc, val); default: /* nothing to do */ break; Loading Loading @@ -4539,31 +4582,6 @@ 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 @@ -4634,9 +4652,6 @@ 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 @@ -4773,16 +4788,6 @@ static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm, return 0; } static int sde_crtc_pm_event_handler(struct drm_crtc *crtc, bool en, struct sde_irq_callback *noirq) { /* * IRQ object noirq is not being used here since there is * no crtc irq from pm event. */ return 0; } static int sde_crtc_idle_interrupt_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *irq) { Loading drivers/gpu/drm/msm/sde/sde_crtc.h +0 −3 Original line number Diff line number Diff line Loading @@ -204,7 +204,6 @@ 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 @@ -265,8 +264,6 @@ 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 +68 −26 Original line number Diff line number Diff line Loading @@ -71,7 +71,6 @@ #define MISR_BUFF_SIZE 256 #define IDLE_TIMEOUT (66 - 16/2) #define IDLE_SHORT_TIMEOUT 1 /* Maximum number of VSYNC wait attempts for RSC state transition */ Loading Loading @@ -197,6 +196,7 @@ enum sde_enc_rc_states { * @rsc_config: rsc configuration for display vtotal, fps, etc. * @cur_conn_roi: current connector roi * @prv_conn_roi: previous connector roi to optimize if unchanged * @idle_timeout: idle timeout duration in milliseconds */ struct sde_encoder_virt { struct drm_encoder base; Loading Loading @@ -242,6 +242,8 @@ struct sde_encoder_virt { struct sde_rsc_cmd_config rsc_config; struct sde_rect cur_conn_roi; struct sde_rect prv_conn_roi; u32 idle_timeout; }; #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base) Loading @@ -261,6 +263,17 @@ bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc) return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC); } void sde_encoder_set_idle_timeout(struct drm_encoder *drm_enc, u32 idle_timeout) { struct sde_encoder_virt *sde_enc; if (!drm_enc) return; sde_enc = to_sde_encoder_virt(drm_enc); sde_enc->idle_timeout = idle_timeout; } bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc) { enum sde_rm_topology_name topology; Loading Loading @@ -1472,6 +1485,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, struct msm_drm_private *priv; struct msm_drm_thread *disp_thread; int ret; bool is_vid_mode = false; if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private || !drm_enc->crtc) { Loading @@ -1480,6 +1494,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, } sde_enc = to_sde_encoder_virt(drm_enc); priv = drm_enc->dev->dev_private; is_vid_mode = sde_enc->disp_info.capabilities & MSM_DISPLAY_CAP_VID_MODE; if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { SDE_ERROR("invalid crtc index\n"); Loading @@ -1489,7 +1505,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, /* * when idle_pc is not supported, process only KICKOFF, STOP and MODESET * events and return early for other events (ie video mode). * events and return early for other events (ie wb display). */ if (!sde_enc->idle_pc_supported && (sw_event != SDE_ENC_RC_EVENT_KICKOFF && Loading Loading @@ -1518,6 +1534,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON) { SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in ON state\n", sw_event); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_EVTLOG_FUNC_CASE1); mutex_unlock(&sde_enc->rc_lock); return 0; } else if (sde_enc->rc_state != SDE_ENC_RC_STATE_OFF && Loading @@ -1530,9 +1548,13 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return -EINVAL; } if (is_vid_mode && sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { _sde_encoder_irq_control(drm_enc, true); } else { /* enable all the clks and resources */ _sde_encoder_resource_control_helper(drm_enc, true); _sde_encoder_resource_control_rsc_update(drm_enc, true); } SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE1); Loading Loading @@ -1562,6 +1584,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, */ if (sde_crtc_frame_pending(drm_enc->crtc) > 1) { SDE_DEBUG_ENC(sde_enc, "skip schedule work"); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_EVTLOG_FUNC_CASE2); return 0; } Loading @@ -1582,7 +1606,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, if (lp == SDE_MODE_DPMS_LP2) idle_timeout = IDLE_SHORT_TIMEOUT; else idle_timeout = IDLE_TIMEOUT; idle_timeout = sde_enc->idle_timeout; if (!autorefresh_enabled) kthread_queue_delayed_work( Loading @@ -1605,11 +1629,17 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, mutex_lock(&sde_enc->rc_lock); if (is_vid_mode && sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { _sde_encoder_irq_control(drm_enc, true); } /* skip if is already OFF or IDLE, resources are off already */ if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF || else if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF || sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in %d state\n", sw_event, sde_enc->rc_state); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_EVTLOG_FUNC_CASE3); mutex_unlock(&sde_enc->rc_lock); return 0; } Loading @@ -1636,6 +1666,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) { SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n", sw_event); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_EVTLOG_FUNC_CASE4); mutex_unlock(&sde_enc->rc_lock); return 0; } else if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON || Loading Loading @@ -1756,9 +1788,15 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return 0; } if (is_vid_mode) { _sde_encoder_irq_control(drm_enc, false); } else { /* disable all the clks and resources */ _sde_encoder_resource_control_rsc_update(drm_enc, false); _sde_encoder_resource_control_rsc_update(drm_enc, false); _sde_encoder_resource_control_helper(drm_enc, false); } SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_ENC_RC_STATE_IDLE, SDE_EVTLOG_FUNC_CASE7); sde_enc->rc_state = SDE_ENC_RC_STATE_IDLE; Loading @@ -1777,20 +1815,6 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return 0; } static void sde_encoder_off_work(struct kthread_work *work) { struct sde_encoder_virt *sde_enc = container_of(work, struct sde_encoder_virt, delayed_off_work.work); if (!sde_enc) { SDE_ERROR("invalid sde encoder\n"); return; } sde_encoder_resource_control(&sde_enc->base, SDE_ENC_RC_EVENT_ENTER_IDLE); } static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, struct drm_display_mode *mode, struct drm_display_mode *adj_mode) Loading Loading @@ -2259,6 +2283,23 @@ static void sde_encoder_frame_done_callback( } } static void sde_encoder_off_work(struct kthread_work *work) { struct sde_encoder_virt *sde_enc = container_of(work, struct sde_encoder_virt, delayed_off_work.work); if (!sde_enc) { SDE_ERROR("invalid sde encoder\n"); return; } sde_encoder_resource_control(&sde_enc->base, SDE_ENC_RC_EVENT_ENTER_IDLE); sde_encoder_frame_done_callback(&sde_enc->base, NULL, SDE_ENCODER_FRAME_EVENT_IDLE); } /** * _sde_encoder_trigger_flush - trigger flush for a physical encoder * drm_enc: Pointer to drm encoder structure Loading Loading @@ -3246,7 +3287,8 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc, SDE_DEBUG("dsi_info->num_of_h_tiles %d\n", disp_info->num_of_h_tiles); if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) if ((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) || (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE)) sde_enc->idle_pc_supported = sde_kms->catalog->has_idle_pc; mutex_lock(&sde_enc->enc_lock); Loading Loading @@ -3411,7 +3453,7 @@ struct drm_encoder *sde_encoder_init( mutex_init(&sde_enc->rc_lock); kthread_init_delayed_work(&sde_enc->delayed_off_work, sde_encoder_off_work); sde_enc->idle_timeout = IDLE_TIMEOUT; memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info)); SDE_DEBUG_ENC(sde_enc, "created\n"); Loading drivers/gpu/drm/msm/sde/sde_encoder.h +12 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ #define SDE_ENCODER_FRAME_EVENT_PANEL_DEAD BIT(2) #define SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE BIT(3) #define SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE BIT(4) #define SDE_ENCODER_FRAME_EVENT_IDLE BIT(5) #define IDLE_TIMEOUT (66 - 16/2) /** * Encoder functions and data types Loading Loading @@ -205,4 +208,13 @@ void sde_encoder_destroy(struct drm_encoder *drm_enc); */ void sde_encoder_prepare_commit(struct drm_encoder *drm_enc); /** * sde_encoder_set_idle_timeout - set the idle timeout for video * and command mode encoders. * @drm_enc: Pointer to previously created drm encoder structure * @idle_timeout: idle timeout duration in milliseconds */ void sde_encoder_set_idle_timeout(struct drm_encoder *drm_enc, u32 idle_timeout); #endif /* __SDE_ENCODER_H__ */ Loading
drivers/gpu/drm/msm/msm_drv.h +1 −1 Original line number Diff line number Diff line Loading @@ -147,7 +147,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_ROT_CLK, CRTC_PROP_ROI_V1, CRTC_PROP_SECURITY_LEVEL, CRTC_PROP_IDLE_TIME, CRTC_PROP_IDLE_TIMEOUT, /* total # of properties */ CRTC_PROP_COUNT Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +79 −74 Original line number Diff line number Diff line Loading @@ -67,13 +67,9 @@ static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm, 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); 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} }; Loading Loading @@ -2026,6 +2022,47 @@ static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts) SDE_ATRACE_END("signal_retire_fence"); } /* _sde_crtc_idle_notify - signal idle timeout to client */ static void _sde_crtc_idle_notify(struct sde_crtc *sde_crtc) { struct drm_crtc *crtc; struct drm_event event; int ret = 0; if (!sde_crtc) { SDE_ERROR("invalid sde crtc\n"); return; } 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); } /* * sde_crtc_handle_event - crtc frame event handle. * This API must manage only non-IRQ context events. */ static bool _sde_crtc_handle_event(struct sde_crtc *sde_crtc, u32 event) { bool event_processed = false; /** * idle events are originated from commit thread and can be processed * in same context */ if (event & SDE_ENCODER_FRAME_EVENT_IDLE) { _sde_crtc_idle_notify(sde_crtc); event_processed = true; } return event_processed; } static void sde_crtc_frame_event_work(struct kthread_work *work) { struct msm_drm_private *priv; Loading Loading @@ -2119,6 +2156,15 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_ATRACE_END("crtc_frame_event"); } /* * sde_crtc_frame_event_cb - crtc frame event callback API. CRTC module * registers this API to encoder for all frame event callbacks like * release_fence, retire_fence, frame_error, frame_done, idle_timeout, * etc. Encoder may call different events from different context - IRQ, * user thread, commit_thread, etc. Each event should be carefully * reviewed and should be processed in proper task context to avoid scheduling * delay or properly manage the irq context's bottom half processing. */ static void sde_crtc_frame_event_cb(void *data, u32 event) { struct drm_crtc *crtc = (struct drm_crtc *)data; Loading @@ -2127,6 +2173,7 @@ static void sde_crtc_frame_event_cb(void *data, u32 event) struct sde_crtc_frame_event *fevent; unsigned long flags; u32 crtc_id; bool event_processed = false; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid parameters\n"); Loading @@ -2139,6 +2186,11 @@ static void sde_crtc_frame_event_cb(void *data, u32 event) SDE_DEBUG("crtc%d\n", crtc->base.id); SDE_EVT32_VERBOSE(DRMID(crtc), event); /* try to process the event in caller context */ event_processed = _sde_crtc_handle_event(sde_crtc, event); if (event_processed) return; spin_lock_irqsave(&sde_crtc->spin_lock, flags); fevent = list_first_entry_or_null(&sde_crtc->frame_event_list, struct sde_crtc_frame_event, list); Loading Loading @@ -2179,6 +2231,24 @@ void sde_crtc_complete_commit(struct drm_crtc *crtc, sde_crtc_secure_ctrl(crtc, true); } /* _sde_crtc_set_idle_timeout - update idle timeout wait duration */ static void _sde_crtc_set_idle_timeout(struct drm_crtc *crtc, u64 val) { struct drm_encoder *encoder; if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } drm_for_each_encoder(encoder, crtc->dev) { if (encoder->crtc != crtc) continue; sde_encoder_set_idle_timeout(encoder, (u32) val); } } /** * _sde_crtc_set_input_fence_timeout - update ns version of in fence timeout * @cstate: Pointer to sde crtc state Loading Loading @@ -2494,12 +2564,6 @@ 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 @@ -2533,7 +2597,6 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, struct msm_drm_thread *event_thread; unsigned long flags; struct sde_crtc_state *cstate; int idle_time = 0; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid crtc\n"); Loading @@ -2559,7 +2622,6 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc, } 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 @@ -2590,15 +2652,6 @@ 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 @@ -2992,8 +3045,7 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) struct drm_plane *plane; struct drm_encoder *encoder; struct sde_crtc_mixer *m; struct drm_event event; u32 power_on = 0, i, misr_status; u32 i, misr_status; if (!crtc) { SDE_ERROR("invalid crtc\n"); Loading @@ -3016,12 +3068,6 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) } sde_cp_crtc_post_ipc(crtc); event.type = DRM_EVENT_SDE_POWER; event.length = sizeof(power_on); power_on = 1; msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, (u8 *)&power_on); for (i = 0; i < sde_crtc->num_mixers; ++i) { m = &sde_crtc->mixers[i]; if (!m->hw_lm || !m->hw_lm->ops.setup_misr || Loading Loading @@ -3054,12 +3100,6 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) sde_plane_set_revalidate(plane, true); sde_cp_crtc_suspend(crtc); event.type = DRM_EVENT_SDE_POWER; event.length = sizeof(power_on); power_on = 0; msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, (u8 *)&power_on); break; default: SDE_DEBUG("event:%d not handled\n", event_type); Loading Loading @@ -3805,7 +3845,8 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, CRTC_PROP_ROT_CLK); msm_property_install_range(&sde_crtc->property_info, "idle_time", 0x0, 0, U64_MAX, 0, CRTC_PROP_IDLE_TIME); "idle_timeout", IDLE_TIMEOUT, 0, U64_MAX, 0, CRTC_PROP_IDLE_TIMEOUT); msm_property_install_blob(&sde_crtc->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); Loading Loading @@ -3938,6 +3979,8 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc, cstate->bw_control = true; cstate->bw_split_vote = true; break; case CRTC_PROP_IDLE_TIMEOUT: _sde_crtc_set_idle_timeout(crtc, val); default: /* nothing to do */ break; Loading Loading @@ -4539,31 +4582,6 @@ 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 @@ -4634,9 +4652,6 @@ 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 @@ -4773,16 +4788,6 @@ static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm, return 0; } static int sde_crtc_pm_event_handler(struct drm_crtc *crtc, bool en, struct sde_irq_callback *noirq) { /* * IRQ object noirq is not being used here since there is * no crtc irq from pm event. */ return 0; } static int sde_crtc_idle_interrupt_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *irq) { Loading
drivers/gpu/drm/msm/sde/sde_crtc.h +0 −3 Original line number Diff line number Diff line Loading @@ -204,7 +204,6 @@ 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 @@ -265,8 +264,6 @@ 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 +68 −26 Original line number Diff line number Diff line Loading @@ -71,7 +71,6 @@ #define MISR_BUFF_SIZE 256 #define IDLE_TIMEOUT (66 - 16/2) #define IDLE_SHORT_TIMEOUT 1 /* Maximum number of VSYNC wait attempts for RSC state transition */ Loading Loading @@ -197,6 +196,7 @@ enum sde_enc_rc_states { * @rsc_config: rsc configuration for display vtotal, fps, etc. * @cur_conn_roi: current connector roi * @prv_conn_roi: previous connector roi to optimize if unchanged * @idle_timeout: idle timeout duration in milliseconds */ struct sde_encoder_virt { struct drm_encoder base; Loading Loading @@ -242,6 +242,8 @@ struct sde_encoder_virt { struct sde_rsc_cmd_config rsc_config; struct sde_rect cur_conn_roi; struct sde_rect prv_conn_roi; u32 idle_timeout; }; #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base) Loading @@ -261,6 +263,17 @@ bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc) return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC); } void sde_encoder_set_idle_timeout(struct drm_encoder *drm_enc, u32 idle_timeout) { struct sde_encoder_virt *sde_enc; if (!drm_enc) return; sde_enc = to_sde_encoder_virt(drm_enc); sde_enc->idle_timeout = idle_timeout; } bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc) { enum sde_rm_topology_name topology; Loading Loading @@ -1472,6 +1485,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, struct msm_drm_private *priv; struct msm_drm_thread *disp_thread; int ret; bool is_vid_mode = false; if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private || !drm_enc->crtc) { Loading @@ -1480,6 +1494,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, } sde_enc = to_sde_encoder_virt(drm_enc); priv = drm_enc->dev->dev_private; is_vid_mode = sde_enc->disp_info.capabilities & MSM_DISPLAY_CAP_VID_MODE; if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { SDE_ERROR("invalid crtc index\n"); Loading @@ -1489,7 +1505,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, /* * when idle_pc is not supported, process only KICKOFF, STOP and MODESET * events and return early for other events (ie video mode). * events and return early for other events (ie wb display). */ if (!sde_enc->idle_pc_supported && (sw_event != SDE_ENC_RC_EVENT_KICKOFF && Loading Loading @@ -1518,6 +1534,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON) { SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in ON state\n", sw_event); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_EVTLOG_FUNC_CASE1); mutex_unlock(&sde_enc->rc_lock); return 0; } else if (sde_enc->rc_state != SDE_ENC_RC_STATE_OFF && Loading @@ -1530,9 +1548,13 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return -EINVAL; } if (is_vid_mode && sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { _sde_encoder_irq_control(drm_enc, true); } else { /* enable all the clks and resources */ _sde_encoder_resource_control_helper(drm_enc, true); _sde_encoder_resource_control_rsc_update(drm_enc, true); } SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE1); Loading Loading @@ -1562,6 +1584,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, */ if (sde_crtc_frame_pending(drm_enc->crtc) > 1) { SDE_DEBUG_ENC(sde_enc, "skip schedule work"); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_EVTLOG_FUNC_CASE2); return 0; } Loading @@ -1582,7 +1606,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, if (lp == SDE_MODE_DPMS_LP2) idle_timeout = IDLE_SHORT_TIMEOUT; else idle_timeout = IDLE_TIMEOUT; idle_timeout = sde_enc->idle_timeout; if (!autorefresh_enabled) kthread_queue_delayed_work( Loading @@ -1605,11 +1629,17 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, mutex_lock(&sde_enc->rc_lock); if (is_vid_mode && sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { _sde_encoder_irq_control(drm_enc, true); } /* skip if is already OFF or IDLE, resources are off already */ if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF || else if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF || sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in %d state\n", sw_event, sde_enc->rc_state); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_EVTLOG_FUNC_CASE3); mutex_unlock(&sde_enc->rc_lock); return 0; } Loading @@ -1636,6 +1666,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) { SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n", sw_event); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_EVTLOG_FUNC_CASE4); mutex_unlock(&sde_enc->rc_lock); return 0; } else if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON || Loading Loading @@ -1756,9 +1788,15 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return 0; } if (is_vid_mode) { _sde_encoder_irq_control(drm_enc, false); } else { /* disable all the clks and resources */ _sde_encoder_resource_control_rsc_update(drm_enc, false); _sde_encoder_resource_control_rsc_update(drm_enc, false); _sde_encoder_resource_control_helper(drm_enc, false); } SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_ENC_RC_STATE_IDLE, SDE_EVTLOG_FUNC_CASE7); sde_enc->rc_state = SDE_ENC_RC_STATE_IDLE; Loading @@ -1777,20 +1815,6 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return 0; } static void sde_encoder_off_work(struct kthread_work *work) { struct sde_encoder_virt *sde_enc = container_of(work, struct sde_encoder_virt, delayed_off_work.work); if (!sde_enc) { SDE_ERROR("invalid sde encoder\n"); return; } sde_encoder_resource_control(&sde_enc->base, SDE_ENC_RC_EVENT_ENTER_IDLE); } static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, struct drm_display_mode *mode, struct drm_display_mode *adj_mode) Loading Loading @@ -2259,6 +2283,23 @@ static void sde_encoder_frame_done_callback( } } static void sde_encoder_off_work(struct kthread_work *work) { struct sde_encoder_virt *sde_enc = container_of(work, struct sde_encoder_virt, delayed_off_work.work); if (!sde_enc) { SDE_ERROR("invalid sde encoder\n"); return; } sde_encoder_resource_control(&sde_enc->base, SDE_ENC_RC_EVENT_ENTER_IDLE); sde_encoder_frame_done_callback(&sde_enc->base, NULL, SDE_ENCODER_FRAME_EVENT_IDLE); } /** * _sde_encoder_trigger_flush - trigger flush for a physical encoder * drm_enc: Pointer to drm encoder structure Loading Loading @@ -3246,7 +3287,8 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc, SDE_DEBUG("dsi_info->num_of_h_tiles %d\n", disp_info->num_of_h_tiles); if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) if ((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) || (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE)) sde_enc->idle_pc_supported = sde_kms->catalog->has_idle_pc; mutex_lock(&sde_enc->enc_lock); Loading Loading @@ -3411,7 +3453,7 @@ struct drm_encoder *sde_encoder_init( mutex_init(&sde_enc->rc_lock); kthread_init_delayed_work(&sde_enc->delayed_off_work, sde_encoder_off_work); sde_enc->idle_timeout = IDLE_TIMEOUT; memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info)); SDE_DEBUG_ENC(sde_enc, "created\n"); Loading
drivers/gpu/drm/msm/sde/sde_encoder.h +12 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ #define SDE_ENCODER_FRAME_EVENT_PANEL_DEAD BIT(2) #define SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE BIT(3) #define SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE BIT(4) #define SDE_ENCODER_FRAME_EVENT_IDLE BIT(5) #define IDLE_TIMEOUT (66 - 16/2) /** * Encoder functions and data types Loading Loading @@ -205,4 +208,13 @@ void sde_encoder_destroy(struct drm_encoder *drm_enc); */ void sde_encoder_prepare_commit(struct drm_encoder *drm_enc); /** * sde_encoder_set_idle_timeout - set the idle timeout for video * and command mode encoders. * @drm_enc: Pointer to previously created drm encoder structure * @idle_timeout: idle timeout duration in milliseconds */ void sde_encoder_set_idle_timeout(struct drm_encoder *drm_enc, u32 idle_timeout); #endif /* __SDE_ENCODER_H__ */