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

Commit a7c7bbe8 authored by Jeykumar Sankaran's avatar Jeykumar Sankaran Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/dsi-staging: add support for dynamic mode switch



Provide support for seamless mode switching in supported panels.
Currently support is limited to smart panels. This changes modifies
drm bridge handlers to support seamless switch by reconfiguring the
DSI controllers with display timing values of the new mode.

Change-Id: Iece513077d76176ca7fa56a3e78c854bdb2b713a
Signed-off-by: default avatarJeykumar Sankaran <jsanka@codeaurora.org>
parent 446a5f15
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -1945,6 +1945,36 @@ void dsi_ctrl_disable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
	spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags);
}

int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl)
{
	if (!dsi_ctrl) {
		pr_err("Invalid params\n");
		return -EINVAL;
	}

	if (dsi_ctrl->hw.ops.host_setup)
		dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw,
				&dsi_ctrl->host_config.common_config);

	if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) {
		if (dsi_ctrl->hw.ops.cmd_engine_setup)
			dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw,
					&dsi_ctrl->host_config.common_config,
					&dsi_ctrl->host_config.u.cmd_engine);

		if (dsi_ctrl->hw.ops.setup_cmd_stream)
			dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
				&dsi_ctrl->host_config.video_timing,
				dsi_ctrl->host_config.video_timing.h_active * 3,
				0x0, NULL);
	} else {
		pr_err("invalid panel mode for resolution switch\n");
		return -EINVAL;
	}

	return 0;
}

/**
 * dsi_ctrl_host_init() - Initialize DSI host hardware.
 * @dsi_ctrl:        DSI controller handle.
+11 −0
Original line number Diff line number Diff line
@@ -359,6 +359,17 @@ int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable);
 */
int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl);

/**
 * dsi_ctrl_host_timing_update - reinitialize host with new timing values
 * @dsi_ctrl:         DSI controller handle.
 *
 * Reinitialize DSI controller hardware with new display timing values
 * when resolution is switched dynamically.
 *
 * Return: error code
 */
int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl);

/**
 * dsi_ctrl_host_init() - Initialize DSI host hardware.
 * @dsi_ctrl:        DSI controller handle.
+1 −1
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ void dsi_ctrl_hw_cmn_host_setup(struct dsi_ctrl_hw *ctrl,
	DSI_W32(ctrl, DSI_CLK_CTRL, 0x23F);

	/* Setup DSI control register */
	reg_value = 0;
	reg_value = DSI_R32(ctrl, DSI_CTRL);
	reg_value |= (cfg->en_crc_check ? BIT(24) : 0);
	reg_value |= (cfg->en_ecc_check ? BIT(20) : 0);
	reg_value |= BIT(8); /* Clock lane */
+3 −1
Original line number Diff line number Diff line
@@ -76,11 +76,13 @@ enum dsi_op_mode {
 * @DSI_MODE_FLAG_SEAMLESS:	Seamless transition requested by user
 * @DSI_MODE_FLAG_DFPS:		Seamless transition is DynamicFPS
 * @DSI_MODE_FLAG_VBLANK_PRE_MODESET:	Transition needs VBLANK before Modeset
 * @DSI_MODE_FLAG_DMS: Seamless transition is dynamic mode switch
 */
enum dsi_mode_flags {
	DSI_MODE_FLAG_SEAMLESS			= BIT(0),
	DSI_MODE_FLAG_DFPS			= BIT(1),
	DSI_MODE_FLAG_VBLANK_PRE_MODESET	= BIT(2)
	DSI_MODE_FLAG_VBLANK_PRE_MODESET	= BIT(2),
	DSI_MODE_FLAG_DMS			= BIT(3),
};

/**
+112 −5
Original line number Diff line number Diff line
@@ -1107,6 +1107,32 @@ static int dsi_display_phy_reset_config(struct dsi_display *display,
	return 0;
}

static int dsi_display_ctrl_update(struct dsi_display *display)
{
	int rc = 0;
	int i;
	struct dsi_display_ctrl *ctrl;

	for (i = 0 ; i < display->ctrl_count; i++) {
		ctrl = &display->ctrl[i];
		rc = dsi_ctrl_host_timing_update(ctrl->ctrl);
		if (rc) {
			pr_err("[%s] failed to update host_%d, rc=%d\n",
				   display->name, i, rc);
			goto error_host_deinit;
		}
	}

	return 0;
error_host_deinit:
	for (i = i - 1; i >= 0; i--) {
		ctrl = &display->ctrl[i];
		(void)dsi_ctrl_host_deinit(ctrl->ctrl);
	}

	return rc;
}

static int dsi_display_ctrl_init(struct dsi_display *display)
{
	int rc = 0;
@@ -3588,17 +3614,80 @@ int dsi_display_set_tpg_state(struct dsi_display *display, bool enable)
	return rc;
}

static int dsi_display_pre_switch(struct dsi_display *display)
{
	int rc = 0;

	rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
			DSI_CORE_CLK, DSI_CLK_ON);
	if (rc) {
		pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
		       display->name, rc);
		goto error;
	}

	rc = dsi_display_ctrl_update(display);
	if (rc) {
		pr_err("[%s] failed to update DSI controller, rc=%d\n",
			   display->name, rc);
		goto error_ctrl_clk_off;
	}

	rc = dsi_display_set_clk_src(display);
	if (rc) {
		pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
			display->name, rc);
		goto error_ctrl_deinit;
	}

	rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
			DSI_LINK_CLK, DSI_CLK_ON);
	if (rc) {
		pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
			   display->name, rc);
		goto error_ctrl_deinit;
	}

	goto error;

error_ctrl_deinit:
	(void)dsi_display_ctrl_deinit(display);
error_ctrl_clk_off:
	(void)dsi_display_clk_ctrl(display->dsi_clk_handle,
			DSI_CORE_CLK, DSI_CLK_OFF);
error:
	return rc;
}

int dsi_display_prepare(struct dsi_display *display)
{
	int rc = 0;
	struct dsi_display_mode *mode;

	if (!display) {
		pr_err("Invalid params\n");
		return -EINVAL;
	}

	if (!display->panel->cur_mode) {
		pr_err("no valid mode set for the display");
		return -EINVAL;
	}

	mutex_lock(&display->display_lock);

	mode = display->panel->cur_mode;

	if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
		/* update dsi ctrl for new mode */
		rc = dsi_display_pre_switch(display);
		if (rc)
			pr_err("[%s] panel pre-prepare-res-switch failed, rc=%d\n",
				   display->name, rc);

		goto error;
	}

	rc = dsi_panel_pre_prepare(display->panel);
	if (rc) {
		pr_err("[%s] panel pre-prepare failed, rc=%d\n",
@@ -3812,12 +3901,21 @@ int dsi_display_enable(struct dsi_display *display)

	mode = display->panel->cur_mode;

	if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
		rc = dsi_panel_post_switch(display->panel);
		if (rc) {
			pr_err("[%s] failed to switch DSI panel mode, rc=%d\n",
				   display->name, rc);
			goto error;
		}
	} else {
		rc = dsi_panel_enable(display->panel);
		if (rc) {
			pr_err("[%s] failed to enable DSI panel, rc=%d\n",
			       display->name, rc);
			goto error;
		}
	}

	if (mode->priv_info->dsc_enabled) {
		mode->priv_info->dsc.pic_width *= display->ctrl_count;
@@ -3829,6 +3927,15 @@ int dsi_display_enable(struct dsi_display *display)
		}
	}

	if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
		rc = dsi_panel_switch(display->panel);
		if (rc)
			pr_err("[%s] failed to switch DSI panel mode, rc=%d\n",
				   display->name, rc);

		goto error_disable_panel;
	}

	if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
		rc = dsi_display_vid_engine_enable(display);
		if (rc) {
Loading