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

Commit bb4754f7 authored by Jeevan Shriram's avatar Jeevan Shriram
Browse files

msm: mdss: reset MDP ctl path for pingpong timeout recovery



When pingpong timeout is received, it could be due to some bad
configuration on MDP pipeline. In order to recover and have clean
HW for next frames, perform SW reset on the faulting ctl path. Also
make sure all the pipes in the bad configuration are halted
properly and does not have any residue transaction for the new
frames.

Conflicts:
	drivers/video/msm/mdss/mdss_mdp_pipe.c

Change-Id: I9a6c6cb6d004fd65c24a7fefe7457ee68af9273a
Signed-off-by: default avatarUjwal Patel <ujwalp@codeaurora.org>
Signed-off-by: default avatarNaseer Ahmed <naseer@codeaurora.org>
Signed-off-by: default avatarJeevan Shriram <jshriram@codeaurora.org>
parent 249a626c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -342,6 +342,8 @@ struct mdss_mdp_mixer {
	bool is_right_mixer;
	struct mdss_mdp_ctl *ctl;
	struct mdss_mdp_pipe *stage_pipe[MAX_PIPES_PER_LM];
	u32 next_pipe_map;
	u32 pipe_mapped;
};

struct mdss_mdp_format_params {
@@ -1144,6 +1146,7 @@ int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
int mdss_mdp_wb_addr_setup(struct mdss_data_type *mdata,
	u32 num_wb, u32 num_intf_wb);

void mdss_mdp_pipe_clk_force_off(struct mdss_mdp_pipe *pipe);
int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe);
int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable);
void mdss_mdp_config_pipe_panic_lut(struct mdss_data_type *mdata);
+84 −3
Original line number Diff line number Diff line
@@ -2123,6 +2123,8 @@ struct mdss_mdp_mixer *mdss_mdp_mixer_alloc(
		mixer->ref_cnt++;
		mixer->params_changed++;
		mixer->ctl = ctl;
		mixer->next_pipe_map = 0;
		mixer->pipe_mapped = 0;
		pr_debug("alloc mixer num %d for ctl=%d\n",
				mixer->num, ctl->num);
	}
@@ -3284,6 +3286,32 @@ end:
	return ret;
}

/*
 * mdss_mdp_pipe_reset() - Halts all the pipes during ctl reset.
 * @mixer: Mixer from which to reset all pipes.
 * This function called during control path reset and will halt
 * all the pipes staged on the mixer.
 */
static void mdss_mdp_pipe_reset(struct mdss_mdp_mixer *mixer)
{
	unsigned long pipe_map = mixer->pipe_mapped;
	u32 bit = 0;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	bool sw_rst_avail = mdss_mdp_pipe_is_sw_reset_available(mdata);

	pr_debug("pipe_map=0x%lx\n", pipe_map);
	for_each_set_bit_from(bit, &pipe_map, MAX_PIPES_PER_LM) {
		struct mdss_mdp_pipe *pipe;

		pipe = mdss_mdp_pipe_search(mdata, 1 << bit);
		if (pipe) {
			mdss_mdp_pipe_fetch_halt(pipe);
			if (sw_rst_avail)
				mdss_mdp_pipe_clk_force_off(pipe);
		}
	}
}

/*
 * mdss_mdp_ctl_reset() - reset mdp ctl path.
 * @ctl: mdp controller.
@@ -3296,6 +3324,7 @@ int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl)
{
	u32 status = 1;
	int cnt = 20;
	struct mdss_mdp_mixer *mixer = ctl->mixer_left;

	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_SW_RESET, 1);

@@ -3311,11 +3340,18 @@ int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl)
		pr_debug("status=%x\n", status);
		cnt--;
		if (cnt == 0) {
			pr_err("timeout\n");
			pr_err("ctl%d reset timedout\n", ctl->num);
			return -EAGAIN;
		}
	} while (status);

	if (mixer) {
		mdss_mdp_pipe_reset(mixer);

		if (ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY)
			mdss_mdp_pipe_reset(ctl->mixer_right);
	}

	return 0;
}

@@ -3342,6 +3378,28 @@ static void mdss_mdp_set_mixer_roi(struct mdss_mdp_ctl *ctl,
		ctl->num, ctl->roi.x, ctl->roi.y, ctl->roi.w, ctl->roi.h);
}

/*
 * mdss_mdp_mixer_update_pipe_map() - keep track of pipe configuration in  mixer
 * @master_ctl: mdp controller.
 *
 * This function keeps track of the current mixer configuration in the hardware.
 * It's callers responsibility to call with master control.
 */
static void mdss_mdp_mixer_update_pipe_map(struct mdss_mdp_ctl *master_ctl,
		       int mixer_mux)
{
	struct mdss_mdp_mixer *mixer = mdss_mdp_mixer_get(master_ctl,
			mixer_mux);

	if (!mixer)
		return;

	pr_debug("mixer%d pipe_mapped=0x%x next_pipes=0x%x\n",
		mixer->num, mixer->pipe_mapped, mixer->next_pipe_map);

	mixer->pipe_mapped = mixer->next_pipe_map;
}

static inline u32 mdss_mdp_mpq_pipe_num_map(u32 pipe_num)
{
	u32 mpq_num;
@@ -3463,6 +3521,13 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl,
			continue;
		}

		/*
		 * pipe which is staged on both LMs will be tracked through
		 * left mixer only.
		 */
		if (!pipe->src_split_req || !mixer->is_right_mixer)
			mixer->next_pipe_map |= pipe->ndx;

		blend_stage = stage - MDSS_MDP_STAGE_0;
		off = MDSS_MDP_REG_LM_BLEND_OFFSET(blend_stage);

@@ -4106,6 +4171,7 @@ int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl, bool use_lock)
{
	struct mdss_mdp_ctl *sctl = NULL;
	int ret;
	bool recovery_needed = false;

	if (use_lock) {
		ret = mutex_lock_interruptible(&ctl->lock);
@@ -4120,15 +4186,27 @@ int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl, bool use_lock)
	}

	ATRACE_BEGIN("wait_pingpong");
	ctl->ops.wait_pingpong(ctl, NULL);
	ret = ctl->ops.wait_pingpong(ctl, NULL);
	ATRACE_END("wait_pingpong");
	if (ret)
		recovery_needed = true;

	sctl = mdss_mdp_get_split_ctl(ctl);

	if (sctl && sctl->ops.wait_pingpong) {
		ATRACE_BEGIN("wait_pingpong sctl");
		sctl->ops.wait_pingpong(sctl, NULL);
		ret = sctl->ops.wait_pingpong(sctl, NULL);
		ATRACE_END("wait_pingpong sctl");
		if (ret)
			recovery_needed = true;
	}

	if (recovery_needed) {
		mdss_mdp_ctl_reset(ctl);
		if (sctl)
			mdss_mdp_ctl_reset(sctl);

		pr_debug("pingpong timeout recovery finished\n");
	}

	if (use_lock)
@@ -4386,6 +4464,9 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
	ctl->flush_reg_data = ctl_flush_bits;
	ctl->flush_bits = 0;

	mdss_mdp_mixer_update_pipe_map(ctl, MDSS_MDP_MIXER_MUX_LEFT);
	mdss_mdp_mixer_update_pipe_map(ctl, MDSS_MDP_MIXER_MUX_RIGHT);

	if (sctl && !ctl->valid_roi && sctl->valid_roi) {
		/*
		 * Seperate kickoff on DSI1 is needed only when we have
+3 −0
Original line number Diff line number Diff line
@@ -1245,6 +1245,9 @@ static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd,
			mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right);
		}
		__overlay_pipe_cleanup(mfd, pipe);
		ctl->mixer_left->next_pipe_map &= ~pipe->ndx;
		if (ctl->mixer_right)
			ctl->mixer_right->next_pipe_map &= ~pipe->ndx;
	}
	mutex_unlock(&mdp5_data->list_lock);
}
+30 −17
Original line number Diff line number Diff line
@@ -909,7 +909,6 @@ static void mdss_mdp_fixed_qos_arbiter_setup(struct mdss_data_type *mdata,
static int mdss_mdp_pipe_init_config(struct mdss_mdp_pipe *pipe,
	struct mdss_mdp_mixer *mixer, bool pipe_share)
{
	u32 reg_val, force_off_mask;
	bool is_realtime;
	int rc = 0;
	struct mdss_data_type *mdata;
@@ -927,22 +926,8 @@ static int mdss_mdp_pipe_init_config(struct mdss_mdp_pipe *pipe,

	mdss_mdp_pipe_panic_signal_ctrl(pipe, false);

	if (pipe && mdss_mdp_pipe_is_sw_reset_available(mdata)) {
		force_off_mask =
			BIT(pipe->clk_ctrl.bit_off + CLK_FORCE_OFF_OFFSET);

		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
		mutex_lock(&mdata->reg_lock);
		reg_val = readl_relaxed(mdata->mdp_base +
			pipe->clk_ctrl.reg_off);
		if (reg_val & force_off_mask) {
			reg_val &= ~force_off_mask;
			writel_relaxed(reg_val,
				mdata->mdp_base + pipe->clk_ctrl.reg_off);
		}
		mutex_unlock(&mdata->reg_lock);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
	}
	if (pipe && mdss_mdp_pipe_is_sw_reset_available(mdata))
		mdss_mdp_pipe_clk_force_off(pipe);

	if (pipe) {
		pr_debug("type=%x   pnum=%d\n", pipe->type, pipe->num);
@@ -1336,6 +1321,34 @@ exit:
	return is_idle;
}

/*
 * mdss_mdp_pipe_clk_force_off() - check force off mask and reset for the pipe.
 * @pipe: pointer to the pipe data structure which needs to be checked for clk.
 *
 * This function would be called where software reset is available for pipe
 * clocks.
 */

void mdss_mdp_pipe_clk_force_off(struct mdss_mdp_pipe *pipe)
{
	u32 reg_val, force_off_mask;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();

	force_off_mask =
		BIT(pipe->clk_ctrl.bit_off + CLK_FORCE_OFF_OFFSET);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	mutex_lock(&mdata->reg_lock);
	reg_val = readl_relaxed(mdata->mdp_base +
			pipe->clk_ctrl.reg_off);
	if (reg_val & force_off_mask) {
		reg_val &= ~force_off_mask;
		writel_relaxed(reg_val,
				mdata->mdp_base + pipe->clk_ctrl.reg_off);
	}
	mutex_unlock(&mdata->reg_lock);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
}

/**
 * mdss_mdp_pipe_fetch_halt() - Halt VBIF client corresponding to specified pipe
 * @pipe: pointer to the pipe data structure which needs to be halted.