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

Commit beea6cd2 authored by Harigovindan P's avatar Harigovindan P Committed by Gerrit - the friendly Code Review server
Browse files

disp: msm: read mdp intf line count and trigger dma accordingly



This change reads the video line count from
MDP_INTF_LINE_COUNT register and checks whether
DMA trigger happens close to the schedule line.
If it is not close to the schedule line, then DMA
command transfer is triggered. Without this change
there is a chance that when 2 DSI's with broadcast,
schedule enabled, the DMA command gets triggered close
to the schedule line which could cause DMA timeout.

Change-Id: Ida92e63e46b4cc703d57ce24097834f810776aa8
Signed-off-by: default avatarHarigovindan P <harigovi@codeaurora.org>
parent d0f5c748
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/errno.h>
@@ -81,6 +81,8 @@ 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.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;
@@ -96,6 +98,8 @@ 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.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 +120,8 @@ 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.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;
+6 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */

#ifndef _DSI_CATALOG_H_
@@ -270,4 +270,9 @@ 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);

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_ */
+71 −10
Original line number Diff line number Diff line
@@ -1219,6 +1219,24 @@ int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl,

	return rc;
}
static u32 calculate_schedule_line(struct dsi_ctrl *dsi_ctrl, u32 flags)
{
	u32 line_no = 0x1;
	struct dsi_mode_info *timing;

	/* 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;

	return line_no;
}

static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
				const struct mipi_dsi_msg *msg,
@@ -1228,20 +1246,13 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
{
	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,
		msg->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;
	line_no = calculate_schedule_line(dsi_ctrl, flags);

	if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
		dsi_hw_ops.schedule_dma_cmd &&
		(dsi_ctrl->current_state.vid_engine_state ==
@@ -1249,6 +1260,8 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
		dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw,
				line_no);

	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;

@@ -1967,6 +1980,9 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev)
		DSI_CTRL_DEBUG(dsi_ctrl, "failed to init axi bus client, rc = %d\n",
				rc);

	if (dsi_ctrl->hw.ops.map_mdp_regs)
		dsi_ctrl->hw.ops.map_mdp_regs(pdev, &dsi_ctrl->hw);

	item->ctrl = dsi_ctrl;

	mutex_lock(&dsi_ctrl_list_lock);
@@ -3298,6 +3314,10 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
{
	int rc = 0;
	struct dsi_ctrl_hw_ops dsi_hw_ops;
	u32 v_total = 0, fps = 0, cur_line = 0, mem_latency_us = 100;
	u32 line_time = 0, schedule_line = 0x1, latency_by_line = 0;
	struct dsi_mode_info *timing;
	unsigned long flag;

	if (!dsi_ctrl) {
		DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n");
@@ -3313,6 +3333,18 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)

	mutex_lock(&dsi_ctrl->ctrl_lock);

	timing = &(dsi_ctrl->host_config.video_timing);

	if (timing &&
		(dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)) {
		v_total = timing->v_sync_width + timing->v_back_porch +
			timing->v_front_porch + timing->v_active;
		fps = timing->refresh_rate;
		schedule_line = calculate_schedule_line(dsi_ctrl, flags);
		line_time = (1000000 / fps) / v_total;
		latency_by_line = CEIL(mem_latency_us, line_time);
	}

	if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER))
		dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw);

@@ -3325,7 +3357,36 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
		reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done);

		/* trigger command */
		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)) {
			/*
			 * This change reads the video line count from
			 * MDP_INTF_LINE_COUNT register and checks whether
			 * DMA trigger happens close to the schedule line.
			 * If it is not close to the schedule line, then DMA
			 * command transfer is triggered.
			 */
			while (1) {
				local_irq_save(flag);
				cur_line =
				dsi_hw_ops.log_line_count(&dsi_ctrl->hw,
					dsi_ctrl->cmd_mode);
				if (cur_line <
					(schedule_line - latency_by_line) ||
					cur_line > (schedule_line + 1)) {
					dsi_hw_ops.trigger_command_dma(
						&dsi_ctrl->hw);
					local_irq_restore(flag);
					break;
				}
				local_irq_restore(flag);
				udelay(1000);
			}
		} else
			dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw);

		if (flags & DSI_CTRL_CMD_ASYNC_WAIT) {
			dsi_ctrl->dma_wait_queued = true;
			queue_work(dsi_ctrl->dma_cmd_workq,
+3 −0
Original line number Diff line number Diff line
@@ -239,6 +239,8 @@ 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.
 * @cmd_mode:		Boolean to indicate if panel is running in
			command mode.
 */
struct dsi_ctrl {
	struct platform_device *pdev;
@@ -299,6 +301,7 @@ struct dsi_ctrl {
	bool null_insertion_enabled;
	bool modeupdated;
	bool split_link_supported;
	bool cmd_mode;
};

/**
+25 −0
Original line number Diff line number Diff line
@@ -838,6 +838,22 @@ 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.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);
};

/*
@@ -848,6 +864,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
@@ -865,6 +888,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;

Loading