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 <pkandula@codeaurora.org>
This commit is contained in:
Prabhanjan Kandula
2021-08-02 12:12:06 -07:00
parent 6bf96605eb
commit 642c86fee9
8 changed files with 91 additions and 15 deletions

View File

@@ -2681,6 +2681,25 @@ u32 sde_crtc_get_dfps_maxfps(struct drm_crtc *crtc)
return 0; 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) static void sde_crtc_vblank_cb(void *data, ktime_t ts)
{ {
struct drm_crtc *crtc = (struct drm_crtc *)data; struct drm_crtc *crtc = (struct drm_crtc *)data;

View File

@@ -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); 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_ */ #endif /* _SDE_CRTC_H_ */

View File

@@ -61,7 +61,7 @@
(p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \ (p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \
##__VA_ARGS__) ##__VA_ARGS__)
#define SEC_TO_MILLI_SEC 1000
#define MISR_BUFF_SIZE 256 #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; *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) int sde_encoder_get_avr_status(struct drm_encoder *drm_enc)
{ {
struct sde_encoder_virt *sde_enc; struct sde_encoder_virt *sde_enc;

View File

@@ -51,6 +51,9 @@
#define IDLE_POWERCOLLAPSE_DURATION (66 - 16/2) #define IDLE_POWERCOLLAPSE_DURATION (66 - 16/2)
#define IDLE_POWERCOLLAPSE_IN_EARLY_WAKEUP (200 - 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 * Encoder functions and data types
* @intfs: Interfaces this encoder is using, INTF_MODE_NONE if unused * @intfs: Interfaces this encoder is using, INTF_MODE_NONE if unused

View File

@@ -22,8 +22,7 @@
#define SDE_ENCODER_NAME_MAX 16 #define SDE_ENCODER_NAME_MAX 16
/* wait for at most 2 vsync for lowest refresh rate (24hz) */ /* wait for at most 2 vsync for lowest refresh rate (24hz) */
#define KICKOFF_TIMEOUT_MS 84 #define DEFAULT_KICKOFF_TIMEOUT_MS 84
#define KICKOFF_TIMEOUT_JIFFIES msecs_to_jiffies(KICKOFF_TIMEOUT_MS)
#define MAX_TE_PROFILE_COUNT 5 #define MAX_TE_PROFILE_COUNT 5
/** /**
@@ -286,6 +285,7 @@ struct sde_encoder_irq {
* @pending_retire_fence_cnt: Atomic counter tracking the pending retire * @pending_retire_fence_cnt: Atomic counter tracking the pending retire
* fences that have to be signalled. * fences that have to be signalled.
* @pending_kickoff_wq: Wait queue for blocking until kickoff completes * @pending_kickoff_wq: Wait queue for blocking until kickoff completes
* @kickoff_timeout_ms: kickoff timeout in mill seconds
* @irq: IRQ tracking structures * @irq: IRQ tracking structures
* @has_intf_te: Interface TE configuration support * @has_intf_te: Interface TE configuration support
* @cont_splash_enabled: Variable to store continuous splash settings. * @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_kickoff_cnt;
atomic_t pending_retire_fence_cnt; atomic_t pending_retire_fence_cnt;
wait_queue_head_t pending_kickoff_wq; wait_queue_head_t pending_kickoff_wq;
u32 kickoff_timeout_ms;
struct sde_encoder_irq irq[INTR_IDX_MAX]; struct sde_encoder_irq irq[INTR_IDX_MAX];
bool has_intf_te; bool has_intf_te;
bool cont_splash_enabled; 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, void sde_encoder_helper_get_pp_line_count(struct drm_encoder *drm_enc,
struct sde_hw_pp_vsync_info *info); 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 * sde_encoder_helper_trigger_flush - control flush helper function
* This helper function may be optionally specified by physical * This helper function may be optionally specified by physical

View File

@@ -37,11 +37,13 @@
#define AUTOREFRESH_SEQ2_POLL_TIMEOUT 1000000 #define AUTOREFRESH_SEQ2_POLL_TIMEOUT 1000000
static inline int _sde_encoder_phys_cmd_get_idle_timeout( 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 ? return cmd_enc->autorefresh.cfg.frame_count ?
cmd_enc->autorefresh.cfg.frame_count * cmd_enc->autorefresh.cfg.frame_count * timeout : timeout;
KICKOFF_TIMEOUT_MS : KICKOFF_TIMEOUT_MS;
} }
static inline bool sde_encoder_phys_cmd_is_master( 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); _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( 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.wq = &phys_enc->pending_kickoff_wq;
wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; 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 */ /* slave encoder doesn't enable for ppsplit */
if (_sde_encoder_phys_is_ppsplit_slave(phys_enc)) 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.wq = &cmd_enc->autorefresh.kickoff_wq;
wait_info.atomic_cnt = &cmd_enc->autorefresh.kickoff_cnt; 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 */ /* wait for autorefresh kickoff to start */
ret = sde_encoder_helper_wait_for_irq(phys_enc, 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; ctl = phys_enc->hw_ctl;
c_conn = to_sde_connector(phys_enc->connector); 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 || if (c_conn->lp_mode == SDE_MODE_DPMS_LP1 ||
c_conn->lp_mode == SDE_MODE_DPMS_LP2) 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.wq = &phys_enc->pending_kickoff_wq;
wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt; 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.wq = &cmd_enc->pending_vblank_wq;
wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt; 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); atomic_inc(&cmd_enc->pending_vblank_cnt);
@@ -1696,6 +1701,7 @@ static void _sde_encoder_autorefresh_disable_seq1(
struct sde_encoder_phys *phys_enc) struct sde_encoder_phys *phys_enc)
{ {
int trial = 0; int trial = 0;
u32 timeout_ms = phys_enc->kickoff_timeout_ms;
struct sde_encoder_phys_cmd *cmd_enc = struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc); to_sde_encoder_phys_cmd(phys_enc);
@@ -1712,7 +1718,7 @@ static void _sde_encoder_autorefresh_disable_seq1(
do { do {
udelay(AUTOREFRESH_SEQ1_POLL_TIME); udelay(AUTOREFRESH_SEQ1_POLL_TIME);
if ((trial * 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, SDE_ERROR_CMDENC(cmd_enc,
"disable autorefresh failed\n"); "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; phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
cmd_enc->stream_sel = 0; cmd_enc->stream_sel = 0;
phys_enc->enable_state = SDE_ENC_DISABLED; 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); sde_encoder_phys_cmd_init_ops(&phys_enc->ops);
phys_enc->comp_type = p->comp_type; phys_enc->comp_type = p->comp_type;

View File

@@ -657,6 +657,9 @@ static void sde_encoder_phys_vid_mode_set(
} }
_sde_encoder_phys_vid_setup_irq_hw_idx(phys_enc); _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( 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.wq = &phys_enc->pending_kickoff_wq;
wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; 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 */ /* Wait for kickoff to complete */
ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_VSYNC, 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->enc_spinlock = p->enc_spinlock;
phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
phys_enc->comp_type = p->comp_type; phys_enc->comp_type = p->comp_type;
phys_enc->kickoff_timeout_ms = DEFAULT_KICKOFF_TIMEOUT_MS;
for (i = 0; i < INTR_IDX_MAX; i++) { for (i = 0; i < INTR_IDX_MAX; i++) {
irq = &phys_enc->irq[i]; irq = &phys_enc->irq[i];
INIT_LIST_HEAD(&irq->cb.list); INIT_LIST_HEAD(&irq->cb.list);

View File

@@ -1402,6 +1402,9 @@ static void sde_encoder_phys_wb_mode_set(
PTR_ERR(phys_enc->hw_cdm)); PTR_ERR(phys_enc->hw_cdm));
phys_enc->hw_cdm = NULL; 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) 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.wq = &phys_enc->pending_kickoff_wq;
wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt; wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt;
wait_info.timeout_ms = max_t(u32, wb_enc->wbdone_timeout, 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, rc = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WB_DONE,
&wait_info); &wait_info);
if (rc == -ETIMEDOUT && _sde_encoder_phys_wb_is_idle(phys_enc)) { 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; ret = -ENOMEM;
goto fail_alloc; goto fail_alloc;
} }
wb_enc->wbdone_timeout = KICKOFF_TIMEOUT_MS;
phys_enc = &wb_enc->base; phys_enc = &wb_enc->base;
phys_enc->kickoff_timeout_ms = DEFAULT_KICKOFF_TIMEOUT_MS;
if (p->sde_kms->vbif[VBIF_NRT]) { if (p->sde_kms->vbif[VBIF_NRT]) {
wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] = wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =