disp: msm: add qsync refresh rate support per mode

This change adds support for qsync min refresh rate per
timing mode and populates qsync min refresh rate based
on the current fps when qsync is enabled.

Change-Id: I191d1d72e95dd065c8c0b56a6100104c00c6d8f6
Signed-off-by: Yashwanth <yvulapu@codeaurora.org>
This commit is contained in:
Yashwanth
2021-05-07 13:31:52 +05:30
parent 8a2ddb713f
commit 64b732f335
15 changed files with 89 additions and 61 deletions

View File

@@ -413,6 +413,7 @@ struct dsi_panel_cmd_set {
* @vdc: VDC compression configuration. * @vdc: VDC compression configuration.
* @pclk_scale: pclk scale factor, target bpp to source bpp * @pclk_scale: pclk scale factor, target bpp to source bpp
* @roi_caps: Panel ROI capabilities. * @roi_caps: Panel ROI capabilities.
* @qsync_min_fps: Qsync min fps rate
*/ */
struct dsi_mode_info { struct dsi_mode_info {
u32 h_active; u32 h_active;
@@ -439,6 +440,7 @@ struct dsi_mode_info {
struct msm_display_vdc_info *vdc; struct msm_display_vdc_info *vdc;
struct msm_ratio pclk_scale; struct msm_ratio pclk_scale;
struct msm_roi_caps roi_caps; struct msm_roi_caps roi_caps;
u32 qsync_min_fps;
}; };
/** /**

View File

@@ -6838,6 +6838,7 @@ int dsi_display_get_modes(struct dsi_display *display,
struct dsi_dyn_clk_caps *dyn_clk_caps; struct dsi_dyn_clk_caps *dyn_clk_caps;
int i, start, end, rc = -EINVAL; int i, start, end, rc = -EINVAL;
int dsc_modes = 0, nondsc_modes = 0; int dsc_modes = 0, nondsc_modes = 0;
struct dsi_qsync_capabilities *qsync_caps;
if (!display || !out_modes) { if (!display || !out_modes) {
DSI_ERR("Invalid params\n"); DSI_ERR("Invalid params\n");
@@ -6868,6 +6869,7 @@ int dsi_display_get_modes(struct dsi_display *display,
goto error; goto error;
} }
qsync_caps = &(display->panel->qsync_caps);
dyn_clk_caps = &(display->panel->dyn_clk_caps); dyn_clk_caps = &(display->panel->dyn_clk_caps);
timing_mode_count = display->panel->num_timing_nodes; 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)); memcpy(sub_mode, &display_mode, sizeof(display_mode));
array_idx++; 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) if (!dfps_caps.dfps_support || !support_video_mode)
continue; continue;
@@ -6970,6 +6980,10 @@ int dsi_display_get_modes(struct dsi_display *display,
curr_refresh_rate = sub_mode->timing.refresh_rate; curr_refresh_rate = sub_mode->timing.refresh_rate;
sub_mode->timing.refresh_rate = dfps_caps.dfps_list[i]; 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, dsi_display_get_dfps_timing(display, sub_mode,
curr_refresh_rate); curr_refresh_rate);
sub_mode->panel_mode_caps = DSI_OP_VIDEO_MODE; 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; 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) int dsi_display_get_avr_step_req_fps(void *display_dsi, u32 mode_fps)
{ {
struct dsi_display *display = (struct dsi_display *)display_dsi; 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 i;
int rc = 0; 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); mutex_lock(&display->display_lock);
display_for_each_ctrl(i, display) { display_for_each_ctrl(i, display) {

View File

@@ -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); 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 * dsi_display_get_avr_step_req_fps() - get avr step rate for given fps
* @display: Handle to display. * @display: Handle to display.

View File

@@ -614,6 +614,7 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
mode_info->mdp_transfer_time_us = mode_info->mdp_transfer_time_us =
dsi_mode->priv_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->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, memcpy(&mode_info->topology, &dsi_mode->priv_info->topology,
sizeof(struct msm_display_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; 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, int dsi_conn_set_info_blob(struct drm_connector *connector,
void *info, void *display, struct msm_mode_info *mode_info) 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", sde_kms_info_add_keystr(info, "qsync support",
panel->qsync_caps.qsync_min_fps ? panel->qsync_caps.qsync_support ?
"true" : "false"); "true" : "false");
if (panel->qsync_caps.qsync_min_fps) if (panel->qsync_caps.qsync_min_fps)
sde_kms_info_add_keyint(info, "qsync_fps", sde_kms_info_add_keyint(info, "qsync_fps",

View File

@@ -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 dsi_conn_set_submode_blob_info(struct drm_connector *conn,
void *info, void *display, struct drm_display_mode *drm_mode); 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_ */ #endif /* _DSI_DRM_H_ */

View File

@@ -904,6 +904,13 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode,
rc); rc);
goto error; 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", 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_active, mode->v_front_porch, mode->v_back_porch,
mode->v_sync_width); 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; struct dsi_parser_utils *utils = &panel->utils;
const char *name = panel->name; 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 * "mdss-dsi-qsync-min-refresh-rate" is defined in cmd mode and
* video mode when there is only one qsync min fps present. * 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: qsync_support:
/* allow qsync support only if DFPS is with VFP approach */ /* allow qsync support only if DFPS is with VFP approach */
if ((panel->dfps_caps.dfps_support) && if ((panel->dfps_caps.dfps_support) &&
!(panel->dfps_caps.type == DSI_DFPS_IMMEDIATE_VFP)) !(panel->dfps_caps.type == DSI_DFPS_IMMEDIATE_VFP)) {
panel->qsync_caps.qsync_min_fps = 0; qsync_caps->qsync_support = false;
qsync_caps->qsync_min_fps = 0;
}
error: error:
if (rc < 0) { if (rc < 0) {

View File

@@ -89,7 +89,7 @@ struct dsi_dfps_capabilities {
}; };
struct dsi_qsync_capabilities { struct dsi_qsync_capabilities {
/* qsync disabled if qsync_min_fps = 0 */ bool qsync_support;
u32 qsync_min_fps; u32 qsync_min_fps;
u32 *qsync_min_fps_list; u32 *qsync_min_fps_list;
int qsync_min_fps_list_len; int qsync_min_fps_list_len;

View File

@@ -747,6 +747,7 @@ struct msm_dyn_clk_list {
* @allowed_mode_switches: bit mask to indicate supported mode switch. * @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. * @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. * @dyn_clk_list: List of dynamic clock rates for RFI.
* @qsync_min_fps: qsync min fps rate
*/ */
struct msm_mode_info { struct msm_mode_info {
uint32_t frame_rate; uint32_t frame_rate;
@@ -765,6 +766,7 @@ struct msm_mode_info {
u32 allowed_mode_switches; u32 allowed_mode_switches;
bool disable_rsc_solver; bool disable_rsc_solver;
struct msm_dyn_clk_list dyn_clk_list; struct msm_dyn_clk_list dyn_clk_list;
u32 qsync_min_fps;
}; };
/** /**

View File

@@ -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_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_cwb_crop", sde_kms->catalog->has_cwb_crop);
sde_kms_info_add_keyint(info, "has_dedicated_cwb_support", sde_kms_info_add_keyint(info, "has_dedicated_cwb_support",
sde_kms->catalog->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); CONNECTOR_PROP_AUTOREFRESH);
if (connector_type == DRM_MODE_CONNECTOR_DSI) { 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, msm_property_install_enum(&c_conn->property_info,
"qsync_mode", 0, 0, e_qsync_mode, "qsync_mode", 0, 0, e_qsync_mode,
ARRAY_SIZE(e_qsync_mode), 0, ARRAY_SIZE(e_qsync_mode), 0,

View File

@@ -400,10 +400,10 @@ struct sde_connector_ops {
/** /**
* get_qsync_min_fps - Get qsync min fps from qsync-min-fps-list * get_qsync_min_fps - Get qsync min fps from qsync-min-fps-list
* @display: Pointer to private display structure * @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 * 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 * get_avr_step_req - Get the required avr_step for given fps rate

View File

@@ -1028,10 +1028,9 @@ static int _sde_encoder_atomic_check_reserve(struct drm_encoder *drm_enc,
return ret; return ret;
} }
static void _sde_encoder_get_qsync_fps_callback( static void _sde_encoder_get_qsync_fps_callback(struct drm_encoder *drm_enc,
struct drm_encoder *drm_enc, u32 *qsync_fps, u32 vrr_fps) u32 *qsync_fps, struct drm_connector_state *conn_state)
{ {
struct msm_display_info *disp_info;
struct sde_encoder_virt *sde_enc; struct sde_encoder_virt *sde_enc;
int rc = 0; int rc = 0;
struct sde_connector *sde_conn; 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); 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) { if (!sde_enc->cur_master) {
return;
} else if (!sde_enc->cur_master || !(disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE)) {
SDE_ERROR("invalid qsync settings %d\n", !sde_enc->cur_master); SDE_ERROR("invalid qsync settings %d\n", !sde_enc->cur_master);
return; 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); sde_conn = to_sde_connector(sde_enc->cur_master->connector);
if (sde_conn->ops.get_qsync_min_fps) 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); SDE_ERROR("invalid qsync min fps %d\n", rc);
return; return;
} }
@@ -1101,7 +1092,8 @@ static int _sde_encoder_avr_step_check(struct sde_connector *sde_conn,
if (!step) if (!step)
return 0; 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 || if (!min_fps || !nom_fps || step % nom_fps || step % min_fps || step < nom_fps ||
(vtotal * nom_fps) % step) { (vtotal * nom_fps) % step) {
SDE_ERROR("invalid avr_step rate! nom:%u min:%u step:%u vtotal:%u\n", nom_fps, SDE_ERROR("invalid avr_step rate! nom:%u min:%u step:%u vtotal:%u\n", nom_fps,

View File

@@ -82,7 +82,7 @@ struct sde_encoder_virt_ops {
void (*handle_frame_done)(struct drm_encoder *parent, void (*handle_frame_done)(struct drm_encoder *parent,
struct sde_encoder_phys *phys, u32 event); struct sde_encoder_phys *phys, u32 event);
void (*get_qsync_fps)(struct drm_encoder *parent, void (*get_qsync_fps)(struct drm_encoder *parent,
u32 *qsync_fps, u32 vrr_fps); u32 *qsync_fps, struct drm_connector_state *conn_state);
}; };
/** /**

View File

@@ -896,7 +896,7 @@ static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc)
if (phys_enc->parent_ops.get_qsync_fps) if (phys_enc->parent_ops.get_qsync_fps)
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) { if (!qsync_min_fps || !default_fps || !yres) {
SDE_ERROR_CMDENC(cmd_enc, SDE_ERROR_CMDENC(cmd_enc,

View File

@@ -397,7 +397,7 @@ static void sde_encoder_phys_vid_setup_timing_engine(
bool is_split_link = false; bool is_split_link = false;
if (!phys_enc || !phys_enc->sde_kms || !phys_enc->hw_ctl || 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); SDE_ERROR("invalid encoder %d\n", !phys_enc);
return; return;
} }
@@ -470,8 +470,7 @@ static void sde_encoder_phys_vid_setup_timing_engine(
exit: exit:
if (phys_enc->parent_ops.get_qsync_fps) if (phys_enc->parent_ops.get_qsync_fps)
phys_enc->parent_ops.get_qsync_fps( phys_enc->parent_ops.get_qsync_fps(
phys_enc->parent, &qsync_min_fps, phys_enc->parent, &qsync_min_fps, phys_enc->connector->state);
drm_mode_vrefresh(&phys_enc->cached_mode));
/* only panels which support qsync will have a non-zero min fps */ /* only panels which support qsync will have a non-zero min fps */
if (qsync_min_fps) { if (qsync_min_fps) {

View File

@@ -1768,7 +1768,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
.install_properties = NULL, .install_properties = NULL,
.set_allowed_mode_switch = dsi_conn_set_allowed_mode_switch, .set_allowed_mode_switch = dsi_conn_set_allowed_mode_switch,
.set_dyn_bit_clk = dsi_conn_set_dyn_bit_clk, .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, .get_avr_step_req = dsi_display_get_avr_step_req_fps,
.prepare_commit = dsi_conn_prepare_commit, .prepare_commit = dsi_conn_prepare_commit,
.set_submode_info = dsi_conn_set_submode_blob_info, .set_submode_info = dsi_conn_set_submode_blob_info,