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

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

Merge changes Iffd02768,I5e4d09c2 into msm-next

* changes:
  msm: sde: issue vbif xin halt after reset sde rotator
  msm: sde: add sde rotator hw hang recovery
parents ef16c798 8996dd90
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -139,6 +139,43 @@ static bool force_on_xin_clk(u32 bit_off, u32 clk_ctl_reg_off, bool enable)
	return clk_forced_on;
}

void sde_mdp_halt_vbif_xin(struct sde_mdp_vbif_halt_params *params)
{
	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
	u32 reg_val;
	bool forced_on;

	if (!mdata || !params || !params->reg_off_mdp_clk_ctrl) {
		SDEROT_ERR("null input parameter\n");
		return;
	}

	if (params->xin_id > MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN1) {
		SDEROT_ERR("xin_id:%d exceed max limit\n", params->xin_id);
		return;
	}

	forced_on = force_on_xin_clk(params->bit_off_mdp_clk_ctrl,
		params->reg_off_mdp_clk_ctrl, true);

	SDEROT_EVTLOG(forced_on, params->xin_id);

	reg_val = SDE_VBIF_READ(mdata, MMSS_VBIF_XIN_HALT_CTRL0);
	SDE_VBIF_WRITE(mdata, MMSS_VBIF_XIN_HALT_CTRL0,
		reg_val | BIT(params->xin_id));

	/* this is a polling operation */
	sde_mdp_wait_for_xin_halt(params->xin_id);

	reg_val = SDE_VBIF_READ(mdata, MMSS_VBIF_XIN_HALT_CTRL0);
	SDE_VBIF_WRITE(mdata, MMSS_VBIF_XIN_HALT_CTRL0,
		reg_val & ~BIT(params->xin_id));

	if (forced_on)
		force_on_xin_clk(params->bit_off_mdp_clk_ctrl,
			params->reg_off_mdp_clk_ctrl, false);
}

u32 sde_mdp_get_ot_limit(u32 width, u32 height, u32 pixfmt, u32 fps, u32 is_rd)
{
	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+14 −0
Original line number Diff line number Diff line
@@ -63,6 +63,18 @@ struct sde_mdp_set_ot_params {
	u32 rotsts_busy_mask;
};

/*
 * struct sde_mdp_vbif_halt_params: parameters for issue halt request to vbif
 * @xin_id: xin port number of vbif
 * @reg_off_mdp_clk_ctrl: reg offset for vbif clock control
 * @bit_off_mdp_clk_ctrl: bit offset for vbif clock control
 */
struct sde_mdp_vbif_halt_params {
	u32 xin_id;
	u32 reg_off_mdp_clk_ctrl;
	u32 bit_off_mdp_clk_ctrl;
};

enum sde_bus_vote_type {
	VOTE_INDEX_DISABLE,
	VOTE_INDEX_19_MHZ,
@@ -276,6 +288,8 @@ u32 sde_mdp_get_ot_limit(u32 width, u32 height, u32 pixfmt, u32 fps, u32 is_rd);

void sde_mdp_set_ot_limit(struct sde_mdp_set_ot_params *params);

void sde_mdp_halt_vbif_xin(struct sde_mdp_vbif_halt_params *params);

int sde_mdp_init_vbif(void);

#define SDE_VBIF_WRITE(mdata, offset, value) \
+141 −10
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include "sde_rotator_debug.h"

#define RES_UHD              (3840*2160)
#define MS_TO_US(t) ((t) * USEC_PER_MSEC)

/* traffic shaping clock ticks = finish_time x 19.2MHz */
#define TRAFFIC_SHAPE_CLKTICK_14MS   268800
@@ -48,7 +49,7 @@
#define XIN_WRITEBACK		1

/* wait for at most 2 vsync for lowest refresh rate (24hz) */
#define KOFF_TIMEOUT		(42 * 32)
#define KOFF_TIMEOUT		(42 * 8)

/* default stream buffer headroom in lines */
#define DEFAULT_SBUF_HEADROOM	20
@@ -665,13 +666,122 @@ static void sde_hw_rotator_disable_irq(struct sde_hw_rotator *rot)
	}
}

static void sde_hw_rotator_halt_vbif_xin_client(void)
{
	struct sde_mdp_vbif_halt_params halt_params;

	memset(&halt_params, 0, sizeof(struct sde_mdp_vbif_halt_params));
	halt_params.xin_id = XIN_SSPP;
	halt_params.reg_off_mdp_clk_ctrl = MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0;
	halt_params.bit_off_mdp_clk_ctrl =
		MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN0;
	sde_mdp_halt_vbif_xin(&halt_params);

	memset(&halt_params, 0, sizeof(struct sde_mdp_vbif_halt_params));
	halt_params.xin_id = XIN_WRITEBACK;
	halt_params.reg_off_mdp_clk_ctrl = MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0;
	halt_params.bit_off_mdp_clk_ctrl =
		MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN1;
	sde_mdp_halt_vbif_xin(&halt_params);
}

/**
 * sde_hw_rotator_reset - Reset rotator hardware
 * @rot: pointer to hw rotator
 * @ctx: pointer to current rotator context during the hw hang
 */
static int sde_hw_rotator_reset(struct sde_hw_rotator *rot,
		struct sde_hw_rotator_context *ctx)
{
	struct sde_hw_rotator_context *rctx = NULL;
	u32 int_mask = (REGDMA_INT_0_MASK | REGDMA_INT_1_MASK |
			REGDMA_INT_2_MASK);
	u32 last_ts[ROT_QUEUE_MAX] = {0,};
	u32 latest_ts;
	int elapsed_time, t;
	int i, j;
	unsigned long flags;

	if (!rot || !ctx) {
		SDEROT_ERR("NULL rotator context\n");
		return -EINVAL;
	}

	if (ctx->q_id >= ROT_QUEUE_MAX) {
		SDEROT_ERR("context q_id out of range: %d\n", ctx->q_id);
		return -EINVAL;
	}

	/* sw reset the hw rotator */
	SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_SW_RESET_OVERRIDE, 1);
	usleep_range(MS_TO_US(10), MS_TO_US(20));
	SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_SW_RESET_OVERRIDE, 0);

	/* halt vbif xin client to ensure no pending transaction */
	sde_hw_rotator_halt_vbif_xin_client();

	spin_lock_irqsave(&rot->rotisr_lock, flags);

	/* update timestamp register with current context */
	last_ts[ctx->q_id] = ctx->timestamp;
	sde_hw_rotator_update_swts(rot, ctx, ctx->timestamp);
	SDEROT_EVTLOG(ctx->timestamp);

	/*
	 * Search for any pending rot session, and look for last timestamp
	 * per hw queue.
	 */
	for (i = 0; i < ROT_QUEUE_MAX; i++) {
		latest_ts = atomic_read(&rot->timestamp[i]);
		latest_ts &= SDE_REGDMA_SWTS_MASK;
		elapsed_time = sde_hw_rotator_elapsed_swts(latest_ts,
			last_ts[i]);

		for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) {
			rctx = rot->rotCtx[i][j];
			if (rctx && rctx != ctx) {
				rctx->last_regdma_isr_status = int_mask;
				rctx->last_regdma_timestamp  = rctx->timestamp;

				t = sde_hw_rotator_elapsed_swts(latest_ts,
							rctx->timestamp);
				if (t < elapsed_time) {
					elapsed_time = t;
					last_ts[i] = rctx->timestamp;
					sde_hw_rotator_update_swts(rot, rctx,
							last_ts[i]);
				}

				SDEROT_DBG("rotctx[%d][%d], ts:%d\n",
						i, j, rctx->timestamp);
				SDEROT_EVTLOG(i, j, rctx->timestamp,
						last_ts[i]);
			}
		}
	}

	/* Finally wakeup all pending rotator context in queue */
	for (i = 0; i < ROT_QUEUE_MAX; i++) {
		for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) {
			rctx = rot->rotCtx[i][j];
			if (rctx && rctx != ctx)
				wake_up_all(&rctx->regdma_waitq);
		}
	}

	spin_unlock_irqrestore(&rot->rotisr_lock, flags);

	return 0;
}

/**
 * sde_hw_rotator_dump_status - Dump hw rotator status on error
 * @rot: Pointer to hw rotator
 */
static void sde_hw_rotator_dump_status(struct sde_hw_rotator *rot)
static void sde_hw_rotator_dump_status(struct sde_hw_rotator *rot, u32 *ubwcerr)
{
	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
	u32 reg = 0;

	SDEROT_ERR(
		"op_mode = %x, int_en = %x, int_status = %x\n",
@@ -700,9 +810,11 @@ static void sde_hw_rotator_dump_status(struct sde_hw_rotator *rot)
		SDE_ROTREG_READ(rot->mdss_base,
			REGDMA_CSR_REGDMA_FSM_STATE));

	reg = SDE_ROTREG_READ(rot->mdss_base, ROT_SSPP_UBWC_ERROR_STATUS);
	if (ubwcerr)
		*ubwcerr = reg;
	SDEROT_ERR(
		"UBWC decode status = %x, UBWC encode status = %x\n",
		SDE_ROTREG_READ(rot->mdss_base, ROT_SSPP_UBWC_ERROR_STATUS),
		"UBWC decode status = %x, UBWC encode status = %x\n", reg,
		SDE_ROTREG_READ(rot->mdss_base, ROT_WB_UBWC_ERROR_STATUS));

	SDEROT_ERR("VBIF XIN HALT status = %x VBIF AXI HALT status = %x\n",
@@ -1788,6 +1900,7 @@ static u32 sde_hw_rotator_wait_done_regdma(
	u32 int_id;
	u32 swts;
	u32 sts = 0;
	u32 ubwcerr = 0;
	unsigned long flags;

	if (rot->irq_num >= 0) {
@@ -1824,8 +1937,26 @@ static u32 sde_hw_rotator_wait_done_regdma(
			else if (status & REGDMA_INVALID_CMD)
				SDEROT_ERR("REGDMA invalid command\n");

			sde_hw_rotator_dump_status(rot);
			sde_hw_rotator_dump_status(rot, &ubwcerr);

			if (ubwcerr) {
				/*
				 * Perform recovery for ROT SSPP UBWC decode
				 * error.
				 * - SW reset rotator hw block
				 * - reset TS logic so all pending rotation
				 *   in hw queue got done signalled
				 */
				spin_unlock_irqrestore(&rot->rotisr_lock,
						flags);
				if (!sde_hw_rotator_reset(rot, ctx))
					status = REGDMA_INCOMPLETE_CMD;
				else
					status = ROT_ERROR_BIT;
				spin_lock_irqsave(&rot->rotisr_lock, flags);
			} else {
				status = ROT_ERROR_BIT;
			}
		} else {
			if (rc == 1)
				SDEROT_WARN(
@@ -1851,12 +1982,12 @@ static u32 sde_hw_rotator_wait_done_regdma(
		if (last_isr & REGDMA_INT_ERR_MASK) {
			SDEROT_ERR("Rotator error, ts:0x%X/0x%X status:%x\n",
				ctx->timestamp, swts, last_isr);
			sde_hw_rotator_dump_status(rot);
			sde_hw_rotator_dump_status(rot, NULL);
			status = ROT_ERROR_BIT;
		} else if (pending) {
			SDEROT_ERR("Rotator timeout, ts:0x%X/0x%X status:%x\n",
				ctx->timestamp, swts, last_isr);
			sde_hw_rotator_dump_status(rot);
			sde_hw_rotator_dump_status(rot, NULL);
			status = ROT_ERROR_BIT;
		} else {
			status = 0;
@@ -1866,7 +1997,7 @@ static u32 sde_hw_rotator_wait_done_regdma(
				last_isr);
	}

	sts = (status & ROT_ERROR_BIT) ? -ENODEV : 0;
	sts = (status & (ROT_ERROR_BIT | REGDMA_INCOMPLETE_CMD)) ? -ENODEV : 0;

	if (status & ROT_ERROR_BIT)
		SDEROT_EVTLOG_TOUT_HANDLER("rot", "rot_dbg_bus",
@@ -2359,7 +2490,7 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw,
				if (status & BIT(0)) {
					SDEROT_ERR("rotator busy 0x%x\n",
							status);
					sde_hw_rotator_dump_status(rot);
					sde_hw_rotator_dump_status(rot, NULL);
					SDEROT_EVTLOG_TOUT_HANDLER("rot",
							"vbif_dbg_bus",
							"panic");