浏览代码

Merge "disp: msm: dsi: add debug ability to read TE read pointer line count"

qctecmdr 4 年之前
父节点
当前提交
faf4a8b1c8
共有 10 个文件被更改,包括 605 次插入39 次删除
  1. 14 0
      msm/dsi/dsi_catalog.c
  2. 9 0
      msm/dsi/dsi_catalog.h
  3. 190 18
      msm/dsi/dsi_ctrl.c
  4. 19 0
      msm/dsi/dsi_ctrl.h
  5. 47 0
      msm/dsi/dsi_ctrl_hw.h
  6. 154 0
      msm/dsi/dsi_ctrl_hw_2_2.c
  7. 7 3
      msm/dsi/dsi_defs.h
  8. 146 4
      msm/dsi/dsi_display.c
  9. 18 14
      msm/dsi/dsi_panel.c
  10. 1 0
      msm/dsi/dsi_panel.h

+ 14 - 0
msm/dsi/dsi_catalog.c

@@ -80,6 +80,10 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
 		ctrl->ops.schedule_dma_cmd = NULL;
 		ctrl->ops.kickoff_command_non_embedded_mode = NULL;
 		ctrl->ops.config_clk_gating = NULL;
+		ctrl->ops.configure_cmddma_window = NULL;
+		ctrl->ops.reset_trig_ctrl = NULL;
+		ctrl->ops.map_mdp_regs = NULL;
+		ctrl->ops.log_line_count = NULL;
 		break;
 	case DSI_CTRL_VERSION_2_0:
 		ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map;
@@ -95,6 +99,10 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
 		ctrl->ops.schedule_dma_cmd = NULL;
 		ctrl->ops.kickoff_command_non_embedded_mode = NULL;
 		ctrl->ops.config_clk_gating = NULL;
+		ctrl->ops.configure_cmddma_window = NULL;
+		ctrl->ops.reset_trig_ctrl = NULL;
+		ctrl->ops.map_mdp_regs = NULL;
+		ctrl->ops.log_line_count = NULL;
 		break;
 	case DSI_CTRL_VERSION_2_2:
 	case DSI_CTRL_VERSION_2_3:
@@ -116,6 +124,12 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
 		ctrl->ops.schedule_dma_cmd = dsi_ctrl_hw_22_schedule_dma_cmd;
 		ctrl->ops.kickoff_command_non_embedded_mode =
 			dsi_ctrl_hw_kickoff_non_embedded_mode;
+		ctrl->ops.configure_cmddma_window =
+			dsi_ctrl_hw_22_configure_cmddma_window;
+		ctrl->ops.reset_trig_ctrl =
+			dsi_ctrl_hw_22_reset_trigger_controls;
+		ctrl->ops.map_mdp_regs = dsi_ctrl_hw_22_map_mdp_regs;
+		ctrl->ops.log_line_count = dsi_ctrl_hw_22_log_line_count;
 		break;
 	default:
 		break;

+ 9 - 0
msm/dsi/dsi_catalog.h

@@ -274,4 +274,13 @@ void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
 
 int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
 				      u32 *dst, u32 size);
+
+void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl,
+		struct dsi_ctrl_cmd_dma_info *cmd,
+		u32 line_no, u32 window);
+void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl,
+				       struct dsi_host_common_cfg *cfg);
+int dsi_ctrl_hw_22_map_mdp_regs(struct platform_device *pdev,
+		struct dsi_ctrl_hw *ctrl);
+u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode);
 #endif /* _DSI_CATALOG_H_ */

+ 190 - 18
msm/dsi/dsi_ctrl.c

@@ -194,6 +194,58 @@ static ssize_t debugfs_reg_dump_read(struct file *file,
 	return len;
 }
 
+static ssize_t debugfs_line_count_read(struct file *file,
+				 char __user *user_buf,
+				 size_t user_len,
+				 loff_t *ppos)
+{
+	struct dsi_ctrl *dsi_ctrl = file->private_data;
+	char *buf;
+	int rc = 0;
+	u32 len = 0;
+	size_t max_len = min_t(size_t, user_len, SZ_4K);
+
+	if (!dsi_ctrl)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	buf = kzalloc(max_len, GFP_KERNEL);
+	if (ZERO_OR_NULL_PTR(buf))
+		return -ENOMEM;
+
+	mutex_lock(&dsi_ctrl->ctrl_lock);
+
+	len += scnprintf(buf, max_len, "Command triggered at line: %04x\n",
+			dsi_ctrl->cmd_trigger_line);
+	len += scnprintf((buf + len), max_len - len,
+			"Command triggered at frame: %04x\n",
+			dsi_ctrl->cmd_trigger_frame);
+	len += scnprintf((buf + len), max_len - len,
+			"Command successful at line: %04x\n",
+			dsi_ctrl->cmd_success_line);
+	len += scnprintf((buf + len), max_len - len,
+			"Command successful at frame: %04x\n",
+			dsi_ctrl->cmd_success_frame);
+
+	mutex_unlock(&dsi_ctrl->ctrl_lock);
+
+	if (len > max_len)
+		len = max_len;
+
+	if (copy_to_user(user_buf, buf, len)) {
+		rc = -EFAULT;
+		goto error;
+	}
+
+	*ppos += len;
+
+error:
+	kfree(buf);
+	return len;
+}
+
 static const struct file_operations state_info_fops = {
 	.open = simple_open,
 	.read = debugfs_state_info_read,
@@ -204,11 +256,16 @@ static const struct file_operations reg_dump_fops = {
 	.read = debugfs_reg_dump_read,
 };
 
+static const struct file_operations cmd_dma_stats_fops = {
+	.open = simple_open,
+	.read = debugfs_line_count_read,
+};
+
 static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl,
 				 struct dentry *parent)
 {
 	int rc = 0;
-	struct dentry *dir, *state_file, *reg_dump;
+	struct dentry *dir, *state_file, *reg_dump, *cmd_dma_logs;
 	char dbg_name[DSI_DEBUG_NAME_LEN];
 
 	if (!dsi_ctrl || !parent) {
@@ -246,6 +303,30 @@ static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl,
 		goto error_remove_dir;
 	}
 
+	cmd_dma_logs = debugfs_create_bool("enable_cmd_dma_stats",
+				       0600,
+				       dir,
+				       &dsi_ctrl->enable_cmd_dma_stats);
+	if (IS_ERR_OR_NULL(cmd_dma_logs)) {
+		rc = PTR_ERR(cmd_dma_logs);
+		DSI_CTRL_ERR(dsi_ctrl,
+				"enable cmd dma stats failed, rc=%d\n",
+				rc);
+		goto error_remove_dir;
+	}
+
+	cmd_dma_logs = debugfs_create_file("cmd_dma_stats",
+				       0444,
+				       dir,
+				       dsi_ctrl,
+				       &cmd_dma_stats_fops);
+	if (IS_ERR_OR_NULL(cmd_dma_logs)) {
+		rc = PTR_ERR(cmd_dma_logs);
+		DSI_CTRL_ERR(dsi_ctrl, "Line count file failed, rc=%d\n",
+				rc);
+		goto error_remove_dir;
+	}
+
 	dsi_ctrl->debugfs_root = dir;
 
 	snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_ctrl",
@@ -1177,6 +1258,60 @@ int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl,
 	return rc;
 }
 
+static void dsi_configure_command_scheduling(struct dsi_ctrl *dsi_ctrl,
+		struct dsi_ctrl_cmd_dma_info *cmd_mem)
+{
+	u32 line_no = 0, window = 0, sched_line_no = 0;
+	struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops;
+	struct dsi_mode_info *timing = &(dsi_ctrl->host_config.video_timing);
+
+	line_no = dsi_ctrl->host_config.common_config.dma_sched_line;
+	window = dsi_ctrl->host_config.common_config.dma_sched_window;
+
+	SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, line_no, window);
+	/*
+	 * In case of command scheduling in video mode, the line at which
+	 * the command is scheduled can revert to the default value i.e. 1
+	 * for the following cases:
+	 *	1) No schedule line defined by the panel.
+	 *	2) schedule line defined is greater than VFP.
+	 */
+	if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
+		dsi_hw_ops.schedule_dma_cmd &&
+		(dsi_ctrl->current_state.vid_engine_state ==
+					DSI_CTRL_ENGINE_ON)) {
+		sched_line_no = (line_no == 0) ? 1 : line_no;
+
+		if (timing) {
+			if (sched_line_no >= timing->v_front_porch)
+				sched_line_no = 1;
+			sched_line_no += timing->v_back_porch +
+				timing->v_sync_width + timing->v_active;
+		}
+		dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw, sched_line_no);
+	}
+
+	/*
+	 * In case of command scheduling in command mode, the window size
+	 * is reset to zero, if the total scheduling window is greater
+	 * than the panel height.
+	 */
+	if ((dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) &&
+			dsi_hw_ops.configure_cmddma_window) {
+		sched_line_no = line_no;
+
+		if ((sched_line_no + window) > timing->v_active)
+			window = 0;
+
+		sched_line_no += timing->v_active;
+
+		dsi_hw_ops.configure_cmddma_window(&dsi_ctrl->hw, cmd_mem,
+				sched_line_no, window);
+	}
+	SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_EXIT,
+			sched_line_no, window);
+}
+
 static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
 				const struct mipi_dsi_msg *msg,
 				struct dsi_ctrl_cmd_dma_fifo_info *cmd,
@@ -1184,27 +1319,20 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
 				u32 flags)
 {
 	u32 hw_flags = 0;
-	u32 line_no = 0x1;
-	struct dsi_mode_info *timing;
 	struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops;
 
 	SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, flags);
-	/* check if custom dma scheduling line needed */
-	if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
-		(flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED))
-		line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line;
 
-	timing = &(dsi_ctrl->host_config.video_timing);
-	if (timing)
-		line_no += timing->v_back_porch + timing->v_sync_width +
-				timing->v_active;
-	if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
-		dsi_hw_ops.schedule_dma_cmd &&
-		(dsi_ctrl->current_state.vid_engine_state ==
-					DSI_CTRL_ENGINE_ON))
-		dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw,
-				line_no);
+	if (dsi_ctrl->hw.reset_trig_ctrl)
+		dsi_hw_ops.reset_trig_ctrl(&dsi_ctrl->hw,
+				&dsi_ctrl->host_config.common_config);
+
+	/* check if custom dma scheduling line needed */
+	if (flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED)
+		dsi_configure_command_scheduling(dsi_ctrl, cmd_mem);
 
+	dsi_ctrl->cmd_mode = (dsi_ctrl->host_config.panel_mode ==
+			DSI_OP_CMD_MODE);
 	hw_flags |= (flags & DSI_CTRL_CMD_DEFER_TRIGGER) ?
 			DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER : 0;
 
@@ -1259,6 +1387,17 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
 							      cmd,
 							      hw_flags);
 		}
+
+		if (dsi_ctrl->enable_cmd_dma_stats) {
+			u32 reg = dsi_hw_ops.log_line_count(&dsi_ctrl->hw,
+					dsi_ctrl->cmd_mode);
+			dsi_ctrl->cmd_trigger_line = (reg & 0xFFFF);
+			dsi_ctrl->cmd_trigger_frame = ((reg >> 16) & 0xFFFF);
+			SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1,
+					dsi_ctrl->cmd_trigger_line,
+					dsi_ctrl->cmd_trigger_frame);
+		}
+
 		if (flags & DSI_CTRL_CMD_ASYNC_WAIT) {
 			dsi_ctrl->dma_wait_queued = true;
 			queue_work(dsi_ctrl->dma_cmd_workq,
@@ -1921,6 +2060,9 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev)
 		goto fail_clks;
 	}
 
+	if (dsi_ctrl->hw.ops.map_mdp_regs)
+		dsi_ctrl->hw.ops.map_mdp_regs(pdev, &dsi_ctrl->hw);
+
 	item->ctrl = dsi_ctrl;
 	sde_dbg_dsi_ctrl_register(dsi_ctrl->hw.base, dsi_ctrl->name);
 
@@ -2584,6 +2726,15 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr)
 		dsi_ctrl_handle_error_status(dsi_ctrl, errors);
 
 	if (status & DSI_CMD_MODE_DMA_DONE) {
+		if (dsi_ctrl->enable_cmd_dma_stats) {
+			u32 reg = dsi_ctrl->hw.ops.log_line_count(&dsi_ctrl->hw,
+						dsi_ctrl->cmd_mode);
+			dsi_ctrl->cmd_success_line = (reg & 0xFFFF);
+			dsi_ctrl->cmd_success_frame = ((reg >> 16) & 0xFFFF);
+			SDE_EVT32(dsi_ctrl->cell_index,	SDE_EVTLOG_FUNC_CASE1,
+					dsi_ctrl->cmd_success_line,
+					dsi_ctrl->cmd_success_frame);
+		}
 		atomic_set(&dsi_ctrl->dma_irq_trig, 1);
 		dsi_ctrl_disable_status_interrupt(dsi_ctrl,
 					DSI_SINT_CMD_MODE_DMA_DONE);
@@ -3191,8 +3342,18 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
 
 	mutex_lock(&dsi_ctrl->ctrl_lock);
 
-	if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER))
+	if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) {
 		dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw);
+		if (dsi_ctrl->enable_cmd_dma_stats) {
+			u32 reg = dsi_hw_ops.log_line_count(&dsi_ctrl->hw,
+					dsi_ctrl->cmd_mode);
+			dsi_ctrl->cmd_trigger_line = (reg & 0xFFFF);
+			dsi_ctrl->cmd_trigger_frame = ((reg >> 16) & 0xFFFF);
+			SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1,
+					dsi_ctrl->cmd_trigger_line,
+					dsi_ctrl->cmd_trigger_frame);
+		}
+	}
 
 	if ((flags & DSI_CTRL_CMD_BROADCAST) &&
 		(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) {
@@ -3207,6 +3368,17 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
 
 		/* trigger command */
 		dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw);
+
+		if (dsi_ctrl->enable_cmd_dma_stats) {
+			u32 reg = dsi_hw_ops.log_line_count(&dsi_ctrl->hw,
+					dsi_ctrl->cmd_mode);
+			dsi_ctrl->cmd_trigger_line = (reg & 0xFFFF);
+			dsi_ctrl->cmd_trigger_frame = ((reg >> 16) & 0xFFFF);
+			SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1,
+					dsi_ctrl->cmd_trigger_line,
+					dsi_ctrl->cmd_trigger_frame);
+		}
+
 		if (flags & DSI_CTRL_CMD_ASYNC_WAIT) {
 			dsi_ctrl->dma_wait_queued = true;
 			queue_work(dsi_ctrl->dma_cmd_workq,

+ 19 - 0
msm/dsi/dsi_ctrl.h

@@ -229,6 +229,19 @@ struct dsi_ctrl_interrupts {
  *                           insert null packet.
  * @modeupdated:	  Boolean to send new roi if mode is updated.
  * @split_link_supported: Boolean to check if hw supports split link.
+ * @enable_cmd_dma_stats: Boolean to indicate the verbose logging during
+ *				CMD transfer.
+ *				count.
+ * @cmd_mode:			Boolean to indicate if panel is running in
+ *				command mode.
+ * @cmd_trigger_line:		unsigned integer that indicates the line at
+ *				which command gets triggered.
+ * @cmd_trigger_frame:		unsigned integer that indicates the frame at
+ *				which command gets triggered.
+ * @cmd_success_line:		unsigned integer that indicates the line at
+ *				which command transfer is successful.
+ * @cmd_success_frame:		unsigned integer that indicates the frame at
+ *				which command transfer is successful.
  */
 struct dsi_ctrl {
 	struct platform_device *pdev;
@@ -289,6 +302,12 @@ struct dsi_ctrl {
 	bool null_insertion_enabled;
 	bool modeupdated;
 	bool split_link_supported;
+	bool enable_cmd_dma_stats;
+	bool cmd_mode;
+	u32 cmd_trigger_line;
+	u32 cmd_trigger_frame;
+	u32 cmd_success_line;
+	u32 cmd_success_frame;
 };
 
 /**

+ 47 - 0
msm/dsi/dsi_ctrl_hw.h

@@ -831,6 +831,41 @@ struct dsi_ctrl_hw_ops {
 	 * @sel_phy:	Bool to control whether to select phy or controller
 	 */
 	void (*hs_req_sel)(struct dsi_ctrl_hw *ctrl, bool sel_phy);
+
+	/**
+	 * hw.ops.configure_cmddma_window() - configure DMA window for CMD TX
+	 * @ctrl:	Pointer to the controller host hardware.
+	 * @cmd:	Pointer to the DSI DMA command info.
+	 * @line_no:	Line number at which the CMD needs to be triggered.
+	 * @window:	Width of the DMA CMD window.
+	 */
+	void (*configure_cmddma_window)(struct dsi_ctrl_hw *ctrl,
+			struct dsi_ctrl_cmd_dma_info *cmd,
+			u32 line_no, u32 window);
+
+	/**
+	 * hw.ops.reset_trig_ctrl() - resets trigger control of DSI controller
+	 * @ctrl:	Pointer to the controller host hardware.
+	 * @cfg:	Common configuration parameters.
+	 */
+	void (*reset_trig_ctrl)(struct dsi_ctrl_hw *ctrl,
+			struct dsi_host_common_cfg *cfg);
+
+	/**
+	 * hw.ops.map_mdp_regs() - maps MDP interface line count registers.
+	 * @pdev:	Pointer to platform device.
+	 * @ctrl:	Pointer to the controller host hardware.
+	 */
+	int (*map_mdp_regs)(struct platform_device *pdev,
+			struct dsi_ctrl_hw *ctrl);
+
+	/**
+	 * hw.ops.log_line_count() - reads the MDP interface line count
+	 *			     registers.
+	 * @ctrl:	Pointer to the controller host hardware.
+	 * @cmd_mode:	Boolean to indicate command mode operation.
+	 */
+	u32 (*log_line_count)(struct dsi_ctrl_hw *ctrl, bool cmd_mode);
 };
 
 /*
@@ -841,6 +876,13 @@ struct dsi_ctrl_hw_ops {
  * @mmss_misc_length:       Length of mmss_misc register map.
  * @disp_cc_base:           Base address of disp_cc register map.
  * @disp_cc_length:         Length of disp_cc register map.
+ * @te_rd_ptr_reg:	    Address of MDP_TEAR_INTF_TEAR_LINE_COUNT. This
+ *			    register is used for testing and validating the RD
+ *			    ptr value when a CMD is triggered and it succeeds.
+ * @line_count_reg:	    Address of MDP_TEAR_INTF_LINE_COUNT. This
+ *			    register is used for testing and validating the
+ *			    line count value when a CMD is triggered and it
+ *			    succeeds.
  * @index:                  Instance ID of the controller.
  * @feature_map:            Features supported by the DSI controller.
  * @ops:                    Function pointers to the operations supported by the
@@ -852,6 +894,8 @@ struct dsi_ctrl_hw_ops {
  * @null_insertion_enabled:  A boolean property to allow dsi controller to
  *                           insert null packet.
  * @widebus_support:        48 bit wide data bus is supported.
+ * @reset_trig_ctrl:		Boolean to indicate if trigger control needs to
+ *				be reset to default.
  */
 struct dsi_ctrl_hw {
 	void __iomem *base;
@@ -859,6 +903,8 @@ struct dsi_ctrl_hw {
 	void __iomem *mmss_misc_base;
 	u32 mmss_misc_length;
 	void __iomem *disp_cc_base;
+	void __iomem *te_rd_ptr_reg;
+	void __iomem *line_count_reg;
 	u32 disp_cc_length;
 	u32 index;
 
@@ -873,6 +919,7 @@ struct dsi_ctrl_hw {
 	bool phy_isolation_enabled;
 	bool null_insertion_enabled;
 	bool widebus_support;
+	bool reset_trig_ctrl;
 };
 
 #endif /* _DSI_CTRL_HW_H_ */

+ 154 - 0
msm/dsi/dsi_ctrl_hw_2_2.c

@@ -12,6 +12,13 @@
 
 /* register to configure DMA scheduling */
 #define DSI_DMA_SCHEDULE_CTRL 0x100
+#define DSI_DMA_SCHEDULE_CTRL2 0x0104
+
+/* MDP INTF registers to be mapped for debug feature*/
+#define MDP_INTF1_TEAR_LINE_COUNT 0xAE36298
+#define MDP_INTF2_TEAR_LINE_COUNT 0xAE37298
+#define MDP_INTF1_LINE_COUNT 0xAE360B0
+#define MDP_INTF2_LINE_COUNT 0xAE370B0
 
 void dsi_ctrl_hw_22_setup_lane_map(struct dsi_ctrl_hw *ctrl,
 		       struct dsi_lane_map *lane_map)
@@ -102,6 +109,7 @@ void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_no)
 	reg |= (line_no & 0xffff);
 
 	DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, reg);
+	ctrl->reset_trig_ctrl = true;
 }
 
 /*
@@ -181,3 +189,149 @@ void dsi_ctrl_hw_22_config_clk_gating(struct dsi_ctrl_hw *ctrl, bool enable,
 
 	DSI_DISP_CC_W32(ctrl, DISP_CC_MISC_CMD_REG_OFF, reg);
 }
+
+/**
+ * dsi_ctrl_hw_22_configure_cmddma_window() - configure DMA window for CMD TX
+ * @ctrl:	Pointer to the controller host hardware.
+ * @cmd:	Pointer to the DSI DMA command info.
+ * @line_no:	Line number at which the CMD needs to be triggered.
+ * @window:	Width of the DMA CMD window.
+ */
+void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl,
+		struct dsi_ctrl_cmd_dma_info *cmd,
+		u32 line_no, u32 window)
+{
+	u32 reg = 0;
+
+	if (!window)
+		return;
+
+	if (cmd->en_broadcast) {
+		reg = DSI_R32(ctrl, DSI_TRIG_CTRL);
+		if (cmd->is_master) {
+			reg &= ~0xF;
+			reg |= 0xc;
+		} else {
+			reg &= ~0xF;
+			reg |= BIT(16);
+		}
+
+		DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
+
+		if (cmd->is_master) {
+			reg = 0;
+			reg |= line_no;
+			reg |= window << 16;
+			DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, reg);
+		}
+	} else {
+		reg = DSI_R32(ctrl, DSI_TRIG_CTRL);
+		reg &= ~0xF;
+		reg |= 0xc;
+		DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
+
+		reg = 0;
+		reg |= line_no;
+		reg |= window << 16;
+		DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, reg);
+	}
+	ctrl->reset_trig_ctrl = true;
+}
+
+/**
+ * dsi_ctrl_hw_22_reset_trigger_controls() - reset dsi trigger configurations
+ * @ctrl:             Pointer to the controller host hardware.
+ * @cfg:              DSI host configuration that is common to both video and
+ *                    command modes.
+ */
+void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl,
+				       struct dsi_host_common_cfg *cfg)
+{
+	u32 reg = 0;
+	const u8 trigger_map[DSI_TRIGGER_MAX] = {
+		0x0, 0x2, 0x1, 0x4, 0x5, 0x6 };
+
+	reg |= (cfg->te_mode == DSI_TE_ON_EXT_PIN) ? BIT(31) : 0;
+	reg |= (trigger_map[cfg->dma_cmd_trigger] & 0x7);
+	reg |= (trigger_map[cfg->mdp_cmd_trigger] & 0x7) << 4;
+	DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
+	DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, 0x0);
+	DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, 0x0);
+	ctrl->reset_trig_ctrl = false;
+}
+
+/**
+ * dsi_ctrl_hw_22_map_mdp_regs() - maps MDP interface line count registers.
+ * @pdev:	Pointer to platform device.
+ * @ctrl:	Pointer to the controller host hardware.
+ *
+ * Return: 0 on success and error on failure.
+ */
+int dsi_ctrl_hw_22_map_mdp_regs(struct platform_device *pdev,
+		struct dsi_ctrl_hw *ctrl)
+{
+	int rc = 0;
+	void __iomem *ptr = NULL, *ptr1 = NULL;
+
+	if (ctrl->index == 0) {
+		ptr = devm_ioremap(&pdev->dev, MDP_INTF1_TEAR_LINE_COUNT, 1);
+		if (IS_ERR_OR_NULL(ptr)) {
+			DSI_CTRL_HW_ERR(ctrl,
+				"MDP TE LINE COUNT address not found\n");
+			rc = PTR_ERR(ptr);
+			return rc;
+		}
+
+		ptr1 = devm_ioremap(&pdev->dev, MDP_INTF1_LINE_COUNT, 1);
+		if (IS_ERR_OR_NULL(ptr1)) {
+			DSI_CTRL_HW_ERR(ctrl,
+				"MDP TE LINE COUNT address not found\n");
+			rc = PTR_ERR(ptr1);
+			return rc;
+		}
+	}
+
+	if (ctrl->index == 1) {
+		ptr = devm_ioremap(&pdev->dev, MDP_INTF2_TEAR_LINE_COUNT, 1);
+		if (IS_ERR_OR_NULL(ptr)) {
+			DSI_CTRL_HW_ERR(ctrl,
+				"MDP TE LINE COUNT address not found\n");
+			rc = PTR_ERR(ptr);
+			return rc;
+		}
+
+		ptr1 = devm_ioremap(&pdev->dev, MDP_INTF2_LINE_COUNT, 1);
+		if (IS_ERR_OR_NULL(ptr1)) {
+			DSI_CTRL_HW_ERR(ctrl,
+				"MDP TE LINE COUNT address not found\n");
+			rc = PTR_ERR(ptr1);
+			return rc;
+		}
+	}
+
+	ctrl->te_rd_ptr_reg = ptr;
+	ctrl->line_count_reg = ptr1;
+
+	return rc;
+}
+
+/**
+ * dsi_ctrl_hw_22_log_line_count() - reads the MDP interface line count
+ *				     registers.
+ * @ctrl:	Pointer to the controller host hardware.
+ * @cmd_mode:	Boolean to indicate command mode operation.
+ *
+ * Return: INTF register value.
+ */
+u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode)
+{
+
+	u32 reg = 0;
+
+	if (cmd_mode && ctrl->te_rd_ptr_reg)
+		reg = readl_relaxed(ctrl->te_rd_ptr_reg);
+	else if (ctrl->line_count_reg)
+		reg = readl_relaxed(ctrl->line_count_reg);
+
+	return reg;
+}

+ 7 - 3
msm/dsi/dsi_defs.h

@@ -472,6 +472,11 @@ struct dsi_split_link_config {
  * @phy_type:            DPHY/CPHY is enabled for this panel.
  * @dsi_split_link_config:  Split Link Configuration.
  * @byte_intf_clk_div:   Determines the factor for calculating byte intf clock.
+ * @dma_sched_line:      Line at which dma command gets triggered. In case of
+ *			 video mode it is the line number after vactive and for
+ *			 cmd it points to the line after TE.
+ * @dma_sched_window:	 Determines the width of the window during the
+ *			 DSI command will be sent by the HW.
  */
 struct dsi_host_common_cfg {
 	enum dsi_pixel_format dst_format;
@@ -497,6 +502,8 @@ struct dsi_host_common_cfg {
 	enum dsi_phy_type phy_type;
 	struct dsi_split_link_config split_link;
 	u32 byte_intf_clk_div;
+	u32 dma_sched_line;
+	u32 dma_sched_window;
 };
 
 /**
@@ -513,8 +520,6 @@ struct dsi_host_common_cfg {
  * @bllp_lp11_en:              Enter low power stop mode (LP-11) during BLLP.
  * @traffic_mode:              Traffic mode for video stream.
  * @vc_id:                     Virtual channel identifier.
- * @dma_sched_line:         Line number, after vactive end, at which command dma
- *			       needs to be triggered.
  */
 struct dsi_video_engine_cfg {
 	bool last_line_interleave_en;
@@ -526,7 +531,6 @@ struct dsi_video_engine_cfg {
 	bool bllp_lp11_en;
 	enum dsi_video_traffic_mode traffic_mode;
 	u32 vc_id;
-	u32 dma_sched_line;
 };
 
 /**

+ 146 - 4
msm/dsi/dsi_display.c

@@ -673,8 +673,10 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl,
 	lenp = config->status_valid_params ?: config->status_cmds_rlen;
 	count = config->status_cmd.count;
 	cmds = config->status_cmd.cmds;
-	flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ |
-		  DSI_CTRL_CMD_CUSTOM_DMA_SCHED);
+	flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ);
+
+	if (ctrl->ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)
+		flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
 
 	for (i = 0; i < count; ++i) {
 		memset(config->status_buf, 0x0, SZ_4K);
@@ -682,6 +684,10 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl,
 			cmds[i].msg.flags |= MIPI_DSI_MSG_LASTCOMMAND;
 			flags |= DSI_CTRL_CMD_LAST_COMMAND;
 		}
+		if ((cmds[i].msg.flags & MIPI_DSI_MSG_CMD_DMA_SCHED) &&
+			 (panel->panel_initialized))
+			flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
+
 		if (config->status_cmd.state == DSI_CMD_SET_STATE_LP)
 			cmds[i].msg.flags |= MIPI_DSI_MSG_USE_LPM;
 		cmds[i].msg.rx_buf = config->status_buf;
@@ -916,6 +922,9 @@ static int dsi_display_cmd_prepare(const char *cmd_buf, u32 cmd_buf_len,
 		return -EINVAL;
 	}
 
+	if (cmd->last_command)
+		cmd->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND;
+
 	for (i = 0; i < cmd->msg.tx_len; i++)
 		payload[i] = cmd_buf[7 + i];
 
@@ -972,8 +981,12 @@ static int dsi_display_cmd_rx(struct dsi_display *display,
 		goto error;
 	}
 
-	flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ |
-			DSI_CTRL_CMD_CUSTOM_DMA_SCHED);
+	flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ);
+	if ((m_ctrl->ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) ||
+			((cmd->msg.flags & MIPI_DSI_MSG_CMD_DMA_SCHED) &&
+			 (display->panel->panel_initialized)))
+		flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
+
 	rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmd->msg, &flags);
 	if (rc <= 0)
 		DSI_ERR("rx cmd transfer failed rc = %d\n", rc);
@@ -1617,6 +1630,107 @@ error:
 	return len;
 }
 
+static ssize_t debugfs_update_cmd_scheduling_params(struct file *file,
+				  const char __user *user_buf,
+				  size_t user_len,
+				  loff_t *ppos)
+{
+	struct dsi_display *display = file->private_data;
+	struct dsi_display_ctrl *display_ctrl;
+	char *buf;
+	int rc = 0;
+	u32 line = 0, window = 0;
+	size_t len;
+	int i;
+
+	if (!display)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	buf = kzalloc(256, GFP_KERNEL);
+	if (ZERO_OR_NULL_PTR(buf))
+		return -ENOMEM;
+
+	len = min_t(size_t, user_len, 255);
+	if (copy_from_user(buf, user_buf, len)) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	buf[len] = '\0'; /* terminate the string */
+
+	if (sscanf(buf, "%d %d", &line, &window) != 2)
+		return -EFAULT;
+
+	display_for_each_ctrl(i, display) {
+		struct dsi_ctrl *ctrl;
+
+		display_ctrl = &display->ctrl[i];
+		if (!display_ctrl->ctrl)
+			continue;
+
+		ctrl = display_ctrl->ctrl;
+		ctrl->host_config.common_config.dma_sched_line = line;
+		ctrl->host_config.common_config.dma_sched_window = window;
+	}
+
+	rc = len;
+
+error:
+	kfree(buf);
+	return rc;
+}
+
+static ssize_t debugfs_read_cmd_scheduling_params(struct file *file,
+				 char __user *user_buf,
+				 size_t user_len,
+				 loff_t *ppos)
+{
+	struct dsi_display *display = file->private_data;
+	struct dsi_display_ctrl *m_ctrl;
+	struct dsi_ctrl *ctrl;
+	char *buf;
+	u32 len = 0;
+	int rc = 0;
+	size_t max_len = min_t(size_t, user_len, SZ_4K);
+
+	if (!display)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	m_ctrl = &display->ctrl[display->cmd_master_idx];
+	ctrl = m_ctrl->ctrl;
+
+	buf = kzalloc(max_len, GFP_KERNEL);
+	if (ZERO_OR_NULL_PTR(buf))
+		return -ENOMEM;
+
+	len += scnprintf(buf, max_len, "Schedule command window start: %d\n",
+			ctrl->host_config.common_config.dma_sched_line);
+	len += scnprintf((buf + len), max_len - len,
+			"Schedule command window width: %d\n",
+			ctrl->host_config.common_config.dma_sched_window);
+
+	if (len > max_len)
+		len = max_len;
+
+	if (copy_to_user(user_buf, buf, len)) {
+		rc = -EFAULT;
+		goto error;
+	}
+
+	*ppos += len;
+
+error:
+	kfree(buf);
+	return len;
+
+}
+
 static const struct file_operations dump_info_fops = {
 	.open = simple_open,
 	.read = debugfs_dump_info_read,
@@ -1639,6 +1753,12 @@ static const struct file_operations esd_check_mode_fops = {
 	.read = debugfs_read_esd_check_mode,
 };
 
+static const struct file_operations dsi_command_scheduling_fops = {
+	.open = simple_open,
+	.write = debugfs_update_cmd_scheduling_params,
+	.read = debugfs_read_cmd_scheduling_params,
+};
+
 static int dsi_display_debugfs_init(struct dsi_display *display)
 {
 	int rc = 0;
@@ -1690,6 +1810,18 @@ static int dsi_display_debugfs_init(struct dsi_display *display)
 		goto error_remove_dir;
 	}
 
+	dump_file = debugfs_create_file("cmd_sched_params",
+					0644,
+					dir,
+					display,
+					&dsi_command_scheduling_fops);
+	if (IS_ERR_OR_NULL(dump_file)) {
+		rc = PTR_ERR(dump_file);
+		DSI_ERR("[%s] debugfs for cmd scheduling file failed, rc=%d\n",
+		       display->name, rc);
+		goto error_remove_dir;
+	}
+
 	misr_data = debugfs_create_file("misr_data",
 					0600,
 					dir,
@@ -2855,6 +2987,12 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display,
 		m_flags |= DSI_CTRL_CMD_LAST_COMMAND;
 	}
 
+	if ((msg->flags & MIPI_DSI_MSG_CMD_DMA_SCHED) &&
+				(display->panel->panel_initialized)) {
+		flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
+		m_flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
+	}
+
 	if (display->queue_cmd_waits ||
 			msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE) {
 		flags |= DSI_CTRL_CMD_ASYNC_WAIT;
@@ -3023,6 +3161,10 @@ static ssize_t dsi_host_transfer(struct mipi_dsi_host *host,
 				msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE)
 			cmd_flags |= DSI_CTRL_CMD_ASYNC_WAIT;
 
+		if ((msg->flags & MIPI_DSI_MSG_CMD_DMA_SCHED) &&
+				(display->panel->panel_initialized))
+			cmd_flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
+
 		rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg,
 				&cmd_flags);
 		if (rc) {

+ 18 - 14
msm/dsi/dsi_panel.c

@@ -1061,7 +1061,7 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host,
 					    struct dsi_parser_utils *utils,
 					    const char *name)
 {
-	u32 val = 0;
+	u32 val = 0, line_no = 0, window = 0;
 	int rc = 0;
 	bool panel_cphy_mode = false;
 
@@ -1094,6 +1094,22 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host,
 	host->phy_type = panel_cphy_mode ? DSI_PHY_TYPE_CPHY
 						: DSI_PHY_TYPE_DPHY;
 
+	rc = utils->read_u32(utils->data, "qcom,mdss-dsi-dma-schedule-line",
+				  &line_no);
+	if (rc)
+		host->dma_sched_line = 0;
+	else
+		host->dma_sched_line = line_no;
+
+	rc = utils->read_u32(utils->data, "qcom,mdss-dsi-dma-schedule-window",
+				  &window);
+	if (rc)
+		host->dma_sched_window = 0;
+	else
+		host->dma_sched_window = window;
+
+	DSI_DEBUG("[%s] DMA scheduling parameters Line: %d Window: %d\n", name,
+			host->dma_sched_line, host->dma_sched_window);
 	return 0;
 }
 
@@ -1354,7 +1370,6 @@ static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg,
 	const char *traffic_mode;
 	u32 vc_id = 0;
 	u32 val = 0;
-	u32 line_no = 0;
 
 	rc = utils->read_u32(utils->data, "qcom,mdss-dsi-h-sync-pulse", &val);
 	if (rc) {
@@ -1417,17 +1432,6 @@ static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg,
 		cfg->vc_id = vc_id;
 	}
 
-	rc = utils->read_u32(utils->data, "qcom,mdss-dsi-dma-schedule-line",
-				  &line_no);
-	if (rc) {
-		DSI_DEBUG("[%s] set default dma scheduling line no\n", name);
-		cfg->dma_sched_line = 0x1;
-		/* do not fail since we have default value */
-		rc = 0;
-	} else {
-		cfg->dma_sched_line = line_no;
-	}
-
 error:
 	return rc;
 }
@@ -1679,7 +1683,7 @@ static int dsi_panel_create_cmd_packets(const char *data,
 		cmd[i].msg.type = data[0];
 		cmd[i].last_command = (data[1] == 1);
 		cmd[i].msg.channel = data[2];
-		cmd[i].msg.flags |= (data[3] == 1 ? MIPI_DSI_MSG_REQ_ACK : 0);
+		cmd[i].msg.flags |= data[3];
 		cmd[i].msg.ctrl = 0;
 		cmd[i].post_wait_ms = cmd[i].msg.wait_ms = data[4];
 		cmd[i].msg.tx_len = ((data[5] << 8) | (data[6]));

+ 1 - 0
msm/dsi/dsi_panel.h

@@ -35,6 +35,7 @@
  * Override to use async transfer
  */
 #define MIPI_DSI_MSG_ASYNC_OVERRIDE BIT(4)
+#define MIPI_DSI_MSG_CMD_DMA_SCHED BIT(5)
 
 enum dsi_panel_rotation {
 	DSI_PANEL_ROTATE_NONE = 0,