Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e9ae4852 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "disp: msm: dsi: Add support for clk switch with constant FPS"

parents 0234c398 a0e89e85
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -240,6 +240,22 @@ 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
+106 −11
Original line number Diff line number Diff line
@@ -4231,6 +4231,7 @@ static int dsi_display_dfps_update(struct dsi_display *display,
	struct dsi_dfps_capabilities dfps_caps;
	int rc = 0;
	int i = 0;
	struct dsi_dyn_clk_caps *dyn_clk_caps;

	if (!display || !dsi_mode || !display->panel) {
		DSI_ERR("Invalid params\n");
@@ -4239,8 +4240,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) {
		DSI_ERR("dfps not supported\n");
	dyn_clk_caps = &(display->panel->dyn_clk_caps);
	if (!dfps_caps.dfps_support && !dyn_clk_caps->maintain_const_fps) {
		DSI_ERR("dfps or constant fps not supported\n");
		return -ENOTSUPP;
	}

@@ -4517,7 +4519,32 @@ 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, mode->dsi_mode_flags,
					display->dsi_clk_handle);
			if (rc) {
				DSI_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,
						commit_phy_timing);
				if (rc)
					DSI_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)
@@ -5902,6 +5929,51 @@ int dsi_display_get_mode_count(struct dsi_display *display,
	return 0;
}

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)
{
@@ -5941,6 +6013,9 @@ 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;
@@ -5960,6 +6035,10 @@ 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;
@@ -6254,13 +6333,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.
@@ -6284,14 +6378,14 @@ 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) {
			if (dfps_caps.dfps_support ||
				dyn_clk_caps->maintain_const_fps) {
				DSI_DEBUG("Mode switch is seamless variable refresh\n");
				adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
				SDE_EVT32(cur_mode->timing.refresh_rate,
@@ -6303,10 +6397,11 @@ int dsi_display_validate_mode_change(struct dsi_display *display,

		/* 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) {
				DSI_DEBUG("dynamic clk change detected\n");
				if (adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) {
				if ((adj_mode->dsi_mode_flags &
					DSI_MODE_FLAG_VRR) &&
					(!dyn_clk_caps->maintain_const_fps)) {
					DSI_ERR("dfps and dyn clk not supported in same commit\n");
					rc = -ENOTSUPP;
					goto error;
+19 −0
Original line number Diff line number Diff line
@@ -1316,6 +1316,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;

	supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable");

@@ -1348,6 +1349,24 @@ 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;
	}
	DSI_DEBUG("Dynamic clock type is [%s]\n", type);
	return 0;
}

+2 −0
Original line number Diff line number Diff line
@@ -81,6 +81,8 @@ 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;
};

struct dsi_pinctrl_info {