From e5fa4590623282f2700919aa7a3fbb40a438ffe3 Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Tue, 2 Feb 2021 19:16:55 -0500 Subject: [PATCH] disp: msm: restrict AVR_STEP based on panel requirement Some panels require a fixed step rate for a particular mode. This change allows DSI panels to specify a single supported step rate for each nominal fps rate which SDE will enforce during atomic check of AVR parameters. Change-Id: I049415449bc88ccd396fced16d4534251eac3a06 Signed-off-by: Steve Cohen --- msm/dsi/dsi_display.c | 34 ++++++++++++++++++++++++++++------ msm/dsi/dsi_display.h | 10 +++++++++- msm/dsi/dsi_drm.c | 24 ++++++++++++++++++++++++ msm/dsi/dsi_panel.c | 37 +++++++++++++++++++++++++++++++++++++ msm/dsi/dsi_panel.h | 6 ++++++ msm/msm_drv.h | 2 ++ msm/sde/sde_connector.h | 8 ++++++++ msm/sde/sde_encoder.c | 21 ++++++++++++++++++++- msm/sde/sde_kms.c | 1 + 9 files changed, 135 insertions(+), 8 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 72c5dec270..299632cefa 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6609,11 +6609,9 @@ int dsi_display_get_info(struct drm_connector *connector, info->height_mm = phy_props.panel_height_mm; info->max_width = 1920; info->max_height = 1080; - info->qsync_min_fps = - display->panel->qsync_caps.qsync_min_fps; - info->has_qsync_min_fps_list = - (display->panel->qsync_caps.qsync_min_fps_list_len > 0) ? - true : false; + info->qsync_min_fps = display->panel->qsync_caps.qsync_min_fps; + info->has_qsync_min_fps_list = (display->panel->qsync_caps.qsync_min_fps_list_len > 0); + info->has_avr_step_req = (display->panel->avr_caps.avr_step_fps_list_len > 0); info->poms_align_vsync = display->panel->poms_align_vsync; switch (display->panel->panel_mode) { @@ -7080,6 +7078,31 @@ int dsi_display_get_qsync_min_fps(void *display_dsi, u32 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; + struct dsi_panel *panel; + u32 i, step = 0; + + if (!display || !display->panel) + return -EINVAL; + + panel = display->panel; + + /* support a single fixed rate, or rate corresponding to dfps list entry */ + if (panel->avr_caps.avr_step_fps_list_len == 1) { + step = panel->avr_caps.avr_step_fps_list[0]; + } else if (panel->avr_caps.avr_step_fps_list_len > 1) { + for (i = 0; i < panel->dfps_caps.dfps_list_len; i++) { + if (panel->dfps_caps.dfps_list[i] == mode_fps) + step = panel->avr_caps.avr_step_fps_list[i]; + } + } + + DSI_DEBUG("mode_fps %u, avr_step fps %u\n", mode_fps, step); + return step; +} + static bool dsi_display_match_timings(const struct dsi_display_mode *mode1, struct dsi_display_mode *mode2) { @@ -7095,7 +7118,6 @@ static bool dsi_display_match_timings(const struct dsi_display_mode *mode1, mode1->timing.refresh_rate == mode2->timing.refresh_rate; } - static bool dsi_display_mode_match(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 d49304d11c..e5322f1074 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -419,10 +419,18 @@ int dsi_display_get_default_lms(void *dsi_display, u32 *num_lm); * @display: Handle to display. * @mode_fps: Fps value of current mode * - * Return: error code. + * 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. + * @mode_fps: Fps value of current mode + * + * Return: AVR step rate or -ve error code. + */ +int dsi_display_get_avr_step_req_fps(void *dsi_display, u32 mode_fps); /** * dsi_display_find_mode() - retrieve cached DSI mode given relevant params diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 6f473e5496..0ef393a41b 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -626,6 +626,28 @@ static const struct drm_bridge_funcs dsi_bridge_ops = { .mode_set = dsi_bridge_mode_set, }; +int dsi_conn_set_avr_step_info(struct dsi_panel *panel, void *info) +{ + u32 i; + int idx = 0; + size_t buff_sz = PAGE_SIZE; + char *buff; + + buff = kzalloc(buff_sz, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + for (i = 0; i < panel->avr_caps.avr_step_fps_list_len && (idx < (buff_sz - 1)); i++) + idx += scnprintf(&buff[idx], buff_sz - idx, "%u@%u ", + panel->avr_caps.avr_step_fps_list[i], + panel->dfps_caps.dfps_list[i]); + + sde_kms_info_add_keystr(info, "avr step requirement", buff); + kfree(buff); + + return 0; +} + int dsi_conn_set_info_blob(struct drm_connector *connector, void *info, void *display, struct msm_mode_info *mode_info) { @@ -674,6 +696,8 @@ int dsi_conn_set_info_blob(struct drm_connector *connector, switch (panel->panel_mode) { case DSI_OP_VIDEO_MODE: sde_kms_info_add_keystr(info, "panel mode", "video"); + if (panel->avr_caps.avr_step_fps_list_len) + dsi_conn_set_avr_step_info(panel, info); break; case DSI_OP_CMD_MODE: sde_kms_info_add_keystr(info, "panel mode", "command"); diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 73739cdf45..1b492d6c62 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1239,6 +1239,38 @@ error: return rc; } +static int dsi_panel_parse_avr_caps(struct dsi_panel *panel, + struct device_node *of_node) +{ + struct dsi_avr_capabilities *avr_caps = &panel->avr_caps; + struct dsi_parser_utils *utils = &panel->utils; + int val, rc = 0; + + val = utils->count_u32_elems(utils->data, "qcom,dsi-qsync-avr-step-list"); + if (val <= 0) { + DSI_DEBUG("[%s] optional avr step list not defined, val:%d\n", panel->name, val); + return rc; + } else if (val > 1 && val != panel->dfps_caps.dfps_list_len) { + DSI_ERR("[%s] avr step list size %d not same as dfps list %d\n", + val, panel->dfps_caps.dfps_list_len); + return -EINVAL; + } + + avr_caps->avr_step_fps_list = kcalloc(val, sizeof(u32), GFP_KERNEL); + if (!avr_caps->avr_step_fps_list) + return -ENOMEM; + + rc = utils->read_u32_array(utils->data, "qcom,dsi-qsync-avr-step-list", + avr_caps->avr_step_fps_list, val); + if (rc) { + kfree(avr_caps->avr_step_fps_list); + return rc; + } + + avr_caps->avr_step_fps_list_len = val; + return rc; +} + static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel, struct device_node *of_node) { @@ -3509,6 +3541,10 @@ struct dsi_panel *dsi_panel_get(struct device *parent, if (rc) DSI_DEBUG("failed to parse qsync features, rc=%d\n", rc); + rc = dsi_panel_parse_avr_caps(panel, of_node); + if (rc) + DSI_ERR("failed to parse AVR features, rc=%d\n", rc); + rc = dsi_panel_parse_dyn_clk_caps(panel); if (rc) DSI_ERR("failed to parse dynamic clk config, rc=%d\n", rc); @@ -3594,6 +3630,7 @@ void dsi_panel_put(struct dsi_panel *panel) /* free resources allocated for ESD check */ dsi_panel_esd_config_deinit(&panel->esd_config); + kfree(panel->avr_caps.avr_step_fps_list); kfree(panel); } diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index a863271fdc..4a88b4fa0e 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -95,6 +95,11 @@ struct dsi_qsync_capabilities { int qsync_min_fps_list_len; }; +struct dsi_avr_capabilities { + u32 *avr_step_fps_list; + u32 avr_step_fps_list_len; +}; + struct dsi_dyn_clk_caps { bool dyn_clk_support; enum dsi_dyn_clk_feature_type type; @@ -247,6 +252,7 @@ struct dsi_panel { bool panel_initialized; bool te_using_watchdog_timer; struct dsi_qsync_capabilities qsync_caps; + struct dsi_avr_capabilities avr_caps; char dce_pps_cmd[DSI_CMD_PPS_SIZE]; enum dsi_dms_mode dms_mode; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index f957ae6618..951ec607b5 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -767,6 +767,7 @@ struct msm_resource_caps_info { * @roi_caps: Region of interest capability info * @qsync_min_fps Minimum fps supported by Qsync feature * @has_qsync_min_fps_list True if dsi-supported-qsync-min-fps-list exits + * @has_avr_step_req Panel has defined requirement for AVR steps * @te_source vsync source pin information * @dsc_count: max dsc hw blocks used by display (only available * for dsi display) @@ -796,6 +797,7 @@ struct msm_display_info { uint32_t qsync_min_fps; bool has_qsync_min_fps_list; + bool has_avr_step_req; uint32_t te_source; diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index b4c29da041..3557cc1cf2 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -389,6 +389,14 @@ struct sde_connector_ops { * Returns: Qsync min fps value on success */ int (*get_qsync_min_fps)(void *display, u32 mode_fps); + + /** + * get_avr_step_req - Get the required avr_step for given fps rate + * @display: Pointer to private display structure + * @mode_fps: Fps value in dfps list + * Returns: AVR step fps value on success + */ + int (*get_avr_step_req)(void *display, u32 mode_fps); }; /** diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 0064ba2229..1f07e1460e 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1042,9 +1042,28 @@ static void _sde_encoder_get_qsync_fps_callback( static int _sde_encoder_avr_step_check(struct sde_connector *sde_conn, struct sde_connector_state *sde_conn_state, u32 step) { + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(sde_conn_state->base.best_encoder); u32 nom_fps = drm_mode_vrefresh(sde_conn_state->msm_mode.base); - u32 min_fps; + u32 min_fps, req_fps = 0; u32 vtotal = sde_conn_state->msm_mode.base->vtotal; + bool has_panel_req = sde_enc->disp_info.has_avr_step_req; + u32 qsync_mode = sde_connector_get_property(&sde_conn_state->base, + CONNECTOR_PROP_QSYNC_MODE); + + if (has_panel_req) { + if (!sde_conn->ops.get_avr_step_req) { + SDE_ERROR("unable to retrieve required step rate\n"); + return -EINVAL; + } + + req_fps = sde_conn->ops.get_avr_step_req(sde_conn->display, nom_fps); + /* when qsync is enabled, the step fps *must* be set to the panel requirement */ + if (qsync_mode && req_fps != step) { + SDE_ERROR("invalid avr_step %u, panel requires %u at nominal %u fps\n", + step, req_fps, nom_fps); + return -EINVAL; + } + } if (!step) return 0; diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 071b29e26f..dfc032cfa8 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1748,6 +1748,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .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_avr_step_req = dsi_display_get_avr_step_req_fps, .prepare_commit = dsi_conn_prepare_commit, }; static const struct sde_connector_ops wb_ops = {