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

Commit 8654e763 authored by Prabhanjan Kandula's avatar Prabhanjan Kandula Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/sde: trigger null commit if a display stuck in cont-splash



SDE driver marks the respective DRM display active when continuous
splash is enabled for that display. It expects a valid commit for
continuous splash enabled display before pm_suspend/pm_resume call.
It may possible that DRM driver client does not push any valid commit
on this display and it may try to enter pm_suspend with active
configuration. That breaks the pm resume commit because suspend state
cached continuous splash enabled commit. This change triggers a null commit
during pm_suspend if a display is stuck in continuous splash enabled state.

Change-Id: I99f978e08ef200a3a7e3d50d30665cfcc1596e2d
Signed-off-by: default avatarPrabhanjan Kandula <pkandula@codeaurora.org>
parent b61ff4fd
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
@@ -77,6 +77,9 @@ static const char * const iommu_ports[] = {
#define SDE_DEBUGFS_DIR "msm_sde"
#define SDE_DEBUGFS_HWMASKNAME "hw_log_mask"

#define SDE_KMS_MODESET_LOCK_TIMEOUT_US 500
#define SDE_KMS_MODESET_LOCK_MAX_TRIALS 20

/**
 * sdecustom - enable certain driver customizations for sde clients
 *	Enabling this modifies the standard DRM behavior slightly and assumes
@@ -2618,11 +2621,79 @@ static bool sde_kms_check_for_splash(struct msm_kms *kms)
	return sde_kms->splash_data.num_splash_displays;
}

static void _sde_kms_null_commit(struct drm_device *dev,
		struct drm_encoder *enc)
{
	struct drm_modeset_acquire_ctx ctx;
	struct drm_connector *conn = NULL;
	struct drm_connector *tmp_conn = NULL;
	struct drm_connector_list_iter conn_iter;
	struct drm_atomic_state *state = NULL;
	struct drm_crtc_state *crtc_state = NULL;
	struct drm_connector_state *conn_state = NULL;
	int retry_cnt = 0;
	int ret = 0;

	drm_modeset_acquire_init(&ctx, 0);

retry:
	ret = drm_modeset_lock_all_ctx(dev, &ctx);
	if (ret == -EDEADLK && retry_cnt < SDE_KMS_MODESET_LOCK_MAX_TRIALS) {
		drm_modeset_backoff(&ctx);
		retry_cnt++;
		udelay(SDE_KMS_MODESET_LOCK_TIMEOUT_US);
		goto retry;
	} else if (WARN_ON(ret)) {
		goto end;
	}

	state = drm_atomic_state_alloc(dev);
	if (!state) {
		DRM_ERROR("failed to allocate atomic state, %d\n", ret);
		goto end;
	}

	state->acquire_ctx = &ctx;
	drm_connector_list_iter_begin(dev, &conn_iter);
	drm_for_each_connector_iter(tmp_conn, &conn_iter) {
		if (enc == tmp_conn->state->best_encoder) {
			conn = tmp_conn;
			break;
		}
	}
	drm_connector_list_iter_end(&conn_iter);

	if (!conn) {
		SDE_ERROR("error in finding conn for enc:%d\n", DRMID(enc));
		goto end;
	}

	crtc_state = drm_atomic_get_crtc_state(state, enc->crtc);
	conn_state = drm_atomic_get_connector_state(state, conn);
	if (IS_ERR(conn_state)) {
		SDE_ERROR("error %d getting connector %d state\n",
				ret, DRMID(conn));
		goto end;
	}

	crtc_state->active = true;
	drm_atomic_set_crtc_for_connector(conn_state, enc->crtc);

	drm_atomic_commit(state);
end:
	if (state)
		drm_atomic_state_put(state);

	drm_modeset_drop_locks(&ctx);
	drm_modeset_acquire_fini(&ctx);
}

static int sde_kms_pm_suspend(struct device *dev)
{
	struct drm_device *ddev;
	struct drm_modeset_acquire_ctx ctx;
	struct drm_connector *conn;
	struct drm_encoder *enc;
	struct drm_connector_list_iter conn_iter;
	struct drm_atomic_state *state = NULL;
	struct sde_kms *sde_kms;
@@ -2641,6 +2712,12 @@ static int sde_kms_pm_suspend(struct device *dev)
	/* disable hot-plug polling */
	drm_kms_helper_poll_disable(ddev);

	/* if a display stuck in CS trigger a null commit to complete handoff */
	drm_for_each_encoder(enc, ddev) {
		if (sde_encoder_in_cont_splash(enc) && enc->crtc)
			_sde_kms_null_commit(ddev, enc);
	}

	/* acquire modeset lock(s) */
	drm_modeset_acquire_init(&ctx, 0);