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

Commit 011fe635 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: fix race conditions when enabling mdp clocks"

parents 9c14640e cf79fd81
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -807,7 +807,7 @@ static void mdss_fb_input_event_handler(struct input_handle *handle,
	struct msm_fb_data_type *mfd = handle->handler->private;
	int rc;

	if (type != EV_ABS)
	if ((type != EV_ABS) || !mdss_fb_is_power_on(mfd))
		return;

	if (mfd->mdp.input_event_handler) {
+24 −13
Original line number Diff line number Diff line
@@ -631,15 +631,20 @@ static int mdss_mdp_clk_update(u32 clk_idx, u32 enable)
	return ret;
}

int mdss_mdp_vsync_clk_enable(int enable)
int mdss_mdp_vsync_clk_enable(int enable, bool locked)
{
	int ret = 0;
	pr_debug("clk enable=%d\n", enable);

	if (!locked)
		mutex_lock(&mdp_clk_lock);

	if (mdss_res->vsync_ena != enable) {
		mdss_res->vsync_ena = enable;
		ret = mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
	}

	if (!locked)
		mutex_unlock(&mdp_clk_lock);
	return ret;
}
@@ -673,14 +678,20 @@ void mdss_mdp_set_clk_rate(unsigned long rate)
	}
}

unsigned long mdss_mdp_get_clk_rate(u32 clk_idx)
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx, bool locked)
{
	unsigned long clk_rate = 0;
	struct clk *clk = mdss_mdp_get_clk(clk_idx);

	if (clk) {
		if (!locked)
			mutex_lock(&mdp_clk_lock);
	if (clk)

		clk_rate = clk_get_rate(clk);

		if (!locked)
			mutex_unlock(&mdp_clk_lock);
	}

	return clk_rate;
}
@@ -827,7 +838,7 @@ static int mdss_mdp_idle_pc_restore(void)
	}
	mdss_hw_init(mdata);
	mdss_iommu_ctrl(0);
	mdss_mdp_ctl_restore();
	mdss_mdp_ctl_restore(true);
	mdata->idle_pc = false;

end:
@@ -956,10 +967,10 @@ void mdss_mdp_clk_ctrl(int enable)
		}
	}

	mutex_unlock(&mdp_clk_lock);

	if (enable && changed)
		mdss_mdp_idle_pc_restore();

	mutex_unlock(&mdp_clk_lock);
}

static inline int mdss_mdp_irq_clk_register(struct mdss_data_type *mdata,
@@ -1093,7 +1104,7 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata)
	/* Setting the default clock rate to the max supported.*/
	mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate);
	pr_debug("mdp clk rate=%ld\n",
		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_CORE));
		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_CORE, false));

	return 0;
}
@@ -1226,10 +1237,8 @@ static void mdss_hw_rev_init(struct mdss_data_type *mdata)
	if (mdata->mdp_rev)
		return;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	mdata->mdp_rev = MDSS_REG_READ(mdata, MDSS_REG_HW_VERSION);
	mdss_mdp_hw_rev_caps_init(mdata);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
}

/**
@@ -1502,7 +1511,9 @@ static ssize_t mdss_mdp_show_capabilities(struct device *dev,
#define SPRINT(fmt, ...) \
		(cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	mdss_hw_rev_init(mdata);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

	SPRINT("mdp_version=5\n");
	SPRINT("hw_rev=%d\n", mdata->mdp_rev);
+4 −4
Original line number Diff line number Diff line
@@ -235,7 +235,7 @@ struct mdss_mdp_ctl_intfs_ops {
					struct mdss_mdp_vsync_handler *);
	int (*config_fps_fnc)(struct mdss_mdp_ctl *ctl,
				struct mdss_mdp_ctl *sctl, int new_fps);
	int (*restore_fnc)(struct mdss_mdp_ctl *ctl);
	int (*restore_fnc)(struct mdss_mdp_ctl *ctl, bool locked);
	int (*early_wake_up_fnc)(struct mdss_mdp_ctl *ctl);

	/*
@@ -990,8 +990,8 @@ int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
void mdss_mdp_footswitch_ctrl_splash(int on);
void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable);
void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
int mdss_mdp_vsync_clk_enable(int enable);
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx, bool locked);
int mdss_mdp_vsync_clk_enable(int enable, bool locked);
void mdss_mdp_clk_ctrl(int enable);
struct mdss_data_type *mdss_mdp_get_mdata(void);
int mdss_mdp_secure_display_ctrl(unsigned int enable);
@@ -1265,7 +1265,7 @@ int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd,
void mdss_mdp_pipe_calc_pixel_extn(struct mdss_mdp_pipe *pipe);
int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable);
int mdss_mdp_wb_get_secure(struct msm_fb_data_type *mfd, uint8_t *enable);
void mdss_mdp_ctl_restore(void);
void mdss_mdp_ctl_restore(bool locked);
int  mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl);
int mdss_mdp_wait_for_xin_halt(u32 xin_id, bool is_vbif_nrt);
void mdss_mdp_set_ot_limit(struct mdss_mdp_set_ot_params *params);
+9 −4
Original line number Diff line number Diff line
@@ -3144,19 +3144,25 @@ static void mdss_mdp_ctl_restore_sub(struct mdss_mdp_ctl *ctl)

/*
 * mdss_mdp_ctl_restore() - restore mdp ctl path
 * @locked - boolean to signal that clock lock is already acquired
 *
 * This function is called whenever MDP comes out of a power collapse as
 * a result of a screen update. It restores the MDP controller's software
 * state to the hardware registers.
 * Function does not enable the clocks, so caller must make sure
 * clocks are enabled before calling.
 * The locked boolean in the parametrs signals that synchronization
 * with mdp clocks access is not required downstream.
 * Only call this function setting this value to true if the clocks access
 * synchronization is guaranteed by the caller.
 */
void mdss_mdp_ctl_restore(void)
void mdss_mdp_ctl_restore(bool locked)
{
	struct mdss_mdp_ctl *ctl = NULL;
	struct mdss_mdp_ctl *sctl;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	u32 cnum;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	for (cnum = MDSS_MDP_CTL0; cnum < mdata->nctl; cnum++) {
		ctl = mdata->ctl_off + cnum;
		if (!mdss_mdp_ctl_is_power_on(ctl))
@@ -3172,9 +3178,8 @@ void mdss_mdp_ctl_restore(void)
			mdss_mdp_ctl_split_display_enable(1, ctl, sctl);
		}
		if (ctl->ops.restore_fnc)
			ctl->ops.restore_fnc(ctl);
			ctl->ops.restore_fnc(ctl, locked);
	}
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
}

static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
+58 −48
Original line number Diff line number Diff line
@@ -179,7 +179,7 @@ static int mdss_mdp_tearcheck_enable(struct mdss_mdp_ctl *ctl, bool enable)
}

static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
		struct mdss_mdp_cmd_ctx *ctx)
		struct mdss_mdp_cmd_ctx *ctx, bool locked)
{
	struct mdss_mdp_pp_tear_check *te = NULL;
	struct mdss_panel_info *pinfo;
@@ -196,10 +196,10 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
	pinfo = &ctl->panel_data->panel_info;
	te = &ctl->panel_data->panel_info.te;

	mdss_mdp_vsync_clk_enable(1);
	mdss_mdp_vsync_clk_enable(1, locked);

	vsync_clk_speed_hz =
		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC);
		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC, locked);

	total_lines = mdss_panel_get_vtotal(pinfo);

@@ -258,7 +258,8 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
	return 0;
}

static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx)
static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx,
		bool locked)
{
	int rc = 0;
	struct mdss_mdp_mixer *mixer;
@@ -267,7 +268,7 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx)

	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
	if (mixer) {
		rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx);
		rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, locked);
		if (rc)
			goto err;
	}
@@ -276,7 +277,7 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx)
	    !is_dsc_compression(pinfo)) {
		mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
		if (mixer)
			rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx);
			rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, locked);
	}
err:
	return rc;
@@ -683,24 +684,32 @@ int mdss_mdp_resource_control(struct mdss_mdp_ctl *ctl, u32 sw_event)
		break;
	case MDP_RSRC_CTL_EVENT_EARLY_WAKE_UP:
		/*
		 * 1. If the current state is ON, stay in ON and cancel any
		 *    pending GATE work item.
		 * 2. If the current state is GATED, stay at GATED and cancel
		 *    any pending POWER-OFF work item.
		 * 3. If the current state is POWER-OFF, Schedule a work item to
		 *    POWER-ON.
		 * Cancel any work item pending and:
		 * 1. If the current state is ON, stay in ON.
		 * 2. If the current state is GATED, stay at GATED.
		 * 3. If the current state is POWER-OFF, POWER-ON and
		 *	schedule a work item to POWER-OFF if no
		 *	kickoffs get scheduled.
		 */
		mutex_lock(&ctl->rsrc_lock);
		if (mdp5_data->resources_state != MDP_RSRC_CTL_STATE_OFF) {

		/* if panels are off, do not process early wake up */
		if ((ctx && __mdss_mdp_cmd_is_panel_power_off(ctx)) ||
			(sctx && __mdss_mdp_cmd_is_panel_power_off(sctx)))
			break;

		/* Cancel GATE Work Item */
		if (cancel_work_sync(&ctx->gate_clk_work))
			pr_debug("%s: %s - gate_work cancelled\n",
				 __func__, get_sw_event_name(sw_event));

		/* Cancel OFF Work Item */
		if (cancel_delayed_work_sync(
				&ctx->delayed_off_clk_work))
			pr_debug("%s: %s - off work cancelled\n",
				 __func__, get_sw_event_name(sw_event));
		} else {

		mutex_lock(&ctl->rsrc_lock);
		if (mdp5_data->resources_state == MDP_RSRC_CTL_STATE_OFF) {
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
			mdss_mdp_ctl_intf_event(ctx->ctl,
						MDSS_EVENT_PANEL_CLK_CTRL,
@@ -741,9 +750,6 @@ static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
{
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();

	if (__mdss_mdp_cmd_is_panel_power_off(ctx))
		return;

	mutex_lock(&ctx->clk_mtx);
	MDSS_XLOG(ctx->pp_num, atomic_read(&ctx->koff_cnt));

@@ -960,11 +966,15 @@ static void clk_ctrl_delayed_off_work(struct work_struct *work)
		get_clk_pwr_state_name
		(mdp5_data->resources_state));

	mutex_lock(&ctl->rsrc_lock);

	if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
		mutex_lock(&cmd_clk_mtx);

		if (mdss_mdp_get_split_display_ctls(&ctl, &sctl)) {
			/* error when getting both controllers, just returnr */
			pr_err("cannot get both controllers for the split display\n");
			return;
			goto exit;
		}

		/* re-assign to have the correct order in the context */
@@ -973,13 +983,10 @@ static void clk_ctrl_delayed_off_work(struct work_struct *work)
		if (!ctx || !sctx) {
			pr_err("invalid %s %s\n",
				ctx?"":"ctx", sctx?"":"sctx");
			return;
			goto exit;
		}
		mutex_lock(&cmd_clk_mtx);
	}

	mutex_lock(&ctl->rsrc_lock);

	if (ctx->autorefresh_init) {
		/*
		 * Driver shouldn't have scheduled this work item if
@@ -1014,12 +1021,12 @@ static void clk_ctrl_delayed_off_work(struct work_struct *work)
	mdp5_data->resources_state = MDP_RSRC_CTL_STATE_OFF;

exit:
	mutex_unlock(&ctl->rsrc_lock);

	/* do this at the end, so we can also protect the global power state*/
	if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY)
		mutex_unlock(&cmd_clk_mtx);

	mutex_unlock(&ctl->rsrc_lock);

	ATRACE_END(__func__);
}

@@ -1053,12 +1060,16 @@ static void clk_ctrl_gate_work(struct work_struct *work)
		ctl->num, get_clk_pwr_state_name
		(mdp5_data->resources_state));

	mutex_lock(&ctl->rsrc_lock);

	if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
		mutex_lock(&cmd_clk_mtx);

		if (mdss_mdp_get_split_display_ctls(&ctl, &sctl)) {
			/* error when getting both controllers, just return */
			pr_err("%s cannot get both cts for the split display\n",
				__func__);
			return;
			goto exit;
		}

		/* re-assign to have the correct order in the context */
@@ -1067,13 +1078,10 @@ static void clk_ctrl_gate_work(struct work_struct *work)
		if (!ctx || !sctx) {
			pr_err("%s ERROR invalid %s %s\n", __func__,
				ctx?"":"ctx", sctx?"":"sctx");
			return;
			goto exit;
		}
		mutex_lock(&cmd_clk_mtx);
	}

	mutex_lock(&ctl->rsrc_lock);

	if (ctx->autorefresh_init) {
		/*
		 * Driver shouldn't have scheduled this work item if
@@ -1104,12 +1112,12 @@ static void clk_ctrl_gate_work(struct work_struct *work)
	mdp5_data->resources_state = MDP_RSRC_CTL_STATE_GATE;

exit:
	mutex_unlock(&ctl->rsrc_lock);

	/* unlock mutex needed for split display */
	if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY)
		mutex_unlock(&cmd_clk_mtx);

	mutex_unlock(&ctl->rsrc_lock);

	ATRACE_END(__func__);
}

@@ -1685,17 +1693,14 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
	return 0;
}

int mdss_mdp_cmd_restore(struct mdss_mdp_ctl *ctl)
int mdss_mdp_cmd_restore(struct mdss_mdp_ctl *ctl, bool locked)
{
	pr_debug("%s: called for ctl%d\n", __func__, ctl->num);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	if (mdss_mdp_cmd_tearcheck_setup(ctl->intf_ctx[MASTER_CTX]))
	if (mdss_mdp_cmd_tearcheck_setup(ctl->intf_ctx[MASTER_CTX], locked))
		pr_warn("%s: tearcheck setup failed\n", __func__);
	else
		mdss_mdp_tearcheck_enable(ctl, true);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

	return 0;
}

@@ -2005,6 +2010,7 @@ static int mdss_mdp_cmd_early_wake_up(struct mdss_mdp_ctl *ctl)
	 * involves cancelling queued work items. So this will be
	 * scheduled in a work item.
	 */
	if (ctx)
		schedule_work(&ctx->early_wakeup_clk_work);
	return 0;
}
@@ -2052,7 +2058,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
				   mdss_mdp_cmd_pingpong_done, ctl);

	ret = mdss_mdp_cmd_tearcheck_setup(ctx);
	ret = mdss_mdp_cmd_tearcheck_setup(ctx, false);
	if (ret)
		pr_err("tearcheck setup failed\n");

@@ -2084,7 +2090,9 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
			 * explictly call the restore function to enable
			 * tearcheck logic.
			 */
			mdss_mdp_cmd_restore(ctl);
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
			mdss_mdp_cmd_restore(ctl, false);
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

			/* Turn on panel so that it can exit low power mode */
			return mdss_mdp_cmd_panel_on(ctl, sctl);
@@ -2124,7 +2132,9 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
			if (mdss_panel_is_power_on(ctx->panel_power_state)) {
				pr_debug("%s: cmd_start with panel always on\n",
						__func__);
				mdss_mdp_cmd_restore(ctl);
				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
				mdss_mdp_cmd_restore(ctl, false);
				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
				return mdss_mdp_cmd_panel_on(ctl, sctl);
			} else {
				pr_err("Intf %d already in use\n", session);
Loading