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 c0eb0521cc..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); @@ -6728,6 +6727,7 @@ 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) { @@ -6735,17 +6735,24 @@ int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_ return -EINVAL; } - /* for dynamic DSI use specified clock rate otherwise restore clock rate */ - if (display->dyn_bit_clk > 0) - clk_rate_hz = display->dyn_bit_clk; - else if (display->cached_clk_rate > 0) - clk_rate_hz = display->cached_clk_rate; + 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; - DSI_DEBUG("dyn_bit_clk:%u, cached_clk_rate:%u, clk_rate_hz:%u\n", - display->dyn_bit_clk, display->cached_clk_rate, 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; } @@ -8412,6 +8419,9 @@ int dsi_display_update_dyn_bit_clk(struct dsi_display *display, } 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); @@ -8440,6 +8450,8 @@ int dsi_display_update_dyn_bit_clk(struct dsi_display *display, 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); diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 4f971c3ccd..dea8474830 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -579,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; @@ -697,11 +704,6 @@ int dsi_conn_set_info_blob(struct drm_connector *connector, sde_kms_info_add_keystr(info, "dyn bitclk support", panel->dyn_clk_caps.dyn_clk_support ? "true" : "false"); - if (panel->dyn_clk_caps.dyn_clk_support) - sde_kms_info_add_list(info, "dyn_bitclk_list", - panel->dyn_clk_caps.bit_clk_list, - panel->dyn_clk_caps.bit_clk_list_len); - switch (panel->phy_props.rotation) { case DSI_PANEL_ROTATE_NONE: sde_kms_info_add_keystr(info, "panel orientation", "none"); @@ -1297,12 +1299,8 @@ void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector, int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector, uint64_t value) { - int i; - bool is_valid = false; struct sde_connector *c_conn = NULL; - struct sde_connector_state *c_state; struct dsi_display *display; - struct dsi_dyn_clk_caps *dyn_clk_caps; if (!connector) { DSI_ERR("invalid connector\n"); @@ -1310,25 +1308,12 @@ int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector, uint64_t value) } c_conn = to_sde_connector(connector); - c_state = to_sde_connector_state(connector->state); - display = (struct dsi_display *) c_conn->display; - dyn_clk_caps = &display->panel->dyn_clk_caps; - - for (i = 0; i < dyn_clk_caps->bit_clk_list_len; i++) { - if (dyn_clk_caps->bit_clk_list[i] == value) { - is_valid = true; - break; - } - } - - if (!is_valid) { - DSI_ERR("invalid dynamic bit clock rate selection %llu\n", value); - return -EINVAL; - } 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_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 4f35471309..09accfe2db 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -703,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; @@ -719,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/sde/sde_connector.c b/msm/sde/sde_connector.c index b87d6c37ff..e2b728c7a1 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -2623,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) { @@ -2761,11 +2767,9 @@ static int _sde_connector_install_properties(struct drm_device *dev, struct msm_display_info *display_info) { struct dsi_display *dsi_display; - int rc, i; + int rc; struct drm_connector *connector; u64 panel_id = ~0x0; - struct dsi_dyn_clk_caps *dyn_clk_caps; - u32 max_bit_clk; msm_property_install_blob(&c_conn->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_SDE_INFO); @@ -2800,17 +2804,10 @@ static int _sde_connector_install_properties(struct drm_device *dev, } if (dsi_display && dsi_display->panel && - dsi_display->panel->dyn_clk_caps.dyn_clk_support) { - - dyn_clk_caps = &dsi_display->panel->dyn_clk_caps; - max_bit_clk = dyn_clk_caps->bit_clk_list[0]; - for (i = 1; i < dyn_clk_caps->bit_clk_list_len; i++) - max_bit_clk = max(dyn_clk_caps->bit_clk_list[i], max_bit_clk); - + dsi_display->panel->dyn_clk_caps.dyn_clk_support) msm_property_install_range(&c_conn->property_info, "dyn_bit_clk", - 0x0, 0, max_bit_clk, max_bit_clk, - CONNECTOR_PROP_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,