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

Commit aadda166 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: sde: Add pre/post power event handler in SDE rotator" into msm-4.8

parents e2cace44 0f9e61dd
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -278,6 +278,10 @@ static void sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on)

	SDEROT_EVTLOG(on);
	SDEROT_DBG("%s: rotator regulators", on ? "Enable" : "Disable");

	if (mgr->ops_hw_pre_pmevent)
		mgr->ops_hw_pre_pmevent(mgr, on);

	ret = sde_rot_enable_vreg(mgr->module_power.vreg_config,
		mgr->module_power.num_vreg, on);
	if (ret) {
@@ -286,10 +290,13 @@ static void sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on)
		return;
	}

	if (mgr->ops_hw_post_pmevent)
		mgr->ops_hw_post_pmevent(mgr, on);

	mgr->regulator_enable = on;
}

static int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable)
int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable)
{
	struct clk *clk;
	int ret = 0;
+4 −0
Original line number Diff line number Diff line
@@ -293,6 +293,8 @@ struct sde_rot_mgr {
	void (*ops_hw_free)(struct sde_rot_mgr *mgr,
			struct sde_rot_hw_resource *hw);
	int (*ops_hw_init)(struct sde_rot_mgr *mgr);
	void (*ops_hw_pre_pmevent)(struct sde_rot_mgr *mgr, bool pmon);
	void (*ops_hw_post_pmevent)(struct sde_rot_mgr *mgr, bool pmon);
	void (*ops_hw_destroy)(struct sde_rot_mgr *mgr);
	ssize_t (*ops_hw_show_caps)(struct sde_rot_mgr *mgr,
			struct device_attribute *attr, char *buf, ssize_t len);
@@ -405,6 +407,8 @@ int sde_rotator_validate_request(struct sde_rot_mgr *rot_dev,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req);

int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable);

static inline void sde_rot_mgr_lock(struct sde_rot_mgr *mgr)
{
	mutex_lock(&mgr->lock);
+103 −1
Original line number Diff line number Diff line
@@ -271,6 +271,7 @@ static int sde_hw_rotator_pending_swts(struct sde_hw_rotator *rot,

	SDEROT_DBG("ts:0x%x, queue_id:%d, swts:0x%x, pending:%d\n",
		ctx->timestamp, ctx->q_id, swts, pending);
	SDEROT_EVTLOG(ctx->timestamp, swts, ctx->q_id, ts_diff);
	return pending;
}

@@ -1239,6 +1240,94 @@ static void sde_hw_rotator_swtc_destroy(struct sde_hw_rotator *rot)
	data->srcp_dma_buf = NULL;
}

/*
 * sde_hw_rotator_pre_pmevent - SDE rotator core will call this before a
 *                              PM event occurs
 * @mgr: Pointer to rotator manager
 * @pmon: Boolean indicate an on/off power event
 */
void sde_hw_rotator_pre_pmevent(struct sde_rot_mgr *mgr, bool pmon)
{
	struct sde_hw_rotator *rot;
	u32 l_ts, h_ts, swts, hwts;
	u32 rotsts, regdmasts;

	/*
	 * Check last HW timestamp with SW timestamp before power off event.
	 * If there is a mismatch, that will be quite possible the rotator HW
	 * is either hang or not finishing last submitted job. In that case,
	 * it is best to do a timeout eventlog to capture some good events
	 * log data for analysis.
	 */
	if (!pmon && mgr && mgr->hw_data) {
		rot = mgr->hw_data;
		h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]);
		l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]);

		/* contruct the combined timstamp */
		swts = (h_ts & SDE_REGDMA_SWTS_MASK) |
			((l_ts & SDE_REGDMA_SWTS_MASK) <<
			 SDE_REGDMA_SWTS_SHIFT);

		/* Need to turn on clock to access rotator register */
		sde_rotator_clk_ctrl(mgr, true);
		hwts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG);
		regdmasts = SDE_ROTREG_READ(rot->mdss_base,
				REGDMA_CSR_REGDMA_BLOCK_STATUS);
		rotsts = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS);

		SDEROT_DBG(
			"swts:0x%x, hwts:0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n",
				swts, hwts, regdmasts, rotsts);
		SDEROT_EVTLOG(swts, hwts, regdmasts, rotsts);

		if ((swts != hwts) && ((regdmasts & REGDMA_BUSY) ||
					(rotsts & ROT_STATUS_MASK))) {
			SDEROT_ERR(
				"Mismatch SWTS with HWTS: swts:0x%x, hwts:0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n",
				swts, hwts, regdmasts, rotsts);
			SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus",
					"panic");
		}

		/* Turn off rotator clock after checking rotator registers */
		sde_rotator_clk_ctrl(mgr, false);
	}
}

/*
 * sde_hw_rotator_post_pmevent - SDE rotator core will call this after a
 *                               PM event occurs
 * @mgr: Pointer to rotator manager
 * @pmon: Boolean indicate an on/off power event
 */
void sde_hw_rotator_post_pmevent(struct sde_rot_mgr *mgr, bool pmon)
{
	struct sde_hw_rotator *rot;
	u32 l_ts, h_ts, swts;

	/*
	 * After a power on event, the rotator HW is reset to default setting.
	 * It is necessary to synchronize the SW timestamp with the HW.
	 */
	if (pmon && mgr && mgr->hw_data) {
		rot = mgr->hw_data;
		h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]);
		l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]);

		/* contruct the combined timstamp */
		swts = (h_ts & SDE_REGDMA_SWTS_MASK) |
			((l_ts & SDE_REGDMA_SWTS_MASK) <<
			 SDE_REGDMA_SWTS_SHIFT);

		SDEROT_DBG("swts:0x%x, h_ts:0x%x, l_ts;0x%x\n",
				swts, h_ts, l_ts);
		SDEROT_EVTLOG(swts, h_ts, l_ts);
		rot->reset_hw_ts = true;
		rot->last_hw_ts = swts;
	}
}

/*
 * sde_hw_rotator_destroy - Destroy hw rotator and free allocated resources
 * @mgr: Pointer to rotator manager
@@ -1455,6 +1544,15 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw,
		return -EINVAL;
	}

	if (rot->reset_hw_ts) {
		SDEROT_EVTLOG(rot->last_hw_ts);
		SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG,
				rot->last_hw_ts);
		/* ensure write is issued to the rotator HW */
		wmb();
		rot->reset_hw_ts = false;
	}

	flags = (item->flags & SDE_ROTATION_FLIP_LR) ?
			SDE_ROT_FLAG_FLIP_LR : 0;
	flags |= (item->flags & SDE_ROTATION_FLIP_UD) ?
@@ -1511,7 +1609,8 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw,
				&entry->dst_buf);
	}

	SDEROT_EVTLOG(flags, item->input.width, item->input.height,
	SDEROT_EVTLOG(ctx->timestamp, flags,
			item->input.width, item->input.height,
			item->output.width, item->output.height,
			entry->src_buf.p[0].addr, entry->dst_buf.p[0].addr);

@@ -1715,6 +1814,7 @@ static int sde_rotator_hw_rev_init(struct sde_hw_rotator *rot)
	mdata->regdump = sde_rot_r3_regdump;
	mdata->regdump_size = ARRAY_SIZE(sde_rot_r3_regdump);

	SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, 0);
	return 0;
}

@@ -2174,6 +2274,8 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
	mgr->ops_hw_create_debugfs = sde_rotator_r3_create_debugfs;
	mgr->ops_hw_get_pixfmt = sde_hw_rotator_get_pixfmt;
	mgr->ops_hw_is_valid_pixfmt = sde_hw_rotator_is_valid_pixfmt;
	mgr->ops_hw_pre_pmevent = sde_hw_rotator_pre_pmevent;
	mgr->ops_hw_post_pmevent = sde_hw_rotator_post_pmevent;

	ret = sde_hw_rotator_parse_dt(mgr->hw_data, mgr->pdev);
	if (ret)
+2 −1
Original line number Diff line number Diff line
@@ -250,9 +250,10 @@
/* General defines */
#define ROT_DONE_MASK                   0x1
#define ROT_DONE_CLEAR                  0x1
#define ROT_BUSY_BIT                    BIT(1)
#define ROT_BUSY_BIT                    BIT(0)
#define ROT_ERROR_BIT                   BIT(8)
#define ROT_STATUS_MASK                 (ROT_BUSY_BIT | ROT_ERROR_BIT)
#define REGDMA_BUSY                     BIT(0)
#define REGDMA_EN                       0x1
#define REGDMA_SECURE_EN                BIT(8)
#define REGDMA_HALT                     BIT(16)
+2 −0
Original line number Diff line number Diff line
@@ -270,6 +270,8 @@ struct sde_hw_rotator {
	spinlock_t rotisr_lock;

	bool    dbgmem;
	bool reset_hw_ts;
	u32 last_hw_ts;
};

/**