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

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

Merge "drm/msm/sde: check in video encoder irq if ctl was flushed"

parents 95db3e5b 4d8dcb8d
Loading
Loading
Loading
Loading
+62 −11
Original line number Diff line number Diff line
@@ -1341,8 +1341,7 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
	struct drm_display_mode *mode;

	int cnt = 0, rc = 0, mixer_width, i, z_pos;
	int left_crtc_zpos_cnt[SDE_STAGE_MAX] = {0};
	int right_crtc_zpos_cnt[SDE_STAGE_MAX] = {0};
	int left_zpos_cnt = 0, right_zpos_cnt = 0;

	if (!crtc) {
		SDE_ERROR("invalid crtc\n");
@@ -1396,11 +1395,12 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
		}
	}

	/* assign mixer stages based on sorted zpos property */
	sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);

	if (!sde_is_custom_client()) {
		int stage_old = pstates[0].stage;

		/* assign mixer stages based on sorted zpos property */
		sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
		z_pos = 0;
		for (i = 0; i < cnt; i++) {
			if (stage_old != pstates[i].stage)
@@ -1410,8 +1410,14 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
		}
	}

	z_pos = -1;
	for (i = 0; i < cnt; i++) {
		/* reset counts at every new blend stage */
		if (pstates[i].stage != z_pos) {
			left_zpos_cnt = 0;
			right_zpos_cnt = 0;
			z_pos = pstates[i].stage;
		}

		/* verify z_pos setting before using it */
		if (z_pos >= SDE_STAGE_MAX - SDE_STAGE_0) {
@@ -1420,22 +1426,24 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
			rc = -EINVAL;
			goto end;
		} else if (pstates[i].drm_pstate->crtc_x < mixer_width) {
			if (left_crtc_zpos_cnt[z_pos] == 2) {
				SDE_ERROR("> 2 plane @ stage%d on left\n",
			if (left_zpos_cnt == 2) {
				SDE_ERROR("> 2 planes @ stage %d on left\n",
					z_pos);
				rc = -EINVAL;
				goto end;
			}
			left_crtc_zpos_cnt[z_pos]++;
			left_zpos_cnt++;

		} else {
			if (right_crtc_zpos_cnt[z_pos] == 2) {
				SDE_ERROR("> 2 plane @ stage%d on right\n",
			if (right_zpos_cnt == 2) {
				SDE_ERROR("> 2 planes @ stage %d on right\n",
					z_pos);
				rc = -EINVAL;
				goto end;
			}
			right_crtc_zpos_cnt[z_pos]++;
			right_zpos_cnt++;
		}

		pstates[i].sde_pstate->stage = z_pos + SDE_STAGE_0;
		SDE_DEBUG("%s: zpos %d", sde_crtc->name, z_pos);
	}
@@ -1447,6 +1455,49 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
		goto end;
	}

	/*
	 * enforce pipe priority restrictions
	 * use pstates sorted by stage to check planes on same stage
	 * we assume that all pipes are in source split so its valid to compare
	 * without taking into account left/right mixer placement
	 */
	for (i = 1; i < cnt; i++) {
		struct plane_state *prv_pstate, *cur_pstate;
		int32_t prv_x, cur_x, prv_id, cur_id;

		prv_pstate = &pstates[i - 1];
		cur_pstate = &pstates[i];
		if (prv_pstate->stage != cur_pstate->stage)
			continue;

		prv_x = prv_pstate->drm_pstate->crtc_x;
		cur_x = cur_pstate->drm_pstate->crtc_x;
		prv_id = prv_pstate->sde_pstate->base.plane->base.id;
		cur_id = cur_pstate->sde_pstate->base.plane->base.id;

		/*
		 * Planes are enumerated in pipe-priority order such that planes
		 * with lower drm_id must be left-most in a shared blend-stage
		 * when using source split.
		 */
		if (cur_x > prv_x && cur_id < prv_id) {
			SDE_ERROR(
				"shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n",
				cur_pstate->stage, cur_id, cur_x,
				prv_id, prv_x);
			rc = -EINVAL;
			goto end;
		} else if (cur_x < prv_x && cur_id > prv_id) {
			SDE_ERROR(
				"shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n",
				cur_pstate->stage, prv_id, prv_x,
				cur_id, cur_x);
			rc = -EINVAL;
			goto end;
		}
	}


end:
	return rc;
}
+21 −4
Original line number Diff line number Diff line
@@ -281,23 +281,40 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
{
	struct sde_encoder_phys_vid *vid_enc = arg;
	struct sde_encoder_phys *phys_enc;
	struct sde_hw_ctl *hw_ctl;
	unsigned long lock_flags;
	int new_cnt;
	u32 flush_register = 0;
	int new_cnt = -1, old_cnt = -1;

	if (!vid_enc)
		return;

	phys_enc = &vid_enc->base;
	hw_ctl = phys_enc->hw_ctl;

	if (phys_enc->parent_ops.handle_vblank_virt)
		phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
				phys_enc);

	old_cnt  = atomic_read(&phys_enc->pending_kickoff_cnt);

	/*
	 * only decrement the pending flush count if we've actually flushed
	 * hardware. due to sw irq latency, vblank may have already happened
	 * so we need to double-check with hw that it accepted the flush bits
	 */
	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
	new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
	SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0,
			new_cnt);
	if (hw_ctl && hw_ctl->ops.get_flush_register)
		flush_register = hw_ctl->ops.get_flush_register(hw_ctl);

	if (flush_register == 0)
		new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt,
				-1, 0);
	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);

	SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0,
			old_cnt, new_cnt, flush_register);

	/* Signal any waiting atomic commit thread */
	wake_up_all(&phys_enc->pending_kickoff_wq);
}
+7 −0
Original line number Diff line number Diff line
@@ -97,6 +97,12 @@ static inline void sde_hw_ctl_trigger_flush(struct sde_hw_ctl *ctx)
	SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
}

static inline u32 sde_hw_ctl_get_flush_register(struct sde_hw_ctl *ctx)
{
	struct sde_hw_blk_reg_map *c = &ctx->hw;

	return SDE_REG_READ(c, CTL_FLUSH);
}

static inline uint32_t sde_hw_ctl_get_bitmask_sspp(struct sde_hw_ctl *ctx,
	enum sde_sspp sspp)
@@ -459,6 +465,7 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops,
	ops->update_pending_flush = sde_hw_ctl_update_pending_flush;
	ops->get_pending_flush = sde_hw_ctl_get_pending_flush;
	ops->trigger_flush = sde_hw_ctl_trigger_flush;
	ops->get_flush_register = sde_hw_ctl_get_flush_register;
	ops->trigger_start = sde_hw_ctl_trigger_start;
	ops->setup_intf_cfg = sde_hw_ctl_intf_cfg;
	ops->reset = sde_hw_ctl_reset_control;
+8 −1
Original line number Diff line number Diff line
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -93,6 +93,13 @@ struct sde_hw_ctl_ops {
	 */
	void (*trigger_flush)(struct sde_hw_ctl *ctx);

	/**
	 * Read the value of the flush register
	 * @ctx       : ctl path ctx pointer
	 * @Return: value of the ctl flush register.
	 */
	u32 (*get_flush_register)(struct sde_hw_ctl *ctx);

	/**
	 * Setup ctl_path interface config
	 * @ctx
+43 −0
Original line number Diff line number Diff line
@@ -370,6 +370,49 @@ void sde_kms_info_append_format(struct sde_kms_info *info,
 */
void sde_kms_info_stop(struct sde_kms_info *info);

/**
 * sde_kms_rect_intersect - intersect two rectangles
 * @r1: first rectangle
 * @r2: scissor rectangle
 * @result: result rectangle, all 0's on no intersection found
 */
void sde_kms_rect_intersect(const struct sde_rect *r1,
		const struct sde_rect *r2,
		struct sde_rect *result);

/**
 * sde_kms_rect_is_equal - compares two rects
 * @r1: rect value to compare
 * @r2: rect value to compare
 *
 * Returns 1 if the rects are same, 0 otherwise.
 */
static inline bool sde_kms_rect_is_equal(struct sde_rect *r1,
		struct sde_rect *r2)
{
	if ((!r1 && r2) || (r1 && !r2))
		return false;

	if (!r1 && !r2)
		return true;

	return r1->x == r2->x && r1->y == r2->y && r1->w == r2->w &&
			r1->h == r2->h;
}

/**
 * sde_kms_rect_is_null - returns true if the width or height of a rect is 0
 * @rect: rectangle to check for zero size
 * @Return: True if width or height of rectangle is 0
 */
static inline bool sde_kms_rect_is_null(const struct sde_rect *r)
{
	if (!r)
		return true;

	return (!r->w || !r->h);
}

/**
 * Vblank enable/disable functions
 */
Loading