Эх сурвалжийг харах

Merge branch 'drm/next/du' of git://linuxtv.org/pinchartl/fbdev into drm-next

rcar-du fixes

* 'drm/next/du' of git://linuxtv.org/pinchartl/fbdev:
  drm: rcar-du: Use the drm atomic state duplication helpers for planes
  drm: rcar-du: Clean up planes in the error paths of .atomic_commit()
  drm: rcar-du: Convert rcar_du_encoders_init_one() return value to 0/<0
  drm: rcar-du: Clarify error message when encoder initialization fails
  drm: rcar-du: Fix crash with groups that have less than 9 planes
  drm: rcar-du: Disable all planes when stopping the CRTC
  drm: rcar-du: Print the error value when DRM/KMS init fails
Dave Airlie 10 жил өмнө
parent
commit
a21be4ece9

+ 15 - 2
drivers/gpu/drm/rcar-du/rcar_du_crtc.c

@@ -214,7 +214,7 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
 	unsigned int i;
 	u32 dspr = 0;
 
-	for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes); ++i) {
+	for (i = 0; i < rcrtc->group->num_planes; ++i) {
 		struct rcar_du_plane *plane = &rcrtc->group->planes[i];
 		unsigned int j;
 
@@ -398,6 +398,19 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
 	if (!rcrtc->started)
 		return;
 
+	/* Disable all planes and wait for the change to take effect. This is
+	 * required as the DSnPR registers are updated on vblank, and no vblank
+	 * will occur once the CRTC is stopped. Disabling planes when starting
+	 * the CRTC thus wouldn't be enough as it would start scanning out
+	 * immediately from old frame buffers until the next vblank.
+	 *
+	 * This increases the CRTC stop delay, especially when multiple CRTCs
+	 * are stopped in one operation as we now wait for one vblank per CRTC.
+	 * Whether this can be improved needs to be researched.
+	 */
+	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
+	drm_crtc_wait_one_vblank(crtc);
+
 	/* Disable vertical blanking interrupt reporting. We first need to wait
 	 * for page flip completion before stopping the CRTC as userspace
 	 * expects page flips to eventually complete.
@@ -432,7 +445,7 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
 	rcar_du_crtc_start(rcrtc);
 
 	/* Commit the planes state. */
-	for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes); ++i) {
+	for (i = 0; i < rcrtc->group->num_planes; ++i) {
 		struct rcar_du_plane *plane = &rcrtc->group->planes[i];
 
 		if (plane->plane.state->crtc != &rcrtc->crtc)

+ 1 - 1
drivers/gpu/drm/rcar-du/rcar_du_drv.c

@@ -190,7 +190,7 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
 	/* DRM/KMS objects */
 	ret = rcar_du_modeset_init(rcdu);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to initialize DRM/KMS\n");
+		dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret);
 		goto done;
 	}
 

+ 2 - 0
drivers/gpu/drm/rcar-du/rcar_du_group.h

@@ -30,6 +30,7 @@ struct rcar_du_device;
  * @used_crtcs: number of CRTCs currently in use
  * @lock: protects the dptsr_planes field and the DPTSR register
  * @dptsr_planes: bitmask of planes driven by dot-clock and timing generator 1
+ * @num_planes: number of planes in the group
  * @planes: planes handled by the group
  */
 struct rcar_du_group {
@@ -44,6 +45,7 @@ struct rcar_du_group {
 	struct mutex lock;
 	unsigned int dptsr_planes;
 
+	unsigned int num_planes;
 	struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
 };
 

+ 20 - 11
drivers/gpu/drm/rcar-du/rcar_du_kms.c

@@ -336,7 +336,7 @@ static int rcar_du_atomic_check(struct drm_device *dev,
 		dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n",
 			__func__, index);
 
-		for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
+		for (i = 0; i < group->num_planes; ++i) {
 			struct rcar_du_plane *plane = &group->planes[i];
 			struct rcar_du_plane_state *plane_state;
 			struct drm_plane_state *s;
@@ -495,8 +495,10 @@ static int rcar_du_atomic_commit(struct drm_device *dev,
 
 	/* Allocate the commit object. */
 	commit = kzalloc(sizeof(*commit), GFP_KERNEL);
-	if (commit == NULL)
-		return -ENOMEM;
+	if (commit == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
 
 	INIT_WORK(&commit->work, rcar_du_atomic_work);
 	commit->dev = dev;
@@ -519,7 +521,7 @@ static int rcar_du_atomic_commit(struct drm_device *dev,
 
 	if (ret) {
 		kfree(commit);
-		return ret;
+		goto error;
 	}
 
 	/* Swap the state, this is the point of no return. */
@@ -531,6 +533,10 @@ static int rcar_du_atomic_commit(struct drm_device *dev,
 		rcar_du_atomic_complete(commit);
 
 	return 0;
+
+error:
+	drm_atomic_helper_cleanup_planes(dev, state);
+	return ret;
 }
 
 /* -----------------------------------------------------------------------------
@@ -573,7 +579,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
 	if (!entity) {
 		dev_dbg(rcdu->dev, "unconnected endpoint %s, skipping\n",
 			ep->local_node->full_name);
-		return 0;
+		return -ENODEV;
 	}
 
 	entity_ep_node = of_parse_phandle(ep->local_node, "remote-endpoint", 0);
@@ -596,7 +602,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
 				 encoder->full_name);
 			of_node_put(entity_ep_node);
 			of_node_put(encoder);
-			return 0;
+			return -ENODEV;
 		}
 
 		break;
@@ -625,7 +631,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
 				 encoder->full_name);
 			of_node_put(encoder);
 			of_node_put(connector);
-			return 0;
+			return -EINVAL;
 		}
 	} else {
 		/*
@@ -639,7 +645,12 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
 	of_node_put(encoder);
 	of_node_put(connector);
 
-	return ret < 0 ? ret : 1;
+	if (ret && ret != -EPROBE_DEFER)
+		dev_warn(rcdu->dev,
+			 "failed to initialize encoder %s (%d), skipping\n",
+			 encoder->full_name, ret);
+
+	return ret;
 }
 
 static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
@@ -688,12 +699,10 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
 				return ret;
 			}
 
-			dev_info(rcdu->dev,
-				 "encoder initialization failed, skipping\n");
 			continue;
 		}
 
-		num_encoders += ret;
+		num_encoders++;
 	}
 
 	return num_encoders;

+ 7 - 8
drivers/gpu/drm/rcar-du/rcar_du_plane.c

@@ -302,13 +302,15 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
 	struct rcar_du_plane_state *state;
 	struct rcar_du_plane_state *copy;
 
+	if (WARN_ON(!plane->state))
+		return NULL;
+
 	state = to_rcar_plane_state(plane->state);
 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
 	if (copy == NULL)
 		return NULL;
 
-	if (copy->state.fb)
-		drm_framebuffer_reference(copy->state.fb);
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
 
 	return &copy->state;
 }
@@ -316,9 +318,7 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
 static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane,
 					       struct drm_plane_state *state)
 {
-	if (state->fb)
-		drm_framebuffer_unreference(state->fb);
-
+	__drm_atomic_helper_plane_destroy_state(plane, state);
 	kfree(to_rcar_plane_state(state));
 }
 
@@ -390,7 +390,6 @@ static const uint32_t formats[] = {
 int rcar_du_planes_init(struct rcar_du_group *rgrp)
 {
 	struct rcar_du_device *rcdu = rgrp->dev;
-	unsigned int num_planes;
 	unsigned int crtcs;
 	unsigned int i;
 	int ret;
@@ -398,11 +397,11 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
 	 /* Create one primary plane per CRTC in this group and seven overlay
 	  * planes.
 	  */
-	num_planes = rgrp->num_crtcs + 7;
+	rgrp->num_planes = rgrp->num_crtcs + 7;
 
 	crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index));
 
-	for (i = 0; i < num_planes; ++i) {
+	for (i = 0; i < rgrp->num_planes; ++i) {
 		enum drm_plane_type type = i < rgrp->num_crtcs
 					 ? DRM_PLANE_TYPE_PRIMARY
 					 : DRM_PLANE_TYPE_OVERLAY;