diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 9e9dc71a75..1b83ddf227 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -413,6 +413,7 @@ struct dsi_panel_cmd_set { * @vdc: VDC compression configuration. * @pclk_scale: pclk scale factor, target bpp to source bpp * @roi_caps: Panel ROI capabilities. + * @qsync_min_fps: Qsync min fps rate */ struct dsi_mode_info { u32 h_active; @@ -439,6 +440,7 @@ struct dsi_mode_info { struct msm_display_vdc_info *vdc; struct msm_ratio pclk_scale; struct msm_roi_caps roi_caps; + u32 qsync_min_fps; }; /** diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 7e7626b404..59be804506 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6838,6 +6838,7 @@ int dsi_display_get_modes(struct dsi_display *display, struct dsi_dyn_clk_caps *dyn_clk_caps; int i, start, end, rc = -EINVAL; int dsc_modes = 0, nondsc_modes = 0; + struct dsi_qsync_capabilities *qsync_caps; if (!display || !out_modes) { DSI_ERR("Invalid params\n"); @@ -6868,6 +6869,7 @@ int dsi_display_get_modes(struct dsi_display *display, goto error; } + qsync_caps = &(display->panel->qsync_caps); dyn_clk_caps = &(display->panel->dyn_clk_caps); timing_mode_count = display->panel->num_timing_nodes; @@ -6963,6 +6965,14 @@ int dsi_display_get_modes(struct dsi_display *display, memcpy(sub_mode, &display_mode, sizeof(display_mode)); array_idx++; + /* + * Populate mode qsync min fps from panel min qsync fps dt property + * in video mode & in command mode where per mode qsync min fps is + * not defined. + */ + if (!sub_mode->timing.qsync_min_fps && qsync_caps->qsync_min_fps) + sub_mode->timing.qsync_min_fps = qsync_caps->qsync_min_fps; + if (!dfps_caps.dfps_support || !support_video_mode) continue; @@ -6970,6 +6980,10 @@ int dsi_display_get_modes(struct dsi_display *display, curr_refresh_rate = sub_mode->timing.refresh_rate; sub_mode->timing.refresh_rate = dfps_caps.dfps_list[i]; + /* Override with qsync min fps list in dfps usecases */ + if (qsync_caps->qsync_min_fps && qsync_caps->qsync_min_fps_list_len) + sub_mode->timing.qsync_min_fps = qsync_caps->qsync_min_fps_list[i]; + dsi_display_get_dfps_timing(display, sub_mode, curr_refresh_rate); sub_mode->panel_mode_caps = DSI_OP_VIDEO_MODE; @@ -7080,25 +7094,6 @@ int dsi_display_get_default_lms(void *dsi_display, u32 *num_lm) return rc; } -int dsi_display_get_qsync_min_fps(void *display_dsi, u32 mode_fps) -{ - struct dsi_display *display = (struct dsi_display *)display_dsi; - struct dsi_panel *panel; - u32 i; - - if (display == NULL || display->panel == NULL) - return -EINVAL; - - panel = display->panel; - for (i = 0; i < panel->dfps_caps.dfps_list_len; i++) { - if (panel->dfps_caps.dfps_list[i] == mode_fps) - return panel->qsync_caps.qsync_min_fps_list[i]; - } - SDE_EVT32(mode_fps); - DSI_DEBUG("Invalid mode_fps %d\n", mode_fps); - return -EINVAL; -} - int dsi_display_get_avr_step_req_fps(void *display_dsi, u32 mode_fps) { struct dsi_display *display = (struct dsi_display *)display_dsi; @@ -8061,11 +8056,6 @@ static int dsi_display_qsync(struct dsi_display *display, bool enable) int i; int rc = 0; - if (!display->panel->qsync_caps.qsync_min_fps) { - DSI_ERR("%s:ERROR: qsync set, but no fps\n", __func__); - return 0; - } - mutex_lock(&display->display_lock); display_for_each_ctrl(i, display) { diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index 2bbdf1fbfc..5a642ab44c 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -419,15 +419,6 @@ void dsi_display_put_mode(struct dsi_display *display, */ int dsi_display_get_default_lms(void *dsi_display, u32 *num_lm); -/** - * dsi_display_get_qsync_min_fps() - get qsync min fps for given fps - * @display: Handle to display. - * @mode_fps: Fps value of current mode - * - * Return: Qsync min fps rate or -ve error code. - */ -int dsi_display_get_qsync_min_fps(void *dsi_display, u32 mode_fps); - /** * dsi_display_get_avr_step_req_fps() - get avr step rate for given fps * @display: Handle to display. diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 2cce66c32b..828de02b90 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -614,6 +614,7 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, mode_info->mdp_transfer_time_us = dsi_mode->priv_info->mdp_transfer_time_us; mode_info->disable_rsc_solver = dsi_mode->priv_info->disable_rsc_solver; + mode_info->qsync_min_fps = dsi_mode->timing.qsync_min_fps; memcpy(&mode_info->topology, &dsi_mode->priv_info->topology, sizeof(struct msm_display_topology)); @@ -699,6 +700,32 @@ int dsi_conn_set_avr_step_info(struct dsi_panel *panel, void *info) return 0; } +int dsi_conn_get_qsync_min_fps(void *display_dsi, struct drm_connector_state *conn_state) +{ + struct dsi_display *display = (struct dsi_display *)display_dsi; + int rc = 0; + struct dsi_display_mode partial_dsi_mode, *dsi_mode; + struct msm_sub_mode new_sub_mode; + struct sde_connector_state *sde_conn_state; + struct drm_display_mode *drm_mode; + + if (!display || !display->drm_conn || !conn_state) + return -EINVAL; + + sde_conn_state = to_sde_connector_state(conn_state); + drm_mode = sde_conn_state->msm_mode.base; + convert_to_dsi_mode(drm_mode, &partial_dsi_mode); + new_sub_mode.dsc_mode = sde_connector_get_property(conn_state, CONNECTOR_PROP_DSC_MODE); + + rc = dsi_display_find_mode(display, &partial_dsi_mode, &new_sub_mode, &dsi_mode); + if (rc) { + DSI_ERR("invalid mode\n"); + return rc; + } + + return dsi_mode->timing.qsync_min_fps; +} + int dsi_conn_set_info_blob(struct drm_connector *connector, void *info, void *display, struct msm_mode_info *mode_info) { @@ -761,7 +788,7 @@ int dsi_conn_set_info_blob(struct drm_connector *connector, } sde_kms_info_add_keystr(info, "qsync support", - panel->qsync_caps.qsync_min_fps ? + panel->qsync_caps.qsync_support ? "true" : "false"); if (panel->qsync_caps.qsync_min_fps) sde_kms_info_add_keyint(info, "qsync_fps", diff --git a/msm/dsi/dsi_drm.h b/msm/dsi/dsi_drm.h index 8910d52002..e2016d293a 100644 --- a/msm/dsi/dsi_drm.h +++ b/msm/dsi/dsi_drm.h @@ -172,4 +172,12 @@ int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector, void dsi_conn_set_submode_blob_info(struct drm_connector *conn, void *info, void *display, struct drm_display_mode *drm_mode); +/** + * dsi_conn_get_qsync_min_fps() - get qsync min fps for given fps + * @display: Handle to display. + * @conn_state: Pointer to drm_connector_state structure + * + * Return: Qsync min fps rate or -ve error code. + */ +int dsi_conn_get_qsync_min_fps(void *dsi_display, struct drm_connector_state *conn_state); #endif /* _DSI_DRM_H_ */ diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 1a77dcf6ef..b0e7470994 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -904,6 +904,13 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, rc); goto error; } + + rc = utils->read_u32(utils->data, "qcom,qsync-mode-min-refresh-rate", &mode->qsync_min_fps); + if (rc) { + DSI_DEBUG("qsync min fps not defined in timing node\n"); + rc = 0; + } + DSI_DEBUG("panel vert active:%d front_portch:%d back_porch:%d pulse_width:%d\n", mode->v_active, mode->v_front_porch, mode->v_back_porch, mode->v_sync_width); @@ -1301,6 +1308,12 @@ static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel, struct dsi_parser_utils *utils = &panel->utils; const char *name = panel->name; + qsync_caps->qsync_support = utils->read_bool(utils->data, "qcom,qsync-enable"); + if (!qsync_caps->qsync_support) { + DSI_DEBUG("qsync feature not enabled\n"); + goto error; + } + /** * "mdss-dsi-qsync-min-refresh-rate" is defined in cmd mode and * video mode when there is only one qsync min fps present. @@ -1373,8 +1386,10 @@ static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel, qsync_support: /* 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_caps.qsync_min_fps = 0; + !(panel->dfps_caps.type == DSI_DFPS_IMMEDIATE_VFP)) { + qsync_caps->qsync_support = false; + qsync_caps->qsync_min_fps = 0; + } error: if (rc < 0) { diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index 72e66f490f..391db67a78 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -89,7 +89,7 @@ struct dsi_dfps_capabilities { }; struct dsi_qsync_capabilities { - /* qsync disabled if qsync_min_fps = 0 */ + bool qsync_support; u32 qsync_min_fps; u32 *qsync_min_fps_list; int qsync_min_fps_list_len; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index ae8f4c1121..08c4b6ac52 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -747,6 +747,7 @@ struct msm_dyn_clk_list { * @allowed_mode_switches: bit mask to indicate supported mode switch. * @disable_rsc_solver: Dynamically disable RSC solver for the timing mode due to lower bitclk rate. * @dyn_clk_list: List of dynamic clock rates for RFI. + * @qsync_min_fps: qsync min fps rate */ struct msm_mode_info { uint32_t frame_rate; @@ -765,6 +766,7 @@ struct msm_mode_info { u32 allowed_mode_switches; bool disable_rsc_solver; struct msm_dyn_clk_list dyn_clk_list; + u32 qsync_min_fps; }; /** diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 75d1a3084f..04efc7ae89 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -2769,6 +2769,7 @@ static int sde_connector_populate_mode_info(struct drm_connector *conn, sde_kms_info_add_keystr(info, "topology", topo_name); } + sde_kms_info_add_keyint(info, "qsync_min_fps", mode_info.qsync_min_fps); sde_kms_info_add_keyint(info, "has_cwb_crop", sde_kms->catalog->has_cwb_crop); sde_kms_info_add_keyint(info, "has_dedicated_cwb_support", sde_kms->catalog->has_dedicated_cwb_support); @@ -2986,7 +2987,8 @@ static int _sde_connector_install_properties(struct drm_device *dev, CONNECTOR_PROP_AUTOREFRESH); if (connector_type == DRM_MODE_CONNECTOR_DSI) { - if (sde_kms->catalog->has_qsync && display_info->qsync_min_fps) { + if (sde_kms->catalog->has_qsync && dsi_display && dsi_display->panel && + dsi_display->panel->qsync_caps.qsync_support) { msm_property_install_enum(&c_conn->property_info, "qsync_mode", 0, 0, e_qsync_mode, ARRAY_SIZE(e_qsync_mode), 0, diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 7594fd0584..fd22ce399b 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -400,10 +400,10 @@ struct sde_connector_ops { /** * get_qsync_min_fps - Get qsync min fps from qsync-min-fps-list * @display: Pointer to private display structure - * @mode_fps: Fps value in dfps list + * @conn_state: Pointer to drm_connector_state structure * Returns: Qsync min fps value on success */ - int (*get_qsync_min_fps)(void *display, u32 mode_fps); + int (*get_qsync_min_fps)(void *display, struct drm_connector_state *conn_state); /** * get_avr_step_req - Get the required avr_step for given fps rate diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 1fe64d66d7..0f0efe6706 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1028,10 +1028,9 @@ static int _sde_encoder_atomic_check_reserve(struct drm_encoder *drm_enc, return ret; } -static void _sde_encoder_get_qsync_fps_callback( - struct drm_encoder *drm_enc, u32 *qsync_fps, u32 vrr_fps) +static void _sde_encoder_get_qsync_fps_callback(struct drm_encoder *drm_enc, + u32 *qsync_fps, struct drm_connector_state *conn_state) { - struct msm_display_info *disp_info; struct sde_encoder_virt *sde_enc; int rc = 0; struct sde_connector *sde_conn; @@ -1046,25 +1045,17 @@ static void _sde_encoder_get_qsync_fps_callback( } sde_enc = to_sde_encoder_virt(drm_enc); - disp_info = &sde_enc->disp_info; - *qsync_fps = disp_info->qsync_min_fps; - if (!disp_info->has_qsync_min_fps_list) { - return; - } else if (!sde_enc->cur_master || !(disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE)) { + if (!sde_enc->cur_master) { SDE_ERROR("invalid qsync settings %d\n", !sde_enc->cur_master); return; } - /* - * If "dsi-supported-qsync-min-fps-list" is defined, get - * the qsync min fps corresponding to the fps in dfps list - */ sde_conn = to_sde_connector(sde_enc->cur_master->connector); if (sde_conn->ops.get_qsync_min_fps) - rc = sde_conn->ops.get_qsync_min_fps(sde_conn->display, vrr_fps); + rc = sde_conn->ops.get_qsync_min_fps(sde_conn->display, conn_state); - if (rc <= 0) { + if (rc < 0) { SDE_ERROR("invalid qsync min fps %d\n", rc); return; } @@ -1101,7 +1092,8 @@ static int _sde_encoder_avr_step_check(struct sde_connector *sde_conn, if (!step) return 0; - _sde_encoder_get_qsync_fps_callback(sde_conn_state->base.best_encoder, &min_fps, nom_fps); + _sde_encoder_get_qsync_fps_callback(sde_conn_state->base.best_encoder, &min_fps, + &sde_conn_state->base); if (!min_fps || !nom_fps || step % nom_fps || step % min_fps || step < nom_fps || (vtotal * nom_fps) % step) { SDE_ERROR("invalid avr_step rate! nom:%u min:%u step:%u vtotal:%u\n", nom_fps, diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 291fe0254a..0064b58fac 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -82,7 +82,7 @@ struct sde_encoder_virt_ops { void (*handle_frame_done)(struct drm_encoder *parent, struct sde_encoder_phys *phys, u32 event); void (*get_qsync_fps)(struct drm_encoder *parent, - u32 *qsync_fps, u32 vrr_fps); + u32 *qsync_fps, struct drm_connector_state *conn_state); }; /** diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index e37e4030f4..d8223fbd9c 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -896,7 +896,7 @@ static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc) if (phys_enc->parent_ops.get_qsync_fps) phys_enc->parent_ops.get_qsync_fps( - phys_enc->parent, &qsync_min_fps, 0); + phys_enc->parent, &qsync_min_fps, conn->state); if (!qsync_min_fps || !default_fps || !yres) { SDE_ERROR_CMDENC(cmd_enc, diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index 38b9c1a447..93267bfee6 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -397,7 +397,7 @@ static void sde_encoder_phys_vid_setup_timing_engine( bool is_split_link = false; if (!phys_enc || !phys_enc->sde_kms || !phys_enc->hw_ctl || - !phys_enc->hw_intf) { + !phys_enc->hw_intf || !phys_enc->connector) { SDE_ERROR("invalid encoder %d\n", !phys_enc); return; } @@ -470,8 +470,7 @@ static void sde_encoder_phys_vid_setup_timing_engine( exit: if (phys_enc->parent_ops.get_qsync_fps) phys_enc->parent_ops.get_qsync_fps( - phys_enc->parent, &qsync_min_fps, - drm_mode_vrefresh(&phys_enc->cached_mode)); + phys_enc->parent, &qsync_min_fps, phys_enc->connector->state); /* only panels which support qsync will have a non-zero min fps */ if (qsync_min_fps) { diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 1ff25f18e6..366135eb57 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1768,7 +1768,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .install_properties = NULL, .set_allowed_mode_switch = dsi_conn_set_allowed_mode_switch, .set_dyn_bit_clk = dsi_conn_set_dyn_bit_clk, - .get_qsync_min_fps = dsi_display_get_qsync_min_fps, + .get_qsync_min_fps = dsi_conn_get_qsync_min_fps, .get_avr_step_req = dsi_display_get_avr_step_req_fps, .prepare_commit = dsi_conn_prepare_commit, .set_submode_info = dsi_conn_set_submode_blob_info,