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

Commit 6b993bde authored by Clarence Ip's avatar Clarence Ip Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/sde: update rotate flush determination



Set the rotate flush bit in the hardware if an inline
rotation was committed or the inline/offline status is
changing, rather than determining it from the current
and past plane rotate statuses. This allows the driver
to properly handle commits that don't update the rotated
planes while inline rotation is active.

Change-Id: Ia1dfd45d7a1a5d164ba3b5d7202bc7dd4b953781
Signed-off-by: default avatarClarence Ip <cip@codeaurora.org>
parent f3f00696
Loading
Loading
Loading
Loading
+43 −24
Original line number Diff line number Diff line
@@ -1404,7 +1404,8 @@ static void _sde_crtc_program_lm_output_roi(struct drm_crtc *crtc)
}

static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
	struct sde_crtc *sde_crtc, struct sde_crtc_mixer *mixer)
		struct drm_crtc_state *old_state, struct sde_crtc *sde_crtc,
		struct sde_crtc_mixer *mixer)
{
	struct drm_plane *plane;
	struct drm_framebuffer *fb;
@@ -1424,7 +1425,7 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
	bool bg_alpha_enable = false;
	u32 prefill = 0;

	if (!sde_crtc || !mixer) {
	if (!sde_crtc || !crtc->state || !mixer) {
		SDE_ERROR("invalid sde_crtc or mixer\n");
		return;
	}
@@ -1435,7 +1436,9 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
	cstate = to_sde_crtc_state(crtc->state);

	cstate->sbuf_prefill_line = 0;
	sde_crtc->sbuf_flush_mask = 0x0;
	sde_crtc->sbuf_flush_mask_old = sde_crtc->sbuf_flush_mask_all;
	sde_crtc->sbuf_flush_mask_all = 0x0;
	sde_crtc->sbuf_flush_mask_delta = 0x0;

	drm_atomic_crtc_for_each_plane(plane, crtc) {
		state = plane->state;
@@ -1457,7 +1460,10 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
		sde_plane_get_ctl_flush(plane, ctl, &flush_mask, &flush_sbuf);

		/* save sbuf flush value for later */
		sde_crtc->sbuf_flush_mask |= flush_sbuf;
		if (old_state && drm_atomic_get_existing_plane_state(
					old_state->state, plane))
			sde_crtc->sbuf_flush_mask_delta |= flush_sbuf;
		sde_crtc->sbuf_flush_mask_all |= flush_sbuf;

		SDE_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n",
				crtc->base.id,
@@ -1584,8 +1590,11 @@ static void _sde_crtc_swap_mixers_for_right_partial_update(
/**
 * _sde_crtc_blend_setup - configure crtc mixers
 * @crtc: Pointer to drm crtc structure
 * @old_state: Pointer to old crtc state
 * @add_planes: Whether or not to add planes to mixers
 */
static void _sde_crtc_blend_setup(struct drm_crtc *crtc, bool add_planes)
static void _sde_crtc_blend_setup(struct drm_crtc *crtc,
		struct drm_crtc_state *old_state, bool add_planes)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *sde_crtc_state;
@@ -1632,7 +1641,7 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc, bool add_planes)
	memset(&sde_crtc->stage_cfg, 0, sizeof(struct sde_hw_stage_cfg));

	if (add_planes)
		_sde_crtc_blend_setup_mixer(crtc, sde_crtc, mixer);
		_sde_crtc_blend_setup_mixer(crtc, old_state, sde_crtc, mixer);

	for (i = 0; i < sde_crtc->num_mixers; i++) {
		const struct sde_rect *lm_roi = &sde_crtc_state->lm_roi[i];
@@ -3203,7 +3212,7 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
	if (unlikely(!sde_crtc->num_mixers))
		return;

	_sde_crtc_blend_setup(crtc, true);
	_sde_crtc_blend_setup(crtc, old_state, true);
	_sde_crtc_dest_scaler_setup(crtc);

	/* cancel the idle notify delayed work */
@@ -3427,23 +3436,29 @@ static int _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc,
	sde_crtc = to_sde_crtc(crtc);

	/*
	 * Update sbuf configuration and flush bits if a flush
	 * mask has been defined for either the current or
	 * previous commit.
	 * Update sbuf configuration and flush bits if either the rot_op_mode
	 * is different or a rotator commit was performed.
	 *
	 * Updates are also required for the first commit after
	 * sbuf_flush_mask becomes 0x0, to properly transition
	 * the hardware out of sbuf mode.
	 * In the case where the rot_op_mode has changed, further require that
	 * the transition is either to or from offline mode unless
	 * sbuf_flush_mask_delta is also non-zero (i.e., a corresponding plane
	 * update was provided to the current commit).
	 */
	if (!sde_crtc->sbuf_flush_mask_old && !sde_crtc->sbuf_flush_mask)
	flush_mask = sde_crtc->sbuf_flush_mask_delta;
	if ((sde_crtc->sbuf_op_mode_old != cstate->sbuf_cfg.rot_op_mode) &&
		(sde_crtc->sbuf_op_mode_old == SDE_CTL_ROT_OP_MODE_OFFLINE ||
		cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE))
		flush_mask |= sde_crtc->sbuf_flush_mask_all |
			sde_crtc->sbuf_flush_mask_old;

	if (!flush_mask &&
		cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE)
		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;

	SDE_ATRACE_BEGIN("crtc_kickoff_rot");

	if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE) {
	if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE &&
			sde_crtc->sbuf_flush_mask_delta) {
		drm_atomic_crtc_for_each_plane(plane, crtc) {
			rc = sde_plane_kickoff_rot(plane);
			if (rc) {
@@ -3479,12 +3494,16 @@ static int _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc,
		/* 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->ops.trigger_rot_start(master_ctl);
			SDE_EVT32(DRMID(crtc), master_ctl->idx - CTL_0);
		}
		SDE_EVT32(DRMID(crtc), master_ctl->idx - CTL_0,
				sde_crtc->sbuf_flush_mask_all,
				sde_crtc->sbuf_flush_mask_delta);
	}

	/* save this in sde_crtc for next commit cycle */
	sde_crtc->sbuf_op_mode_old = cstate->sbuf_cfg.rot_op_mode;

	SDE_ATRACE_END("crtc_kickoff_rot");
	return rc;
}
@@ -3626,7 +3645,7 @@ static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
	cstate->sbuf_cfg.rot_op_mode = SDE_CTL_ROT_OP_MODE_OFFLINE;
	_sde_crtc_commit_kickoff_rot(crtc, cstate);
	_sde_crtc_remove_pipe_flush(sde_crtc);
	_sde_crtc_blend_setup(crtc, false);
	_sde_crtc_blend_setup(crtc, old_state, false);

	/* take h/w components out of reset */
	for (i = plane_count - 1; i >= 0; --i)
@@ -3682,7 +3701,7 @@ static bool _sde_crtc_prepare_for_kickoff_rot(struct drm_device *dev,
	cstate = to_sde_crtc_state(crtc->state);

	/* default to ASYNC mode for inline rotation */
	cstate->sbuf_cfg.rot_op_mode = sde_crtc->sbuf_flush_mask ?
	cstate->sbuf_cfg.rot_op_mode = sde_crtc->sbuf_flush_mask_all ?
		SDE_CTL_ROT_OP_MODE_INLINE_ASYNC : SDE_CTL_ROT_OP_MODE_OFFLINE;

	if (cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE)
@@ -3827,7 +3846,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,

	if (is_error) {
		_sde_crtc_remove_pipe_flush(sde_crtc);
		_sde_crtc_blend_setup(crtc, false);
		_sde_crtc_blend_setup(crtc, old_state, false);
	}

	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+6 −2
Original line number Diff line number Diff line
@@ -215,8 +215,10 @@ struct sde_crtc_event {
 * @misr_enable   : boolean entry indicates misr enable/disable status.
 * @misr_frame_count  : misr frame count provided by client
 * @misr_data     : store misr data before turning off the clocks.
 * @sbuf_flush_mask: flush mask for inline rotator
 * @sbuf_op_mode_old : inline rotator op mode for previous commit cycle
 * @sbuf_flush_mask_old: inline rotator flush mask for previous commit
 * @sbuf_flush_mask_all: inline rotator flush mask for all attached planes
 * @sbuf_flush_mask_delta: inline rotator flush mask for current delta state
 * @idle_notify_work: delayed worker to notify idle timeout to user space
 * @power_event   : registered power event handle
 * @cur_perf      : current performance committed to clock/bandwidth driver
@@ -284,8 +286,10 @@ struct sde_crtc {
	u32 misr_frame_count;
	u32 misr_data[CRTC_DUAL_MIXERS];

	u32 sbuf_flush_mask;
	u32 sbuf_op_mode_old;
	u32 sbuf_flush_mask_old;
	u32 sbuf_flush_mask_all;
	u32 sbuf_flush_mask_delta;
	struct kthread_delayed_work idle_notify_work;

	struct sde_power_event *power_event;