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

Commit c9053a44 authored by Ingrid Gallardo's avatar Ingrid Gallardo Committed by Abhijith Desai
Browse files

msm: mdss: add mdp guard window property



For some panels, the mdp kickoff transaction must
be controlled and only triggered when the scanline
is within certain region. This change adds the
support to control the scanline where the kickoff
can be triggered through panel properties and
if the scanline is not within this region, then
driver will wait for an extra delay that is also
configurable through a panel property.

Change-Id: I06bc6b03f77109adfed428b876915f59d3b5bbfd
Signed-off-by: default avatarIngrid Gallardo <ingridg@codeaurora.org>
parent 9db3a823
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -285,6 +285,35 @@ Optional properties:
					60 = 60 frames per second (default)
- qcom,mdss-dsi-panel-clockrate:	A 64 bit value specifies the panel clock speed in Hz.
					0 = default value.
- qcom,mdss-mdp-kickoff-threshold:	This property can be used to define a region
					(in terms of scanlines) where the
hardware is allowed
					to trigger a data transfer from MDP to DSI.
					If this property is used, the region must be defined setting
					two values, the low and the high thresholds:
					<low_threshold high_threshold>
					Where following condition must be met:
					low_threshold < high_threshold
					These values will be used by the driver in such way that if
					the Driver receives a request to kickoff a transfer (MDP to DSI),
					the transfer will be triggered only if the following condition
					is satisfied:
					low_threshold < scanline < high_threshold
					If the condition is not met, then the driver will delay the
					transfer by the time defined in the following property:
					"qcom,mdss-mdp-kickoff-delay".
					So in order to use this property, the delay property must
					be defined as well and greater than 0.
- qcom,mdss-mdp-kickoff-delay:	This property defines the delay in microseconds that
					the driver will delay before triggering an MDP transfer if the
					thresholds defined by the following property are not met:
					"qcom,mdss-mdp-kickoff-threshold".
					So in order to use this property, the threshold property must
					be defined as well. Note that this delay cannot be zero
					and also should not be greater than
the fps window.
					i.e. For 60fps value should not exceed
16666 uS.
- qcom,mdss-mdp-transfer-time-us:	Specifies the dsi transfer time for command mode
					panels in microseconds. Driver uses this number to adjust
					the clock rate according to the expected transfer time.
@@ -634,6 +663,8 @@ Example:
		qcom,mdss-dsi-dma-trigger = <0>;
		qcom,mdss-dsi-panel-framerate = <60>;
		qcom,mdss-dsi-panel-clockrate = <424000000>;
		qcom,mdss-mdp-kickoff-threshold = <11 2430>;
		qcom,mdss-mdp-kickoff-delay = <1000>;
		qcom,mdss-mdp-transfer-time-us = <12500>;
		qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33
					22 27 1e 03 04 00];
+44 −0
Original line number Diff line number Diff line
@@ -1064,6 +1064,48 @@ static int mdss_dsi_panel_low_power_config(struct mdss_panel_data *pdata,
	return 0;
}

static void mdss_dsi_parse_mdp_kickoff_threshold(struct device_node *np,
	struct mdss_panel_info *pinfo)
{
	int len, rc;
	const u32 *src;
	u32 tmp;
	u32 max_delay_us;

	pinfo->mdp_koff_thshold = false;
	src = of_get_property(np, "qcom,mdss-mdp-kickoff-threshold", &len);
	if (!src || (len == 0))
		return;

	rc = of_property_read_u32(np, "qcom,mdss-mdp-kickoff-delay", &tmp);
	if (!rc)
		pinfo->mdp_koff_delay = tmp;
	else
		return;

	if (pinfo->mipi.frame_rate == 0) {
		pr_err("cannot enable guard window, unexpected panel fps\n");
		return;
	}

	pinfo->mdp_koff_thshold_low = be32_to_cpu(src[0]);
	pinfo->mdp_koff_thshold_high = be32_to_cpu(src[1]);
	max_delay_us = 1000000 / pinfo->mipi.frame_rate;

	/* enable the feature if threshold is valid */
	if ((pinfo->mdp_koff_thshold_low < pinfo->mdp_koff_thshold_high) &&
	   ((pinfo->mdp_koff_delay > 0) ||
	    (pinfo->mdp_koff_delay < max_delay_us)))
		pinfo->mdp_koff_thshold = true;

	pr_debug("panel kickoff thshold:[%d, %d] delay:%d (max:%d) enable:%d\n",
		pinfo->mdp_koff_thshold_low,
		pinfo->mdp_koff_thshold_high,
		pinfo->mdp_koff_delay,
		max_delay_us,
		pinfo->mdp_koff_thshold);
}

static void mdss_dsi_parse_trigger(struct device_node *np, char *trigger,
		char *trigger_key)
{
@@ -2845,6 +2887,8 @@ static int mdss_panel_parse_dt(struct device_node *np,
	rc = of_property_read_u32(np, "qcom,mdss-mdp-transfer-time-us", &tmp);
	pinfo->mdp_transfer_time_us = (!rc ? tmp : DEFAULT_MDP_TRANSFER_TIME);

	mdss_dsi_parse_mdp_kickoff_threshold(np, pinfo);

	pinfo->mipi.lp11_init = of_property_read_bool(np,
					"qcom,mdss-dsi-lp11-init");
	rc = of_property_read_u32(np, "qcom,mdss-dsi-init-delay-us", &tmp);
+71 −13
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ struct mdss_mdp_cmd_ctx {
	struct mutex clk_mtx;
	spinlock_t clk_lock;
	spinlock_t koff_lock;
	spinlock_t ctlstart_lock;
	struct work_struct gate_clk_work;
	struct delayed_work delayed_off_clk_work;
	struct work_struct pp_done_work;
@@ -147,26 +148,20 @@ static inline u32 mdss_mdp_cmd_line_count(struct mdss_mdp_ctl *ctl)
	u32 init;
	u32 height;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);

	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
	if (!mixer) {
		mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
		if (!mixer) {
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
		if (!mixer)
			goto exit;
	}
	}

	init = mdss_mdp_pingpong_read(mixer->pingpong_base,
		MDSS_MDP_REG_PP_VSYNC_INIT_VAL) & 0xffff;
	height = mdss_mdp_pingpong_read(mixer->pingpong_base,
		MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT) & 0xffff;

	if (height < init) {
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
	if (height < init)
		goto exit;
	}

	cnt = mdss_mdp_pingpong_read(mixer->pingpong_base,
		MDSS_MDP_REG_PP_INT_COUNT_VAL) & 0xffff;
@@ -176,13 +171,21 @@ static inline u32 mdss_mdp_cmd_line_count(struct mdss_mdp_ctl *ctl)
	else
		cnt -= init;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

	pr_debug("cnt=%d init=%d height=%d\n", cnt, init, height);
exit:
	return cnt;
}

static inline u32 mdss_mdp_cmd_line_count_wrapper(struct mdss_mdp_ctl *ctl)
{
	u32 ret;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	ret = mdss_mdp_cmd_line_count(ctl);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
	return ret;
}

static int mdss_mdp_tearcheck_enable(struct mdss_mdp_ctl *ctl, bool enable)
{
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -2643,12 +2646,42 @@ static int mdss_mdp_disable_autorefresh(struct mdss_mdp_ctl *ctl,
	return 0;
}

static bool wait_for_read_ptr_if_late(struct mdss_mdp_ctl *ctl,
	struct mdss_mdp_ctl *sctl, struct mdss_panel_info *pinfo)
{
	u32 line_count;
	u32 sline_count = 0;
	bool ret = true;
	u32 low_threshold = pinfo->mdp_koff_thshold_low;
	u32 high_threshold = pinfo->mdp_koff_thshold_high;

	/* read the line count */
	line_count = mdss_mdp_cmd_line_count(ctl);
	if (sctl)
		sline_count = mdss_mdp_cmd_line_count(sctl);

	/* if line count is between the range, return to trigger transfer */
	if (((line_count > low_threshold) && (line_count < high_threshold)) &&
	     (!sctl || ((sline_count > low_threshold) &&
			(sline_count < high_threshold))))
		ret = false;

	pr_debug("threshold:[%d, %d]\n", low_threshold, high_threshold);
	pr_debug("line:%d sline:%d ret:%d\n", line_count, sline_count, ret);
	MDSS_XLOG(line_count, sline_count, ret);

	return ret;
}

static void __mdss_mdp_kickoff(struct mdss_mdp_ctl *ctl,
	struct mdss_mdp_cmd_ctx *ctx)
	struct mdss_mdp_ctl *sctl, struct mdss_mdp_cmd_ctx *ctx)
{
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	bool is_pp_split = is_pingpong_split(ctl->mfd);
	struct mdss_panel_info *pinfo = NULL;

	if (ctl->panel_data)
		pinfo = &ctl->panel_data->panel_info;

	MDSS_XLOG(ctx->autorefresh_state);

@@ -2673,9 +2706,33 @@ static void __mdss_mdp_kickoff(struct mdss_mdp_ctl *ctl,
		ctx->autorefresh_state = MDP_AUTOREFRESH_ON;

	} else {

		/*
		 * Some panels can require that mdp is within some range
		 * of the scanlines in order to trigger the tansfer.
		 * If that is the case, make  sure the panel scanline
		 * is within the limit to start.
		 * Acquire an spinlock for this operation to raise the
		 * priority of this thread and make sure the context
		 * is maintained, so we can have the less time possible
		 * between the check of the scanline and the kickoff.
		 */
		if (pinfo && pinfo->mdp_koff_thshold) {
			spin_lock(&ctx->ctlstart_lock);
			if (wait_for_read_ptr_if_late(ctl, sctl, pinfo)) {
				spin_unlock(&ctx->ctlstart_lock);
				usleep_range(pinfo->mdp_koff_delay,
						pinfo->mdp_koff_delay + 10);
				spin_lock(&ctx->ctlstart_lock);
			}
		}

		/* SW Kickoff */
		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
		MDSS_XLOG(0x11, ctx->autorefresh_state);

		if (pinfo && pinfo->mdp_koff_thshold)
			spin_unlock(&ctx->ctlstart_lock);
	}
}

@@ -2807,7 +2864,7 @@ static int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
	}

	/* Kickoff */
	__mdss_mdp_kickoff(ctl, ctx);
	__mdss_mdp_kickoff(ctl, sctl, ctx);

	mdss_mdp_cmd_post_programming(ctl);

@@ -3241,6 +3298,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
	init_completion(&ctx->autorefresh_done);
	spin_lock_init(&ctx->clk_lock);
	spin_lock_init(&ctx->koff_lock);
	spin_lock_init(&ctx->ctlstart_lock);
	mutex_init(&ctx->clk_mtx);
	mutex_init(&ctx->mdp_rdptr_lock);
	mutex_init(&ctx->mdp_wrptr_lock);
@@ -3529,7 +3587,7 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
	ctl->ops.wait_pingpong = mdss_mdp_cmd_wait4pingpong;
	ctl->ops.add_vsync_handler = mdss_mdp_cmd_add_vsync_handler;
	ctl->ops.remove_vsync_handler = mdss_mdp_cmd_remove_vsync_handler;
	ctl->ops.read_line_cnt_fnc = mdss_mdp_cmd_line_count;
	ctl->ops.read_line_cnt_fnc = mdss_mdp_cmd_line_count_wrapper;
	ctl->ops.restore_fnc = mdss_mdp_cmd_restore;
	ctl->ops.early_wake_up_fnc = mdss_mdp_cmd_early_wake_up;
	ctl->ops.reconfigure = mdss_mdp_cmd_reconfigure;
+4 −0
Original line number Diff line number Diff line
@@ -672,6 +672,10 @@ struct mdss_panel_info {
	u32 saved_fporch;
	/* current fps, once is programmed in hw */
	int current_fps;
	u32 mdp_koff_thshold_low;
	u32 mdp_koff_thshold_high;
	bool mdp_koff_thshold;
	u32 mdp_koff_delay;

	int panel_max_fps;
	int panel_max_vtotal;