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

Commit 9befef11 authored by Jeykumar Sankaran's avatar Jeykumar Sankaran Committed by Gerrit - the friendly Code Review server
Browse files

msm: mdss: handle multiple MDP interrupt register sets



This change enhances the existing MDP ISR routine handlers
to handle multiple MDP register sets. Maintain IRQ
handlers and callbacks in a single file.

Change-Id: Iea6e77be1eaab5ccf2fd89f7c98e2dd328af7de0
Signed-off-by: default avatarJeykumar Sankaran <jsanka@codeaurora.org>
parent fc23af4e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -321,7 +321,7 @@ struct mdss_data_type {
	u32 default_ot_wr_limit;

	struct irq_domain *irq_domain;
	u32 mdp_irq_mask;
	u32 *mdp_irq_mask;
	u32 mdp_hist_irq_mask;

	int suspend_fs_ena;
+335 −52
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ struct msm_mdp_interface mdp5 = {
#define MEM_PROTECT_SD_CTRL_FLAT 0x14

static DEFINE_SPINLOCK(mdp_lock);
static DEFINE_SPINLOCK(mdss_mdp_intr_lock);
static DEFINE_MUTEX(mdp_clk_lock);
static DEFINE_MUTEX(mdp_iommu_ref_cnt_lock);
static DEFINE_MUTEX(mdp_fs_idle_pc_lock);
@@ -149,6 +150,83 @@ u32 invalid_mdp107_wb_output_fmts[] = {
	MDP_BGRX_8888,
};

/*
 * struct intr_call - array of intr handlers
 * @func: intr handler
 * @arg: requested argument to the handler
 */
struct intr_callback {
	void (*func)(void *);
	void *arg;
};

/*
 * struct mdss_mdp_intr_reg - array of MDP intr register sets
 * @clr_off: offset to CLEAR reg
 * @en_off: offset to ENABLE reg
 * @status_off: offset to STATUS reg
 */
struct mdss_mdp_intr_reg {
	u32 clr_off;
	u32 en_off;
	u32 status_off;
};

/*
 * struct mdss_mdp_irq - maps each irq with i/f
 * @intr_type: type of interface
 * @intf_num: i/f the irq is associated with
 * @irq_mask: corresponding bit in the reg set
 * @reg_idx: which reg set to program
 */
struct mdss_mdp_irq {
	u32 intr_type;
	u32 intf_num;
	u32 irq_mask;
	u32 reg_idx;
};

static struct mdss_mdp_intr_reg mdp_intr_reg[] = {
	{ MDSS_MDP_REG_INTR_CLEAR, MDSS_MDP_REG_INTR_EN,
		MDSS_MDP_REG_INTR_STATUS },
	{ MDSS_MDP_REG_INTR2_CLEAR, MDSS_MDP_REG_INTR2_EN,
		MDSS_MDP_REG_INTR2_STATUS }
};

static struct mdss_mdp_irq mdp_irq_map[] =  {
	{ MDSS_MDP_IRQ_TYPE_INTF_UNDER_RUN, 1, MDSS_MDP_INTR_INTF_0_UNDERRUN, 0},
	{ MDSS_MDP_IRQ_TYPE_INTF_UNDER_RUN, 2, MDSS_MDP_INTR_INTF_1_UNDERRUN, 0},
	{ MDSS_MDP_IRQ_TYPE_INTF_UNDER_RUN, 3, MDSS_MDP_INTR_INTF_2_UNDERRUN, 0},
	{ MDSS_MDP_IRQ_TYPE_INTF_UNDER_RUN, 4, MDSS_MDP_INTR_INTF_3_UNDERRUN, 0},
	{ MDSS_MDP_IRQ_TYPE_INTF_VSYNC, 1, MDSS_MDP_INTR_INTF_0_VSYNC, 0},
	{ MDSS_MDP_IRQ_TYPE_INTF_VSYNC, 2, MDSS_MDP_INTR_INTF_1_VSYNC, 0},
	{ MDSS_MDP_IRQ_TYPE_INTF_VSYNC, 3, MDSS_MDP_INTR_INTF_2_VSYNC, 0},
	{ MDSS_MDP_IRQ_TYPE_INTF_VSYNC, 4, MDSS_MDP_INTR_INTF_3_VSYNC, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, 0, MDSS_MDP_INTR_PING_PONG_0_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, 1, MDSS_MDP_INTR_PING_PONG_1_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, 2, MDSS_MDP_INTR_PING_PONG_2_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, 3, MDSS_MDP_INTR_PING_PONG_3_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_RD_PTR, 0, MDSS_MDP_INTR_PING_PONG_0_RD_PTR, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_RD_PTR, 1, MDSS_MDP_INTR_PING_PONG_1_RD_PTR, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_RD_PTR, 2, MDSS_MDP_INTR_PING_PONG_2_RD_PTR, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_RD_PTR, 3, MDSS_MDP_INTR_PING_PONG_3_RD_PTR, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_WR_PTR, 0, MDSS_MDP_INTR_PING_PONG_0_WR_PTR, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_WR_PTR, 1, MDSS_MDP_INTR_PING_PONG_1_WR_PTR, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_WR_PTR, 2, MDSS_MDP_INTR_PING_PONG_2_WR_PTR, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_WR_PTR, 3, MDSS_MDP_INTR_PING_PONG_3_WR_PTR, 0},
	{ MDSS_MDP_IRQ_TYPE_WB_ROT_COMP, 0, MDSS_MDP_INTR_WB_0_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_WB_ROT_COMP, 1, MDSS_MDP_INTR_WB_1_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_WB_WFD_COMP, 0, MDSS_MDP_INTR_WB_2_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF, 0, MDSS_MDP_INTR_PING_PONG_0_AUTOREFRESH_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF, 1, MDSS_MDP_INTR_PING_PONG_1_AUTOREFRESH_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF, 2, MDSS_MDP_INTR_PING_PONG_2_AUTOREFRESH_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF, 3, MDSS_MDP_INTR_PING_PONG_3_AUTOREFRESH_DONE, 0},
	{ MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, 2, MDSS_MDP_INTR2_PING_PONG_2_CWB_OVERFLOW, 1},
	{ MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, 3, MDSS_MDP_INTR2_PING_PONG_2_CWB_OVERFLOW, 1}
};

static struct intr_callback *mdp_intr_cb;

static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on);
static int mdss_mdp_parse_dt(struct platform_device *pdev);
static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev);
@@ -169,6 +247,21 @@ static int mdss_mdp_parse_dt_ppb_off(struct platform_device *pdev);
static int mdss_mdp_parse_dt_cdm(struct platform_device *pdev);
static int mdss_mdp_parse_dt_dsc(struct platform_device *pdev);

static inline u32 is_mdp_irq_enabled(void)
{
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	int i;

	for (i = 0; i < ARRAY_SIZE(mdp_intr_reg); i++)
		if (mdata->mdp_irq_mask[i] != 0)
			return 1;

	if (mdata->mdp_hist_irq_mask)
		return 1;

	return 0;
}

u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp)
{
	/* The adreno GPU hardware requires that the pitch be aligned to
@@ -608,12 +701,23 @@ int mdss_update_reg_bus_vote(struct reg_bus_client *bus_client, u32 usecase_ndx)
#endif


static inline u32 mdss_mdp_irq_mask(u32 intr_type, u32 intf_num)
static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num)
{
	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
		intf_num = (intf_num - MDSS_MDP_INTF0) * 2;
	return 1 << (intr_type + intf_num);
	int i;

	for (i = 0; i < ARRAY_SIZE(mdp_irq_map); i++) {
		if (intr_type == mdp_irq_map[i].intr_type &&
			intf_num == mdp_irq_map[i].intf_num)
			return i;
	}
	return -EINVAL;
}

u32 mdss_mdp_get_irq_mask(u32 intr_type, u32 intf_num)
{
	int idx = mdss_mdp_intr2index(intr_type, intf_num);

	return (idx < 0) ? 0 : mdp_irq_map[idx].irq_mask;
}

/* function assumes that mdp is clocked to access hw registers */
@@ -621,38 +725,55 @@ void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
		u32 intr_type, u32 intf_num)
{
	unsigned long irq_flags;
	u32 irq;
	int irq_idx;
	struct mdss_mdp_intr_reg reg;
	struct mdss_mdp_irq irq;

	irq_idx = mdss_mdp_intr2index(intr_type, intf_num);
	if (irq_idx < 0) {
		pr_err("invalid irq request\n");
		return;
	}

	irq = mdss_mdp_irq_mask(intr_type, intf_num);
	irq = mdp_irq_map[irq_idx];
	reg = mdp_intr_reg[irq.reg_idx];

	pr_debug("clearing mdp irq mask=%x\n", irq);
	pr_debug("clearing mdp irq mask=%x\n", irq.irq_mask);
	spin_lock_irqsave(&mdp_lock, irq_flags);
	writel_relaxed(irq, mdata->mdp_base + MDSS_MDP_REG_INTR_CLEAR);
	writel_relaxed(irq.irq_mask, mdata->mdp_base + reg.clr_off);
	spin_unlock_irqrestore(&mdp_lock, irq_flags);
}

int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num)
{
	u32 irq;
	int irq_idx, idx;
	unsigned long irq_flags;
	int ret = 0;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_mdp_intr_reg reg;
	struct mdss_mdp_irq irq;

	irq_idx = mdss_mdp_intr2index(intr_type, intf_num);
	if (irq_idx < 0) {
		pr_err("invalid irq request\n");
		return -EINVAL;
	}

	irq = mdss_mdp_irq_mask(intr_type, intf_num);
	irq = mdp_irq_map[irq_idx];
	reg = mdp_intr_reg[irq.reg_idx];

	spin_lock_irqsave(&mdp_lock, irq_flags);
	if (mdata->mdp_irq_mask & irq) {
	if (mdata->mdp_irq_mask[irq.reg_idx] & irq.irq_mask) {
		pr_warn("MDSS MDP IRQ-0x%x is already set, mask=%x\n",
				irq, mdata->mdp_irq_mask);
				irq.irq_mask, mdata->mdp_irq_mask[idx]);
		ret = -EBUSY;
	} else {
		pr_debug("MDP IRQ mask old=%x new=%x\n",
				mdata->mdp_irq_mask, irq);
		mdata->mdp_irq_mask |= irq;
		writel_relaxed(irq, mdata->mdp_base +
			MDSS_MDP_REG_INTR_CLEAR);
		writel_relaxed(mdata->mdp_irq_mask, mdata->mdp_base +
			MDSS_MDP_REG_INTR_EN);
				mdata->mdp_irq_mask[irq.reg_idx], irq.irq_mask);
		mdata->mdp_irq_mask[irq.reg_idx] |= irq.irq_mask;
		writel_relaxed(irq.irq_mask, mdata->mdp_base + reg.clr_off);
		writel_relaxed(mdata->mdp_irq_mask[irq.reg_idx],
				mdata->mdp_base + reg.en_off);
		mdata->mdss_util->enable_irq(&mdss_mdp_hw);
	}
	spin_unlock_irqrestore(&mdp_lock, irq_flags);
@@ -669,7 +790,7 @@ int mdss_mdp_hist_irq_enable(u32 irq)
				irq, mdata->mdp_hist_irq_mask);
		ret = -EBUSY;
	} else {
		pr_debug("MDP IRQ mask old=%x new=%x\n",
		pr_debug("mask old=%x new=%x\n",
				mdata->mdp_hist_irq_mask, irq);
		mdata->mdp_hist_irq_mask |= irq;
		writel_relaxed(irq, mdata->mdp_base +
@@ -684,47 +805,61 @@ int mdss_mdp_hist_irq_enable(u32 irq)

void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num)
{
	u32 irq;
	int irq_idx;
	unsigned long irq_flags;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_mdp_intr_reg reg;
	struct mdss_mdp_irq irq;

	irq_idx = mdss_mdp_intr2index(intr_type, intf_num);
	if (irq_idx < 0) {
		pr_err("invalid irq request\n");
		return;
	}

	irq = mdss_mdp_irq_mask(intr_type, intf_num);
	irq =  mdp_irq_map[irq_idx];
	reg = mdp_intr_reg[irq.reg_idx];

	spin_lock_irqsave(&mdp_lock, irq_flags);
	if (!(mdata->mdp_irq_mask & irq)) {
	if (!(mdata->mdp_irq_mask[irq.reg_idx] & irq.irq_mask)) {
		pr_warn("MDSS MDP IRQ-%x is NOT set, mask=%x\n",
				irq, mdata->mdp_irq_mask);
				irq.irq_mask, mdata->mdp_irq_mask[irq.reg_idx]);
	} else {
		mdata->mdp_irq_mask &= ~irq;

		writel_relaxed(mdata->mdp_irq_mask, mdata->mdp_base +
			MDSS_MDP_REG_INTR_EN);
		if ((mdata->mdp_irq_mask == 0) &&
			(mdata->mdp_hist_irq_mask == 0))
		mdata->mdp_irq_mask[irq.reg_idx] &= ~irq.irq_mask;
		writel_relaxed(mdata->mdp_irq_mask[irq.reg_idx],
				mdata->mdp_base + reg.en_off);
		if (!is_mdp_irq_enabled())
			mdata->mdss_util->disable_irq(&mdss_mdp_hw);
	}
	spin_unlock_irqrestore(&mdp_lock, irq_flags);
}

/*
 * This function is used to check and clear the status of
 * INTR and does not handle INTR2 and HIST_INTR
 */
/* This function is used to check and clear the status of MDP interrupts */
void mdss_mdp_intr_check_and_clear(u32 intr_type, u32 intf_num)
{
	u32 status, irq;
	u32 status;
	int irq_idx;
	unsigned long irq_flags;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_mdp_intr_reg reg;
	struct mdss_mdp_irq irq;

	irq_idx = mdss_mdp_intr2index(intr_type, intf_num);
	if (irq_idx < 0) {
		pr_err("invalid irq request\n");
		return;
	}

	irq = mdss_mdp_irq_mask(intr_type, intf_num);
	irq =  mdp_irq_map[irq_idx];
	reg = mdp_intr_reg[irq.reg_idx];

	spin_lock_irqsave(&mdp_lock, irq_flags);
	status = irq & readl_relaxed(mdata->mdp_base +
			MDSS_MDP_REG_INTR_STATUS);
	status = irq.irq_mask & readl_relaxed(mdata->mdp_base +
			reg.status_off);
	if (status) {
		pr_debug("clearing irq: intr_type:%d, intf_num:%d\n",
				intr_type, intf_num);
		writel_relaxed(irq, mdata->mdp_base + MDSS_MDP_REG_INTR_CLEAR);
		writel_relaxed(irq.irq_mask, mdata->mdp_base + reg.clr_off);
	}
	spin_unlock_irqrestore(&mdp_lock, irq_flags);
}
@@ -740,8 +875,7 @@ void mdss_mdp_hist_irq_disable(u32 irq)
		mdata->mdp_hist_irq_mask &= ~irq;
		writel_relaxed(mdata->mdp_hist_irq_mask, mdata->mdp_base +
			MDSS_MDP_REG_HIST_INTR_EN);
		if ((mdata->mdp_irq_mask == 0) &&
			(mdata->mdp_hist_irq_mask == 0))
		if (!is_mdp_irq_enabled())
			mdata->mdss_util->disable_irq(&mdss_mdp_hw);
	}
}
@@ -758,24 +892,163 @@ void mdss_mdp_hist_irq_disable(u32 irq)
*/
void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num)
{
	u32 irq;
	int irq_idx;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_mdp_intr_reg reg;
	struct mdss_mdp_irq irq;

	irq = mdss_mdp_irq_mask(intr_type, intf_num);
	irq_idx = mdss_mdp_intr2index(intr_type, intf_num);
	if (irq_idx < 0) {
		pr_err("invalid irq request\n");
		return;
	}

	if (!(mdata->mdp_irq_mask & irq)) {
	irq = mdp_irq_map[irq_idx];
	reg = mdp_intr_reg[irq.reg_idx];

	if (!(mdata->mdp_irq_mask[irq.reg_idx] & irq.irq_mask)) {
		pr_warn("MDSS MDP IRQ-%x is NOT set, mask=%x\n",
				irq, mdata->mdp_irq_mask);
				irq.irq_mask, mdata->mdp_irq_mask[irq.reg_idx]);
	} else {
		mdata->mdp_irq_mask &= ~irq;
		writel_relaxed(mdata->mdp_irq_mask, mdata->mdp_base +
			MDSS_MDP_REG_INTR_EN);
		if ((mdata->mdp_irq_mask == 0) &&
			(mdata->mdp_hist_irq_mask == 0))
		mdata->mdp_irq_mask[irq.reg_idx] &= ~irq.irq_mask;
		writel_relaxed(mdata->mdp_irq_mask[irq.reg_idx],
				mdata->mdp_base + reg.en_off);
		if (!is_mdp_irq_enabled())
			mdata->mdss_util->disable_irq_nosync(&mdss_mdp_hw);
	}
}

int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
		       void (*fnc_ptr)(void *), void *arg)
{
	unsigned long flags;
	int index;

	index = mdss_mdp_intr2index(intr_type, intf_num);
	if (index < 0) {
		pr_warn("invalid intr type=%u intf_numf_num=%u\n",
				intr_type, intf_num);
		return -EINVAL;
	}

	spin_lock_irqsave(&mdss_mdp_intr_lock, flags);
	WARN(mdp_intr_cb[index].func && fnc_ptr,
			"replacing current intr callback for ndx=%d\n", index);
	mdp_intr_cb[index].func = fnc_ptr;
	mdp_intr_cb[index].arg = arg;
	spin_unlock_irqrestore(&mdss_mdp_intr_lock, flags);

	return 0;
}

int mdss_mdp_set_intr_callback_nosync(u32 intr_type, u32 intf_num,
		       void	  (*fnc_ptr)(void *), void *arg)
{
	int index;

	index = mdss_mdp_intr2index(intr_type, intf_num);
	if (index < 0) {
		pr_warn("invalid intr Typee=%u intf_num=%u\n",
				intr_type, intf_num);
		return -EINVAL;
	}

	WARN(mdp_intr_cb[index].func && fnc_ptr,
			"replacing current intr callbackack for ndx=%d\n",
			index);
	mdp_intr_cb[index].func = fnc_ptr;
	mdp_intr_cb[index].arg = arg;

	return 0;
}

static inline void mdss_mdp_intr_done(int index)
{
	void (*fnc)(void *);
	void *arg;

	spin_lock(&mdss_mdp_intr_lock);
	fnc = mdp_intr_cb[index].func;
	arg = mdp_intr_cb[index].arg;
	spin_unlock(&mdss_mdp_intr_lock);
	if (fnc)
		fnc(arg);
}

irqreturn_t mdss_mdp_isr(int irq, void *ptr)
{
	struct mdss_data_type *mdata = ptr;
	u32 isr, mask, hist_isr, hist_mask;
	int i, j;

	if (!mdata->clk_ena)
		return IRQ_HANDLED;

	for (i = 0; i < ARRAY_SIZE(mdp_intr_reg); i++) {
		struct mdss_mdp_intr_reg reg = mdp_intr_reg[i];

		isr = readl_relaxed(mdata->mdp_base + reg.status_off);
		if (isr == 0)
			continue;

		mask = readl_relaxed(mdata->mdp_base + reg.en_off);
		writel_relaxed(isr, mdata->mdp_base + reg.clr_off);

		pr_debug("%s: reg:%d isr=%x mask=%x\n",
				__func__, i+1, isr, mask);

		isr &= mask;
		if (isr == 0)
			continue;

		for (j = 0; j < ARRAY_SIZE(mdp_irq_map); j++)
			if (mdp_irq_map[j].reg_idx == i &&
					(isr & mdp_irq_map[j].irq_mask))
				mdss_mdp_intr_done(j);
		if (!i) {
			if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE)
				mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0, false);

			if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE)
				mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1, false);

			if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
				mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP, true);

			if (isr & MDSS_MDP_INTR_INTF_1_VSYNC)
				mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0, true);

			if (isr & MDSS_MDP_INTR_INTF_2_VSYNC)
				mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1, true);

			if (isr & MDSS_MDP_INTR_INTF_3_VSYNC)
				mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI, true);

			if (isr & MDSS_MDP_INTR_WB_0_DONE)
				mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true);

			if (isr & MDSS_MDP_INTR_WB_1_DONE)
				mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true);

			if (isr &  MDSS_MDP_INTR_WB_2_DONE)
				mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true);
		}
	}

	hist_isr = readl_relaxed(mdata->mdp_base +
			MDSS_MDP_REG_HIST_INTR_STATUS);
	if (hist_isr != 0) {
		hist_mask = readl_relaxed(mdata->mdp_base +
				MDSS_MDP_REG_HIST_INTR_EN);
		writel_relaxed(hist_isr, mdata->mdp_base +
				MDSS_MDP_REG_HIST_INTR_CLEAR);
		hist_isr &= hist_mask;
		if (hist_isr != 0)
			mdss_mdp_hist_intr_done(hist_isr);
	}
	return IRQ_HANDLED;
}

static int mdss_mdp_clk_update(u32 clk_idx, u32 enable)
{
	int ret = -ENODEV;
@@ -2342,6 +2615,16 @@ static int mdss_mdp_probe(struct platform_device *pdev)
	else
		mdata->handoff_pending = true;

	mdp_intr_cb  = kcalloc(ARRAY_SIZE(mdp_irq_map),
			sizeof(struct intr_callback), GFP_KERNEL);
	if (mdp_intr_cb == NULL)
		return -ENOMEM;

	mdss_res->mdp_irq_mask = kcalloc(ARRAY_SIZE(mdp_intr_reg),
			sizeof(u32), GFP_KERNEL);
	if (mdss_res->mdp_irq_mask == NULL)
		return -ENOMEM;

	pr_info("mdss version = 0x%x, bootloader display is %s\n",
		mdata->mdp_rev, display_on ? "on" : "off");

+1 −0
Original line number Diff line number Diff line
@@ -1326,6 +1326,7 @@ int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
			       void (*fnc_ptr)(void *), void *arg);
int mdss_mdp_set_intr_callback_nosync(u32 intr_type, u32 intf_num,
			       void (*fnc_ptr)(void *), void *arg);
u32 mdss_mdp_get_irq_mask(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);
+15 −8
Original line number Diff line number Diff line
@@ -60,6 +60,9 @@ static inline u32 mdss_mdp_hwio_mask(struct mdss_mdp_hwio_cfg *cfg, u32 val)

#define MDSS_MDP_REG_HW_VERSION				0x0
#define MDSS_MDP_REG_DISP_INTF_SEL			0x00004
#define MDSS_MDP_REG_INTR2_EN				0x00008
#define MDSS_MDP_REG_INTR2_STATUS			0x0000C
#define MDSS_MDP_REG_INTR2_CLEAR			0x0002C
#define MDSS_MDP_REG_INTR_EN				0x00010
#define MDSS_MDP_REG_INTR_STATUS			0x00014
#define MDSS_MDP_REG_INTR_CLEAR				0x00018
@@ -115,6 +118,9 @@ static inline u32 mdss_mdp_hwio_mask(struct mdss_mdp_hwio_cfg *cfg, u32 val)
#define MDSS_MDP_INTR_INTF_3_UNDERRUN			BIT(30)
#define MDSS_MDP_INTR_INTF_3_VSYNC			BIT(31)

#define MDSS_MDP_INTR2_PING_PONG_2_CWB_OVERFLOW	        BIT(14)
#define MDSS_MDP_INTR2_PING_PONG_3_CWB_OVERFLOW	        BIT(15)

#define MDSS_MDP_HIST_INTR_VIG_0_DONE			BIT(0)
#define MDSS_MDP_HIST_INTR_VIG_0_RESET_DONE		BIT(1)
#define MDSS_MDP_HIST_INTR_VIG_1_DONE			BIT(4)
@@ -133,14 +139,15 @@ static inline u32 mdss_mdp_hwio_mask(struct mdss_mdp_hwio_cfg *cfg, u32 val)
#define MDSS_MDP_HIST_INTR_DSPP_3_RESET_DONE		BIT(23)

enum mdss_mdp_intr_type {
	MDSS_MDP_IRQ_WB_ROT_COMP = 0,
	MDSS_MDP_IRQ_WB_WFD = 4,
	MDSS_MDP_IRQ_PING_PONG_COMP = 8,
	MDSS_MDP_IRQ_PING_PONG_RD_PTR = 12,
	MDSS_MDP_IRQ_PING_PONG_WR_PTR = 16,
	MDSS_MDP_IRQ_PING_PONG_AUTO_REF = 20,
	MDSS_MDP_IRQ_INTF_UNDER_RUN = 24,
	MDSS_MDP_IRQ_INTF_VSYNC = 25,
	MDSS_MDP_IRQ_TYPE_WB_ROT_COMP,
	MDSS_MDP_IRQ_TYPE_WB_WFD_COMP,
	MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
	MDSS_MDP_IRQ_TYPE_PING_PONG_RD_PTR,
	MDSS_MDP_IRQ_TYPE_PING_PONG_WR_PTR,
	MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF,
	MDSS_MDP_IRQ_TYPE_INTF_UNDER_RUN,
	MDSS_MDP_IRQ_TYPE_INTF_VSYNC,
	MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
};

#define MDSS_MDP_REG_IGC_VIG_BASE			0x200
+43 −38
Original line number Diff line number Diff line
@@ -1124,9 +1124,10 @@ static void mdss_mdp_cmd_intf_recovery(void *data, int event)
	spin_lock_irqsave(&ctx->koff_lock, flags);
	if (reset_done && atomic_add_unless(&ctx->koff_cnt, -1, 0)) {
		pr_debug("%s: intf_num=%d\n", __func__, ctx->ctl->intf_num);
		mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
		mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
			ctx->current_pp_num);
		mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
		mdss_mdp_set_intr_callback_nosync(
				MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
				ctx->current_pp_num, NULL, NULL);
		if (mdss_mdp_cmd_do_notifier(ctx))
			notify_frame_timeout = true;
@@ -1163,9 +1164,9 @@ static void mdss_mdp_cmd_pingpong_done(void *arg)

	spin_lock(&ctx->koff_lock);

	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
		ctx->current_pp_num);
	mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
	mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
		ctx->current_pp_num, NULL, NULL);

	MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->current_pp_num);
@@ -1237,18 +1238,18 @@ static int mdss_mdp_setup_lineptr(struct mdss_mdp_cmd_ctx *ctx,
		if (enable) {
			/* enable clocks and irq */
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
			mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_WR_PTR,
			mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_PING_PONG_WR_PTR,
				ctx->default_pp_num);
		} else {
			/* disable clocks and irq */
			mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_WR_PTR,
			mdss_mdp_irq_disable(MDSS_MDP_IRQ_TYPE_PING_PONG_WR_PTR,
				ctx->default_pp_num);
			/*
			 * check the intr status and clear the irq before
			 * disabling the clocks
			 */
			mdss_mdp_intr_check_and_clear(
				MDSS_MDP_IRQ_PING_PONG_WR_PTR,
				MDSS_MDP_IRQ_TYPE_PING_PONG_WR_PTR,
				ctx->default_pp_num);

			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
@@ -1392,9 +1393,9 @@ static void mdss_mdp_cmd_autorefresh_pp_done(void *arg)
		return;
	}

	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
		ctx->current_pp_num);
	mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
	mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
		ctx->current_pp_num, NULL, NULL);

	MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->current_pp_num);
@@ -1688,18 +1689,18 @@ static int mdss_mdp_setup_vsync(struct mdss_mdp_cmd_ctx *ctx,
		if (enable) {
			/* enable clocks and irq */
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
			mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
			mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_PING_PONG_RD_PTR,
				ctx->default_pp_num);
		} else {
			/* disable clocks and irq */
			mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
			mdss_mdp_irq_disable(MDSS_MDP_IRQ_TYPE_PING_PONG_RD_PTR,
				ctx->default_pp_num);
			/*
			 * check the intr status and clear the irq before
			 * disabling the clocks
			 */
			mdss_mdp_intr_check_and_clear(
				MDSS_MDP_IRQ_PING_PONG_RD_PTR,
				MDSS_MDP_IRQ_TYPE_PING_PONG_RD_PTR,
				ctx->default_pp_num);

			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
@@ -1864,14 +1865,15 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)

	if (rc <= 0) {
		u32 status, mask;
		mask = BIT(MDSS_MDP_IRQ_PING_PONG_COMP + ctx->current_pp_num);
		mask = mdss_mdp_get_irq_mask(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
				ctx->current_pp_num);
		status = mask & readl_relaxed(ctl->mdata->mdp_base +
				MDSS_MDP_REG_INTR_STATUS);
		MDSS_XLOG(status, rc, atomic_read(&ctx->koff_cnt));
		if (status) {
			pr_warn("pp done but irq not triggered\n");
			mdss_mdp_irq_clear(ctl->mdata,
				MDSS_MDP_IRQ_PING_PONG_COMP,
				MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
				ctx->current_pp_num);
			local_irq_save(flags);
			mdss_mdp_cmd_pingpong_done(ctl);
@@ -1902,9 +1904,10 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
		ctx->pp_timeout_report_cnt++;
		rc = -EPERM;

		mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
		mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
			ctx->current_pp_num);
		mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
		mdss_mdp_set_intr_callback_nosync(
				MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
				ctx->current_pp_num, NULL, NULL);
		if (atomic_add_unless(&ctx->koff_cnt, -1, 0)
			&& mdss_mdp_cmd_do_notifier(ctx))
@@ -2277,7 +2280,7 @@ static void mdss_mdp_cmd_post_programming(struct mdss_mdp_ctl *mctl)
static void mdss_mdp_cmd_wait4_autorefresh_pp(struct mdss_mdp_ctl *ctl)
{
	int rc;
	u32 val, line_out, intr_type = MDSS_MDP_IRQ_PING_PONG_COMP;
	u32 val, line_out, intr_type = MDSS_MDP_IRQ_TYPE_PING_PONG_COMP;
	char __iomem *pp_base = ctl->mixer_left->pingpong_base;
	struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX];

@@ -2301,7 +2304,7 @@ static void mdss_mdp_cmd_wait4_autorefresh_pp(struct mdss_mdp_ctl *ctl)
				MDSS_MDP_REG_PP_LINE_COUNT);
			if (val == ctl->mixer_left->roi.h) {
				mdss_mdp_irq_clear(ctl->mdata,
					MDSS_MDP_IRQ_PING_PONG_COMP,
					MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
					ctx->current_pp_num);
				mdss_mdp_irq_disable_nosync(intr_type,
					ctx->current_pp_num);
@@ -2329,9 +2332,9 @@ static void mdss_mdp_cmd_autorefresh_done(void *arg)
		return;
	}

	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_AUTO_REF,
	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF,
		ctx->current_pp_num);
	mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_PING_PONG_AUTO_REF,
	mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF,
		ctx->current_pp_num, NULL, NULL);

	MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->current_pp_num);
@@ -2400,9 +2403,9 @@ static void mdss_mdp_cmd_wait4_autorefresh_done(struct mdss_mdp_ctl *ctl)
	reinit_completion(&ctx->autorefresh_done);

	/* enable autorefresh done */
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_AUTO_REF,
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF,
		ctx->current_pp_num, mdss_mdp_cmd_autorefresh_done, ctl);
	mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_AUTO_REF,
	mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF,
		ctx->current_pp_num);

	/*
@@ -2420,7 +2423,8 @@ static void mdss_mdp_cmd_wait4_autorefresh_done(struct mdss_mdp_ctl *ctl)
	if (rc <= 0) {
		u32 status, mask;

		mask = BIT(MDSS_MDP_IRQ_PING_PONG_AUTO_REF +
		mask = mdss_mdp_get_irq_mask(
				MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF,
				ctx->current_pp_num);
		status = mask & readl_relaxed(ctl->mdata->mdp_base +
				MDSS_MDP_REG_INTR_STATUS);
@@ -2428,14 +2432,14 @@ static void mdss_mdp_cmd_wait4_autorefresh_done(struct mdss_mdp_ctl *ctl)
		if (status) {
			pr_warn("autorefresh done but irq not triggered\n");
			mdss_mdp_irq_clear(ctl->mdata,
				MDSS_MDP_IRQ_PING_PONG_AUTO_REF,
				MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF,
				ctx->current_pp_num);
			local_irq_save(flags);
			mdss_mdp_irq_disable_nosync(
				MDSS_MDP_IRQ_PING_PONG_AUTO_REF,
				MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF,
				ctx->current_pp_num);
			mdss_mdp_set_intr_callback_nosync(
				MDSS_MDP_IRQ_PING_PONG_AUTO_REF,
				MDSS_MDP_IRQ_TYPE_PING_PONG_AUTO_REF,
				ctx->current_pp_num, NULL, NULL);
			local_irq_restore(flags);
			rc = 1;
@@ -2663,13 +2667,14 @@ static int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
		mdss_mdp_disable_autorefresh(ctl, sctl);
	}

	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP,
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
		ctx->current_pp_num, mdss_mdp_cmd_pingpong_done, ctl);
	mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->current_pp_num);
	mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
			ctx->current_pp_num);
	if (sctx) {
		mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP,
		mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
			sctx->current_pp_num, mdss_mdp_cmd_pingpong_done, sctl);
		mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP,
		mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
			sctx->current_pp_num);
	}

@@ -2805,11 +2810,11 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl,
		return 0;
	}

	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_PING_PONG_RD_PTR,
		ctx->default_pp_num, NULL, NULL);
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_WR_PTR,
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_PING_PONG_WR_PTR,
		ctx->default_pp_num, NULL, NULL);
	mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
	mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
		ctx->default_pp_num, NULL, NULL);

	memset(ctx, 0, sizeof(*ctx));
@@ -3140,10 +3145,10 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
		default_pp_num, aux_pp_num);
	MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt));

	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_PING_PONG_RD_PTR,
		ctx->default_pp_num, mdss_mdp_cmd_readptr_done, ctl);

	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_WR_PTR,
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_PING_PONG_WR_PTR,
		ctx->default_pp_num, mdss_mdp_cmd_writeptr_done, ctl);

	ret = mdss_mdp_cmd_tearcheck_setup(ctx, false);
Loading