Commit 1b85a071 authored by Inki Dae's avatar Inki Dae
Browse files

drm/exynos: update crtc to plane safely



if old_crtc isn't same as encoder->crtc then it means that
user changed crtc id to another one so a plane to old_crtc
should be disabled so that current plane can be updated safely
and plane->crtc should be set to new crtc(encoder->crtc)

Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
parent 01ed8126
Loading
Loading
Loading
Loading
+56 −3
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
 * @dpms: store the encoder dpms value.
 */
struct exynos_drm_encoder {
	struct drm_crtc			*old_crtc;
	struct drm_encoder		drm_encoder;
	struct exynos_drm_manager	*manager;
	int dpms;
@@ -124,22 +125,74 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
	return true;
}

static void disable_plane_to_crtc(struct drm_device *dev,
						struct drm_crtc *old_crtc,
						struct drm_crtc *new_crtc)
{
	struct drm_plane *plane;

	/*
	 * if old_crtc isn't same as encoder->crtc then it means that
	 * user changed crtc id to another one so the plane to old_crtc
	 * should be disabled and plane->crtc should be set to new_crtc
	 * (encoder->crtc)
	 */
	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
		if (plane->crtc == old_crtc) {
			/*
			 * do not change below call order.
			 *
			 * plane->funcs->disable_plane call checks
			 * if encoder->crtc is same as plane->crtc and if same
			 * then overlay_ops->disable callback will be called
			 * to diasble current hw overlay so plane->crtc should
			 * have new_crtc because new_crtc was set to
			 * encoder->crtc in advance.
			 */
			plane->crtc = new_crtc;
			plane->funcs->disable_plane(plane);
		}
	}
}

static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
					 struct drm_display_mode *mode,
					 struct drm_display_mode *adjusted_mode)
{
	struct drm_device *dev = encoder->dev;
	struct drm_connector *connector;
	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
	struct exynos_drm_manager_ops *manager_ops = manager->ops;
	struct exynos_drm_manager *manager;
	struct exynos_drm_manager_ops *manager_ops;

	DRM_DEBUG_KMS("%s\n", __FILE__);

	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		if (connector->encoder == encoder)
		if (connector->encoder == encoder) {
			struct exynos_drm_encoder *exynos_encoder;

			exynos_encoder = to_exynos_encoder(encoder);

			if (exynos_encoder->old_crtc != encoder->crtc &&
					exynos_encoder->old_crtc) {

				/*
				 * disable a plane to old crtc and change
				 * crtc of the plane to new one.
				 */
				disable_plane_to_crtc(dev,
						exynos_encoder->old_crtc,
						encoder->crtc);
			}

			manager = exynos_drm_get_manager(encoder);
			manager_ops = manager->ops;

			if (manager_ops && manager_ops->mode_set)
				manager_ops->mode_set(manager->dev,
							adjusted_mode);

			exynos_encoder->old_crtc = encoder->crtc;
		}
	}
}