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

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

Merge "msm: mdss: add retire fence support"

parents 8a6e4a34 2758fa9e
Loading
Loading
Loading
Loading
+86 −30
Original line number Diff line number Diff line
@@ -444,17 +444,27 @@ static int mdss_fb_probe(struct platform_device *pdev)
		 mfd->mdp_sync_pt_data.timeline =
				sw_sync_timeline_create(timeline_name);
		if (mfd->mdp_sync_pt_data.timeline == NULL) {
			pr_err("%s: cannot create time line", __func__);
			pr_err("cannot create release fence time line\n");
			return -ENOMEM;
		}
		mfd->mdp_sync_pt_data.notifier.notifier_call =
			__mdss_fb_sync_buf_done_callback;
	}
	if ((mfd->panel.type == WRITEBACK_PANEL) ||
			(mfd->panel.type == MIPI_CMD_PANEL))

	switch (mfd->panel.type) {
	case WRITEBACK_PANEL:
		mfd->mdp_sync_pt_data.threshold = 1;
	else
		mfd->mdp_sync_pt_data.retire_threshold = 0;
		break;
	case MIPI_CMD_PANEL:
		mfd->mdp_sync_pt_data.threshold = 1;
		mfd->mdp_sync_pt_data.retire_threshold = 1;
		break;
	default:
		mfd->mdp_sync_pt_data.threshold = 2;
		mfd->mdp_sync_pt_data.retire_threshold = 0;
		break;
	}

	if (mfd->splash_logo_enabled) {
		mfd->splash_thread = kthread_run(mdss_fb_splash_thread, mfd,
@@ -2041,42 +2051,37 @@ static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
}

/**
 * mdss_fb_sync_get_rel_fence() - get release fence from sync pt timeline
 * @sync_pt_data:	Sync pt structure holding timeline and fence info.
 * mdss_fb_sync_get_fence() - get fence from timeline
 * @timeline:	Timeline to create the fence on
 * @fence_name:	Name of the fence that will be created for debugging
 * @val:	Timeline value at which the fence will be signaled
 *
 * Function returns a release fence on the timeline associated with the
 * sync pt struct given and it's associated information. The release fence
 * created can be used to signal when buffers provided will be released.
 * Function returns a fence on the timeline given with the name provided.
 * The fence created will be signaled when the timeline is advanced.
 */
static struct sync_fence *__mdss_fb_sync_get_rel_fence(
		struct msm_sync_pt_data *sync_pt_data)
struct sync_fence *mdss_fb_sync_get_fence(struct sw_sync_timeline *timeline,
		const char *fence_name, int val)
{
	struct sync_pt *rel_sync_pt;
	struct sync_fence *rel_fence;
	int val;

	val = sync_pt_data->timeline_value + sync_pt_data->threshold +
		atomic_read(&sync_pt_data->commit_cnt);
	struct sync_pt *sync_pt;
	struct sync_fence *fence;

	pr_debug("%s: buf sync rel fence timeline=%d\n",
		sync_pt_data->fence_name, val);
	pr_debug("%s: buf sync fence timeline=%d\n", fence_name, val);

	rel_sync_pt = sw_sync_pt_create(sync_pt_data->timeline, val);
	if (rel_sync_pt == NULL) {
		pr_err("%s: cannot create sync point\n",
				sync_pt_data->fence_name);
	sync_pt = sw_sync_pt_create(timeline, val);
	if (sync_pt == NULL) {
		pr_err("%s: cannot create sync point\n", fence_name);
		return NULL;
	}

	/* create fence */
	rel_fence = sync_fence_create(sync_pt_data->fence_name, rel_sync_pt);
	if (rel_fence == NULL) {
		sync_pt_free(rel_sync_pt);
		pr_err("%s: cannot create fence\n", sync_pt_data->fence_name);
	fence = sync_fence_create(fence_name, sync_pt);
	if (fence == NULL) {
		sync_pt_free(sync_pt);
		pr_err("%s: cannot create fence\n", fence_name);
		return NULL;
	}

	return rel_fence;
	return fence;
}

static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
@@ -2084,8 +2089,10 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
{
	int i, ret = 0;
	int acq_fen_fd[MDP_MAX_FENCE_FD];
	struct sync_fence *fence, *rel_fence;
	struct sync_fence *fence, *rel_fence, *retire_fence;
	int rel_fen_fd;
	int retire_fen_fd;
	int val;

	if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
				(sync_pt_data->timeline == NULL))
@@ -2120,7 +2127,12 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
	if (ret)
		goto buf_sync_err_1;

	rel_fence = __mdss_fb_sync_get_rel_fence(sync_pt_data);
	val = sync_pt_data->timeline_value + sync_pt_data->threshold +
			atomic_read(&sync_pt_data->commit_cnt);

	/* Set release fence */
	rel_fence = mdss_fb_sync_get_fence(sync_pt_data->timeline,
			sync_pt_data->fence_name, val);
	if (IS_ERR_OR_NULL(rel_fence)) {
		pr_err("%s: unable to retrieve release fence\n",
				sync_pt_data->fence_name);
@@ -2144,6 +2156,50 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
		pr_err("%s: copy_to_user failed\n", sync_pt_data->fence_name);
		goto buf_sync_err_3;
	}

	if (!(buf_sync->flags & MDP_BUF_SYNC_FLAG_RETIRE_FENCE))
		goto skip_retire_fence;

	if (sync_pt_data->get_retire_fence)
		retire_fence = sync_pt_data->get_retire_fence(sync_pt_data);
	else
		retire_fence = NULL;

	if (IS_ERR_OR_NULL(retire_fence)) {
		val += sync_pt_data->retire_threshold;
		retire_fence = mdss_fb_sync_get_fence(
			sync_pt_data->timeline, "mdp-retire", val);
	}

	if (IS_ERR_OR_NULL(retire_fence)) {
		pr_err("%s: unable to retrieve retire fence\n",
				sync_pt_data->fence_name);
		ret = retire_fence ? PTR_ERR(rel_fence) : -ENOMEM;
		goto buf_sync_err_3;
	}
	retire_fen_fd = get_unused_fd_flags(0);

	if (retire_fen_fd < 0) {
		pr_err("%s: get_unused_fd_flags failed for retire fence\n",
				sync_pt_data->fence_name);
		ret = -EIO;
		sync_fence_put(retire_fence);
		goto buf_sync_err_3;
	}

	sync_fence_install(retire_fence, retire_fen_fd);

	ret = copy_to_user(buf_sync->retire_fen_fd, &retire_fen_fd,
			sizeof(int));
	if (ret) {
		pr_err("%s: copy_to_user failed for retire fence\n",
				sync_pt_data->fence_name);
		put_unused_fd(retire_fen_fd);
		sync_fence_put(retire_fence);
		goto buf_sync_err_3;
	}

skip_retire_fence:
	mutex_unlock(&sync_pt_data->sync_mutex);

	if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
+6 −1
Original line number Diff line number Diff line
@@ -98,13 +98,16 @@ struct msm_sync_pt_data {
	struct sw_sync_timeline *timeline;
	int timeline_value;
	u32 threshold;

	u32 retire_threshold;
	atomic_t commit_cnt;
	bool flushed;
	bool async_wait_fences;

	struct mutex sync_mutex;
	struct notifier_block notifier;

	struct sync_fence *(*get_retire_fence)
		(struct msm_sync_pt_data *sync_pt_data);
};

struct msm_fb_data_type;
@@ -248,6 +251,8 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
int mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data);
void mdss_fb_signal_timeline(struct msm_sync_pt_data *sync_pt_data);
struct sync_fence *mdss_fb_sync_get_fence(struct sw_sync_timeline *timeline,
				const char *fence_name, int val);
int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state);
#endif /* MDSS_FB_H */
+5 −0
Original line number Diff line number Diff line
@@ -432,6 +432,11 @@ struct mdss_overlay_private {
	u32 splash_mem_addr;
	u32 splash_mem_size;
	u32 sd_enabled;

	struct sw_sync_timeline *vsync_timeline;
	struct mdss_mdp_vsync_handler vsync_retire_handler;
	struct work_struct retire_work;
	int retire_cnt;
};

/**
+108 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/msm_mdp.h>
#include <linux/memblock.h>
#include <linux/sw_sync.h>

#include <linux/msm_iommu_domains.h>
#include <mach/event_timer.h>
@@ -2775,6 +2776,107 @@ static int mdss_mdp_overlay_splash_image(struct msm_fb_data_type *mfd,
	return rc;
}

static void __vsync_retire_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
{
	struct msm_fb_data_type *mfd = ctl->mfd;
	struct mdss_overlay_private *mdp5_data;

	if (!mfd || !mfd->mdp.private1) {
		pr_warn("Invalid handle for vsync\n");
		return;
	}

	mdp5_data = mfd_to_mdp5_data(mfd);
	schedule_work(&mdp5_data->retire_work);
}

static void __vsync_retire_work_handler(struct work_struct *work)
{
	struct mdss_overlay_private *mdp5_data =
		container_of(work, typeof(*mdp5_data), retire_work);
	struct msm_sync_pt_data *sync_pt_data;

	if (!mdp5_data->ctl || !mdp5_data->ctl->mfd)
		return;

	if (!mdp5_data->ctl->remove_vsync_handler)
		return;

	sync_pt_data = &mdp5_data->ctl->mfd->mdp_sync_pt_data;
	mutex_lock(&sync_pt_data->sync_mutex);
	if (mdp5_data->retire_cnt > 0) {
		sw_sync_timeline_inc(mdp5_data->vsync_timeline, 1);

		mdp5_data->retire_cnt--;
		if (mdp5_data->retire_cnt == 0) {
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
			mdp5_data->ctl->remove_vsync_handler(mdp5_data->ctl,
					&mdp5_data->vsync_retire_handler);
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
		}
	}
	mutex_unlock(&sync_pt_data->sync_mutex);
}

static struct sync_fence *
__vsync_retire_get_fence(struct msm_sync_pt_data *sync_pt_data)
{
	struct msm_fb_data_type *mfd;
	struct mdss_overlay_private *mdp5_data;
	struct mdss_mdp_ctl *ctl;
	int rc, value;

	mfd = container_of(sync_pt_data, typeof(*mfd), mdp_sync_pt_data);
	mdp5_data = mfd_to_mdp5_data(mfd);

	if (!mdp5_data || !mdp5_data->ctl)
		return ERR_PTR(-ENODEV);

	ctl = mdp5_data->ctl;
	if (!ctl->add_vsync_handler)
		return ERR_PTR(-EOPNOTSUPP);

	if (!ctl->power_on) {
		pr_debug("fb%d vsync pending first update\n", mfd->index);
		return ERR_PTR(-EPERM);
	}

	if (mdp5_data->retire_cnt == 0) {
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
		rc = ctl->add_vsync_handler(ctl,
				&mdp5_data->vsync_retire_handler);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
		if (IS_ERR_VALUE(rc))
			return ERR_PTR(rc);
	}
	value = mdp5_data->vsync_timeline->value + 1 + mdp5_data->retire_cnt;
	mdp5_data->retire_cnt++;

	return mdss_fb_sync_get_fence(mdp5_data->vsync_timeline,
			"mdp-retire", value);
}

static int __vsync_retire_setup(struct msm_fb_data_type *mfd)
{
	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
	char name[24];

	snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index);
	mdp5_data->vsync_timeline = sw_sync_timeline_create(name);
	if (mdp5_data->vsync_timeline == NULL) {
		pr_err("cannot vsync create time line");
		return -ENOMEM;
	}
	mfd->mdp_sync_pt_data.get_retire_fence = __vsync_retire_get_fence;

	mdp5_data->vsync_retire_handler.vsync_handler =
		__vsync_retire_handle_vsync;
	mdp5_data->vsync_retire_handler.cmd_post_flush = false;
	INIT_WORK(&mdp5_data->retire_work, __vsync_retire_work_handler);

	return 0;
}

int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
	struct device *dev = mfd->fbi->dev;
@@ -2846,6 +2948,12 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
			pr_err("Error dfps sysfs creation ret=%d\n", rc);
			goto init_fail;
		}
	} else if (mfd->panel_info->type == MIPI_CMD_PANEL) {
		rc = __vsync_retire_setup(mfd);
		if (IS_ERR_VALUE(rc)) {
			pr_err("unable to create vsync timeline\n");
			goto init_fail;
		}
	}
	mfd->mdp_sync_pt_data.async_wait_fences = true;

+2 −8
Original line number Diff line number Diff line
@@ -994,6 +994,7 @@ struct msmfb_metadata {

#define MDP_MAX_FENCE_FD	32
#define MDP_BUF_SYNC_FLAG_WAIT	1
#define MDP_BUF_SYNC_FLAG_RETIRE_FENCE	0x10

struct mdp_buf_sync {
	uint32_t flags;
@@ -1001,6 +1002,7 @@ struct mdp_buf_sync {
	uint32_t session_id;
	int *acq_fen_fd;
	int *rel_fen_fd;
	int *retire_fen_fd;
};

struct mdp_async_blit_req_list {
@@ -1010,19 +1012,11 @@ struct mdp_async_blit_req_list {
};

#define MDP_DISPLAY_COMMIT_OVERLAY	1
struct mdp_buf_fence {
	uint32_t flags;
	uint32_t acq_fen_fd_cnt;
	int acq_fen_fd[MDP_MAX_FENCE_FD];
	int rel_fen_fd[MDP_MAX_FENCE_FD];
};


struct mdp_display_commit {
	uint32_t flags;
	uint32_t wait_for_finish;
	struct fb_var_screeninfo var;
	struct mdp_buf_fence buf_fence;
	struct mdp_rect roi;
};