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

Commit baaf5d15 authored by Veera Sundaram Sankaran's avatar Veera Sundaram Sankaran
Browse files

msm: mdss: add lineptr interrupt support for video mode panels



Add lineptr interrupt support by making use of INTR_PROG_LINE
register part of the interfaces. This would generate the interrupt
when the configured pixel location in the panel video timing in terms
of video raster structure is reached for the frame. The lineptr can
be updated through the lineptr_value node. Any modification to the value
would take effect immediately for video mode panels.

Write a value from 1 to [line size] to enable interrupts, 0 to disable:
	/sys/devices/virtual/graphics/fb0/lineptr_value

To handle interrupt, read from:
	/sys/devices/virtual/graphics/fb0/lineptr_event

Change-Id: I33c09b2dcfc7b49ce94f5e31b5b297b0445fd073
Acked-by: default avatarMike Mager <mikemager@codeaurora.org>
Signed-off-by: default avatarVeera Sundaram Sankaran <veeras@codeaurora.org>
parent 9befef11
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -323,6 +323,7 @@ struct mdss_data_type {
	struct irq_domain *irq_domain;
	u32 *mdp_irq_mask;
	u32 mdp_hist_irq_mask;
	u32 mdp_intf_irq_mask;

	int suspend_fs_ena;
	u8 clk_ena;
+16 −0
Original line number Diff line number Diff line
@@ -259,6 +259,9 @@ static inline u32 is_mdp_irq_enabled(void)
	if (mdata->mdp_hist_irq_mask)
		return 1;

	if (mdata->mdp_intf_irq_mask)
		return 1;

	return 0;
}

@@ -720,6 +723,17 @@ u32 mdss_mdp_get_irq_mask(u32 intr_type, u32 intf_num)
	return (idx < 0) ? 0 : mdp_irq_map[idx].irq_mask;
}

void mdss_mdp_enable_hw_irq(struct mdss_data_type *mdata)
{
	mdata->mdss_util->enable_irq(&mdss_mdp_hw);
}

void mdss_mdp_disable_hw_irq(struct mdss_data_type *mdata)
{
	if (!is_mdp_irq_enabled())
		mdata->mdss_util->disable_irq(&mdss_mdp_hw);
}

/* function assumes that mdp is clocked to access hw registers */
void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
		u32 intr_type, u32 intf_num)
@@ -1046,6 +1060,8 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr)
		if (hist_isr != 0)
			mdss_mdp_hist_intr_done(hist_isr);
	}

	mdss_mdp_video_isr(mdata->video_intf, mdata->nintf);
	return IRQ_HANDLED;
}

+8 −1
Original line number Diff line number Diff line
@@ -341,6 +341,9 @@ struct mdss_mdp_ctl_intfs_ops {
			enum dynamic_switch_modes mode, bool pre);
	/* called before do any register programming  from commit thread */
	void (*pre_programming)(struct mdss_mdp_ctl *ctl);

	/* to update lineptr, [1..yres] - enable, 0 - disable */
	int (*update_lineptr)(struct mdss_mdp_ctl *ctl, bool enable);
};

struct mdss_mdp_ctl {
@@ -1295,7 +1298,7 @@ static inline bool mdss_mdp_is_lineptr_supported(struct mdss_mdp_ctl *ctl)

	pinfo = &ctl->panel_data->panel_info;

	return (((pinfo->type == MIPI_CMD_PANEL)
	return (ctl->is_video_mode || ((pinfo->type == MIPI_CMD_PANEL)
			&& (pinfo->te.tear_check_en)) ? true : false);
}

@@ -1652,6 +1655,10 @@ void mdss_mdp_wb_free(struct mdss_mdp_writeback *wb);
void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl,
	struct mdss_panel_info *pinfo);

void mdss_mdp_video_isr(void *ptr, u32 count);
void mdss_mdp_enable_hw_irq(struct mdss_data_type *mdata);
void mdss_mdp_disable_hw_irq(struct mdss_data_type *mdata);

void mdss_mdp_set_supported_formats(struct mdss_data_type *mdata);

#ifdef CONFIG_FB_MSM_MDP_NONE
+10 −0
Original line number Diff line number Diff line
@@ -150,6 +150,12 @@ enum mdss_mdp_intr_type {
	MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
};

#define MDSS_MDP_INTF_INTR_PROG_LINE		BIT(8)

enum mdss_mdp_intf_intr_type {
	MDSS_MDP_INTF_IRQ_PROG_LINE = 8,
};

#define MDSS_MDP_REG_IGC_VIG_BASE			0x200
#define MDSS_MDP_REG_IGC_RGB_BASE			0x210
#define MDSS_MDP_REG_IGC_DMA_BASE			0x220
@@ -659,6 +665,10 @@ enum mdss_mpd_intf_index {
#define MDSS_MDP_REG_INTF_TPG_BLK_WHITE_PATTERN_FRAMES	0x118
#define MDSS_MDP_REG_INTF_TPG_RGB_MAPPING		0x11C
#define MDSS_MDP_REG_INTF_PROG_FETCH_START		0x170
#define MDSS_MDP_REG_INTF_INTR_EN			0x1C0
#define MDSS_MDP_REG_INTF_INTR_STATUS			0x1C4
#define MDSS_MDP_REG_INTF_INTR_CLEAR			0x1C8
#define MDSS_MDP_REG_INTF_PROG_LINE_INTR_CONF		0x250
#define MDSS_MDP_REG_INTF_VBLANK_END_CONF		0x264

#define MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN		0x0A8
+421 −44
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@

#include <linux/iopoll.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
#include <linux/memblock.h>
#include <video/msm_hdmi_modes.h>
@@ -34,6 +35,16 @@
/* Filter out input events for 1 vsync time after receiving an input event*/
#define INPUT_EVENT_HANDLER_DELAY_USECS 16000

enum {
	MDP_INTF_INTR_PROG_LINE,
	MDP_INTF_INTR_MAX,
};

struct intr_callback {
	void (*func)(void *);
	void *arg;
};

/* intf timing settings */
struct intf_timing_params {
	u32 width;
@@ -73,6 +84,20 @@ struct mdss_mdp_video_ctx {
	struct list_head vsync_handlers;
	struct mdss_intf_recovery intf_recovery;
	struct work_struct early_wakeup_dfps_work;

	atomic_t lineptr_ref;
	spinlock_t lineptr_lock;
	struct mutex lineptr_mtx;
	struct list_head lineptr_handlers;

	struct intf_timing_params itp;
	bool lineptr_enabled;
	u32 prev_wr_ptr_irq;

	struct intr_callback mdp_intf_intr_cb[MDP_INTF_INTR_MAX];
	u32 intf_irq_mask;
	spinlock_t mdss_mdp_video_lock;
	spinlock_t mdss_mdp_intf_intr_lock;
};

static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx,
@@ -107,6 +132,158 @@ line_count_exit:
	return line_cnt;
}

static int mdss_mdp_intf_intr2index(u32 intr_type)
{
	int index = -1;

	switch (intr_type) {
	case MDSS_MDP_INTF_IRQ_PROG_LINE:
		index = MDP_INTF_INTR_PROG_LINE;
		break;
	}
	return index;
}

int mdss_mdp_set_intf_intr_callback(struct mdss_mdp_video_ctx *ctx,
		u32 intr_type, void (*fnc_ptr)(void *), void *arg)
{
	unsigned long flags;
	int index;

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

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

	return 0;
}

static inline void mdss_mdp_intf_intr_done(struct mdss_mdp_video_ctx *ctx,
	int index)
{
	void (*fnc)(void *);
	void *arg;

	spin_lock(&ctx->mdss_mdp_intf_intr_lock);
	fnc = ctx->mdp_intf_intr_cb[index].func;
	arg = ctx->mdp_intf_intr_cb[index].arg;
	spin_unlock(&ctx->mdss_mdp_intf_intr_lock);
	if (fnc)
		fnc(arg);
}

/*
 * mdss_mdp_video_isr() - ISR handler for video mode interfaces
 *
 * @ptr: pointer to all the video ctx
 * @count: number of interfaces which should match ctx
 *
 * The video isr is meant to handle all the interrupts in video interface,
 * in MDSS_MDP_REG_INTF_INTR_EN register. Currently it handles only the
 * programmable lineptr interrupt.
 */
void mdss_mdp_video_isr(void *ptr, u32 count)
{
	struct mdss_mdp_video_ctx *head = (struct mdss_mdp_video_ctx *) ptr;
	int i;

	for (i = 0; i < count; i++) {
		struct mdss_mdp_video_ctx *ctx = &head[i];
		u32 intr, mask;

		if (!ctx->intf_irq_mask)
			continue;

		intr = mdp_video_read(ctx, MDSS_MDP_REG_INTF_INTR_STATUS);
		mask = mdp_video_read(ctx, MDSS_MDP_REG_INTF_INTR_EN);
		mdp_video_write(ctx, MDSS_MDP_REG_INTF_INTR_CLEAR, intr);

		pr_debug("%s: intf=%d intr=%x mask=%x\n", __func__,
				i, intr, mask);

		if (!(intr & mask))
			continue;

		if (intr & MDSS_MDP_INTF_INTR_PROG_LINE)
			mdss_mdp_intf_intr_done(ctx, MDP_INTF_INTR_PROG_LINE);
	}
}

static int mdss_mdp_video_intf_irq_enable(struct mdss_mdp_ctl *ctl,
		u32 intr_type)
{
	struct mdss_mdp_video_ctx *ctx;
	unsigned long irq_flags;
	int ret = 0;
	u32 irq;

	if (!ctl || !ctl->intf_ctx[MASTER_CTX])
		return -ENODEV;

	ctx = ctl->intf_ctx[MASTER_CTX];

	irq = 1 << intr_type;

	spin_lock_irqsave(&ctx->mdss_mdp_video_lock, irq_flags);
	if (ctx->intf_irq_mask & irq) {
		pr_warn("MDSS MDP Intf IRQ-0x%x is already set, mask=%x\n",
				irq, ctx->intf_irq_mask);
		ret = -EBUSY;
	} else {
		pr_debug("MDSS MDP Intf IRQ mask old=%x new=%x\n",
				ctx->intf_irq_mask, irq);
		ctx->intf_irq_mask |= irq;
		mdp_video_write(ctx, MDSS_MDP_REG_INTF_INTR_CLEAR, irq);
		mdp_video_write(ctx, MDSS_MDP_REG_INTF_INTR_EN,
				ctx->intf_irq_mask);
		ctl->mdata->mdp_intf_irq_mask |=
				(1 << (ctx->intf_num - MDSS_MDP_INTF0));
		mdss_mdp_enable_hw_irq(ctl->mdata);
	}
	spin_unlock_irqrestore(&ctx->mdss_mdp_video_lock, irq_flags);

	return ret;
}

void mdss_mdp_video_intf_irq_disable(struct mdss_mdp_ctl *ctl, u32 intr_type)
{
	struct mdss_mdp_video_ctx *ctx;
	unsigned long irq_flags;
	u32 irq;

	if (!ctl || !ctl->intf_ctx[MASTER_CTX])
		return;

	ctx = ctl->intf_ctx[MASTER_CTX];

	irq = 1 << intr_type;

	spin_lock_irqsave(&ctx->mdss_mdp_video_lock, irq_flags);
	if (!(ctx->intf_irq_mask & irq)) {
		pr_warn("MDSS MDP Intf IRQ-%x is NOT set, mask=%x\n",
				irq, ctx->intf_irq_mask);
	} else {
		ctx->intf_irq_mask &= ~irq;
		mdp_video_write(ctx, MDSS_MDP_REG_INTF_INTR_CLEAR, irq);
		mdp_video_write(ctx, MDSS_MDP_REG_INTF_INTR_EN,
				ctx->intf_irq_mask);
		if (ctx->intf_irq_mask == 0) {
			ctl->mdata->mdp_intf_irq_mask &=
				~(1 << (ctx->intf_num - MDSS_MDP_INTF0));
			mdss_mdp_disable_hw_irq(ctl->mdata);
		}
	}
	spin_unlock_irqrestore(&ctx->mdss_mdp_video_lock, irq_flags);
}

int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata,
				u32 *offsets,  u32 count)
{
@@ -125,6 +302,7 @@ int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata,
		head[i].ref_cnt = 0;
		head[i].intf_num = i + MDSS_MDP_INTF0;
		INIT_LIST_HEAD(&head[i].vsync_handlers);
		INIT_LIST_HEAD(&head[i].lineptr_handlers);
	}

	mdata->video_intf = head;
@@ -344,6 +522,25 @@ static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
	return 0;
}

static void mdss_mdp_video_timegen_flush(struct mdss_mdp_ctl *ctl,
					struct mdss_mdp_video_ctx *sctx)
{
	u32 ctl_flush;
	struct mdss_data_type *mdata;

	mdata = ctl->mdata;
	ctl_flush = (BIT(31) >> (ctl->intf_num - MDSS_MDP_INTF0));
	if (sctx) {
		/* For 8939, sctx is always INTF2 and the flush bit is BIT 31 */
		if (mdata->mdp_rev == MDSS_MDP_HW_REV_108)
			ctl_flush |= BIT(31);
		else
			ctl_flush |= (BIT(31) >>
					(sctx->intf_num - MDSS_MDP_INTF0));
	}
	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush);
	MDSS_XLOG(ctl->intf_num, sctx?sctx->intf_num:0xf00, ctl_flush);
}

static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl, bool clear)
{
@@ -436,6 +633,167 @@ static int mdss_mdp_video_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
	return 0;
}

static int mdss_mdp_video_add_lineptr_handler(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_lineptr_handler *handle)
{
	struct mdss_mdp_video_ctx *ctx;
	unsigned long flags;
	int ret = 0;
	bool irq_en = false;

	if (!handle || !(handle->lineptr_handler)) {
		ret = -EINVAL;
		goto exit;
	}

	ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
	if (!ctx) {
		pr_err("invalid ctx for ctl=%d\n", ctl->num);
		ret = -ENODEV;
		goto exit;
	}

	spin_lock_irqsave(&ctx->lineptr_lock, flags);
	if (!handle->enabled) {
		handle->enabled = true;
		list_add(&handle->list, &ctx->lineptr_handlers);
		irq_en = true;
	}
	spin_unlock_irqrestore(&ctx->lineptr_lock, flags);

	if (irq_en) {
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
		mutex_lock(&ctx->lineptr_mtx);
		if (atomic_inc_return(&ctx->lineptr_ref) == 1)
			mdss_mdp_video_intf_irq_enable(ctl,
				MDSS_MDP_INTF_IRQ_PROG_LINE);
		mutex_unlock(&ctx->lineptr_mtx);
	}
	ctx->lineptr_enabled = true;

exit:
	return ret;
}

static int mdss_mdp_video_remove_lineptr_handler(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_lineptr_handler *handle)
{
	struct mdss_mdp_video_ctx *ctx;
	unsigned long flags;
	bool irq_dis = false;

	ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
	if (!ctx || !ctx->lineptr_enabled)
		return -EINVAL;

	spin_lock_irqsave(&ctx->lineptr_lock, flags);
	if (handle->enabled) {
		handle->enabled = false;
		list_del_init(&handle->list);
		irq_dis = true;
	}
	spin_unlock_irqrestore(&ctx->lineptr_lock, flags);

	if (irq_dis) {
		mutex_lock(&ctx->lineptr_mtx);
		if (atomic_dec_return(&ctx->lineptr_ref) == 0)
			mdss_mdp_video_intf_irq_disable(ctl,
				MDSS_MDP_INTF_IRQ_PROG_LINE);
		mutex_unlock(&ctx->lineptr_mtx);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
	}
	ctx->lineptr_enabled = false;
	ctx->prev_wr_ptr_irq = 0;

	return 0;
}

static int mdss_mdp_video_set_lineptr(struct mdss_mdp_ctl *ctl,
	u32 new_lineptr)
{
	struct mdss_mdp_video_ctx *ctx;
	u32 pixel_start, offset, hsync_period;

	ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
	if (!ctx) {
		pr_err("invalid ctx for ctl=%d\n", ctl->num);
		return -ENODEV;
	}

	if (0 == new_lineptr) {
		mdp_video_write(ctx,
			MDSS_MDP_REG_INTF_PROG_LINE_INTR_CONF, UINT_MAX);
	} else if (new_lineptr <= ctx->itp.yres) {
		hsync_period = ctx->itp.hsync_pulse_width
			+ ctx->itp.h_back_porch + ctx->itp.width
			+ ctx->itp.h_front_porch;

		offset = ((ctx->itp.vsync_pulse_width + ctx->itp.v_back_porch)
				* hsync_period) + ctx->itp.hsync_skew;

		/* convert from line to pixel */
		pixel_start = offset + (hsync_period * (new_lineptr - 1));
		mdp_video_write(ctx, MDSS_MDP_REG_INTF_PROG_LINE_INTR_CONF,
			pixel_start);

		mdss_mdp_video_timegen_flush(ctl, ctx);
	} else {
		pr_err("invalid new lineptr_value: new=%d yres=%d\n",
				new_lineptr, ctx->itp.yres);
		return -EINVAL;
	}

	return 0;
}

static int mdss_mdp_video_lineptr_ctrl(struct mdss_mdp_ctl *ctl, bool enable)
{
	struct mdss_mdp_pp_tear_check *te;
	struct mdss_mdp_video_ctx *ctx;
	int rc = 0;

	ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
	if (!ctx || !ctl->is_master)
		return -EINVAL;

	te = &ctl->panel_data->panel_info.te;
	pr_debug("%pS->%s: ctl=%d en=%d, prev_lineptr=%d, lineptr=%d\n",
			__builtin_return_address(0), __func__, ctl->num,
			enable, ctx->prev_wr_ptr_irq, te->wr_ptr_irq);

	if (enable) {
		/* update reg only if the value has changed */
		if (ctx->prev_wr_ptr_irq != te->wr_ptr_irq) {
			if (mdss_mdp_video_set_lineptr(ctl,
						te->wr_ptr_irq) < 0) {
				/* invalid new value, so restore the previous */
				te->wr_ptr_irq = ctx->prev_wr_ptr_irq;
				goto end;
			}
			ctx->prev_wr_ptr_irq = te->wr_ptr_irq;
		}

		/*
		 * add handler only when lineptr is not enabled
		 * and wr ptr is non zero
		 */
		if (!ctx->lineptr_enabled && te->wr_ptr_irq)
			rc = mdss_mdp_video_add_lineptr_handler(ctl,
				&ctl->lineptr_handler);
		/* Disable handler when the value is zero */
		else if (ctx->lineptr_enabled && !te->wr_ptr_irq)
			rc = mdss_mdp_video_remove_lineptr_handler(ctl,
				&ctl->lineptr_handler);
	} else {
		if (ctx->lineptr_enabled)
			rc = mdss_mdp_video_remove_lineptr_handler(ctl,
				&ctl->lineptr_handler);
	}

end:
	return rc;
}

void mdss_mdp_turn_off_time_engine(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_video_ctx *ctx, u32 sleep_time)
{
@@ -492,6 +850,8 @@ static int mdss_mdp_video_ctx_stop(struct mdss_mdp_ctl *ctl,
		ctx->intf_num, NULL, NULL);
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_INTF_UNDER_RUN,
		ctx->intf_num, NULL, NULL);
	mdss_mdp_set_intf_intr_callback(ctx, MDSS_MDP_INTF_IRQ_PROG_LINE,
		NULL, NULL);

	ctx->ref_cnt--;
end:
@@ -551,6 +911,9 @@ static int mdss_mdp_video_intfs_stop(struct mdss_mdp_ctl *ctl,
	list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
		mdss_mdp_video_remove_vsync_handler(ctl, handle);

	if (mdss_mdp_is_lineptr_supported(ctl))
		mdss_mdp_video_lineptr_ctrl(ctl, false);

	return 0;
}

@@ -607,6 +970,28 @@ static void mdss_mdp_video_vsync_intr_done(void *arg)
	spin_unlock(&ctx->vsync_lock);
}

static void mdss_mdp_video_lineptr_intr_done(void *arg)
{
	struct mdss_mdp_ctl *ctl = arg;
	struct mdss_mdp_video_ctx *ctx = ctl->intf_ctx[MASTER_CTX];
	struct mdss_mdp_lineptr_handler *tmp;
	ktime_t lineptr_time;

	if (!ctx) {
		pr_err("invalid ctx\n");
		return;
	}

	lineptr_time = ktime_get();
	pr_debug("intr lineptr_time=%lld\n", ktime_to_ms(lineptr_time));

	spin_lock(&ctx->lineptr_lock);
	list_for_each_entry(tmp, &ctx->lineptr_handlers, list) {
		tmp->lineptr_handler(ctl, lineptr_time);
	}
	spin_unlock(&ctx->lineptr_lock);
}

static int mdss_mdp_video_pollwait(struct mdss_mdp_ctl *ctl)
{
	struct mdss_mdp_video_ctx *ctx = ctl->intf_ctx[MASTER_CTX];
@@ -889,26 +1274,6 @@ static int mdss_mdp_video_dfps_check_line_cnt(struct mdss_mdp_ctl *ctl)
	return 0;
}

static void mdss_mdp_video_timegen_flush(struct mdss_mdp_ctl *ctl,
					struct mdss_mdp_video_ctx *sctx)
{
	u32 ctl_flush;
	struct mdss_data_type *mdata;

	mdata = ctl->mdata;
	ctl_flush = (BIT(31) >> (ctl->intf_num - MDSS_MDP_INTF0));
	if (sctx) {
		/* For 8939, sctx is always INTF2 and the flush bit is BIT 31 */
		if (mdata->mdp_rev == MDSS_MDP_HW_REV_108)
			ctl_flush |= BIT(31);
		else
			ctl_flush |= (BIT(31) >>
					(sctx->intf_num - MDSS_MDP_INTF0));
	}
	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush);
	MDSS_XLOG(ctl->intf_num, sctx?sctx->intf_num:0xf00, ctl_flush);
}

/**
 * mdss_mdp_video_config_fps() - modify the fps.
 * @ctl: pointer to the master controller.
@@ -1163,6 +1528,9 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
			CTL_INTF_EVENT_FLAG_DEFAULT);
	}

	if (mdss_mdp_is_lineptr_supported(ctl))
		mdss_mdp_video_lineptr_ctrl(ctl, true);

	return 0;
}

@@ -1397,7 +1765,7 @@ static void mdss_mdp_handoff_programmable_fetch(struct mdss_mdp_ctl *ctl,
static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_video_ctx *ctx, struct mdss_panel_info *pinfo)
{
	struct intf_timing_params itp = {0};
	struct intf_timing_params *itp = &ctx->itp;
	u32 dst_bpp;
	struct mdss_data_type *mdata = ctl->mdata;
	struct dsc_desc *dsc = NULL;
@@ -1409,6 +1777,11 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
	spin_lock_init(&ctx->dfps_lock);
	mutex_init(&ctx->vsync_mtx);
	atomic_set(&ctx->vsync_ref, 0);
	spin_lock_init(&ctx->lineptr_lock);
	spin_lock_init(&ctx->mdss_mdp_video_lock);
	spin_lock_init(&ctx->mdss_mdp_intf_intr_lock);
	mutex_init(&ctx->lineptr_mtx);
	atomic_set(&ctx->lineptr_ref, 0);
	INIT_WORK(&ctl->recover_work, recover_underrun_work);

	if (ctl->intf_type == MDSS_INTF_DSI) {
@@ -1452,49 +1825,52 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_INTF_UNDER_RUN,
				ctx->intf_num,
				mdss_mdp_video_underrun_intr_done, ctl);
	mdss_mdp_set_intf_intr_callback(ctx, MDSS_MDP_INTF_IRQ_PROG_LINE,
			mdss_mdp_video_lineptr_intr_done, ctl);

	dst_bpp = pinfo->fbc.enabled ? (pinfo->fbc.target_bpp) : (pinfo->bpp);

	itp.width = mult_frac((pinfo->xres + pinfo->lcdc.border_left +
	memset(itp, 0, sizeof(struct intf_timing_params));
	itp->width = mult_frac((pinfo->xres + pinfo->lcdc.border_left +
			pinfo->lcdc.border_right), dst_bpp, pinfo->bpp);
	itp.height = pinfo->yres + pinfo->lcdc.border_top +
	itp->height = pinfo->yres + pinfo->lcdc.border_top +
					pinfo->lcdc.border_bottom;
	itp.border_clr = pinfo->lcdc.border_clr;
	itp.underflow_clr = pinfo->lcdc.underflow_clr;
	itp.hsync_skew = pinfo->lcdc.hsync_skew;
	itp->border_clr = pinfo->lcdc.border_clr;
	itp->underflow_clr = pinfo->lcdc.underflow_clr;
	itp->hsync_skew = pinfo->lcdc.hsync_skew;

	/* tg active area is not work, hence yres should equal to height */
	itp.xres = mult_frac((pinfo->xres + pinfo->lcdc.border_left +
	itp->xres = mult_frac((pinfo->xres + pinfo->lcdc.border_left +
			pinfo->lcdc.border_right), dst_bpp, pinfo->bpp);

	itp.yres = pinfo->yres + pinfo->lcdc.border_top +
	itp->yres = pinfo->yres + pinfo->lcdc.border_top +
				pinfo->lcdc.border_bottom;

	if (dsc) {	/* compressed */
		itp.width = dsc->pclk_per_line;
		itp.xres = dsc->pclk_per_line;
		itp->width = dsc->pclk_per_line;
		itp->xres = dsc->pclk_per_line;
	}

	itp.h_back_porch = pinfo->lcdc.h_back_porch;
	itp.h_front_porch = pinfo->lcdc.h_front_porch;
	itp.v_back_porch = pinfo->lcdc.v_back_porch;
	itp.v_front_porch = pinfo->lcdc.v_front_porch;
	itp.hsync_pulse_width = pinfo->lcdc.h_pulse_width;
	itp.vsync_pulse_width = pinfo->lcdc.v_pulse_width;
	itp->h_back_porch = pinfo->lcdc.h_back_porch;
	itp->h_front_porch = pinfo->lcdc.h_front_porch;
	itp->v_back_porch = pinfo->lcdc.v_back_porch;
	itp->v_front_porch = pinfo->lcdc.v_front_porch;
	itp->hsync_pulse_width = pinfo->lcdc.h_pulse_width;
	itp->vsync_pulse_width = pinfo->lcdc.v_pulse_width;
	/*
	 * In case of YUV420 output, MDP outputs data at half the rate. So
	 * reduce all horizontal parameters by half
	 */
	if (ctl->cdm && pinfo->out_format == MDP_Y_CBCR_H2V2) {
		itp.width >>= 1;
		itp.hsync_skew >>= 1;
		itp.xres >>= 1;
		itp.h_back_porch >>= 1;
		itp.h_front_porch >>= 1;
		itp.hsync_pulse_width >>= 1;
		itp->width >>= 1;
		itp->hsync_skew >>= 1;
		itp->xres >>= 1;
		itp->h_back_porch >>= 1;
		itp->h_front_porch >>= 1;
		itp->hsync_pulse_width >>= 1;
	}
	if (!ctl->panel_data->panel_info.cont_splash_enabled) {
		if (mdss_mdp_video_timegen_setup(ctl, &itp, ctx)) {
		if (mdss_mdp_video_timegen_setup(ctl, itp, ctx)) {
			pr_err("unable to set timing parameters intfs: %d\n",
				ctx->intf_num);
			return -EINVAL;
@@ -1511,8 +1887,8 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
	mdss_mdp_disable_prefill(ctl);

	mdp_video_write(ctx, MDSS_MDP_REG_INTF_PANEL_FORMAT, ctl->dst_format);
	return 0;

	return 0;
}

static int mdss_mdp_video_intfs_setup(struct mdss_mdp_ctl *ctl,
@@ -1763,6 +2139,7 @@ int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
	ctl->ops.remove_vsync_handler = mdss_mdp_video_remove_vsync_handler;
	ctl->ops.config_fps_fnc = mdss_mdp_video_config_fps;
	ctl->ops.early_wake_up_fnc = mdss_mdp_video_early_wake_up;
	ctl->ops.update_lineptr = mdss_mdp_video_lineptr_ctrl;

	return 0;
}
Loading