diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 2a0471e738..9e9dc71a75 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -598,16 +598,6 @@ 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 @@ -646,7 +636,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_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 fcbc2ae0b0..2d57419517 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6714,14 +6714,18 @@ void dsi_display_adjust_mode_timing(struct dsi_display *display, default: break; } + + dsi_mode->pixel_clk_khz = div_u64(dsi_mode->timing.clk_rate_hz * lanes, bpp); + do_div(dsi_mode->pixel_clk_khz, 1000); + dsi_mode->pixel_clk_khz *= display->ctrl_count; } static void _dsi_display_populate_bit_clks(struct dsi_display *display, int start, int end) { struct dsi_dyn_clk_caps *dyn_clk_caps; - struct dsi_display_mode *src; + struct dsi_display_mode *src, dst; struct dsi_host_common_cfg *cfg; - int i, bpp, lanes = 0; + int i, j, bpp, lanes = 0; if (!display) return; @@ -6754,9 +6758,33 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, int star dsi_display_adjust_mode_timing(display, src, lanes, bpp); - src->pixel_clk_khz = div_u64(src->timing.clk_rate_hz * lanes, bpp); - src->pixel_clk_khz /= 1000; - src->pixel_clk_khz *= display->ctrl_count; + /* populate mode adjusted values */ + for (j = 0; j < src->priv_info->bit_clk_list.count; j++) { + memcpy(&dst, src, sizeof(struct dsi_display_mode)); + memcpy(&dst.timing, &src->timing, sizeof(struct dsi_mode_info)); + dst.timing.clk_rate_hz = src->priv_info->bit_clk_list.rates[j]; + + dsi_display_adjust_mode_timing(display, &dst, lanes, bpp); + + /* store the list of RFI matching porches */ + switch (dyn_clk_caps->type) { + case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: + src->priv_info->bit_clk_list.front_porches[j] = + dst.timing.h_front_porch; + break; + + case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: + src->priv_info->bit_clk_list.front_porches[j] = + dst.timing.v_front_porch; + break; + + default: + break; + } + + /* store the list of RFI matching pixel clocks */ + src->priv_info->bit_clk_list.pixel_clks_khz[j] = dst.pixel_clk_khz; + } } } @@ -8579,11 +8607,6 @@ int dsi_display_update_dyn_bit_clk(struct dsi_display *display, 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, diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 790a4d3d3d..3005e65226 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -589,12 +589,13 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, struct dsi_display_mode partial_dsi_mode, *dsi_mode = NULL; struct dsi_mode_info *timing; int src_bpp, tar_bpp, rc = 0; + struct dsi_display *dsi_display = (struct dsi_display *) display; if (!drm_mode || !mode_info) return -EINVAL; convert_to_dsi_mode(drm_mode, &partial_dsi_mode); - rc = dsi_display_find_mode(display, &partial_dsi_mode, sub_mode, &dsi_mode); + rc = dsi_display_find_mode(dsi_display, &partial_dsi_mode, NULL, &dsi_mode); if (rc || !dsi_mode->priv_info) return -EINVAL; @@ -607,7 +608,6 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, mode_info->jitter_numer = dsi_mode->priv_info->panel_jitter_numer; mode_info->jitter_denom = dsi_mode->priv_info->panel_jitter_denom; mode_info->dfps_maxfps = dsi_drm_get_dfps_maxfps(display); - mode_info->clk_rate = dsi_mode->timing.clk_rate_hz; mode_info->panel_mode_caps = dsi_mode->panel_mode_caps; mode_info->mdp_transfer_time_us = dsi_mode->priv_info->mdp_transfer_time_us; @@ -617,12 +617,23 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, 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; + struct msm_dyn_clk_list *dyn_clk_list = &mode_info->dyn_clk_list; + + dyn_clk_list->rates = dsi_mode->priv_info->bit_clk_list.rates; + dyn_clk_list->count = dsi_mode->priv_info->bit_clk_list.count; + dyn_clk_list->type = dsi_display->panel->dyn_clk_caps.type; + dyn_clk_list->front_porches = dsi_mode->priv_info->bit_clk_list.front_porches; + dyn_clk_list->pixel_clks_khz = dsi_mode->priv_info->bit_clk_list.pixel_clks_khz; + + rc = dsi_display_restore_bit_clk(dsi_display, dsi_mode); + if (rc) { + DSI_ERR("[%s] bit clk rate cannot be restored\n", dsi_display->name); + return rc; + } } + mode_info->clk_rate = dsi_mode->timing.clk_rate_hz; + 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; @@ -845,6 +856,12 @@ void dsi_conn_set_submode_blob_info(struct drm_connector *conn, struct dsi_display_mode partial_dsi_mode; int count, i; int preferred_submode_idx = -EINVAL; + enum dsi_dyn_clk_feature_type dyn_clk_type; + char *dyn_clk_types[DSI_DYN_CLK_TYPE_MAX] = { + [DSI_DYN_CLK_TYPE_LEGACY] = "none", + [DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP] = "hfp", + [DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP] = "vfp", + }; if (!conn || !display || !drm_mode) { DSI_ERR("Invalid params\n"); @@ -861,35 +878,46 @@ void dsi_conn_set_submode_blob_info(struct drm_connector *conn, u32 panel_mode_caps = 0; const char *topo_name = NULL; - if (dsi_display_mode_match(&partial_dsi_mode, dsi_mode, - DSI_MODE_MATCH_FULL_TIMINGS)) { + if (!dsi_display_mode_match(&partial_dsi_mode, dsi_mode, + DSI_MODE_MATCH_FULL_TIMINGS)) + continue; - sde_kms_info_add_keyint(info, "submode_idx", i); + sde_kms_info_add_keyint(info, "submode_idx", i); - if (dsi_mode->is_preferred) - preferred_submode_idx = i; + if (dsi_mode->is_preferred) + preferred_submode_idx = i; - if (dsi_mode->panel_mode_caps & DSI_OP_CMD_MODE) - panel_mode_caps |= DRM_MODE_FLAG_CMD_MODE_PANEL; - if (dsi_mode->panel_mode_caps & DSI_OP_VIDEO_MODE) - panel_mode_caps |= DRM_MODE_FLAG_VID_MODE_PANEL; + if (dsi_mode->panel_mode_caps & DSI_OP_CMD_MODE) + panel_mode_caps |= DRM_MODE_FLAG_CMD_MODE_PANEL; + if (dsi_mode->panel_mode_caps & DSI_OP_VIDEO_MODE) + panel_mode_caps |= DRM_MODE_FLAG_VID_MODE_PANEL; - sde_kms_info_add_keyint(info, "panel_mode_capabilities", - panel_mode_caps); + sde_kms_info_add_keyint(info, "panel_mode_capabilities", + panel_mode_caps); - sde_kms_info_add_keyint(info, "dsc_mode", - dsi_mode->priv_info->dsc_enabled ? MSM_DISPLAY_DSC_MODE_ENABLED : - MSM_DISPLAY_DSC_MODE_DISABLED); - topo_name = sde_conn_get_topology_name(conn, - dsi_mode->priv_info->topology); - if (topo_name) - sde_kms_info_add_keystr(info, "topology", topo_name); + sde_kms_info_add_keyint(info, "dsc_mode", + dsi_mode->priv_info->dsc_enabled ? MSM_DISPLAY_DSC_MODE_ENABLED : + MSM_DISPLAY_DSC_MODE_DISABLED); + topo_name = sde_conn_get_topology_name(conn, + dsi_mode->priv_info->topology); + if (topo_name) + sde_kms_info_add_keystr(info, "topology", topo_name); - if (dsi_mode->priv_info->bit_clk_list.count > 0) - sde_kms_info_add_list(info, "dyn_bitclk_list", - dsi_mode->priv_info->bit_clk_list.rates, - dsi_mode->priv_info->bit_clk_list.count); - } + if (!dsi_mode->priv_info->bit_clk_list.count) + continue; + + dyn_clk_type = dsi_display->panel->dyn_clk_caps.type; + sde_kms_info_add_list(info, "dyn_bitclk_list", + dsi_mode->priv_info->bit_clk_list.rates, + dsi_mode->priv_info->bit_clk_list.count); + sde_kms_info_add_keystr(info, "dyn_fp_type", + dyn_clk_types[dyn_clk_type]); + sde_kms_info_add_list(info, "dyn_fp_list", + dsi_mode->priv_info->bit_clk_list.front_porches, + dsi_mode->priv_info->bit_clk_list.count); + sde_kms_info_add_list(info, "dyn_pclk_list", + dsi_mode->priv_info->bit_clk_list.pixel_clks_khz, + dsi_mode->priv_info->bit_clk_list.count); } if (preferred_submode_idx >= 0) diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index fe9a0d86d0..1a77dcf6ef 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1388,7 +1388,7 @@ 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; + struct msm_dyn_clk_list *bit_clk_list; if (!mode || !mode->priv_info) { DSI_ERR("invalid arguments\n"); @@ -1398,26 +1398,51 @@ static int dsi_panel_parse_dyn_clk_list(struct dsi_display_mode *mode, 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; + if (bit_clk_list->count < 1 || bit_clk_list->count > 100) { + DSI_ERR("invalid number of bit clock values, must be between 1 and 100\n"); + return -EINVAL; + } 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 = -ENOMEM; + goto error; + } + + bit_clk_list->front_porches = kcalloc(bit_clk_list->count, sizeof(u32), GFP_KERNEL); + if (!bit_clk_list->front_porches) { + DSI_ERR("failed to allocate space for front porch list\n"); + rc = -ENOMEM; + goto error; + } + + bit_clk_list->pixel_clks_khz = kcalloc(bit_clk_list->count, sizeof(u32), GFP_KERNEL); + if (!bit_clk_list->pixel_clks_khz) { + DSI_ERR("failed to allocate space for pclk list\n"); + rc = -ENOMEM; + goto error; } 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; + DSI_ERR("failed to parse supported bit clk list values, rc=%d\n", rc); + goto error; } 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; + +error: + bit_clk_list->count = 0; + kfree(bit_clk_list->rates); + kfree(bit_clk_list->front_porches); + kfree(bit_clk_list->pixel_clks_khz); + + return rc; } static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel) diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 93d835d1d7..ae8f4c1121 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -712,6 +712,22 @@ struct msm_display_topology { enum msm_display_compression_type comp_type; }; +/** + * struct msm_dyn_clk_list - list of dynamic clock rates. + * @count: number of supported clock rates + * @rates: list of supported clock rates + * @type: dynamic clock feature support type + * @front_porches: list of clock rate matching porch compensation values + * @pixel_clks_khz: list of clock rate matching pixel clock values + */ +struct msm_dyn_clk_list { + u32 count; + u32 *rates; + u32 type; + u32 *front_porches; + u32 *pixel_clks_khz; +}; + /** * struct msm_mode_info - defines all msm custom mode info * @frame_rate: frame_rate of the mode @@ -729,9 +745,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 * @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. */ struct msm_mode_info { uint32_t frame_rate; @@ -748,9 +763,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; bool disable_rsc_solver; + struct msm_dyn_clk_list dyn_clk_list; }; /**