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

Commit 0a5c9aad authored by Hai Li's avatar Hai Li Committed by Rob Clark
Browse files

drm/msm: Use customized function to wait for atomic commit done



MDP FLUSH registers could indicate if the previous flush updates
has taken effect at vsync boundary. Making use of this H/W feature
can catch the vsync that happened between CRTC atomic_flush and
*_wait_for_vblanks, to avoid unnecessary wait.

This change allows kms CRTCs to use their own *_wait_for_commit_done
functions to wait for FLUSH register cleared at vsync, before commit
completion.

Signed-off-by: default avatarHai Li <hali@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent 7eed919a
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -51,6 +51,11 @@ struct mdp4_crtc {
	/* if there is a pending flip, these will be non-null: */
	struct drm_pending_vblank_event *event;

	/* Bits have been flushed at the last commit,
	 * used to decide if a vsync has happened since last commit.
	 */
	u32 flushed_mask;

#define PENDING_CURSOR 0x1
#define PENDING_FLIP   0x2
	atomic_t pending;
@@ -93,6 +98,8 @@ static void crtc_flush(struct drm_crtc *crtc)

	DBG("%s: flush=%08x", mdp4_crtc->name, flush);

	mdp4_crtc->flushed_mask = flush;

	mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush);
}

@@ -537,6 +544,29 @@ static void mdp4_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
	crtc_flush(crtc);
}

static void mdp4_crtc_wait_for_flush_done(struct drm_crtc *crtc)
{
	struct drm_device *dev = crtc->dev;
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct mdp4_kms *mdp4_kms = get_kms(crtc);
	int ret;

	ret = drm_crtc_vblank_get(crtc);
	if (ret)
		return;

	ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue,
		!(mdp4_read(mdp4_kms, REG_MDP4_OVERLAY_FLUSH) &
			mdp4_crtc->flushed_mask),
		msecs_to_jiffies(50));
	if (ret <= 0)
		dev_warn(dev->dev, "vblank time out, crtc=%d\n", mdp4_crtc->id);

	mdp4_crtc->flushed_mask = 0;

	drm_crtc_vblank_put(crtc);
}

uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc)
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
@@ -600,6 +630,15 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer)
	mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel);
}

void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc)
{
	/* wait_for_flush_done is the only case for now.
	 * Later we will have command mode CRTC to wait for
	 * other event.
	 */
	mdp4_crtc_wait_for_flush_done(crtc);
}

static const char *dma_names[] = {
		"DMA_P", "DMA_S", "DMA_E",
};
+7 −0
Original line number Diff line number Diff line
@@ -159,6 +159,12 @@ static void mdp4_complete_commit(struct msm_kms *kms, struct drm_atomic_state *s
	mdp4_disable(mdp4_kms);
}

static void mdp4_wait_for_crtc_commit_done(struct msm_kms *kms,
						struct drm_crtc *crtc)
{
	mdp4_crtc_wait_for_commit_done(crtc);
}

static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate,
		struct drm_encoder *encoder)
{
@@ -197,6 +203,7 @@ static const struct mdp_kms_funcs kms_funcs = {
		.disable_vblank  = mdp4_disable_vblank,
		.prepare_commit  = mdp4_prepare_commit,
		.complete_commit = mdp4_complete_commit,
		.wait_for_crtc_commit_done = mdp4_wait_for_crtc_commit_done,
		.get_format      = mdp_get_format,
		.round_pixclk    = mdp4_round_pixclk,
		.preclose        = mdp4_preclose,
+1 −0
Original line number Diff line number Diff line
@@ -206,6 +206,7 @@ uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc);
void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config);
void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer);
void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc);
struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
		struct drm_plane *plane, int id, int ovlp_id,
		enum mdp4_dma dma_id);
+49 −6
Original line number Diff line number Diff line
@@ -46,6 +46,11 @@ struct mdp5_crtc {
	/* if there is a pending flip, these will be non-null: */
	struct drm_pending_vblank_event *event;

	/* Bits have been flushed at the last commit,
	 * used to decide if a vsync has happened since last commit.
	 */
	u32 flushed_mask;

#define PENDING_CURSOR 0x1
#define PENDING_FLIP   0x2
	atomic_t pending;
@@ -82,12 +87,12 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending)
	mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank);
}

static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
static u32 crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
{
	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);

	DBG("%s: flush=%08x", mdp5_crtc->name, flush_mask);
	mdp5_ctl_commit(mdp5_crtc->ctl, flush_mask);
	return mdp5_ctl_commit(mdp5_crtc->ctl, flush_mask);
}

/*
@@ -95,7 +100,7 @@ static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
 * so that we can safely queue unref to current fb (ie. next
 * vblank we know hw is done w/ previous scanout_fb).
 */
static void crtc_flush_all(struct drm_crtc *crtc)
static u32 crtc_flush_all(struct drm_crtc *crtc)
{
	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
	struct drm_plane *plane;
@@ -103,7 +108,7 @@ static void crtc_flush_all(struct drm_crtc *crtc)

	/* this should not happen: */
	if (WARN_ON(!mdp5_crtc->ctl))
		return;
		return 0;

	drm_atomic_crtc_for_each_plane(plane, crtc) {
		flush_mask |= mdp5_plane_get_flush(plane);
@@ -111,7 +116,7 @@ static void crtc_flush_all(struct drm_crtc *crtc)

	flush_mask |= mdp_ctl_flush_mask_lm(mdp5_crtc->lm);

	crtc_flush(crtc, flush_mask);
	return crtc_flush(crtc, flush_mask);
}

/* if file!=NULL, this is preclose potential cancel-flip path */
@@ -395,7 +400,9 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc)
		return;

	blend_setup(crtc);
	crtc_flush_all(crtc);

	mdp5_crtc->flushed_mask = crtc_flush_all(crtc);

	request_pending(crtc, PENDING_FLIP);
}

@@ -600,6 +607,32 @@ static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
	DBG("%s: error: %08x", mdp5_crtc->name, irqstatus);
}

static void mdp5_crtc_wait_for_flush_done(struct drm_crtc *crtc)
{
	struct drm_device *dev = crtc->dev;
	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
	int ret;

	/* Should not call this function if crtc is disabled. */
	if (!mdp5_crtc->ctl)
		return;

	ret = drm_crtc_vblank_get(crtc);
	if (ret)
		return;

	ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue,
		((mdp5_ctl_get_commit_status(mdp5_crtc->ctl) &
		mdp5_crtc->flushed_mask) == 0),
		msecs_to_jiffies(50));
	if (ret <= 0)
		dev_warn(dev->dev, "vblank time out, crtc=%d\n", mdp5_crtc->id);

	mdp5_crtc->flushed_mask = 0;

	drm_crtc_vblank_put(crtc);
}

uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc)
{
	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
@@ -631,6 +664,7 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf)
		mdp5_crtc->vblank.irqmask = lm2ppdone(lm);
	else
		mdp5_crtc->vblank.irqmask = intf2vblank(lm, intf);

	mdp_irq_update(&mdp5_kms->base);

	mdp5_ctl_set_intf(mdp5_crtc->ctl, intf);
@@ -648,6 +682,15 @@ struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc)
	return WARN_ON(!crtc) ? NULL : mdp5_crtc->ctl;
}

void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc)
{
	/* wait_for_flush_done is the only case for now.
	 * Later we will have command mode CRTC to wait for
	 * other event.
	 */
	mdp5_crtc_wait_for_flush_done(crtc);
}

/* initialize crtc */
struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
		struct drm_plane *plane, int id)
+9 −2
Original line number Diff line number Diff line
@@ -392,8 +392,10 @@ static u32 fix_sw_flush(struct mdp5_ctl *ctl, u32 flush_mask)
 * CTL registers need to be flushed in some circumstances; if that is the
 * case, some trigger bits will be present in both flush mask and
 * ctl->pending_ctl_trigger.
 *
 * Return H/W flushed bit mask.
 */
int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
{
	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
	struct op_mode *pipeline = &ctl->pipeline;
@@ -424,7 +426,12 @@ int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
		refill_start_mask(ctl);
	}

	return 0;
	return flush_mask;
}

u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl)
{
	return ctl_read(ctl, REG_MDP5_CTL_FLUSH(ctl->id));
}

void mdp5_ctl_release(struct mdp5_ctl *ctl)
Loading