Loading drivers/gpu/drm/msm/sde/sde_crtc.c +10 −11 Original line number Diff line number Diff line Loading @@ -3148,14 +3148,13 @@ static void _sde_crtc_remove_pipe_flush(struct drm_crtc *crtc) } /** * _sde_crtc_reset_hw - attempt hardware reset on errors * sde_crtc_reset_hw - attempt hardware reset on errors * @crtc: Pointer to DRM crtc instance * @old_state: Pointer to crtc state for previous commit * @recovery_events: Whether or not recovery events are enabled * Returns: Zero if current commit should still be attempted */ static int _sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, bool recovery_events) { struct drm_plane *plane_halt[MAX_PLANES]; Loading Loading @@ -3265,9 +3264,10 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_crtc_state *cstate; bool is_error = false, reset_req, recovery_events; bool is_error = false, reset_req; unsigned long flags; enum sde_crtc_idle_pc_state idle_pc_state; struct sde_encoder_kickoff_params params = { 0 }; if (!crtc) { SDE_ERROR("invalid argument\n"); Loading Loading @@ -3299,8 +3299,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, idle_pc_state = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_PC_STATE); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct sde_encoder_kickoff_params params = { 0 }; if (encoder->crtc != crtc) continue; Loading @@ -3313,9 +3311,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, if (sde_encoder_prepare_for_kickoff(encoder, ¶ms)) reset_req = true; recovery_events = sde_encoder_recovery_events_enabled(encoder); if (idle_pc_state != IDLE_PC_NONE) sde_encoder_control_idle_pc(encoder, (idle_pc_state == IDLE_PC_ENABLE) ? true : false); Loading @@ -3326,7 +3321,11 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, * preparing for the kickoff */ if (reset_req) { if (_sde_crtc_reset_hw(crtc, old_state, recovery_events)) sde_crtc->frame_trigger_mode = params.frame_trigger_mode; if (sde_crtc->frame_trigger_mode != FRAME_DONE_WAIT_POSTED_START && sde_crtc_reset_hw(crtc, old_state, params.recovery_events_enabled)) is_error = true; } Loading drivers/gpu/drm/msm/sde/sde_crtc.h +26 −0 Original line number Diff line number Diff line Loading @@ -219,6 +219,7 @@ struct sde_crtc_fps_info { * @power_event : registered power event handle * @cur_perf : current performance committed to clock/bandwidth driver * @plane_mask_old: keeps track of the planes used in the previous commit * @frame_trigger_mode: frame trigger mode */ struct sde_crtc { struct drm_crtc base; Loading Loading @@ -289,6 +290,7 @@ struct sde_crtc { /* blob for histogram data */ struct drm_property_blob *hist_blob; enum frame_trigger_mode_type frame_trigger_mode; }; #define to_sde_crtc(x) container_of(x, struct sde_crtc, base) Loading Loading @@ -441,6 +443,30 @@ static inline int sde_crtc_frame_pending(struct drm_crtc *crtc) return atomic_read(&sde_crtc->frame_pending); } /** * sde_crtc_reset_hw - attempt hardware reset on errors * @crtc: Pointer to DRM crtc instance * @old_state: Pointer to crtc state for previous commit * @recovery_events: Whether or not recovery events are enabled * Returns: Zero if current commit should still be attempted */ int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, bool recovery_events); /** * sde_crtc_request_frame_reset - requests for next frame reset * @crtc: Pointer to drm crtc object */ static inline int sde_crtc_request_frame_reset(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); if (sde_crtc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) sde_crtc_reset_hw(crtc, crtc->state, false); return 0; } /** * sde_crtc_vblank - enable or disable vblanks for this crtc * @crtc: Pointer to drm crtc object Loading drivers/gpu/drm/msm/sde/sde_encoder.c +55 −46 Original line number Diff line number Diff line Loading @@ -189,9 +189,8 @@ enum sde_enc_rc_states { * @debugfs_root: Debug file system root file node * @enc_lock: Lock around physical encoder create/destroy and access. * @frame_busy_mask: Bitmask tracking which phys_enc we are still * busy processing current command. * Bit0 = phys_encs[0] etc. * @frame_done_cnt: Atomic counter for tracking which phys_enc is * done with frame processing. * @crtc_frame_event_cb: callback handler for frame event * @crtc_frame_event_cb_data: callback handler private data * @vsync_event_timer: vsync timer Loading @@ -214,6 +213,8 @@ enum sde_enc_rc_states { * @topology: topology of the display * @vblank_enabled: boolean to track userspace vblank vote * @idle_pc_restore: flag to indicate idle_pc_restore happened * @frame_trigger_mode: frame trigger mode indication for command * mode display * @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 Loading Loading @@ -244,7 +245,7 @@ struct sde_encoder_virt { struct dentry *debugfs_root; struct mutex enc_lock; DECLARE_BITMAP(frame_busy_mask, MAX_PHYS_ENCODERS_PER_VIRTUAL); atomic_t frame_done_cnt[MAX_PHYS_ENCODERS_PER_VIRTUAL]; void (*crtc_frame_event_cb)(void *data, u32 event); struct sde_crtc_frame_event_cb_data crtc_frame_event_cb_data; Loading @@ -267,6 +268,7 @@ struct sde_encoder_virt { struct msm_display_topology topology; bool vblank_enabled; bool idle_pc_restore; enum frame_trigger_mode_type frame_trigger_mode; struct sde_rsc_cmd_config rsc_config; struct sde_rect cur_conn_roi; Loading Loading @@ -2255,6 +2257,17 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return -EINVAL; } /* * schedule off work item only when there are no * frames pending */ if (sde_crtc_frame_pending(sde_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; } if (sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { SDE_ERROR("invalid crtc index :%u\n", sde_enc->crtc->index); Loading @@ -2276,17 +2289,6 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return -EINVAL; } /* * schedule off work item only when there are no * frames pending */ if (sde_crtc_frame_pending(sde_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; } /* schedule delayed off work if autorefresh is disabled */ if (sde_enc->cur_master && sde_enc->cur_master->ops.is_autorefresh_enabled) Loading Loading @@ -2487,17 +2489,10 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, SDE_EVTLOG_ERROR); mutex_unlock(&sde_enc->rc_lock); return 0; } /* * if we are in ON but a frame was just kicked off, * ignore the IDLE event, it's probably a stale timer event */ if (sde_enc->frame_busy_mask[0]) { SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc:%d frame pending\n", sw_event, sde_enc->rc_state); } else if (sde_crtc_frame_pending(sde_enc->crtc) > 1) { SDE_DEBUG_ENC(sde_enc, "skip idle entry"); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, sde_crtc_frame_pending(sde_enc->crtc), SDE_EVTLOG_ERROR); mutex_unlock(&sde_enc->rc_lock); return 0; Loading Loading @@ -3045,6 +3040,7 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) phys->comp_type = comp_info->comp_type; phys->comp_ratio = comp_info->comp_ratio; phys->wide_bus_en = mode_info.wide_bus_en; phys->frame_trigger_mode = sde_enc->frame_trigger_mode; if (phys != sde_enc->cur_master) { /** * on DMS request, the encoder will be enabled Loading Loading @@ -3414,6 +3410,8 @@ static void sde_encoder_frame_done_callback( { struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); unsigned int i; bool trigger = true; enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE; if (!drm_enc || !sde_enc->cur_master) { SDE_ERROR("invalid param: drm_enc %x, cur_master %x\n", Loading @@ -3428,25 +3426,34 @@ static void sde_encoder_frame_done_callback( | SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) { if (!sde_enc->frame_busy_mask[0]) { /** * suppress frame_done without waiter, * likely autorefresh */ SDE_EVT32(DRMID(drm_enc), event, ready_phys->intf_idx); return; } if (ready_phys->connector) topology = sde_connector_get_topology_name( ready_phys->connector); /* One of the physical encoders has become idle */ for (i = 0; i < sde_enc->num_phys_encs; i++) { if (sde_enc->phys_encs[i] == ready_phys) { clear_bit(i, sde_enc->frame_busy_mask); if ((sde_enc->phys_encs[i] == ready_phys) || (event & SDE_ENCODER_FRAME_EVENT_ERROR)) { SDE_EVT32_VERBOSE(DRMID(drm_enc), i, sde_enc->frame_busy_mask[0]); atomic_read(&sde_enc->frame_done_cnt[i])); if (!atomic_add_unless( &sde_enc->frame_done_cnt[i], 1, 1)) { SDE_EVT32(DRMID(drm_enc), event, ready_phys->intf_idx, SDE_EVTLOG_ERROR); SDE_ERROR_ENC(sde_enc, "intf idx:%d, event:%d\n", ready_phys->intf_idx, event); return; } } if (topology != SDE_RM_TOPOLOGY_PPSPLIT && atomic_read(&sde_enc->frame_done_cnt[i]) != 1) trigger = false; } if (!sde_enc->frame_busy_mask[0]) { if (trigger) { sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_FRAME_DONE); Loading @@ -3454,6 +3461,8 @@ static void sde_encoder_frame_done_callback( sde_enc->crtc_frame_event_cb( &sde_enc->crtc_frame_event_cb_data, event); for (i = 0; i < sde_enc->num_phys_encs; i++) atomic_set(&sde_enc->frame_done_cnt[i], 0); } } else { if (sde_enc->crtc_frame_event_cb) Loading Loading @@ -3770,14 +3779,6 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) if (phys->connector) topology = sde_connector_get_topology_name( phys->connector); /* * don't wait on ppsplit slaves or skipped encoders because * they dont receive irqs */ if (!(topology == SDE_RM_TOPOLOGY_PPSPLIT && phys->split_role == ENC_ROLE_SLAVE) && phys->split_role != ENC_ROLE_SKIP) set_bit(i, sde_enc->frame_busy_mask); if (!phys->ops.needs_single_flush || !phys->ops.needs_single_flush(phys)) { Loading Loading @@ -4415,6 +4416,9 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, for (i = 0; i < sde_enc->num_phys_encs; i++) { phys = sde_enc->phys_encs[i]; params->is_primary = sde_enc->disp_info.is_primary; params->frame_trigger_mode = sde_enc->frame_trigger_mode; params->recovery_events_enabled = sde_enc->recovery_events_enabled; if (phys) { if (phys->ops.prepare_for_kickoff) { rc = phys->ops.prepare_for_kickoff( Loading Loading @@ -4855,6 +4859,9 @@ static int _sde_encoder_init_debugfs(struct drm_encoder *drm_enc) debugfs_create_bool("idle_power_collapse", 0600, sde_enc->debugfs_root, &sde_enc->idle_pc_enabled); debugfs_create_u32("frame_trigger_mode", 0600, sde_enc->debugfs_root, &sde_enc->frame_trigger_mode); for (i = 0; i < sde_enc->num_phys_encs; i++) if (sde_enc->phys_encs[i] && sde_enc->phys_encs[i]->ops.late_register) Loading Loading @@ -5152,6 +5159,8 @@ struct drm_encoder *sde_encoder_init( sde_enc->cur_master = NULL; spin_lock_init(&sde_enc->enc_spinlock); mutex_init(&sde_enc->vblank_ctl_lock); for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) atomic_set(&sde_enc->frame_done_cnt[i], 0); drm_enc = &sde_enc->base; drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode, NULL); drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs); Loading drivers/gpu/drm/msm/sde/sde_encoder.h +3 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include "msm_prop.h" #include "sde_hw_mdss.h" #include "sde_kms.h" #define SDE_ENCODER_FRAME_EVENT_DONE BIT(0) #define SDE_ENCODER_FRAME_EVENT_ERROR BIT(1) Loading Loading @@ -58,11 +59,13 @@ struct sde_encoder_hw_resources { * @affected_displays: bitmask, bit set means the ROI of the commit lies within * the bounds of the physical display at the bit index * @recovery_events_enabled: indicates status of client for recoovery events * @frame_trigger_mode: indicates frame trigger mode */ struct sde_encoder_kickoff_params { u32 is_primary; unsigned long affected_displays; bool recovery_events_enabled; enum frame_trigger_mode_type frame_trigger_mode; }; /** Loading drivers/gpu/drm/msm/sde/sde_encoder_phys.h +3 −3 Original line number Diff line number Diff line Loading @@ -281,6 +281,8 @@ struct sde_encoder_irq { * @in_clone_mode Indicates if encoder is in clone mode ref@CWB * @vfp_cached: cached vertical front porch to be used for * programming ROT and MDP fetch start * @frame_trigger_mode: frame trigger mode indication for command * mode display */ struct sde_encoder_phys { struct drm_encoder *parent; Loading Loading @@ -320,6 +322,7 @@ struct sde_encoder_phys { bool cont_splash_enabled; bool in_clone_mode; int vfp_cached; enum frame_trigger_mode_type frame_trigger_mode; }; static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys) Loading Loading @@ -359,8 +362,6 @@ struct sde_encoder_phys_cmd_autorefresh { * @base: Baseclass physical encoder structure * @intf_idx: Intf Block index used by this phys encoder * @stream_sel: Stream selection for multi-stream interfaces * @serialize_wait4pp: serialize wait4pp feature waits for pp_done interrupt * after ctl_start instead of before next frame kickoff * @pp_timeout_report_cnt: number of pingpong done irq timeout errors * @autorefresh: autorefresh feature state * @pending_rd_ptr_cnt: atomic counter to indicate if retire fence can be Loading @@ -374,7 +375,6 @@ struct sde_encoder_phys_cmd_autorefresh { struct sde_encoder_phys_cmd { struct sde_encoder_phys base; int stream_sel; bool serialize_wait4pp; int pp_timeout_report_cnt; struct sde_encoder_phys_cmd_autorefresh autorefresh; atomic_t pending_rd_ptr_cnt; Loading Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +10 −11 Original line number Diff line number Diff line Loading @@ -3148,14 +3148,13 @@ static void _sde_crtc_remove_pipe_flush(struct drm_crtc *crtc) } /** * _sde_crtc_reset_hw - attempt hardware reset on errors * sde_crtc_reset_hw - attempt hardware reset on errors * @crtc: Pointer to DRM crtc instance * @old_state: Pointer to crtc state for previous commit * @recovery_events: Whether or not recovery events are enabled * Returns: Zero if current commit should still be attempted */ static int _sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, bool recovery_events) { struct drm_plane *plane_halt[MAX_PLANES]; Loading Loading @@ -3265,9 +3264,10 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_crtc_state *cstate; bool is_error = false, reset_req, recovery_events; bool is_error = false, reset_req; unsigned long flags; enum sde_crtc_idle_pc_state idle_pc_state; struct sde_encoder_kickoff_params params = { 0 }; if (!crtc) { SDE_ERROR("invalid argument\n"); Loading Loading @@ -3299,8 +3299,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, idle_pc_state = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_PC_STATE); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct sde_encoder_kickoff_params params = { 0 }; if (encoder->crtc != crtc) continue; Loading @@ -3313,9 +3311,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, if (sde_encoder_prepare_for_kickoff(encoder, ¶ms)) reset_req = true; recovery_events = sde_encoder_recovery_events_enabled(encoder); if (idle_pc_state != IDLE_PC_NONE) sde_encoder_control_idle_pc(encoder, (idle_pc_state == IDLE_PC_ENABLE) ? true : false); Loading @@ -3326,7 +3321,11 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, * preparing for the kickoff */ if (reset_req) { if (_sde_crtc_reset_hw(crtc, old_state, recovery_events)) sde_crtc->frame_trigger_mode = params.frame_trigger_mode; if (sde_crtc->frame_trigger_mode != FRAME_DONE_WAIT_POSTED_START && sde_crtc_reset_hw(crtc, old_state, params.recovery_events_enabled)) is_error = true; } Loading
drivers/gpu/drm/msm/sde/sde_crtc.h +26 −0 Original line number Diff line number Diff line Loading @@ -219,6 +219,7 @@ struct sde_crtc_fps_info { * @power_event : registered power event handle * @cur_perf : current performance committed to clock/bandwidth driver * @plane_mask_old: keeps track of the planes used in the previous commit * @frame_trigger_mode: frame trigger mode */ struct sde_crtc { struct drm_crtc base; Loading Loading @@ -289,6 +290,7 @@ struct sde_crtc { /* blob for histogram data */ struct drm_property_blob *hist_blob; enum frame_trigger_mode_type frame_trigger_mode; }; #define to_sde_crtc(x) container_of(x, struct sde_crtc, base) Loading Loading @@ -441,6 +443,30 @@ static inline int sde_crtc_frame_pending(struct drm_crtc *crtc) return atomic_read(&sde_crtc->frame_pending); } /** * sde_crtc_reset_hw - attempt hardware reset on errors * @crtc: Pointer to DRM crtc instance * @old_state: Pointer to crtc state for previous commit * @recovery_events: Whether or not recovery events are enabled * Returns: Zero if current commit should still be attempted */ int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, bool recovery_events); /** * sde_crtc_request_frame_reset - requests for next frame reset * @crtc: Pointer to drm crtc object */ static inline int sde_crtc_request_frame_reset(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); if (sde_crtc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) sde_crtc_reset_hw(crtc, crtc->state, false); return 0; } /** * sde_crtc_vblank - enable or disable vblanks for this crtc * @crtc: Pointer to drm crtc object Loading
drivers/gpu/drm/msm/sde/sde_encoder.c +55 −46 Original line number Diff line number Diff line Loading @@ -189,9 +189,8 @@ enum sde_enc_rc_states { * @debugfs_root: Debug file system root file node * @enc_lock: Lock around physical encoder create/destroy and access. * @frame_busy_mask: Bitmask tracking which phys_enc we are still * busy processing current command. * Bit0 = phys_encs[0] etc. * @frame_done_cnt: Atomic counter for tracking which phys_enc is * done with frame processing. * @crtc_frame_event_cb: callback handler for frame event * @crtc_frame_event_cb_data: callback handler private data * @vsync_event_timer: vsync timer Loading @@ -214,6 +213,8 @@ enum sde_enc_rc_states { * @topology: topology of the display * @vblank_enabled: boolean to track userspace vblank vote * @idle_pc_restore: flag to indicate idle_pc_restore happened * @frame_trigger_mode: frame trigger mode indication for command * mode display * @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 Loading Loading @@ -244,7 +245,7 @@ struct sde_encoder_virt { struct dentry *debugfs_root; struct mutex enc_lock; DECLARE_BITMAP(frame_busy_mask, MAX_PHYS_ENCODERS_PER_VIRTUAL); atomic_t frame_done_cnt[MAX_PHYS_ENCODERS_PER_VIRTUAL]; void (*crtc_frame_event_cb)(void *data, u32 event); struct sde_crtc_frame_event_cb_data crtc_frame_event_cb_data; Loading @@ -267,6 +268,7 @@ struct sde_encoder_virt { struct msm_display_topology topology; bool vblank_enabled; bool idle_pc_restore; enum frame_trigger_mode_type frame_trigger_mode; struct sde_rsc_cmd_config rsc_config; struct sde_rect cur_conn_roi; Loading Loading @@ -2255,6 +2257,17 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return -EINVAL; } /* * schedule off work item only when there are no * frames pending */ if (sde_crtc_frame_pending(sde_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; } if (sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { SDE_ERROR("invalid crtc index :%u\n", sde_enc->crtc->index); Loading @@ -2276,17 +2289,6 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return -EINVAL; } /* * schedule off work item only when there are no * frames pending */ if (sde_crtc_frame_pending(sde_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; } /* schedule delayed off work if autorefresh is disabled */ if (sde_enc->cur_master && sde_enc->cur_master->ops.is_autorefresh_enabled) Loading Loading @@ -2487,17 +2489,10 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, SDE_EVTLOG_ERROR); mutex_unlock(&sde_enc->rc_lock); return 0; } /* * if we are in ON but a frame was just kicked off, * ignore the IDLE event, it's probably a stale timer event */ if (sde_enc->frame_busy_mask[0]) { SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc:%d frame pending\n", sw_event, sde_enc->rc_state); } else if (sde_crtc_frame_pending(sde_enc->crtc) > 1) { SDE_DEBUG_ENC(sde_enc, "skip idle entry"); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, sde_crtc_frame_pending(sde_enc->crtc), SDE_EVTLOG_ERROR); mutex_unlock(&sde_enc->rc_lock); return 0; Loading Loading @@ -3045,6 +3040,7 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) phys->comp_type = comp_info->comp_type; phys->comp_ratio = comp_info->comp_ratio; phys->wide_bus_en = mode_info.wide_bus_en; phys->frame_trigger_mode = sde_enc->frame_trigger_mode; if (phys != sde_enc->cur_master) { /** * on DMS request, the encoder will be enabled Loading Loading @@ -3414,6 +3410,8 @@ static void sde_encoder_frame_done_callback( { struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); unsigned int i; bool trigger = true; enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE; if (!drm_enc || !sde_enc->cur_master) { SDE_ERROR("invalid param: drm_enc %x, cur_master %x\n", Loading @@ -3428,25 +3426,34 @@ static void sde_encoder_frame_done_callback( | SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) { if (!sde_enc->frame_busy_mask[0]) { /** * suppress frame_done without waiter, * likely autorefresh */ SDE_EVT32(DRMID(drm_enc), event, ready_phys->intf_idx); return; } if (ready_phys->connector) topology = sde_connector_get_topology_name( ready_phys->connector); /* One of the physical encoders has become idle */ for (i = 0; i < sde_enc->num_phys_encs; i++) { if (sde_enc->phys_encs[i] == ready_phys) { clear_bit(i, sde_enc->frame_busy_mask); if ((sde_enc->phys_encs[i] == ready_phys) || (event & SDE_ENCODER_FRAME_EVENT_ERROR)) { SDE_EVT32_VERBOSE(DRMID(drm_enc), i, sde_enc->frame_busy_mask[0]); atomic_read(&sde_enc->frame_done_cnt[i])); if (!atomic_add_unless( &sde_enc->frame_done_cnt[i], 1, 1)) { SDE_EVT32(DRMID(drm_enc), event, ready_phys->intf_idx, SDE_EVTLOG_ERROR); SDE_ERROR_ENC(sde_enc, "intf idx:%d, event:%d\n", ready_phys->intf_idx, event); return; } } if (topology != SDE_RM_TOPOLOGY_PPSPLIT && atomic_read(&sde_enc->frame_done_cnt[i]) != 1) trigger = false; } if (!sde_enc->frame_busy_mask[0]) { if (trigger) { sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_FRAME_DONE); Loading @@ -3454,6 +3461,8 @@ static void sde_encoder_frame_done_callback( sde_enc->crtc_frame_event_cb( &sde_enc->crtc_frame_event_cb_data, event); for (i = 0; i < sde_enc->num_phys_encs; i++) atomic_set(&sde_enc->frame_done_cnt[i], 0); } } else { if (sde_enc->crtc_frame_event_cb) Loading Loading @@ -3770,14 +3779,6 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) if (phys->connector) topology = sde_connector_get_topology_name( phys->connector); /* * don't wait on ppsplit slaves or skipped encoders because * they dont receive irqs */ if (!(topology == SDE_RM_TOPOLOGY_PPSPLIT && phys->split_role == ENC_ROLE_SLAVE) && phys->split_role != ENC_ROLE_SKIP) set_bit(i, sde_enc->frame_busy_mask); if (!phys->ops.needs_single_flush || !phys->ops.needs_single_flush(phys)) { Loading Loading @@ -4415,6 +4416,9 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, for (i = 0; i < sde_enc->num_phys_encs; i++) { phys = sde_enc->phys_encs[i]; params->is_primary = sde_enc->disp_info.is_primary; params->frame_trigger_mode = sde_enc->frame_trigger_mode; params->recovery_events_enabled = sde_enc->recovery_events_enabled; if (phys) { if (phys->ops.prepare_for_kickoff) { rc = phys->ops.prepare_for_kickoff( Loading Loading @@ -4855,6 +4859,9 @@ static int _sde_encoder_init_debugfs(struct drm_encoder *drm_enc) debugfs_create_bool("idle_power_collapse", 0600, sde_enc->debugfs_root, &sde_enc->idle_pc_enabled); debugfs_create_u32("frame_trigger_mode", 0600, sde_enc->debugfs_root, &sde_enc->frame_trigger_mode); for (i = 0; i < sde_enc->num_phys_encs; i++) if (sde_enc->phys_encs[i] && sde_enc->phys_encs[i]->ops.late_register) Loading Loading @@ -5152,6 +5159,8 @@ struct drm_encoder *sde_encoder_init( sde_enc->cur_master = NULL; spin_lock_init(&sde_enc->enc_spinlock); mutex_init(&sde_enc->vblank_ctl_lock); for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) atomic_set(&sde_enc->frame_done_cnt[i], 0); drm_enc = &sde_enc->base; drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode, NULL); drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs); Loading
drivers/gpu/drm/msm/sde/sde_encoder.h +3 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include "msm_prop.h" #include "sde_hw_mdss.h" #include "sde_kms.h" #define SDE_ENCODER_FRAME_EVENT_DONE BIT(0) #define SDE_ENCODER_FRAME_EVENT_ERROR BIT(1) Loading Loading @@ -58,11 +59,13 @@ struct sde_encoder_hw_resources { * @affected_displays: bitmask, bit set means the ROI of the commit lies within * the bounds of the physical display at the bit index * @recovery_events_enabled: indicates status of client for recoovery events * @frame_trigger_mode: indicates frame trigger mode */ struct sde_encoder_kickoff_params { u32 is_primary; unsigned long affected_displays; bool recovery_events_enabled; enum frame_trigger_mode_type frame_trigger_mode; }; /** Loading
drivers/gpu/drm/msm/sde/sde_encoder_phys.h +3 −3 Original line number Diff line number Diff line Loading @@ -281,6 +281,8 @@ struct sde_encoder_irq { * @in_clone_mode Indicates if encoder is in clone mode ref@CWB * @vfp_cached: cached vertical front porch to be used for * programming ROT and MDP fetch start * @frame_trigger_mode: frame trigger mode indication for command * mode display */ struct sde_encoder_phys { struct drm_encoder *parent; Loading Loading @@ -320,6 +322,7 @@ struct sde_encoder_phys { bool cont_splash_enabled; bool in_clone_mode; int vfp_cached; enum frame_trigger_mode_type frame_trigger_mode; }; static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys) Loading Loading @@ -359,8 +362,6 @@ struct sde_encoder_phys_cmd_autorefresh { * @base: Baseclass physical encoder structure * @intf_idx: Intf Block index used by this phys encoder * @stream_sel: Stream selection for multi-stream interfaces * @serialize_wait4pp: serialize wait4pp feature waits for pp_done interrupt * after ctl_start instead of before next frame kickoff * @pp_timeout_report_cnt: number of pingpong done irq timeout errors * @autorefresh: autorefresh feature state * @pending_rd_ptr_cnt: atomic counter to indicate if retire fence can be Loading @@ -374,7 +375,6 @@ struct sde_encoder_phys_cmd_autorefresh { struct sde_encoder_phys_cmd { struct sde_encoder_phys base; int stream_sel; bool serialize_wait4pp; int pp_timeout_report_cnt; struct sde_encoder_phys_cmd_autorefresh autorefresh; atomic_t pending_rd_ptr_cnt; Loading