drm/msm/dsi-staging: add support for command mode panels

Add support for command mode panels. Command engine state must be
ref-counted since it is toggled in two paths, command transfer and mdp
command frame updates.

Change-Id: I9aba97465ad822c4c862f6aa5422dc47cb6664c8
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index 114998f..3f698cb 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -28,6 +28,7 @@
 	ctrl->ops.video_engine_setup     = dsi_ctrl_hw_14_video_engine_setup;
 	ctrl->ops.set_video_timing       = dsi_ctrl_hw_14_set_video_timing;
 	ctrl->ops.cmd_engine_setup       = dsi_ctrl_hw_14_cmd_engine_setup;
+	ctrl->ops.setup_cmd_stream       = dsi_ctrl_hw_14_setup_cmd_stream;
 	ctrl->ops.ctrl_en                = dsi_ctrl_hw_14_ctrl_en;
 	ctrl->ops.cmd_engine_en          = dsi_ctrl_hw_14_cmd_engine_en;
 	ctrl->ops.phy_sw_reset           = dsi_ctrl_hw_14_phy_sw_reset;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index e4b33c2..506fa28 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -75,6 +75,11 @@
 void dsi_ctrl_hw_14_ctrl_en(struct dsi_ctrl_hw *ctrl, bool on);
 void dsi_ctrl_hw_14_cmd_engine_en(struct dsi_ctrl_hw *ctrl, bool on);
 
+void dsi_ctrl_hw_14_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
+				     u32 width_in_pixels,
+				     u32 h_stride,
+				     u32 height_in_lines,
+				     u32 vc_id);
 void dsi_ctrl_hw_14_phy_sw_reset(struct dsi_ctrl_hw *ctrl);
 void dsi_ctrl_hw_14_soft_reset(struct dsi_ctrl_hw *ctrl);
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index a282fce..381827e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1485,23 +1485,30 @@
 		goto error;
 	}
 
-	dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw,
-					  &dsi_ctrl->host_config.video_timing);
-
 	dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw,
 					&dsi_ctrl->host_config.lane_map);
 
 	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->host_config.panel_mode == DSI_OP_CMD_MODE) {
 		dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw,
 					&dsi_ctrl->host_config.common_config,
 					&dsi_ctrl->host_config.u.cmd_engine);
-	else
+
+		dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
+				dsi_ctrl->host_config.video_timing.h_active,
+				dsi_ctrl->host_config.video_timing.h_active * 3,
+				dsi_ctrl->host_config.video_timing.v_active,
+				0x0);
+	} else {
 		dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw,
 					&dsi_ctrl->host_config.common_config,
 					&dsi_ctrl->host_config.u.video_engine);
+		dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw,
+					  &dsi_ctrl->host_config.video_timing);
+	}
+
 
 
 	dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index b5ddfbb..a33d6d3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -272,6 +272,22 @@
 				 struct dsi_cmd_engine_cfg *cfg);
 
 	/**
+	 * setup_cmd_stream() - set up parameters for command pixel streams
+	 * @ctrl:          Pointer to controller host hardware.
+	 * @width_in_pixels:   Width of the stream in pixels.
+	 * @h_stride:          Horizontal stride in bytes.
+	 * @height_inLines:    Number of lines in the stream.
+	 * @vc_id:             stream_id.
+	 *
+	 * Setup parameters for command mode pixel stream size.
+	 */
+	void (*setup_cmd_stream)(struct dsi_ctrl_hw *ctrl,
+				 u32 width_in_pixels,
+				 u32 h_stride,
+				 u32 height_in_lines,
+				 u32 vc_id);
+
+	/**
 	 * ctrl_en() - enable DSI controller engine
 	 * @ctrl:          Pointer to the controller host hardware.
 	 * @on:            turn on/off the DSI controller engine.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_1_4.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_1_4.c
index 8326024..9d819a2 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_1_4.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_1_4.c
@@ -85,9 +85,6 @@
 
 	DSI_W32(ctrl, DSI_CTRL, reg_value);
 
-	/* Enable Timing double buffering */
-	DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x1);
-
 	pr_debug("[DSI_%d]Host configuration complete\n", ctrl->index);
 }
 
@@ -198,6 +195,35 @@
 }
 
 /**
+ * setup_cmd_stream() - set up parameters for command pixel streams
+ * @ctrl:          Pointer to controller host hardware.
+ * @width_in_pixels:   Width of the stream in pixels.
+ * @h_stride:          Horizontal stride in bytes.
+ * @height_inLines:    Number of lines in the stream.
+ * @vc_id:             stream_id
+ *
+ * Setup parameters for command mode pixel stream size.
+ */
+void dsi_ctrl_hw_14_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
+				     u32 width_in_pixels,
+				     u32 h_stride,
+				     u32 height_in_lines,
+				     u32 vc_id)
+{
+	u32 reg = 0;
+
+	reg = (h_stride + 1) << 16;
+	reg |= (vc_id & 0x3) << 8;
+	reg |= 0x39; /* packet data type */
+	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, reg);
+	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, reg);
+
+	reg = (height_in_lines << 16) | width_in_pixels;
+	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, reg);
+	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, reg);
+}
+
+/**
  * video_engine_setup() - Setup dsi host controller for video mode
  * @ctrl:          Pointer to controller host hardware.
  * @common_cfg:    Common configuration parameters.
@@ -229,6 +255,9 @@
 	reg |= (common_cfg->bit_swap_green ? BIT(4) : 0);
 	reg |= (common_cfg->bit_swap_blue ? BIT(8) : 0);
 	DSI_W32(ctrl, DSI_VIDEO_MODE_DATA_CTRL, reg);
+	/* Enable Timing double buffering */
+	DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x1);
+
 
 	pr_debug("[DSI_%d] Video engine setup done\n", ctrl->index);
 }
@@ -255,6 +284,10 @@
 	reg |= cmd_mode_format_map[common_cfg->dst_format];
 	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_CTRL, reg);
 
+	reg = DSI_R32(ctrl, DSI_COMMAND_MODE_MDP_CTRL2);
+	reg |= BIT(16);
+	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_CTRL2, reg);
+
 	reg = cfg->wr_mem_start & 0xFF;
 	reg |= (cfg->wr_mem_continue & 0xFF) << 8;
 	reg |= (cfg->insert_dcs_command ? BIT(16) : 0);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 68e3b52..1e2226c0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -364,6 +364,11 @@
 	int i;
 	struct dsi_display_ctrl *m_ctrl, *ctrl;
 
+	if (display->cmd_engine_refcount > 0) {
+		display->cmd_engine_refcount++;
+		return 0;
+	}
+
 	m_ctrl = &display->ctrl[display->cmd_master_idx];
 
 	rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON);
@@ -387,6 +392,7 @@
 		}
 	}
 
+	display->cmd_engine_refcount++;
 	return rc;
 error_disable_master:
 	(void)dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
@@ -400,6 +406,14 @@
 	int i;
 	struct dsi_display_ctrl *m_ctrl, *ctrl;
 
+	if (display->cmd_engine_refcount == 0) {
+		pr_err("[%s] Invalid refcount\n", display->name);
+		return 0;
+	} else if (display->cmd_engine_refcount > 1) {
+		display->cmd_engine_refcount--;
+		return 0;
+	}
+
 	m_ctrl = &display->ctrl[display->cmd_master_idx];
 	for (i = 0; i < display->ctrl_count; i++) {
 		ctrl = &display->ctrl[i];
@@ -421,6 +435,7 @@
 	}
 
 error:
+	display->cmd_engine_refcount = 0;
 	return rc;
 }
 
@@ -1834,20 +1849,33 @@
 	if (rc) {
 		pr_err("[%s] failed to enable DSI panel, rc=%d\n",
 		       display->name, rc);
-		goto error_disable_vid_engine;
+		goto error;
 	}
 
-	rc = dsi_display_vid_engine_enable(display);
-	if (rc) {
-		pr_err("[%s] failed to enable DSI video engine, rc=%d\n",
-		       display->name, rc);
-		goto error;
+	if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
+		rc = dsi_display_vid_engine_enable(display);
+		if (rc) {
+			pr_err("[%s]failed to enable DSI video engine, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_panel;
+		}
+	} else if (display->config.panel_mode == DSI_OP_CMD_MODE) {
+		rc = dsi_display_cmd_engine_enable(display);
+		if (rc) {
+			pr_err("[%s]failed to enable DSI cmd engine, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_panel;
+		}
+	} else {
+		pr_err("[%s] Invalid configuration\n", display->name);
+		rc = -EINVAL;
+		goto error_disable_panel;
 	}
 
 	goto error;
 
-error_disable_vid_engine:
-	(void)dsi_display_vid_engine_disable(display);
+error_disable_panel:
+	(void)dsi_panel_disable(display->panel);
 error:
 	mutex_unlock(&display->display_lock);
 	return rc;
@@ -1914,10 +1942,20 @@
 		pr_err("[%s] failed to disable DSI panel, rc=%d\n",
 		       display->name, rc);
 
-	rc = dsi_display_vid_engine_disable(display);
-	if (rc)
-		pr_err("[%s] failed to disable video engine, rc=%d\n",
-		       display->name, rc);
+	if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
+		rc = dsi_display_vid_engine_disable(display);
+		if (rc)
+			pr_err("[%s]failed to disable DSI vid engine, rc=%d\n",
+			       display->name, rc);
+	} else if (display->config.panel_mode == DSI_OP_CMD_MODE) {
+		rc = dsi_display_cmd_engine_disable(display);
+		if (rc)
+			pr_err("[%s]failed to disable DSI cmd engine, rc=%d\n",
+			       display->name, rc);
+	} else {
+		pr_err("[%s] Invalid configuration\n", display->name);
+		rc = -EINVAL;
+	}
 
 	mutex_unlock(&display->display_lock);
 	return rc;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index df15bb8..1897ce3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -101,10 +101,6 @@
 	u32 dsi_ctrl_idx;
 
 	enum dsi_power_state power_state;
-	bool cmd_engine_enabled;
-	bool video_engine_enabled;
-	bool ulps_enabled;
-	bool clamps_enabled;
 
 	/* phy info */
 	struct msm_dsi_phy *phy;
@@ -182,6 +178,7 @@
 	struct mipi_dsi_host host;
 	struct dsi_connector *connector;
 	struct dsi_bridge    *bridge;
+	u32 cmd_engine_refcount;
 };
 
 int dsi_display_dev_probe(struct platform_device *pdev);