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

Commit 8a9b38a3 authored by Alan Kwong's avatar Alan Kwong
Browse files

drm/msm: add affected planes during idle power restore



During idle power restore, software plane states are not
modified so they are not added to the new atomic state
during commit. This causes drm framework to bypass plane
atomic check & update, and results in pipe buffer offset
to be in reset state. This causes smmu fault subsequently.

Add affected planes to new atomic state during first atomic
check after power restore so hardware pipe buffer offset
will be updated.

CRs-Fixed: 2064858
Change-Id: Icd8978cfb24a1c19980fab99f607102e95a16b85
Signed-off-by: default avatarAlan Kwong <akwong@codeaurora.org>
parent 84cf4451
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -126,10 +126,21 @@ static void msm_fb_output_poll_changed(struct drm_device *dev)
int msm_atomic_check(struct drm_device *dev,
			    struct drm_atomic_state *state)
{
	struct msm_drm_private *priv;

	if (!dev)
		return -EINVAL;

	if (msm_is_suspend_blocked(dev)) {
		DRM_DEBUG("rejecting commit during suspend\n");
		return -EBUSY;
	}

	priv = dev->dev_private;
	if (priv && priv->kms && priv->kms->funcs &&
			priv->kms->funcs->atomic_check)
		return priv->kms->funcs->atomic_check(priv->kms, state);

	return drm_atomic_helper_check(dev, state);
}

+3 −0
Original line number Diff line number Diff line
@@ -75,6 +75,9 @@ struct msm_kms_funcs {
			const struct msm_format *msm_fmt,
			const struct drm_mode_fb_cmd2 *cmd,
			struct drm_gem_object **bos);
	/* perform complete atomic check of given atomic state */
	int (*atomic_check)(struct msm_kms *kms,
				    struct drm_atomic_state *state);
	/* misc: */
	long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
			struct drm_encoder *encoder);
+24 −1
Original line number Diff line number Diff line
@@ -2357,6 +2357,8 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc)

	_sde_crtc_rp_duplicate(&old_cstate->rp, &cstate->rp);

	cstate->idle_pc = sde_crtc->idle_pc;

	return &cstate->base;
}

@@ -2457,6 +2459,24 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
			sde_encoder_virt_restore(encoder);
		}

	} else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) {
		/*
		 * Serialize h/w idle state update with crtc atomic check.
		 * Grab the modeset lock to ensure that there is no on-going
		 * atomic check, then increment the idle_pc counter. The next
		 * atomic check will detect a new idle_pc since the counter
		 * has advanced between the old_state and new_state, and
		 * therefore properly reprogram all relevant drm objects'
		 * hardware.
		 */
		drm_modeset_lock_crtc(crtc, NULL);

		sde_crtc->idle_pc++;

		SDE_DEBUG("crtc%d idle_pc:%d\n", crtc->base.id,
				sde_crtc->idle_pc);
		SDE_EVT32(DRMID(crtc), sde_crtc->idle_pc);

	} else if (event_type == SDE_POWER_EVENT_POST_DISABLE) {
		struct drm_plane *plane;

@@ -2466,6 +2486,8 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
		 */
		drm_atomic_crtc_for_each_plane(plane, crtc)
			sde_plane_set_revalidate(plane, true);

		drm_modeset_unlock_crtc(crtc);
	}

	mutex_unlock(&sde_crtc->crtc_lock);
@@ -2594,7 +2616,8 @@ static void sde_crtc_enable(struct drm_crtc *crtc)

	sde_crtc->power_event = sde_power_handle_register_event(
		&priv->phandle,
		SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE,
		SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE |
		SDE_POWER_EVENT_PRE_DISABLE,
		sde_crtc_handle_power_event, crtc, sde_crtc->name);
}

+5 −0
Original line number Diff line number Diff line
@@ -125,6 +125,7 @@ struct sde_crtc_event {
 * @vblank_cb_time  : ktime at vblank count reset
 * @vblank_refcount : reference count for vblank enable request
 * @suspend         : whether or not a suspend operation is in progress
 * @idle_pc       : count of current idle power collapse request
 * @feature_list  : list of color processing features supported on a crtc
 * @active_list   : list of color processing features are active
 * @dirty_list    : list of color processing features are dirty
@@ -173,6 +174,7 @@ struct sde_crtc {
	ktime_t vblank_cb_time;
	atomic_t vblank_refcount;
	bool suspend;
	u32 idle_pc;

	struct list_head feature_list;
	struct list_head active_list;
@@ -278,6 +280,7 @@ struct sde_crtc_respool {
 * @sbuf_cfg: stream buffer configuration
 * @sbuf_prefill_line: number of line for inline rotator prefetch
 * @sbuf_flush_mask: flush mask for inline rotator
 * @idle_pc: count of idle power collapse request when state is duplicated
 */
struct sde_crtc_state {
	struct drm_crtc_state base;
@@ -307,6 +310,8 @@ struct sde_crtc_state {
	u32 sbuf_prefill_line;
	u32 sbuf_flush_mask;

	u32 idle_pc;

	struct sde_crtc_respool rp;
};

+43 −0
Original line number Diff line number Diff line
@@ -1370,6 +1370,48 @@ static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file)
		sde_crtc_cancel_pending_flip(priv->crtcs[i], file);
}

static int sde_kms_atomic_check(struct msm_kms *kms,
		struct drm_atomic_state *state)
{
	struct sde_kms *sde_kms = to_sde_kms(kms);
	struct drm_device *dev = sde_kms->dev;
	struct drm_crtc *crtc;
	struct drm_crtc_state *crtc_state;
	int rc, i;

	if (!kms || !state)
		return -EINVAL;

	/*
	 * Add planes (and other affected DRM objects, if any) to new state
	 * if idle power collapse occurred since previous commit.
	 * Since atomic state is a delta from the last, if the user-space
	 * did not request any changes on a plane/connector, that object
	 * will not be included in the new atomic state. Idle power collapse
	 * is driver-autonomous, so the driver needs to ensure that all
	 * hardware is reprogrammed as the power comes back on by forcing
	 * the drm objects attached to the CRTC into the new atomic state.
	 */
	for_each_crtc_in_state(state, crtc, crtc_state, i) {
		struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state);
		struct sde_crtc_state *old_cstate =
				to_sde_crtc_state(crtc->state);

		if (cstate->idle_pc != old_cstate->idle_pc) {
			SDE_DEBUG("crtc%d idle_pc:%d/%d\n",
					crtc->base.id, cstate->idle_pc,
					old_cstate->idle_pc);
			SDE_EVT32(DRMID(crtc), cstate->idle_pc,
					old_cstate->idle_pc);
			rc = drm_atomic_add_affected_planes(state, crtc);
			if (rc)
				return rc;
		}
	}

	return drm_atomic_helper_check(dev, state);
}

static const struct msm_kms_funcs kms_funcs = {
	.hw_init         = sde_kms_hw_init,
	.postinit        = sde_kms_postinit,
@@ -1387,6 +1429,7 @@ static const struct msm_kms_funcs kms_funcs = {
	.enable_vblank   = sde_kms_enable_vblank,
	.disable_vblank  = sde_kms_disable_vblank,
	.check_modified_format = sde_format_check_modified_format,
	.atomic_check    = sde_kms_atomic_check,
	.get_format      = sde_get_msm_format,
	.round_pixclk    = sde_kms_round_pixclk,
	.destroy         = sde_kms_destroy,