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

Commit 8ee49957 authored by Clarence Ip's avatar Clarence Ip
Browse files

drm/msm/sde: abort inline rotation on rot commit error



Inline rotation commits require both the DRM/KMS and rotator
drivers to accept their respective configurations to proceed.
Commits with inline rotation need to fail gracefully in the
event the rotator driver flags an error during the commit
phase, so trigger a fallback 'is error' kickoff within the
encoder during those situations.

Change-Id: I84b91a2ffe9fcd5b36205a86344e85fffc94009b
Signed-off-by: default avatarClarence Ip <cip@codeaurora.org>
parent 662698e4
Loading
Loading
Loading
Loading
+35 −15
Original line number Diff line number Diff line
@@ -2725,17 +2725,17 @@ static int _sde_crtc_wait_for_frame_done(struct drm_crtc *crtc)
	return rc;
}

static void _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc,
static int _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc,
		struct sde_crtc_state *cstate)
{
	struct drm_plane *plane;
	struct sde_crtc *sde_crtc;
	struct sde_hw_ctl *ctl, *master_ctl;
	u32 flush_mask;
	int i;
	int i, rc = 0;

	if (!crtc || !cstate)
		return;
		return -EINVAL;

	sde_crtc = to_sde_crtc(crtc);

@@ -2749,7 +2749,7 @@ static void _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc,
	 * the hardware out of sbuf mode.
	 */
	if (!sde_crtc->sbuf_flush_mask_old && !sde_crtc->sbuf_flush_mask)
		return;
		return 0;

	flush_mask = sde_crtc->sbuf_flush_mask_old | sde_crtc->sbuf_flush_mask;
	sde_crtc->sbuf_flush_mask_old = sde_crtc->sbuf_flush_mask;
@@ -2758,29 +2758,47 @@ static void _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc,

	if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE) {
		drm_atomic_crtc_for_each_plane(plane, crtc) {
			sde_plane_kickoff(plane);
			rc = sde_plane_kickoff_rot(plane);
			if (rc) {
				SDE_ERROR("crtc%d cancelling inline rotation\n",
						crtc->base.id);
				SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR);

				/* revert to offline on errors */
				cstate->sbuf_cfg.rot_op_mode =
					SDE_CTL_ROT_OP_MODE_OFFLINE;
				break;
			}
		}
	}

	master_ctl = NULL;
	for (i = 0; i < sde_crtc->num_mixers; i++) {
		ctl = sde_crtc->mixers[i].hw_ctl;
		if (!ctl || !ctl->ops.setup_sbuf_cfg ||
				!ctl->ops.update_pending_flush)
		if (!ctl)
			continue;

		if (!master_ctl || master_ctl->idx > ctl->idx)
			master_ctl = ctl;

		ctl->ops.setup_sbuf_cfg(ctl, &cstate->sbuf_cfg);
		ctl->ops.update_pending_flush(ctl, flush_mask);
	}

	if (cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_INLINE_ASYNC &&
			master_ctl && master_ctl->ops.trigger_rot_start)
	/* only update sbuf_cfg and flush for master ctl */
	if (master_ctl && master_ctl->ops.setup_sbuf_cfg &&
			master_ctl->ops.update_pending_flush) {
		master_ctl->ops.setup_sbuf_cfg(master_ctl, &cstate->sbuf_cfg);
		master_ctl->ops.update_pending_flush(master_ctl, flush_mask);

		/* explicitly trigger rotator for async modes */
		if (cstate->sbuf_cfg.rot_op_mode ==
				SDE_CTL_ROT_OP_MODE_INLINE_ASYNC &&
				master_ctl->ops.trigger_rot_start) {
			master_ctl->ops.trigger_rot_start(master_ctl);
			SDE_EVT32(DRMID(crtc), master_ctl->idx - CTL_0);
		}
	}

	SDE_ATRACE_END("crtc_kickoff_rot");
	return rc;
}

/**
@@ -2886,7 +2904,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
	 * can start as soon as it's ready.
	 */
	if (cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_INLINE_ASYNC)
		_sde_crtc_commit_kickoff_rot(crtc, cstate);
		if (_sde_crtc_commit_kickoff_rot(crtc, cstate))
			is_error = true;

	/* wait for frame_event_done completion */
	SDE_ATRACE_BEGIN("wait_for_frame_done_event");
@@ -2923,7 +2942,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
	 * offline mode.
	 */
	if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_INLINE_ASYNC)
		_sde_crtc_commit_kickoff_rot(crtc, cstate);
		if (_sde_crtc_commit_kickoff_rot(crtc, cstate))
			is_error = true;

	sde_vbif_clear_errors(sde_kms);

+4 −4
Original line number Diff line number Diff line
@@ -2410,21 +2410,21 @@ static void sde_plane_rot_atomic_update(struct drm_plane *plane,
	sde_plane_rot_submit_command(plane, state, SDE_HW_ROT_CMD_COMMIT);
}

void sde_plane_kickoff(struct drm_plane *plane)
int sde_plane_kickoff_rot(struct drm_plane *plane)
{
	struct sde_plane_state *pstate;

	if (!plane || !plane->state) {
		SDE_ERROR("invalid plane\n");
		return;
		return -EINVAL;
	}

	pstate = to_sde_plane_state(plane->state);

	if (!pstate->rot.rot_hw || !pstate->rot.rot_hw->ops.commit)
		return;
		return 0;

	pstate->rot.rot_hw->ops.commit(pstate->rot.rot_hw,
	return pstate->rot.rot_hw->ops.commit(pstate->rot.rot_hw,
			&pstate->rot.rot_cmd,
			SDE_HW_ROT_CMD_START);
}
+3 −2
Original line number Diff line number Diff line
@@ -226,10 +226,11 @@ void sde_plane_restore(struct drm_plane *plane);
void sde_plane_flush(struct drm_plane *plane);

/**
 * sde_plane_kickoff - final plane operations before commit kickoff
 * sde_plane_kickoff_rot - final plane rotator operations before commit kickoff
 * @plane: Pointer to drm plane structure
 * Returns: Zero on success
 */
void sde_plane_kickoff(struct drm_plane *plane);
int sde_plane_kickoff_rot(struct drm_plane *plane);

/**
 * sde_plane_set_error: enable/disable error condition