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

Commit 7a015c49 authored by Veera Sundaram Sankaran's avatar Veera Sundaram Sankaran Committed by Jeykumar Sankaran
Browse files

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



Add lineptr interrupt support by making use of the mdp write pointer
interrupt. This would make use of the hw feature to generate interrupts
when the display read pointer reaches the configured value. Expose event
and lineptr sysfs nodes to monitor and to configure the lineptr values.
The lineptr handlers are added during kickoff and removed during pingpong
work done. The configured lineptr value gets effect only in the next
kickoff. This feature is currently supported only for command mode panels.
It would skip setting the handlers for partial update frames, as the
feature is supported only with full frame updates.

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: Id044d1bad4159955078ccab4d4dc82807d7e6102
Acked-by: default avatarMike Mager <mikemager@qti.qualcomm.com>
Signed-off-by: default avatarVeera Sundaram Sankaran <veeras@codeaurora.org>
parent ee833ce5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1325,6 +1325,7 @@ static void mdss_panel_parse_te_params(struct device_node *np,
	rc = of_property_read_u32
		(np, "qcom,mdss-tear-check-rd-ptr-trigger-intr", &tmp);
	te->rd_ptr_irq = (!rc ? tmp : timing->yres + 1);
	te->wr_ptr_irq = 0;
}


+50 −0
Original line number Diff line number Diff line
@@ -190,6 +190,12 @@ struct mdss_mdp_vsync_handler {
	struct list_head list;
};

struct mdss_mdp_lineptr_handler {
	bool enabled;
	mdp_vsync_handler_t lineptr_handler;
	struct list_head list;
};

enum mdss_mdp_wb_ctl_type {
	MDSS_MDP_WB_CTL_TYPE_BLOCK = 1,
	MDSS_MDP_WB_CTL_TYPE_LINE
@@ -342,6 +348,8 @@ struct mdss_mdp_ctl {
	struct work_struct recover_work;
	struct work_struct remove_underrun_handler;

	struct mdss_mdp_lineptr_handler lineptr_handler;

	/*
	 * This ROI is aligned to as per following guidelines and
	 * sent to the panel driver.
@@ -659,7 +667,9 @@ struct mdss_mdp_wfd;

struct mdss_overlay_private {
	ktime_t vsync_time;
	ktime_t lineptr_time;
	struct kernfs_node *vsync_event_sd;
	struct kernfs_node *lineptr_event_sd;
	struct kernfs_node *hist_event_sd;
	struct kernfs_node *bl_event_sd;
	struct kernfs_node *ad_event_sd;
@@ -1180,6 +1190,46 @@ static inline int mdss_mdp_get_display_id(struct mdss_mdp_pipe *pipe)
	return (pipe && pipe->mfd) ? pipe->mfd->index : -1;
}

static inline bool mdss_mdp_is_full_frame_update(struct mdss_mdp_ctl *ctl)
{
	struct mdss_mdp_mixer *mixer;
	struct mdss_rect *roi;

	if (mdss_mdp_get_pu_type(ctl) != MDSS_MDP_DEFAULT_UPDATE)
		return false;

	if (ctl->mixer_left->valid_roi) {
		mixer = ctl->mixer_left;
		roi = &mixer->roi;
		if ((roi->x != 0) || (roi->y != 0) || (roi->w != mixer->width)
			|| (roi->h != mixer->height))
			return false;
	}

	if (ctl->mixer_right && ctl->mixer_right->valid_roi) {
		mixer = ctl->mixer_right;
		roi = &mixer->roi;
		if ((roi->x != 0) || (roi->y != 0) || (roi->w != mixer->width)
			|| (roi->h != mixer->height))
			return false;
	}

	return true;
}

static inline bool mdss_mdp_is_lineptr_supported(struct mdss_mdp_ctl *ctl)
{
	struct mdss_panel_info *pinfo;

	if (!ctl || !ctl->mixer_left || !ctl->is_master)
		return false;

	pinfo = &ctl->panel_data->panel_info;

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

irqreturn_t mdss_mdp_isr(int irq, void *ptr);
void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
		u32 intr_type, u32 intf_num);
+233 −3
Original line number Diff line number Diff line
@@ -60,10 +60,12 @@ struct mdss_mdp_cmd_ctx {
	struct completion pp_done;
	wait_queue_head_t pp_waitq;
	struct list_head vsync_handlers;
	struct list_head lineptr_handlers;
	int panel_power_state;
	atomic_t koff_cnt;
	u32 intf_stopped;
	struct mutex mdp_rdptr_lock;
	struct mutex mdp_wrptr_lock;
	struct mutex clk_mtx;
	spinlock_t clk_lock;
	spinlock_t koff_lock;
@@ -86,6 +88,9 @@ struct mdss_mdp_cmd_ctx {
	struct completion autorefresh_done;

	int vsync_irq_cnt;
	int lineptr_irq_cnt;
	bool lineptr_enabled;
	u32 prev_wr_ptr_irq;

	struct mdss_intf_recovery intf_recovery;
	struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
@@ -280,9 +285,10 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,

	cfg |= vclks_line;

	pr_debug("%s: yres=%d vclks=%x height=%d init=%d rd=%d start=%d\n",
	pr_debug("%s: yres=%d vclks=%x height=%d init=%d rd=%d start=%d wr=%d\n",
		__func__, pinfo->yres, vclks_line, te->sync_cfg_height,
		te->vsync_init_val, te->rd_ptr_irq, te->start_pos);
		te->vsync_init_val, te->rd_ptr_irq, te->start_pos,
		te->wr_ptr_irq);
	pr_debug("thrd_start =%d thrd_cont=%d pp_split=%d\n",
		te->sync_threshold_start, te->sync_threshold_continue,
		ctx->pingpong_split_slave);
@@ -303,6 +309,9 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
	mdss_mdp_pingpong_write(pingpong_base,
		MDSS_MDP_REG_PP_RD_PTR_IRQ,
		te ? te->rd_ptr_irq : 0);
	mdss_mdp_pingpong_write(pingpong_base,
		MDSS_MDP_REG_PP_WR_PTR_IRQ,
		te ? te->wr_ptr_irq : 0);
	mdss_mdp_pingpong_write(pingpong_base,
		MDSS_MDP_REG_PP_START_POS,
		te ? te->start_pos : 0);
@@ -967,6 +976,28 @@ static void mdss_mdp_cmd_readptr_done(void *arg)
	spin_unlock(&ctx->clk_lock);
}

static void mdss_mdp_cmd_writeptr_done(void *arg)
{
	struct mdss_mdp_ctl *ctl = arg;
	struct mdss_mdp_cmd_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();

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

static void mdss_mdp_cmd_intf_recovery(void *data, int event)
{
	struct mdss_mdp_cmd_ctx *ctx = data;
@@ -1079,6 +1110,178 @@ static void mdss_mdp_cmd_pingpong_done(void *arg)
	spin_unlock(&ctx->koff_lock);
}

static int mdss_mdp_setup_lineptr(struct mdss_mdp_cmd_ctx *ctx,
	bool enable)
{
	int changed = 0;

	mutex_lock(&ctx->mdp_wrptr_lock);

	if (enable) {
		if (ctx->lineptr_irq_cnt == 0)
			changed++;
		ctx->lineptr_irq_cnt++;
	} else {
		if (ctx->lineptr_irq_cnt) {
			ctx->lineptr_irq_cnt--;
			if (ctx->lineptr_irq_cnt == 0)
				changed++;
		} else {
			pr_warn("%pS->%s: wr_ptr can not be turned off\n",
				__builtin_return_address(0), __func__);
		}
	}

	if (changed)
		MDSS_XLOG(ctx->lineptr_irq_cnt, enable, current->pid);

	pr_debug("%pS->%s: lineptr_irq_cnt=%d changed=%d enable=%d ctl:%d pp:%d\n",
			__builtin_return_address(0), __func__,
			ctx->lineptr_irq_cnt, changed, enable,
			ctx->ctl->num, ctx->default_pp_num);

	if (changed) {
		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,
				ctx->default_pp_num);
		} else {
			/* disable clocks and irq */
			mdss_mdp_irq_disable(MDSS_MDP_IRQ_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,
				ctx->default_pp_num);

			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
		}
	}

	mutex_unlock(&ctx->mdp_wrptr_lock);
	return ctx->lineptr_irq_cnt;
}

static int mdss_mdp_cmd_add_lineptr_handler(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_lineptr_handler *handle)
{
	struct mdss_mdp_cmd_ctx *ctx;
	unsigned long flags;
	int ret = 0;

	mutex_lock(&ctl->offlock);
	ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX];
	if (!ctx || !ctl->is_master) {
		ret = -EINVAL;
		goto done;
	}

	pr_debug("%pS->%s: ctl=%d\n",
		__builtin_return_address(0), __func__, ctl->num);

	MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt));

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

	if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY)
		mutex_lock(&cmd_clk_mtx);

	mdss_mdp_setup_lineptr(ctx, true);
	ctx->lineptr_enabled = true;

	if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY)
		mutex_unlock(&cmd_clk_mtx);
done:
	mutex_unlock(&ctl->offlock);

	return ret;
}

static int mdss_mdp_cmd_remove_lineptr_handler(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_lineptr_handler *handle)
{
	struct mdss_mdp_cmd_ctx *ctx;
	unsigned long flags;
	bool disabled = true;

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

	pr_debug("%pS->%s: ctl=%d\n",
		__builtin_return_address(0), __func__, ctl->num);

	MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt));

	spin_lock_irqsave(&ctx->clk_lock, flags);
	if (handle->enabled) {
		handle->enabled = false;
		list_del_init(&handle->list);
	} else {
		disabled = false;
	}
	spin_unlock_irqrestore(&ctx->clk_lock, flags);

	if (disabled)
		mdss_mdp_setup_lineptr(ctx, false);
	ctx->lineptr_enabled = false;
	ctx->prev_wr_ptr_irq = 0;

	return 0;
}

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

	ctx = (struct mdss_mdp_cmd_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) {
			ctx->prev_wr_ptr_irq = te->wr_ptr_irq;
			mdss_mdp_pingpong_write(ctl->mixer_left->pingpong_base,
				MDSS_MDP_REG_PP_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_cmd_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_cmd_remove_lineptr_handler(ctl,
				&ctl->lineptr_handler);
	} else {
		if (ctx->lineptr_enabled)
			rc = mdss_mdp_cmd_remove_lineptr_handler(ctl,
				&ctl->lineptr_handler);
	}

	return rc;
}

/**
 * mdss_mdp_cmd_autorefresh_pp_done() - pp done irq callback for autorefresh
 * @arg: void pointer to the controller context.
@@ -1114,14 +1317,20 @@ static void pingpong_done_work(struct work_struct *work)
	u32 status;
	struct mdss_mdp_cmd_ctx *ctx =
		container_of(work, typeof(*ctx), pp_done_work);
	struct mdss_mdp_ctl *ctl = ctx->ctl;

	if (ctx->ctl) {
	if (ctl) {
		while (atomic_add_unless(&ctx->pp_done_cnt, -1, 0))
			mdss_mdp_ctl_notify(ctx->ctl, MDP_NOTIFY_FRAME_DONE);

		status = mdss_mdp_ctl_perf_get_transaction_status(ctx->ctl);
		if (status == 0)
			mdss_mdp_ctl_perf_release_bw(ctx->ctl);

		if (!ctl->is_master)
			ctl = mdss_mdp_get_main_ctl(ctl);
		if (mdss_mdp_is_lineptr_supported(ctl))
			mdss_mdp_cmd_lineptr_ctrl(ctl, false);
	}
}

@@ -2370,6 +2579,13 @@ static int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
			PERF_SW_COMMIT_STATE, PERF_STATUS_DONE);
	}

	if (mdss_mdp_is_lineptr_supported(ctl)) {
		if (mdss_mdp_is_full_frame_update(ctl))
			mdss_mdp_cmd_lineptr_ctrl(ctl, true);
		else if (ctx->lineptr_enabled)
			mdss_mdp_cmd_lineptr_ctrl(ctl, false);
	}

	/* Kickoff */
	__mdss_mdp_kickoff(ctl, ctx);

@@ -2450,6 +2666,11 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl,
		while (mdss_mdp_setup_vsync(ctx, false))
			;
	}
	if (ctx->lineptr_irq_cnt) {
		WARN(1, "lineptr irq still enabled\n");
		while (mdss_mdp_setup_lineptr(ctx, false))
			;
	}

	if (!ctl->pending_mode_switch) {
		mdss_mdp_ctl_intf_event(ctl,
@@ -2473,6 +2694,8 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl,

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

@@ -2529,6 +2752,8 @@ static int mdss_mdp_cmd_stop_sub(struct mdss_mdp_ctl *ctl,

	list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
		mdss_mdp_cmd_remove_vsync_handler(ctl, handle);
	if (mdss_mdp_is_lineptr_supported(ctl))
		mdss_mdp_cmd_lineptr_ctrl(ctl, false);
	MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), XLOG_FUNC_ENTRY);

	/* Command mode is supported only starting at INTF1 */
@@ -2771,6 +2996,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
	spin_lock_init(&ctx->koff_lock);
	mutex_init(&ctx->clk_mtx);
	mutex_init(&ctx->mdp_rdptr_lock);
	mutex_init(&ctx->mdp_wrptr_lock);
	INIT_WORK(&ctx->gate_clk_work, clk_ctrl_gate_work);
	INIT_DELAYED_WORK(&ctx->delayed_off_clk_work,
		clk_ctrl_delayed_off_work);
@@ -2780,6 +3006,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
	ctx->autorefresh_state = MDP_AUTOREFRESH_OFF;
	ctx->autorefresh_frame_cnt = 0;
	INIT_LIST_HEAD(&ctx->vsync_handlers);
	INIT_LIST_HEAD(&ctx->lineptr_handlers);

	ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery;
	ctx->intf_recovery.data = ctx;
@@ -2793,6 +3020,9 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_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,
		ctx->default_pp_num, mdss_mdp_cmd_writeptr_done, ctl);

	ret = mdss_mdp_cmd_tearcheck_setup(ctx, false);
	if (ret)
		pr_err("tearcheck setup failed\n");
+112 −0
Original line number Diff line number Diff line
@@ -2619,6 +2619,30 @@ static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
	sysfs_notify_dirent(mdp5_data->vsync_event_sd);
}

/* function is called in irq context should have minimum processing */
static void mdss_mdp_overlay_handle_lineptr(struct mdss_mdp_ctl *ctl,
						ktime_t t)
{
	struct mdss_overlay_private *mdp5_data = NULL;

	if (!ctl || !ctl->mfd) {
		pr_warn("Invalid handle for lineptr\n");
		return;
	}

	mdp5_data = mfd_to_mdp5_data(ctl->mfd);
	if (!mdp5_data) {
		pr_err("mdp5_data is NULL\n");
		return;
	}

	pr_debug("lineptr irq on fb%d play_cnt=%d\n",
			ctl->mfd->index, ctl->play_cnt);

	mdp5_data->lineptr_time = t;
	sysfs_notify_dirent(mdp5_data->lineptr_event_sd);
}

int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
{
	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
@@ -2891,6 +2915,78 @@ static ssize_t mdss_mdp_vsync_show_event(struct device *dev,
	return ret;
}

static ssize_t mdss_mdp_lineptr_show_event(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct fb_info *fbi = dev_get_drvdata(dev);
	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
	u64 lineptr_ticks;
	int ret;

	if (!mdp5_data->ctl ||
		(!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled
			&& !mdss_mdp_ctl_is_power_on(mdp5_data->ctl)))
		return -EAGAIN;

	lineptr_ticks = ktime_to_ns(mdp5_data->lineptr_time);

	pr_debug("fb%d lineptr=%llu\n", mfd->index, lineptr_ticks);
	ret = scnprintf(buf, PAGE_SIZE, "LINEPTR=%llu\n", lineptr_ticks);

	return ret;
}

static ssize_t mdss_mdp_lineptr_show_value(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct fb_info *fbi = dev_get_drvdata(dev);
	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
	int ret, lineptr_val;

	if (!mdp5_data->ctl ||
		(!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled
			&& !mdss_mdp_ctl_is_power_on(mdp5_data->ctl)))
		return -EAGAIN;

	lineptr_val = mfd->panel_info->te.wr_ptr_irq;

	ret = scnprintf(buf, PAGE_SIZE, "%d\n", lineptr_val);

	return ret;
}

static ssize_t mdss_mdp_lineptr_set_value(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct fb_info *fbi = dev_get_drvdata(dev);
	struct msm_fb_data_type *mfd = fbi->par;
	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
	int ret, lineptr_value;

	ret = kstrtoint(buf, 10, &lineptr_value);
	if (ret) {
		pr_err("Invalid input for ad\n");
		return -EINVAL;
	}

	if (!mdp5_data->ctl ||
		(!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled
			&& !mdss_mdp_ctl_is_power_on(mdp5_data->ctl)))
		return -EAGAIN;

	if (!mdss_mdp_is_lineptr_supported(mdp5_data->ctl)) {
		pr_err("lineptr not supported\n");
		return -ENOTSUPP;
	}

	/* the new lineptr value will take effect in the next kickoff */
	mfd->panel_info->te.wr_ptr_irq = lineptr_value;

	return count;
}

static ssize_t mdss_mdp_bl_show_event(struct device *dev,
		struct device_attribute *attr, char *buf)
{
@@ -3224,6 +3320,9 @@ static DEVICE_ATTR(msm_misr_en, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(msm_cmd_autorefresh_en, S_IRUGO | S_IWUSR,
	mdss_mdp_cmd_autorefresh_show, mdss_mdp_cmd_autorefresh_store);
static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
static DEVICE_ATTR(lineptr_event, S_IRUGO, mdss_mdp_lineptr_show_event, NULL);
static DEVICE_ATTR(lineptr_value, S_IRUGO | S_IWUSR | S_IWGRP,
		mdss_mdp_lineptr_show_value, mdss_mdp_lineptr_set_value);
static DEVICE_ATTR(ad, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_ad_show,
	mdss_mdp_ad_store);
static DEVICE_ATTR(dyn_pu, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_dyn_pu_show,
@@ -3235,6 +3334,8 @@ static DEVICE_ATTR(ad_bl_event, S_IRUGO, mdss_mdp_ad_bl_show_event, NULL);

static struct attribute *mdp_overlay_sysfs_attrs[] = {
	&dev_attr_vsync_event.attr,
	&dev_attr_lineptr_event.attr,
	&dev_attr_lineptr_value.attr,
	&dev_attr_ad.attr,
	&dev_attr_dyn_pu.attr,
	&dev_attr_msm_misr_en.attr,
@@ -4597,6 +4698,9 @@ static struct mdss_mdp_ctl *__mdss_mdp_overlay_ctl_init(
			mdss_mdp_recover_underrun_handler;
	ctl->recover_underrun_handler.cmd_post_flush = false;

	ctl->lineptr_handler.lineptr_handler =
					mdss_mdp_overlay_handle_lineptr;

	INIT_WORK(&ctl->remove_underrun_handler,
				remove_underrun_vsync_handler);

@@ -5350,6 +5454,14 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
		goto init_fail;
	}

	mdp5_data->lineptr_event_sd = sysfs_get_dirent(dev->kobj.sd,
						     "lineptr_event");
	if (!mdp5_data->lineptr_event_sd) {
		pr_err("lineptr_event sysfs lookup failed\n");
		rc = -ENODEV;
		goto init_fail;
	}

	mdp5_data->hist_event_sd = sysfs_get_dirent(dev->kobj.sd,
						    "hist_event");
	if (!mdp5_data->hist_event_sd) {
+19 −0
Original line number Diff line number Diff line
@@ -49,6 +49,10 @@ enum {
	MDP_INTR_PING_PONG_1_RD_PTR,
	MDP_INTR_PING_PONG_2_RD_PTR,
	MDP_INTR_PING_PONG_3_RD_PTR,
	MDP_INTR_PING_PONG_0_WR_PTR,
	MDP_INTR_PING_PONG_1_WR_PTR,
	MDP_INTR_PING_PONG_2_WR_PTR,
	MDP_INTR_PING_PONG_3_WR_PTR,
	MDP_INTR_WB_0,
	MDP_INTR_WB_1,
	MDP_INTR_WB_2,
@@ -83,6 +87,9 @@ static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num)
	case MDSS_MDP_IRQ_PING_PONG_RD_PTR:
		index = MDP_INTR_PING_PONG_0_RD_PTR + intf_num;
		break;
	case MDSS_MDP_IRQ_PING_PONG_WR_PTR:
		index = MDP_INTR_PING_PONG_0_WR_PTR + intf_num;
		break;
	case MDSS_MDP_IRQ_WB_ROT_COMP:
		index = MDP_INTR_WB_0 + intf_num;
		break;
@@ -216,6 +223,18 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr)
	if (isr & MDSS_MDP_INTR_PING_PONG_3_RD_PTR)
		mdss_mdp_intr_done(MDP_INTR_PING_PONG_3_RD_PTR);

	if (isr & MDSS_MDP_INTR_PING_PONG_0_WR_PTR)
		mdss_mdp_intr_done(MDP_INTR_PING_PONG_0_WR_PTR);

	if (isr & MDSS_MDP_INTR_PING_PONG_1_WR_PTR)
		mdss_mdp_intr_done(MDP_INTR_PING_PONG_1_WR_PTR);

	if (isr & MDSS_MDP_INTR_PING_PONG_2_WR_PTR)
		mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_WR_PTR);

	if (isr & MDSS_MDP_INTR_PING_PONG_3_WR_PTR)
		mdss_mdp_intr_done(MDP_INTR_PING_PONG_3_WR_PTR);

	if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) {
		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP, true);
Loading