diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index e48deb214e..d37561c6a7 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -3257,13 +3257,14 @@ struct dsi_panel *dsi_panel_get(struct device *parent, if (rc) DSI_ERR("failed to parse dfps configuration, rc=%d\n", rc); - if (!(panel->dfps_caps.dfps_support)) { - /* qsync and dfps are mutually exclusive features */ - rc = dsi_panel_parse_qsync_caps(panel, of_node); - if (rc) - DSI_DEBUG("failed to parse qsync features, rc=%d\n", - rc); - } + rc = dsi_panel_parse_qsync_caps(panel, of_node); + if (rc) + DSI_DEBUG("failed to parse qsync features, rc=%d\n", rc); + + /* allow qsync support only if DFPS is with VFP approach */ + if ((panel->dfps_caps.dfps_support) && + !(panel->dfps_caps.type == DSI_DFPS_IMMEDIATE_VFP)) + panel->qsync_min_fps = 0; rc = dsi_panel_parse_dyn_clk_caps(panel); if (rc) diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index c45dc8ca52..1375a4eb2c 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -621,17 +621,24 @@ void sde_connector_set_colorspace(struct sde_connector *c_conn) void sde_connector_set_qsync_params(struct drm_connector *connector) { - struct sde_connector *c_conn = to_sde_connector(connector); - u32 qsync_propval; + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + u32 qsync_propval = 0; + bool prop_dirty; if (!connector) return; + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector->state); c_conn->qsync_updated = false; - qsync_propval = sde_connector_get_property(c_conn->base.state, - CONNECTOR_PROP_QSYNC_MODE); - if (qsync_propval != c_conn->qsync_mode) { + prop_dirty = msm_property_is_dirty(&c_conn->property_info, + &c_state->property_state, + CONNECTOR_PROP_QSYNC_MODE); + if (prop_dirty) { + qsync_propval = sde_connector_get_property(c_conn->base.state, + CONNECTOR_PROP_QSYNC_MODE); SDE_DEBUG("updated qsync mode %d -> %d\n", c_conn->qsync_mode, qsync_propval); c_conn->qsync_updated = true; @@ -1376,6 +1383,10 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, if (rc) SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc); break; + case CONNECTOR_PROP_QSYNC_MODE: + msm_property_set_dirty(&c_conn->property_info, + &c_state->property_state, idx); + break; default: break; } @@ -2027,13 +2038,33 @@ static int sde_connector_atomic_check(struct drm_connector *connector, struct drm_connector_state *new_conn_state) { struct sde_connector *c_conn; + struct sde_connector_state *c_state; + bool qsync_dirty = false, has_modeset = false; if (!connector) { SDE_ERROR("invalid connector\n"); - return 0; + return -EINVAL; + } + + if (!new_conn_state) { + SDE_ERROR("invalid connector state\n"); + return -EINVAL; } c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(new_conn_state); + + has_modeset = sde_crtc_atomic_check_has_modeset(new_conn_state->state, + new_conn_state->crtc); + qsync_dirty = msm_property_is_dirty(&c_conn->property_info, + &c_state->property_state, + CONNECTOR_PROP_QSYNC_MODE); + + SDE_DEBUG("has_modeset %d qsync_dirty %d\n", has_modeset, qsync_dirty); + if (has_modeset && qsync_dirty) { + SDE_ERROR("invalid qsync update during modeset\n"); + return -EINVAL; + } if (c_conn->ops.atomic_check) return c_conn->ops.atomic_check(connector, diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index 8b8e32ed97..21e70ed9c2 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -714,6 +714,25 @@ static inline int sde_crtc_get_secure_level(struct drm_crtc *crtc, CRTC_PROP_SECURITY_LEVEL); } +/** sde_crtc_atomic_check_has_modeset - checks if the new_crtc_state in the + * drm_atomic_state has a modeset + * @state : pointer to drm_atomic_state + * @crtc : Pointer to drm crtc structure + * Returns true if crtc has modeset + */ +static inline bool sde_crtc_atomic_check_has_modeset( + struct drm_atomic_state *state, struct drm_crtc *crtc) +{ + struct drm_crtc_state *crtc_state; + + if (!state || !crtc) + return false; + + crtc_state = drm_atomic_get_new_crtc_state(state, + crtc); + return (crtc_state && drm_atomic_crtc_needs_modeset(crtc_state)); +} + /** * sde_crtc_get_secure_transition - determines the operations to be * performed before transitioning to secure state diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index f290c0e1e9..04da2e25f9 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -332,7 +332,7 @@ static void _sde_encoder_phys_vid_setup_avr( return; } - if (qsync_min_fps >= default_fps) { + if (qsync_min_fps > default_fps) { SDE_ERROR_VIDENC(vid_enc, "qsync fps %d must be less than default %d\n", qsync_min_fps, default_fps); diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 2bebbca07e..8d23b4638b 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -129,7 +129,7 @@ static int sde_hw_intf_avr_setup(struct sde_hw_intf *ctx, u32 min_fps, default_fps, diff_fps; u32 vsync_period_slow; u32 avr_vtotal; - u32 add_porches; + u32 add_porches = 0; if (!ctx || !params || !avr_params) { SDE_ERROR("invalid input parameter(s)\n"); @@ -146,7 +146,10 @@ static int sde_hw_intf_avr_setup(struct sde_hw_intf *ctx, vsync_period = params->vsync_pulse_width + params->v_back_porch + params->height + params->v_front_porch; - add_porches = mult_frac(vsync_period, diff_fps, min_fps); + + if (diff_fps) + add_porches = mult_frac(vsync_period, diff_fps, min_fps); + vsync_period_slow = vsync_period + add_porches; avr_vtotal = vsync_period_slow * hsync_period;