diff mbox

[10/13] drm/exynos: update crtc to plane safely

Message ID 1345197059-25583-11-git-send-email-inki.dae@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Inki Dae Aug. 17, 2012, 9:50 a.m. UTC
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: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_encoder.c |   59 +++++++++++++++++++++++++-
 1 files changed, 56 insertions(+), 3 deletions(-)

Comments

Joonyoung Shim Aug. 20, 2012, 1:25 a.m. UTC | #1
On 08/17/2012 06:50 PM, Inki Dae wrote:
> 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: Inki Dae <inki.dae@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>   drivers/gpu/drm/exynos/exynos_drm_encoder.c |   59 +++++++++++++++++++++++++-
>   1 files changed, 56 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> index a562a94..7bcace8 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> @@ -44,6 +44,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;
> @@ -106,22 +107,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);

Does needs to do this in for statement?

> +
> +			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;

Does needs to do this in for statement?


> +
>   			if (manager_ops && manager_ops->mode_set)
>   				manager_ops->mode_set(manager->dev,
>   							adjusted_mode);
> +
> +			exynos_encoder->old_crtc = encoder->crtc;
> +		}
>   	}
>   }
>
diff mbox

Patch

diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index a562a94..7bcace8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -44,6 +44,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;
@@ -106,22 +107,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;
+		}
 	}
 }