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

Commit f9c04f16 authored by Adrian Salido-Moreno's avatar Adrian Salido-Moreno Committed by Gerrit - the friendly Code Review server
Browse files

msm: mdss: dsi: add support for multiple panel timing settings



Some DSI panels support more than one resolution or panel timing.
Add support to parse and configure different panel timing settings
and ability to switch between them dynamically if possible.

CRs-fixed: 873962
Change-Id: I532587eaa763499c9d51909937339093cd74a8cf
Signed-off-by: default avatarChandan Uddaraju <chandanu@codeaurora.org>
Signed-off-by: default avatarAdrian Salido-Moreno <adrianm@codeaurora.org>
[veeras@codeaurora.org: Resolve merge conflicts in mdss-dsi-panel.txt,
 mdss_dsi.c, mdss_dsi_host.c, mdss_dsi_panel.c]
Signed-off-by: default avatarVeera Sundaram Sankaran <veeras@codeaurora.org>
parent a8f8cd1d
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -384,6 +384,8 @@ Optional properties:
						go blank during transition.
					"dynamic-switch-immediate"= Switch on next frame update. Panel will
						not go blank for this transition.
					"dynamic-resolution-switch-immediate"= Switch the panel resolution. Panel will
						not go blank for this transition.
- qcom,mdss-dsi-post-mode-switch-on-command:		Multiple dcs packets used for turning on DSI panel
					after panel has switch modes.
					Refer to "qcom,mdss-dsi-on-command" section for adding commands.
@@ -453,6 +455,20 @@ Optional properites:
- qcom,adjust-timer-wakeup-ms:		An integer value to indicate the timer delay(in ms) to accommodate
					s/w delay while configuring the event timer wakeup logic.

- qcom,mdss-dsi-display-timings:	Parent node that lists the different resolutions that the panel supports.
					Each child represents timings settings for a specific resolution.

Additional properties added to the second level nodes that represent timings properties:
- qcom,mdss-dsi-timing-default:		Property that specifies the current child as the default
					timing configuration that will be used.
- qcom,mdss-dsi-timing-switch-command:	List of commands that need to be sent
					to panel when the resolution/timing switch happens dynamically.
					Refer to "qcom,mdss-dsi-on-command" section for adding commands.
- qcom,mdss-dsi-timing-switch-command-state:	String that specifies the ctrl state for sending resolution switch
					commands.
					"dsi_lp_mode" = DSI low power mode (default)
					"dsi_hs_mode" = DSI high speed mode

Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.

@@ -594,6 +610,31 @@ Example:
		qcom,mdss-dsi-force-clock-lane-hs;
		qcom,compression-mode = "dsc";
		qcom,adjust-timer-wakeup-ms = <1>;
		qcom,mdss-dsi-display-timings {
			wqhd {
				qcom,mdss-dsi-timing-default;
				qcom,mdss-dsi-panel-width = <720>;
				qcom,mdss-dsi-panel-height = <2560>;
				qcom,mdss-dsi-h-front-porch = <20>;
				qcom,mdss-dsi-h-back-porch = <8>;
				qcom,mdss-dsi-h-pulse-width = <8>;
				qcom,mdss-dsi-h-sync-skew = <0>;
				qcom,mdss-dsi-v-back-porch = <4>;
				qcom,mdss-dsi-v-front-porch = <728>;
				qcom,mdss-dsi-v-pulse-width = <4>;
				qcom,mdss-dsi-panel-framerate = <60>;
				qcom,mdss-dsi-panel-timings = [E6 38 26 00 68 6E 2A 3C 2C 03 04 00];
				qcom,mdss-dsi-t-clk-post = <0x02>;
				qcom,mdss-dsi-t-clk-pre = <0x2a>;
				qcom,mdss-dsi-on-command = [05 01 00 00 a0 00 02 11 00
					05 01 00 00 02 00 02 29 00];
				qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
				qcom,mdss-dsi-timing-switch-command = [
					29 00 00 00 00 00 02 B0 04
					29 00 00 00 00 00 02 F1 00];
				qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_mode";
			};
		};
		qcom,panel-supply-entries {
			#address-cells = <1>;
			#size-cells = <0>;
+14 −47
Original line number Diff line number Diff line
@@ -1099,15 +1099,18 @@ int mdss_dsi_switch_mode(struct mdss_panel_data *pdata, int mode)
	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
		panel_data);

	if (pinfo->dms_mode != DYNAMIC_MODE_SWITCH_IMMEDIATE) {
	if ((pinfo->dms_mode != DYNAMIC_MODE_RESOLUTION_SWITCH_IMMEDIATE) &&
			(pinfo->dms_mode != DYNAMIC_MODE_SWITCH_IMMEDIATE)) {
		pr_debug("%s: Dynamic mode switch not enabled.\n", __func__);
		return -EPERM;
	}

	if (mode == MIPI_VIDEO_PANEL) {
		mode = DSI_VIDEO_MODE;
		mode = SWITCH_TO_VIDEO_MODE;
	} else if (mode == MIPI_CMD_PANEL) {
		mode = DSI_CMD_MODE;
		mode = SWITCH_TO_CMD_MODE;
	} else if (mode == SWITCH_RESOLUTION) {
		pr_debug("Resolution switch mode selected\n");
	} else {
		pr_err("Invalid mode selected, mode=%d\n", mode);
		return -EINVAL;
@@ -1353,8 +1356,9 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
				panel_data);
	mipi  = &pdata->panel_info.mipi;

	pr_debug("%s+: ctrl=%p ndx=%d cur_blank_state=%d\n", __func__,
		ctrl_pdata, ctrl_pdata->ndx, pdata->panel_info.blank_state);
	pr_debug("%s+: ctrl=%p ndx=%d cur_blank_state=%d ctrl_state=%x\n",
			__func__, ctrl_pdata, ctrl_pdata->ndx,
			pdata->panel_info.blank_state, ctrl_pdata->ctrl_state);

	if (mdss_dsi_is_ctrl_clk_master(ctrl_pdata))
		sctrl = mdss_dsi_get_ctrl_clk_slave();
@@ -1442,9 +1446,9 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata, int power_state)
		pr_info("%s: switching to %s mode\n", __func__,
			(pdata->panel_info.mipi.mode ? "video" : "command"));
		if (pdata->panel_info.type == MIPI_CMD_PANEL) {
			ctrl_pdata->switch_mode(pdata, DSI_VIDEO_MODE);
			ctrl_pdata->switch_mode(pdata, SWITCH_TO_VIDEO_MODE);
		} else if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
			ctrl_pdata->switch_mode(pdata, DSI_CMD_MODE);
			ctrl_pdata->switch_mode(pdata, SWITCH_TO_CMD_MODE);
			mdss_dsi_set_tear_off(ctrl_pdata);
		}
	}
@@ -1989,46 +1993,6 @@ int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
	return 0;
}

static int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata)
{
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
	int rc = 0;

	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
							panel_data);
	rc = mdss_dsi_clk_div_config(&pdata->panel_info,
			pdata->panel_info.mipi.frame_rate);
	if (rc) {
		pr_err("%s: unable to initialize the clk dividers\n",
								__func__);
		return rc;
	}
	ctrl_pdata->refresh_clk_rate = false;
	ctrl_pdata->pclk_rate = pdata->panel_info.mipi.dsi_pclk_rate;
	ctrl_pdata->byte_clk_rate = pdata->panel_info.clk_rate / 8;
	pr_debug("%s ctrl_pdata->byte_clk_rate=%d ctrl_pdata->pclk_rate=%d\n",
		__func__, ctrl_pdata->byte_clk_rate, ctrl_pdata->pclk_rate);

	rc = mdss_dsi_clk_set_link_rate(ctrl_pdata->dsi_clk_handle,
		MDSS_DSI_LINK_BYTE_CLK, ctrl_pdata->byte_clk_rate,
		MDSS_DSI_CLK_UPDATE_CLK_RATE_AT_ON);
	if (rc) {
		pr_err("%s: dsi_byte_clk - clk_set_rate failed\n",
				__func__);
		return rc;
	}

	rc = mdss_dsi_clk_set_link_rate(ctrl_pdata->dsi_clk_handle,
		MDSS_DSI_LINK_PIX_CLK, ctrl_pdata->pclk_rate,
		MDSS_DSI_CLK_UPDATE_CLK_RATE_AT_ON);
	if (rc) {
		pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n",
			__func__);
		return rc;
	}
	return rc;
}

static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
				  int event, void *arg)
{
@@ -2143,6 +2107,9 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
		if (ctrl_pdata->check_status)
			rc = ctrl_pdata->check_status(ctrl_pdata);
		break;
	case MDSS_EVENT_PANEL_TIMING_SWITCH:
		rc = mdss_dsi_panel_timing_switch(ctrl_pdata, arg);
		break;
	case MDSS_EVENT_FB_REGISTERED:
		mdss_dsi_debugfs_init(ctrl_pdata);
		break;
+16 −0
Original line number Diff line number Diff line
@@ -310,6 +310,18 @@ struct dsi_panel_cmds {
	int link_state;
};

struct dsi_panel_timing {
	struct mdss_panel_timing timing;
	uint32_t phy_timing[12];
	uint32_t phy_timing_8996[40];
	/* DSI_CLKOUT_TIMING_CTRL */
	char t_clk_post;
	char t_clk_pre;
	struct dsi_panel_cmds on_cmds;
	struct dsi_panel_cmds post_panel_on_cmds;
	struct dsi_panel_cmds switch_cmds;
};

struct dsi_kickoff_action {
	struct list_head act_entry;
	void (*action) (void *);
@@ -520,6 +532,7 @@ void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
			    int frame_rate);
int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata);
int mdss_dsi_link_clk_init(struct platform_device *pdev,
		      struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_link_clk_deinit(struct device *dev,
@@ -570,6 +583,9 @@ u32 mdss_dsi_panel_cmd_read(struct mdss_dsi_ctrl_pdata *ctrl, char cmd0,
int mdss_dsi_panel_init(struct device_node *node,
		struct mdss_dsi_ctrl_pdata *ctrl_pdata,
		bool cmd_cfg_cont_splash);
int mdss_dsi_panel_timing_switch(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
			struct mdss_panel_timing *timing);

int mdss_panel_parse_bl_settings(struct device_node *np,
			struct mdss_dsi_ctrl_pdata *ctrl_pdata);
int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
+8 −8
Original line number Diff line number Diff line
@@ -1081,7 +1081,6 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata)
	struct mdss_panel_info *pinfo;
	struct mipi_panel_info *mipi;
	struct dsc_desc *dsc = NULL;
	u64 clk_rate;
	u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
	u32 ystride, bpp, dst_bpp, byte_num;
	u32 stream_ctrl, stream_total;
@@ -1095,9 +1094,6 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata)
	if (pinfo->compression_mode == COMPRESSION_DSC)
		dsc = &pinfo->dsc;

	clk_rate = pdata->panel_info.clk_rate;
	clk_rate = min(clk_rate, pdata->panel_info.clk_max);

	dst_bpp = pdata->panel_info.fbc.enabled ?
		(pdata->panel_info.fbc.target_bpp) : (pinfo->bpp);

@@ -1110,6 +1106,8 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata)
	width = mult_frac(pdata->panel_info.xres, dst_bpp,
			pdata->panel_info.bpp);
	height = pdata->panel_info.yres;
	pr_debug("%s: fbc=%d width=%d height=%d dst_bpp=%d\n", __func__,
			pdata->panel_info.fbc.enabled, width, height, dst_bpp);

	if (dsc)	/* compressed */
		width = dsc->pclk_per_line;
@@ -1122,11 +1120,11 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata)
				pdata->panel_info.lcdc.border_bottom;
	}

	mipi = &pdata->panel_info.mipi;
	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
		vsync_period = vspw + vbp + height + dummy_yres + vfp;
		hsync_period = hspw + hbp + width + dummy_xres + hfp;

	mipi = &pdata->panel_info.mipi;
	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
		if (ctrl_pdata->shared_data->timing_db_mode)
			MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x1e8, 0x1);
		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24,
@@ -1324,9 +1322,11 @@ static int mdss_dsi_cmds2buf_tx(struct mdss_dsi_ctrl_pdata *ctrl,
			if (IS_ERR_VALUE(len)) {
				mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
				pr_err("%s: failed to call cmd_dma_tx for cmd = 0x%x\n",
					__func__,  cmds->payload[0]);
					__func__,  cm->payload[0]);
				return 0;
			}
			pr_debug("%s: cmd_dma_tx for cmd = 0x%x, len = %d\n",
					__func__,  cm->payload[0], len);

			if (!wait || dchdr->wait > VSYNC_PERIOD)
				usleep_range(dchdr->wait * 1000, dchdr->wait * 1000);
+353 −184

File changed.

Preview size limit exceeded, changes collapsed.

Loading