diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 3428c78cd7..8370cd1f73 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -613,6 +613,10 @@ struct dsi_host_config { * @panel_prefill_lines: Panel prefill lines for RSC * @mdp_transfer_time_us: Specifies the mdp transfer time for command mode * panels in microseconds. + * @mdp_transfer_time_us_min: Specifies the minimum possible mdp transfer time + * for command mode panels in microseconds. + * @mdp_transfer_time_us_max: Specifies the maximum possible mdp transfer time + * for command mode panels in microseconds. * @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels. * @qsync_min_fps: Qsync min fps value for the mode * @clk_rate_hz: DSI bit clock per lane in hz. @@ -640,6 +644,8 @@ struct dsi_display_mode_priv_info { u32 panel_jitter_denom; u32 panel_prefill_lines; u32 mdp_transfer_time_us; + u32 mdp_transfer_time_us_min; + u32 mdp_transfer_time_us_max; u32 dsi_transfer_time_us; u32 qsync_min_fps; u64 clk_rate_hz; diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index e67639a529..f1cc08b537 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -7311,6 +7311,46 @@ int dsi_display_get_avr_step_req_fps(void *display_dsi, u32 mode_fps) return step; } +int dsi_display_update_transfer_time(void *display, u32 transfer_time) +{ + struct dsi_display *disp = (struct dsi_display *)display; + int rc = 0, i = 0; + u32 transfer_time_min, transfer_time_max; + struct dsi_display_ctrl *ctrl; + + if (!disp->panel || !disp->panel->cur_mode || !disp->panel->cur_mode->priv_info) + return -EINVAL; + + transfer_time_min = disp->panel->cur_mode->priv_info->mdp_transfer_time_us_min; + transfer_time_max = disp->panel->cur_mode->priv_info->mdp_transfer_time_us_max; + + if (!transfer_time_min || !transfer_time_max) + return 0; + + if (transfer_time < transfer_time_min || transfer_time > transfer_time_max) { + DSI_ERR("invalid transfer time %u, min: %u, max: %u\n", + transfer_time, transfer_time_min, transfer_time_max); + return -EINVAL; + } + + disp->panel->cur_mode->priv_info->mdp_transfer_time_us = transfer_time; + disp->panel->cur_mode->priv_info->dsi_transfer_time_us = transfer_time; + + display_for_each_ctrl(i, disp) { + ctrl = &disp->ctrl[i]; + rc = dsi_ctrl_update_host_config(ctrl->ctrl, &disp->config, + disp->panel->cur_mode, 0x0, + disp->dsi_clk_handle); + if (rc) { + DSI_ERR("[%s] failed to update ctrl config, rc=%d\n", disp->name, rc); + return rc; + } + } + atomic_set(&disp->clkrate_change_pending, 1); + + return 0; +} + static bool dsi_display_match_timings(const struct dsi_display_mode *mode1, struct dsi_display_mode *mode2, unsigned int match_flags) { diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index 5a642ab44c..5bdca42943 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -831,4 +831,13 @@ int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_ bool dsi_display_mode_match(const struct dsi_display_mode *mode1, struct dsi_display_mode *mode2, unsigned int match_flags); +/** + * dsi_display_update_transfer_time() - update DSI transfer time and clocks + * @display: handle to display + * @transfer_time: transfer time value to be updated + * + * Return: error code + */ +int dsi_display_update_transfer_time(void *display, u32 transfer_time); + #endif /* _DSI_DISPLAY_H_ */ diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 0216d31a0d..7a8ca00bb2 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -634,8 +634,9 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, mode_info->jitter_denom = dsi_mode->priv_info->panel_jitter_denom; mode_info->dfps_maxfps = dsi_drm_get_dfps_maxfps(display); mode_info->panel_mode_caps = dsi_mode->panel_mode_caps; - mode_info->mdp_transfer_time_us = - dsi_mode->priv_info->mdp_transfer_time_us; + mode_info->mdp_transfer_time_us = dsi_mode->priv_info->mdp_transfer_time_us; + mode_info->mdp_transfer_time_us_min = dsi_mode->priv_info->mdp_transfer_time_us_min; + mode_info->mdp_transfer_time_us_max = dsi_mode->priv_info->mdp_transfer_time_us_max; mode_info->disable_rsc_solver = dsi_mode->priv_info->disable_rsc_solver; mode_info->qsync_min_fps = dsi_mode->timing.qsync_min_fps; mode_info->wd_jitter = dsi_mode->priv_info->wd_jitter; diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 75e5c43708..39eb8ee5d3 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -782,6 +782,7 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, u64 tmp64 = 0; struct dsi_display_mode *display_mode; struct dsi_display_mode_priv_info *priv_info; + u32 usecs_fps = 0; display_mode = container_of(mode, struct dsi_display_mode, timing); @@ -804,11 +805,22 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, rc = utils->read_u32(utils->data, "qcom,mdss-mdp-transfer-time-us", &mode->mdp_transfer_time_us); - if (!rc) - display_mode->priv_info->mdp_transfer_time_us = - mode->mdp_transfer_time_us; - else - display_mode->priv_info->mdp_transfer_time_us = 0; + if (rc) + mode->mdp_transfer_time_us = 0; + + rc = utils->read_u32(utils->data, "qcom,mdss-mdp-transfer-time-us-min", + &priv_info->mdp_transfer_time_us_min); + if (rc) + priv_info->mdp_transfer_time_us_min = 0; + else if (!rc && mode->mdp_transfer_time_us < priv_info->mdp_transfer_time_us_min) + mode->mdp_transfer_time_us = priv_info->mdp_transfer_time_us_min; + + rc = utils->read_u32(utils->data, "qcom,mdss-mdp-transfer-time-us-max", + &priv_info->mdp_transfer_time_us_max); + if (rc) + priv_info->mdp_transfer_time_us_max = 0; + else if (!rc && mode->mdp_transfer_time_us > priv_info->mdp_transfer_time_us_max) + mode->mdp_transfer_time_us = priv_info->mdp_transfer_time_us_max; priv_info->disable_rsc_solver = utils->read_bool(utils->data, "qcom,disable-rsc-solver"); @@ -821,6 +833,11 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, goto error; } + usecs_fps = DIV_ROUND_UP((1 * 1000 * 1000), mode->refresh_rate); + if (mode->mdp_transfer_time_us > usecs_fps) + mode->mdp_transfer_time_us = 0; + priv_info->mdp_transfer_time_us = mode->mdp_transfer_time_us; + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-width", &mode->h_active); if (rc) { diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 1ca8b7a451..a5d1d17a33 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -223,6 +223,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_DIMMING_CTRL, CONNECTOR_PROP_DIMMING_MIN_BL, CONNECTOR_PROP_EARLY_FENCE_LINE, + CONNECTOR_PROP_DYN_TRANSFER_TIME, /* enum/bitmask properties */ CONNECTOR_PROP_TOPOLOGY_NAME, @@ -790,6 +791,10 @@ struct msm_display_wd_jitter_config { * @panel_mode_caps panel mode capabilities * @mdp_transfer_time_us Specifies the mdp transfer time for command mode * panels in microseconds. + * @mdp_transfer_time_us_min Specifies the minimum possible mdp transfer time + * for command mode panels in microseconds. + * @mdp_transfer_time_us_max Specifies the maximum possible mdp transfer time + * for command mode panels in microseconds. * @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. @@ -810,6 +815,8 @@ struct msm_mode_info { bool wide_bus_en; u32 panel_mode_caps; u32 mdp_transfer_time_us; + u32 mdp_transfer_time_us_min; + u32 mdp_transfer_time_us_max; u32 allowed_mode_switches; bool disable_rsc_solver; struct msm_dyn_clk_list dyn_clk_list; diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 2336742bf7..896735fe52 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1686,6 +1686,20 @@ end: return rc; } +static int _sde_connector_set_prop_dyn_transfer_time(struct sde_connector *c_conn, uint64_t val) +{ + int rc = 0; + + if (!c_conn->ops.update_transfer_time) + return rc; + + rc = c_conn->ops.update_transfer_time(c_conn->display, val); + if (rc) + SDE_ERROR_CONN(c_conn, "updating transfer time failed, val: %u, rc %d\n", val, rc); + + return rc; +} + static int sde_connector_atomic_set_property(struct drm_connector *connector, struct drm_connector_state *state, struct drm_property *property, @@ -1776,6 +1790,9 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, if (rc) SDE_ERROR_CONN(c_conn, "dynamic bit clock set failed, rc: %d", rc); + break; + case CONNECTOR_PROP_DYN_TRANSFER_TIME: + _sde_connector_set_prop_dyn_transfer_time(c_conn, val); break; default: break; @@ -2879,6 +2896,13 @@ static int sde_connector_populate_mode_info(struct drm_connector *conn, sde_kms_info_add_keyint(info, "mdp_transfer_time_us", mode_info.mdp_transfer_time_us); + if (mode_info.mdp_transfer_time_us_min && mode_info.mdp_transfer_time_us_max) { + sde_kms_info_add_keyint(info, "mdp_transfer_time_us_min", + mode_info.mdp_transfer_time_us_min); + sde_kms_info_add_keyint(info, "mdp_transfer_time_us_max", + mode_info.mdp_transfer_time_us_max); + } + sde_kms_info_add_keyint(info, "allowed_mode_switch", mode_info.allowed_mode_switches); @@ -3044,6 +3068,8 @@ static int _sde_connector_install_properties(struct drm_device *dev, msm_property_install_range(&c_conn->property_info, "dyn_bit_clk", 0x0, 0, ~0, 0, CONNECTOR_PROP_DYN_BIT_CLK); + msm_property_install_range(&c_conn->property_info, "dyn_transfer_time", + 0x0, 0, 1000000, 0, CONNECTOR_PROP_DYN_TRANSFER_TIME); mutex_lock(&c_conn->base.dev->mode_config.mutex); sde_connector_fill_modes(&c_conn->base, diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 2355a4e8a2..42b29dd3bc 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -431,6 +431,13 @@ struct sde_connector_ops { */ int (*get_num_lm_from_mode)(void *display, const struct drm_display_mode *mode); + /* + * update_transfer_time - Update transfer time + * @display: Pointer to private display structure + * @transfer_time: new transfer time to be updated + */ + int (*update_transfer_time)(void *display, u32 transfer_time); + }; /** diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 2e81d6c1dd..1fdba43ad0 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1787,6 +1787,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .prepare_commit = dsi_conn_prepare_commit, .set_submode_info = dsi_conn_set_submode_blob_info, .get_num_lm_from_mode = dsi_conn_get_lm_from_mode, + .update_transfer_time = dsi_display_update_transfer_time, }; static const struct sde_connector_ops wb_ops = { .post_init = sde_wb_connector_post_init, @@ -1807,6 +1808,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .install_properties = NULL, .set_dyn_bit_clk = NULL, .set_allowed_mode_switch = NULL, + .update_transfer_time = NULL, }; static const struct sde_connector_ops dp_ops = { .post_init = dp_connector_post_init, @@ -1829,6 +1831,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .install_properties = dp_connector_install_properties, .set_allowed_mode_switch = NULL, .set_dyn_bit_clk = NULL, + .update_transfer_time = NULL, }; struct msm_display_info info; struct drm_encoder *encoder;