diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 22f2334afb..1f494e97a0 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -3362,6 +3362,7 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) sde_enc->phys_encs[i]->cont_splash_enabled = false; sde_enc->phys_encs[i]->connector = NULL; } + atomic_set(&sde_enc->frame_done_cnt[i], 0); } sde_enc->cur_master = NULL; @@ -3647,8 +3648,7 @@ static void sde_encoder_frame_done_callback( /* 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) || - (event & SDE_ENCODER_FRAME_EVENT_ERROR)) { + if (sde_enc->phys_encs[i] == ready_phys) { SDE_EVT32_VERBOSE(DRMID(drm_enc), i, atomic_read(&sde_enc->frame_done_cnt[i])); if (!atomic_add_unless( diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index bf58e27893..83232d7464 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -365,12 +365,12 @@ struct sde_encoder_phys_cmd_autorefresh { * struct sde_encoder_phys_cmd - sub-class of sde_encoder_phys to handle command * mode specific operations * @base: Baseclass physical encoder structure - * @intf_idx: Intf Block index used by this phys encoder * @stream_sel: Stream selection for multi-stream interfaces * @pp_timeout_report_cnt: number of pingpong done irq timeout errors * @autorefresh: autorefresh feature state * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK * @pending_vblank_wq: Wait queue for blocking until VBLANK received + * @wr_ptr_wait_success: log wr_ptr_wait success for release fence trigger */ struct sde_encoder_phys_cmd { struct sde_encoder_phys base; @@ -379,6 +379,7 @@ struct sde_encoder_phys_cmd { struct sde_encoder_phys_cmd_autorefresh autorefresh; atomic_t pending_vblank_cnt; wait_queue_head_t pending_vblank_wq; + bool wr_ptr_wait_success; }; /** diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index 6234c14006..8034784f6f 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -461,20 +461,18 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout( conn = phys_enc->connector; - if (atomic_read(&phys_enc->pending_kickoff_cnt) == 0) + /* decrement the kickoff_cnt before checking for ESD status */ + if (!atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) return 0; cmd_enc->pp_timeout_report_cnt++; - pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); + pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt) + 1; SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, cmd_enc->pp_timeout_report_cnt, pending_kickoff_cnt, frame_event); - /* decrement the kickoff_cnt before checking for ESD status */ - atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); - /* check if panel is still sending TE signal or not */ if (sde_connector_esd_status(phys_enc->connector)) goto exit; @@ -651,13 +649,29 @@ static int _sde_encoder_phys_cmd_wait_for_idle( to_sde_encoder_phys_cmd(phys_enc); struct sde_encoder_wait_info wait_info; bool recovery_events; - int ret, i, pending_cnt; + int ret; + struct sde_hw_ctl *ctl; if (!phys_enc) { SDE_ERROR("invalid encoder\n"); return -EINVAL; } + ctl = phys_enc->hw_ctl; + if (cmd_enc->wr_ptr_wait_success && + (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) && + ctl->ops.get_scheduler_status && + (ctl->ops.get_scheduler_status(ctl) & BIT(0)) && + atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0) && + phys_enc->parent_ops.handle_frame_done) { + + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, + SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE); + return 0; + } + wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; @@ -671,9 +685,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle( ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG, &wait_info); if (ret == -ETIMEDOUT) { - pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); - for (i = 0; i < pending_cnt; i++) - _sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc, + _sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc, recovery_events); } else if (!ret) { if (cmd_enc->pp_timeout_report_cnt && recovery_events) { @@ -1368,19 +1380,9 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr( phys_enc->parent_ops.handle_frame_done( phys_enc->parent, phys_enc, SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); - - } else if ((ret == 0) && - (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) - && ctl->ops.get_scheduler_status - && (ctl->ops.get_scheduler_status(ctl) & BIT(0)) - && atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0) - && phys_enc->parent_ops.handle_frame_done) { - phys_enc->parent_ops.handle_frame_done( - phys_enc->parent, phys_enc, - SDE_ENCODER_FRAME_EVENT_DONE | - SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE); } + cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false; return ret; } @@ -1408,7 +1410,7 @@ static int sde_encoder_phys_cmd_wait_for_tx_complete( static int sde_encoder_phys_cmd_wait_for_commit_done( struct sde_encoder_phys *phys_enc) { - int rc = 0; + int rc = 0, i, pending_cnt; struct sde_encoder_phys_cmd *cmd_enc; if (!phys_enc) @@ -1421,11 +1423,11 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( rc = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc); if (rc == -ETIMEDOUT) goto wait_for_idle; - } - if (!rc && sde_encoder_phys_cmd_is_master(phys_enc) && - cmd_enc->autorefresh.cfg.enable) - rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(phys_enc); + if (cmd_enc->autorefresh.cfg.enable) + rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done( + phys_enc); + } /* wait for posted start or serialize trigger */ if ((atomic_read(&phys_enc->pending_kickoff_cnt) > 1) || @@ -1435,14 +1437,16 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( return rc; wait_for_idle: - rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc); + pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); + for (i = 0; i < pending_cnt; i++) + rc |= sde_encoder_wait_for_event(phys_enc->parent, + MSM_ENC_TX_COMPLETE); if (rc) { SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->frame_trigger_mode, atomic_read(&phys_enc->pending_kickoff_cnt), phys_enc->enable_state, rc); - atomic_set(&phys_enc->pending_kickoff_cnt, 0); SDE_ERROR("pp:%d failed wait_for_idle: %d\n", phys_enc->hw_pp->idx - PINGPONG_0, rc); if (phys_enc->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET)