diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 7d235538c0..d4d0627c63 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -247,6 +247,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE, CONNECTOR_PROP_SET_PANEL_MODE, CONNECTOR_PROP_AVR_STEP, + CONNECTOR_PROP_EPT, CONNECTOR_PROP_CACHE_STATE, CONNECTOR_PROP_DSC_MODE, CONNECTOR_PROP_WB_USAGE_TYPE, diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 1fc11c35da..61438bd68a 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -3175,6 +3175,10 @@ static int _sde_connector_install_properties(struct drm_device *dev, "qsync_mode", 0, 0, e_qsync_mode, ARRAY_SIZE(e_qsync_mode), 0, CONNECTOR_PROP_QSYNC_MODE); + if (test_bit(SDE_FEATURE_EPT, sde_kms->catalog->features)) + msm_property_install_range(&c_conn->property_info, + "EPT", 0x0, 0, U64_MAX, 0, + CONNECTOR_PROP_EPT); if (test_bit(SDE_FEATURE_AVR_STEP, sde_kms->catalog->features)) msm_property_install_range(&c_conn->property_info, "avr_step", 0x0, 0, U32_MAX, 0, diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 72d222734a..48655a7088 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1241,7 +1241,7 @@ static int _sde_encoder_atomic_check_qsync(struct sde_connector *sde_conn, { int rc = 0; u32 avr_step; - bool qsync_dirty, has_modeset; + bool qsync_dirty, has_modeset, ept; struct drm_connector_state *conn_state = &sde_conn_state->base; u32 qsync_mode = sde_connector_get_property(&sde_conn_state->base, CONNECTOR_PROP_QSYNC_MODE); @@ -1249,9 +1249,12 @@ static int _sde_encoder_atomic_check_qsync(struct sde_connector *sde_conn, has_modeset = sde_crtc_atomic_check_has_modeset(conn_state->state, conn_state->crtc); qsync_dirty = msm_property_is_dirty(&sde_conn->property_info, &sde_conn_state->property_state, CONNECTOR_PROP_QSYNC_MODE); + ept = msm_property_is_dirty(&sde_conn->property_info, + &sde_conn_state->property_state, CONNECTOR_PROP_EPT); - if (has_modeset && qsync_dirty && (msm_is_mode_seamless_poms(&sde_conn_state->msm_mode) || - msm_is_mode_seamless_dyn_clk(&sde_conn_state->msm_mode))) { + if (has_modeset && (qsync_dirty || ept) && + (msm_is_mode_seamless_poms(&sde_conn_state->msm_mode) || + msm_is_mode_seamless_dyn_clk(&sde_conn_state->msm_mode))) { SDE_ERROR("invalid qsync update during modeset priv flag:%x\n", sde_conn_state->msm_mode.private_flags); return -EINVAL; @@ -4642,6 +4645,56 @@ static int _sde_encoder_prepare_for_kickoff_processing(struct drm_encoder *drm_e return ret; } +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; + struct drm_connector *drm_conn; + + if (!sde_enc->cur_master || !sde_enc->cur_master->connector) + return; + + drm_conn = sde_enc->cur_master->connector; + ept = sde_connector_get_property(drm_conn->state, CONNECTOR_PROP_EPT); + if (!ept) + return; + + avr_step_fps = sde_connector_get_avr_step(drm_conn); + qsync_mode = sde_connector_get_property(drm_conn->state, CONNECTOR_PROP_QSYNC_MODE); + if (qsync_mode) + _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; + + current_ts = ktime_get_ns(); + /* ept is in ns and avr_step is mulitple of refresh rate */ + ept_ts = avr_step_fps ? ept - DIV_ROUND_UP(NSEC_PER_SEC, avr_step_fps) + NSEC_PER_MSEC + : ept - NSEC_PER_MSEC; + + /* ept time already elapsed */ + if (ept_ts <= current_ts) { + SDE_DEBUG("enc:%d, ept elapsed; ept:%llu, ept_ts:%llu, current_ts:%llu\n", + DRMID(&sde_enc->base), ept, ept_ts, current_ts); + return; + } + + timeout_us = DIV_ROUND_UP((ept_ts - current_ts), 1000); + /* validate timeout is not beyond the min fps */ + if (timeout_us > DIV_ROUND_UP(USEC_PER_SEC, min_fps)) { + SDE_ERROR("enc:%d, invalid timeout_us:%llu; ept:%llu, ept_ts:%llu, cur_ts:%llu\n", + DRMID(&sde_enc->base), timeout_us, ept, ept_ts, current_ts); + return; + } + + SDE_ATRACE_BEGIN("schedule_timeout"); + usleep_range(timeout_us, timeout_us + 10); + SDE_ATRACE_END("schedule_timeout"); + + SDE_EVT32(DRMID(&sde_enc->base), qsync_mode, avr_step_fps, min_fps, ktime_to_us(current_ts), + ktime_to_us(ept_ts), timeout_us); +} + int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, struct sde_encoder_kickoff_params *params) { @@ -4715,6 +4768,8 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, goto end; } + _sde_encoder_delay_kickoff_processing(sde_enc); + ret = _sde_encoder_prepare_for_kickoff_processing(drm_enc, params, sde_enc, sde_kms, needs_hw_reset, is_cmd_mode); diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index 3e279aae38..0a401e5eaf 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -59,6 +59,8 @@ ((!(phys_enc) || ((idx) < 0) || ((idx) >= INTR_IDX_MAX)) ? \ 0 : ((phys_enc)->irq[(idx)].irq_idx >= 0)) +#define DEFAULT_MIN_FPS 10 + /** * Encoder functions and data types * @intfs: Interfaces this encoder is using, INTF_MODE_NONE if unused diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index 9edf9fb927..7804aaefad 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -1339,7 +1339,12 @@ static void sde_encoder_phys_cmd_tearcheck_config( * disable sde hw generated TE signal, since hw TE will arrive first. * Only caveat is if due to error, we hit wrap-around. */ - tc_cfg.sync_cfg_height = 0xFFF0; + 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; + 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; diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index bfa132598b..4152f1fe2c 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -5395,6 +5395,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) set_bit(SDE_FEATURE_SYS_CACHE_NSE, sde_cfg->features); set_bit(SDE_FEATURE_SYS_CACHE_STALING, sde_cfg->features); set_bit(SDE_FEATURE_WB_ROTATION, sde_cfg->features); + set_bit(SDE_FEATURE_EPT, sde_cfg->features); sde_cfg->allowed_dsc_reservation_switch = SDE_DP_DSC_RESERVATION_SWITCH; sde_cfg->autorefresh_disable_seq = AUTOREFRESH_DISABLE_SEQ2; sde_cfg->perf.min_prefill_lines = 40; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 8181ab17bc..3b05df5d0d 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -767,6 +767,7 @@ enum { * @SDE_FEATURE_SUI_BLENDSTAGE SecureUI Blendstage supported * @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_UBWC_STATS UBWC statistics supported * @SDE_FEATURE_VBIF_CLK_SPLIT VBIF clock split supported * @SDE_FEATURE_CTL_DONE Support for CTL DONE irq @@ -813,6 +814,7 @@ enum sde_mdss_features { SDE_FEATURE_SUI_BLENDSTAGE, SDE_FEATURE_SUI_NS_ALLOWED, SDE_FEATURE_TRUSTED_VM, + SDE_FEATURE_EPT, SDE_FEATURE_UBWC_STATS, SDE_FEATURE_VBIF_CLK_SPLIT, SDE_FEATURE_CTL_DONE, diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index e2bb33de3a..ecfcf50faf 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -1022,6 +1022,11 @@ static void sde_hw_intf_enable_wide_bus(struct sde_hw_intf *intf, SDE_REG_WRITE(c, INTF_CONFIG2, intf_cfg2); } +static bool sde_hw_intf_is_te_32bit_supported(struct sde_hw_intf *intf) +{ + return (intf->cap->features & BIT(SDE_INTF_TE_32BIT)); +} + static void _setup_intf_ops(struct sde_hw_intf_ops *ops, unsigned long cap) { @@ -1038,6 +1043,7 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops, ops->avr_ctrl = sde_hw_intf_avr_ctrl; ops->enable_compressed_input = sde_hw_intf_enable_compressed_input; ops->enable_wide_bus = sde_hw_intf_enable_wide_bus; + ops->is_te_32bit_supported = sde_hw_intf_is_te_32bit_supported; if (cap & BIT(SDE_INTF_STATUS)) ops->get_status = sde_hw_intf_v1_get_status; diff --git a/msm/sde/sde_hw_intf.h b/msm/sde/sde_hw_intf.h index 828351128d..9fccea48e6 100644 --- a/msm/sde/sde_hw_intf.h +++ b/msm/sde/sde_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -267,6 +267,11 @@ struct sde_hw_intf_ops { */ void (*override_tear_rd_ptr_val)(struct sde_hw_intf *intf, u32 adjusted_linecnt); + + /** + * Check if intf supports 32-bit registers for TE + */ + bool (*is_te_32bit_supported)(struct sde_hw_intf *intf); }; struct sde_hw_intf {