From 642c86fee91239093b9b135b24ff76f1b72661f9 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Mon, 2 Aug 2021 12:12:06 -0700 Subject: [PATCH] disp: msm: sde: compute timeouts based on refresh rate Current timeout values in sde driver for vblank, kickoff and frame complete timeouts are fixed and can be much lower than a vsync incase of low refresh rate display. Compute timeouts based on refresh rate for low refresh rate displays. Change-Id: I9dda41feb15446de7451824e185321de421ad575 Signed-off-by: Prabhanjan Kandula --- msm/sde/sde_crtc.c | 19 +++++++++++++++++++ msm/sde/sde_crtc.h | 6 ++++++ msm/sde/sde_encoder.c | 28 +++++++++++++++++++++++++++- msm/sde/sde_encoder.h | 3 +++ msm/sde/sde_encoder_phys.h | 12 ++++++++++-- msm/sde/sde_encoder_phys_cmd.c | 25 ++++++++++++++++--------- msm/sde/sde_encoder_phys_vid.c | 6 +++++- msm/sde/sde_encoder_phys_wb.c | 7 +++++-- 8 files changed, 91 insertions(+), 15 deletions(-) diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 23e8c2a453..48b93af509 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -2681,6 +2681,25 @@ u32 sde_crtc_get_dfps_maxfps(struct drm_crtc *crtc) return 0; } +struct drm_encoder *sde_crtc_get_src_encoder_of_clone(struct drm_crtc *crtc) +{ + struct drm_encoder *enc; + struct sde_crtc *sde_crtc; + + if (!crtc || !crtc->dev) + return NULL; + + sde_crtc = to_sde_crtc(crtc); + drm_for_each_encoder_mask(enc, crtc->dev, sde_crtc->cached_encoder_mask) { + if (sde_encoder_in_clone_mode(enc)) + continue; + + return enc; + } + + return NULL; +} + static void sde_crtc_vblank_cb(void *data, ktime_t ts) { struct drm_crtc *crtc = (struct drm_crtc *)data; diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index 82be602895..44d94ce990 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -1057,4 +1057,10 @@ void _sde_crtc_clear_dim_layers_v1(struct drm_crtc_state *state); */ void sde_crtc_cancel_delayed_work(struct drm_crtc *crtc); +/* + * sde_crtc_get_src_encoder_of_clone- find source encoder of a clone mode encoder + * @cstate: Pointer to DRM crtc object + */ +struct drm_encoder *sde_crtc_get_src_encoder_of_clone(struct drm_crtc *crtc); + #endif /* _SDE_CRTC_H_ */ diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 1fe64d66d7..3cb8097ccf 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -61,7 +61,7 @@ (p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \ ##__VA_ARGS__) - +#define SEC_TO_MILLI_SEC 1000 #define MISR_BUFF_SIZE 256 @@ -4488,6 +4488,32 @@ void sde_encoder_get_transfer_time(struct drm_encoder *drm_enc, *transfer_time_us = info->mdp_transfer_time_us; } +u32 sde_encoder_helper_get_kickoff_timeout_ms(struct drm_encoder *drm_enc) +{ + struct drm_encoder *src_enc = drm_enc; + struct sde_encoder_virt *sde_enc; + u32 fps; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return DEFAULT_KICKOFF_TIMEOUT_MS; + } + + if (sde_encoder_in_clone_mode(drm_enc)) + src_enc = sde_crtc_get_src_encoder_of_clone(drm_enc->crtc); + + if (!src_enc) + return DEFAULT_KICKOFF_TIMEOUT_MS; + + sde_enc = to_sde_encoder_virt(src_enc); + fps = sde_enc->mode_info.frame_rate; + + if (!fps || fps >= DEFAULT_TIMEOUT_FPS_THRESHOLD) + return DEFAULT_KICKOFF_TIMEOUT_MS; + else + return (SEC_TO_MILLI_SEC / fps) * 2; +} + int sde_encoder_get_avr_status(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc; diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index 5529e2bd3a..874a472ff3 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -51,6 +51,9 @@ #define IDLE_POWERCOLLAPSE_DURATION (66 - 16/2) #define IDLE_POWERCOLLAPSE_IN_EARLY_WAKEUP (200 - 16/2) +/* below this fps limit, timeouts are adjusted based on fps */ +#define DEFAULT_TIMEOUT_FPS_THRESHOLD 24 + /** * Encoder functions and data types * @intfs: Interfaces this encoder is using, INTF_MODE_NONE if unused diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 291fe0254a..ba3b661c5e 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -22,8 +22,7 @@ #define SDE_ENCODER_NAME_MAX 16 /* wait for at most 2 vsync for lowest refresh rate (24hz) */ -#define KICKOFF_TIMEOUT_MS 84 -#define KICKOFF_TIMEOUT_JIFFIES msecs_to_jiffies(KICKOFF_TIMEOUT_MS) +#define DEFAULT_KICKOFF_TIMEOUT_MS 84 #define MAX_TE_PROFILE_COUNT 5 /** @@ -286,6 +285,7 @@ struct sde_encoder_irq { * @pending_retire_fence_cnt: Atomic counter tracking the pending retire * fences that have to be signalled. * @pending_kickoff_wq: Wait queue for blocking until kickoff completes + * @kickoff_timeout_ms: kickoff timeout in mill seconds * @irq: IRQ tracking structures * @has_intf_te: Interface TE configuration support * @cont_splash_enabled: Variable to store continuous splash settings. @@ -332,6 +332,7 @@ struct sde_encoder_phys { atomic_t pending_kickoff_cnt; atomic_t pending_retire_fence_cnt; wait_queue_head_t pending_kickoff_wq; + u32 kickoff_timeout_ms; struct sde_encoder_irq irq[INTR_IDX_MAX]; bool has_intf_te; bool cont_splash_enabled; @@ -539,6 +540,13 @@ void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc, void sde_encoder_helper_get_pp_line_count(struct drm_encoder *drm_enc, struct sde_hw_pp_vsync_info *info); +/** + * sde_encoder_helper_get_kickoff_timeout_ms- get the kickoff timeout value based on fps + * @drm_enc: Pointer to drm encoder structure + * Returns: Kickoff timeout in milli seconds + */ +u32 sde_encoder_helper_get_kickoff_timeout_ms(struct drm_encoder *drm_enc); + /** * sde_encoder_helper_trigger_flush - control flush helper function * This helper function may be optionally specified by physical diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index e37e4030f4..c6ef692c64 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -37,11 +37,13 @@ #define AUTOREFRESH_SEQ2_POLL_TIMEOUT 1000000 static inline int _sde_encoder_phys_cmd_get_idle_timeout( - struct sde_encoder_phys_cmd *cmd_enc) + struct sde_encoder_phys *phys_enc) { + u32 timeout = phys_enc->kickoff_timeout_ms; + struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + return cmd_enc->autorefresh.cfg.frame_count ? - cmd_enc->autorefresh.cfg.frame_count * - KICKOFF_TIMEOUT_MS : KICKOFF_TIMEOUT_MS; + cmd_enc->autorefresh.cfg.frame_count * timeout : timeout; } static inline bool sde_encoder_phys_cmd_is_master( @@ -450,6 +452,9 @@ static void sde_encoder_phys_cmd_mode_set( } _sde_encoder_phys_cmd_setup_irq_hw_idx(phys_enc); + + phys_enc->kickoff_timeout_ms = + sde_encoder_helper_get_kickoff_timeout_ms(phys_enc->parent); } static int _sde_encoder_phys_cmd_handle_ppdone_timeout( @@ -708,7 +713,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle( wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; - wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + wait_info.timeout_ms = phys_enc->kickoff_timeout_ms; /* slave encoder doesn't enable for ppsplit */ if (_sde_encoder_phys_is_ppsplit_slave(phys_enc)) @@ -748,7 +753,7 @@ static int _sde_encoder_phys_cmd_wait_for_autorefresh_done( wait_info.wq = &cmd_enc->autorefresh.kickoff_wq; wait_info.atomic_cnt = &cmd_enc->autorefresh.kickoff_cnt; - wait_info.timeout_ms = _sde_encoder_phys_cmd_get_idle_timeout(cmd_enc); + wait_info.timeout_ms = _sde_encoder_phys_cmd_get_idle_timeout(phys_enc); /* wait for autorefresh kickoff to start */ ret = sde_encoder_helper_wait_for_irq(phys_enc, @@ -1427,11 +1432,11 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr( } ctl = phys_enc->hw_ctl; c_conn = to_sde_connector(phys_enc->connector); - timeout_ms = KICKOFF_TIMEOUT_MS; + timeout_ms = phys_enc->kickoff_timeout_ms; if (c_conn->lp_mode == SDE_MODE_DPMS_LP1 || c_conn->lp_mode == SDE_MODE_DPMS_LP2) - timeout_ms = (KICKOFF_TIMEOUT_MS) * 2; + timeout_ms = timeout_ms * 2; wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt; @@ -1649,7 +1654,7 @@ static int sde_encoder_phys_cmd_wait_for_vblank( wait_info.wq = &cmd_enc->pending_vblank_wq; wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt; - wait_info.timeout_ms = _sde_encoder_phys_cmd_get_idle_timeout(cmd_enc); + wait_info.timeout_ms = _sde_encoder_phys_cmd_get_idle_timeout(phys_enc); atomic_inc(&cmd_enc->pending_vblank_cnt); @@ -1696,6 +1701,7 @@ static void _sde_encoder_autorefresh_disable_seq1( struct sde_encoder_phys *phys_enc) { int trial = 0; + u32 timeout_ms = phys_enc->kickoff_timeout_ms; struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); @@ -1712,7 +1718,7 @@ static void _sde_encoder_autorefresh_disable_seq1( do { udelay(AUTOREFRESH_SEQ1_POLL_TIME); if ((trial * AUTOREFRESH_SEQ1_POLL_TIME) - > (KICKOFF_TIMEOUT_MS * USEC_PER_MSEC)) { + > (timeout_ms * USEC_PER_MSEC)) { SDE_ERROR_CMDENC(cmd_enc, "disable autorefresh failed\n"); @@ -1954,6 +1960,7 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; cmd_enc->stream_sel = 0; phys_enc->enable_state = SDE_ENC_DISABLED; + phys_enc->kickoff_timeout_ms = DEFAULT_KICKOFF_TIMEOUT_MS; sde_encoder_phys_cmd_init_ops(&phys_enc->ops); phys_enc->comp_type = p->comp_type; diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index 38b9c1a447..dc50bf7bd0 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -657,6 +657,9 @@ static void sde_encoder_phys_vid_mode_set( } _sde_encoder_phys_vid_setup_irq_hw_idx(phys_enc); + + phys_enc->kickoff_timeout_ms = + sde_encoder_helper_get_kickoff_timeout_ms(phys_enc->parent); } static int sde_encoder_phys_vid_control_vblank_irq( @@ -889,7 +892,7 @@ static int _sde_encoder_phys_vid_wait_for_vblank( wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; - wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + wait_info.timeout_ms = phys_enc->kickoff_timeout_ms; /* Wait for kickoff to complete */ ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_VSYNC, @@ -1361,6 +1364,7 @@ struct sde_encoder_phys *sde_encoder_phys_vid_init( phys_enc->enc_spinlock = p->enc_spinlock; phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; phys_enc->comp_type = p->comp_type; + phys_enc->kickoff_timeout_ms = DEFAULT_KICKOFF_TIMEOUT_MS; for (i = 0; i < INTR_IDX_MAX; i++) { irq = &phys_enc->irq[i]; INIT_LIST_HEAD(&irq->cb.list); diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index fa37667638..e4bb396311 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/msm/sde/sde_encoder_phys_wb.c @@ -1402,6 +1402,9 @@ static void sde_encoder_phys_wb_mode_set( PTR_ERR(phys_enc->hw_cdm)); phys_enc->hw_cdm = NULL; } + + phys_enc->kickoff_timeout_ms = + sde_encoder_helper_get_kickoff_timeout_ms(phys_enc->parent); } static int sde_encoder_phys_wb_frame_timeout(struct sde_encoder_phys *phys_enc) @@ -1508,7 +1511,7 @@ static int _sde_encoder_phys_wb_wait_for_commit_done( wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt; wait_info.timeout_ms = max_t(u32, wb_enc->wbdone_timeout, - KICKOFF_TIMEOUT_MS); + phys_enc->kickoff_timeout_ms); rc = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WB_DONE, &wait_info); if (rc == -ETIMEDOUT && _sde_encoder_phys_wb_is_idle(phys_enc)) { @@ -2037,9 +2040,9 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( ret = -ENOMEM; goto fail_alloc; } - wb_enc->wbdone_timeout = KICKOFF_TIMEOUT_MS; phys_enc = &wb_enc->base; + phys_enc->kickoff_timeout_ms = DEFAULT_KICKOFF_TIMEOUT_MS; if (p->sde_kms->vbif[VBIF_NRT]) { wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =