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

Commit 2a4c5f87 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: delay dma commands for split-dsi cmd mode panels"

parents cebc2fd1 3a8db755
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -181,6 +181,7 @@ static ssize_t panel_debug_base_reg_write(struct file *file,
	if (mdata->debug_inf.debug_enable_clock)
	if (mdata->debug_inf.debug_enable_clock)
		mdata->debug_inf.debug_enable_clock(1);
		mdata->debug_inf.debug_enable_clock(1);


	if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)
		mdss_dsi_cmdlist_put(ctrl_pdata, &cmdreq);
		mdss_dsi_cmdlist_put(ctrl_pdata, &cmdreq);


	if (mdata->debug_inf.debug_enable_clock)
	if (mdata->debug_inf.debug_enable_clock)
+15 −1
Original line number Original line Diff line number Diff line
@@ -1483,7 +1483,6 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
			}
			}
			ATRACE_END("dsi_panel_on");
			ATRACE_END("dsi_panel_on");
		}
		}
		ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
	}
	}


	if ((pdata->panel_info.type == MIPI_CMD_PANEL) &&
	if ((pdata->panel_info.type == MIPI_CMD_PANEL) &&
@@ -1493,6 +1492,8 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
			enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio));
			enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio));
	}
	}


	ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;

error:
error:
	mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle,
	mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle,
			  MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_OFF);
			  MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_OFF);
@@ -2343,6 +2344,15 @@ int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
	return 0;
	return 0;
}
}


static int mdss_dsi_register_mdp_callback(struct mdss_dsi_ctrl_pdata *ctrl,
	struct mdss_intf_recovery *mdp_callback)
{
	mutex_lock(&ctrl->mutex);
	ctrl->mdp_callback = mdp_callback;
	mutex_unlock(&ctrl->mutex);
	return 0;
}

static struct device_node *mdss_dsi_get_fb_node_cb(struct platform_device *pdev)
static struct device_node *mdss_dsi_get_fb_node_cb(struct platform_device *pdev)
{
{
	struct device_node *fb_node;
	struct device_node *fb_node;
@@ -2493,6 +2503,10 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
		rc = mdss_dsi_register_recovery_handler(ctrl_pdata,
		rc = mdss_dsi_register_recovery_handler(ctrl_pdata,
			(struct mdss_intf_recovery *)arg);
			(struct mdss_intf_recovery *)arg);
		break;
		break;
	case MDSS_EVENT_REGISTER_MDP_CALLBACK:
		rc = mdss_dsi_register_mdp_callback(ctrl_pdata,
			(struct mdss_intf_recovery *)arg);
		break;
	case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
	case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
		mode = (u32)(unsigned long) arg;
		mode = (u32)(unsigned long) arg;
		mdss_dsi_switch_mode(pdata, mode);
		mdss_dsi_switch_mode(pdata, mode);
+1 −0
Original line number Original line Diff line number Diff line
@@ -456,6 +456,7 @@ struct mdss_dsi_ctrl_pdata {
	u32 dsi_irq_mask;
	u32 dsi_irq_mask;
	struct mdss_hw *dsi_hw;
	struct mdss_hw *dsi_hw;
	struct mdss_intf_recovery *recovery;
	struct mdss_intf_recovery *recovery;
	struct mdss_intf_recovery *mdp_callback;


	struct dsi_panel_cmds on_cmds;
	struct dsi_panel_cmds on_cmds;
	struct dsi_panel_cmds post_dms_on_cmds;
	struct dsi_panel_cmds post_dms_on_cmds;
+54 −0
Original line number Original line Diff line number Diff line
@@ -2479,6 +2479,49 @@ int mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
	return len;
	return len;
}
}


static inline bool mdss_dsi_delay_cmd(struct mdss_dsi_ctrl_pdata *ctrl,
	bool from_mdp)
{
	unsigned long flags;
	bool mdp_busy = false;
	bool need_wait = false;

	if (!ctrl->mdp_callback)
		goto exit;

	/* delay only for split dsi, cmd mode and burst mode enabled cases */
	if (!mdss_dsi_is_hw_config_split(ctrl->shared_data) ||
	    !(ctrl->panel_mode == DSI_CMD_MODE) ||
	    !ctrl->burst_mode_enabled)
		goto exit;

	/* delay only if cmd is not from mdp and panel has been initialized */
	if (from_mdp || !(ctrl->ctrl_state & CTRL_STATE_PANEL_INIT))
		goto exit;

	/* if broadcast enabled, apply delay only if this is the ctrl trigger */
	if (mdss_dsi_sync_wait_enable(ctrl) &&
	   !mdss_dsi_sync_wait_trigger(ctrl))
		goto exit;

	spin_lock_irqsave(&ctrl->mdp_lock, flags);
	if (ctrl->mdp_busy == true)
		mdp_busy = true;
	spin_unlock_irqrestore(&ctrl->mdp_lock, flags);

	/*
	 * apply delay only if:
	 *  mdp_busy bool is set - kickoff is being scheduled by sw
	 *  MDP_BUSY bit  is not set - transfer is not on-going in hw yet
	 */
	if (mdp_busy && !(MIPI_INP(ctrl->ctrl_base + 0x008) & BIT(2)))
		need_wait = true;

exit:
	MDSS_XLOG(need_wait, from_mdp, mdp_busy);
	return need_wait;
}

int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
{
{
	struct dcs_cmd_req *req;
	struct dcs_cmd_req *req;
@@ -2581,6 +2624,17 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
	mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle, MDSS_DSI_ALL_CLKS,
	mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle, MDSS_DSI_ALL_CLKS,
			  MDSS_DSI_CLK_ON);
			  MDSS_DSI_CLK_ON);


	/*
	 * In ping pong split cases, check if we need to apply a
	 * delay for any commands that are not coming from
	 * mdp path
	 */
	mutex_lock(&ctrl->mutex);
	if (mdss_dsi_delay_cmd(ctrl, from_mdp))
		ctrl->mdp_callback->fxn(ctrl->mdp_callback->data,
			MDP_INTF_CALLBACK_DSI_WAIT);
	mutex_unlock(&ctrl->mutex);

	if (req->flags & CMD_REQ_HS_MODE)
	if (req->flags & CMD_REQ_HS_MODE)
		mdss_dsi_set_tx_power_mode(0, &ctrl->panel_data);
		mdss_dsi_set_tx_power_mode(0, &ctrl->panel_data);


+120 −0
Original line number Original line Diff line number Diff line
@@ -13,6 +13,8 @@


#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/pm_runtime.h>
#include <linux/pm_runtime.h>
#include <linux/iopoll.h>
#include <linux/delay.h>


#include "mdss_mdp.h"
#include "mdss_mdp.h"
#include "mdss_panel.h"
#include "mdss_panel.h"
@@ -57,6 +59,8 @@ struct mdss_mdp_cmd_ctx {


	u8 ref_cnt;
	u8 ref_cnt;
	struct completion stop_comp;
	struct completion stop_comp;
	atomic_t rdptr_cnt;
	wait_queue_head_t rdptr_waitq;
	struct completion pp_done;
	struct completion pp_done;
	wait_queue_head_t pp_waitq;
	wait_queue_head_t pp_waitq;
	struct list_head vsync_handlers;
	struct list_head vsync_handlers;
@@ -88,6 +92,7 @@ struct mdss_mdp_cmd_ctx {
	int vsync_irq_cnt;
	int vsync_irq_cnt;


	struct mdss_intf_recovery intf_recovery;
	struct mdss_intf_recovery intf_recovery;
	struct mdss_intf_recovery intf_mdp_callback;
	struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
	struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
	u32 pp_timeout_report_cnt;
	u32 pp_timeout_report_cnt;
	bool pingpong_split_slave;
	bool pingpong_split_slave;
@@ -101,6 +106,7 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx);
static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg);
static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg);
static int mdss_mdp_disable_autorefresh(struct mdss_mdp_ctl *ctl,
static int mdss_mdp_disable_autorefresh(struct mdss_mdp_ctl *ctl,
	struct mdss_mdp_ctl *sctl);
	struct mdss_mdp_ctl *sctl);
static int mdss_mdp_setup_vsync(struct mdss_mdp_cmd_ctx *ctx, bool enable);


static bool __mdss_mdp_cmd_is_aux_pp_needed(struct mdss_data_type *mdata,
static bool __mdss_mdp_cmd_is_aux_pp_needed(struct mdss_data_type *mdata,
	struct mdss_mdp_ctl *mctl)
	struct mdss_mdp_ctl *mctl)
@@ -959,6 +965,17 @@ static void mdss_mdp_cmd_readptr_done(void *arg)
	MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt));
	MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt));
	complete_all(&ctx->rdptr_done);
	complete_all(&ctx->rdptr_done);


	/* If caller is waiting for the read pointer, notify. */
	if (atomic_read(&ctx->rdptr_cnt)) {
		if (atomic_add_unless(&ctx->rdptr_cnt, -1, 0)) {
			MDSS_XLOG(atomic_read(&ctx->rdptr_cnt));
			if (atomic_read(&ctx->rdptr_cnt))
				pr_warn("%s: too many rdptrs=%d!\n",
				  __func__, atomic_read(&ctx->rdptr_cnt));
		}
		wake_up_all(&ctx->rdptr_waitq);
	}

	spin_lock(&ctx->clk_lock);
	spin_lock(&ctx->clk_lock);
	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
		if (tmp->enabled && !tmp->cmd_post_flush)
		if (tmp->enabled && !tmp->cmd_post_flush)
@@ -967,6 +984,82 @@ static void mdss_mdp_cmd_readptr_done(void *arg)
	spin_unlock(&ctx->clk_lock);
	spin_unlock(&ctx->clk_lock);
}
}


static int mdss_mdp_cmd_wait4readptr(struct mdss_mdp_cmd_ctx *ctx)
{
	int rc = 0;

	rc = wait_event_timeout(ctx->rdptr_waitq,
			atomic_read(&ctx->rdptr_cnt) == 0,
			KOFF_TIMEOUT);
	if (rc <= 0) {
		if (atomic_read(&ctx->rdptr_cnt))
			pr_err("timed out waiting for rdptr irq\n");
		else
			rc = 1;
	}
	return rc;
}

static void mdss_mdp_cmd_intf_callback(void *data, int event)
{
	struct mdss_mdp_cmd_ctx *ctx = data;
	struct mdss_mdp_pp_tear_check *te = NULL;
	u32 timeout_us = 3000, val = 0;
	struct mdss_mdp_mixer *mixer;

	if (!data) {
		pr_err("%s: invalid ctx\n", __func__);
		return;
	}

	if (!ctx->ctl)
		return;

	switch (event) {
	case MDP_INTF_CALLBACK_DSI_WAIT:
		pr_debug("%s: wait for frame cnt:%d event:%d\n",
			__func__, atomic_read(&ctx->rdptr_cnt), event);

		/*
		 * if we are going to suspended or pp split is not enabled,
		 * just return
		 */
		if (ctx->intf_stopped || !is_pingpong_split(ctx->ctl->mfd))
			return;
		atomic_inc(&ctx->rdptr_cnt);

		/* enable clks and rd_ptr interrupt */
		mdss_mdp_setup_vsync(ctx, true);

		mixer = mdss_mdp_mixer_get(ctx->ctl, MDSS_MDP_MIXER_MUX_LEFT);
		if (!mixer) {
			pr_err("%s: null mixer\n", __func__);
			return;
		}

		/* wait for read pointer */
		MDSS_XLOG(atomic_read(&ctx->rdptr_cnt));
		pr_debug("%s: wait for frame cnt:%d\n",
			__func__, atomic_read(&ctx->rdptr_cnt));
		mdss_mdp_cmd_wait4readptr(ctx);

		/* wait for 3ms to make sure we are within the frame */
		te = &ctx->ctl->panel_data->panel_info.te;
		readl_poll_timeout(mixer->pingpong_base +
			MDSS_MDP_REG_PP_INT_COUNT_VAL, val,
			(val & 0xffff) > (te->start_pos +
			te->sync_threshold_start), 10, timeout_us);

		/* disable rd_ptr interrupt */
		mdss_mdp_setup_vsync(ctx, false);

		break;
	default:
		pr_debug("%s: unhandled event=%d\n", __func__, event);
		break;
	}
}

static void mdss_mdp_cmd_intf_recovery(void *data, int event)
static void mdss_mdp_cmd_intf_recovery(void *data, int event)
{
{
	struct mdss_mdp_cmd_ctx *ctx = data;
	struct mdss_mdp_cmd_ctx *ctx = data;
@@ -1757,6 +1850,11 @@ static int mdss_mdp_cmd_panel_on(struct mdss_mdp_ctl *ctl,
			(void *)&ctx->intf_recovery,
			(void *)&ctx->intf_recovery,
			CTL_INTF_EVENT_FLAG_DEFAULT);
			CTL_INTF_EVENT_FLAG_DEFAULT);


		mdss_mdp_ctl_intf_event(ctl,
			MDSS_EVENT_REGISTER_MDP_CALLBACK,
			(void *)&ctx->intf_mdp_callback,
			CTL_INTF_EVENT_FLAG_DEFAULT);

		ctx->intf_stopped = 0;
		ctx->intf_stopped = 0;
		if (sctx)
		if (sctx)
			sctx->intf_stopped = 0;
			sctx->intf_stopped = 0;
@@ -2438,6 +2536,14 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl,
	/* intf stopped,  no more kickoff */
	/* intf stopped,  no more kickoff */
	ctx->intf_stopped = 1;
	ctx->intf_stopped = 1;


	/* Make sure any rd ptr for dsi callback is done before disable vsync */
	if (is_pingpong_split(ctl->mfd)) {
		pr_debug("%s will wait for rd ptr:%d\n", __func__,
			atomic_read(&ctx->rdptr_cnt));
		MDSS_XLOG(atomic_read(&ctx->rdptr_cnt));
		mdss_mdp_cmd_wait4readptr(ctx);
	}

	/*
	/*
	 * if any vsyncs are still enabled, loop until the refcount
	 * if any vsyncs are still enabled, loop until the refcount
	 * goes to zero, so the rd ptr interrupt is disabled.
	 * goes to zero, so the rd ptr interrupt is disabled.
@@ -2455,6 +2561,10 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl,
		mdss_mdp_ctl_intf_event(ctl,
		mdss_mdp_ctl_intf_event(ctl,
			MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
			MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
			NULL, CTL_INTF_EVENT_FLAG_DEFAULT);
			NULL, CTL_INTF_EVENT_FLAG_DEFAULT);

		mdss_mdp_ctl_intf_event(ctl,
			MDSS_EVENT_REGISTER_MDP_CALLBACK,
			NULL, CTL_INTF_EVENT_FLAG_DEFAULT);
	}
	}


	/* shut down the MDP/DSI resources if still enabled */
	/* shut down the MDP/DSI resources if still enabled */
@@ -2608,6 +2718,12 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
				MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
				MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
				(void *)&ctx->intf_recovery,
				(void *)&ctx->intf_recovery,
				CTL_INTF_EVENT_FLAG_DEFAULT);
				CTL_INTF_EVENT_FLAG_DEFAULT);

			mdss_mdp_ctl_intf_event(ctl,
				MDSS_EVENT_REGISTER_MDP_CALLBACK,
				(void *)&ctx->intf_mdp_callback,
				CTL_INTF_EVENT_FLAG_DEFAULT);

			ctx->intf_stopped = 0;
			ctx->intf_stopped = 0;
			if (sctx)
			if (sctx)
				sctx->intf_stopped = 0;
				sctx->intf_stopped = 0;
@@ -2762,6 +2878,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
	ctx->pingpong_split_slave = pingpong_split_slave;
	ctx->pingpong_split_slave = pingpong_split_slave;
	ctx->pp_timeout_report_cnt = 0;
	ctx->pp_timeout_report_cnt = 0;
	init_waitqueue_head(&ctx->pp_waitq);
	init_waitqueue_head(&ctx->pp_waitq);
	init_waitqueue_head(&ctx->rdptr_waitq);
	init_completion(&ctx->stop_comp);
	init_completion(&ctx->stop_comp);
	init_completion(&ctx->autorefresh_ppdone);
	init_completion(&ctx->autorefresh_ppdone);
	init_completion(&ctx->rdptr_done);
	init_completion(&ctx->rdptr_done);
@@ -2784,6 +2901,9 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
	ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery;
	ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery;
	ctx->intf_recovery.data = ctx;
	ctx->intf_recovery.data = ctx;


	ctx->intf_mdp_callback.fxn = mdss_mdp_cmd_intf_callback;
	ctx->intf_mdp_callback.data = ctx;

	ctx->intf_stopped = 0;
	ctx->intf_stopped = 0;


	pr_debug("%s: ctx=%p num=%d aux=%d\n", __func__, ctx,
	pr_debug("%s: ctx=%p num=%d aux=%d\n", __func__, ctx,
Loading