Loading drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +17 −0 Original line number Diff line number Diff line Loading @@ -240,6 +240,23 @@ enum dsi_dfps_type { DSI_DFPS_MAX }; /** * enum dsi_dyn_clk_feature_type - Dynamic clock feature support type * @DSI_DYN_CLK_TYPE_LEGACY: Constant FPS is not supported * @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: Constant FPS supported with * change in hfp * @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: Constant FPS supported with * change in vfp * @DSI_DYN_CLK_TYPE_MAX: */ enum dsi_dyn_clk_feature_type { DSI_DYN_CLK_TYPE_LEGACY = 0, DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP, DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP, DSI_DYN_CLK_TYPE_MAX }; /** * enum dsi_cmd_set_type - DSI command set type * @DSI_CMD_SET_PRE_ON: Panel pre on Loading drivers/gpu/drm/msm/dsi-staging/dsi_display.c +106 −15 Original line number Diff line number Diff line Loading @@ -4286,6 +4286,7 @@ static int dsi_display_dfps_update(struct dsi_display *display, struct dsi_display_ctrl *m_ctrl, *ctrl; struct dsi_display_mode *panel_mode; struct dsi_dfps_capabilities dfps_caps; struct dsi_dyn_clk_caps *dyn_clk_caps; int rc = 0; int i = 0; Loading @@ -4296,8 +4297,9 @@ static int dsi_display_dfps_update(struct dsi_display *display, timing = &dsi_mode->timing; dsi_panel_get_dfps_caps(display->panel, &dfps_caps); if (!dfps_caps.dfps_support) { pr_err("dfps not supported\n"); dyn_clk_caps = &(display->panel->dyn_clk_caps); if (!dfps_caps.dfps_support && !dyn_clk_caps->maintain_const_fps) { pr_err("dfps or constant fps not supported\n"); return -ENOTSUPP; } Loading Loading @@ -4551,7 +4553,34 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, display->name, rc); goto error; } } else if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) { display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; rc = dsi_ctrl_update_host_config(ctrl->ctrl, &display->config, mode->dsi_mode_flags, display->dsi_clk_handle); if (rc) { pr_err("failed to update ctrl config\n"); goto error; } } if (priv_info->phy_timing_len) { display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; rc = dsi_phy_set_timing_params(ctrl->phy, priv_info->phy_timing_val, priv_info->phy_timing_len); if (rc) pr_err("Fail to add timing params\n"); } } if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) return rc; } if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) { if (display->panel->panel_mode == DSI_OP_VIDEO_MODE) { rc = dsi_display_dynamic_clk_switch_vid(display, mode); if (rc) Loading Loading @@ -6115,6 +6144,51 @@ int dsi_display_get_mode_count(struct dsi_display *display, return 0; } static void dsi_display_adjust_mode_timing( struct dsi_dyn_clk_caps *dyn_clk_caps, struct dsi_display_mode *dsi_mode, int lanes, int bpp) { u32 new_htotal, new_vtotal, htotal, vtotal, old_htotal; if (!dyn_clk_caps->maintain_const_fps) return; /* When there is a dynamic clock switch, there is small change * in FPS. To compensate for this difference in FPS, hfp or vfp * is adjusted. It has been assumed that the refined porch values * are supported by the panel. This logic can be enhanced further * in future by taking min/max porches supported by the panel */ switch (dyn_clk_caps->type) { case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: vtotal = DSI_V_TOTAL(&dsi_mode->timing); old_htotal = DSI_H_TOTAL_DSC(&dsi_mode->timing); new_htotal = (dsi_mode->timing.clk_rate_hz * lanes); new_htotal /= (bpp * vtotal * dsi_mode->timing.refresh_rate); if (old_htotal > new_htotal) dsi_mode->timing.h_front_porch -= (old_htotal - new_htotal); else dsi_mode->timing.h_front_porch += (new_htotal - old_htotal); break; case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: htotal = DSI_H_TOTAL_DSC(&dsi_mode->timing); new_vtotal = (dsi_mode->timing.clk_rate_hz * lanes); new_vtotal /= (bpp * htotal * dsi_mode->timing.refresh_rate); dsi_mode->timing.v_front_porch = new_vtotal - dsi_mode->timing.v_back_porch - dsi_mode->timing.v_sync_width - dsi_mode->timing.v_active; break; default: break; } } static void _dsi_display_populate_bit_clks(struct dsi_display *display, int start, int end, u32 *mode_idx) { Loading Loading @@ -6154,6 +6228,7 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, * be based on user or device tree preferrence. */ src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0]; dsi_display_adjust_mode_timing(dyn_clk_caps, src, lanes, bpp); src->pixel_clk_khz = div_u64(src->timing.clk_rate_hz * lanes, bpp); src->pixel_clk_khz /= 1000; Loading @@ -6173,6 +6248,8 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, } memcpy(dst, src, sizeof(struct dsi_display_mode)); dst->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[i]; dsi_display_adjust_mode_timing(dyn_clk_caps, dst, lanes, bpp); dst->pixel_clk_khz = div_u64(dst->timing.clk_rate_hz * lanes, bpp); dst->pixel_clk_khz /= 1000; Loading Loading @@ -6422,13 +6499,28 @@ int dsi_display_find_mode(struct dsi_display *display, return rc; } static inline bool dsi_display_mode_switch_dfps(struct dsi_display_mode *cur, struct dsi_display_mode *adj) { /* * If there is a change in the hfp or vfp of the current and adjoining * mode,then either it is a dfps mode switch or dynamic clk change with * constant fps. */ if ((cur->timing.h_front_porch != adj->timing.h_front_porch) || (cur->timing.v_front_porch != adj->timing.v_front_porch)) return true; else return false; } /** * dsi_display_validate_mode_change() - Validate mode change case. * @display: DSI display handle. * @cur_mode: Current mode. * @adj_mode: Mode to be set. * MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there * is change in fps but vactive and hactive are same. * is change in hfp or vfp but vactive and hactive are same. * DSI_MODE_FLAG_DYN_CLK flag is set if there * is change in clk but vactive and hactive are same. * Return: error code. Loading @@ -6452,15 +6544,15 @@ int dsi_display_validate_mode_change(struct dsi_display *display, } mutex_lock(&display->display_lock); dyn_clk_caps = &(display->panel->dyn_clk_caps); if ((cur_mode->timing.v_active == adj_mode->timing.v_active) && (cur_mode->timing.h_active == adj_mode->timing.h_active)) { /* dfps change use case */ if (cur_mode->timing.refresh_rate != adj_mode->timing.refresh_rate) { /* dfps and dynamic clock with const fps use case */ if (dsi_display_mode_switch_dfps(cur_mode, adj_mode)) { dsi_panel_get_dfps_caps(display->panel, &dfps_caps); if (dfps_caps.dfps_support) { pr_debug("Mode switch is seamless variable refresh\n"); if (dfps_caps.dfps_support || dyn_clk_caps->maintain_const_fps) { pr_debug("mode switch is variable refresh\n"); adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; SDE_EVT32(cur_mode->timing.refresh_rate, adj_mode->timing.refresh_rate, Loading @@ -6468,15 +6560,14 @@ int dsi_display_validate_mode_change(struct dsi_display *display, adj_mode->timing.h_front_porch); } } /* dynamic clk change use case */ if (cur_mode->pixel_clk_khz != adj_mode->pixel_clk_khz) { dyn_clk_caps = &(display->panel->dyn_clk_caps); if (dyn_clk_caps->dyn_clk_support) { pr_debug("dynamic clk change detected\n"); if (adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) { pr_err("dfps and dyn clk not supported in same commit\n"); if ((adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) && (!dyn_clk_caps->maintain_const_fps)) { pr_err("dfps and dyn clk concurrent\n"); rc = -ENOTSUPP; goto error; } Loading drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +20 −0 Original line number Diff line number Diff line Loading @@ -1338,6 +1338,7 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel) 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 = NULL; supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable"); Loading Loading @@ -1377,6 +1378,25 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel) dyn_clk_caps->dyn_clk_support = true; type = utils->get_property(utils->data, "qcom,dsi-dyn-clk-type", NULL); if (!type) { dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY; dyn_clk_caps->maintain_const_fps = false; return 0; } if (!strcmp(type, "constant-fps-adjust-hfp")) { dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP; dyn_clk_caps->maintain_const_fps = true; } else if (!strcmp(type, "constant-fps-adjust-vfp")) { dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP; dyn_clk_caps->maintain_const_fps = true; } else { dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY; dyn_clk_caps->maintain_const_fps = false; } pr_debug("Dynamic clock type is %d\n", dyn_clk_caps->type); return 0; } Loading drivers/gpu/drm/msm/dsi-staging/dsi_panel.h +2 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,8 @@ struct dsi_dyn_clk_caps { u32 *bit_clk_list; u32 bit_clk_list_len; bool skip_phy_timing_update; enum dsi_dyn_clk_feature_type type; bool maintain_const_fps; }; struct dsi_pinctrl_info { Loading Loading
drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +17 −0 Original line number Diff line number Diff line Loading @@ -240,6 +240,23 @@ enum dsi_dfps_type { DSI_DFPS_MAX }; /** * enum dsi_dyn_clk_feature_type - Dynamic clock feature support type * @DSI_DYN_CLK_TYPE_LEGACY: Constant FPS is not supported * @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: Constant FPS supported with * change in hfp * @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: Constant FPS supported with * change in vfp * @DSI_DYN_CLK_TYPE_MAX: */ enum dsi_dyn_clk_feature_type { DSI_DYN_CLK_TYPE_LEGACY = 0, DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP, DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP, DSI_DYN_CLK_TYPE_MAX }; /** * enum dsi_cmd_set_type - DSI command set type * @DSI_CMD_SET_PRE_ON: Panel pre on Loading
drivers/gpu/drm/msm/dsi-staging/dsi_display.c +106 −15 Original line number Diff line number Diff line Loading @@ -4286,6 +4286,7 @@ static int dsi_display_dfps_update(struct dsi_display *display, struct dsi_display_ctrl *m_ctrl, *ctrl; struct dsi_display_mode *panel_mode; struct dsi_dfps_capabilities dfps_caps; struct dsi_dyn_clk_caps *dyn_clk_caps; int rc = 0; int i = 0; Loading @@ -4296,8 +4297,9 @@ static int dsi_display_dfps_update(struct dsi_display *display, timing = &dsi_mode->timing; dsi_panel_get_dfps_caps(display->panel, &dfps_caps); if (!dfps_caps.dfps_support) { pr_err("dfps not supported\n"); dyn_clk_caps = &(display->panel->dyn_clk_caps); if (!dfps_caps.dfps_support && !dyn_clk_caps->maintain_const_fps) { pr_err("dfps or constant fps not supported\n"); return -ENOTSUPP; } Loading Loading @@ -4551,7 +4553,34 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, display->name, rc); goto error; } } else if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) { display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; rc = dsi_ctrl_update_host_config(ctrl->ctrl, &display->config, mode->dsi_mode_flags, display->dsi_clk_handle); if (rc) { pr_err("failed to update ctrl config\n"); goto error; } } if (priv_info->phy_timing_len) { display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; rc = dsi_phy_set_timing_params(ctrl->phy, priv_info->phy_timing_val, priv_info->phy_timing_len); if (rc) pr_err("Fail to add timing params\n"); } } if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) return rc; } if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) { if (display->panel->panel_mode == DSI_OP_VIDEO_MODE) { rc = dsi_display_dynamic_clk_switch_vid(display, mode); if (rc) Loading Loading @@ -6115,6 +6144,51 @@ int dsi_display_get_mode_count(struct dsi_display *display, return 0; } static void dsi_display_adjust_mode_timing( struct dsi_dyn_clk_caps *dyn_clk_caps, struct dsi_display_mode *dsi_mode, int lanes, int bpp) { u32 new_htotal, new_vtotal, htotal, vtotal, old_htotal; if (!dyn_clk_caps->maintain_const_fps) return; /* When there is a dynamic clock switch, there is small change * in FPS. To compensate for this difference in FPS, hfp or vfp * is adjusted. It has been assumed that the refined porch values * are supported by the panel. This logic can be enhanced further * in future by taking min/max porches supported by the panel */ switch (dyn_clk_caps->type) { case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: vtotal = DSI_V_TOTAL(&dsi_mode->timing); old_htotal = DSI_H_TOTAL_DSC(&dsi_mode->timing); new_htotal = (dsi_mode->timing.clk_rate_hz * lanes); new_htotal /= (bpp * vtotal * dsi_mode->timing.refresh_rate); if (old_htotal > new_htotal) dsi_mode->timing.h_front_porch -= (old_htotal - new_htotal); else dsi_mode->timing.h_front_porch += (new_htotal - old_htotal); break; case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: htotal = DSI_H_TOTAL_DSC(&dsi_mode->timing); new_vtotal = (dsi_mode->timing.clk_rate_hz * lanes); new_vtotal /= (bpp * htotal * dsi_mode->timing.refresh_rate); dsi_mode->timing.v_front_porch = new_vtotal - dsi_mode->timing.v_back_porch - dsi_mode->timing.v_sync_width - dsi_mode->timing.v_active; break; default: break; } } static void _dsi_display_populate_bit_clks(struct dsi_display *display, int start, int end, u32 *mode_idx) { Loading Loading @@ -6154,6 +6228,7 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, * be based on user or device tree preferrence. */ src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0]; dsi_display_adjust_mode_timing(dyn_clk_caps, src, lanes, bpp); src->pixel_clk_khz = div_u64(src->timing.clk_rate_hz * lanes, bpp); src->pixel_clk_khz /= 1000; Loading @@ -6173,6 +6248,8 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display, } memcpy(dst, src, sizeof(struct dsi_display_mode)); dst->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[i]; dsi_display_adjust_mode_timing(dyn_clk_caps, dst, lanes, bpp); dst->pixel_clk_khz = div_u64(dst->timing.clk_rate_hz * lanes, bpp); dst->pixel_clk_khz /= 1000; Loading Loading @@ -6422,13 +6499,28 @@ int dsi_display_find_mode(struct dsi_display *display, return rc; } static inline bool dsi_display_mode_switch_dfps(struct dsi_display_mode *cur, struct dsi_display_mode *adj) { /* * If there is a change in the hfp or vfp of the current and adjoining * mode,then either it is a dfps mode switch or dynamic clk change with * constant fps. */ if ((cur->timing.h_front_porch != adj->timing.h_front_porch) || (cur->timing.v_front_porch != adj->timing.v_front_porch)) return true; else return false; } /** * dsi_display_validate_mode_change() - Validate mode change case. * @display: DSI display handle. * @cur_mode: Current mode. * @adj_mode: Mode to be set. * MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there * is change in fps but vactive and hactive are same. * is change in hfp or vfp but vactive and hactive are same. * DSI_MODE_FLAG_DYN_CLK flag is set if there * is change in clk but vactive and hactive are same. * Return: error code. Loading @@ -6452,15 +6544,15 @@ int dsi_display_validate_mode_change(struct dsi_display *display, } mutex_lock(&display->display_lock); dyn_clk_caps = &(display->panel->dyn_clk_caps); if ((cur_mode->timing.v_active == adj_mode->timing.v_active) && (cur_mode->timing.h_active == adj_mode->timing.h_active)) { /* dfps change use case */ if (cur_mode->timing.refresh_rate != adj_mode->timing.refresh_rate) { /* dfps and dynamic clock with const fps use case */ if (dsi_display_mode_switch_dfps(cur_mode, adj_mode)) { dsi_panel_get_dfps_caps(display->panel, &dfps_caps); if (dfps_caps.dfps_support) { pr_debug("Mode switch is seamless variable refresh\n"); if (dfps_caps.dfps_support || dyn_clk_caps->maintain_const_fps) { pr_debug("mode switch is variable refresh\n"); adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; SDE_EVT32(cur_mode->timing.refresh_rate, adj_mode->timing.refresh_rate, Loading @@ -6468,15 +6560,14 @@ int dsi_display_validate_mode_change(struct dsi_display *display, adj_mode->timing.h_front_porch); } } /* dynamic clk change use case */ if (cur_mode->pixel_clk_khz != adj_mode->pixel_clk_khz) { dyn_clk_caps = &(display->panel->dyn_clk_caps); if (dyn_clk_caps->dyn_clk_support) { pr_debug("dynamic clk change detected\n"); if (adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) { pr_err("dfps and dyn clk not supported in same commit\n"); if ((adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) && (!dyn_clk_caps->maintain_const_fps)) { pr_err("dfps and dyn clk concurrent\n"); rc = -ENOTSUPP; goto error; } Loading
drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +20 −0 Original line number Diff line number Diff line Loading @@ -1338,6 +1338,7 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel) 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 = NULL; supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable"); Loading Loading @@ -1377,6 +1378,25 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel) dyn_clk_caps->dyn_clk_support = true; type = utils->get_property(utils->data, "qcom,dsi-dyn-clk-type", NULL); if (!type) { dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY; dyn_clk_caps->maintain_const_fps = false; return 0; } if (!strcmp(type, "constant-fps-adjust-hfp")) { dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP; dyn_clk_caps->maintain_const_fps = true; } else if (!strcmp(type, "constant-fps-adjust-vfp")) { dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP; dyn_clk_caps->maintain_const_fps = true; } else { dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY; dyn_clk_caps->maintain_const_fps = false; } pr_debug("Dynamic clock type is %d\n", dyn_clk_caps->type); return 0; } Loading
drivers/gpu/drm/msm/dsi-staging/dsi_panel.h +2 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,8 @@ struct dsi_dyn_clk_caps { u32 *bit_clk_list; u32 bit_clk_list_len; bool skip_phy_timing_update; enum dsi_dyn_clk_feature_type type; bool maintain_const_fps; }; struct dsi_pinctrl_info { Loading