From e5fcf7f2636912329918c12aed81610c7157673b Mon Sep 17 00:00:00 2001 From: Nilaan Gunabalachandran Date: Thu, 26 Aug 2021 10:15:46 -0700 Subject: [PATCH] disp: msm: add capability to dynamically update the transfer time This change adds a connector OP, that will be used to update frame transfer time dynamically at the request from user space. It also adds parsing for new device tree entries that set the minimum and maximum trasnfer times on a mode basis. These min and max transfer times are also published to userspace through the connector mode info capabilities blob. Change-Id: I12aedf96a51ff7feb2c5b3b1353d3c4ec8dcb068 Signed-off-by: Satya Rama Aditya Pinapala Signed-off-by: Nilaan Gunabalachandran --- msm/dsi/dsi_defs.h | 6 ++++++ msm/dsi/dsi_display.c | 40 ++++++++++++++++++++++++++++++++++++++++ msm/dsi/dsi_display.h | 9 +++++++++ msm/dsi/dsi_drm.c | 5 +++-- msm/dsi/dsi_panel.c | 27 ++++++++++++++++++++++----- msm/msm_drv.h | 7 +++++++ msm/sde/sde_connector.c | 26 ++++++++++++++++++++++++++ msm/sde/sde_connector.h | 7 +++++++ msm/sde/sde_kms.c | 3 +++ 9 files changed, 123 insertions(+), 7 deletions(-) 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;