disp: msm: sde: program the start window based on "EPT_FPS"
Introduce a new connector property called “EPT_FPS” for the cmd mode panels. User space will set the “EPT_FPS” based on the intended content fps, relative to the last retire fence timestamp as calculated by Surface flinger. Program start window based on the Expected Present Time fps. Change-Id: I24b93e0f941af9fb2422b2484328254d04a1acbe Signed-off-by: Shirisha Kollapuram <quic_kshirish@quicinc.com> Signed-off-by: Veera Sundaram Sankaran <quic_veeras@quicinc.com>
This commit is contained in:

committed by
Veera Sundaram Sankaran

parent
2e3ba9430c
commit
0d6e7e269a
@@ -248,6 +248,7 @@ enum msm_mdp_conn_property {
|
||||
CONNECTOR_PROP_SET_PANEL_MODE,
|
||||
CONNECTOR_PROP_AVR_STEP_STATE,
|
||||
CONNECTOR_PROP_EPT,
|
||||
CONNECTOR_PROP_EPT_FPS,
|
||||
CONNECTOR_PROP_CACHE_STATE,
|
||||
CONNECTOR_PROP_DSC_MODE,
|
||||
CONNECTOR_PROP_WB_USAGE_TYPE,
|
||||
|
@@ -854,7 +854,7 @@ void sde_connector_set_qsync_params(struct drm_connector *connector)
|
||||
{
|
||||
struct sde_connector *c_conn;
|
||||
struct sde_connector_state *c_state;
|
||||
u32 qsync_propval = 0;
|
||||
u32 qsync_propval = 0, ept_fps = 0;
|
||||
bool prop_dirty;
|
||||
|
||||
if (!connector)
|
||||
@@ -882,6 +882,16 @@ void sde_connector_set_qsync_params(struct drm_connector *connector)
|
||||
CONNECTOR_PROP_AVR_STEP_STATE);
|
||||
if (prop_dirty)
|
||||
c_conn->qsync_updated = true;
|
||||
|
||||
prop_dirty = msm_property_is_dirty(&c_conn->property_info, &c_state->property_state,
|
||||
CONNECTOR_PROP_EPT_FPS);
|
||||
if (prop_dirty) {
|
||||
ept_fps = sde_connector_get_property(c_conn->base.state, CONNECTOR_PROP_EPT_FPS);
|
||||
if (ept_fps != c_conn->ept_fps) {
|
||||
c_conn->qsync_updated = true;
|
||||
c_conn->ept_fps = ept_fps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sde_connector_complete_qsync_commit(struct drm_connector *conn,
|
||||
@@ -1794,6 +1804,8 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
|
||||
SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc);
|
||||
break;
|
||||
case CONNECTOR_PROP_QSYNC_MODE:
|
||||
case CONNECTOR_PROP_AVR_STEP_STATE:
|
||||
case CONNECTOR_PROP_EPT_FPS:
|
||||
msm_property_set_dirty(&c_conn->property_info,
|
||||
&c_state->property_state, idx);
|
||||
break;
|
||||
@@ -3077,6 +3089,11 @@ static void _sde_connector_install_qsync_properties(struct sde_kms *sde_kms,
|
||||
msm_property_install_enum(&c_conn->property_info, "avr_step_state",
|
||||
0, 0, e_avr_step_state, ARRAY_SIZE(e_avr_step_state), 0,
|
||||
CONNECTOR_PROP_AVR_STEP_STATE);
|
||||
|
||||
if (test_bit(SDE_FEATURE_EPT_FPS, sde_kms->catalog->features) &&
|
||||
(display_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE))
|
||||
msm_property_install_range(&c_conn->property_info,
|
||||
"EPT_FPS", 0x0, 0, U32_MAX, 0, CONNECTOR_PROP_EPT_FPS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -567,6 +567,7 @@ struct sde_misr_sign {
|
||||
* @dimming_bl_notify_enabled: Flag to indicate if dimming bl notify is enabled or not
|
||||
* @qsync_mode: Cached Qsync mode, 0=disabled, 1=continuous mode
|
||||
* @qsync_updated: Qsync settings were updated
|
||||
* @ept_fps: ept fps is updated, 0 means ept_fps is disabled
|
||||
* @colorspace_updated: Colorspace property was updated
|
||||
* @last_cmd_tx_sts: status of the last command transfer
|
||||
* @hdr_capable: external hdr support present
|
||||
@@ -641,6 +642,7 @@ struct sde_connector {
|
||||
u8 hdr_plus_app_ver;
|
||||
u32 qsync_mode;
|
||||
bool qsync_updated;
|
||||
u32 ept_fps;
|
||||
|
||||
bool colorspace_updated;
|
||||
|
||||
|
@@ -4659,10 +4659,12 @@ void _sde_encoder_delay_kickoff_processing(struct sde_encoder_virt *sde_enc)
|
||||
ktime_t current_ts, ept_ts;
|
||||
u32 avr_step_fps, min_fps = 0, qsync_mode;
|
||||
u64 timeout_us = 0, ept;
|
||||
bool is_cmd_mode;
|
||||
struct drm_connector *drm_conn;
|
||||
struct msm_mode_info *info = &sde_enc->mode_info;
|
||||
struct sde_kms *sde_kms = sde_encoder_get_kms(&sde_enc->base);
|
||||
|
||||
if (!sde_enc->cur_master || !sde_enc->cur_master->connector)
|
||||
if (!sde_enc->cur_master || !sde_enc->cur_master->connector || !sde_kms)
|
||||
return;
|
||||
|
||||
drm_conn = sde_enc->cur_master->connector;
|
||||
@@ -4675,6 +4677,15 @@ void _sde_encoder_delay_kickoff_processing(struct sde_encoder_virt *sde_enc)
|
||||
_sde_encoder_get_qsync_fps_callback(&sde_enc->base, &min_fps, drm_conn->state);
|
||||
/* use min qsync fps, if feature is enabled; otherwise min default fps */
|
||||
min_fps = min_fps ? min_fps : DEFAULT_MIN_FPS;
|
||||
is_cmd_mode = sde_encoder_check_curr_mode(&sde_enc->base, MSM_DISPLAY_CMD_MODE);
|
||||
|
||||
/* for cmd mode with qsync - EPT_FPS will be used to delay the processing */
|
||||
if (test_bit(SDE_FEATURE_EPT_FPS, sde_kms->catalog->features)
|
||||
&& is_cmd_mode && qsync_mode) {
|
||||
SDE_DEBUG("enc:%d, ept:%llu not applicable for cmd mode with qsync enabled",
|
||||
DRMID(&sde_enc->base), ept);
|
||||
return;
|
||||
}
|
||||
|
||||
avr_step_fps = info->avr_step_fps;
|
||||
current_ts = ktime_get_ns();
|
||||
|
@@ -1296,50 +1296,55 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc,
|
||||
}
|
||||
}
|
||||
|
||||
static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc)
|
||||
static void _get_tearcheck_cfg(struct sde_encoder_phys *phys_enc,
|
||||
u32 *t_lines, u32 *c_height, u32 *s_pos)
|
||||
{
|
||||
struct drm_connector *conn = phys_enc->connector;
|
||||
u32 qsync_mode;
|
||||
struct drm_display_mode *mode;
|
||||
u32 threshold_lines, adjusted_threshold_lines;
|
||||
struct sde_encoder_phys_cmd *cmd_enc =
|
||||
to_sde_encoder_phys_cmd(phys_enc);
|
||||
struct sde_encoder_virt *sde_enc;
|
||||
struct msm_mode_info *info;
|
||||
struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(phys_enc->parent);
|
||||
struct msm_mode_info *info = &sde_enc->mode_info;
|
||||
struct drm_display_mode *mode = &phys_enc->cached_mode;
|
||||
enum sde_rm_qsync_modes qsync_mode;
|
||||
ktime_t qsync_time_ns, default_time_ns, default_line_time_ns, ept_time_ns;
|
||||
ktime_t extra_time_ns = 0, ept_extra_time_ns = 0, qsync_l_bound_ns, qsync_u_bound_ns;
|
||||
u32 threshold_lines, ept_threshold_lines = 0, yres;
|
||||
u32 default_fps, qsync_min_fps = 0, ept_fps = 0;
|
||||
u32 adjusted_threshold_lines, cfg_height, start_pos;
|
||||
|
||||
if (!conn || !conn->state)
|
||||
return 0;
|
||||
*t_lines = *c_height = *s_pos = 0;
|
||||
if (!conn || !conn->state || !phys_enc->sde_kms)
|
||||
return;
|
||||
|
||||
/*
|
||||
* By setting sync_cfg_height to near max register value, we essentially
|
||||
* disable sde hw generated TE signal, since hw TE will arrive first.
|
||||
* Only caveat is if due to error, we hit wrap-around.
|
||||
*/
|
||||
if (phys_enc->hw_intf->ops.is_te_32bit_supported
|
||||
&& phys_enc->hw_intf->ops.is_te_32bit_supported(phys_enc->hw_intf))
|
||||
cfg_height = 0xFFFFFFF0;
|
||||
else
|
||||
cfg_height = 0xFFF0;
|
||||
|
||||
adjusted_threshold_lines = DEFAULT_TEARCHECK_SYNC_THRESH_START;
|
||||
start_pos = mode->vdisplay;
|
||||
|
||||
yres = mode->vtotal;
|
||||
default_fps = drm_mode_vrefresh(mode);
|
||||
|
||||
sde_enc = to_sde_encoder_virt(phys_enc->parent);
|
||||
info = &sde_enc->mode_info;
|
||||
mode = &phys_enc->cached_mode;
|
||||
qsync_mode = sde_connector_get_qsync_mode(conn);
|
||||
threshold_lines = adjusted_threshold_lines = DEFAULT_TEARCHECK_SYNC_THRESH_START;
|
||||
|
||||
if (mode && (qsync_mode == SDE_RM_QSYNC_CONTINUOUS_MODE)) {
|
||||
u32 qsync_min_fps = 0;
|
||||
ktime_t qsync_time_ns;
|
||||
ktime_t qsync_l_bound_ns, qsync_u_bound_ns;
|
||||
u32 default_fps = drm_mode_vrefresh(mode);
|
||||
ktime_t default_time_ns;
|
||||
ktime_t default_line_time_ns;
|
||||
ktime_t extra_time_ns;
|
||||
u32 yres = mode->vtotal;
|
||||
if (qsync_mode != SDE_RM_QSYNC_CONTINUOUS_MODE)
|
||||
goto exit;
|
||||
|
||||
if (phys_enc->parent_ops.get_qsync_fps)
|
||||
phys_enc->parent_ops.get_qsync_fps(phys_enc->parent, &qsync_min_fps,
|
||||
conn->state);
|
||||
phys_enc->parent_ops.get_qsync_fps(phys_enc->parent, &qsync_min_fps, conn->state);
|
||||
|
||||
if (!qsync_min_fps || !default_fps || !yres) {
|
||||
SDE_ERROR_CMDENC(cmd_enc,
|
||||
"wrong qsync params %d %d %d\n",
|
||||
SDE_ERROR_CMDENC(cmd_enc, "wrong qsync params %d %d %d\n",
|
||||
qsync_min_fps, default_fps, yres);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (qsync_min_fps >= default_fps) {
|
||||
SDE_ERROR_CMDENC(cmd_enc,
|
||||
"qsync fps:%d must be less than default:%d\n",
|
||||
} else if (qsync_min_fps >= default_fps) {
|
||||
SDE_ERROR_CMDENC(cmd_enc, "qsync fps:%d must be less than default:%d\n",
|
||||
qsync_min_fps, default_fps);
|
||||
goto exit;
|
||||
}
|
||||
@@ -1352,8 +1357,8 @@ static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc)
|
||||
* nominal_line_time = nominal_period / vtotal
|
||||
* qsync_safe_window_lines = qsync_safe_window_period / nominal_line_time
|
||||
*/
|
||||
qsync_time_ns = mult_frac(1000000000, 1, qsync_min_fps);
|
||||
default_time_ns = mult_frac(1000000000, 1, default_fps);
|
||||
qsync_time_ns = mult_frac(NSEC_PER_SEC, 1, qsync_min_fps);
|
||||
default_time_ns = mult_frac(NSEC_PER_SEC, 1, default_fps);
|
||||
|
||||
sde_encoder_helper_get_jitter_bounds_ns(qsync_min_fps, info->jitter_numer,
|
||||
info->jitter_denom, &qsync_l_bound_ns, &qsync_u_bound_ns);
|
||||
@@ -1370,25 +1375,48 @@ static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc)
|
||||
if (adjusted_threshold_lines - 2 > DEFAULT_TEARCHECK_SYNC_THRESH_START)
|
||||
adjusted_threshold_lines -= 2;
|
||||
|
||||
/* override cfg_height & start_pos only if EPT_FPS feature is enabled */
|
||||
if (test_bit(SDE_FEATURE_EPT_FPS, phys_enc->sde_kms->catalog->features)) {
|
||||
cfg_height -= (start_pos + threshold_lines);
|
||||
|
||||
ept_fps = sde_connector_get_property(conn->state, CONNECTOR_PROP_EPT_FPS);
|
||||
if (!ept_fps) {
|
||||
goto end;
|
||||
} else if (ept_fps > default_fps) {
|
||||
SDE_ERROR_CMDENC(cmd_enc, "EPT fps:%d must be less than default:%d\n",
|
||||
ept_fps, default_fps);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* override start_pos, only when ept_fps is valid */
|
||||
ept_time_ns = mult_frac(NSEC_PER_SEC, 1, ept_fps);
|
||||
ept_extra_time_ns = ept_time_ns - default_time_ns;
|
||||
ept_threshold_lines = mult_frac(1, ept_extra_time_ns, default_line_time_ns);
|
||||
start_pos += ept_threshold_lines;
|
||||
}
|
||||
|
||||
end:
|
||||
SDE_DEBUG_CMDENC(cmd_enc,
|
||||
"qsync mode:%u min_fps:%u time:%lld low:%lld up:%lld jitter:%u/%u\n",
|
||||
"qsync mode:%u min_fps:%u ts:%llu jitter_ns:%llu/%llu jitter:%u/%u\n",
|
||||
qsync_mode, qsync_min_fps, qsync_time_ns, qsync_l_bound_ns,
|
||||
qsync_u_bound_ns, info->jitter_numer, info->jitter_denom);
|
||||
SDE_DEBUG_CMDENC(cmd_enc,
|
||||
"default fps:%u time:%lld yres:%u line_time:%lld\n",
|
||||
default_fps, default_time_ns, yres, default_line_time_ns);
|
||||
SDE_DEBUG_CMDENC(cmd_enc,
|
||||
"extra_time:%lld threshold_lines:%u adjusted_threshold_lines:%u\n",
|
||||
extra_time_ns, threshold_lines, adjusted_threshold_lines);
|
||||
SDE_DEBUG_CMDENC(cmd_enc, "default fps:%u ts:%llu yres:%u line_time:%llu extra_time:%llu\n",
|
||||
default_fps, default_time_ns, yres, default_line_time_ns, extra_time_ns);
|
||||
SDE_DEBUG_CMDENC(cmd_enc, "ept_fps:%d ts:%llu ept_extra_time:%llu ept_threshold_lines:%u\n",
|
||||
ept_fps, ept_time_ns, ept_extra_time_ns, ept_threshold_lines);
|
||||
SDE_DEBUG_CMDENC(cmd_enc, "threshold_lines:%u cfg_height:%u start_pos:%u\n",
|
||||
adjusted_threshold_lines, cfg_height, start_pos);
|
||||
|
||||
SDE_EVT32(qsync_mode, qsync_min_fps, default_fps, info->jitter_numer,
|
||||
info->jitter_denom, yres, extra_time_ns, default_line_time_ns,
|
||||
adjusted_threshold_lines);
|
||||
}
|
||||
adjusted_threshold_lines, start_pos, cfg_height, ept_fps);
|
||||
|
||||
exit:
|
||||
*t_lines = adjusted_threshold_lines;
|
||||
*c_height = cfg_height;
|
||||
*s_pos = start_pos;
|
||||
|
||||
return adjusted_threshold_lines;
|
||||
return;
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_cmd_tearcheck_config(
|
||||
@@ -1399,7 +1427,7 @@ static void sde_encoder_phys_cmd_tearcheck_config(
|
||||
struct sde_hw_tear_check tc_cfg = { 0 };
|
||||
struct drm_display_mode *mode;
|
||||
bool tc_enable = true;
|
||||
u32 vsync_hz;
|
||||
u32 vsync_hz, threshold, cfg_height, start_pos;
|
||||
int vrefresh;
|
||||
struct msm_drm_private *priv;
|
||||
struct sde_kms *sde_kms;
|
||||
@@ -1458,21 +1486,13 @@ static void sde_encoder_phys_cmd_tearcheck_config(
|
||||
/* enable external TE after kickoff to avoid premature autorefresh */
|
||||
tc_cfg.hw_vsync_mode = 0;
|
||||
|
||||
/*
|
||||
* By setting sync_cfg_height to near max register value, we essentially
|
||||
* disable sde hw generated TE signal, since hw TE will arrive first.
|
||||
* Only caveat is if due to error, we hit wrap-around.
|
||||
*/
|
||||
if (phys_enc->hw_intf->ops.is_te_32bit_supported
|
||||
&& phys_enc->hw_intf->ops.is_te_32bit_supported(phys_enc->hw_intf))
|
||||
tc_cfg.sync_cfg_height = 0xFFFFFFF0;
|
||||
else
|
||||
tc_cfg.sync_cfg_height = 0xFFF0;
|
||||
_get_tearcheck_cfg(phys_enc, &threshold, &cfg_height, &start_pos);
|
||||
tc_cfg.sync_threshold_start = threshold;
|
||||
tc_cfg.sync_cfg_height = cfg_height;
|
||||
tc_cfg.start_pos = start_pos;
|
||||
|
||||
tc_cfg.vsync_init_val = mode->vdisplay;
|
||||
tc_cfg.sync_threshold_start = _get_tearcheck_threshold(phys_enc);
|
||||
tc_cfg.sync_threshold_continue = DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE;
|
||||
tc_cfg.start_pos = mode->vdisplay;
|
||||
tc_cfg.rd_ptr_irq = mode->vdisplay + 1;
|
||||
tc_cfg.wr_ptr_irq = 1;
|
||||
cmd_enc->qsync_threshold_lines = tc_cfg.sync_threshold_start;
|
||||
@@ -1823,8 +1843,11 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
|
||||
}
|
||||
|
||||
if (sde_connector_is_qsync_updated(phys_enc->connector)) {
|
||||
tc_cfg.sync_threshold_start = _get_tearcheck_threshold(
|
||||
phys_enc);
|
||||
u32 threshold, cfg_height, start_pos;
|
||||
|
||||
_get_tearcheck_cfg(phys_enc, &threshold, &cfg_height, &start_pos);
|
||||
tc_cfg.sync_threshold_start = threshold;
|
||||
tc_cfg.start_pos = start_pos;
|
||||
cmd_enc->qsync_threshold_lines = tc_cfg.sync_threshold_start;
|
||||
if (phys_enc->has_intf_te &&
|
||||
phys_enc->hw_intf->ops.update_tearcheck)
|
||||
@@ -1833,7 +1856,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
|
||||
else if (phys_enc->hw_pp->ops.update_tearcheck)
|
||||
phys_enc->hw_pp->ops.update_tearcheck(
|
||||
phys_enc->hw_pp, &tc_cfg);
|
||||
SDE_EVT32(DRMID(phys_enc->parent), tc_cfg.sync_threshold_start);
|
||||
SDE_EVT32(DRMID(phys_enc->parent), tc_cfg.sync_threshold_start, tc_cfg.start_pos);
|
||||
}
|
||||
|
||||
sde_enc = to_sde_encoder_virt(phys_enc->parent);
|
||||
|
@@ -768,6 +768,7 @@ enum {
|
||||
* @SDE_FEATURE_SUI_NS_ALLOWED SecureUI allowed to access non-secure context banks
|
||||
* @SDE_FEATURE_TRUSTED_VM Trusted VM supported
|
||||
* @SDE_FEATURE_EPT Expected present time supported
|
||||
* @SDE_FEATURE_EPT_FPS Expected fps supported for cmd mode
|
||||
* @SDE_FEATURE_UBWC_STATS UBWC statistics supported
|
||||
* @SDE_FEATURE_VBIF_CLK_SPLIT VBIF clock split supported
|
||||
* @SDE_FEATURE_CTL_DONE Support for CTL DONE irq
|
||||
@@ -815,6 +816,7 @@ enum sde_mdss_features {
|
||||
SDE_FEATURE_SUI_NS_ALLOWED,
|
||||
SDE_FEATURE_TRUSTED_VM,
|
||||
SDE_FEATURE_EPT,
|
||||
SDE_FEATURE_EPT_FPS,
|
||||
SDE_FEATURE_UBWC_STATS,
|
||||
SDE_FEATURE_VBIF_CLK_SPLIT,
|
||||
SDE_FEATURE_CTL_DONE,
|
||||
|
@@ -863,6 +863,7 @@ static void sde_hw_intf_update_te(struct sde_hw_intf *intf,
|
||||
cfg &= ~0xFFFF;
|
||||
cfg |= te->sync_threshold_start;
|
||||
SDE_REG_WRITE(c, INTF_TEAR_SYNC_THRESH, cfg);
|
||||
SDE_REG_WRITE(c, INTF_TEAR_START_POS, te->start_pos);
|
||||
}
|
||||
|
||||
static int sde_hw_intf_connect_external_te(struct sde_hw_intf *intf,
|
||||
|
Reference in New Issue
Block a user