diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index fec47e87ee..9248e8cf4f 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -587,6 +587,16 @@ struct dsi_host_config { struct dsi_lane_map lane_map; }; +/** + * struct dyn_clk_list - list of dynamic clock rates. + * @rates: list of supported clock rates + * @count: number of supported clock rates + */ +struct dyn_clk_list { + u32 *rates; + u32 count; +}; + /** * struct dsi_display_mode_priv_info - private mode info that will be attached * with each drm mode @@ -600,6 +610,7 @@ struct dsi_host_config { * @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels. * @clk_rate_hz: DSI bit clock per lane in hz. * @min_dsi_clk_hz: Min dsi clk per lane to transfer frame in vsync time. + * @bit_clk_list: List of dynamic bit clock rates supported. * @topology: Topology selected for the panel * @dsc: DSC compression info * @vdc: VDC compression info @@ -623,6 +634,7 @@ struct dsi_display_mode_priv_info { u32 dsi_transfer_time_us; u64 clk_rate_hz; u64 min_dsi_clk_hz; + struct dyn_clk_list bit_clk_list; struct msm_display_topology topology; struct msm_display_dsc_info dsc; diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index fc09f65af7..9f15d3253a 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6678,12 +6678,11 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, src = &display->modes[i]; if (!src) return; - /* - * TODO: currently setting the first bit rate in - * the list as preferred rate. But ideally should - * be based on user or device tree preferrence. - */ - src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0]; + + if (!src->priv_info->bit_clk_list.count) + continue; + + src->timing.clk_rate_hz = src->priv_info->bit_clk_list.rates[0]; dsi_display_adjust_mode_timing(display, src, lanes, bpp); @@ -6726,6 +6725,37 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, } } +int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_mode *mode) +{ + int i; + u32 clk_rate_hz = 0; + + if (!display || !mode || !mode->priv_info) { + DSI_ERR("invalid arguments\n"); + return -EINVAL; + } + + clk_rate_hz = display->cached_clk_rate; + + if (mode->priv_info->bit_clk_list.count) { + /* use first entry as the default bit clk rate */ + clk_rate_hz = mode->priv_info->bit_clk_list.rates[0]; + + for (i = 0; i < mode->priv_info->bit_clk_list.count; i++) { + if (display->dyn_bit_clk == mode->priv_info->bit_clk_list.rates[i]) + clk_rate_hz = display->dyn_bit_clk; + } + } + + mode->timing.clk_rate_hz = clk_rate_hz; + mode->priv_info->clk_rate_hz = clk_rate_hz; + + SDE_EVT32(clk_rate_hz, display->cached_clk_rate, display->dyn_bit_clk); + DSI_DEBUG("clk_rate_hz:%u, cached_clk_rate:%u, dyn_bit_clk:%u\n", + clk_rate_hz, display->cached_clk_rate, display->dyn_bit_clk); + return 0; +} + void dsi_display_put_mode(struct dsi_display *display, struct dsi_display_mode *mode) { @@ -7237,9 +7267,11 @@ int dsi_display_set_mode(struct dsi_display *display, } } - /*For dynamic DSI setting, use specified clock rate */ - if (display->cached_clk_rate > 0) - adj_mode.priv_info->clk_rate_hz = display->cached_clk_rate; + rc = dsi_display_restore_bit_clk(display, &adj_mode); + if (rc) { + DSI_ERR("[%s] bit clk rate cannot be restored\n", display->name); + goto error; + } rc = dsi_display_validate_mode_set(display, &adj_mode, flags); if (rc) { @@ -7253,11 +7285,13 @@ int dsi_display_set_mode(struct dsi_display *display, goto error; } - DSI_INFO("mdp_transfer_time=%d, hactive=%d, vactive=%d, fps=%d\n", + DSI_INFO("mdp_transfer_time=%d, hactive=%d, vactive=%d, fps=%d, clk_rate=%llu\n", adj_mode.priv_info->mdp_transfer_time_us, - timing.h_active, timing.v_active, timing.refresh_rate); + timing.h_active, timing.v_active, timing.refresh_rate, + adj_mode.priv_info->clk_rate_hz); SDE_EVT32(adj_mode.priv_info->mdp_transfer_time_us, - timing.h_active, timing.v_active, timing.refresh_rate); + timing.h_active, timing.v_active, timing.refresh_rate, + adj_mode.priv_info->clk_rate_hz); memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode)); error: @@ -8366,6 +8400,67 @@ int dsi_display_update_pps(char *pps_cmd, void *disp) return 0; } +int dsi_display_update_dyn_bit_clk(struct dsi_display *display, + struct dsi_display_mode *mode) +{ + struct dsi_dyn_clk_caps *dyn_clk_caps; + struct dsi_host_common_cfg *host_cfg; + int bpp, lanes = 0; + + if (!display || !mode) { + DSI_ERR("invalid arguments\n"); + return -EINVAL; + } + + dyn_clk_caps = &(display->panel->dyn_clk_caps); + if (!dyn_clk_caps->dyn_clk_support) { + DSI_DEBUG("dynamic bit clock support not enabled\n"); + return 0; + } else if (!display->dyn_bit_clk_pending) { + DSI_DEBUG("dynamic bit clock rate not updated\n"); + return 0; + } else if (!display->dyn_bit_clk) { + DSI_DEBUG("dynamic bit clock rate cleared\n"); + return 0; + } else if (display->dyn_bit_clk < mode->priv_info->min_dsi_clk_hz) { + DSI_ERR("dynamic bit clock rate %llu smaller than minimum value:%llu\n", + display->dyn_bit_clk, mode->priv_info->min_dsi_clk_hz); + return -EINVAL; + } + + /* update mode clk rate with user value */ + mode->timing.clk_rate_hz = display->dyn_bit_clk; + mode->priv_info->clk_rate_hz = display->dyn_bit_clk; + + host_cfg = &(display->panel->host_config); + bpp = dsi_pixel_format_to_bpp(host_cfg->dst_format); + + if (host_cfg->data_lanes & DSI_DATA_LANE_0) + lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_1) + lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_2) + lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_3) + lanes++; + + dsi_display_adjust_mode_timing(display, mode, lanes, bpp); + + /* adjust pixel clock based on dynamic bit clock */ + mode->pixel_clk_khz = div_u64(mode->timing.clk_rate_hz * lanes, bpp); + do_div(mode->pixel_clk_khz, 1000); + mode->pixel_clk_khz *= display->ctrl_count; + + SDE_EVT32(display->dyn_bit_clk, mode->priv_info->min_dsi_clk_hz, mode->pixel_clk_khz); + DSI_DEBUG("dynamic bit clk:%u, min dsi clk:%llu, lanes:%d, bpp:%d, pck:%d Khz\n", + display->dyn_bit_clk, mode->priv_info->min_dsi_clk_hz, lanes, bpp, + mode->pixel_clk_khz); + + display->dyn_bit_clk_pending = false; + + return 0; +} + int dsi_display_dump_clks_state(struct dsi_display *display) { int rc = 0; diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index cce1500ed4..9f22b2bab7 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -154,6 +154,8 @@ struct dsi_display_ext_bridge { * index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array. * @cmd_master_idx: The master controller for sending DSI commands to panel. * @video_master_idx: The master controller for enabling video engine. + * @dyn_bit_clk: The DSI bit clock rate dynamically set by user mode client. + * @dyn_bit_clk_pending: Flag indicating the pending DSI dynamic bit clock rate change. * @cached_clk_rate: The cached DSI clock rate set dynamically by sysfs. * @clkrate_change_pending: Flag indicating the pending DSI clock re-enabling. * @clock_info: Clock sourcing for DSI display. @@ -225,7 +227,9 @@ struct dsi_display { u32 video_master_idx; /* dynamic DSI clock info*/ - u32 cached_clk_rate; + u32 dyn_bit_clk; + bool dyn_bit_clk_pending; + u32 cached_clk_rate; atomic_t clkrate_change_pending; struct dsi_display_clk_info clock_info; @@ -776,4 +780,21 @@ int dsi_display_get_panel_vfp(void *display, */ int dsi_display_dump_clks_state(struct dsi_display *display); +/** + * dsi_display_update_dyn_bit_clk() - update mode timing to compensate for dynamic bit clock + * @display: Handle to display + * @mode: Mode to be updated + * Return: Zero on Success + */ +int dsi_display_update_dyn_bit_clk(struct dsi_display *display, struct dsi_display_mode *mode); + +/** + * dsi_display_restore_bit_clk() - restore mode bit clock rate value from dynamic bit clock + * @display: Handle to display + * @mode: Mode to be updated + * Return: Zero on Success + */ +int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_mode *mode); + + #endif /* _DSI_DISPLAY_H_ */ diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 21f94e1275..e390d2508e 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -342,7 +342,9 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode) { - struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + int rc = 0; + struct dsi_bridge *c_bridge = NULL; + struct dsi_display *display; struct drm_connector *conn; struct sde_connector_state *conn_state; @@ -351,6 +353,18 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge, return; } + c_bridge = to_dsi_bridge(bridge); + if (!c_bridge) { + DSI_ERR("invalid dsi bridge\n"); + return; + } + + display = c_bridge->display; + if (!display || !display->drm_conn || !display->drm_conn->state) { + DSI_ERR("invalid display\n"); + return; + } + memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode)); convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode)); conn = sde_encoder_get_connector(bridge->dev, bridge->encoder); @@ -366,9 +380,11 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge, msm_parse_mode_priv_info(&conn_state->msm_mode, &(c_bridge->dsi_mode)); - /* restore bit_clk_rate also for dynamic clk use cases */ - c_bridge->dsi_mode.timing.clk_rate_hz = - dsi_drm_find_bit_clk_rate(c_bridge->display, adjusted_mode); + rc = dsi_display_restore_bit_clk(display, &c_bridge->dsi_mode); + if (rc) { + DSI_ERR("[%s] bit clk rate cannot be restored\n", display->name); + return; + } DSI_DEBUG("clk_rate: %llu\n", c_bridge->dsi_mode.timing.clk_rate_hz); } @@ -436,6 +452,18 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, dsi_mode.timing.dsc_enabled = dsi_mode.priv_info->dsc_enabled; dsi_mode.timing.dsc = &dsi_mode.priv_info->dsc; + rc = dsi_display_restore_bit_clk(display, &dsi_mode); + if (rc) { + DSI_ERR("[%s] bit clk rate cannot be restored\n", display->name); + return false; + } + + rc = dsi_display_update_dyn_bit_clk(display, &dsi_mode); + if (rc) { + DSI_ERR("[%s] failed to update bit clock\n", display->name); + return false; + } + rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode, DSI_VALIDATE_FLAG_ALLOW_ADJUST); if (rc) { @@ -517,33 +545,6 @@ u32 dsi_drm_get_dfps_maxfps(void *display) return dfps_maxfps; } -u64 dsi_drm_find_bit_clk_rate(void *display, - const struct drm_display_mode *drm_mode) -{ - int i = 0, count = 0; - struct dsi_display *dsi_display = display; - struct dsi_display_mode *dsi_mode; - u64 bit_clk_rate = 0; - - if (!dsi_display || !drm_mode) - return 0; - - dsi_display_get_mode_count(dsi_display, &count); - - for (i = 0; i < count; i++) { - dsi_mode = &dsi_display->modes[i]; - if ((dsi_mode->timing.v_active == drm_mode->vdisplay) && - (dsi_mode->timing.h_active == drm_mode->hdisplay) && - (dsi_mode->pixel_clk_khz == drm_mode->clock) && - (dsi_mode->timing.refresh_rate == drm_mode_vrefresh(drm_mode))) { - bit_clk_rate = dsi_mode->timing.clk_rate_hz; - break; - } - } - - return bit_clk_rate; -} - int dsi_conn_get_mode_info(struct drm_connector *connector, const struct drm_display_mode *drm_mode, struct msm_mode_info *mode_info, @@ -578,6 +579,13 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, memcpy(&mode_info->topology, &dsi_mode->priv_info->topology, sizeof(struct msm_display_topology)); + if (dsi_mode->priv_info->bit_clk_list.count) { + mode_info->bit_clk_rates = + dsi_mode->priv_info->bit_clk_list.rates; + mode_info->bit_clk_count = + dsi_mode->priv_info->bit_clk_list.count; + } + if (dsi_mode->priv_info->dsc_enabled) { mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC; mode_info->topology.comp_type = MSM_DISPLAY_COMPRESSION_DSC; @@ -1296,3 +1304,25 @@ void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector, mode_idx++; } } + +int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector, uint64_t value) +{ + struct sde_connector *c_conn = NULL; + struct dsi_display *display; + + if (!connector) { + DSI_ERR("invalid connector\n"); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + display = (struct dsi_display *) c_conn->display; + + display->dyn_bit_clk = value; + display->dyn_bit_clk_pending = true; + + SDE_EVT32(display->dyn_bit_clk); + DSI_DEBUG("update dynamic bit clock rate to %llu\n", display->dyn_bit_clk); + + return 0; +} diff --git a/msm/dsi/dsi_drm.h b/msm/dsi/dsi_drm.h index 188281f8c1..e198412d9b 100644 --- a/msm/dsi/dsi_drm.h +++ b/msm/dsi/dsi_drm.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef _DSI_DRM_H_ @@ -134,9 +134,6 @@ int dsi_conn_post_kickoff(struct drm_connector *connector, void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, struct drm_display_mode *drm_mode); -u64 dsi_drm_find_bit_clk_rate(void *display, - const struct drm_display_mode *drm_mode); - /** * dsi_conn_prepare_commit - program pre commit time features * @display: Pointer to private display structure @@ -154,4 +151,13 @@ int dsi_conn_prepare_commit(void *display, void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector, void *display); +/** + * dsi_conn_set_dyn_bit_clk - set target dynamic clock rate + * @connector: Pointer to drm connector structure + * @value: Target dynamic clock rate + * Returns: Zero on success + */ +int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector, + uint64_t value); + #endif /* _DSI_DRM_H_ */ diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 85d02d8b4e..fa194876a7 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1326,13 +1326,48 @@ error: return rc; } +static int dsi_panel_parse_dyn_clk_list(struct dsi_display_mode *mode, + struct dsi_parser_utils *utils) +{ + int i, rc = 0; + struct dyn_clk_list *bit_clk_list; + + if (!mode || !mode->priv_info) { + DSI_ERR("invalid arguments\n"); + return -EINVAL; + } + + bit_clk_list = &mode->priv_info->bit_clk_list; + + bit_clk_list->count = utils->count_u32_elems(utils->data, "qcom,dsi-dyn-clk-list"); + if (bit_clk_list->count < 1) + return 0; + + bit_clk_list->rates = kcalloc(bit_clk_list->count, sizeof(u32), GFP_KERNEL); + if (!bit_clk_list->rates) { + DSI_ERR("failed to allocate space for bit clock list\n"); + return -ENOMEM; + } + + rc = utils->read_u32_array(utils->data, "qcom,dsi-dyn-clk-list", + bit_clk_list->rates, bit_clk_list->count); + if (rc) { + DSI_ERR("failed to parse supported bit clk list, rc=%d\n", rc); + return -EINVAL; + } + + for (i = 0; i < bit_clk_list->count; i++) + DSI_DEBUG("bit clk rate[%d]:%d\n", i, bit_clk_list->rates[i]); + + return 0; +} + static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel) { int rc = 0; bool supported = false; struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps; struct dsi_parser_utils *utils = &panel->utils; - const char *name = panel->name; const char *type; supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable"); @@ -1342,28 +1377,6 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel) return rc; } - dyn_clk_caps->bit_clk_list_len = utils->count_u32_elems(utils->data, - "qcom,dsi-dyn-clk-list"); - - if (dyn_clk_caps->bit_clk_list_len < 1) { - DSI_ERR("[%s] failed to get supported bit clk list\n", name); - return -EINVAL; - } - - dyn_clk_caps->bit_clk_list = kcalloc(dyn_clk_caps->bit_clk_list_len, - sizeof(u32), GFP_KERNEL); - if (!dyn_clk_caps->bit_clk_list) - return -ENOMEM; - - rc = utils->read_u32_array(utils->data, "qcom,dsi-dyn-clk-list", - dyn_clk_caps->bit_clk_list, - dyn_clk_caps->bit_clk_list_len); - - if (rc) { - DSI_ERR("[%s] failed to parse supported bit clk list\n", name); - return -EINVAL; - } - dyn_clk_caps->dyn_clk_support = true; type = utils->get_property(utils->data, @@ -4032,6 +4045,12 @@ int dsi_panel_get_mode(struct dsi_panel *panel, goto parse_fail; } + if (panel->dyn_clk_caps.dyn_clk_support) { + rc = dsi_panel_parse_dyn_clk_list(mode, utils); + if (rc) + DSI_ERR("failed to parse dynamic clk rates, rc=%d\n", rc); + } + rc = dsi_panel_parse_dsc_params(mode, utils); if (rc) { DSI_ERR("failed to parse dsc params, rc=%d\n", rc); diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index b9707c3f2c..cf3becf268 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -97,8 +97,6 @@ struct dsi_qsync_capabilities { struct dsi_dyn_clk_caps { bool dyn_clk_support; - u32 *bit_clk_list; - u32 bit_clk_list_len; enum dsi_dyn_clk_feature_type type; bool maintain_const_fps; }; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index a4a8b0ee08..09accfe2db 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -211,6 +211,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_BL_SCALE, CONNECTOR_PROP_SV_BL_SCALE, CONNECTOR_PROP_SUPPORTED_COLORSPACES, + CONNECTOR_PROP_DYN_BIT_CLK, /* enum/bitmask properties */ CONNECTOR_PROP_TOPOLOGY_NAME, @@ -702,6 +703,8 @@ struct msm_display_topology { * @mdp_transfer_time_us Specifies the mdp transfer time for command mode * panels in microseconds. * @allowed_mode_switches: bit mask to indicate supported mode switch. + * @bit_clk_rates: list of supported bit clock rates + * @bit_clk_count: number of supported bit clock rates */ struct msm_mode_info { uint32_t frame_rate; @@ -718,6 +721,8 @@ struct msm_mode_info { u32 panel_mode_caps; u32 mdp_transfer_time_us; u32 allowed_mode_switches; + u32 *bit_clk_rates; + u32 bit_clk_count; }; /** diff --git a/msm/msm_kms.h b/msm/msm_kms.h index 00e04a649b..3e081bab30 100644 --- a/msm/msm_kms.h +++ b/msm/msm_kms.h @@ -292,6 +292,9 @@ static inline bool msm_is_private_mode_changed( if (msm_is_mode_seamless_poms(msm_mode)) return true; + if (msm_is_mode_seamless_dyn_clk(msm_mode)) + return true; + return false; } diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index e9ee658733..e2b728c7a1 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1595,6 +1595,15 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, c_conn->expected_panel_mode = MSM_DISPLAY_CMD_MODE; break; + case CONNECTOR_PROP_DYN_BIT_CLK: + if (!c_conn->ops.set_dyn_bit_clk) + break; + + rc = c_conn->ops.set_dyn_bit_clk(connector, val); + if (rc) + SDE_ERROR_CONN(c_conn, "dynamic bit clock set failed, rc: %d", rc); + + break; default: break; } @@ -2614,6 +2623,12 @@ static int sde_connector_populate_mode_info(struct drm_connector *conn, sde_kms_info_add_keyint(info, "bit_clk_rate", mode_info.clk_rate); + if (mode_info.bit_clk_count > 0) + sde_kms_info_add_list(info, "dyn_bitclk_list", + mode_info.bit_clk_rates, + mode_info.bit_clk_count); + + topology_idx = (int)sde_rm_get_topology_name(&sde_kms->rm, mode_info.topology); if (topology_idx < SDE_RM_TOPOLOGY_MAX) { @@ -2788,6 +2803,12 @@ static int _sde_connector_install_properties(struct drm_device *dev, CONNECTOR_PROP_HDR_INFO); } + if (dsi_display && dsi_display->panel && + dsi_display->panel->dyn_clk_caps.dyn_clk_support) + msm_property_install_range(&c_conn->property_info, "dyn_bit_clk", + 0x0, 0, ~0, 0, CONNECTOR_PROP_DYN_BIT_CLK); + + mutex_lock(&c_conn->base.dev->mode_config.mutex); sde_connector_fill_modes(&c_conn->base, dev->mode_config.max_width, diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 0d266a5b43..4a5f5456e5 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -374,6 +374,14 @@ struct sde_connector_ops { void (*set_allowed_mode_switch)(struct drm_connector *connector, void *display); + /** + * set_dyn_bit_clk - set target dynamic clock rate + * @connector: Pointer to drm connector structure + * @value: Target dynamic clock rate + * Returns: Zero on success + */ + int (*set_dyn_bit_clk)(struct drm_connector *connector, uint64_t value); + /** * get_qsync_min_fps - Get qsync min fps from qsync-min-fps-list * @display: Pointer to private display structure @@ -961,6 +969,14 @@ int sde_connector_set_blob_data(struct drm_connector *conn, */ int sde_connector_roi_v1_check_roi(struct drm_connector_state *conn_state); +/** + * sde_connector_set_dyn_bit_clk - set dynamic bit clock + * @conn: Pointer to drm_connector struct + * @value: Property value + * Returns: Zero on success + */ +int sde_connector_set_dyn_bit_clk(struct drm_connector *conn, uint64_t value); + /** * sde_connector_schedule_status_work - manage ESD thread * conn: Pointer to drm_connector struct diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index f8a43caa9d..6d21878ef9 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1736,6 +1736,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .cmd_receive = dsi_display_cmd_receive, .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, .prepare_commit = dsi_conn_prepare_commit, }; @@ -1756,6 +1757,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .get_panel_vfp = NULL, .cmd_receive = NULL, .install_properties = NULL, + .set_dyn_bit_clk = NULL, .set_allowed_mode_switch = NULL, }; static const struct sde_connector_ops dp_ops = { @@ -1778,6 +1780,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .cmd_receive = NULL, .install_properties = dp_connector_install_properties, .set_allowed_mode_switch = NULL, + .set_dyn_bit_clk = NULL, }; struct msm_display_info info; struct drm_encoder *encoder; diff --git a/msm/sde/sde_kms.h b/msm/sde/sde_kms.h index cf34ff3744..1ad19fece4 100644 --- a/msm/sde/sde_kms.h +++ b/msm/sde/sde_kms.h @@ -611,6 +611,16 @@ void sde_kms_info_append_format(struct sde_kms_info *info, */ void sde_kms_info_stop(struct sde_kms_info *info); +/** + * sde_kms_info_add_list - add a space separated list to 'sde_kms_info' + * @info: Pointer to sde_kms_info structure + * @key: Pointer to key string + * @item: Pointer to array of integer values + * @size: Number of integers to parse + */ +void sde_kms_info_add_list(struct sde_kms_info *info, + const char *key, uint32_t *item, size_t size); + /** * sde_kms_rect_intersect - intersect two rectangles * @r1: first rectangle diff --git a/msm/sde/sde_kms_utils.c b/msm/sde/sde_kms_utils.c index 7bb2445e2b..e2b156a961 100644 --- a/msm/sde/sde_kms_utils.c +++ b/msm/sde/sde_kms_utils.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "sde-kms_utils:[%s] " fmt, __func__ @@ -91,6 +91,28 @@ void sde_kms_info_append(struct sde_kms_info *info, } } +void sde_kms_info_add_list(struct sde_kms_info *info, const char *key, uint32_t *value, size_t size) +{ + uint32_t i, len; + + if (!info || !key || !value || !size) + return; + + sde_kms_info_start(info, key); + for (i = 0; i < size; i++) { + len = scnprintf(info->data + info->staged_len, + SDE_KMS_INFO_MAX_SIZE - info->len, "%d ", + value[i]); + + /* check if snprintf truncated the string */ + if ((info->staged_len + len) < SDE_KMS_INFO_MAX_SIZE) { + info->staged_len += len; + info->start = false; + } + } + sde_kms_info_stop(info); +} + void sde_kms_info_append_format(struct sde_kms_info *info, uint32_t pixel_format, uint64_t modifier)