dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client
@ 2019-03-26 17:55 Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 01/16] drm/fb-helper: Remove unused gamma_size variable Noralf Trønnes
                   ` (17 more replies)
  0 siblings, 18 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes, mstaudt

This moves the modesetting code from drm_fb_helper to drm_client so it
can be shared by all internal clients.

I have also added a client display abstraction and a bootsplash example
client to show where this might be heading. Hopefully Max Staudt will be
able to pick up his bootsplash work now.

Noralf.

Noralf Trønnes (16):
  drm/fb-helper: Remove unused gamma_size variable
  drm/fb-helper: dpms_legacy(): Only set on connectors in use
  drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  drm/fb-helper: No need to cache rotation and sw_rotations
  drm/fb-helper: Remove drm_fb_helper_crtc->{x,y,desired_mode}
  drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
  drm/fb-helper: Remove drm_fb_helper_crtc
  drm/fb-helper: Prepare to move out commit code
  drm/fb-helper: Move out commit code
  drm/fb-helper: Remove drm_fb_helper_connector
  drm/fb-helper: Prepare to move out modeset config code
  drm/fb-helper: Move out modeset config code
  drm/fb-helper: Avoid race with DRM userspace
  drm/client: Add display abstraction
  drm/client: Hack: Add bootsplash example
  drm/vc4: Call drm_dev_register() after all setup is done

 Documentation/gpu/todo.rst          |   10 +
 drivers/gpu/drm/Kconfig             |    5 +
 drivers/gpu/drm/Makefile            |    1 +
 drivers/gpu/drm/drm_atomic.c        |  168 ++++
 drivers/gpu/drm/drm_atomic_helper.c |  164 ---
 drivers/gpu/drm/drm_auth.c          |   20 +
 drivers/gpu/drm/drm_bootsplash.c    |  216 ++++
 drivers/gpu/drm/drm_client.c        | 1449 +++++++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc_internal.h |    5 +
 drivers/gpu/drm/drm_drv.c           |    4 +
 drivers/gpu/drm/drm_fb_helper.c     | 1151 ++-------------------
 drivers/gpu/drm/drm_internal.h      |    2 +
 drivers/gpu/drm/i915/intel_fbdev.c  |  218 ----
 drivers/gpu/drm/vc4/vc4_drv.c       |    6 +-
 include/drm/drm_atomic_helper.h     |    4 -
 include/drm/drm_client.h            |  117 +++
 include/drm/drm_fb_helper.h         |  127 +--
 17 files changed, 2128 insertions(+), 1539 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_bootsplash.c

-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH 01/16] drm/fb-helper: Remove unused gamma_size variable
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 18:23   ` Daniel Vetter
  2019-03-26 17:55 ` [PATCH 02/16] drm/fb-helper: dpms_legacy(): Only set on connectors in use Noralf Trønnes
                   ` (16 subsequent siblings)
  17 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes, mstaudt

The gamma_size variable has not been used since
commit 4abe35204af8 ("drm/kms/fb: use slow work mechanism for normal hotplug also.")

While in the area move a comment back to its code block.
They got separated by
commit d50ba256b5f1 ("drm/kms: start adding command line interface using fb.").

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 04d23cb430bf..eea15465da7a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1873,7 +1873,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	int crtc_count = 0;
 	int i;
 	struct drm_fb_helper_surface_size sizes;
-	int gamma_size = 0;
 	int best_depth = 0;
 
 	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
@@ -1889,7 +1888,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	if (preferred_bpp != sizes.surface_bpp)
 		sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
 
-	/* first up get a count of crtcs now in use and new min/maxes width/heights */
 	drm_fb_helper_for_each_connector(fb_helper, i) {
 		struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
 		struct drm_cmdline_mode *cmdline_mode;
@@ -1969,6 +1967,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 		sizes.surface_depth = best_depth;
 	}
 
+	/* first up get a count of crtcs now in use and new min/maxes width/heights */
 	crtc_count = 0;
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		struct drm_display_mode *desired_mode;
@@ -1991,9 +1990,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 		x = fb_helper->crtc_info[i].x;
 		y = fb_helper->crtc_info[i].y;
 
-		if (gamma_size == 0)
-			gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
-
 		sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
 		sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
 
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 02/16] drm/fb-helper: dpms_legacy(): Only set on connectors in use
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 01/16] drm/fb-helper: Remove unused gamma_size variable Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 18:26   ` Daniel Vetter
  2019-03-26 17:55 ` [PATCH 03/16] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
                   ` (15 subsequent siblings)
  17 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, mstaudt

For each enabled crtc the functions sets dpms on all registered connectors.
Limit this to only doing it once and on the connectors actually in use.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index eea15465da7a..b91df658db59 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -639,20 +639,19 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
 {
 	struct drm_device *dev = fb_helper->dev;
-	struct drm_crtc *crtc;
 	struct drm_connector *connector;
+	struct drm_mode_set *modeset;
 	int i, j;
 
 	drm_modeset_lock_all(dev);
 	for (i = 0; i < fb_helper->crtc_count; i++) {
-		crtc = fb_helper->crtc_info[i].mode_set.crtc;
+		modeset = &fb_helper->crtc_info[i].mode_set;
 
-		if (!crtc->enabled)
+		if (!modeset->crtc->enabled)
 			continue;
 
-		/* Walk the connectors & encoders on this fb turning them on/off */
-		drm_fb_helper_for_each_connector(fb_helper, j) {
-			connector = fb_helper->connector_info[j]->connector;
+		for (j = 0; j < modeset->num_connectors; j++) {
+			connector = modeset->connectors[j];
 			connector->funcs->dpms(connector, dpms_mode);
 			drm_object_property_set_value(&connector->base,
 				dev->mode_config.dpms_property, dpms_mode);
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 03/16] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 01/16] drm/fb-helper: Remove unused gamma_size variable Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 02/16] drm/fb-helper: dpms_legacy(): Only set on connectors in use Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 20:48   ` Daniel Vetter
  2019-03-26 17:55 ` [PATCH 04/16] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
                   ` (14 subsequent siblings)
  17 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, mstaudt

Prepare for moving drm_fb_helper modesetting code to drm_client.
drm_client will be linked to drm.ko, so move
__drm_atomic_helper_disable_plane() and __drm_atomic_helper_set_config()
out of drm_kms_helper.ko.

While at it, fix two checkpatch complaints:
- WARNING: Block comments use a trailing */ on a separate line
- CHECK: Alignment should match open parenthesis

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_atomic.c        | 168 ++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_atomic_helper.c | 164 ---------------------------
 drivers/gpu/drm/drm_crtc_internal.h |   5 +
 include/drm/drm_atomic_helper.h     |   4 -
 4 files changed, 173 insertions(+), 168 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5eb40130fafb..c3a9ffbf2310 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1130,6 +1130,174 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
 }
 EXPORT_SYMBOL(drm_atomic_nonblocking_commit);
 
+/* just used from drm-client and atomic-helper: */
+int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
+				      struct drm_plane_state *plane_state)
+{
+	int ret;
+
+	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
+	if (ret != 0)
+		return ret;
+
+	drm_atomic_set_fb_for_plane(plane_state, NULL);
+	plane_state->crtc_x = 0;
+	plane_state->crtc_y = 0;
+	plane_state->crtc_w = 0;
+	plane_state->crtc_h = 0;
+	plane_state->src_x = 0;
+	plane_state->src_y = 0;
+	plane_state->src_w = 0;
+	plane_state->src_h = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_disable_plane);
+
+static int update_output_state(struct drm_atomic_state *state,
+			       struct drm_mode_set *set)
+{
+	struct drm_device *dev = set->crtc->dev;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *new_crtc_state;
+	struct drm_connector *connector;
+	struct drm_connector_state *new_conn_state;
+	int ret, i;
+
+	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	/* First disable all connectors on the target crtc. */
+	ret = drm_atomic_add_affected_connectors(state, set->crtc);
+	if (ret)
+		return ret;
+
+	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
+		if (new_conn_state->crtc == set->crtc) {
+			ret = drm_atomic_set_crtc_for_connector(new_conn_state,
+								NULL);
+			if (ret)
+				return ret;
+
+			/* Make sure legacy setCrtc always re-trains */
+			new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
+		}
+	}
+
+	/* Then set all connectors from set->connectors on the target crtc */
+	for (i = 0; i < set->num_connectors; i++) {
+		new_conn_state = drm_atomic_get_connector_state(state,
+								set->connectors[i]);
+		if (IS_ERR(new_conn_state))
+			return PTR_ERR(new_conn_state);
+
+		ret = drm_atomic_set_crtc_for_connector(new_conn_state,
+							set->crtc);
+		if (ret)
+			return ret;
+	}
+
+	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+		/*
+		 * Don't update ->enable for the CRTC in the set_config request,
+		 * since a mismatch would indicate a bug in the upper layers.
+		 * The actual modeset code later on will catch any
+		 * inconsistencies here.
+		 */
+		if (crtc == set->crtc)
+			continue;
+
+		if (!new_crtc_state->connector_mask) {
+			ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
+								NULL);
+			if (ret < 0)
+				return ret;
+
+			new_crtc_state->active = false;
+		}
+	}
+
+	return 0;
+}
+
+/* just used from drm-client and atomic-helper: */
+int __drm_atomic_helper_set_config(struct drm_mode_set *set,
+				   struct drm_atomic_state *state)
+{
+	struct drm_crtc_state *crtc_state;
+	struct drm_plane_state *primary_state;
+	struct drm_crtc *crtc = set->crtc;
+	int hdisplay, vdisplay;
+	int ret;
+
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
+	if (IS_ERR(primary_state))
+		return PTR_ERR(primary_state);
+
+	if (!set->mode) {
+		WARN_ON(set->fb);
+		WARN_ON(set->num_connectors);
+
+		ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
+		if (ret != 0)
+			return ret;
+
+		crtc_state->active = false;
+
+		ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
+		if (ret != 0)
+			return ret;
+
+		drm_atomic_set_fb_for_plane(primary_state, NULL);
+
+		goto commit;
+	}
+
+	WARN_ON(!set->fb);
+	WARN_ON(!set->num_connectors);
+
+	ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
+	if (ret != 0)
+		return ret;
+
+	crtc_state->active = true;
+
+	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
+	if (ret != 0)
+		return ret;
+
+	drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
+
+	drm_atomic_set_fb_for_plane(primary_state, set->fb);
+	primary_state->crtc_x = 0;
+	primary_state->crtc_y = 0;
+	primary_state->crtc_w = hdisplay;
+	primary_state->crtc_h = vdisplay;
+	primary_state->src_x = set->x << 16;
+	primary_state->src_y = set->y << 16;
+	if (drm_rotation_90_or_270(primary_state->rotation)) {
+		primary_state->src_w = vdisplay << 16;
+		primary_state->src_h = hdisplay << 16;
+	} else {
+		primary_state->src_w = hdisplay << 16;
+		primary_state->src_h = vdisplay << 16;
+	}
+
+commit:
+	ret = update_output_state(state, set);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_set_config);
+
 void drm_atomic_print_state(const struct drm_atomic_state *state)
 {
 	struct drm_printer p = drm_info_printer(state->dev->dev);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 2453678d1186..b0d960da53cb 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2831,95 +2831,6 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane,
 }
 EXPORT_SYMBOL(drm_atomic_helper_disable_plane);
 
-/* just used from fb-helper and atomic-helper: */
-int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
-		struct drm_plane_state *plane_state)
-{
-	int ret;
-
-	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
-	if (ret != 0)
-		return ret;
-
-	drm_atomic_set_fb_for_plane(plane_state, NULL);
-	plane_state->crtc_x = 0;
-	plane_state->crtc_y = 0;
-	plane_state->crtc_w = 0;
-	plane_state->crtc_h = 0;
-	plane_state->src_x = 0;
-	plane_state->src_y = 0;
-	plane_state->src_w = 0;
-	plane_state->src_h = 0;
-
-	return 0;
-}
-
-static int update_output_state(struct drm_atomic_state *state,
-			       struct drm_mode_set *set)
-{
-	struct drm_device *dev = set->crtc->dev;
-	struct drm_crtc *crtc;
-	struct drm_crtc_state *new_crtc_state;
-	struct drm_connector *connector;
-	struct drm_connector_state *new_conn_state;
-	int ret, i;
-
-	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
-			       state->acquire_ctx);
-	if (ret)
-		return ret;
-
-	/* First disable all connectors on the target crtc. */
-	ret = drm_atomic_add_affected_connectors(state, set->crtc);
-	if (ret)
-		return ret;
-
-	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
-		if (new_conn_state->crtc == set->crtc) {
-			ret = drm_atomic_set_crtc_for_connector(new_conn_state,
-								NULL);
-			if (ret)
-				return ret;
-
-			/* Make sure legacy setCrtc always re-trains */
-			new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
-		}
-	}
-
-	/* Then set all connectors from set->connectors on the target crtc */
-	for (i = 0; i < set->num_connectors; i++) {
-		new_conn_state = drm_atomic_get_connector_state(state,
-							    set->connectors[i]);
-		if (IS_ERR(new_conn_state))
-			return PTR_ERR(new_conn_state);
-
-		ret = drm_atomic_set_crtc_for_connector(new_conn_state,
-							set->crtc);
-		if (ret)
-			return ret;
-	}
-
-	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
-		/* Don't update ->enable for the CRTC in the set_config request,
-		 * since a mismatch would indicate a bug in the upper layers.
-		 * The actual modeset code later on will catch any
-		 * inconsistencies here. */
-		if (crtc == set->crtc)
-			continue;
-
-		if (!new_crtc_state->connector_mask) {
-			ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
-								NULL);
-			if (ret < 0)
-				return ret;
-
-			new_crtc_state->active = false;
-		}
-	}
-
-	return 0;
-}
-
 /**
  * drm_atomic_helper_set_config - set a new config from userspace
  * @set: mode set configuration
@@ -2964,81 +2875,6 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set,
 }
 EXPORT_SYMBOL(drm_atomic_helper_set_config);
 
-/* just used from fb-helper and atomic-helper: */
-int __drm_atomic_helper_set_config(struct drm_mode_set *set,
-		struct drm_atomic_state *state)
-{
-	struct drm_crtc_state *crtc_state;
-	struct drm_plane_state *primary_state;
-	struct drm_crtc *crtc = set->crtc;
-	int hdisplay, vdisplay;
-	int ret;
-
-	crtc_state = drm_atomic_get_crtc_state(state, crtc);
-	if (IS_ERR(crtc_state))
-		return PTR_ERR(crtc_state);
-
-	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
-	if (IS_ERR(primary_state))
-		return PTR_ERR(primary_state);
-
-	if (!set->mode) {
-		WARN_ON(set->fb);
-		WARN_ON(set->num_connectors);
-
-		ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
-		if (ret != 0)
-			return ret;
-
-		crtc_state->active = false;
-
-		ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
-		if (ret != 0)
-			return ret;
-
-		drm_atomic_set_fb_for_plane(primary_state, NULL);
-
-		goto commit;
-	}
-
-	WARN_ON(!set->fb);
-	WARN_ON(!set->num_connectors);
-
-	ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
-	if (ret != 0)
-		return ret;
-
-	crtc_state->active = true;
-
-	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
-	if (ret != 0)
-		return ret;
-
-	drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
-
-	drm_atomic_set_fb_for_plane(primary_state, set->fb);
-	primary_state->crtc_x = 0;
-	primary_state->crtc_y = 0;
-	primary_state->crtc_w = hdisplay;
-	primary_state->crtc_h = vdisplay;
-	primary_state->src_x = set->x << 16;
-	primary_state->src_y = set->y << 16;
-	if (drm_rotation_90_or_270(primary_state->rotation)) {
-		primary_state->src_w = vdisplay << 16;
-		primary_state->src_h = hdisplay << 16;
-	} else {
-		primary_state->src_w = hdisplay << 16;
-		primary_state->src_h = vdisplay << 16;
-	}
-
-commit:
-	ret = update_output_state(state, set);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
 static int __drm_atomic_helper_disable_all(struct drm_device *dev,
 					   struct drm_modeset_acquire_ctx *ctx,
 					   bool clean_old_fbs)
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index 216f2a9ee3d4..22a63a544ec7 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -207,6 +207,11 @@ struct drm_minor;
 int drm_atomic_debugfs_init(struct drm_minor *minor);
 #endif
 
+int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
+				      struct drm_plane_state *plane_state);
+int __drm_atomic_helper_set_config(struct drm_mode_set *set,
+				   struct drm_atomic_state *state);
+
 void drm_atomic_print_state(const struct drm_atomic_state *state);
 
 /* drm_atomic_uapi.c */
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 58214be3bf3d..bf4e07141d81 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -117,12 +117,8 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
 				   struct drm_modeset_acquire_ctx *ctx);
 int drm_atomic_helper_disable_plane(struct drm_plane *plane,
 				    struct drm_modeset_acquire_ctx *ctx);
-int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
-		struct drm_plane_state *plane_state);
 int drm_atomic_helper_set_config(struct drm_mode_set *set,
 				 struct drm_modeset_acquire_ctx *ctx);
-int __drm_atomic_helper_set_config(struct drm_mode_set *set,
-		struct drm_atomic_state *state);
 
 int drm_atomic_helper_disable_all(struct drm_device *dev,
 				  struct drm_modeset_acquire_ctx *ctx);
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 04/16] drm/fb-helper: No need to cache rotation and sw_rotations
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (2 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 03/16] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-28  8:03   ` Daniel Vetter
  2019-03-26 17:55 ` [PATCH 05/16] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode} Noralf Trønnes
                   ` (13 subsequent siblings)
  17 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes, mstaudt

Getting rotation info is cheap so we can do it on demand.

This is done in preparation for the removal of struct drm_fb_helper_crtc.

Cc: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---

Hans, 

You had this comment inline in restore_fbdev_mode_atomic() the last time
I sent this out:

  We want plane_state->rotation to be set to DRM_MODE_ROTATE_0 in the else
  case, AFAIK new_plane_state starts with the current state and rotation
  may have a different value there.
  
  Otherwise this looks good to me.

Rotation is reset for each plane in the code section above the one I'm
changing.

Noralf.

 drivers/gpu/drm/drm_fb_helper.c | 131 ++++++++++++++++----------------
 include/drm/drm_fb_helper.h     |   8 --
 2 files changed, 65 insertions(+), 74 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b91df658db59..e1b147fdd3f9 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -387,6 +387,49 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
+/* Check if the plane can hw rotate to match panel orientation */
+static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
+					 unsigned int *rotation)
+{
+	struct drm_connector *connector = modeset->connectors[0];
+	struct drm_plane *plane = modeset->crtc->primary;
+	u64 valid_mask = 0;
+	unsigned int i;
+
+	if (!modeset->num_connectors)
+		return false;
+
+	switch (connector->display_info.panel_orientation) {
+	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
+		*rotation = DRM_MODE_ROTATE_180;
+		break;
+	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
+		*rotation = DRM_MODE_ROTATE_90;
+		break;
+	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
+		*rotation = DRM_MODE_ROTATE_270;
+		break;
+	default:
+		*rotation = DRM_MODE_ROTATE_0;
+	}
+
+	/*
+	 * TODO: support 90 / 270 degree hardware rotation,
+	 * depending on the hardware this may require the framebuffer
+	 * to be in a specific tiling format.
+	 */
+	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
+		return false;
+
+	for (i = 0; i < plane->rotation_property->num_values; i++)
+		valid_mask |= (1ULL << plane->rotation_property->values[i]);
+
+	if (!(*rotation & valid_mask))
+		return false;
+
+	return true;
+}
+
 static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
 {
 	struct drm_device *dev = fb_helper->dev;
@@ -427,10 +470,13 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
 		struct drm_plane *primary = mode_set->crtc->primary;
+		unsigned int rotation;
 
-		/* Cannot fail as we've already gotten the plane state above */
-		plane_state = drm_atomic_get_new_plane_state(state, primary);
-		plane_state->rotation = fb_helper->crtc_info[i].rotation;
+		if (drm_fb_helper_panel_rotation(mode_set, &rotation)) {
+			/* Cannot fail as we've already gotten the plane state above */
+			plane_state = drm_atomic_get_new_plane_state(state, primary);
+			plane_state->rotation = rotation;
+		}
 
 		ret = __drm_atomic_helper_set_config(mode_set, state);
 		if (ret != 0)
@@ -881,7 +927,6 @@ int drm_fb_helper_init(struct drm_device *dev,
 		if (!fb_helper->crtc_info[i].mode_set.connectors)
 			goto out_free;
 		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
-		fb_helper->crtc_info[i].rotation = DRM_MODE_ROTATE_0;
 	}
 
 	i = 0;
@@ -2500,62 +2545,6 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	return best_score;
 }
 
-/*
- * This function checks if rotation is necessary because of panel orientation
- * and if it is, if it is supported.
- * If rotation is necessary and supported, it gets set in fb_crtc.rotation.
- * If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets
- * or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only
- * one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do
- * the unsupported rotation.
- */
-static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
-				    struct drm_fb_helper_crtc *fb_crtc,
-				    struct drm_connector *connector)
-{
-	struct drm_plane *plane = fb_crtc->mode_set.crtc->primary;
-	uint64_t valid_mask = 0;
-	int i, rotation;
-
-	fb_crtc->rotation = DRM_MODE_ROTATE_0;
-
-	switch (connector->display_info.panel_orientation) {
-	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
-		rotation = DRM_MODE_ROTATE_180;
-		break;
-	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
-		rotation = DRM_MODE_ROTATE_90;
-		break;
-	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
-		rotation = DRM_MODE_ROTATE_270;
-		break;
-	default:
-		rotation = DRM_MODE_ROTATE_0;
-	}
-
-	/*
-	 * TODO: support 90 / 270 degree hardware rotation,
-	 * depending on the hardware this may require the framebuffer
-	 * to be in a specific tiling format.
-	 */
-	if (rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property) {
-		fb_helper->sw_rotations |= rotation;
-		return;
-	}
-
-	for (i = 0; i < plane->rotation_property->num_values; i++)
-		valid_mask |= (1ULL << plane->rotation_property->values[i]);
-
-	if (!(rotation & valid_mask)) {
-		fb_helper->sw_rotations |= rotation;
-		return;
-	}
-
-	fb_crtc->rotation = rotation;
-	/* Rotating in hardware, fbcon should not rotate */
-	fb_helper->sw_rotations |= DRM_MODE_ROTATE_0;
-}
-
 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			    u32 width, u32 height)
 {
@@ -2615,7 +2604,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		drm_fb_helper_modeset_release(fb_helper,
 					      &fb_helper->crtc_info[i].mode_set);
 
-	fb_helper->sw_rotations = 0;
 	drm_fb_helper_for_each_connector(fb_helper, i) {
 		struct drm_display_mode *mode = modes[i];
 		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
@@ -2635,7 +2623,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			modeset->mode = drm_mode_duplicate(dev,
 							   fb_crtc->desired_mode);
 			drm_connector_get(connector);
-			drm_setup_crtc_rotation(fb_helper, fb_crtc, connector);
 			modeset->connectors[modeset->num_connectors++] = connector;
 			modeset->x = offset->x;
 			modeset->y = offset->y;
@@ -2658,11 +2645,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 {
 	struct fb_info *info = fb_helper->fbdev;
+	unsigned int rotation, sw_rotations = 0;
 	int i;
 
-	for (i = 0; i < fb_helper->crtc_count; i++)
-		if (fb_helper->crtc_info[i].mode_set.num_connectors)
-			fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
+	for (i = 0; i < fb_helper->crtc_count; i++) {
+		struct drm_mode_set *modeset = &fb_helper->crtc_info[i].mode_set;
+
+		if (!modeset->num_connectors)
+			continue;
+
+		modeset->fb = fb_helper->fb;
+
+		if (drm_fb_helper_panel_rotation(modeset, &rotation))
+			/* Rotating in hardware, fbcon should not rotate */
+			sw_rotations |= DRM_MODE_ROTATE_0;
+		else
+			sw_rotations |= rotation;
+	}
 
 	mutex_lock(&fb_helper->dev->mode_config.mutex);
 	drm_fb_helper_for_each_connector(fb_helper, i) {
@@ -2678,7 +2677,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 	}
 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
-	switch (fb_helper->sw_rotations) {
+	switch (sw_rotations) {
 	case DRM_MODE_ROTATE_0:
 		info->fbcon_rotate_hint = FB_ROTATE_UR;
 		break;
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index bb9acea61369..cff1aa222886 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -50,7 +50,6 @@ struct drm_fb_helper_crtc {
 	struct drm_mode_set mode_set;
 	struct drm_display_mode *desired_mode;
 	int x, y;
-	int rotation;
 };
 
 /**
@@ -175,13 +174,6 @@ struct drm_fb_helper {
 	struct drm_fb_helper_crtc *crtc_info;
 	int connector_count;
 	int connector_info_alloc_count;
-	/**
-	 * @sw_rotations:
-	 * Bitmask of all rotations requested for panel-orientation which
-	 * could not be handled in hardware. If only one bit is set
-	 * fbdev->fbcon_rotate_hint gets set to the requested rotation.
-	 */
-	int sw_rotations;
 	/**
 	 * @connector_info:
 	 *
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 05/16] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode}
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (3 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 04/16] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-28  8:19   ` Daniel Vetter
  2019-03-26 17:55 ` [PATCH 06/16] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper Noralf Trønnes
                   ` (12 subsequent siblings)
  17 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes, mstaudt

The values are already present in the modeset.

This is done in preparation for the removal of struct drm_fb_helper_crtc.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c | 12 ++++--------
 include/drm/drm_fb_helper.h     |  2 --
 2 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index e1b147fdd3f9..36310901e935 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2023,16 +2023,16 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 		 */
 		bool lastv = true, lasth = true;
 
-		desired_mode = fb_helper->crtc_info[i].desired_mode;
 		mode_set = &fb_helper->crtc_info[i].mode_set;
+		desired_mode = mode_set->mode;
 
 		if (!desired_mode)
 			continue;
 
 		crtc_count++;
 
-		x = fb_helper->crtc_info[i].x;
-		y = fb_helper->crtc_info[i].y;
+		x = mode_set->x;
+		y = mode_set->y;
 
 		sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
 		sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
@@ -2617,11 +2617,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
 				      mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
 
-			fb_crtc->desired_mode = mode;
-			fb_crtc->x = offset->x;
-			fb_crtc->y = offset->y;
-			modeset->mode = drm_mode_duplicate(dev,
-							   fb_crtc->desired_mode);
+			modeset->mode = drm_mode_duplicate(dev, mode);
 			drm_connector_get(connector);
 			modeset->connectors[modeset->num_connectors++] = connector;
 			modeset->x = offset->x;
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index cff1aa222886..7a095964f6b2 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -48,8 +48,6 @@ struct drm_fb_offset {
 
 struct drm_fb_helper_crtc {
 	struct drm_mode_set mode_set;
-	struct drm_display_mode *desired_mode;
-	int x, y;
 };
 
 /**
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 06/16] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (4 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 05/16] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode} Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-27 13:33   ` Jani Nikula
  2019-03-26 17:55 ` [PATCH 07/16] drm/fb-helper: Remove drm_fb_helper_crtc Noralf Trønnes
                   ` (11 subsequent siblings)
  17 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: Daniel Vetter, intel-gfx, Noralf Trønnes, mstaudt

It is generic code and having it in the helper will let other drivers
benefit from it.

One change was necessary assuming this to be true:
INTEL_INFO(dev_priv)->num_pipes == dev->mode_config.num_crtc

Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: intel-gfx@lists.freedesktop.org
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c    | 194 ++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_fbdev.c | 218 -----------------------------
 include/drm/drm_fb_helper.h        |  23 ---
 3 files changed, 190 insertions(+), 245 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 36310901e935..634f4dcf0c41 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2545,6 +2545,194 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	return best_score;
 }
 
+static struct drm_fb_helper_crtc *
+drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
+{
+	int i;
+
+	for (i = 0; i < fb_helper->crtc_count; i++)
+		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
+			return &fb_helper->crtc_info[i];
+
+	return NULL;
+}
+
+/* Try to read the BIOS display configuration and use it for the initial config */
+static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
+					  struct drm_fb_helper_crtc **crtcs,
+					  struct drm_display_mode **modes,
+					  struct drm_fb_offset *offsets,
+					  bool *enabled, int width, int height)
+{
+	struct drm_device *dev = fb_helper->dev;
+	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
+	unsigned long conn_configured, conn_seq;
+	int i, j;
+	bool *save_enabled;
+	bool fallback = true, ret = true;
+	int num_connectors_enabled = 0;
+	int num_connectors_detected = 0;
+	struct drm_modeset_acquire_ctx ctx;
+
+	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
+	if (!save_enabled)
+		return false;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
+		drm_modeset_backoff(&ctx);
+
+	memcpy(save_enabled, enabled, count);
+	conn_seq = GENMASK(count - 1, 0);
+	conn_configured = 0;
+retry:
+	for (i = 0; i < count; i++) {
+		struct drm_fb_helper_connector *fb_conn;
+		struct drm_connector *connector;
+		struct drm_encoder *encoder;
+		struct drm_fb_helper_crtc *new_crtc;
+
+		fb_conn = fb_helper->connector_info[i];
+		connector = fb_conn->connector;
+
+		if (conn_configured & BIT(i))
+			continue;
+
+		/* First pass, only consider tiled connectors */
+		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
+			continue;
+
+		if (connector->status == connector_status_connected)
+			num_connectors_detected++;
+
+		if (!enabled[i]) {
+			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
+				      connector->name);
+			conn_configured |= BIT(i);
+			continue;
+		}
+
+		if (connector->force == DRM_FORCE_OFF) {
+			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
+				      connector->name);
+			enabled[i] = false;
+			continue;
+		}
+
+		encoder = connector->state->best_encoder;
+		if (!encoder || WARN_ON(!connector->state->crtc)) {
+			if (connector->force > DRM_FORCE_OFF)
+				goto bail;
+
+			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
+				      connector->name);
+			enabled[i] = false;
+			conn_configured |= BIT(i);
+			continue;
+		}
+
+		num_connectors_enabled++;
+
+		new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
+
+		/*
+		 * Make sure we're not trying to drive multiple connectors
+		 * with a single CRTC, since our cloning support may not
+		 * match the BIOS.
+		 */
+		for (j = 0; j < count; j++) {
+			if (crtcs[j] == new_crtc) {
+				DRM_DEBUG_KMS("fallback: cloned configuration\n");
+				goto bail;
+			}
+		}
+
+		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
+			      connector->name);
+
+		/* go for command line mode first */
+		modes[i] = drm_pick_cmdline_mode(fb_conn);
+
+		/* try for preferred next */
+		if (!modes[i]) {
+			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
+				      connector->name, connector->has_tile);
+			modes[i] = drm_has_preferred_mode(fb_conn, width,
+							  height);
+		}
+
+		/* No preferred mode marked by the EDID? Are there any modes? */
+		if (!modes[i] && !list_empty(&connector->modes)) {
+			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
+				      connector->name);
+			modes[i] = list_first_entry(&connector->modes,
+						    struct drm_display_mode,
+						    head);
+		}
+
+		/* last resort: use current mode */
+		if (!modes[i]) {
+			/*
+			 * IMPORTANT: We want to use the adjusted mode (i.e.
+			 * after the panel fitter upscaling) as the initial
+			 * config, not the input mode, which is what crtc->mode
+			 * usually contains. But since our current
+			 * code puts a mode derived from the post-pfit timings
+			 * into crtc->mode this works out correctly.
+			 *
+			 * This is crtc->mode and not crtc->state->mode for the
+			 * fastboot check to work correctly.
+			 */
+			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
+				      connector->name);
+			modes[i] = &connector->state->crtc->mode;
+		}
+		crtcs[i] = new_crtc;
+
+		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
+			      connector->name,
+			      connector->state->crtc->base.id,
+			      connector->state->crtc->name,
+			      modes[i]->hdisplay, modes[i]->vdisplay,
+			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
+
+		fallback = false;
+		conn_configured |= BIT(i);
+	}
+
+	if (conn_configured != conn_seq) { /* repeat until no more are found */
+		conn_seq = conn_configured;
+		goto retry;
+	}
+
+	/*
+	 * If the BIOS didn't enable everything it could, fall back to have the
+	 * same user experiencing of lighting up as much as possible like the
+	 * fbdev helper library.
+	 */
+	if (num_connectors_enabled != num_connectors_detected &&
+	    num_connectors_enabled < dev->mode_config.num_crtc) {
+		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
+		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
+			      num_connectors_detected);
+		fallback = true;
+	}
+
+	if (fallback) {
+bail:
+		DRM_DEBUG_KMS("Not using firmware configuration\n");
+		memcpy(enabled, save_enabled, count);
+		ret = false;
+	}
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	kfree(save_enabled);
+	return ret;
+}
+
 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			    u32 width, u32 height)
 {
@@ -2577,10 +2765,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
 	drm_enable_connectors(fb_helper, enabled);
 
-	if (!(fb_helper->funcs->initial_config &&
-	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
-					       offsets,
-					       enabled, width, height))) {
+	if (!drm_fb_helper_firmware_config(fb_helper, crtcs, modes, offsets,
+					   enabled, width, height)) {
 		memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
 		memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
 		memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index e8f694b57b8a..20e91600cf71 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -292,225 +292,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
 	return ret;
 }
 
-static struct drm_fb_helper_crtc *
-intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
-{
-	int i;
-
-	for (i = 0; i < fb_helper->crtc_count; i++)
-		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
-			return &fb_helper->crtc_info[i];
-
-	return NULL;
-}
-
-/*
- * Try to read the BIOS display configuration and use it for the initial
- * fb configuration.
- *
- * The BIOS or boot loader will generally create an initial display
- * configuration for us that includes some set of active pipes and displays.
- * This routine tries to figure out which pipes and connectors are active
- * and stuffs them into the crtcs and modes array given to us by the
- * drm_fb_helper code.
- *
- * The overall sequence is:
- *   intel_fbdev_init - from driver load
- *     intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data
- *     drm_fb_helper_init - build fb helper structs
- *     drm_fb_helper_single_add_all_connectors - more fb helper structs
- *   intel_fbdev_initial_config - apply the config
- *     drm_fb_helper_initial_config - call ->probe then register_framebuffer()
- *         drm_setup_crtcs - build crtc config for fbdev
- *           intel_fb_initial_config - find active connectors etc
- *         drm_fb_helper_single_fb_probe - set up fbdev
- *           intelfb_create - re-use or alloc fb, build out fbdev structs
- *
- * Note that we don't make special consideration whether we could actually
- * switch to the selected modes without a full modeset. E.g. when the display
- * is in VGA mode we need to recalculate watermarks and set a new high-res
- * framebuffer anyway.
- */
-static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
-				    struct drm_fb_helper_crtc **crtcs,
-				    struct drm_display_mode **modes,
-				    struct drm_fb_offset *offsets,
-				    bool *enabled, int width, int height)
-{
-	struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
-	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
-	unsigned long conn_configured, conn_seq;
-	int i, j;
-	bool *save_enabled;
-	bool fallback = true, ret = true;
-	int num_connectors_enabled = 0;
-	int num_connectors_detected = 0;
-	struct drm_modeset_acquire_ctx ctx;
-
-	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
-	if (!save_enabled)
-		return false;
-
-	drm_modeset_acquire_init(&ctx, 0);
-
-	while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
-		drm_modeset_backoff(&ctx);
-
-	memcpy(save_enabled, enabled, count);
-	conn_seq = GENMASK(count - 1, 0);
-	conn_configured = 0;
-retry:
-	for (i = 0; i < count; i++) {
-		struct drm_fb_helper_connector *fb_conn;
-		struct drm_connector *connector;
-		struct drm_encoder *encoder;
-		struct drm_fb_helper_crtc *new_crtc;
-
-		fb_conn = fb_helper->connector_info[i];
-		connector = fb_conn->connector;
-
-		if (conn_configured & BIT(i))
-			continue;
-
-		/* First pass, only consider tiled connectors */
-		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
-			continue;
-
-		if (connector->status == connector_status_connected)
-			num_connectors_detected++;
-
-		if (!enabled[i]) {
-			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
-				      connector->name);
-			conn_configured |= BIT(i);
-			continue;
-		}
-
-		if (connector->force == DRM_FORCE_OFF) {
-			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
-				      connector->name);
-			enabled[i] = false;
-			continue;
-		}
-
-		encoder = connector->state->best_encoder;
-		if (!encoder || WARN_ON(!connector->state->crtc)) {
-			if (connector->force > DRM_FORCE_OFF)
-				goto bail;
-
-			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
-				      connector->name);
-			enabled[i] = false;
-			conn_configured |= BIT(i);
-			continue;
-		}
-
-		num_connectors_enabled++;
-
-		new_crtc = intel_fb_helper_crtc(fb_helper,
-						connector->state->crtc);
-
-		/*
-		 * Make sure we're not trying to drive multiple connectors
-		 * with a single CRTC, since our cloning support may not
-		 * match the BIOS.
-		 */
-		for (j = 0; j < count; j++) {
-			if (crtcs[j] == new_crtc) {
-				DRM_DEBUG_KMS("fallback: cloned configuration\n");
-				goto bail;
-			}
-		}
-
-		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
-			      connector->name);
-
-		/* go for command line mode first */
-		modes[i] = drm_pick_cmdline_mode(fb_conn);
-
-		/* try for preferred next */
-		if (!modes[i]) {
-			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
-				      connector->name, connector->has_tile);
-			modes[i] = drm_has_preferred_mode(fb_conn, width,
-							  height);
-		}
-
-		/* No preferred mode marked by the EDID? Are there any modes? */
-		if (!modes[i] && !list_empty(&connector->modes)) {
-			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
-				      connector->name);
-			modes[i] = list_first_entry(&connector->modes,
-						    struct drm_display_mode,
-						    head);
-		}
-
-		/* last resort: use current mode */
-		if (!modes[i]) {
-			/*
-			 * IMPORTANT: We want to use the adjusted mode (i.e.
-			 * after the panel fitter upscaling) as the initial
-			 * config, not the input mode, which is what crtc->mode
-			 * usually contains. But since our current
-			 * code puts a mode derived from the post-pfit timings
-			 * into crtc->mode this works out correctly.
-			 *
-			 * This is crtc->mode and not crtc->state->mode for the
-			 * fastboot check to work correctly. crtc_state->mode has
-			 * I915_MODE_FLAG_INHERITED, which we clear to force check
-			 * state.
-			 */
-			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
-				      connector->name);
-			modes[i] = &connector->state->crtc->mode;
-		}
-		crtcs[i] = new_crtc;
-
-		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
-			      connector->name,
-			      connector->state->crtc->base.id,
-			      connector->state->crtc->name,
-			      modes[i]->hdisplay, modes[i]->vdisplay,
-			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :"");
-
-		fallback = false;
-		conn_configured |= BIT(i);
-	}
-
-	if (conn_configured != conn_seq) { /* repeat until no more are found */
-		conn_seq = conn_configured;
-		goto retry;
-	}
-
-	/*
-	 * If the BIOS didn't enable everything it could, fall back to have the
-	 * same user experiencing of lighting up as much as possible like the
-	 * fbdev helper library.
-	 */
-	if (num_connectors_enabled != num_connectors_detected &&
-	    num_connectors_enabled < INTEL_INFO(dev_priv)->num_pipes) {
-		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
-		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
-			      num_connectors_detected);
-		fallback = true;
-	}
-
-	if (fallback) {
-bail:
-		DRM_DEBUG_KMS("Not using firmware configuration\n");
-		memcpy(enabled, save_enabled, count);
-		ret = false;
-	}
-
-	drm_modeset_drop_locks(&ctx);
-	drm_modeset_acquire_fini(&ctx);
-
-	kfree(save_enabled);
-	return ret;
-}
-
 static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
-	.initial_config = intel_fb_initial_config,
 	.fb_probe = intelfb_create,
 };
 
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 7a095964f6b2..bca4b34dc93b 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -100,29 +100,6 @@ struct drm_fb_helper_funcs {
 	 */
 	int (*fb_probe)(struct drm_fb_helper *helper,
 			struct drm_fb_helper_surface_size *sizes);
-
-	/**
-	 * @initial_config:
-	 *
-	 * Driver callback to setup an initial fbdev display configuration.
-	 * Drivers can use this callback to tell the fbdev emulation what the
-	 * preferred initial configuration is. This is useful to implement
-	 * smooth booting where the fbdev (and subsequently all userspace) never
-	 * changes the mode, but always inherits the existing configuration.
-	 *
-	 * This callback is optional.
-	 *
-	 * RETURNS:
-	 *
-	 * The driver should return true if a suitable initial configuration has
-	 * been filled out and false when the fbdev helper should fall back to
-	 * the default probing logic.
-	 */
-	bool (*initial_config)(struct drm_fb_helper *fb_helper,
-			       struct drm_fb_helper_crtc **crtcs,
-			       struct drm_display_mode **modes,
-			       struct drm_fb_offset *offsets,
-			       bool *enabled, int width, int height);
 };
 
 struct drm_fb_helper_connector {
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 07/16] drm/fb-helper: Remove drm_fb_helper_crtc
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (5 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 06/16] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 08/16] drm/fb-helper: Prepare to move out commit code Noralf Trønnes
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes, mstaudt

It now only contains the modeset so use that directly instead. The modeset
code will be moved to drm_client, so add code there.

The modeset connector array size is hardcoded for the cloned case to avoid
having to pass in a value from the driver. A value of 8 is chosen to err
on the safe side. This means that the max connector argument for
drm_fb_helper_init() and drm_fb_helper_fbdev_setup() isn't used anymore,
a todo entry for this is added.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 Documentation/gpu/todo.rst      |   7 +
 drivers/gpu/drm/drm_client.c    |  93 ++++++++++++
 drivers/gpu/drm/drm_fb_helper.c | 262 +++++++++++---------------------
 include/drm/drm_client.h        |  16 ++
 include/drm/drm_fb_helper.h     |  14 +-
 5 files changed, 207 insertions(+), 185 deletions(-)

diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 1528ad2d598b..8fa08b5feab7 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -300,6 +300,13 @@ it to use drm_mode_hsync() instead.
 
 Contact: Sean Paul
 
+drm_fb_helper cleanup tasks
+---------------------------
+
+- The max connector argument for drm_fb_helper_init() and
+  drm_fb_helper_fbdev_setup() isn't used anymore and can be removed.
+
+
 Core refactorings
 =================
 
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 9b2bd28dde0a..84f848f21679 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -392,6 +392,99 @@ void drm_client_framebuffer_delete(struct drm_client_buffer *buffer)
 }
 EXPORT_SYMBOL(drm_client_framebuffer_delete);
 
+/**
+ * drm_client_modesets_create() - Create modeset array
+ * @dev: DRM device
+ *
+ * This function creates a &drm_mode_set array, one entry per CRTC.
+ *
+ * Returns:
+ * A &drm_mode_set array or an error pointer on allocation failure.
+ */
+struct drm_mode_set *drm_client_modesets_create(struct drm_device *dev)
+{
+	unsigned int num_crtc = dev->mode_config.num_crtc;
+	struct drm_mode_set *modeset, *modesets;
+	unsigned int max_connector_count = 1;
+	struct drm_crtc *crtc;
+	unsigned int i = 0;
+
+	/* Add terminating zero entry to enable index less iteration */
+	modesets = kcalloc(num_crtc + 1, sizeof(*modesets), GFP_KERNEL);
+	if (!modesets)
+		return ERR_PTR(-ENOMEM);
+
+	drm_for_each_crtc(crtc, dev)
+		modesets[i++].crtc = crtc;
+
+	/* Cloning is only supported in the single crtc case. */
+	if (num_crtc == 1)
+		max_connector_count = DRM_CLIENT_MAX_CLONED_CONNECTORS;
+
+	drm_client_for_each_modeset(modeset, modesets) {
+		modeset->connectors = kcalloc(max_connector_count,
+					      sizeof(*modeset->connectors), GFP_KERNEL);
+		if (!modeset->connectors)
+			goto err_free;
+	}
+
+	return modesets;
+
+err_free:
+	drm_client_modesets_release(modesets);
+
+	return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL(drm_client_modesets_create);
+
+/**
+ * drm_client_modesets_release() - Free modesets
+ * @modesets: Modeset array (can be NULL or error pointer)
+ *
+ * This function destroys any attached display modes, puts connectors and frees
+ * the modeset array.
+ */
+void drm_client_modesets_release(struct drm_mode_set *modesets)
+{
+	struct drm_mode_set *modeset;
+	unsigned int i;
+
+	if (IS_ERR_OR_NULL(modesets))
+		return;
+
+	drm_client_for_each_modeset(modeset, modesets) {
+		drm_mode_destroy(modeset->crtc->dev, modeset->mode);
+
+		for (i = 0; i < modeset->num_connectors; i++)
+			drm_connector_put(modeset->connectors[i]);
+		kfree(modeset->connectors);
+	}
+	kfree(modesets);
+}
+EXPORT_SYMBOL(drm_client_modesets_release);
+
+/**
+ * drm_client_find_modeset() - Find modeset matching a CRTC
+ * @modesets: Modeset array
+ * @crtc: CRTC
+ *
+ * This function looks up the modeset connected to @crtc.
+ *
+ * Returns:
+ * A &drm_mode_set or NULL.
+ */
+struct drm_mode_set *drm_client_find_modeset(struct drm_mode_set *modesets, struct drm_crtc *crtc)
+{
+	struct drm_mode_set *modeset;
+
+	drm_client_for_each_modeset(modeset, modesets)
+		if (modeset->crtc == crtc)
+			return modeset;
+
+	return NULL;
+}
+EXPORT_SYMBOL(drm_client_find_modeset);
+
 #ifdef CONFIG_DEBUG_FS
 static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
 {
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 634f4dcf0c41..85bea51e2072 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -316,13 +316,10 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
 {
 	struct drm_fb_helper *helper = info->par;
 	const struct drm_crtc_helper_funcs *funcs;
-	int i;
+	struct drm_mode_set *mode_set;
 
 	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
-		for (i = 0; i < helper->crtc_count; i++) {
-			struct drm_mode_set *mode_set =
-				&helper->crtc_info[i].mode_set;
-
+		drm_client_for_each_modeset(mode_set, helper->modesets) {
 			if (!mode_set->crtc->enabled)
 				continue;
 
@@ -354,12 +351,10 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 	struct drm_fb_helper *helper = info->par;
 	struct drm_crtc *crtc;
 	const struct drm_crtc_helper_funcs *funcs;
+	struct drm_mode_set *mode_set;
 	struct drm_framebuffer *fb;
-	int i;
-
-	for (i = 0; i < helper->crtc_count; i++) {
-		struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
 
+	drm_client_for_each_modeset(mode_set, helper->modesets) {
 		crtc = mode_set->crtc;
 		if (drm_drv_uses_atomic_modeset(crtc->dev))
 			continue;
@@ -436,8 +431,9 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 	struct drm_plane_state *plane_state;
 	struct drm_plane *plane;
 	struct drm_atomic_state *state;
-	int i, ret;
 	struct drm_modeset_acquire_ctx ctx;
+	struct drm_mode_set *mode_set;
+	int ret;
 
 	drm_modeset_acquire_init(&ctx, 0);
 
@@ -467,8 +463,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 			goto out_state;
 	}
 
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+	drm_client_for_each_modeset(mode_set, fb_helper->modesets) {
 		struct drm_plane *primary = mode_set->crtc->primary;
 		unsigned int rotation;
 
@@ -517,8 +512,9 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
 {
 	struct drm_device *dev = fb_helper->dev;
+	struct drm_mode_set *mode_set;
 	struct drm_plane *plane;
-	int i, ret = 0;
+	int ret = 0;
 
 	drm_modeset_lock_all(fb_helper->dev);
 	drm_for_each_plane(plane, dev) {
@@ -531,8 +527,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
 						    DRM_MODE_ROTATE_0);
 	}
 
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+	drm_client_for_each_modeset(mode_set, fb_helper->modesets) {
 		struct drm_crtc *crtc = mode_set->crtc;
 
 		if (crtc->funcs->cursor_set2) {
@@ -687,12 +682,10 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
 	struct drm_device *dev = fb_helper->dev;
 	struct drm_connector *connector;
 	struct drm_mode_set *modeset;
-	int i, j;
+	int j;
 
 	drm_modeset_lock_all(dev);
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		modeset = &fb_helper->crtc_info[i].mode_set;
-
+	drm_client_for_each_modeset(modeset, fb_helper->modesets) {
 		if (!modeset->crtc->enabled)
 			continue;
 
@@ -762,43 +755,6 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_blank);
 
-static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper,
-					  struct drm_mode_set *modeset)
-{
-	int i;
-
-	for (i = 0; i < modeset->num_connectors; i++) {
-		drm_connector_put(modeset->connectors[i]);
-		modeset->connectors[i] = NULL;
-	}
-	modeset->num_connectors = 0;
-
-	drm_mode_destroy(helper->dev, modeset->mode);
-	modeset->mode = NULL;
-
-	/* FIXME should hold a ref? */
-	modeset->fb = NULL;
-}
-
-static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
-{
-	int i;
-
-	for (i = 0; i < helper->connector_count; i++) {
-		drm_connector_put(helper->connector_info[i]->connector);
-		kfree(helper->connector_info[i]);
-	}
-	kfree(helper->connector_info);
-
-	for (i = 0; i < helper->crtc_count; i++) {
-		struct drm_mode_set *modeset = &helper->crtc_info[i].mode_set;
-
-		drm_fb_helper_modeset_release(helper, modeset);
-		kfree(modeset->connectors);
-	}
-	kfree(helper->crtc_info);
-}
-
 static void drm_fb_helper_resume_worker(struct work_struct *work)
 {
 	struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
@@ -877,7 +833,7 @@ EXPORT_SYMBOL(drm_fb_helper_prepare);
  * drm_fb_helper_init - initialize a &struct drm_fb_helper
  * @dev: drm device
  * @fb_helper: driver-allocated fbdev helper structure to initialize
- * @max_conn_count: max connector count
+ * @max_conn_count: max connector count (not used)
  *
  * This allocates the structures for the fbdev helper with the given limits.
  * Note that this won't yet touch the hardware (through the driver interfaces)
@@ -893,53 +849,28 @@ int drm_fb_helper_init(struct drm_device *dev,
 		       struct drm_fb_helper *fb_helper,
 		       int max_conn_count)
 {
-	struct drm_crtc *crtc;
-	struct drm_mode_config *config = &dev->mode_config;
-	int i;
-
 	if (!drm_fbdev_emulation) {
 		dev->fb_helper = fb_helper;
 		return 0;
 	}
 
-	if (!max_conn_count)
-		return -EINVAL;
-
-	fb_helper->crtc_info = kcalloc(config->num_crtc, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
-	if (!fb_helper->crtc_info)
+	fb_helper->modesets = drm_client_modesets_create(dev);
+	if (IS_ERR(fb_helper->modesets))
 		return -ENOMEM;
 
-	fb_helper->crtc_count = config->num_crtc;
 	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
-	if (!fb_helper->connector_info) {
-		kfree(fb_helper->crtc_info);
-		return -ENOMEM;
-	}
+	if (!fb_helper->connector_info)
+		goto out_free;
+
 	fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
 	fb_helper->connector_count = 0;
 
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		fb_helper->crtc_info[i].mode_set.connectors =
-			kcalloc(max_conn_count,
-				sizeof(struct drm_connector *),
-				GFP_KERNEL);
-
-		if (!fb_helper->crtc_info[i].mode_set.connectors)
-			goto out_free;
-		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
-	}
-
-	i = 0;
-	drm_for_each_crtc(crtc, dev) {
-		fb_helper->crtc_info[i].mode_set.crtc = crtc;
-		i++;
-	}
-
 	dev->fb_helper = fb_helper;
 
 	return 0;
 out_free:
-	drm_fb_helper_crtc_free(fb_helper);
+	drm_client_modesets_release(fb_helper->modesets);
+
 	return -ENOMEM;
 }
 EXPORT_SYMBOL(drm_fb_helper_init);
@@ -1014,6 +945,7 @@ EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 {
 	struct fb_info *info;
+	int i;
 
 	if (!fb_helper)
 		return;
@@ -1043,8 +975,13 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 	mutex_unlock(&kernel_fb_helper_lock);
 
 	mutex_destroy(&fb_helper->lock);
-	drm_fb_helper_crtc_free(fb_helper);
+	drm_client_modesets_release(fb_helper->modesets);
 
+	for (i = 0; i < fb_helper->connector_count; i++) {
+		drm_connector_put(fb_helper->connector_info[i]->connector);
+		kfree(fb_helper->connector_info[i]);
+	}
+	kfree(fb_helper->connector_info);
 }
 EXPORT_SYMBOL(drm_fb_helper_fini);
 
@@ -1389,13 +1326,14 @@ static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
 static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
 {
 	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_mode_set *modeset;
 	struct drm_crtc *crtc;
 	u16 *r, *g, *b;
-	int i, ret = 0;
+	int ret = 0;
 
 	drm_modeset_lock_all(fb_helper->dev);
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		crtc = fb_helper->crtc_info[i].mode_set.crtc;
+	drm_client_for_each_modeset(modeset, fb_helper->modesets) {
+		crtc = modeset->crtc;
 		if (!crtc->funcs->gamma_set || !crtc->gamma_size)
 			return -EINVAL;
 
@@ -1471,10 +1409,11 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
 	struct drm_modeset_acquire_ctx ctx;
 	struct drm_crtc_state *crtc_state;
 	struct drm_atomic_state *state;
+	struct drm_mode_set *modeset;
 	struct drm_crtc *crtc;
 	u16 *r, *g, *b;
-	int i, ret = 0;
 	bool replaced;
+	int ret = 0;
 
 	drm_modeset_acquire_init(&ctx, 0);
 
@@ -1486,8 +1425,8 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
 
 	state->acquire_ctx = &ctx;
 retry:
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		crtc = fb_helper->crtc_info[i].mode_set.crtc;
+	drm_client_for_each_modeset(modeset, fb_helper->modesets) {
+		crtc = modeset->crtc;
 
 		if (!gamma_lut)
 			gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
@@ -1515,8 +1454,8 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
 	if (ret)
 		goto out_state;
 
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		crtc = fb_helper->crtc_info[i].mode_set.crtc;
+	drm_client_for_each_modeset(modeset, fb_helper->modesets) {
+		crtc = modeset->crtc;
 
 		r = crtc->gamma_store;
 		g = r + crtc->gamma_size;
@@ -1592,7 +1531,6 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
 	struct drm_fb_helper *fb_helper = info->par;
-	struct drm_mode_set *mode_set;
 	struct drm_crtc *crtc;
 	int ret = 0;
 
@@ -1620,8 +1558,7 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 		 * make. If we're not smart enough here, one should
 		 * just consider switch the userspace to KMS.
 		 */
-		mode_set = &fb_helper->crtc_info[0].mode_set;
-		crtc = mode_set->crtc;
+		crtc = fb_helper->modesets[0].crtc;
 
 		/*
 		 * Only wait for a vblank event if the CRTC is
@@ -1817,13 +1754,9 @@ EXPORT_SYMBOL(drm_fb_helper_set_par);
 
 static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
 {
-	int i;
-
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		struct drm_mode_set *mode_set;
-
-		mode_set = &fb_helper->crtc_info[i].mode_set;
+	struct drm_mode_set *mode_set;
 
+	drm_client_for_each_modeset(mode_set, fb_helper->modesets) {
 		mode_set->x = x;
 		mode_set->y = y;
 	}
@@ -1853,12 +1786,9 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
 	struct drm_fb_helper *fb_helper = info->par;
 	struct drm_mode_set *modeset;
 	int ret = 0;
-	int i;
 
 	drm_modeset_lock_all(fb_helper->dev);
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		modeset = &fb_helper->crtc_info[i].mode_set;
-
+	drm_client_for_each_modeset(modeset, fb_helper->modesets) {
 		modeset->x = var->xoffset;
 		modeset->y = var->yoffset;
 
@@ -1917,6 +1847,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	int crtc_count = 0;
 	int i;
 	struct drm_fb_helper_surface_size sizes;
+	struct drm_mode_set *mode_set;
 	int best_depth = 0;
 
 	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
@@ -1967,13 +1898,12 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	 * supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth
 	 * 16) we need to scale down the depth of the sizes we request.
 	 */
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+	drm_client_for_each_modeset(mode_set, fb_helper->modesets) {
 		struct drm_crtc *crtc = mode_set->crtc;
 		struct drm_plane *plane = crtc->primary;
 		int j;
 
-		DRM_DEBUG("test CRTC %d primary plane\n", i);
+		DRM_DEBUG("test CRTC %u primary plane\n", drm_crtc_index(crtc));
 
 		for (j = 0; j < plane->format_count; j++) {
 			const struct drm_format_info *fmt;
@@ -2013,9 +1943,8 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 
 	/* first up get a count of crtcs now in use and new min/maxes width/heights */
 	crtc_count = 0;
-	for (i = 0; i < fb_helper->crtc_count; i++) {
+	drm_client_for_each_modeset(mode_set, fb_helper->modesets) {
 		struct drm_display_mode *desired_mode;
-		struct drm_mode_set *mode_set;
 		int x, y, j;
 		/* in case of tile group, are we the last tile vert or horiz?
 		 * If no tile group you are always the last one both vertically
@@ -2023,7 +1952,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 		 */
 		bool lastv = true, lasth = true;
 
-		mode_set = &fb_helper->crtc_info[i].mode_set;
 		desired_mode = mode_set->mode;
 
 		if (!desired_mode)
@@ -2282,7 +2210,7 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 	struct drm_display_mode *dmt_mode, *mode;
 
 	/* only contemplate cloning in the single crtc case */
-	if (fb_helper->crtc_count > 1)
+	if (fb_helper->dev->mode_config.num_crtc > 1)
 		return false;
 
 	count = 0;
@@ -2471,15 +2399,17 @@ static bool connector_has_possible_crtc(struct drm_connector *connector,
 }
 
 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
-			  struct drm_fb_helper_crtc **best_crtcs,
+			  struct drm_mode_set *modesets,
+			  struct drm_crtc **best_crtcs,
 			  struct drm_display_mode **modes,
 			  int n, int width, int height)
 {
-	int c, o;
 	struct drm_connector *connector;
 	int my_score, best_score, score;
-	struct drm_fb_helper_crtc **crtcs, *crtc;
+	struct drm_crtc **crtcs, *crtc;
+	struct drm_mode_set *modeset;
 	struct drm_fb_helper_connector *fb_helper_conn;
+	int o;
 
 	if (n == fb_helper->connector_count)
 		return 0;
@@ -2488,12 +2418,11 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	connector = fb_helper_conn->connector;
 
 	best_crtcs[n] = NULL;
-	best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
+	best_score = drm_pick_crtcs(fb_helper, modesets, best_crtcs, modes, n + 1, width, height);
 	if (modes[n] == NULL)
 		return best_score;
 
-	crtcs = kcalloc(fb_helper->connector_count,
-			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
+	crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
 	if (!crtcs)
 		return best_score;
 
@@ -2509,11 +2438,10 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	 * select a crtc for this connector and then attempt to configure
 	 * remaining connectors
 	 */
-	for (c = 0; c < fb_helper->crtc_count; c++) {
-		crtc = &fb_helper->crtc_info[c];
+	drm_client_for_each_modeset(modeset, modesets) {
+		crtc = modeset->crtc;
 
-		if (!connector_has_possible_crtc(connector,
-						 crtc->mode_set.crtc))
+		if (!connector_has_possible_crtc(connector, crtc))
 			continue;
 
 		for (o = 0; o < n; o++)
@@ -2522,7 +2450,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 
 		if (o < n) {
 			/* ignore cloning unless only a single crtc */
-			if (fb_helper->crtc_count > 1)
+			if (fb_helper->dev->mode_config.num_crtc > 1)
 				continue;
 
 			if (!drm_mode_equal(modes[o], modes[n]))
@@ -2530,14 +2458,13 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 		}
 
 		crtcs[n] = crtc;
-		memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
-		score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
+		memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
+		score = my_score + drm_pick_crtcs(fb_helper, modesets, crtcs, modes, n + 1,
 						  width, height);
 		if (score > best_score) {
 			best_score = score;
 			memcpy(best_crtcs, crtcs,
-			       fb_helper->connector_count *
-			       sizeof(struct drm_fb_helper_crtc *));
+			       fb_helper->connector_count * sizeof(*crtcs));
 		}
 	}
 
@@ -2545,21 +2472,9 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	return best_score;
 }
 
-static struct drm_fb_helper_crtc *
-drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
-{
-	int i;
-
-	for (i = 0; i < fb_helper->crtc_count; i++)
-		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
-			return &fb_helper->crtc_info[i];
-
-	return NULL;
-}
-
 /* Try to read the BIOS display configuration and use it for the initial config */
 static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
-					  struct drm_fb_helper_crtc **crtcs,
+					  struct drm_crtc **crtcs,
 					  struct drm_display_mode **modes,
 					  struct drm_fb_offset *offsets,
 					  bool *enabled, int width, int height)
@@ -2591,7 +2506,7 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 		struct drm_fb_helper_connector *fb_conn;
 		struct drm_connector *connector;
 		struct drm_encoder *encoder;
-		struct drm_fb_helper_crtc *new_crtc;
+		struct drm_crtc *new_crtc;
 
 		fb_conn = fb_helper->connector_info[i];
 		connector = fb_conn->connector;
@@ -2634,7 +2549,7 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 
 		num_connectors_enabled++;
 
-		new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
+		new_crtc = connector->state->crtc;
 
 		/*
 		 * Make sure we're not trying to drive multiple connectors
@@ -2737,9 +2652,10 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			    u32 width, u32 height)
 {
 	struct drm_device *dev = fb_helper->dev;
-	struct drm_fb_helper_crtc **crtcs;
 	struct drm_display_mode **modes;
 	struct drm_fb_offset *offsets;
+	struct drm_mode_set *modesets;
+	struct drm_crtc **crtcs;
 	bool *enabled;
 	int i;
 
@@ -2747,15 +2663,15 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	/* prevent concurrent modification of connector_count by hotplug */
 	lockdep_assert_held(&fb_helper->lock);
 
-	crtcs = kcalloc(fb_helper->connector_count,
-			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
+	modesets = drm_client_modesets_create(dev);
+	crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
 	modes = kcalloc(fb_helper->connector_count,
 			sizeof(struct drm_display_mode *), GFP_KERNEL);
 	offsets = kcalloc(fb_helper->connector_count,
 			  sizeof(struct drm_fb_offset), GFP_KERNEL);
 	enabled = kcalloc(fb_helper->connector_count,
 			  sizeof(bool), GFP_KERNEL);
-	if (!crtcs || !modes || !enabled || !offsets) {
+	if (IS_ERR(modesets) || !crtcs || !modes || !enabled || !offsets) {
 		DRM_ERROR("Memory allocation failed\n");
 		goto out;
 	}
@@ -2780,28 +2696,26 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
 			      width, height);
 
-		drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
+		drm_pick_crtcs(fb_helper, modesets, crtcs, modes, 0, width, height);
 	}
 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
-	/* need to set the modesets up here for use later */
-	/* fill out the connector<->crtc mappings into the modesets */
-	for (i = 0; i < fb_helper->crtc_count; i++)
-		drm_fb_helper_modeset_release(fb_helper,
-					      &fb_helper->crtc_info[i].mode_set);
-
 	drm_fb_helper_for_each_connector(fb_helper, i) {
 		struct drm_display_mode *mode = modes[i];
-		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
+		struct drm_crtc *crtc = crtcs[i];
 		struct drm_fb_offset *offset = &offsets[i];
 
-		if (mode && fb_crtc) {
-			struct drm_mode_set *modeset = &fb_crtc->mode_set;
+		if (mode && crtc) {
+			struct drm_mode_set *modeset = drm_client_find_modeset(modesets, crtc);
 			struct drm_connector *connector =
 				fb_helper->connector_info[i]->connector;
 
 			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
-				      mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
+				      mode->name, crtc->base.id, offset->x, offset->y);
+
+			if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
+					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1)))
+				break;
 
 			modeset->mode = drm_mode_duplicate(dev, mode);
 			drm_connector_get(connector);
@@ -2810,11 +2724,14 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			modeset->y = offset->y;
 		}
 	}
+
+	swap(fb_helper->modesets, modesets);
 out:
 	kfree(crtcs);
 	kfree(modes);
 	kfree(offsets);
 	kfree(enabled);
+	drm_client_modesets_release(modesets);
 }
 
 /*
@@ -2828,11 +2745,10 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 {
 	struct fb_info *info = fb_helper->fbdev;
 	unsigned int rotation, sw_rotations = 0;
+	struct drm_mode_set *modeset;
 	int i;
 
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		struct drm_mode_set *modeset = &fb_helper->crtc_info[i].mode_set;
-
+	drm_client_for_each_modeset(modeset, fb_helper->modesets) {
 		if (!modeset->num_connectors)
 			continue;
 
@@ -3058,8 +2974,7 @@ EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
  * @funcs: fbdev helper functions
  * @preferred_bpp: Preferred bits per pixel for the device.
  *                 @dev->mode_config.preferred_depth is used if this is zero.
- * @max_conn_count: Maximum number of connectors.
- *                  @dev->mode_config.num_connector is used if this is zero.
+ * @max_conn_count: Maximum number of connectors (not used)
  *
  * This function sets up fbdev emulation and registers fbdev for access by
  * userspace. If all connectors are disconnected, setup is deferred to the next
@@ -3087,16 +3002,9 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev,
 	if (!preferred_bpp)
 		preferred_bpp = 32;
 
-	if (!max_conn_count)
-		max_conn_count = dev->mode_config.num_connector;
-	if (!max_conn_count) {
-		DRM_DEV_ERROR(dev->dev, "fbdev: No connectors\n");
-		return -EINVAL;
-	}
-
 	drm_fb_helper_prepare(dev, fb_helper, funcs);
 
-	ret = drm_fb_helper_init(dev, fb_helper, max_conn_count);
+	ret = drm_fb_helper_init(dev, fb_helper, 0);
 	if (ret < 0) {
 		DRM_DEV_ERROR(dev->dev, "fbdev: Failed to initialize (ret=%d)\n", ret);
 		return ret;
@@ -3413,7 +3321,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
 
 	drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
 
-	ret = drm_fb_helper_init(dev, fb_helper, dev->mode_config.num_connector);
+	ret = drm_fb_helper_init(dev, fb_helper, 0);
 	if (ret)
 		goto err;
 
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 8b552b1a6ce9..b2efce3f7781 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -5,6 +5,8 @@
 
 #include <linux/types.h>
 
+#include <drm/drm_crtc.h>
+
 struct drm_client_dev;
 struct drm_device;
 struct drm_file;
@@ -13,6 +15,8 @@ struct drm_gem_object;
 struct drm_minor;
 struct module;
 
+#define DRM_CLIENT_MAX_CLONED_CONNECTORS	8
+
 /**
  * struct drm_client_funcs - DRM client callbacks
  */
@@ -135,6 +139,18 @@ struct drm_client_buffer *
 drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format);
 void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
 
+struct drm_mode_set *drm_client_modesets_create(struct drm_device *dev);
+void drm_client_modesets_release(struct drm_mode_set *modesets);
+struct drm_mode_set *drm_client_find_modeset(struct drm_mode_set *modesets, struct drm_crtc *crtc);
+
+/**
+ * drm_client_for_each_modeset() - Iterate over modesets
+ * @modeset: &drm_mode_set loop cursor
+ * @modesets: Modeset array to iterate over
+ */
+#define drm_client_for_each_modeset(modeset, modesets) \
+	for (modeset = modesets; modeset->crtc; modeset++)
+
 int drm_client_debugfs_init(struct drm_minor *minor);
 
 #endif
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index bca4b34dc93b..905697c37c5b 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -46,10 +46,6 @@ struct drm_fb_offset {
 	int x, y;
 };
 
-struct drm_fb_helper_crtc {
-	struct drm_mode_set mode_set;
-};
-
 /**
  * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
  * @fb_width: fbdev width
@@ -110,8 +106,6 @@ struct drm_fb_helper_connector {
  * struct drm_fb_helper - main structure to emulate fbdev on top of KMS
  * @fb: Scanout framebuffer object
  * @dev: DRM device
- * @crtc_count: number of possible CRTCs
- * @crtc_info: per-CRTC helper state (mode, x/y offset, etc)
  * @connector_count: number of connected connectors
  * @connector_info_alloc_count: size of connector_info
  * @funcs: driver callbacks for fb helper
@@ -145,8 +139,12 @@ struct drm_fb_helper {
 
 	struct drm_framebuffer *fb;
 	struct drm_device *dev;
-	int crtc_count;
-	struct drm_fb_helper_crtc *crtc_info;
+
+	/**
+	 * @modesets: CRTC configurations
+	 */
+	struct drm_mode_set *modesets;
+
 	int connector_count;
 	int connector_info_alloc_count;
 	/**
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 08/16] drm/fb-helper: Prepare to move out commit code
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (6 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 07/16] drm/fb-helper: Remove drm_fb_helper_crtc Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 09/16] drm/fb-helper: Move " Noralf Trønnes
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, mstaudt

This makes the necessary changes so the commit code can be moved out to
drm_client as-is in the next patch. It's split up to ease review.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c | 93 +++++++++++++++++++++------------
 1 file changed, 59 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 85bea51e2072..9dcb77dfff0a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -382,9 +382,20 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
-/* Check if the plane can hw rotate to match panel orientation */
-static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
-					 unsigned int *rotation)
+/**
+ * drm_client_panel_rotation() - Check panel orientation
+ * @modeset: DRM modeset
+ * @rotation: Returned rotation value
+ *
+ * This function checks if the primary plane in @modeset can hw rotate to match
+ * the panel orientation on its connector.
+ *
+ * Note: Currently only 0 and 180 degrees are supported.
+ *
+ * Return:
+ * True if the plane can do the rotation, false otherwise.
+ */
+bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
 {
 	struct drm_connector *connector = modeset->connectors[0];
 	struct drm_plane *plane = modeset->crtc->primary;
@@ -425,9 +436,9 @@ static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
 	return true;
 }
 
-static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
+static int drm_client_modesets_commit_atomic(struct drm_device *dev, struct drm_mode_set *modesets,
+					     bool active)
 {
-	struct drm_device *dev = fb_helper->dev;
 	struct drm_plane_state *plane_state;
 	struct drm_plane *plane;
 	struct drm_atomic_state *state;
@@ -463,11 +474,11 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 			goto out_state;
 	}
 
-	drm_client_for_each_modeset(mode_set, fb_helper->modesets) {
+	drm_client_for_each_modeset(mode_set, modesets) {
 		struct drm_plane *primary = mode_set->crtc->primary;
 		unsigned int rotation;
 
-		if (drm_fb_helper_panel_rotation(mode_set, &rotation)) {
+		if (drm_client_panel_rotation(mode_set, &rotation)) {
 			/* Cannot fail as we've already gotten the plane state above */
 			plane_state = drm_atomic_get_new_plane_state(state, primary);
 			plane_state->rotation = rotation;
@@ -509,14 +520,13 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 	goto retry;
 }
 
-static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
+static int drm_client_modesets_commit_legacy(struct drm_device *dev, struct drm_mode_set *modesets)
 {
-	struct drm_device *dev = fb_helper->dev;
 	struct drm_mode_set *mode_set;
 	struct drm_plane *plane;
 	int ret = 0;
 
-	drm_modeset_lock_all(fb_helper->dev);
+	drm_modeset_lock_all(dev);
 	drm_for_each_plane(plane, dev) {
 		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
 			drm_plane_force_disable(plane);
@@ -527,7 +537,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
 						    DRM_MODE_ROTATE_0);
 	}
 
-	drm_client_for_each_modeset(mode_set, fb_helper->modesets) {
+	drm_client_for_each_modeset(mode_set, modesets) {
 		struct drm_crtc *crtc = mode_set->crtc;
 
 		if (crtc->funcs->cursor_set2) {
@@ -545,19 +555,25 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
 			goto out;
 	}
 out:
-	drm_modeset_unlock_all(fb_helper->dev);
+	drm_modeset_unlock_all(dev);
 
 	return ret;
 }
 
-static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
+/**
+ * drm_client_modesets_commit() - Commit CRTC configuration
+ * @dev: DRM device
+ * @modesets: Modeset array
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modesets_commit(struct drm_device *dev, struct drm_mode_set *modesets)
 {
-	struct drm_device *dev = fb_helper->dev;
-
 	if (drm_drv_uses_atomic_modeset(dev))
-		return restore_fbdev_mode_atomic(fb_helper, true);
+		return drm_client_modesets_commit_atomic(dev, modesets, true);
 	else
-		return restore_fbdev_mode_legacy(fb_helper);
+		return drm_client_modesets_commit_legacy(dev, modesets);
 }
 
 /**
@@ -583,7 +599,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
 		return 0;
 
 	mutex_lock(&fb_helper->lock);
-	ret = restore_fbdev_mode(fb_helper);
+	ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
 
 	do_delayed = fb_helper->delayed_hotplug;
 	if (do_delayed)
@@ -645,7 +661,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
 			continue;
 
 		mutex_lock(&helper->lock);
-		ret = restore_fbdev_mode(helper);
+		ret = drm_client_modesets_commit(dev, helper->modesets);
 		if (ret)
 			error = true;
 		mutex_unlock(&helper->lock);
@@ -677,15 +693,15 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 #endif
 
-static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
+static void drm_client_modesets_dpms_legacy(struct drm_device *dev, struct drm_mode_set *modesets,
+					    int dpms_mode)
 {
-	struct drm_device *dev = fb_helper->dev;
 	struct drm_connector *connector;
 	struct drm_mode_set *modeset;
 	int j;
 
 	drm_modeset_lock_all(dev);
-	drm_client_for_each_modeset(modeset, fb_helper->modesets) {
+	drm_client_for_each_modeset(modeset, modesets) {
 		if (!modeset->crtc->enabled)
 			continue;
 
@@ -699,6 +715,22 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
 	drm_modeset_unlock_all(dev);
 }
 
+/**
+ * drm_client_modesets_dpms() - Set DPMS mode
+ * @dev: DRM device
+ * @modesets: Modeset array
+ * @mode: DPMS mode
+ *
+ * Note: For atomic drivers @mode is reduced to on/off.
+ */
+void drm_client_modesets_dpms(struct drm_device *dev, struct drm_mode_set *modesets, int mode)
+{
+	if (drm_drv_uses_atomic_modeset(dev))
+		drm_client_modesets_commit_atomic(dev, modesets, mode == DRM_MODE_DPMS_ON);
+	else
+		drm_client_modesets_dpms_legacy(dev, modesets, mode);
+}
+
 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 {
 	struct drm_fb_helper *fb_helper = info->par;
@@ -707,15 +739,8 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 	 * For each CRTC in this fb, turn the connectors on/off.
 	 */
 	mutex_lock(&fb_helper->lock);
-	if (!drm_fb_helper_is_bound(fb_helper)) {
-		mutex_unlock(&fb_helper->lock);
-		return;
-	}
-
-	if (drm_drv_uses_atomic_modeset(fb_helper->dev))
-		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
-	else
-		dpms_legacy(fb_helper, dpms_mode);
+	if (drm_fb_helper_is_bound(fb_helper))
+		drm_client_modesets_dpms(fb_helper->dev, fb_helper->modesets, dpms_mode);
 	mutex_unlock(&fb_helper->lock);
 }
 
@@ -1770,7 +1795,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
 
 	pan_set(fb_helper, var->xoffset, var->yoffset);
 
-	ret = restore_fbdev_mode_atomic(fb_helper, true);
+	ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
 	if (!ret) {
 		info->var.xoffset = var->xoffset;
 		info->var.yoffset = var->yoffset;
@@ -1987,7 +2012,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 
 		/* First time: disable all crtc's.. */
 		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
-			restore_fbdev_mode(fb_helper);
+			drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
 		return -EAGAIN;
 	}
 
@@ -2754,7 +2779,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 
 		modeset->fb = fb_helper->fb;
 
-		if (drm_fb_helper_panel_rotation(modeset, &rotation))
+		if (drm_client_panel_rotation(modeset, &rotation))
 			/* Rotating in hardware, fbcon should not rotate */
 			sw_rotations |= DRM_MODE_ROTATE_0;
 		else
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 09/16] drm/fb-helper: Move out commit code
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (7 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 08/16] drm/fb-helper: Prepare to move out commit code Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-27 14:13   ` Emmanuel Vadot
  2019-03-26 17:55 ` [PATCH 10/16] drm/fb-helper: Remove drm_fb_helper_connector Noralf Trønnes
                   ` (8 subsequent siblings)
  17 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, mstaudt

Move the modeset commit code to drm_client.
No changes except exporting API.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_client.c    | 236 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_fb_helper.c | 232 -------------------------------
 include/drm/drm_client.h        |   3 +
 3 files changed, 239 insertions(+), 232 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 84f848f21679..5b199c051960 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -9,6 +9,7 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_client.h>
 #include <drm/drm_debugfs.h>
 #include <drm/drm_device.h>
@@ -485,6 +486,241 @@ struct drm_mode_set *drm_client_find_modeset(struct drm_mode_set *modesets, stru
 }
 EXPORT_SYMBOL(drm_client_find_modeset);
 
+/**
+ * drm_client_panel_rotation() - Check panel orientation
+ * @modeset: DRM modeset
+ * @rotation: Returned rotation value
+ *
+ * This function checks if the primary plane in @modeset can hw rotate to match
+ * the panel orientation on its connector.
+ *
+ * Note: Currently only 0 and 180 degrees are supported.
+ *
+ * Return:
+ * True if the plane can do the rotation, false otherwise.
+ */
+bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
+{
+	struct drm_connector *connector = modeset->connectors[0];
+	struct drm_plane *plane = modeset->crtc->primary;
+	u64 valid_mask = 0;
+	unsigned int i;
+
+	if (!modeset->num_connectors)
+		return false;
+
+	switch (connector->display_info.panel_orientation) {
+	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
+		*rotation = DRM_MODE_ROTATE_180;
+		break;
+	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
+		*rotation = DRM_MODE_ROTATE_90;
+		break;
+	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
+		*rotation = DRM_MODE_ROTATE_270;
+		break;
+	default:
+		*rotation = DRM_MODE_ROTATE_0;
+	}
+
+	/*
+	 * TODO: support 90 / 270 degree hardware rotation,
+	 * depending on the hardware this may require the framebuffer
+	 * to be in a specific tiling format.
+	 */
+	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
+		return false;
+
+	for (i = 0; i < plane->rotation_property->num_values; i++)
+		valid_mask |= (1ULL << plane->rotation_property->values[i]);
+
+	if (!(*rotation & valid_mask))
+		return false;
+
+	return true;
+}
+EXPORT_SYMBOL(drm_client_panel_rotation);
+
+static int drm_client_modesets_commit_atomic(struct drm_device *dev, struct drm_mode_set *modesets,
+					     bool active)
+{
+	struct drm_plane_state *plane_state;
+	struct drm_plane *plane;
+	struct drm_atomic_state *state;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_mode_set *mode_set;
+	int ret;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state) {
+		ret = -ENOMEM;
+		goto out_ctx;
+	}
+
+	state->acquire_ctx = &ctx;
+retry:
+	drm_for_each_plane(plane, dev) {
+		plane_state = drm_atomic_get_plane_state(state, plane);
+		if (IS_ERR(plane_state)) {
+			ret = PTR_ERR(plane_state);
+			goto out_state;
+		}
+
+		plane_state->rotation = DRM_MODE_ROTATE_0;
+
+		/* disable non-primary: */
+		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+			continue;
+
+		ret = __drm_atomic_helper_disable_plane(plane, plane_state);
+		if (ret != 0)
+			goto out_state;
+	}
+
+	drm_client_for_each_modeset(mode_set, modesets) {
+		struct drm_plane *primary = mode_set->crtc->primary;
+		unsigned int rotation;
+
+		if (drm_client_panel_rotation(mode_set, &rotation)) {
+			/* Cannot fail as we've already gotten the plane state above */
+			plane_state = drm_atomic_get_new_plane_state(state, primary);
+			plane_state->rotation = rotation;
+		}
+
+		ret = __drm_atomic_helper_set_config(mode_set, state);
+		if (ret != 0)
+			goto out_state;
+
+		/*
+		 * __drm_atomic_helper_set_config() sets active when a
+		 * mode is set, unconditionally clear it if we force DPMS off
+		 */
+		if (!active) {
+			struct drm_crtc *crtc = mode_set->crtc;
+			struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+
+			crtc_state->active = false;
+		}
+	}
+
+	ret = drm_atomic_commit(state);
+
+out_state:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_put(state);
+out_ctx:
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	return ret;
+
+backoff:
+	drm_atomic_state_clear(state);
+	drm_modeset_backoff(&ctx);
+
+	goto retry;
+}
+
+static int drm_client_modesets_commit_legacy(struct drm_device *dev, struct drm_mode_set *modesets)
+{
+	struct drm_mode_set *mode_set;
+	struct drm_plane *plane;
+	int ret = 0;
+
+	drm_modeset_lock_all(dev);
+	drm_for_each_plane(plane, dev) {
+		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
+			drm_plane_force_disable(plane);
+
+		if (plane->rotation_property)
+			drm_mode_plane_set_obj_prop(plane,
+						    plane->rotation_property,
+						    DRM_MODE_ROTATE_0);
+	}
+
+	drm_client_for_each_modeset(mode_set, modesets) {
+		struct drm_crtc *crtc = mode_set->crtc;
+
+		if (crtc->funcs->cursor_set2) {
+			ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);
+			if (ret)
+				goto out;
+		} else if (crtc->funcs->cursor_set) {
+			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
+			if (ret)
+				goto out;
+		}
+
+		ret = drm_mode_set_config_internal(mode_set);
+		if (ret)
+			goto out;
+	}
+out:
+	drm_modeset_unlock_all(dev);
+
+	return ret;
+}
+
+/**
+ * drm_client_modesets_commit() - Commit CRTC configuration
+ * @dev: DRM device
+ * @modesets: Modeset array
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modesets_commit(struct drm_device *dev, struct drm_mode_set *modesets)
+{
+	if (drm_drv_uses_atomic_modeset(dev))
+		return drm_client_modesets_commit_atomic(dev, modesets, true);
+	else
+		return drm_client_modesets_commit_legacy(dev, modesets);
+}
+EXPORT_SYMBOL(drm_client_modesets_commit);
+
+static void drm_client_modesets_dpms_legacy(struct drm_device *dev, struct drm_mode_set *modesets,
+					    int dpms_mode)
+{
+	struct drm_connector *connector;
+	struct drm_mode_set *modeset;
+	int j;
+
+	drm_modeset_lock_all(dev);
+	drm_client_for_each_modeset(modeset, modesets) {
+		if (!modeset->crtc->enabled)
+			continue;
+
+		for (j = 0; j < modeset->num_connectors; j++) {
+			connector = modeset->connectors[j];
+			connector->funcs->dpms(connector, dpms_mode);
+			drm_object_property_set_value(&connector->base,
+				dev->mode_config.dpms_property, dpms_mode);
+		}
+	}
+	drm_modeset_unlock_all(dev);
+}
+
+/**
+ * drm_client_modesets_dpms() - Set DPMS mode
+ * @dev: DRM device
+ * @modesets: Modeset array
+ * @mode: DPMS mode
+ *
+ * Note: For atomic drivers @mode is reduced to on/off.
+ */
+void drm_client_modesets_dpms(struct drm_device *dev, struct drm_mode_set *modesets, int mode)
+{
+	if (drm_drv_uses_atomic_modeset(dev))
+		drm_client_modesets_commit_atomic(dev, modesets, mode == DRM_MODE_DPMS_ON);
+	else
+		drm_client_modesets_dpms_legacy(dev, modesets, mode);
+}
+EXPORT_SYMBOL(drm_client_modesets_dpms);
+
 #ifdef CONFIG_DEBUG_FS
 static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
 {
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 9dcb77dfff0a..be946d702019 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -382,200 +382,6 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
-/**
- * drm_client_panel_rotation() - Check panel orientation
- * @modeset: DRM modeset
- * @rotation: Returned rotation value
- *
- * This function checks if the primary plane in @modeset can hw rotate to match
- * the panel orientation on its connector.
- *
- * Note: Currently only 0 and 180 degrees are supported.
- *
- * Return:
- * True if the plane can do the rotation, false otherwise.
- */
-bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
-{
-	struct drm_connector *connector = modeset->connectors[0];
-	struct drm_plane *plane = modeset->crtc->primary;
-	u64 valid_mask = 0;
-	unsigned int i;
-
-	if (!modeset->num_connectors)
-		return false;
-
-	switch (connector->display_info.panel_orientation) {
-	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
-		*rotation = DRM_MODE_ROTATE_180;
-		break;
-	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
-		*rotation = DRM_MODE_ROTATE_90;
-		break;
-	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
-		*rotation = DRM_MODE_ROTATE_270;
-		break;
-	default:
-		*rotation = DRM_MODE_ROTATE_0;
-	}
-
-	/*
-	 * TODO: support 90 / 270 degree hardware rotation,
-	 * depending on the hardware this may require the framebuffer
-	 * to be in a specific tiling format.
-	 */
-	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
-		return false;
-
-	for (i = 0; i < plane->rotation_property->num_values; i++)
-		valid_mask |= (1ULL << plane->rotation_property->values[i]);
-
-	if (!(*rotation & valid_mask))
-		return false;
-
-	return true;
-}
-
-static int drm_client_modesets_commit_atomic(struct drm_device *dev, struct drm_mode_set *modesets,
-					     bool active)
-{
-	struct drm_plane_state *plane_state;
-	struct drm_plane *plane;
-	struct drm_atomic_state *state;
-	struct drm_modeset_acquire_ctx ctx;
-	struct drm_mode_set *mode_set;
-	int ret;
-
-	drm_modeset_acquire_init(&ctx, 0);
-
-	state = drm_atomic_state_alloc(dev);
-	if (!state) {
-		ret = -ENOMEM;
-		goto out_ctx;
-	}
-
-	state->acquire_ctx = &ctx;
-retry:
-	drm_for_each_plane(plane, dev) {
-		plane_state = drm_atomic_get_plane_state(state, plane);
-		if (IS_ERR(plane_state)) {
-			ret = PTR_ERR(plane_state);
-			goto out_state;
-		}
-
-		plane_state->rotation = DRM_MODE_ROTATE_0;
-
-		/* disable non-primary: */
-		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
-			continue;
-
-		ret = __drm_atomic_helper_disable_plane(plane, plane_state);
-		if (ret != 0)
-			goto out_state;
-	}
-
-	drm_client_for_each_modeset(mode_set, modesets) {
-		struct drm_plane *primary = mode_set->crtc->primary;
-		unsigned int rotation;
-
-		if (drm_client_panel_rotation(mode_set, &rotation)) {
-			/* Cannot fail as we've already gotten the plane state above */
-			plane_state = drm_atomic_get_new_plane_state(state, primary);
-			plane_state->rotation = rotation;
-		}
-
-		ret = __drm_atomic_helper_set_config(mode_set, state);
-		if (ret != 0)
-			goto out_state;
-
-		/*
-		 * __drm_atomic_helper_set_config() sets active when a
-		 * mode is set, unconditionally clear it if we force DPMS off
-		 */
-		if (!active) {
-			struct drm_crtc *crtc = mode_set->crtc;
-			struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
-
-			crtc_state->active = false;
-		}
-	}
-
-	ret = drm_atomic_commit(state);
-
-out_state:
-	if (ret == -EDEADLK)
-		goto backoff;
-
-	drm_atomic_state_put(state);
-out_ctx:
-	drm_modeset_drop_locks(&ctx);
-	drm_modeset_acquire_fini(&ctx);
-
-	return ret;
-
-backoff:
-	drm_atomic_state_clear(state);
-	drm_modeset_backoff(&ctx);
-
-	goto retry;
-}
-
-static int drm_client_modesets_commit_legacy(struct drm_device *dev, struct drm_mode_set *modesets)
-{
-	struct drm_mode_set *mode_set;
-	struct drm_plane *plane;
-	int ret = 0;
-
-	drm_modeset_lock_all(dev);
-	drm_for_each_plane(plane, dev) {
-		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
-			drm_plane_force_disable(plane);
-
-		if (plane->rotation_property)
-			drm_mode_plane_set_obj_prop(plane,
-						    plane->rotation_property,
-						    DRM_MODE_ROTATE_0);
-	}
-
-	drm_client_for_each_modeset(mode_set, modesets) {
-		struct drm_crtc *crtc = mode_set->crtc;
-
-		if (crtc->funcs->cursor_set2) {
-			ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);
-			if (ret)
-				goto out;
-		} else if (crtc->funcs->cursor_set) {
-			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
-			if (ret)
-				goto out;
-		}
-
-		ret = drm_mode_set_config_internal(mode_set);
-		if (ret)
-			goto out;
-	}
-out:
-	drm_modeset_unlock_all(dev);
-
-	return ret;
-}
-
-/**
- * drm_client_modesets_commit() - Commit CRTC configuration
- * @dev: DRM device
- * @modesets: Modeset array
- *
- * Returns:
- * Zero on success or negative error code on failure.
- */
-int drm_client_modesets_commit(struct drm_device *dev, struct drm_mode_set *modesets)
-{
-	if (drm_drv_uses_atomic_modeset(dev))
-		return drm_client_modesets_commit_atomic(dev, modesets, true);
-	else
-		return drm_client_modesets_commit_legacy(dev, modesets);
-}
-
 /**
  * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
  * @fb_helper: driver-allocated fbdev helper, can be NULL
@@ -693,44 +499,6 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 #endif
 
-static void drm_client_modesets_dpms_legacy(struct drm_device *dev, struct drm_mode_set *modesets,
-					    int dpms_mode)
-{
-	struct drm_connector *connector;
-	struct drm_mode_set *modeset;
-	int j;
-
-	drm_modeset_lock_all(dev);
-	drm_client_for_each_modeset(modeset, modesets) {
-		if (!modeset->crtc->enabled)
-			continue;
-
-		for (j = 0; j < modeset->num_connectors; j++) {
-			connector = modeset->connectors[j];
-			connector->funcs->dpms(connector, dpms_mode);
-			drm_object_property_set_value(&connector->base,
-				dev->mode_config.dpms_property, dpms_mode);
-		}
-	}
-	drm_modeset_unlock_all(dev);
-}
-
-/**
- * drm_client_modesets_dpms() - Set DPMS mode
- * @dev: DRM device
- * @modesets: Modeset array
- * @mode: DPMS mode
- *
- * Note: For atomic drivers @mode is reduced to on/off.
- */
-void drm_client_modesets_dpms(struct drm_device *dev, struct drm_mode_set *modesets, int mode)
-{
-	if (drm_drv_uses_atomic_modeset(dev))
-		drm_client_modesets_commit_atomic(dev, modesets, mode == DRM_MODE_DPMS_ON);
-	else
-		drm_client_modesets_dpms_legacy(dev, modesets, mode);
-}
-
 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 {
 	struct drm_fb_helper *fb_helper = info->par;
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index b2efce3f7781..01e787f8bc12 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -142,6 +142,9 @@ void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
 struct drm_mode_set *drm_client_modesets_create(struct drm_device *dev);
 void drm_client_modesets_release(struct drm_mode_set *modesets);
 struct drm_mode_set *drm_client_find_modeset(struct drm_mode_set *modesets, struct drm_crtc *crtc);
+bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
+int drm_client_modesets_commit(struct drm_device *dev, struct drm_mode_set *modesets);
+void drm_client_modesets_dpms(struct drm_device *dev, struct drm_mode_set *modesets, int mode);
 
 /**
  * drm_client_for_each_modeset() - Iterate over modesets
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 10/16] drm/fb-helper: Remove drm_fb_helper_connector
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (8 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 09/16] drm/fb-helper: Move " Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 11/16] drm/fb-helper: Prepare to move out modeset config code Noralf Trønnes
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes, mstaudt

All drivers add all their connectors so there's no need to keep around an
array of available connectors.

Rename functions which signature is changed since they will be moved to
drm_client in a later patch.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---

checkpatch complains, but I'm unable to satisfy it:

ERROR: Macros with complex values should be enclosed in parentheses
#939: FILE: include/drm/drm_client.h:160:
+#define drm_client_for_each_connector_iter(connector, iter) \
+       drm_for_each_connector_iter(connector, iter) \
+               if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)


 Documentation/gpu/todo.rst      |   3 +
 drivers/gpu/drm/drm_fb_helper.c | 499 ++++++++++----------------------
 include/drm/drm_client.h        |  15 +
 include/drm/drm_fb_helper.h     |  80 ++---
 4 files changed, 194 insertions(+), 403 deletions(-)

diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 8fa08b5feab7..f6cdd1c26788 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -306,6 +306,9 @@ drm_fb_helper cleanup tasks
 - The max connector argument for drm_fb_helper_init() and
   drm_fb_helper_fbdev_setup() isn't used anymore and can be removed.
 
+- The helper doesn't keep an array of connectors anymore so these can be
+  removed: drm_fb_helper_single_add_all_connectors(),
+  drm_fb_helper_add_one_connector() and drm_fb_helper_remove_one_connector().
 
 Core refactorings
 =================
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index be946d702019..de805956849d 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -92,12 +92,6 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
  * Setup fbdev emulation by calling drm_fb_helper_fbdev_setup() and tear it
  * down by calling drm_fb_helper_fbdev_teardown().
  *
- * Drivers that need to handle connector hotplugging (e.g. dp mst) can't use
- * the setup helper and will need to do the whole four-step setup process with
- * drm_fb_helper_prepare(), drm_fb_helper_init(),
- * drm_fb_helper_single_add_all_connectors(), enable hotplugging and
- * drm_fb_helper_initial_config() to avoid a possible race window.
- *
  * At runtime drivers should restore the fbdev console by using
  * drm_fb_helper_lastclose() as their &drm_driver.lastclose callback.
  * They should also notify the fb helper code from updates to the output
@@ -120,8 +114,7 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
  * encoders and connectors. To finish up the fbdev helper initialization, the
  * drm_fb_helper_init() function is called. To probe for all attached displays
  * and set up an initial configuration using the detected hardware, drivers
- * should call drm_fb_helper_single_add_all_connectors() followed by
- * drm_fb_helper_initial_config().
+ * should call drm_fb_helper_initial_config().
  *
  * If &drm_framebuffer_funcs.dirty is set, the
  * drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit} functions will
@@ -134,165 +127,6 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
  * deferred I/O (coupled with drm_fb_helper_fbdev_teardown()).
  */
 
-#define drm_fb_helper_for_each_connector(fbh, i__) \
-	for (({ lockdep_assert_held(&(fbh)->lock); }), \
-	     i__ = 0; i__ < (fbh)->connector_count; i__++)
-
-static int __drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
-					     struct drm_connector *connector)
-{
-	struct drm_fb_helper_connector *fb_conn;
-	struct drm_fb_helper_connector **temp;
-	unsigned int count;
-
-	if (!drm_fbdev_emulation)
-		return 0;
-
-	lockdep_assert_held(&fb_helper->lock);
-
-	count = fb_helper->connector_count + 1;
-
-	if (count > fb_helper->connector_info_alloc_count) {
-		size_t size = count * sizeof(fb_conn);
-
-		temp = krealloc(fb_helper->connector_info, size, GFP_KERNEL);
-		if (!temp)
-			return -ENOMEM;
-
-		fb_helper->connector_info_alloc_count = count;
-		fb_helper->connector_info = temp;
-	}
-
-	fb_conn = kzalloc(sizeof(*fb_conn), GFP_KERNEL);
-	if (!fb_conn)
-		return -ENOMEM;
-
-	drm_connector_get(connector);
-	fb_conn->connector = connector;
-	fb_helper->connector_info[fb_helper->connector_count++] = fb_conn;
-
-	return 0;
-}
-
-int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
-				    struct drm_connector *connector)
-{
-	int err;
-
-	if (!fb_helper)
-		return 0;
-
-	mutex_lock(&fb_helper->lock);
-	err = __drm_fb_helper_add_one_connector(fb_helper, connector);
-	mutex_unlock(&fb_helper->lock);
-
-	return err;
-}
-EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
-
-/**
- * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev
- * 					       emulation helper
- * @fb_helper: fbdev initialized with drm_fb_helper_init, can be NULL
- *
- * This functions adds all the available connectors for use with the given
- * fb_helper. This is a separate step to allow drivers to freely assign
- * connectors to the fbdev, e.g. if some are reserved for special purposes or
- * not adequate to be used for the fbcon.
- *
- * This function is protected against concurrent connector hotadds/removals
- * using drm_fb_helper_add_one_connector() and
- * drm_fb_helper_remove_one_connector().
- */
-int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
-{
-	struct drm_device *dev;
-	struct drm_connector *connector;
-	struct drm_connector_list_iter conn_iter;
-	int i, ret = 0;
-
-	if (!drm_fbdev_emulation || !fb_helper)
-		return 0;
-
-	dev = fb_helper->dev;
-
-	mutex_lock(&fb_helper->lock);
-	drm_connector_list_iter_begin(dev, &conn_iter);
-	drm_for_each_connector_iter(connector, &conn_iter) {
-		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
-			continue;
-
-		ret = __drm_fb_helper_add_one_connector(fb_helper, connector);
-		if (ret)
-			goto fail;
-	}
-	goto out;
-
-fail:
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		struct drm_fb_helper_connector *fb_helper_connector =
-			fb_helper->connector_info[i];
-
-		drm_connector_put(fb_helper_connector->connector);
-
-		kfree(fb_helper_connector);
-		fb_helper->connector_info[i] = NULL;
-	}
-	fb_helper->connector_count = 0;
-out:
-	drm_connector_list_iter_end(&conn_iter);
-	mutex_unlock(&fb_helper->lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
-
-static int __drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
-						struct drm_connector *connector)
-{
-	struct drm_fb_helper_connector *fb_helper_connector;
-	int i, j;
-
-	if (!drm_fbdev_emulation)
-		return 0;
-
-	lockdep_assert_held(&fb_helper->lock);
-
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		if (fb_helper->connector_info[i]->connector == connector)
-			break;
-	}
-
-	if (i == fb_helper->connector_count)
-		return -EINVAL;
-	fb_helper_connector = fb_helper->connector_info[i];
-	drm_connector_put(fb_helper_connector->connector);
-
-	for (j = i + 1; j < fb_helper->connector_count; j++)
-		fb_helper->connector_info[j - 1] = fb_helper->connector_info[j];
-
-	fb_helper->connector_count--;
-	kfree(fb_helper_connector);
-
-	return 0;
-}
-
-int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
-				       struct drm_connector *connector)
-{
-	int err;
-
-	if (!fb_helper)
-		return 0;
-
-	mutex_lock(&fb_helper->lock);
-	err = __drm_fb_helper_remove_one_connector(fb_helper, connector);
-	mutex_unlock(&fb_helper->lock);
-
-	return err;
-}
-EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
-
 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
 {
 	uint16_t *r_base, *g_base, *b_base;
@@ -651,20 +485,9 @@ int drm_fb_helper_init(struct drm_device *dev,
 	if (IS_ERR(fb_helper->modesets))
 		return -ENOMEM;
 
-	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
-	if (!fb_helper->connector_info)
-		goto out_free;
-
-	fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
-	fb_helper->connector_count = 0;
-
 	dev->fb_helper = fb_helper;
 
 	return 0;
-out_free:
-	drm_client_modesets_release(fb_helper->modesets);
-
-	return -ENOMEM;
 }
 EXPORT_SYMBOL(drm_fb_helper_init);
 
@@ -738,7 +561,6 @@ EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 {
 	struct fb_info *info;
-	int i;
 
 	if (!fb_helper)
 		return;
@@ -769,12 +591,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 
 	mutex_destroy(&fb_helper->lock);
 	drm_client_modesets_release(fb_helper->modesets);
-
-	for (i = 0; i < fb_helper->connector_count; i++) {
-		drm_connector_put(fb_helper->connector_info[i]->connector);
-		kfree(fb_helper->connector_info[i]);
-	}
-	kfree(fb_helper->connector_info);
 }
 EXPORT_SYMBOL(drm_fb_helper_fini);
 
@@ -1638,8 +1454,9 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 {
 	int ret = 0;
 	int crtc_count = 0;
-	int i;
+	struct drm_connector_list_iter conn_iter;
 	struct drm_fb_helper_surface_size sizes;
+	struct drm_connector *connector;
 	struct drm_mode_set *mode_set;
 	int best_depth = 0;
 
@@ -1656,11 +1473,11 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	if (preferred_bpp != sizes.surface_bpp)
 		sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
+	drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
+	drm_client_for_each_connector_iter(connector, &conn_iter) {
 		struct drm_cmdline_mode *cmdline_mode;
 
-		cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
+		cmdline_mode = &connector->cmdline_mode;
 
 		if (cmdline_mode->bpp_specified) {
 			switch (cmdline_mode->bpp) {
@@ -1685,6 +1502,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 			break;
 		}
 	}
+	drm_connector_list_iter_end(&conn_iter);
 
 	/*
 	 * If we run into a situation where, for example, the primary plane
@@ -1865,26 +1683,12 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
 }
 EXPORT_SYMBOL(drm_fb_helper_fill_var);
 
-static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
-						uint32_t maxX,
-						uint32_t maxY)
-{
-	struct drm_connector *connector;
-	int i, count = 0;
-
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		connector = fb_helper->connector_info[i]->connector;
-		count += connector->funcs->fill_modes(connector, maxX, maxY);
-	}
-
-	return count;
-}
-
-struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
+static struct drm_display_mode *
+drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height)
 {
 	struct drm_display_mode *mode;
 
-	list_for_each_entry(mode, &fb_connector->connector->modes, head) {
+	list_for_each_entry(mode, &connector->modes, head) {
 		if (mode->hdisplay > width ||
 		    mode->vdisplay > height)
 			continue;
@@ -1893,20 +1697,15 @@ struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *
 	}
 	return NULL;
 }
-EXPORT_SYMBOL(drm_has_preferred_mode);
 
-static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
-{
-	return fb_connector->connector->cmdline_mode.specified;
-}
-
-struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn)
+static struct drm_display_mode *
+drm_connector_pick_cmdline_mode(struct drm_connector *connector)
 {
 	struct drm_cmdline_mode *cmdline_mode;
 	struct drm_display_mode *mode;
 	bool prefer_non_interlace;
 
-	cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
+	cmdline_mode = &connector->cmdline_mode;
 	if (cmdline_mode->specified == false)
 		return NULL;
 
@@ -1918,7 +1717,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
 
 	prefer_non_interlace = !cmdline_mode->interlace;
 again:
-	list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
+	list_for_each_entry(mode, &connector->modes, head) {
 		/* check width/height */
 		if (mode->hdisplay != cmdline_mode->xres ||
 		    mode->vdisplay != cmdline_mode->yres)
@@ -1945,12 +1744,10 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
 	}
 
 create_mode:
-	mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
-						 cmdline_mode);
-	list_add(&mode->head, &fb_helper_conn->connector->modes);
+	mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
+	list_add(&mode->head, &connector->modes);
 	return mode;
 }
-EXPORT_SYMBOL(drm_pick_cmdline_mode);
 
 static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
 {
@@ -1967,15 +1764,16 @@ static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
 	return enable;
 }
 
-static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
-				  bool *enabled)
+static void drm_client_connectors_enabled(struct drm_connector **connectors,
+					  unsigned int connector_count,
+					  bool *enabled)
 {
 	bool any_enabled = false;
 	struct drm_connector *connector;
 	int i = 0;
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		connector = fb_helper->connector_info[i]->connector;
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
 		enabled[i] = drm_connector_enabled(connector, true);
 		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
 			      connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");
@@ -1986,28 +1784,27 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
 	if (any_enabled)
 		return;
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		connector = fb_helper->connector_info[i]->connector;
-		enabled[i] = drm_connector_enabled(connector, false);
-	}
+	for (i = 0; i < connector_count; i++)
+		enabled[i] = drm_connector_enabled(connectors[i], false);
 }
 
-static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
-			      struct drm_display_mode **modes,
-			      struct drm_fb_offset *offsets,
-			      bool *enabled, int width, int height)
+static bool drm_client_target_cloned(struct drm_device *dev,
+				     struct drm_connector **connectors,
+				     unsigned int connector_count,
+				     struct drm_display_mode **modes,
+				     struct drm_fb_offset *offsets,
+				     bool *enabled, int width, int height)
 {
 	int count, i, j;
 	bool can_clone = false;
-	struct drm_fb_helper_connector *fb_helper_conn;
 	struct drm_display_mode *dmt_mode, *mode;
 
 	/* only contemplate cloning in the single crtc case */
-	if (fb_helper->dev->mode_config.num_crtc > 1)
+	if (dev->mode_config.num_crtc > 1)
 		return false;
 
 	count = 0;
-	drm_fb_helper_for_each_connector(fb_helper, i) {
+	for (i = 0; i < connector_count; i++) {
 		if (enabled[i])
 			count++;
 	}
@@ -2018,11 +1815,10 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 
 	/* check the command line or if nothing common pick 1024x768 */
 	can_clone = true;
-	drm_fb_helper_for_each_connector(fb_helper, i) {
+	for (i = 0; i < connector_count; i++) {
 		if (!enabled[i])
 			continue;
-		fb_helper_conn = fb_helper->connector_info[i];
-		modes[i] = drm_pick_cmdline_mode(fb_helper_conn);
+		modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
 		if (!modes[i]) {
 			can_clone = false;
 			break;
@@ -2046,14 +1842,13 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 
 	/* try and find a 1024x768 mode on each connector */
 	can_clone = true;
-	dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false);
+	dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
+	for (i = 0; i < connector_count; i++) {
 		if (!enabled[i])
 			continue;
 
-		fb_helper_conn = fb_helper->connector_info[i];
-		list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
+		list_for_each_entry(mode, &connectors[i]->modes, head) {
 			if (drm_mode_match(mode, dmt_mode,
 					   DRM_MODE_MATCH_TIMINGS |
 					   DRM_MODE_MATCH_CLOCK |
@@ -2073,30 +1868,31 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 	return false;
 }
 
-static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
-				struct drm_display_mode **modes,
-				struct drm_fb_offset *offsets,
-				int idx,
-				int h_idx, int v_idx)
+static int drm_client_get_tile_offsets(struct drm_connector **connectors,
+				       unsigned int connector_count,
+				       struct drm_display_mode **modes,
+				       struct drm_fb_offset *offsets,
+				       int idx,
+				       int h_idx, int v_idx)
 {
-	struct drm_fb_helper_connector *fb_helper_conn;
+	struct drm_connector *connector;
 	int i;
 	int hoffset = 0, voffset = 0;
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		fb_helper_conn = fb_helper->connector_info[i];
-		if (!fb_helper_conn->connector->has_tile)
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
+		if (!connector->has_tile)
 			continue;
 
 		if (!modes[i] && (h_idx || v_idx)) {
 			DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
-				      fb_helper_conn->connector->base.id);
+				      connector->base.id);
 			continue;
 		}
-		if (fb_helper_conn->connector->tile_h_loc < h_idx)
+		if (connector->tile_h_loc < h_idx)
 			hoffset += modes[i]->hdisplay;
 
-		if (fb_helper_conn->connector->tile_v_loc < v_idx)
+		if (connector->tile_v_loc < v_idx)
 			voffset += modes[i]->vdisplay;
 	}
 	offsets[idx].x = hoffset;
@@ -2105,20 +1901,21 @@ static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
 	return 0;
 }
 
-static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
-				 struct drm_display_mode **modes,
-				 struct drm_fb_offset *offsets,
-				 bool *enabled, int width, int height)
+static bool drm_client_target_preferred(struct drm_connector **connectors,
+					unsigned int connector_count,
+					struct drm_display_mode **modes,
+					struct drm_fb_offset *offsets,
+					bool *enabled, int width, int height)
 {
-	struct drm_fb_helper_connector *fb_helper_conn;
-	const u64 mask = BIT_ULL(fb_helper->connector_count) - 1;
+	const u64 mask = BIT_ULL(connector_count) - 1;
+	struct drm_connector *connector;
 	u64 conn_configured = 0;
 	int tile_pass = 0;
 	int i;
 
 retry:
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		fb_helper_conn = fb_helper->connector_info[i];
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
 
 		if (conn_configured & BIT_ULL(i))
 			continue;
@@ -2129,17 +1926,17 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 		}
 
 		/* first pass over all the untiled connectors */
-		if (tile_pass == 0 && fb_helper_conn->connector->has_tile)
+		if (tile_pass == 0 && connector->has_tile)
 			continue;
 
 		if (tile_pass == 1) {
-			if (fb_helper_conn->connector->tile_h_loc != 0 ||
-			    fb_helper_conn->connector->tile_v_loc != 0)
+			if (connector->tile_h_loc != 0 ||
+			    connector->tile_v_loc != 0)
 				continue;
 
 		} else {
-			if (fb_helper_conn->connector->tile_h_loc != tile_pass - 1 &&
-			    fb_helper_conn->connector->tile_v_loc != tile_pass - 1)
+			if (connector->tile_h_loc != tile_pass - 1 &&
+			    connector->tile_v_loc != tile_pass - 1)
 			/* if this tile_pass doesn't cover any of the tiles - keep going */
 				continue;
 
@@ -2147,22 +1944,22 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 			 * find the tile offsets for this pass - need to find
 			 * all tiles left and above
 			 */
-			drm_get_tile_offsets(fb_helper, modes, offsets,
-					     i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc);
+			drm_client_get_tile_offsets(connectors, connector_count, modes, offsets, i,
+						    connector->tile_h_loc, connector->tile_v_loc);
 		}
 		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
-			      fb_helper_conn->connector->base.id);
+			      connector->base.id);
 
 		/* got for command line mode first */
-		modes[i] = drm_pick_cmdline_mode(fb_helper_conn);
+		modes[i] = drm_connector_pick_cmdline_mode(connector);
 		if (!modes[i]) {
 			DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
-				      fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0);
-			modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
+				      connector->base.id, connector->tile_group ? connector->tile_group->id : 0);
+			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
 		}
 		/* No preferred modes, pick one off the list */
-		if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
-			list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
+		if (!modes[i] && !list_empty(&connector->modes)) {
+			list_for_each_entry(modes[i], &connector->modes, head)
 				break;
 		}
 		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
@@ -2191,40 +1988,41 @@ static bool connector_has_possible_crtc(struct drm_connector *connector,
 	return false;
 }
 
-static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
-			  struct drm_mode_set *modesets,
-			  struct drm_crtc **best_crtcs,
-			  struct drm_display_mode **modes,
-			  int n, int width, int height)
+static int drm_client_pick_crtcs(struct drm_device *dev,
+				 struct drm_mode_set *modesets,
+				 struct drm_connector **connectors,
+				 unsigned int connector_count,
+				 struct drm_crtc **best_crtcs,
+				 struct drm_display_mode **modes,
+				 int n, int width, int height)
 {
 	struct drm_connector *connector;
 	int my_score, best_score, score;
 	struct drm_crtc **crtcs, *crtc;
 	struct drm_mode_set *modeset;
-	struct drm_fb_helper_connector *fb_helper_conn;
 	int o;
 
-	if (n == fb_helper->connector_count)
+	if (n == connector_count)
 		return 0;
 
-	fb_helper_conn = fb_helper->connector_info[n];
-	connector = fb_helper_conn->connector;
+	connector = connectors[n];
 
 	best_crtcs[n] = NULL;
-	best_score = drm_pick_crtcs(fb_helper, modesets, best_crtcs, modes, n + 1, width, height);
+	best_score = drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
+					   best_crtcs, modes, n + 1, width, height);
 	if (modes[n] == NULL)
 		return best_score;
 
-	crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
+	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
 	if (!crtcs)
 		return best_score;
 
 	my_score = 1;
 	if (connector->status == connector_status_connected)
 		my_score++;
-	if (drm_has_cmdline_mode(fb_helper_conn))
+	if (connector->cmdline_mode.specified)
 		my_score++;
-	if (drm_has_preferred_mode(fb_helper_conn, width, height))
+	if (drm_connector_has_preferred_mode(connector, width, height))
 		my_score++;
 
 	/*
@@ -2243,7 +2041,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 
 		if (o < n) {
 			/* ignore cloning unless only a single crtc */
-			if (fb_helper->dev->mode_config.num_crtc > 1)
+			if (dev->mode_config.num_crtc > 1)
 				continue;
 
 			if (!drm_mode_equal(modes[o], modes[n]))
@@ -2252,12 +2050,11 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 
 		crtcs[n] = crtc;
 		memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
-		score = my_score + drm_pick_crtcs(fb_helper, modesets, crtcs, modes, n + 1,
-						  width, height);
+		score = my_score + drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
+							 crtcs, modes, n + 1, width, height);
 		if (score > best_score) {
 			best_score = score;
-			memcpy(best_crtcs, crtcs,
-			       fb_helper->connector_count * sizeof(*crtcs));
+			memcpy(best_crtcs, crtcs, connector_count * sizeof(*crtcs));
 		}
 	}
 
@@ -2266,14 +2063,15 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 }
 
 /* Try to read the BIOS display configuration and use it for the initial config */
-static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
-					  struct drm_crtc **crtcs,
-					  struct drm_display_mode **modes,
-					  struct drm_fb_offset *offsets,
-					  bool *enabled, int width, int height)
+static bool drm_client_firmware_config(struct drm_device *dev,
+				       struct drm_connector **connectors,
+				       unsigned int connector_count,
+				       struct drm_crtc **crtcs,
+				       struct drm_display_mode **modes,
+				       struct drm_fb_offset *offsets,
+				       bool *enabled, int width, int height)
 {
-	struct drm_device *dev = fb_helper->dev;
-	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
+	unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
 	unsigned long conn_configured, conn_seq;
 	int i, j;
 	bool *save_enabled;
@@ -2296,13 +2094,11 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 	conn_configured = 0;
 retry:
 	for (i = 0; i < count; i++) {
-		struct drm_fb_helper_connector *fb_conn;
 		struct drm_connector *connector;
 		struct drm_encoder *encoder;
 		struct drm_crtc *new_crtc;
 
-		fb_conn = fb_helper->connector_info[i];
-		connector = fb_conn->connector;
+		connector = connectors[i];
 
 		if (conn_configured & BIT(i))
 			continue;
@@ -2360,14 +2156,13 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 			      connector->name);
 
 		/* go for command line mode first */
-		modes[i] = drm_pick_cmdline_mode(fb_conn);
+		modes[i] = drm_connector_pick_cmdline_mode(connector);
 
 		/* try for preferred next */
 		if (!modes[i]) {
 			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
 				      connector->name, connector->has_tile);
-			modes[i] = drm_has_preferred_mode(fb_conn, width,
-							  height);
+			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
 		}
 
 		/* No preferred mode marked by the EDID? Are there any modes? */
@@ -2444,10 +2239,14 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			    u32 width, u32 height)
 {
+	struct drm_connector *connector, **connectors = NULL;
+	struct drm_connector_list_iter conn_iter;
 	struct drm_device *dev = fb_helper->dev;
+	struct drm_mode_set *modesets = NULL;
+	unsigned int total_modes_count = 0;
+	unsigned int connector_count = 0;
 	struct drm_display_mode **modes;
 	struct drm_fb_offset *offsets;
-	struct drm_mode_set *modesets;
 	struct drm_crtc **crtcs;
 	bool *enabled;
 	int i;
@@ -2456,52 +2255,68 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	/* prevent concurrent modification of connector_count by hotplug */
 	lockdep_assert_held(&fb_helper->lock);
 
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_client_for_each_connector_iter(connector, &conn_iter) {
+		struct drm_connector **tmp;
+
+		tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
+		if (!tmp)
+			goto free_connectors;
+
+		connectors = tmp;
+		drm_connector_get(connector);
+		connectors[connector_count++] = connector;
+	}
+	drm_connector_list_iter_end(&conn_iter);
+
+	if (!connector_count)
+		return;
+
 	modesets = drm_client_modesets_create(dev);
-	crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
-	modes = kcalloc(fb_helper->connector_count,
-			sizeof(struct drm_display_mode *), GFP_KERNEL);
-	offsets = kcalloc(fb_helper->connector_count,
-			  sizeof(struct drm_fb_offset), GFP_KERNEL);
-	enabled = kcalloc(fb_helper->connector_count,
-			  sizeof(bool), GFP_KERNEL);
+	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
+	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
+	offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
+	enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
 	if (IS_ERR(modesets) || !crtcs || !modes || !enabled || !offsets) {
 		DRM_ERROR("Memory allocation failed\n");
 		goto out;
 	}
 
 	mutex_lock(&fb_helper->dev->mode_config.mutex);
-	if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
+	for (i = 0; i < connector_count; i++)
+		total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
+	if (!total_modes_count)
 		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
-	drm_enable_connectors(fb_helper, enabled);
+	drm_client_connectors_enabled(connectors, connector_count, enabled);
 
-	if (!drm_fb_helper_firmware_config(fb_helper, crtcs, modes, offsets,
-					   enabled, width, height)) {
-		memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
-		memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
-		memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
+	if (!drm_client_firmware_config(dev, connectors, connector_count, crtcs,
+					modes, offsets, enabled, width, height)) {
+		memset(modes, 0, connector_count * sizeof(*modes));
+		memset(crtcs, 0, connector_count * sizeof(*crtcs));
+		memset(offsets, 0, connector_count * sizeof(*offsets));
 
-		if (!drm_target_cloned(fb_helper, modes, offsets,
-				       enabled, width, height) &&
-		    !drm_target_preferred(fb_helper, modes, offsets,
-					  enabled, width, height))
+		if (!drm_client_target_cloned(dev, connectors, connector_count, modes,
+					      offsets, enabled, width, height) &&
+		    !drm_client_target_preferred(connectors, connector_count, modes,
+						 offsets, enabled, width, height))
 			DRM_ERROR("Unable to find initial modes\n");
 
 		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
 			      width, height);
 
-		drm_pick_crtcs(fb_helper, modesets, crtcs, modes, 0, width, height);
+		drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
+				      crtcs, modes, 0, width, height);
 	}
 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
+	for (i = 0; i < connector_count; i++) {
 		struct drm_display_mode *mode = modes[i];
 		struct drm_crtc *crtc = crtcs[i];
 		struct drm_fb_offset *offset = &offsets[i];
 
 		if (mode && crtc) {
 			struct drm_mode_set *modeset = drm_client_find_modeset(modesets, crtc);
-			struct drm_connector *connector =
-				fb_helper->connector_info[i]->connector;
+			struct drm_connector *connector = connectors[i];
 
 			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
 				      mode->name, crtc->base.id, offset->x, offset->y);
@@ -2524,6 +2339,13 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	kfree(modes);
 	kfree(offsets);
 	kfree(enabled);
+free_connectors:
+	if (connectors) {
+		for (i = 0; i < connector_count; i++)
+			drm_connector_put(connectors[i]);
+		kfree(connectors);
+	}
+
 	drm_client_modesets_release(modesets);
 }
 
@@ -2536,10 +2358,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
  */
 static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 {
+	struct drm_connector_list_iter conn_iter;
 	struct fb_info *info = fb_helper->fbdev;
 	unsigned int rotation, sw_rotations = 0;
+	struct drm_connector *connector;
 	struct drm_mode_set *modeset;
-	int i;
 
 	drm_client_for_each_modeset(modeset, fb_helper->modesets) {
 		if (!modeset->num_connectors)
@@ -2554,10 +2377,8 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 			sw_rotations |= rotation;
 	}
 
-	mutex_lock(&fb_helper->dev->mode_config.mutex);
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		struct drm_connector *connector =
-					fb_helper->connector_info[i]->connector;
+	drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
+	drm_client_for_each_connector_iter(connector, &conn_iter) {
 
 		/* use first connected connector for the physical dimensions */
 		if (connector->status == connector_status_connected) {
@@ -2566,7 +2387,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 			break;
 		}
 	}
-	mutex_unlock(&fb_helper->dev->mode_config.mutex);
+	drm_connector_list_iter_end(&conn_iter);
 
 	switch (sw_rotations) {
 	case DRM_MODE_ROTATE_0:
@@ -2803,12 +2624,6 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev,
 		return ret;
 	}
 
-	ret = drm_fb_helper_single_add_all_connectors(fb_helper);
-	if (ret < 0) {
-		DRM_DEV_ERROR(dev->dev, "fbdev: Failed to add connectors (ret=%d)\n", ret);
-		goto err_drm_fb_helper_fini;
-	}
-
 	if (!drm_drv_uses_atomic_modeset(dev))
 		drm_helper_disable_unused_functions(dev);
 
@@ -3118,10 +2933,6 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
 	if (ret)
 		goto err;
 
-	ret = drm_fb_helper_single_add_all_connectors(fb_helper);
-	if (ret)
-		goto err_cleanup;
-
 	if (!drm_drv_uses_atomic_modeset(dev))
 		drm_helper_disable_unused_functions(dev);
 
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 01e787f8bc12..a55f5ecae64a 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -5,6 +5,7 @@
 
 #include <linux/types.h>
 
+#include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
 
 struct drm_client_dev;
@@ -146,6 +147,20 @@ bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotat
 int drm_client_modesets_commit(struct drm_device *dev, struct drm_mode_set *modesets);
 void drm_client_modesets_dpms(struct drm_device *dev, struct drm_mode_set *modesets, int mode);
 
+/**
+ * drm_client_for_each_connector_iter - connector_list iterator macro
+ * @connector: &struct drm_connector pointer used as cursor
+ * @iter: &struct drm_connector_list_iter
+ *
+ * This iterates the connectors that are useable for internal clients (excludes
+ * writeback connectors).
+ *
+ * For more info see drm_for_each_connector_iter().
+ */
+#define drm_client_for_each_connector_iter(connector, iter) \
+	drm_for_each_connector_iter(connector, iter) \
+		if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
+
 /**
  * drm_client_for_each_modeset() - Iterate over modesets
  * @modeset: &drm_mode_set loop cursor
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 905697c37c5b..946bf179e96e 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -98,16 +98,10 @@ struct drm_fb_helper_funcs {
 			struct drm_fb_helper_surface_size *sizes);
 };
 
-struct drm_fb_helper_connector {
-	struct drm_connector *connector;
-};
-
 /**
  * struct drm_fb_helper - main structure to emulate fbdev on top of KMS
  * @fb: Scanout framebuffer object
  * @dev: DRM device
- * @connector_count: number of connected connectors
- * @connector_info_alloc_count: size of connector_info
  * @funcs: driver callbacks for fb helper
  * @fbdev: emulated fbdev device info struct
  * @pseudo_palette: fake palette of 16 colors
@@ -145,15 +139,6 @@ struct drm_fb_helper {
 	 */
 	struct drm_mode_set *modesets;
 
-	int connector_count;
-	int connector_info_alloc_count;
-	/**
-	 * @connector_info:
-	 *
-	 * Array of per-connector information. Do not iterate directly, but use
-	 * drm_fb_helper_for_each_connector.
-	 */
-	struct drm_fb_helper_connector **connector_info;
 	const struct drm_fb_helper_funcs *funcs;
 	struct fb_info *fbdev;
 	u32 pseudo_palette[17];
@@ -294,18 +279,8 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 
 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
 int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
-int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
 int drm_fb_helper_debug_enter(struct fb_info *info);
 int drm_fb_helper_debug_leave(struct fb_info *info);
-struct drm_display_mode *
-drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector,
-			int width, int height);
-struct drm_display_mode *
-drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn);
-
-int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector);
-int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
-				       struct drm_connector *connector);
 
 int drm_fb_helper_fbdev_setup(struct drm_device *dev,
 			      struct drm_fb_helper *fb_helper,
@@ -484,12 +459,6 @@ static inline int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper,
 	return 0;
 }
 
-static inline int
-drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
-{
-	return 0;
-}
-
 static inline int drm_fb_helper_debug_enter(struct fb_info *info)
 {
 	return 0;
@@ -500,34 +469,6 @@ static inline int drm_fb_helper_debug_leave(struct fb_info *info)
 	return 0;
 }
 
-static inline struct drm_display_mode *
-drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector,
-		       int width, int height)
-{
-	return NULL;
-}
-
-static inline struct drm_display_mode *
-drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
-		      int width, int height)
-{
-	return NULL;
-}
-
-static inline int
-drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
-				struct drm_connector *connector)
-{
-	return 0;
-}
-
-static inline int
-drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
-				   struct drm_connector *connector)
-{
-	return 0;
-}
-
 static inline int
 drm_fb_helper_fbdev_setup(struct drm_device *dev,
 			  struct drm_fb_helper *fb_helper,
@@ -569,6 +510,27 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
 
 #endif
 
+/* TODO: There's a todo entry to remove these three */
+static inline int
+drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
+{
+	return 0;
+}
+
+static inline int
+drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
+				struct drm_connector *connector)
+{
+	return 0;
+}
+
+static inline int
+drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
+				   struct drm_connector *connector)
+{
+	return 0;
+}
+
 /**
  * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
  * @a: memory range, users of which are to be removed
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 11/16] drm/fb-helper: Prepare to move out modeset config code
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (9 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 10/16] drm/fb-helper: Remove drm_fb_helper_connector Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 12/16] drm/fb-helper: Move " Noralf Trønnes
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes, mstaudt

This prepares the modeset code so it can be moved out as-is in the next
patch.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c | 75 +++++++++++++++++++++++++--------
 include/drm/drm_fb_helper.h     |  4 --
 2 files changed, 57 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index de805956849d..afe4d4220e4d 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -45,6 +45,10 @@
 #include "drm_crtc_internal.h"
 #include "drm_crtc_helper_internal.h"
 
+struct drm_client_offset {
+	int x, y;
+};
+
 static bool drm_fbdev_emulation = true;
 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
 MODULE_PARM_DESC(fbdev_emulation,
@@ -1792,7 +1796,7 @@ static bool drm_client_target_cloned(struct drm_device *dev,
 				     struct drm_connector **connectors,
 				     unsigned int connector_count,
 				     struct drm_display_mode **modes,
-				     struct drm_fb_offset *offsets,
+				     struct drm_client_offset *offsets,
 				     bool *enabled, int width, int height)
 {
 	int count, i, j;
@@ -1871,7 +1875,7 @@ static bool drm_client_target_cloned(struct drm_device *dev,
 static int drm_client_get_tile_offsets(struct drm_connector **connectors,
 				       unsigned int connector_count,
 				       struct drm_display_mode **modes,
-				       struct drm_fb_offset *offsets,
+				       struct drm_client_offset *offsets,
 				       int idx,
 				       int h_idx, int v_idx)
 {
@@ -1904,7 +1908,7 @@ static int drm_client_get_tile_offsets(struct drm_connector **connectors,
 static bool drm_client_target_preferred(struct drm_connector **connectors,
 					unsigned int connector_count,
 					struct drm_display_mode **modes,
-					struct drm_fb_offset *offsets,
+					struct drm_client_offset *offsets,
 					bool *enabled, int width, int height)
 {
 	const u64 mask = BIT_ULL(connector_count) - 1;
@@ -2068,7 +2072,7 @@ static bool drm_client_firmware_config(struct drm_device *dev,
 				       unsigned int connector_count,
 				       struct drm_crtc **crtcs,
 				       struct drm_display_mode **modes,
-				       struct drm_fb_offset *offsets,
+				       struct drm_client_offset *offsets,
 				       bool *enabled, int width, int height)
 {
 	unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
@@ -2236,32 +2240,51 @@ static bool drm_client_firmware_config(struct drm_device *dev,
 	return ret;
 }
 
-static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
-			    u32 width, u32 height)
+/**
+ * drm_client_modesets_probe() - Probe for displays
+ * @dev: DRM device
+ * @width: Maximum display mode width (optional)
+ * @height: Maximum display mode height (optional)
+ *
+ * This function tries to set up pipelines for enabled connectors and returns
+ * the CRTC config as a &drm_mode_set array.
+ *
+ * Use drm_client_modesets_release() to free the array and its resources.
+ *
+ * Returns:
+ * A &drm_mode_set array on success, NULL if no connectors are found
+ * or error pointer on failure.
+ */
+struct drm_mode_set *
+drm_client_modesets_probe(struct drm_device *dev, unsigned int width, unsigned int height)
 {
 	struct drm_connector *connector, **connectors = NULL;
 	struct drm_connector_list_iter conn_iter;
-	struct drm_device *dev = fb_helper->dev;
 	struct drm_mode_set *modesets = NULL;
 	unsigned int total_modes_count = 0;
+	struct drm_client_offset *offsets;
 	unsigned int connector_count = 0;
 	struct drm_display_mode **modes;
-	struct drm_fb_offset *offsets;
 	struct drm_crtc **crtcs;
+	int i, ret = 0;
 	bool *enabled;
-	int i;
 
 	DRM_DEBUG_KMS("\n");
-	/* prevent concurrent modification of connector_count by hotplug */
-	lockdep_assert_held(&fb_helper->lock);
+
+	if (!width)
+		width = dev->mode_config.max_width;
+	if (!height)
+		height = dev->mode_config.max_height;
 
 	drm_connector_list_iter_begin(dev, &conn_iter);
 	drm_client_for_each_connector_iter(connector, &conn_iter) {
 		struct drm_connector **tmp;
 
 		tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
-		if (!tmp)
+		if (!tmp) {
+			ret = -ENOMEM;
 			goto free_connectors;
+		}
 
 		connectors = tmp;
 		drm_connector_get(connector);
@@ -2270,7 +2293,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	drm_connector_list_iter_end(&conn_iter);
 
 	if (!connector_count)
-		return;
+		return NULL;
 
 	modesets = drm_client_modesets_create(dev);
 	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
@@ -2279,10 +2302,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
 	if (IS_ERR(modesets) || !crtcs || !modes || !enabled || !offsets) {
 		DRM_ERROR("Memory allocation failed\n");
+		ret = -ENOMEM;
 		goto out;
 	}
 
-	mutex_lock(&fb_helper->dev->mode_config.mutex);
+	mutex_lock(&dev->mode_config.mutex);
 	for (i = 0; i < connector_count; i++)
 		total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
 	if (!total_modes_count)
@@ -2307,12 +2331,12 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
 				      crtcs, modes, 0, width, height);
 	}
-	mutex_unlock(&fb_helper->dev->mode_config.mutex);
+	mutex_unlock(&dev->mode_config.mutex);
 
 	for (i = 0; i < connector_count; i++) {
 		struct drm_display_mode *mode = modes[i];
 		struct drm_crtc *crtc = crtcs[i];
-		struct drm_fb_offset *offset = &offsets[i];
+		struct drm_client_offset *offset = &offsets[i];
 
 		if (mode && crtc) {
 			struct drm_mode_set *modeset = drm_client_find_modeset(modesets, crtc);
@@ -2332,8 +2356,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			modeset->y = offset->y;
 		}
 	}
-
-	swap(fb_helper->modesets, modesets);
 out:
 	kfree(crtcs);
 	kfree(modes);
@@ -2346,6 +2368,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		kfree(connectors);
 	}
 
+	if (ret) {
+		drm_client_modesets_release(modesets);
+		return ERR_PTR(ret);
+	}
+
+	return modesets;
+}
+
+static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, u32 width, u32 height)
+{
+	struct drm_mode_set *modesets;
+
+	modesets = drm_client_modesets_probe(fb_helper->dev, width, height);
+	if (IS_ERR_OR_NULL(modesets))
+		return;
+
+	swap(fb_helper->modesets, modesets);
 	drm_client_modesets_release(modesets);
 }
 
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 946bf179e96e..bd38d5c85c92 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -42,10 +42,6 @@ enum mode_set_atomic {
 	ENTER_ATOMIC_MODE_SET,
 };
 
-struct drm_fb_offset {
-	int x, y;
-};
-
 /**
  * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
  * @fb_width: fbdev width
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 12/16] drm/fb-helper: Move out modeset config code
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (10 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 11/16] drm/fb-helper: Prepare to move out modeset config code Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 13/16] drm/fb-helper: Avoid race with DRM userspace Noralf Trønnes
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, mstaudt

No functional changes, just moving code as-is and fixing includes.
There is one addition and that is exporting drm_client_modesets_probe().

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_client.c    | 698 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_fb_helper.c | 697 -------------------------------
 include/drm/drm_client.h        |   4 +-
 3 files changed, 700 insertions(+), 699 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 5b199c051960..3bc96b0b30ec 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -11,9 +11,11 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_client.h>
+#include <drm/drm_connector.h>
 #include <drm/drm_debugfs.h>
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
+#include <drm/drm_encoder.h>
 #include <drm/drm_file.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_gem.h>
@@ -24,6 +26,12 @@
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
 
+#define DRM_CLIENT_MAX_CLONED_CONNECTORS	8
+
+struct drm_client_offset {
+	int x, y;
+};
+
 /**
  * DOC: overview
  *
@@ -486,6 +494,696 @@ struct drm_mode_set *drm_client_find_modeset(struct drm_mode_set *modesets, stru
 }
 EXPORT_SYMBOL(drm_client_find_modeset);
 
+static struct drm_display_mode *
+drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height)
+{
+	struct drm_display_mode *mode;
+
+	list_for_each_entry(mode, &connector->modes, head) {
+		if (mode->hdisplay > width ||
+		    mode->vdisplay > height)
+			continue;
+		if (mode->type & DRM_MODE_TYPE_PREFERRED)
+			return mode;
+	}
+	return NULL;
+}
+
+static struct drm_display_mode *
+drm_connector_pick_cmdline_mode(struct drm_connector *connector)
+{
+	struct drm_cmdline_mode *cmdline_mode;
+	struct drm_display_mode *mode;
+	bool prefer_non_interlace;
+
+	cmdline_mode = &connector->cmdline_mode;
+	if (cmdline_mode->specified == false)
+		return NULL;
+
+	/* attempt to find a matching mode in the list of modes
+	 *  we have gotten so far, if not add a CVT mode that conforms
+	 */
+	if (cmdline_mode->rb || cmdline_mode->margins)
+		goto create_mode;
+
+	prefer_non_interlace = !cmdline_mode->interlace;
+again:
+	list_for_each_entry(mode, &connector->modes, head) {
+		/* check width/height */
+		if (mode->hdisplay != cmdline_mode->xres ||
+		    mode->vdisplay != cmdline_mode->yres)
+			continue;
+
+		if (cmdline_mode->refresh_specified) {
+			if (mode->vrefresh != cmdline_mode->refresh)
+				continue;
+		}
+
+		if (cmdline_mode->interlace) {
+			if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
+				continue;
+		} else if (prefer_non_interlace) {
+			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+				continue;
+		}
+		return mode;
+	}
+
+	if (prefer_non_interlace) {
+		prefer_non_interlace = false;
+		goto again;
+	}
+
+create_mode:
+	mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
+	list_add(&mode->head, &connector->modes);
+	return mode;
+}
+
+static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
+{
+	bool enable;
+
+	if (connector->display_info.non_desktop)
+		return false;
+
+	if (strict)
+		enable = connector->status == connector_status_connected;
+	else
+		enable = connector->status != connector_status_disconnected;
+
+	return enable;
+}
+
+static void drm_client_connectors_enabled(struct drm_connector **connectors,
+					  unsigned int connector_count,
+					  bool *enabled)
+{
+	bool any_enabled = false;
+	struct drm_connector *connector;
+	int i = 0;
+
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
+		enabled[i] = drm_connector_enabled(connector, true);
+		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
+			      connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");
+
+		any_enabled |= enabled[i];
+	}
+
+	if (any_enabled)
+		return;
+
+	for (i = 0; i < connector_count; i++)
+		enabled[i] = drm_connector_enabled(connectors[i], false);
+}
+
+static bool drm_client_target_cloned(struct drm_device *dev,
+				     struct drm_connector **connectors,
+				     unsigned int connector_count,
+				     struct drm_display_mode **modes,
+				     struct drm_client_offset *offsets,
+				     bool *enabled, int width, int height)
+{
+	int count, i, j;
+	bool can_clone = false;
+	struct drm_display_mode *dmt_mode, *mode;
+
+	/* only contemplate cloning in the single crtc case */
+	if (dev->mode_config.num_crtc > 1)
+		return false;
+
+	count = 0;
+	for (i = 0; i < connector_count; i++) {
+		if (enabled[i])
+			count++;
+	}
+
+	/* only contemplate cloning if more than one connector is enabled */
+	if (count <= 1)
+		return false;
+
+	/* check the command line or if nothing common pick 1024x768 */
+	can_clone = true;
+	for (i = 0; i < connector_count; i++) {
+		if (!enabled[i])
+			continue;
+		modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
+		if (!modes[i]) {
+			can_clone = false;
+			break;
+		}
+		for (j = 0; j < i; j++) {
+			if (!enabled[j])
+				continue;
+			if (!drm_mode_match(modes[j], modes[i],
+					    DRM_MODE_MATCH_TIMINGS |
+					    DRM_MODE_MATCH_CLOCK |
+					    DRM_MODE_MATCH_FLAGS |
+					    DRM_MODE_MATCH_3D_FLAGS))
+				can_clone = false;
+		}
+	}
+
+	if (can_clone) {
+		DRM_DEBUG_KMS("can clone using command line\n");
+		return true;
+	}
+
+	/* try and find a 1024x768 mode on each connector */
+	can_clone = true;
+	dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
+
+	for (i = 0; i < connector_count; i++) {
+		if (!enabled[i])
+			continue;
+
+		list_for_each_entry(mode, &connectors[i]->modes, head) {
+			if (drm_mode_match(mode, dmt_mode,
+					   DRM_MODE_MATCH_TIMINGS |
+					   DRM_MODE_MATCH_CLOCK |
+					   DRM_MODE_MATCH_FLAGS |
+					   DRM_MODE_MATCH_3D_FLAGS))
+				modes[i] = mode;
+		}
+		if (!modes[i])
+			can_clone = false;
+	}
+
+	if (can_clone) {
+		DRM_DEBUG_KMS("can clone using 1024x768\n");
+		return true;
+	}
+	DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
+	return false;
+}
+
+static int drm_client_get_tile_offsets(struct drm_connector **connectors,
+				       unsigned int connector_count,
+				       struct drm_display_mode **modes,
+				       struct drm_client_offset *offsets,
+				       int idx,
+				       int h_idx, int v_idx)
+{
+	struct drm_connector *connector;
+	int i;
+	int hoffset = 0, voffset = 0;
+
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
+		if (!connector->has_tile)
+			continue;
+
+		if (!modes[i] && (h_idx || v_idx)) {
+			DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
+				      connector->base.id);
+			continue;
+		}
+		if (connector->tile_h_loc < h_idx)
+			hoffset += modes[i]->hdisplay;
+
+		if (connector->tile_v_loc < v_idx)
+			voffset += modes[i]->vdisplay;
+	}
+	offsets[idx].x = hoffset;
+	offsets[idx].y = voffset;
+	DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
+	return 0;
+}
+
+static bool drm_client_target_preferred(struct drm_connector **connectors,
+					unsigned int connector_count,
+					struct drm_display_mode **modes,
+					struct drm_client_offset *offsets,
+					bool *enabled, int width, int height)
+{
+	const u64 mask = BIT_ULL(connector_count) - 1;
+	struct drm_connector *connector;
+	u64 conn_configured = 0;
+	int tile_pass = 0;
+	int i;
+
+retry:
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
+
+		if (conn_configured & BIT_ULL(i))
+			continue;
+
+		if (enabled[i] == false) {
+			conn_configured |= BIT_ULL(i);
+			continue;
+		}
+
+		/* first pass over all the untiled connectors */
+		if (tile_pass == 0 && connector->has_tile)
+			continue;
+
+		if (tile_pass == 1) {
+			if (connector->tile_h_loc != 0 ||
+			    connector->tile_v_loc != 0)
+				continue;
+
+		} else {
+			if (connector->tile_h_loc != tile_pass - 1 &&
+			    connector->tile_v_loc != tile_pass - 1)
+			/* if this tile_pass doesn't cover any of the tiles - keep going */
+				continue;
+
+			/*
+			 * find the tile offsets for this pass - need to find
+			 * all tiles left and above
+			 */
+			drm_client_get_tile_offsets(connectors, connector_count, modes, offsets, i,
+						    connector->tile_h_loc, connector->tile_v_loc);
+		}
+		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
+			      connector->base.id);
+
+		/* got for command line mode first */
+		modes[i] = drm_connector_pick_cmdline_mode(connector);
+		if (!modes[i]) {
+			DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
+				      connector->base.id, connector->tile_group ? connector->tile_group->id : 0);
+			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
+		}
+		/* No preferred modes, pick one off the list */
+		if (!modes[i] && !list_empty(&connector->modes)) {
+			list_for_each_entry(modes[i], &connector->modes, head)
+				break;
+		}
+		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
+			  "none");
+		conn_configured |= BIT_ULL(i);
+	}
+
+	if ((conn_configured & mask) != mask) {
+		tile_pass++;
+		goto retry;
+	}
+	return true;
+}
+
+static bool connector_has_possible_crtc(struct drm_connector *connector,
+					struct drm_crtc *crtc)
+{
+	struct drm_encoder *encoder;
+	int i;
+
+	drm_connector_for_each_possible_encoder(connector, encoder, i) {
+		if (encoder->possible_crtcs & drm_crtc_mask(crtc))
+			return true;
+	}
+
+	return false;
+}
+
+static int drm_client_pick_crtcs(struct drm_device *dev,
+				 struct drm_mode_set *modesets,
+				 struct drm_connector **connectors,
+				 unsigned int connector_count,
+				 struct drm_crtc **best_crtcs,
+				 struct drm_display_mode **modes,
+				 int n, int width, int height)
+{
+	struct drm_connector *connector;
+	int my_score, best_score, score;
+	struct drm_crtc **crtcs, *crtc;
+	struct drm_mode_set *modeset;
+	int o;
+
+	if (n == connector_count)
+		return 0;
+
+	connector = connectors[n];
+
+	best_crtcs[n] = NULL;
+	best_score = drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
+					   best_crtcs, modes, n + 1, width, height);
+	if (modes[n] == NULL)
+		return best_score;
+
+	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
+	if (!crtcs)
+		return best_score;
+
+	my_score = 1;
+	if (connector->status == connector_status_connected)
+		my_score++;
+	if (connector->cmdline_mode.specified)
+		my_score++;
+	if (drm_connector_has_preferred_mode(connector, width, height))
+		my_score++;
+
+	/*
+	 * select a crtc for this connector and then attempt to configure
+	 * remaining connectors
+	 */
+	drm_client_for_each_modeset(modeset, modesets) {
+		crtc = modeset->crtc;
+
+		if (!connector_has_possible_crtc(connector, crtc))
+			continue;
+
+		for (o = 0; o < n; o++)
+			if (best_crtcs[o] == crtc)
+				break;
+
+		if (o < n) {
+			/* ignore cloning unless only a single crtc */
+			if (dev->mode_config.num_crtc > 1)
+				continue;
+
+			if (!drm_mode_equal(modes[o], modes[n]))
+				continue;
+		}
+
+		crtcs[n] = crtc;
+		memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
+		score = my_score + drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
+							 crtcs, modes, n + 1, width, height);
+		if (score > best_score) {
+			best_score = score;
+			memcpy(best_crtcs, crtcs, connector_count * sizeof(*crtcs));
+		}
+	}
+
+	kfree(crtcs);
+	return best_score;
+}
+
+/* Try to read the BIOS display configuration and use it for the initial config */
+static bool drm_client_firmware_config(struct drm_device *dev,
+				       struct drm_connector **connectors,
+				       unsigned int connector_count,
+				       struct drm_crtc **crtcs,
+				       struct drm_display_mode **modes,
+				       struct drm_client_offset *offsets,
+				       bool *enabled, int width, int height)
+{
+	unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
+	unsigned long conn_configured, conn_seq;
+	int i, j;
+	bool *save_enabled;
+	bool fallback = true, ret = true;
+	int num_connectors_enabled = 0;
+	int num_connectors_detected = 0;
+	struct drm_modeset_acquire_ctx ctx;
+
+	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
+	if (!save_enabled)
+		return false;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
+		drm_modeset_backoff(&ctx);
+
+	memcpy(save_enabled, enabled, count);
+	conn_seq = GENMASK(count - 1, 0);
+	conn_configured = 0;
+retry:
+	for (i = 0; i < count; i++) {
+		struct drm_connector *connector;
+		struct drm_encoder *encoder;
+		struct drm_crtc *new_crtc;
+
+		connector = connectors[i];
+
+		if (conn_configured & BIT(i))
+			continue;
+
+		/* First pass, only consider tiled connectors */
+		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
+			continue;
+
+		if (connector->status == connector_status_connected)
+			num_connectors_detected++;
+
+		if (!enabled[i]) {
+			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
+				      connector->name);
+			conn_configured |= BIT(i);
+			continue;
+		}
+
+		if (connector->force == DRM_FORCE_OFF) {
+			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
+				      connector->name);
+			enabled[i] = false;
+			continue;
+		}
+
+		encoder = connector->state->best_encoder;
+		if (!encoder || WARN_ON(!connector->state->crtc)) {
+			if (connector->force > DRM_FORCE_OFF)
+				goto bail;
+
+			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
+				      connector->name);
+			enabled[i] = false;
+			conn_configured |= BIT(i);
+			continue;
+		}
+
+		num_connectors_enabled++;
+
+		new_crtc = connector->state->crtc;
+
+		/*
+		 * Make sure we're not trying to drive multiple connectors
+		 * with a single CRTC, since our cloning support may not
+		 * match the BIOS.
+		 */
+		for (j = 0; j < count; j++) {
+			if (crtcs[j] == new_crtc) {
+				DRM_DEBUG_KMS("fallback: cloned configuration\n");
+				goto bail;
+			}
+		}
+
+		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
+			      connector->name);
+
+		/* go for command line mode first */
+		modes[i] = drm_connector_pick_cmdline_mode(connector);
+
+		/* try for preferred next */
+		if (!modes[i]) {
+			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
+				      connector->name, connector->has_tile);
+			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
+		}
+
+		/* No preferred mode marked by the EDID? Are there any modes? */
+		if (!modes[i] && !list_empty(&connector->modes)) {
+			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
+				      connector->name);
+			modes[i] = list_first_entry(&connector->modes,
+						    struct drm_display_mode,
+						    head);
+		}
+
+		/* last resort: use current mode */
+		if (!modes[i]) {
+			/*
+			 * IMPORTANT: We want to use the adjusted mode (i.e.
+			 * after the panel fitter upscaling) as the initial
+			 * config, not the input mode, which is what crtc->mode
+			 * usually contains. But since our current
+			 * code puts a mode derived from the post-pfit timings
+			 * into crtc->mode this works out correctly.
+			 *
+			 * This is crtc->mode and not crtc->state->mode for the
+			 * fastboot check to work correctly.
+			 */
+			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
+				      connector->name);
+			modes[i] = &connector->state->crtc->mode;
+		}
+		crtcs[i] = new_crtc;
+
+		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
+			      connector->name,
+			      connector->state->crtc->base.id,
+			      connector->state->crtc->name,
+			      modes[i]->hdisplay, modes[i]->vdisplay,
+			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
+
+		fallback = false;
+		conn_configured |= BIT(i);
+	}
+
+	if (conn_configured != conn_seq) { /* repeat until no more are found */
+		conn_seq = conn_configured;
+		goto retry;
+	}
+
+	/*
+	 * If the BIOS didn't enable everything it could, fall back to have the
+	 * same user experiencing of lighting up as much as possible like the
+	 * fbdev helper library.
+	 */
+	if (num_connectors_enabled != num_connectors_detected &&
+	    num_connectors_enabled < dev->mode_config.num_crtc) {
+		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
+		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
+			      num_connectors_detected);
+		fallback = true;
+	}
+
+	if (fallback) {
+bail:
+		DRM_DEBUG_KMS("Not using firmware configuration\n");
+		memcpy(enabled, save_enabled, count);
+		ret = false;
+	}
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	kfree(save_enabled);
+	return ret;
+}
+
+/**
+ * drm_client_modesets_probe() - Probe for displays
+ * @dev: DRM device
+ * @width: Maximum display mode width (optional)
+ * @height: Maximum display mode height (optional)
+ *
+ * This function tries to set up pipelines for enabled connectors and returns
+ * the CRTC config as a &drm_mode_set array.
+ *
+ * Use drm_client_modesets_release() to free the array and its resources.
+ *
+ * Returns:
+ * A &drm_mode_set array on success, NULL if no connectors are found
+ * or error pointer on failure.
+ */
+struct drm_mode_set *
+drm_client_modesets_probe(struct drm_device *dev, unsigned int width, unsigned int height)
+{
+	struct drm_connector *connector, **connectors = NULL;
+	struct drm_connector_list_iter conn_iter;
+	struct drm_mode_set *modesets = NULL;
+	unsigned int total_modes_count = 0;
+	struct drm_client_offset *offsets;
+	unsigned int connector_count = 0;
+	struct drm_display_mode **modes;
+	struct drm_crtc **crtcs;
+	int i, ret = 0;
+	bool *enabled;
+
+	DRM_DEBUG_KMS("\n");
+
+	if (!width)
+		width = dev->mode_config.max_width;
+	if (!height)
+		height = dev->mode_config.max_height;
+
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_client_for_each_connector_iter(connector, &conn_iter) {
+		struct drm_connector **tmp;
+
+		tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
+		if (!tmp) {
+			ret = -ENOMEM;
+			goto free_connectors;
+		}
+
+		connectors = tmp;
+		drm_connector_get(connector);
+		connectors[connector_count++] = connector;
+	}
+	drm_connector_list_iter_end(&conn_iter);
+
+	if (!connector_count)
+		return NULL;
+
+	modesets = drm_client_modesets_create(dev);
+	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
+	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
+	offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
+	enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
+	if (IS_ERR(modesets) || !crtcs || !modes || !enabled || !offsets) {
+		DRM_ERROR("Memory allocation failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	mutex_lock(&dev->mode_config.mutex);
+	for (i = 0; i < connector_count; i++)
+		total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
+	if (!total_modes_count)
+		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
+	drm_client_connectors_enabled(connectors, connector_count, enabled);
+
+	if (!drm_client_firmware_config(dev, connectors, connector_count, crtcs,
+					modes, offsets, enabled, width, height)) {
+		memset(modes, 0, connector_count * sizeof(*modes));
+		memset(crtcs, 0, connector_count * sizeof(*crtcs));
+		memset(offsets, 0, connector_count * sizeof(*offsets));
+
+		if (!drm_client_target_cloned(dev, connectors, connector_count, modes,
+					      offsets, enabled, width, height) &&
+		    !drm_client_target_preferred(connectors, connector_count, modes,
+						 offsets, enabled, width, height))
+			DRM_ERROR("Unable to find initial modes\n");
+
+		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
+			      width, height);
+
+		drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
+				      crtcs, modes, 0, width, height);
+	}
+	mutex_unlock(&dev->mode_config.mutex);
+
+	for (i = 0; i < connector_count; i++) {
+		struct drm_display_mode *mode = modes[i];
+		struct drm_crtc *crtc = crtcs[i];
+		struct drm_client_offset *offset = &offsets[i];
+
+		if (mode && crtc) {
+			struct drm_mode_set *modeset = drm_client_find_modeset(modesets, crtc);
+			struct drm_connector *connector = connectors[i];
+
+			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
+				      mode->name, crtc->base.id, offset->x, offset->y);
+
+			if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
+					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1)))
+				break;
+
+			modeset->mode = drm_mode_duplicate(dev, mode);
+			drm_connector_get(connector);
+			modeset->connectors[modeset->num_connectors++] = connector;
+			modeset->x = offset->x;
+			modeset->y = offset->y;
+		}
+	}
+out:
+	kfree(crtcs);
+	kfree(modes);
+	kfree(offsets);
+	kfree(enabled);
+free_connectors:
+	if (connectors) {
+		for (i = 0; i < connector_count; i++)
+			drm_connector_put(connectors[i]);
+		kfree(connectors);
+	}
+
+	if (ret) {
+		drm_client_modesets_release(modesets);
+		return ERR_PTR(ret);
+	}
+
+	return modesets;
+}
+EXPORT_SYMBOL(drm_client_modesets_probe);
+
 /**
  * drm_client_panel_rotation() - Check panel orientation
  * @modeset: DRM modeset
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index afe4d4220e4d..4a073cd4e423 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -40,14 +40,6 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_atomic.h>
-#include <drm/drm_atomic_helper.h>
-
-#include "drm_crtc_internal.h"
-#include "drm_crtc_helper_internal.h"
-
-struct drm_client_offset {
-	int x, y;
-};
 
 static bool drm_fbdev_emulation = true;
 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
@@ -1687,695 +1679,6 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
 }
 EXPORT_SYMBOL(drm_fb_helper_fill_var);
 
-static struct drm_display_mode *
-drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height)
-{
-	struct drm_display_mode *mode;
-
-	list_for_each_entry(mode, &connector->modes, head) {
-		if (mode->hdisplay > width ||
-		    mode->vdisplay > height)
-			continue;
-		if (mode->type & DRM_MODE_TYPE_PREFERRED)
-			return mode;
-	}
-	return NULL;
-}
-
-static struct drm_display_mode *
-drm_connector_pick_cmdline_mode(struct drm_connector *connector)
-{
-	struct drm_cmdline_mode *cmdline_mode;
-	struct drm_display_mode *mode;
-	bool prefer_non_interlace;
-
-	cmdline_mode = &connector->cmdline_mode;
-	if (cmdline_mode->specified == false)
-		return NULL;
-
-	/* attempt to find a matching mode in the list of modes
-	 *  we have gotten so far, if not add a CVT mode that conforms
-	 */
-	if (cmdline_mode->rb || cmdline_mode->margins)
-		goto create_mode;
-
-	prefer_non_interlace = !cmdline_mode->interlace;
-again:
-	list_for_each_entry(mode, &connector->modes, head) {
-		/* check width/height */
-		if (mode->hdisplay != cmdline_mode->xres ||
-		    mode->vdisplay != cmdline_mode->yres)
-			continue;
-
-		if (cmdline_mode->refresh_specified) {
-			if (mode->vrefresh != cmdline_mode->refresh)
-				continue;
-		}
-
-		if (cmdline_mode->interlace) {
-			if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
-				continue;
-		} else if (prefer_non_interlace) {
-			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-				continue;
-		}
-		return mode;
-	}
-
-	if (prefer_non_interlace) {
-		prefer_non_interlace = false;
-		goto again;
-	}
-
-create_mode:
-	mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
-	list_add(&mode->head, &connector->modes);
-	return mode;
-}
-
-static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
-{
-	bool enable;
-
-	if (connector->display_info.non_desktop)
-		return false;
-
-	if (strict)
-		enable = connector->status == connector_status_connected;
-	else
-		enable = connector->status != connector_status_disconnected;
-
-	return enable;
-}
-
-static void drm_client_connectors_enabled(struct drm_connector **connectors,
-					  unsigned int connector_count,
-					  bool *enabled)
-{
-	bool any_enabled = false;
-	struct drm_connector *connector;
-	int i = 0;
-
-	for (i = 0; i < connector_count; i++) {
-		connector = connectors[i];
-		enabled[i] = drm_connector_enabled(connector, true);
-		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
-			      connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");
-
-		any_enabled |= enabled[i];
-	}
-
-	if (any_enabled)
-		return;
-
-	for (i = 0; i < connector_count; i++)
-		enabled[i] = drm_connector_enabled(connectors[i], false);
-}
-
-static bool drm_client_target_cloned(struct drm_device *dev,
-				     struct drm_connector **connectors,
-				     unsigned int connector_count,
-				     struct drm_display_mode **modes,
-				     struct drm_client_offset *offsets,
-				     bool *enabled, int width, int height)
-{
-	int count, i, j;
-	bool can_clone = false;
-	struct drm_display_mode *dmt_mode, *mode;
-
-	/* only contemplate cloning in the single crtc case */
-	if (dev->mode_config.num_crtc > 1)
-		return false;
-
-	count = 0;
-	for (i = 0; i < connector_count; i++) {
-		if (enabled[i])
-			count++;
-	}
-
-	/* only contemplate cloning if more than one connector is enabled */
-	if (count <= 1)
-		return false;
-
-	/* check the command line or if nothing common pick 1024x768 */
-	can_clone = true;
-	for (i = 0; i < connector_count; i++) {
-		if (!enabled[i])
-			continue;
-		modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
-		if (!modes[i]) {
-			can_clone = false;
-			break;
-		}
-		for (j = 0; j < i; j++) {
-			if (!enabled[j])
-				continue;
-			if (!drm_mode_match(modes[j], modes[i],
-					    DRM_MODE_MATCH_TIMINGS |
-					    DRM_MODE_MATCH_CLOCK |
-					    DRM_MODE_MATCH_FLAGS |
-					    DRM_MODE_MATCH_3D_FLAGS))
-				can_clone = false;
-		}
-	}
-
-	if (can_clone) {
-		DRM_DEBUG_KMS("can clone using command line\n");
-		return true;
-	}
-
-	/* try and find a 1024x768 mode on each connector */
-	can_clone = true;
-	dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
-
-	for (i = 0; i < connector_count; i++) {
-		if (!enabled[i])
-			continue;
-
-		list_for_each_entry(mode, &connectors[i]->modes, head) {
-			if (drm_mode_match(mode, dmt_mode,
-					   DRM_MODE_MATCH_TIMINGS |
-					   DRM_MODE_MATCH_CLOCK |
-					   DRM_MODE_MATCH_FLAGS |
-					   DRM_MODE_MATCH_3D_FLAGS))
-				modes[i] = mode;
-		}
-		if (!modes[i])
-			can_clone = false;
-	}
-
-	if (can_clone) {
-		DRM_DEBUG_KMS("can clone using 1024x768\n");
-		return true;
-	}
-	DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
-	return false;
-}
-
-static int drm_client_get_tile_offsets(struct drm_connector **connectors,
-				       unsigned int connector_count,
-				       struct drm_display_mode **modes,
-				       struct drm_client_offset *offsets,
-				       int idx,
-				       int h_idx, int v_idx)
-{
-	struct drm_connector *connector;
-	int i;
-	int hoffset = 0, voffset = 0;
-
-	for (i = 0; i < connector_count; i++) {
-		connector = connectors[i];
-		if (!connector->has_tile)
-			continue;
-
-		if (!modes[i] && (h_idx || v_idx)) {
-			DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
-				      connector->base.id);
-			continue;
-		}
-		if (connector->tile_h_loc < h_idx)
-			hoffset += modes[i]->hdisplay;
-
-		if (connector->tile_v_loc < v_idx)
-			voffset += modes[i]->vdisplay;
-	}
-	offsets[idx].x = hoffset;
-	offsets[idx].y = voffset;
-	DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
-	return 0;
-}
-
-static bool drm_client_target_preferred(struct drm_connector **connectors,
-					unsigned int connector_count,
-					struct drm_display_mode **modes,
-					struct drm_client_offset *offsets,
-					bool *enabled, int width, int height)
-{
-	const u64 mask = BIT_ULL(connector_count) - 1;
-	struct drm_connector *connector;
-	u64 conn_configured = 0;
-	int tile_pass = 0;
-	int i;
-
-retry:
-	for (i = 0; i < connector_count; i++) {
-		connector = connectors[i];
-
-		if (conn_configured & BIT_ULL(i))
-			continue;
-
-		if (enabled[i] == false) {
-			conn_configured |= BIT_ULL(i);
-			continue;
-		}
-
-		/* first pass over all the untiled connectors */
-		if (tile_pass == 0 && connector->has_tile)
-			continue;
-
-		if (tile_pass == 1) {
-			if (connector->tile_h_loc != 0 ||
-			    connector->tile_v_loc != 0)
-				continue;
-
-		} else {
-			if (connector->tile_h_loc != tile_pass - 1 &&
-			    connector->tile_v_loc != tile_pass - 1)
-			/* if this tile_pass doesn't cover any of the tiles - keep going */
-				continue;
-
-			/*
-			 * find the tile offsets for this pass - need to find
-			 * all tiles left and above
-			 */
-			drm_client_get_tile_offsets(connectors, connector_count, modes, offsets, i,
-						    connector->tile_h_loc, connector->tile_v_loc);
-		}
-		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
-			      connector->base.id);
-
-		/* got for command line mode first */
-		modes[i] = drm_connector_pick_cmdline_mode(connector);
-		if (!modes[i]) {
-			DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
-				      connector->base.id, connector->tile_group ? connector->tile_group->id : 0);
-			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
-		}
-		/* No preferred modes, pick one off the list */
-		if (!modes[i] && !list_empty(&connector->modes)) {
-			list_for_each_entry(modes[i], &connector->modes, head)
-				break;
-		}
-		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
-			  "none");
-		conn_configured |= BIT_ULL(i);
-	}
-
-	if ((conn_configured & mask) != mask) {
-		tile_pass++;
-		goto retry;
-	}
-	return true;
-}
-
-static bool connector_has_possible_crtc(struct drm_connector *connector,
-					struct drm_crtc *crtc)
-{
-	struct drm_encoder *encoder;
-	int i;
-
-	drm_connector_for_each_possible_encoder(connector, encoder, i) {
-		if (encoder->possible_crtcs & drm_crtc_mask(crtc))
-			return true;
-	}
-
-	return false;
-}
-
-static int drm_client_pick_crtcs(struct drm_device *dev,
-				 struct drm_mode_set *modesets,
-				 struct drm_connector **connectors,
-				 unsigned int connector_count,
-				 struct drm_crtc **best_crtcs,
-				 struct drm_display_mode **modes,
-				 int n, int width, int height)
-{
-	struct drm_connector *connector;
-	int my_score, best_score, score;
-	struct drm_crtc **crtcs, *crtc;
-	struct drm_mode_set *modeset;
-	int o;
-
-	if (n == connector_count)
-		return 0;
-
-	connector = connectors[n];
-
-	best_crtcs[n] = NULL;
-	best_score = drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
-					   best_crtcs, modes, n + 1, width, height);
-	if (modes[n] == NULL)
-		return best_score;
-
-	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
-	if (!crtcs)
-		return best_score;
-
-	my_score = 1;
-	if (connector->status == connector_status_connected)
-		my_score++;
-	if (connector->cmdline_mode.specified)
-		my_score++;
-	if (drm_connector_has_preferred_mode(connector, width, height))
-		my_score++;
-
-	/*
-	 * select a crtc for this connector and then attempt to configure
-	 * remaining connectors
-	 */
-	drm_client_for_each_modeset(modeset, modesets) {
-		crtc = modeset->crtc;
-
-		if (!connector_has_possible_crtc(connector, crtc))
-			continue;
-
-		for (o = 0; o < n; o++)
-			if (best_crtcs[o] == crtc)
-				break;
-
-		if (o < n) {
-			/* ignore cloning unless only a single crtc */
-			if (dev->mode_config.num_crtc > 1)
-				continue;
-
-			if (!drm_mode_equal(modes[o], modes[n]))
-				continue;
-		}
-
-		crtcs[n] = crtc;
-		memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
-		score = my_score + drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
-							 crtcs, modes, n + 1, width, height);
-		if (score > best_score) {
-			best_score = score;
-			memcpy(best_crtcs, crtcs, connector_count * sizeof(*crtcs));
-		}
-	}
-
-	kfree(crtcs);
-	return best_score;
-}
-
-/* Try to read the BIOS display configuration and use it for the initial config */
-static bool drm_client_firmware_config(struct drm_device *dev,
-				       struct drm_connector **connectors,
-				       unsigned int connector_count,
-				       struct drm_crtc **crtcs,
-				       struct drm_display_mode **modes,
-				       struct drm_client_offset *offsets,
-				       bool *enabled, int width, int height)
-{
-	unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
-	unsigned long conn_configured, conn_seq;
-	int i, j;
-	bool *save_enabled;
-	bool fallback = true, ret = true;
-	int num_connectors_enabled = 0;
-	int num_connectors_detected = 0;
-	struct drm_modeset_acquire_ctx ctx;
-
-	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
-	if (!save_enabled)
-		return false;
-
-	drm_modeset_acquire_init(&ctx, 0);
-
-	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
-		drm_modeset_backoff(&ctx);
-
-	memcpy(save_enabled, enabled, count);
-	conn_seq = GENMASK(count - 1, 0);
-	conn_configured = 0;
-retry:
-	for (i = 0; i < count; i++) {
-		struct drm_connector *connector;
-		struct drm_encoder *encoder;
-		struct drm_crtc *new_crtc;
-
-		connector = connectors[i];
-
-		if (conn_configured & BIT(i))
-			continue;
-
-		/* First pass, only consider tiled connectors */
-		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
-			continue;
-
-		if (connector->status == connector_status_connected)
-			num_connectors_detected++;
-
-		if (!enabled[i]) {
-			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
-				      connector->name);
-			conn_configured |= BIT(i);
-			continue;
-		}
-
-		if (connector->force == DRM_FORCE_OFF) {
-			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
-				      connector->name);
-			enabled[i] = false;
-			continue;
-		}
-
-		encoder = connector->state->best_encoder;
-		if (!encoder || WARN_ON(!connector->state->crtc)) {
-			if (connector->force > DRM_FORCE_OFF)
-				goto bail;
-
-			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
-				      connector->name);
-			enabled[i] = false;
-			conn_configured |= BIT(i);
-			continue;
-		}
-
-		num_connectors_enabled++;
-
-		new_crtc = connector->state->crtc;
-
-		/*
-		 * Make sure we're not trying to drive multiple connectors
-		 * with a single CRTC, since our cloning support may not
-		 * match the BIOS.
-		 */
-		for (j = 0; j < count; j++) {
-			if (crtcs[j] == new_crtc) {
-				DRM_DEBUG_KMS("fallback: cloned configuration\n");
-				goto bail;
-			}
-		}
-
-		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
-			      connector->name);
-
-		/* go for command line mode first */
-		modes[i] = drm_connector_pick_cmdline_mode(connector);
-
-		/* try for preferred next */
-		if (!modes[i]) {
-			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
-				      connector->name, connector->has_tile);
-			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
-		}
-
-		/* No preferred mode marked by the EDID? Are there any modes? */
-		if (!modes[i] && !list_empty(&connector->modes)) {
-			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
-				      connector->name);
-			modes[i] = list_first_entry(&connector->modes,
-						    struct drm_display_mode,
-						    head);
-		}
-
-		/* last resort: use current mode */
-		if (!modes[i]) {
-			/*
-			 * IMPORTANT: We want to use the adjusted mode (i.e.
-			 * after the panel fitter upscaling) as the initial
-			 * config, not the input mode, which is what crtc->mode
-			 * usually contains. But since our current
-			 * code puts a mode derived from the post-pfit timings
-			 * into crtc->mode this works out correctly.
-			 *
-			 * This is crtc->mode and not crtc->state->mode for the
-			 * fastboot check to work correctly.
-			 */
-			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
-				      connector->name);
-			modes[i] = &connector->state->crtc->mode;
-		}
-		crtcs[i] = new_crtc;
-
-		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
-			      connector->name,
-			      connector->state->crtc->base.id,
-			      connector->state->crtc->name,
-			      modes[i]->hdisplay, modes[i]->vdisplay,
-			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
-
-		fallback = false;
-		conn_configured |= BIT(i);
-	}
-
-	if (conn_configured != conn_seq) { /* repeat until no more are found */
-		conn_seq = conn_configured;
-		goto retry;
-	}
-
-	/*
-	 * If the BIOS didn't enable everything it could, fall back to have the
-	 * same user experiencing of lighting up as much as possible like the
-	 * fbdev helper library.
-	 */
-	if (num_connectors_enabled != num_connectors_detected &&
-	    num_connectors_enabled < dev->mode_config.num_crtc) {
-		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
-		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
-			      num_connectors_detected);
-		fallback = true;
-	}
-
-	if (fallback) {
-bail:
-		DRM_DEBUG_KMS("Not using firmware configuration\n");
-		memcpy(enabled, save_enabled, count);
-		ret = false;
-	}
-
-	drm_modeset_drop_locks(&ctx);
-	drm_modeset_acquire_fini(&ctx);
-
-	kfree(save_enabled);
-	return ret;
-}
-
-/**
- * drm_client_modesets_probe() - Probe for displays
- * @dev: DRM device
- * @width: Maximum display mode width (optional)
- * @height: Maximum display mode height (optional)
- *
- * This function tries to set up pipelines for enabled connectors and returns
- * the CRTC config as a &drm_mode_set array.
- *
- * Use drm_client_modesets_release() to free the array and its resources.
- *
- * Returns:
- * A &drm_mode_set array on success, NULL if no connectors are found
- * or error pointer on failure.
- */
-struct drm_mode_set *
-drm_client_modesets_probe(struct drm_device *dev, unsigned int width, unsigned int height)
-{
-	struct drm_connector *connector, **connectors = NULL;
-	struct drm_connector_list_iter conn_iter;
-	struct drm_mode_set *modesets = NULL;
-	unsigned int total_modes_count = 0;
-	struct drm_client_offset *offsets;
-	unsigned int connector_count = 0;
-	struct drm_display_mode **modes;
-	struct drm_crtc **crtcs;
-	int i, ret = 0;
-	bool *enabled;
-
-	DRM_DEBUG_KMS("\n");
-
-	if (!width)
-		width = dev->mode_config.max_width;
-	if (!height)
-		height = dev->mode_config.max_height;
-
-	drm_connector_list_iter_begin(dev, &conn_iter);
-	drm_client_for_each_connector_iter(connector, &conn_iter) {
-		struct drm_connector **tmp;
-
-		tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
-		if (!tmp) {
-			ret = -ENOMEM;
-			goto free_connectors;
-		}
-
-		connectors = tmp;
-		drm_connector_get(connector);
-		connectors[connector_count++] = connector;
-	}
-	drm_connector_list_iter_end(&conn_iter);
-
-	if (!connector_count)
-		return NULL;
-
-	modesets = drm_client_modesets_create(dev);
-	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
-	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
-	offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
-	enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
-	if (IS_ERR(modesets) || !crtcs || !modes || !enabled || !offsets) {
-		DRM_ERROR("Memory allocation failed\n");
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	mutex_lock(&dev->mode_config.mutex);
-	for (i = 0; i < connector_count; i++)
-		total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
-	if (!total_modes_count)
-		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
-	drm_client_connectors_enabled(connectors, connector_count, enabled);
-
-	if (!drm_client_firmware_config(dev, connectors, connector_count, crtcs,
-					modes, offsets, enabled, width, height)) {
-		memset(modes, 0, connector_count * sizeof(*modes));
-		memset(crtcs, 0, connector_count * sizeof(*crtcs));
-		memset(offsets, 0, connector_count * sizeof(*offsets));
-
-		if (!drm_client_target_cloned(dev, connectors, connector_count, modes,
-					      offsets, enabled, width, height) &&
-		    !drm_client_target_preferred(connectors, connector_count, modes,
-						 offsets, enabled, width, height))
-			DRM_ERROR("Unable to find initial modes\n");
-
-		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
-			      width, height);
-
-		drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
-				      crtcs, modes, 0, width, height);
-	}
-	mutex_unlock(&dev->mode_config.mutex);
-
-	for (i = 0; i < connector_count; i++) {
-		struct drm_display_mode *mode = modes[i];
-		struct drm_crtc *crtc = crtcs[i];
-		struct drm_client_offset *offset = &offsets[i];
-
-		if (mode && crtc) {
-			struct drm_mode_set *modeset = drm_client_find_modeset(modesets, crtc);
-			struct drm_connector *connector = connectors[i];
-
-			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
-				      mode->name, crtc->base.id, offset->x, offset->y);
-
-			if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
-					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1)))
-				break;
-
-			modeset->mode = drm_mode_duplicate(dev, mode);
-			drm_connector_get(connector);
-			modeset->connectors[modeset->num_connectors++] = connector;
-			modeset->x = offset->x;
-			modeset->y = offset->y;
-		}
-	}
-out:
-	kfree(crtcs);
-	kfree(modes);
-	kfree(offsets);
-	kfree(enabled);
-free_connectors:
-	if (connectors) {
-		for (i = 0; i < connector_count; i++)
-			drm_connector_put(connectors[i]);
-		kfree(connectors);
-	}
-
-	if (ret) {
-		drm_client_modesets_release(modesets);
-		return ERR_PTR(ret);
-	}
-
-	return modesets;
-}
-
 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, u32 width, u32 height)
 {
 	struct drm_mode_set *modesets;
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index a55f5ecae64a..78fb82bd8371 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -16,8 +16,6 @@ struct drm_gem_object;
 struct drm_minor;
 struct module;
 
-#define DRM_CLIENT_MAX_CLONED_CONNECTORS	8
-
 /**
  * struct drm_client_funcs - DRM client callbacks
  */
@@ -143,6 +141,8 @@ void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
 struct drm_mode_set *drm_client_modesets_create(struct drm_device *dev);
 void drm_client_modesets_release(struct drm_mode_set *modesets);
 struct drm_mode_set *drm_client_find_modeset(struct drm_mode_set *modesets, struct drm_crtc *crtc);
+struct drm_mode_set *
+drm_client_modesets_probe(struct drm_device *dev, unsigned int width, unsigned int height);
 bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
 int drm_client_modesets_commit(struct drm_device *dev, struct drm_mode_set *modesets);
 void drm_client_modesets_dpms(struct drm_device *dev, struct drm_mode_set *modesets, int mode);
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 13/16] drm/fb-helper: Avoid race with DRM userspace
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (11 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 12/16] drm/fb-helper: Move " Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-28  8:17   ` Daniel Vetter
  2019-03-26 17:55 ` [PATCH 14/16] drm/client: Add display abstraction Noralf Trønnes
                   ` (4 subsequent siblings)
  17 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: Daniel Vetter, intel-gfx, Noralf Trønnes, mstaudt

drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
This is done by looking at the fb on the primary plane. By the time
fb-helper gets around to committing, it's possible that the facts have
changed.

Avoid this race by holding the drm_device->master_mutex lock while
committing. When DRM userspace does its first open, it will now wait
until fb-helper is done. The helper will stay away if there's a master.

Locking rule: Always take the fb-helper lock first.

Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_auth.c      | 20 ++++++++++++++
 drivers/gpu/drm/drm_fb_helper.c | 49 ++++++++++++++++++++++++---------
 drivers/gpu/drm/drm_internal.h  |  2 ++
 3 files changed, 58 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index 1669c42c40ed..db199807b7dc 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -368,3 +368,23 @@ void drm_master_put(struct drm_master **master)
 	*master = NULL;
 }
 EXPORT_SYMBOL(drm_master_put);
+
+/* Used by drm_client and drm_fb_helper */
+bool drm_master_internal_acquire(struct drm_device *dev)
+{
+	mutex_lock(&dev->master_mutex);
+	if (dev->master) {
+		mutex_unlock(&dev->master_mutex);
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL(drm_master_internal_acquire);
+
+/* Used by drm_client and drm_fb_helper */
+void drm_master_internal_release(struct drm_device *dev)
+{
+	mutex_unlock(&dev->master_mutex);
+}
+EXPORT_SYMBOL(drm_master_internal_release);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 4a073cd4e423..9f253fcf3f79 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -41,6 +41,8 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_atomic.h>
 
+#include "drm_internal.h"
+
 static bool drm_fbdev_emulation = true;
 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
 MODULE_PARM_DESC(fbdev_emulation,
@@ -235,7 +237,12 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
 		return 0;
 
 	mutex_lock(&fb_helper->lock);
-	ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
+	if (drm_master_internal_acquire(fb_helper->dev)) {
+		ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
+		drm_master_internal_release(fb_helper->dev);
+	} else {
+		ret = -EBUSY;
+	}
 
 	do_delayed = fb_helper->delayed_hotplug;
 	if (do_delayed)
@@ -332,13 +339,16 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 {
 	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
 
 	/*
 	 * For each CRTC in this fb, turn the connectors on/off.
 	 */
 	mutex_lock(&fb_helper->lock);
-	if (drm_fb_helper_is_bound(fb_helper))
-		drm_client_modesets_dpms(fb_helper->dev, fb_helper->modesets, dpms_mode);
+	if (drm_master_internal_acquire(dev)) {
+		drm_client_modesets_dpms(dev, fb_helper->modesets, dpms_mode);
+		drm_master_internal_release(dev);
+	}
 	mutex_unlock(&fb_helper->lock);
 }
 
@@ -1097,6 +1107,7 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
 {
 	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
 	int ret;
 
 	if (oops_in_progress)
@@ -1104,9 +1115,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
 
 	mutex_lock(&fb_helper->lock);
 
-	if (!drm_fb_helper_is_bound(fb_helper)) {
+	if (!drm_master_internal_acquire(dev)) {
 		ret = -EBUSY;
-		goto out;
+		goto unlock;
 	}
 
 	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
@@ -1116,7 +1127,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
 	else
 		ret = setcmap_legacy(cmap, info);
 
-out:
+	drm_master_internal_release(dev);
+unlock:
 	mutex_unlock(&fb_helper->lock);
 
 	return ret;
@@ -1136,11 +1148,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
 	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
 	struct drm_crtc *crtc;
 	int ret = 0;
 
 	mutex_lock(&fb_helper->lock);
-	if (!drm_fb_helper_is_bound(fb_helper)) {
+
+	if (!drm_master_internal_acquire(dev)) {
 		ret = -EBUSY;
 		goto unlock;
 	}
@@ -1177,13 +1191,15 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 		}
 
 		ret = 0;
-		goto unlock;
+		break;
 	default:
 		ret = -ENOTTY;
 	}
 
+	drm_master_internal_release(dev);
 unlock:
 	mutex_unlock(&fb_helper->lock);
+
 	return ret;
 }
 EXPORT_SYMBOL(drm_fb_helper_ioctl);
@@ -1426,15 +1442,19 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
 		return -EBUSY;
 
 	mutex_lock(&fb_helper->lock);
-	if (!drm_fb_helper_is_bound(fb_helper)) {
-		mutex_unlock(&fb_helper->lock);
-		return -EBUSY;
+
+	if (!drm_master_internal_acquire(dev)) {
+		ret = -EBUSY;
+		goto unlock;
 	}
 
 	if (drm_drv_uses_atomic_modeset(dev))
 		ret = pan_display_atomic(var, info);
 	else
 		ret = pan_display_legacy(var, info);
+
+	drm_master_internal_release(dev);
+unlock:
 	mutex_unlock(&fb_helper->lock);
 
 	return ret;
@@ -1451,6 +1471,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	int ret = 0;
 	int crtc_count = 0;
 	struct drm_connector_list_iter conn_iter;
+	struct drm_device *dev = fb_helper->dev;
 	struct drm_fb_helper_surface_size sizes;
 	struct drm_connector *connector;
 	struct drm_mode_set *mode_set;
@@ -1593,8 +1614,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 		DRM_INFO("Cannot find any crtc or sizes\n");
 
 		/* First time: disable all crtc's.. */
-		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
-			drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
+		if (!fb_helper->deferred_setup && drm_master_internal_acquire(dev)) {
+			drm_client_modesets_commit(dev, fb_helper->modesets);
+			drm_master_internal_release(dev);
+		}
 		return -EAGAIN;
 	}
 
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index 251d67e04c2d..6d5d1184c084 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -91,6 +91,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
 			 struct drm_file *file_priv);
 int drm_master_open(struct drm_file *file_priv);
 void drm_master_release(struct drm_file *file_priv);
+bool drm_master_internal_acquire(struct drm_device *dev);
+void drm_master_internal_release(struct drm_device *dev);
 
 /* drm_sysfs.c */
 extern struct class *drm_class;
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 14/16] drm/client: Add display abstraction
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (12 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 13/16] drm/fb-helper: Avoid race with DRM userspace Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 15/16] drm/client: Hack: Add bootsplash example Noralf Trønnes
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes, mstaudt

Add display abstraction and helpers to probe for displays and commit
modesets.

TODO:
If the bootsplash client doesn't need to subclass drm_client_display,
the callbacks can be removed.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_client.c | 415 +++++++++++++++++++++++++++++++++++
 include/drm/drm_client.h     |  80 +++++++
 2 files changed, 495 insertions(+)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 3bc96b0b30ec..ef01a31a9dbe 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/list.h>
+#include <linux/list_sort.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/seq_file.h>
@@ -106,6 +107,9 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
 
 	drm_dev_get(dev);
 
+	mutex_init(&client->displaylist_mutex);
+	INIT_LIST_HEAD(&client->displaylist);
+
 	return 0;
 
 err_put_module:
@@ -156,6 +160,9 @@ void drm_client_release(struct drm_client_dev *client)
 
 	DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name);
 
+	drm_client_release_displays(client);
+	mutex_destroy(&client->displaylist_mutex);
+
 	drm_client_close(client);
 	drm_dev_put(dev);
 	if (client->funcs)
@@ -1419,6 +1426,414 @@ void drm_client_modesets_dpms(struct drm_device *dev, struct drm_mode_set *modes
 }
 EXPORT_SYMBOL(drm_client_modesets_dpms);
 
+static struct drm_client_display *
+drm_client_display_alloc(struct drm_client_dev *client, unsigned int num_modesets)
+{
+	struct drm_client_display *display;
+	struct drm_mode_set *modesets;
+
+	modesets = kcalloc(num_modesets + 1, sizeof(*modesets), GFP_KERNEL);
+	if (!modesets)
+		return ERR_PTR(-ENOMEM);
+
+	if (client->funcs && client->funcs->display_alloc)
+		display = client->funcs->display_alloc(client);
+	else
+		display = kzalloc(sizeof(*display), GFP_KERNEL);
+	if (!display)
+		display = ERR_PTR(-ENOMEM);
+
+	if (IS_ERR(display)) {
+		kfree(modesets);
+		return display;
+	}
+
+	display->client = client;
+	display->modesets = modesets;
+
+	return display;
+}
+
+static void drm_client_display_release(struct drm_client_display *display)
+{
+	unsigned int i;
+
+	if (!display)
+		return;
+
+	for (i = 0; i < display->num_buffers; i++)
+		drm_client_framebuffer_delete(display->buffers[i]);
+	kfree(display->buffers);
+
+	drm_mode_destroy(display->client->dev, display->mode);
+
+	drm_client_modesets_release(display->modesets);
+
+	if (display->client->funcs && display->client->funcs->display_free)
+		display->client->funcs->display_free(display);
+	else
+		kfree(display);
+}
+
+static void drm_client_display_debugprint(struct drm_client_display *display)
+{
+	struct drm_display_mode *mode = display->mode;
+	struct drm_mode_set *modeset;
+	unsigned int i;
+
+	DRM_DEBUG_KMS("  %dx%d %dHz\n", mode->hdisplay, mode->vdisplay, mode->vrefresh);
+
+	drm_client_for_each_modeset(modeset, display->modesets) {
+		DRM_DEBUG_KMS("    crtc=%d, connectors:", modeset->crtc->base.id);
+		for (i = 0; i < modeset->num_connectors; i++)
+			DRM_DEBUG_KMS("      %s\n", modeset->connectors[i]->name);
+	}
+}
+
+static bool drm_client_modeset_equal(struct drm_mode_set *modeset1, struct drm_mode_set *modeset2)
+{
+	unsigned int i;
+
+	if (modeset1->crtc != modeset2->crtc ||
+	    !drm_mode_equal(modeset1->mode, modeset2->mode) ||
+	    modeset1->x != modeset2->x || modeset1->y != modeset2->y ||
+	    modeset1->num_connectors != modeset2->num_connectors)
+		return false;
+
+	for (i = 0; i < modeset1->num_connectors; i++) {
+		if (modeset1->connectors[i] != modeset2->connectors[i])
+			return false;
+	}
+
+	return true;
+}
+
+static bool drm_client_display_equal(struct drm_client_display *display1,
+				     struct drm_client_display *display2)
+{
+	struct drm_mode_set *modeset1, *modeset2;
+
+	if (!display1 || !display2)
+		return false;
+
+	if (display1 == display2)
+		return true;
+
+	if (!drm_mode_equal(display1->mode, display2->mode))
+		return false;
+
+	for (modeset1 = display1->modesets, modeset2 = display2->modesets;
+	     modeset1->crtc && modeset2->crtc; modeset1++, modeset2++)
+		if (!drm_client_modeset_equal(modeset1, modeset2))
+			return false;
+
+	return !modeset1->crtc && !modeset2->crtc;
+}
+
+static int drm_client_display_framebuffer_create(struct drm_client_display *display,
+						 unsigned int num_buffers, u32 format)
+{
+	struct drm_client_buffer **buffers;
+	struct drm_mode_set *modeset;
+	unsigned int i;
+	int ret;
+
+	if (!display || !display->mode)
+		return -EINVAL;
+
+	if (display->num_buffers && display->num_buffers != num_buffers)
+		return -EINVAL;
+
+	if (display->num_buffers == num_buffers)
+		return 0;
+
+	buffers = kcalloc(num_buffers, sizeof(*buffers), GFP_KERNEL);
+	if (!buffers)
+		return -ENOMEM;
+
+	for (i = 0; i < num_buffers; i++) {
+		buffers[i] = drm_client_framebuffer_create(display->client, display->mode->hdisplay,
+							   display->mode->vdisplay, format);
+		if (IS_ERR(buffers[i])) {
+			ret = PTR_ERR(buffers[i]);
+			goto err_free;
+		}
+	}
+
+	display->buffers = buffers;
+	display->num_buffers = num_buffers;
+
+	drm_client_for_each_modeset(modeset, display->modesets)
+		modeset->fb = display->buffers[0]->fb;
+
+	return 0;
+
+err_free:
+	for (i = 0; i < num_buffers; i++) {
+		if (!IS_ERR_OR_NULL(buffers[i]))
+			drm_client_framebuffer_delete(buffers[i]);
+	}
+	kfree(buffers);
+
+	return ret;
+}
+
+static int drm_client_find_displays(struct drm_client_dev *client, struct list_head *displaylist)
+{
+	struct drm_mode_set *modeset, *modesets;
+	struct drm_device *dev = client->dev;
+	struct drm_client_display *display;
+	unsigned int num_modesets = 0;
+	int ret = 0;
+
+	modesets = drm_client_modesets_probe(dev, 0, 0);
+	if (IS_ERR_OR_NULL(modesets))
+		return PTR_ERR_OR_ZERO(modesets);
+
+	/* TODO: Support more than one tiled monitor? */
+	display = NULL;
+	drm_client_for_each_modeset(modeset, modesets) {
+		if (!modeset->mode || !modeset->connectors[0]->has_tile)
+			continue;
+
+		if (!display) {
+			display = drm_client_display_alloc(client, dev->mode_config.num_crtc);
+			if (IS_ERR(display)) {
+				ret = PTR_ERR(display);
+				goto err_free;
+			}
+
+			list_add(&display->list, displaylist);
+		}
+
+		display->modesets[num_modesets++] = *modeset;
+		modeset->num_connectors = 0;
+		modeset->connectors = NULL;
+		modeset->mode = NULL;
+	}
+
+	/* Contruct a mode for the tiled monitor */
+	if (display) {
+		int hdisplay = 0, vdisplay = 0, vrefresh = 0;
+
+		drm_client_for_each_modeset(modeset, display->modesets) {
+			if (!modeset->y)
+				hdisplay += modeset->mode->hdisplay;
+			if (!modeset->x)
+				vdisplay += modeset->mode->vdisplay;
+			vrefresh = modeset->mode->vrefresh;
+		}
+
+		display->mode = drm_cvt_mode(dev, hdisplay, vdisplay, vrefresh, false, false, false);
+		if (!display->mode) {
+			ret = -ENOMEM;
+			goto err_free;
+		}
+	}
+
+	/* The rest have one display per modeset */
+	drm_client_for_each_modeset(modeset, modesets) {
+		if (!modeset->mode || modeset->connectors[0]->has_tile)
+			continue;
+
+		display = drm_client_display_alloc(client, 1);
+		if (IS_ERR(display)) {
+			ret = PTR_ERR(display);
+			goto err_free;
+		}
+
+		list_add(&display->list, displaylist);
+		display->modesets[0] = *modeset;
+		modeset->num_connectors = 0;
+		modeset->connectors = NULL;
+		modeset->mode = NULL;
+
+		display->mode = drm_mode_duplicate(dev, display->modesets[0].mode);
+		if (!display->mode) {
+			ret = -ENOMEM;
+			goto err_free;
+		}
+	}
+
+	goto out;
+
+err_free:
+	list_for_each_entry(display, displaylist, list)
+		drm_client_display_release(display);
+out:
+	drm_client_modesets_release(modesets);
+
+	return ret;
+}
+
+static int drm_client_displays_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b)
+{
+	struct drm_client_display *a = list_entry(lh_a, struct drm_client_display, list);
+	struct drm_client_display *b = list_entry(lh_b, struct drm_client_display, list);
+
+	return b->mode->hdisplay * b->mode->vdisplay - a->mode->hdisplay * a->mode->vdisplay;
+}
+
+static void drm_client_displays_sort(struct list_head *displaylist)
+{
+	list_sort(NULL, displaylist, drm_client_displays_compare);
+}
+
+/**
+ * drm_client_probe_displays() - Probe for displays
+ * @client: DRM client
+ * @num_buffers: Number of buffers to attach (optional)
+ * @format: Buffer format
+ *
+ * This function probes for connected displays and updates the clients list of displays.
+ * The list is sorted from largest to smallest.
+ *
+ * Returns:
+ * Number of displays or negative error code on failure.
+ */
+int drm_client_probe_displays(struct drm_client_dev *client, unsigned int num_buffers, u32 format)
+{
+	struct drm_client_display *display, *tmp;
+	LIST_HEAD(displaylist);
+	bool changed = false;
+	int ret;
+
+	ret = drm_client_find_displays(client, &displaylist);
+	if (ret < 0)
+		return ret;
+
+	if (list_empty(&displaylist)) {
+		drm_client_release_displays(client);
+		return 0;
+	}
+
+	mutex_lock(&client->displaylist_mutex);
+
+	/* If a display hasn't changed, keep it to avoid reallocating buffers */
+	list_for_each_entry_safe(display, tmp, &client->displaylist, list) {
+		struct drm_client_display *display2, *tmp2;
+		bool found = false;
+
+		list_for_each_entry_safe(display2, tmp2, &displaylist, list) {
+			if (drm_client_display_equal(display, display2)) {
+				list_del(&display2->list);
+				drm_client_display_release(display2);
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			list_del(&display->list);
+			drm_client_display_release(display);
+			changed = true;
+		}
+	}
+
+	if (!list_empty(&displaylist))
+		changed = true;
+
+	list_splice(&displaylist, &client->displaylist);
+
+	/* Sort from largest to smallest */
+	drm_client_displays_sort(&client->displaylist);
+
+	if (changed) {
+		DRM_DEBUG_KMS("Displays:\n");
+		drm_client_for_each_display(display, client)
+			drm_client_display_debugprint(display);
+	}
+
+	if (num_buffers) {
+		drm_client_for_each_display(display, client) {
+			ret = drm_client_display_framebuffer_create(display, num_buffers, format);
+			if (ret)
+				goto out_unlock;
+		}
+	}
+
+	ret = 0;
+	drm_client_for_each_display(display, client)
+		ret++;
+
+out_unlock:
+	mutex_unlock(&client->displaylist_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_client_probe_displays);
+
+/**
+ * drm_client_release_displays() - Release displays
+ * @client: DRM client
+ *
+ * This function releases all the clients displays.
+ */
+void drm_client_release_displays(struct drm_client_dev *client)
+{
+	struct drm_client_display *display, *tmp;
+
+	mutex_lock(&client->displaylist_mutex);
+	list_for_each_entry_safe(display, tmp, &client->displaylist, list) {
+		list_del(&display->list);
+		drm_client_display_release(display);
+	}
+	mutex_unlock(&client->displaylist_mutex);
+}
+EXPORT_SYMBOL(drm_client_release_displays);
+
+static int drm_client_display_set_buffer(struct drm_client_display *display, unsigned int buffer)
+{
+	struct drm_mode_set *modeset;
+
+	if (!display || buffer >= display->num_buffers)
+		return -EINVAL;
+
+	drm_client_for_each_modeset(modeset, display->modesets)
+		modeset->fb = display->buffers[buffer]->fb;
+
+	return 0;
+}
+
+static int drm_client_display_commit(struct drm_client_display *display)
+{
+	int ret;
+
+	if (!display)
+		return -EINVAL;
+
+	if (!drm_master_internal_acquire(display->client->dev))
+		return -EBUSY;
+
+	ret = drm_client_modesets_commit(display->client->dev, display->modesets);
+
+	drm_master_internal_release(display->client->dev);
+
+	return ret;
+}
+
+/**
+ * drm_client_display_commit_buffer() - Commit display modeset(s) with buffer
+ * @display: Client display
+ * @buffer: Buffer index
+ *
+ * This function sets the framebuffer to @buffer and commits the modeset(s).
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_display_commit_buffer(struct drm_client_display *display, unsigned int buffer)
+{
+	int ret;
+
+	ret = drm_client_display_set_buffer(display, buffer);
+	if (ret)
+		return ret;
+
+	return drm_client_display_commit(display);
+}
+EXPORT_SYMBOL(drm_client_display_commit_buffer);
+
 #ifdef CONFIG_DEBUG_FS
 static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
 {
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 78fb82bd8371..ef7a9bd07b3c 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -3,12 +3,15 @@
 #ifndef _DRM_CLIENT_H_
 #define _DRM_CLIENT_H_
 
+#include <linux/list.h>
+#include <linux/mutex.h>
 #include <linux/types.h>
 
 #include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
 
 struct drm_client_dev;
+struct drm_client_display;
 struct drm_device;
 struct drm_file;
 struct drm_framebuffer;
@@ -55,6 +58,25 @@ struct drm_client_funcs {
 	 * This callback is optional.
 	 */
 	int (*hotplug)(struct drm_client_dev *client);
+
+	/**
+	 * @display_alloc:
+	 *
+	 * Called when allocating a &drm_client_display. It can be use to
+	 * subclass the structure.
+	 *
+	 * This callback is optional.
+	 */
+	struct drm_client_display *(*display_alloc)(struct drm_client_dev *client);
+
+	/**
+	 * @display_free:
+	 *
+	 * Called when releasing a &drm_client_display.
+	 *
+	 * This callback is optional.
+	 */
+	void (*display_free)(struct drm_client_display *display);
 };
 
 /**
@@ -88,6 +110,19 @@ struct drm_client_dev {
 	 * @file: DRM file
 	 */
 	struct drm_file *file;
+
+	/**
+	 * @displaylist_mutex: Protects @displaylist.
+	 */
+	struct mutex displaylist_mutex;
+
+	/**
+	 * @displaylist:
+	 *
+	 * List of displays, linked through &drm_client_display.list.
+	 */
+	struct list_head displaylist;
+
 };
 
 int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
@@ -169,6 +204,51 @@ void drm_client_modesets_dpms(struct drm_device *dev, struct drm_mode_set *modes
 #define drm_client_for_each_modeset(modeset, modesets) \
 	for (modeset = modesets; modeset->crtc; modeset++)
 
+/**
+ * struct drm_client_display - DRM client display
+ */
+struct drm_client_display {
+	/**
+	 * @client: DRM client.
+	 */
+	struct drm_client_dev *client;
+
+	/**
+	 * @list:
+	 *
+	 * List of all displays for a client, linked into
+	 * &drm_client_dev.displaylist. Protected by &drm_client_dev.displaylist_mutex.
+	 */
+	struct list_head list;
+
+	/**
+	 * @mode: Current display mode.
+	 */
+	struct drm_display_mode *mode;
+
+	/**
+	 * @modesets: Per CRTC array of modeset configurations.
+	 */
+	struct drm_mode_set *modesets;
+
+	/**
+	 * @buffers: Display buffers (optional).
+	 */
+	struct drm_client_buffer **buffers;
+
+	/**
+	 * @num_buffers: Number of backing buffers.
+	 */
+	unsigned int num_buffers;
+};
+
+int drm_client_probe_displays(struct drm_client_dev *client, unsigned int num_buffers, u32 format);
+void drm_client_release_displays(struct drm_client_dev *client);
+int drm_client_display_commit_buffer(struct drm_client_display *display, unsigned int buffer);
+
+#define drm_client_for_each_display(display, client) \
+	list_for_each_entry(display, &(client)->displaylist, list)
+
 int drm_client_debugfs_init(struct drm_minor *minor);
 
 #endif
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 15/16] drm/client: Hack: Add bootsplash example
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (13 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 14/16] drm/client: Add display abstraction Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 17:55 ` [PATCH 16/16] drm/vc4: Call drm_dev_register() after all setup is done Noralf Trønnes
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, mstaudt

An example to showcase the client API.

TODO:
A bootsplash client needs a way to tell drm_fb_helper to stay away,
otherwise it will chime in on setup and hotplug.
Most DRM drivers register fbdev before calling drm_dev_register() (the
generic emulation is an exception). This have to be reversed for
bootsplash to fend off fbdev.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/Kconfig          |   5 +
 drivers/gpu/drm/Makefile         |   1 +
 drivers/gpu/drm/drm_bootsplash.c | 216 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_client.c     |   7 +
 drivers/gpu/drm/drm_drv.c        |   4 +
 include/drm/drm_client.h         |   3 +
 6 files changed, 236 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_bootsplash.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 5e1bc630b885..a7019c54e2a2 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -65,6 +65,11 @@ config DRM_DEBUG_SELFTEST
 
 	  If in doubt, say "N".
 
+config DRM_CLIENT_BOOTSPLASH
+	bool "DRM Bootsplash"
+	help
+	  DRM Bootsplash
+
 config DRM_KMS_HELPER
 	tristate
 	depends on DRM
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e630eccb951c..ac0573023842 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -32,6 +32,7 @@ drm-$(CONFIG_OF) += drm_of.o
 drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm-$(CONFIG_DRM_CLIENT_BOOTSPLASH) += drm_bootsplash.o
 
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \
 		drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
diff --git a/drivers/gpu/drm/drm_bootsplash.c b/drivers/gpu/drm/drm_bootsplash.c
new file mode 100644
index 000000000000..fdc3349a2496
--- /dev/null
+++ b/drivers/gpu/drm/drm_bootsplash.c
@@ -0,0 +1,216 @@
+/* DRM internal client example */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/keyboard.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include <drm/drm_client.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_print.h>
+
+// drm_lastclose()
+#include "drm_internal.h"
+
+static bool drm_bootsplash_enabled = true;
+module_param_named(bootsplash_enabled, drm_bootsplash_enabled, bool, 0600);
+MODULE_PARM_DESC(bootsplash_enabled, "Enable bootsplash client [default=true]");
+
+struct drm_bootsplash {
+	struct drm_client_dev client;
+	struct mutex lock;
+	struct work_struct worker;
+	bool started;
+	bool stop;
+};
+
+static bool drm_bootsplash_key_pressed;
+
+static int drm_bootsplash_keyboard_notifier_call(struct notifier_block *blk,
+						 unsigned long code, void *_param)
+{
+	/* Any key is good */
+	drm_bootsplash_key_pressed = true;
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block drm_bootsplash_keyboard_notifier_block = {
+	.notifier_call = drm_bootsplash_keyboard_notifier_call,
+};
+
+static u32 drm_bootsplash_color_table[3] = {
+	0x00ff0000, 0x0000ff00, 0x000000ff,
+};
+
+/* Draw a box with changing colors */
+static void drm_bootsplash_draw(struct drm_client_buffer *buffer, unsigned int sequence)
+{
+	unsigned int width = buffer->fb->width;
+	unsigned int height = buffer->fb->height;
+	unsigned int x, y;
+	u32 *pix;
+
+	pix = buffer->vaddr;
+	pix += ((height / 2) - 50) * width;
+	pix += (width / 2) - 50;
+
+	for (y = 0; y < 100; y++) {
+		for (x = 0; x < 100; x++)
+			*pix++ = drm_bootsplash_color_table[sequence];
+		pix += width - 100;
+	}
+}
+
+static void drm_bootsplash_worker(struct work_struct *work)
+{
+	struct drm_bootsplash *splash = container_of(work, struct drm_bootsplash, worker);
+	struct drm_client_dev *client = &splash->client;
+	struct drm_device *dev = client->dev;
+	struct drm_client_display *display;
+	unsigned int buffer_num = 0, sequence = 0, i;
+	bool stop;
+	int ret = 0;
+
+	while (!drm_bootsplash_key_pressed) {
+		mutex_lock(&splash->lock);
+		stop = splash->stop;
+		mutex_unlock(&splash->lock);
+		if (stop)
+			break;
+
+		buffer_num = !buffer_num;
+
+		mutex_lock(&client->displaylist_mutex);
+
+		ret = -ENOENT;
+
+		i = 0;
+		drm_client_for_each_display(display, client) {
+			DRM_DEBUG_KMS("draw: i=%u, buffer_num=%u, sequence=%u\n", i++, buffer_num, sequence);
+
+			drm_bootsplash_draw(display->buffers[buffer_num], sequence);
+
+			ret = drm_client_display_commit_buffer(display, buffer_num);
+			if (ret == -EBUSY)
+				break;
+
+		}
+		mutex_unlock(&client->displaylist_mutex);
+
+		if (ret == -ENOENT || ret == -EBUSY)
+			break;
+
+		if (++sequence == 3)
+			sequence = 0;
+
+		msleep(500);
+	}
+
+	/* Restore fbdev (or other) on key press. */
+	/* TODO: Check if it's OK to call drm_lastclose here. */
+	if (drm_bootsplash_key_pressed && !splash->stop)
+		drm_lastclose(dev);
+
+	drm_client_release_displays(client);
+
+	DRM_DEV_DEBUG_KMS(dev->dev, "Bootsplash has stopped (key=%u stop=%u, ret=%d).\n",
+			  drm_bootsplash_key_pressed, splash->stop, ret);
+}
+
+static int drm_bootsplash_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_bootsplash *splash = container_of(client, struct drm_bootsplash, client);
+	int ret;
+
+	if (drm_bootsplash_key_pressed)
+		return 0;
+
+	mutex_lock(&splash->lock);
+
+	ret = drm_client_probe_displays(client, 2, DRM_FORMAT_XRGB8888);
+	if (!ret)
+		ret = -ENOENT;
+	if (ret < 0)
+		goto out_unlock;
+
+	/*
+	 * TODO: Deal with rotated panels, might have to sw rotate
+	if (drm_client_panel_rotation(...))
+	 */
+
+	if (!splash->started) {
+		splash->started = true;
+		schedule_work(&splash->worker);
+	}
+
+out_unlock:
+	mutex_unlock(&splash->lock);
+
+	return ret;
+}
+
+static void drm_bootsplash_client_unregister(struct drm_client_dev *client)
+{
+	struct drm_bootsplash *splash = container_of(client, struct drm_bootsplash, client);
+
+	DRM_DEBUG_KMS("%s: IN\n", __func__);
+
+	mutex_lock(&splash->lock);
+	splash->stop = true;
+	mutex_unlock(&splash->lock);
+
+	flush_work(&splash->worker);
+
+	drm_client_release(client);
+	kfree(splash);
+
+	unregister_keyboard_notifier(&drm_bootsplash_keyboard_notifier_block);
+
+	DRM_DEBUG_KMS("%s: OUT\n", __func__);
+}
+
+static const struct drm_client_funcs drm_bootsplash_client_funcs = {
+	.owner		= THIS_MODULE,
+	.unregister	= drm_bootsplash_client_unregister,
+	.hotplug	= drm_bootsplash_client_hotplug,
+};
+
+void drm_bootsplash_client_register(struct drm_device *dev)
+{
+	struct drm_bootsplash *splash;
+	int ret;
+
+	if (!drm_bootsplash_enabled)
+		return;
+
+	splash = kzalloc(sizeof(*splash), GFP_KERNEL);
+	if (!splash)
+		return;
+
+	ret = drm_client_init(dev, &splash->client, "bootsplash", &drm_bootsplash_client_funcs);
+	if (ret) {
+		DRM_DEV_ERROR(dev->dev, "Failed to create client, ret=%d\n", ret);
+		kfree(splash);
+		return;
+	}
+
+	/* For this simple example only allow the first */
+	drm_bootsplash_enabled = false;
+
+	mutex_init(&splash->lock);
+
+	INIT_WORK(&splash->worker, drm_bootsplash_worker);
+
+	drm_client_add(&splash->client);
+
+	register_keyboard_notifier(&drm_bootsplash_keyboard_notifier_block);
+
+	drm_bootsplash_client_hotplug(&splash->client);
+}
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index ef01a31a9dbe..b7458fac0863 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -170,6 +170,13 @@ void drm_client_release(struct drm_client_dev *client)
 }
 EXPORT_SYMBOL(drm_client_release);
 
+void drm_client_dev_register(struct drm_device *dev)
+{
+#if CONFIG_DRM_CLIENT_BOOTSPLASH
+	drm_bootsplash_client_register(dev);
+#endif
+}
+
 void drm_client_dev_unregister(struct drm_device *dev)
 {
 	struct drm_client_dev *client, *tmp;
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 50d849d1bc6e..fbbb5f998baf 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -1018,6 +1018,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
 out_unlock:
 	mutex_unlock(&drm_global_mutex);
+
+	if (!ret)
+		drm_client_dev_register(dev);
+
 	return ret;
 }
 EXPORT_SYMBOL(drm_dev_register);
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index ef7a9bd07b3c..cabd3055ba8a 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -130,6 +130,7 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
 void drm_client_release(struct drm_client_dev *client);
 void drm_client_add(struct drm_client_dev *client);
 
+void drm_client_dev_register(struct drm_device *dev);
 void drm_client_dev_unregister(struct drm_device *dev);
 void drm_client_dev_hotplug(struct drm_device *dev);
 void drm_client_dev_restore(struct drm_device *dev);
@@ -251,4 +252,6 @@ int drm_client_display_commit_buffer(struct drm_client_display *display, unsigne
 
 int drm_client_debugfs_init(struct drm_minor *minor);
 
+void drm_bootsplash_client_register(struct drm_device *dev);
+
 #endif
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 16/16] drm/vc4: Call drm_dev_register() after all setup is done
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (14 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 15/16] drm/client: Hack: Add bootsplash example Noralf Trønnes
@ 2019-03-26 17:55 ` Noralf Trønnes
  2019-03-26 20:40   ` Daniel Vetter
  2019-03-27 16:36   ` Eric Anholt
  2019-03-27 13:45 ` [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
  2019-03-28  9:31 ` [Intel-gfx] " Daniel Vetter
  17 siblings, 2 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-26 17:55 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes, mstaudt

drm_dev_register() initializes internal clients like bootsplash as the
last thing it does, so all setup needs to be done at this point.

Fix by calling vc4_kms_load() before registering.
Also check the error code returned from that function.

Cc: Eric Anholt <eric@anholt.net>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/vc4/vc4_drv.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 4daf44fd4548..ba87b2dfa767 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -280,11 +280,13 @@ static int vc4_drm_bind(struct device *dev)
 
 	drm_fb_helper_remove_conflicting_framebuffers(NULL, "vc4drmfb", false);
 
-	ret = drm_dev_register(drm, 0);
+	ret = vc4_kms_load(drm);
 	if (ret < 0)
 		goto unbind_all;
 
-	vc4_kms_load(drm);
+	ret = drm_dev_register(drm, 0);
+	if (ret < 0)
+		goto unbind_all;
 
 	drm_fbdev_generic_setup(drm, 16);
 
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH 01/16] drm/fb-helper: Remove unused gamma_size variable
  2019-03-26 17:55 ` [PATCH 01/16] drm/fb-helper: Remove unused gamma_size variable Noralf Trønnes
@ 2019-03-26 18:23   ` Daniel Vetter
  2019-04-03  9:19     ` [Intel-gfx] " Noralf Trønnes
  0 siblings, 1 reply; 42+ messages in thread
From: Daniel Vetter @ 2019-03-26 18:23 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, mstaudt, dri-devel

On Tue, Mar 26, 2019 at 06:55:31PM +0100, Noralf Trønnes wrote:
> The gamma_size variable has not been used since
> commit 4abe35204af8 ("drm/kms/fb: use slow work mechanism for normal hotplug also.")
> 
> While in the area move a comment back to its code block.
> They got separated by
> commit d50ba256b5f1 ("drm/kms: start adding command line interface using fb.").
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/drm_fb_helper.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 04d23cb430bf..eea15465da7a 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -1873,7 +1873,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  	int crtc_count = 0;
>  	int i;
>  	struct drm_fb_helper_surface_size sizes;
> -	int gamma_size = 0;
>  	int best_depth = 0;
>  
>  	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
> @@ -1889,7 +1888,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  	if (preferred_bpp != sizes.surface_bpp)
>  		sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
>  
> -	/* first up get a count of crtcs now in use and new min/maxes width/heights */
>  	drm_fb_helper_for_each_connector(fb_helper, i) {
>  		struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
>  		struct drm_cmdline_mode *cmdline_mode;
> @@ -1969,6 +1967,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  		sizes.surface_depth = best_depth;
>  	}
>  
> +	/* first up get a count of crtcs now in use and new min/maxes width/heights */
>  	crtc_count = 0;
>  	for (i = 0; i < fb_helper->crtc_count; i++) {
>  		struct drm_display_mode *desired_mode;
> @@ -1991,9 +1990,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  		x = fb_helper->crtc_info[i].x;
>  		y = fb_helper->crtc_info[i].y;
>  
> -		if (gamma_size == 0)
> -			gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
> -
>  		sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
>  		sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
>  
> -- 
> 2.20.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 02/16] drm/fb-helper: dpms_legacy(): Only set on connectors in use
  2019-03-26 17:55 ` [PATCH 02/16] drm/fb-helper: dpms_legacy(): Only set on connectors in use Noralf Trønnes
@ 2019-03-26 18:26   ` Daniel Vetter
  0 siblings, 0 replies; 42+ messages in thread
From: Daniel Vetter @ 2019-03-26 18:26 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, mstaudt, dri-devel

On Tue, Mar 26, 2019 at 06:55:32PM +0100, Noralf Trønnes wrote:
> For each enabled crtc the functions sets dpms on all registered connectors.
> Limit this to only doing it once and on the connectors actually in use.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Fixes: 023eb571a1d0 ("drm: correctly update connector DPMS status in drm_fb_helper")
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Just want to trick the AUTOSEL bot into cherrypicking a silly patch onto
-stable :-)

-Daniel

> ---
>  drivers/gpu/drm/drm_fb_helper.c | 11 +++++------
>  1 file changed, 5 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index eea15465da7a..b91df658db59 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -639,20 +639,19 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
>  static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
>  {
>  	struct drm_device *dev = fb_helper->dev;
> -	struct drm_crtc *crtc;
>  	struct drm_connector *connector;
> +	struct drm_mode_set *modeset;
>  	int i, j;
>  
>  	drm_modeset_lock_all(dev);
>  	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		crtc = fb_helper->crtc_info[i].mode_set.crtc;
> +		modeset = &fb_helper->crtc_info[i].mode_set;
>  
> -		if (!crtc->enabled)
> +		if (!modeset->crtc->enabled)
>  			continue;
>  
> -		/* Walk the connectors & encoders on this fb turning them on/off */
> -		drm_fb_helper_for_each_connector(fb_helper, j) {
> -			connector = fb_helper->connector_info[j]->connector;
> +		for (j = 0; j < modeset->num_connectors; j++) {
> +			connector = modeset->connectors[j];
>  			connector->funcs->dpms(connector, dpms_mode);
>  			drm_object_property_set_value(&connector->base,
>  				dev->mode_config.dpms_property, dpms_mode);
> -- 
> 2.20.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 16/16] drm/vc4: Call drm_dev_register() after all setup is done
  2019-03-26 17:55 ` [PATCH 16/16] drm/vc4: Call drm_dev_register() after all setup is done Noralf Trønnes
@ 2019-03-26 20:40   ` Daniel Vetter
  2019-03-27 16:36   ` Eric Anholt
  1 sibling, 0 replies; 42+ messages in thread
From: Daniel Vetter @ 2019-03-26 20:40 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, mstaudt, dri-devel

On Tue, Mar 26, 2019 at 06:55:46PM +0100, Noralf Trønnes wrote:
> drm_dev_register() initializes internal clients like bootsplash as the
> last thing it does, so all setup needs to be done at this point.
> 
> Fix by calling vc4_kms_load() before registering.
> Also check the error code returned from that function.
> 
> Cc: Eric Anholt <eric@anholt.net>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

Looks like this has been slightly backwards ever since vc4 landed. I guess
would have needed the split between kms setup and fbdev setup (which is
now done with the generic fbdev).

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/vc4/vc4_drv.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
> index 4daf44fd4548..ba87b2dfa767 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.c
> +++ b/drivers/gpu/drm/vc4/vc4_drv.c
> @@ -280,11 +280,13 @@ static int vc4_drm_bind(struct device *dev)
>  
>  	drm_fb_helper_remove_conflicting_framebuffers(NULL, "vc4drmfb", false);
>  
> -	ret = drm_dev_register(drm, 0);
> +	ret = vc4_kms_load(drm);
>  	if (ret < 0)
>  		goto unbind_all;
>  
> -	vc4_kms_load(drm);
> +	ret = drm_dev_register(drm, 0);
> +	if (ret < 0)
> +		goto unbind_all;
>  
>  	drm_fbdev_generic_setup(drm, 16);
>  
> -- 
> 2.20.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 03/16] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  2019-03-26 17:55 ` [PATCH 03/16] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
@ 2019-03-26 20:48   ` Daniel Vetter
  2019-03-27 13:41     ` [Intel-gfx] " Noralf Trønnes
  0 siblings, 1 reply; 42+ messages in thread
From: Daniel Vetter @ 2019-03-26 20:48 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, mstaudt, dri-devel

On Tue, Mar 26, 2019 at 06:55:33PM +0100, Noralf Trønnes wrote:
> Prepare for moving drm_fb_helper modesetting code to drm_client.
> drm_client will be linked to drm.ko, so move
> __drm_atomic_helper_disable_plane() and __drm_atomic_helper_set_config()
> out of drm_kms_helper.ko.
> 
> While at it, fix two checkpatch complaints:
> - WARNING: Block comments use a trailing */ on a separate line
> - CHECK: Alignment should match open parenthesis
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

Triggers a bit my midlayer ocd, but I can't come up with a better idea
either.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/drm_atomic.c        | 168 ++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_atomic_helper.c | 164 ---------------------------
>  drivers/gpu/drm/drm_crtc_internal.h |   5 +
>  include/drm/drm_atomic_helper.h     |   4 -
>  4 files changed, 173 insertions(+), 168 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 5eb40130fafb..c3a9ffbf2310 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1130,6 +1130,174 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
>  }
>  EXPORT_SYMBOL(drm_atomic_nonblocking_commit);
>  
> +/* just used from drm-client and atomic-helper: */
> +int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
> +				      struct drm_plane_state *plane_state)
> +{
> +	int ret;
> +
> +	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
> +	if (ret != 0)
> +		return ret;
> +
> +	drm_atomic_set_fb_for_plane(plane_state, NULL);
> +	plane_state->crtc_x = 0;
> +	plane_state->crtc_y = 0;
> +	plane_state->crtc_w = 0;
> +	plane_state->crtc_h = 0;
> +	plane_state->src_x = 0;
> +	plane_state->src_y = 0;
> +	plane_state->src_w = 0;
> +	plane_state->src_h = 0;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(__drm_atomic_helper_disable_plane);
> +
> +static int update_output_state(struct drm_atomic_state *state,
> +			       struct drm_mode_set *set)
> +{
> +	struct drm_device *dev = set->crtc->dev;
> +	struct drm_crtc *crtc;
> +	struct drm_crtc_state *new_crtc_state;
> +	struct drm_connector *connector;
> +	struct drm_connector_state *new_conn_state;
> +	int ret, i;
> +
> +	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
> +			       state->acquire_ctx);
> +	if (ret)
> +		return ret;
> +
> +	/* First disable all connectors on the target crtc. */
> +	ret = drm_atomic_add_affected_connectors(state, set->crtc);
> +	if (ret)
> +		return ret;
> +
> +	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
> +		if (new_conn_state->crtc == set->crtc) {
> +			ret = drm_atomic_set_crtc_for_connector(new_conn_state,
> +								NULL);
> +			if (ret)
> +				return ret;
> +
> +			/* Make sure legacy setCrtc always re-trains */
> +			new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
> +		}
> +	}
> +
> +	/* Then set all connectors from set->connectors on the target crtc */
> +	for (i = 0; i < set->num_connectors; i++) {
> +		new_conn_state = drm_atomic_get_connector_state(state,
> +								set->connectors[i]);
> +		if (IS_ERR(new_conn_state))
> +			return PTR_ERR(new_conn_state);
> +
> +		ret = drm_atomic_set_crtc_for_connector(new_conn_state,
> +							set->crtc);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
> +		/*
> +		 * Don't update ->enable for the CRTC in the set_config request,
> +		 * since a mismatch would indicate a bug in the upper layers.
> +		 * The actual modeset code later on will catch any
> +		 * inconsistencies here.
> +		 */
> +		if (crtc == set->crtc)
> +			continue;
> +
> +		if (!new_crtc_state->connector_mask) {
> +			ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
> +								NULL);
> +			if (ret < 0)
> +				return ret;
> +
> +			new_crtc_state->active = false;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/* just used from drm-client and atomic-helper: */
> +int __drm_atomic_helper_set_config(struct drm_mode_set *set,
> +				   struct drm_atomic_state *state)
> +{
> +	struct drm_crtc_state *crtc_state;
> +	struct drm_plane_state *primary_state;
> +	struct drm_crtc *crtc = set->crtc;
> +	int hdisplay, vdisplay;
> +	int ret;
> +
> +	crtc_state = drm_atomic_get_crtc_state(state, crtc);
> +	if (IS_ERR(crtc_state))
> +		return PTR_ERR(crtc_state);
> +
> +	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
> +	if (IS_ERR(primary_state))
> +		return PTR_ERR(primary_state);
> +
> +	if (!set->mode) {
> +		WARN_ON(set->fb);
> +		WARN_ON(set->num_connectors);
> +
> +		ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
> +		if (ret != 0)
> +			return ret;
> +
> +		crtc_state->active = false;
> +
> +		ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
> +		if (ret != 0)
> +			return ret;
> +
> +		drm_atomic_set_fb_for_plane(primary_state, NULL);
> +
> +		goto commit;
> +	}
> +
> +	WARN_ON(!set->fb);
> +	WARN_ON(!set->num_connectors);
> +
> +	ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
> +	if (ret != 0)
> +		return ret;
> +
> +	crtc_state->active = true;
> +
> +	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
> +	if (ret != 0)
> +		return ret;
> +
> +	drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
> +
> +	drm_atomic_set_fb_for_plane(primary_state, set->fb);
> +	primary_state->crtc_x = 0;
> +	primary_state->crtc_y = 0;
> +	primary_state->crtc_w = hdisplay;
> +	primary_state->crtc_h = vdisplay;
> +	primary_state->src_x = set->x << 16;
> +	primary_state->src_y = set->y << 16;
> +	if (drm_rotation_90_or_270(primary_state->rotation)) {
> +		primary_state->src_w = vdisplay << 16;
> +		primary_state->src_h = hdisplay << 16;
> +	} else {
> +		primary_state->src_w = hdisplay << 16;
> +		primary_state->src_h = vdisplay << 16;
> +	}
> +
> +commit:
> +	ret = update_output_state(state, set);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(__drm_atomic_helper_set_config);
> +
>  void drm_atomic_print_state(const struct drm_atomic_state *state)
>  {
>  	struct drm_printer p = drm_info_printer(state->dev->dev);
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 2453678d1186..b0d960da53cb 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -2831,95 +2831,6 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane,
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_disable_plane);
>  
> -/* just used from fb-helper and atomic-helper: */
> -int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
> -		struct drm_plane_state *plane_state)
> -{
> -	int ret;
> -
> -	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
> -	if (ret != 0)
> -		return ret;
> -
> -	drm_atomic_set_fb_for_plane(plane_state, NULL);
> -	plane_state->crtc_x = 0;
> -	plane_state->crtc_y = 0;
> -	plane_state->crtc_w = 0;
> -	plane_state->crtc_h = 0;
> -	plane_state->src_x = 0;
> -	plane_state->src_y = 0;
> -	plane_state->src_w = 0;
> -	plane_state->src_h = 0;
> -
> -	return 0;
> -}
> -
> -static int update_output_state(struct drm_atomic_state *state,
> -			       struct drm_mode_set *set)
> -{
> -	struct drm_device *dev = set->crtc->dev;
> -	struct drm_crtc *crtc;
> -	struct drm_crtc_state *new_crtc_state;
> -	struct drm_connector *connector;
> -	struct drm_connector_state *new_conn_state;
> -	int ret, i;
> -
> -	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
> -			       state->acquire_ctx);
> -	if (ret)
> -		return ret;
> -
> -	/* First disable all connectors on the target crtc. */
> -	ret = drm_atomic_add_affected_connectors(state, set->crtc);
> -	if (ret)
> -		return ret;
> -
> -	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
> -		if (new_conn_state->crtc == set->crtc) {
> -			ret = drm_atomic_set_crtc_for_connector(new_conn_state,
> -								NULL);
> -			if (ret)
> -				return ret;
> -
> -			/* Make sure legacy setCrtc always re-trains */
> -			new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
> -		}
> -	}
> -
> -	/* Then set all connectors from set->connectors on the target crtc */
> -	for (i = 0; i < set->num_connectors; i++) {
> -		new_conn_state = drm_atomic_get_connector_state(state,
> -							    set->connectors[i]);
> -		if (IS_ERR(new_conn_state))
> -			return PTR_ERR(new_conn_state);
> -
> -		ret = drm_atomic_set_crtc_for_connector(new_conn_state,
> -							set->crtc);
> -		if (ret)
> -			return ret;
> -	}
> -
> -	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
> -		/* Don't update ->enable for the CRTC in the set_config request,
> -		 * since a mismatch would indicate a bug in the upper layers.
> -		 * The actual modeset code later on will catch any
> -		 * inconsistencies here. */
> -		if (crtc == set->crtc)
> -			continue;
> -
> -		if (!new_crtc_state->connector_mask) {
> -			ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
> -								NULL);
> -			if (ret < 0)
> -				return ret;
> -
> -			new_crtc_state->active = false;
> -		}
> -	}
> -
> -	return 0;
> -}
> -
>  /**
>   * drm_atomic_helper_set_config - set a new config from userspace
>   * @set: mode set configuration
> @@ -2964,81 +2875,6 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set,
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_set_config);
>  
> -/* just used from fb-helper and atomic-helper: */
> -int __drm_atomic_helper_set_config(struct drm_mode_set *set,
> -		struct drm_atomic_state *state)
> -{
> -	struct drm_crtc_state *crtc_state;
> -	struct drm_plane_state *primary_state;
> -	struct drm_crtc *crtc = set->crtc;
> -	int hdisplay, vdisplay;
> -	int ret;
> -
> -	crtc_state = drm_atomic_get_crtc_state(state, crtc);
> -	if (IS_ERR(crtc_state))
> -		return PTR_ERR(crtc_state);
> -
> -	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
> -	if (IS_ERR(primary_state))
> -		return PTR_ERR(primary_state);
> -
> -	if (!set->mode) {
> -		WARN_ON(set->fb);
> -		WARN_ON(set->num_connectors);
> -
> -		ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
> -		if (ret != 0)
> -			return ret;
> -
> -		crtc_state->active = false;
> -
> -		ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
> -		if (ret != 0)
> -			return ret;
> -
> -		drm_atomic_set_fb_for_plane(primary_state, NULL);
> -
> -		goto commit;
> -	}
> -
> -	WARN_ON(!set->fb);
> -	WARN_ON(!set->num_connectors);
> -
> -	ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
> -	if (ret != 0)
> -		return ret;
> -
> -	crtc_state->active = true;
> -
> -	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
> -	if (ret != 0)
> -		return ret;
> -
> -	drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
> -
> -	drm_atomic_set_fb_for_plane(primary_state, set->fb);
> -	primary_state->crtc_x = 0;
> -	primary_state->crtc_y = 0;
> -	primary_state->crtc_w = hdisplay;
> -	primary_state->crtc_h = vdisplay;
> -	primary_state->src_x = set->x << 16;
> -	primary_state->src_y = set->y << 16;
> -	if (drm_rotation_90_or_270(primary_state->rotation)) {
> -		primary_state->src_w = vdisplay << 16;
> -		primary_state->src_h = hdisplay << 16;
> -	} else {
> -		primary_state->src_w = hdisplay << 16;
> -		primary_state->src_h = vdisplay << 16;
> -	}
> -
> -commit:
> -	ret = update_output_state(state, set);
> -	if (ret)
> -		return ret;
> -
> -	return 0;
> -}
> -
>  static int __drm_atomic_helper_disable_all(struct drm_device *dev,
>  					   struct drm_modeset_acquire_ctx *ctx,
>  					   bool clean_old_fbs)
> diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
> index 216f2a9ee3d4..22a63a544ec7 100644
> --- a/drivers/gpu/drm/drm_crtc_internal.h
> +++ b/drivers/gpu/drm/drm_crtc_internal.h
> @@ -207,6 +207,11 @@ struct drm_minor;
>  int drm_atomic_debugfs_init(struct drm_minor *minor);
>  #endif
>  
> +int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
> +				      struct drm_plane_state *plane_state);
> +int __drm_atomic_helper_set_config(struct drm_mode_set *set,
> +				   struct drm_atomic_state *state);
> +
>  void drm_atomic_print_state(const struct drm_atomic_state *state);
>  
>  /* drm_atomic_uapi.c */
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index 58214be3bf3d..bf4e07141d81 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -117,12 +117,8 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
>  				   struct drm_modeset_acquire_ctx *ctx);
>  int drm_atomic_helper_disable_plane(struct drm_plane *plane,
>  				    struct drm_modeset_acquire_ctx *ctx);
> -int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
> -		struct drm_plane_state *plane_state);
>  int drm_atomic_helper_set_config(struct drm_mode_set *set,
>  				 struct drm_modeset_acquire_ctx *ctx);
> -int __drm_atomic_helper_set_config(struct drm_mode_set *set,
> -		struct drm_atomic_state *state);
>  
>  int drm_atomic_helper_disable_all(struct drm_device *dev,
>  				  struct drm_modeset_acquire_ctx *ctx);
> -- 
> 2.20.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 06/16] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
  2019-03-26 17:55 ` [PATCH 06/16] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper Noralf Trønnes
@ 2019-03-27 13:33   ` Jani Nikula
  2019-03-30 20:50     ` Noralf Trønnes
  0 siblings, 1 reply; 42+ messages in thread
From: Jani Nikula @ 2019-03-27 13:33 UTC (permalink / raw)
  To: Noralf Trønnes, dri-devel
  Cc: Daniel Vetter, intel-gfx, mstaudt, Rodrigo Vivi

On Tue, 26 Mar 2019, Noralf Trønnes <noralf@tronnes.org> wrote:
> It is generic code and having it in the helper will let other drivers
> benefit from it.
>
> One change was necessary assuming this to be true:
> INTEL_INFO(dev_priv)->num_pipes == dev->mode_config.num_crtc

This holds after intel_modeset_init(), in time for the use here.

> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Cc: intel-gfx@lists.freedesktop.org
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

Reviewed-by: Jani Nikula <jani.nikula@intel.com>

and

Acked-by: Jani Nikula <jani.nikula@intel.com>

for merging via drm-misc or whichever tree makes most sense.


> ---
>  drivers/gpu/drm/drm_fb_helper.c    | 194 ++++++++++++++++++++++++-
>  drivers/gpu/drm/i915/intel_fbdev.c | 218 -----------------------------
>  include/drm/drm_fb_helper.h        |  23 ---
>  3 files changed, 190 insertions(+), 245 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 36310901e935..634f4dcf0c41 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -2545,6 +2545,194 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
>  	return best_score;
>  }
>  
> +static struct drm_fb_helper_crtc *
> +drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
> +{
> +	int i;
> +
> +	for (i = 0; i < fb_helper->crtc_count; i++)
> +		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
> +			return &fb_helper->crtc_info[i];
> +
> +	return NULL;
> +}
> +
> +/* Try to read the BIOS display configuration and use it for the initial config */
> +static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
> +					  struct drm_fb_helper_crtc **crtcs,
> +					  struct drm_display_mode **modes,
> +					  struct drm_fb_offset *offsets,
> +					  bool *enabled, int width, int height)
> +{
> +	struct drm_device *dev = fb_helper->dev;
> +	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
> +	unsigned long conn_configured, conn_seq;
> +	int i, j;
> +	bool *save_enabled;
> +	bool fallback = true, ret = true;
> +	int num_connectors_enabled = 0;
> +	int num_connectors_detected = 0;
> +	struct drm_modeset_acquire_ctx ctx;
> +
> +	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
> +	if (!save_enabled)
> +		return false;
> +
> +	drm_modeset_acquire_init(&ctx, 0);
> +
> +	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
> +		drm_modeset_backoff(&ctx);
> +
> +	memcpy(save_enabled, enabled, count);
> +	conn_seq = GENMASK(count - 1, 0);
> +	conn_configured = 0;
> +retry:
> +	for (i = 0; i < count; i++) {
> +		struct drm_fb_helper_connector *fb_conn;
> +		struct drm_connector *connector;
> +		struct drm_encoder *encoder;
> +		struct drm_fb_helper_crtc *new_crtc;
> +
> +		fb_conn = fb_helper->connector_info[i];
> +		connector = fb_conn->connector;
> +
> +		if (conn_configured & BIT(i))
> +			continue;
> +
> +		/* First pass, only consider tiled connectors */
> +		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
> +			continue;
> +
> +		if (connector->status == connector_status_connected)
> +			num_connectors_detected++;
> +
> +		if (!enabled[i]) {
> +			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
> +				      connector->name);
> +			conn_configured |= BIT(i);
> +			continue;
> +		}
> +
> +		if (connector->force == DRM_FORCE_OFF) {
> +			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
> +				      connector->name);
> +			enabled[i] = false;
> +			continue;
> +		}
> +
> +		encoder = connector->state->best_encoder;
> +		if (!encoder || WARN_ON(!connector->state->crtc)) {
> +			if (connector->force > DRM_FORCE_OFF)
> +				goto bail;
> +
> +			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
> +				      connector->name);
> +			enabled[i] = false;
> +			conn_configured |= BIT(i);
> +			continue;
> +		}
> +
> +		num_connectors_enabled++;
> +
> +		new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
> +
> +		/*
> +		 * Make sure we're not trying to drive multiple connectors
> +		 * with a single CRTC, since our cloning support may not
> +		 * match the BIOS.
> +		 */
> +		for (j = 0; j < count; j++) {
> +			if (crtcs[j] == new_crtc) {
> +				DRM_DEBUG_KMS("fallback: cloned configuration\n");
> +				goto bail;
> +			}
> +		}
> +
> +		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
> +			      connector->name);
> +
> +		/* go for command line mode first */
> +		modes[i] = drm_pick_cmdline_mode(fb_conn);
> +
> +		/* try for preferred next */
> +		if (!modes[i]) {
> +			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
> +				      connector->name, connector->has_tile);
> +			modes[i] = drm_has_preferred_mode(fb_conn, width,
> +							  height);
> +		}
> +
> +		/* No preferred mode marked by the EDID? Are there any modes? */
> +		if (!modes[i] && !list_empty(&connector->modes)) {
> +			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
> +				      connector->name);
> +			modes[i] = list_first_entry(&connector->modes,
> +						    struct drm_display_mode,
> +						    head);
> +		}
> +
> +		/* last resort: use current mode */
> +		if (!modes[i]) {
> +			/*
> +			 * IMPORTANT: We want to use the adjusted mode (i.e.
> +			 * after the panel fitter upscaling) as the initial
> +			 * config, not the input mode, which is what crtc->mode
> +			 * usually contains. But since our current
> +			 * code puts a mode derived from the post-pfit timings
> +			 * into crtc->mode this works out correctly.
> +			 *
> +			 * This is crtc->mode and not crtc->state->mode for the
> +			 * fastboot check to work correctly.
> +			 */
> +			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
> +				      connector->name);
> +			modes[i] = &connector->state->crtc->mode;
> +		}
> +		crtcs[i] = new_crtc;
> +
> +		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
> +			      connector->name,
> +			      connector->state->crtc->base.id,
> +			      connector->state->crtc->name,
> +			      modes[i]->hdisplay, modes[i]->vdisplay,
> +			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
> +
> +		fallback = false;
> +		conn_configured |= BIT(i);
> +	}
> +
> +	if (conn_configured != conn_seq) { /* repeat until no more are found */
> +		conn_seq = conn_configured;
> +		goto retry;
> +	}
> +
> +	/*
> +	 * If the BIOS didn't enable everything it could, fall back to have the
> +	 * same user experiencing of lighting up as much as possible like the
> +	 * fbdev helper library.
> +	 */
> +	if (num_connectors_enabled != num_connectors_detected &&
> +	    num_connectors_enabled < dev->mode_config.num_crtc) {
> +		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
> +		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
> +			      num_connectors_detected);
> +		fallback = true;
> +	}
> +
> +	if (fallback) {
> +bail:
> +		DRM_DEBUG_KMS("Not using firmware configuration\n");
> +		memcpy(enabled, save_enabled, count);
> +		ret = false;
> +	}
> +
> +	drm_modeset_drop_locks(&ctx);
> +	drm_modeset_acquire_fini(&ctx);
> +
> +	kfree(save_enabled);
> +	return ret;
> +}
> +
>  static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  			    u32 width, u32 height)
>  {
> @@ -2577,10 +2765,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
>  	drm_enable_connectors(fb_helper, enabled);
>  
> -	if (!(fb_helper->funcs->initial_config &&
> -	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
> -					       offsets,
> -					       enabled, width, height))) {
> +	if (!drm_fb_helper_firmware_config(fb_helper, crtcs, modes, offsets,
> +					   enabled, width, height)) {
>  		memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
>  		memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
>  		memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
> index e8f694b57b8a..20e91600cf71 100644
> --- a/drivers/gpu/drm/i915/intel_fbdev.c
> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
> @@ -292,225 +292,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
>  	return ret;
>  }
>  
> -static struct drm_fb_helper_crtc *
> -intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
> -{
> -	int i;
> -
> -	for (i = 0; i < fb_helper->crtc_count; i++)
> -		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
> -			return &fb_helper->crtc_info[i];
> -
> -	return NULL;
> -}
> -
> -/*
> - * Try to read the BIOS display configuration and use it for the initial
> - * fb configuration.
> - *
> - * The BIOS or boot loader will generally create an initial display
> - * configuration for us that includes some set of active pipes and displays.
> - * This routine tries to figure out which pipes and connectors are active
> - * and stuffs them into the crtcs and modes array given to us by the
> - * drm_fb_helper code.
> - *
> - * The overall sequence is:
> - *   intel_fbdev_init - from driver load
> - *     intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data
> - *     drm_fb_helper_init - build fb helper structs
> - *     drm_fb_helper_single_add_all_connectors - more fb helper structs
> - *   intel_fbdev_initial_config - apply the config
> - *     drm_fb_helper_initial_config - call ->probe then register_framebuffer()
> - *         drm_setup_crtcs - build crtc config for fbdev
> - *           intel_fb_initial_config - find active connectors etc
> - *         drm_fb_helper_single_fb_probe - set up fbdev
> - *           intelfb_create - re-use or alloc fb, build out fbdev structs
> - *
> - * Note that we don't make special consideration whether we could actually
> - * switch to the selected modes without a full modeset. E.g. when the display
> - * is in VGA mode we need to recalculate watermarks and set a new high-res
> - * framebuffer anyway.
> - */
> -static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
> -				    struct drm_fb_helper_crtc **crtcs,
> -				    struct drm_display_mode **modes,
> -				    struct drm_fb_offset *offsets,
> -				    bool *enabled, int width, int height)
> -{
> -	struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
> -	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
> -	unsigned long conn_configured, conn_seq;
> -	int i, j;
> -	bool *save_enabled;
> -	bool fallback = true, ret = true;
> -	int num_connectors_enabled = 0;
> -	int num_connectors_detected = 0;
> -	struct drm_modeset_acquire_ctx ctx;
> -
> -	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
> -	if (!save_enabled)
> -		return false;
> -
> -	drm_modeset_acquire_init(&ctx, 0);
> -
> -	while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
> -		drm_modeset_backoff(&ctx);
> -
> -	memcpy(save_enabled, enabled, count);
> -	conn_seq = GENMASK(count - 1, 0);
> -	conn_configured = 0;
> -retry:
> -	for (i = 0; i < count; i++) {
> -		struct drm_fb_helper_connector *fb_conn;
> -		struct drm_connector *connector;
> -		struct drm_encoder *encoder;
> -		struct drm_fb_helper_crtc *new_crtc;
> -
> -		fb_conn = fb_helper->connector_info[i];
> -		connector = fb_conn->connector;
> -
> -		if (conn_configured & BIT(i))
> -			continue;
> -
> -		/* First pass, only consider tiled connectors */
> -		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
> -			continue;
> -
> -		if (connector->status == connector_status_connected)
> -			num_connectors_detected++;
> -
> -		if (!enabled[i]) {
> -			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
> -				      connector->name);
> -			conn_configured |= BIT(i);
> -			continue;
> -		}
> -
> -		if (connector->force == DRM_FORCE_OFF) {
> -			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
> -				      connector->name);
> -			enabled[i] = false;
> -			continue;
> -		}
> -
> -		encoder = connector->state->best_encoder;
> -		if (!encoder || WARN_ON(!connector->state->crtc)) {
> -			if (connector->force > DRM_FORCE_OFF)
> -				goto bail;
> -
> -			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
> -				      connector->name);
> -			enabled[i] = false;
> -			conn_configured |= BIT(i);
> -			continue;
> -		}
> -
> -		num_connectors_enabled++;
> -
> -		new_crtc = intel_fb_helper_crtc(fb_helper,
> -						connector->state->crtc);
> -
> -		/*
> -		 * Make sure we're not trying to drive multiple connectors
> -		 * with a single CRTC, since our cloning support may not
> -		 * match the BIOS.
> -		 */
> -		for (j = 0; j < count; j++) {
> -			if (crtcs[j] == new_crtc) {
> -				DRM_DEBUG_KMS("fallback: cloned configuration\n");
> -				goto bail;
> -			}
> -		}
> -
> -		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
> -			      connector->name);
> -
> -		/* go for command line mode first */
> -		modes[i] = drm_pick_cmdline_mode(fb_conn);
> -
> -		/* try for preferred next */
> -		if (!modes[i]) {
> -			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
> -				      connector->name, connector->has_tile);
> -			modes[i] = drm_has_preferred_mode(fb_conn, width,
> -							  height);
> -		}
> -
> -		/* No preferred mode marked by the EDID? Are there any modes? */
> -		if (!modes[i] && !list_empty(&connector->modes)) {
> -			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
> -				      connector->name);
> -			modes[i] = list_first_entry(&connector->modes,
> -						    struct drm_display_mode,
> -						    head);
> -		}
> -
> -		/* last resort: use current mode */
> -		if (!modes[i]) {
> -			/*
> -			 * IMPORTANT: We want to use the adjusted mode (i.e.
> -			 * after the panel fitter upscaling) as the initial
> -			 * config, not the input mode, which is what crtc->mode
> -			 * usually contains. But since our current
> -			 * code puts a mode derived from the post-pfit timings
> -			 * into crtc->mode this works out correctly.
> -			 *
> -			 * This is crtc->mode and not crtc->state->mode for the
> -			 * fastboot check to work correctly. crtc_state->mode has
> -			 * I915_MODE_FLAG_INHERITED, which we clear to force check
> -			 * state.
> -			 */
> -			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
> -				      connector->name);
> -			modes[i] = &connector->state->crtc->mode;
> -		}
> -		crtcs[i] = new_crtc;
> -
> -		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
> -			      connector->name,
> -			      connector->state->crtc->base.id,
> -			      connector->state->crtc->name,
> -			      modes[i]->hdisplay, modes[i]->vdisplay,
> -			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :"");
> -
> -		fallback = false;
> -		conn_configured |= BIT(i);
> -	}
> -
> -	if (conn_configured != conn_seq) { /* repeat until no more are found */
> -		conn_seq = conn_configured;
> -		goto retry;
> -	}
> -
> -	/*
> -	 * If the BIOS didn't enable everything it could, fall back to have the
> -	 * same user experiencing of lighting up as much as possible like the
> -	 * fbdev helper library.
> -	 */
> -	if (num_connectors_enabled != num_connectors_detected &&
> -	    num_connectors_enabled < INTEL_INFO(dev_priv)->num_pipes) {
> -		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
> -		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
> -			      num_connectors_detected);
> -		fallback = true;
> -	}
> -
> -	if (fallback) {
> -bail:
> -		DRM_DEBUG_KMS("Not using firmware configuration\n");
> -		memcpy(enabled, save_enabled, count);
> -		ret = false;
> -	}
> -
> -	drm_modeset_drop_locks(&ctx);
> -	drm_modeset_acquire_fini(&ctx);
> -
> -	kfree(save_enabled);
> -	return ret;
> -}
> -
>  static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
> -	.initial_config = intel_fb_initial_config,
>  	.fb_probe = intelfb_create,
>  };
>  
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 7a095964f6b2..bca4b34dc93b 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -100,29 +100,6 @@ struct drm_fb_helper_funcs {
>  	 */
>  	int (*fb_probe)(struct drm_fb_helper *helper,
>  			struct drm_fb_helper_surface_size *sizes);
> -
> -	/**
> -	 * @initial_config:
> -	 *
> -	 * Driver callback to setup an initial fbdev display configuration.
> -	 * Drivers can use this callback to tell the fbdev emulation what the
> -	 * preferred initial configuration is. This is useful to implement
> -	 * smooth booting where the fbdev (and subsequently all userspace) never
> -	 * changes the mode, but always inherits the existing configuration.
> -	 *
> -	 * This callback is optional.
> -	 *
> -	 * RETURNS:
> -	 *
> -	 * The driver should return true if a suitable initial configuration has
> -	 * been filled out and false when the fbdev helper should fall back to
> -	 * the default probing logic.
> -	 */
> -	bool (*initial_config)(struct drm_fb_helper *fb_helper,
> -			       struct drm_fb_helper_crtc **crtcs,
> -			       struct drm_display_mode **modes,
> -			       struct drm_fb_offset *offsets,
> -			       bool *enabled, int width, int height);
>  };
>  
>  struct drm_fb_helper_connector {

-- 
Jani Nikula, Intel Open Source Graphics Center
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Intel-gfx] [PATCH 03/16] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  2019-03-26 20:48   ` Daniel Vetter
@ 2019-03-27 13:41     ` Noralf Trønnes
  2019-03-27 13:55       ` Daniel Vetter
  0 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-27 13:41 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, mstaudt, dri-devel



Den 26.03.2019 21.48, skrev Daniel Vetter:
> On Tue, Mar 26, 2019 at 06:55:33PM +0100, Noralf Trønnes wrote:
>> Prepare for moving drm_fb_helper modesetting code to drm_client.
>> drm_client will be linked to drm.ko, so move
>> __drm_atomic_helper_disable_plane() and __drm_atomic_helper_set_config()
>> out of drm_kms_helper.ko.
>>
>> While at it, fix two checkpatch complaints:
>> - WARNING: Block comments use a trailing */ on a separate line
>> - CHECK: Alignment should match open parenthesis
>>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> 
> Triggers a bit my midlayer ocd, but I can't come up with a better idea
> either.
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 

The Intel CI informed me that this patch didn't apply.

Turns out there's a patch in drm-next by Sean:

drm: Merge __drm_atomic_helper_disable_all() into
drm_atomic_helper_disable_all()

https://cgit.freedesktop.org/drm/drm/commit?id=37406a60fac7de336dec331a8707a94462ac5a5e

Should I move the whole function with the kerneldoc to drm_atomic.c, or
should I keep the doc and function in drm_atomic_helper.c and just
recreate __drm_atomic_helper_disable_all() and call that ?

Noralf.

>> ---
>>  drivers/gpu/drm/drm_atomic.c        | 168 ++++++++++++++++++++++++++++
>>  drivers/gpu/drm/drm_atomic_helper.c | 164 ---------------------------
>>  drivers/gpu/drm/drm_crtc_internal.h |   5 +
>>  include/drm/drm_atomic_helper.h     |   4 -
>>  4 files changed, 173 insertions(+), 168 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> index 5eb40130fafb..c3a9ffbf2310 100644
>> --- a/drivers/gpu/drm/drm_atomic.c
>> +++ b/drivers/gpu/drm/drm_atomic.c
>> @@ -1130,6 +1130,174 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
>>  }
>>  EXPORT_SYMBOL(drm_atomic_nonblocking_commit);
>>  
>> +/* just used from drm-client and atomic-helper: */
>> +int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
>> +				      struct drm_plane_state *plane_state)
>> +{
>> +	int ret;
>> +
>> +	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
>> +	if (ret != 0)
>> +		return ret;
>> +
>> +	drm_atomic_set_fb_for_plane(plane_state, NULL);
>> +	plane_state->crtc_x = 0;
>> +	plane_state->crtc_y = 0;
>> +	plane_state->crtc_w = 0;
>> +	plane_state->crtc_h = 0;
>> +	plane_state->src_x = 0;
>> +	plane_state->src_y = 0;
>> +	plane_state->src_w = 0;
>> +	plane_state->src_h = 0;
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(__drm_atomic_helper_disable_plane);
>> +
>> +static int update_output_state(struct drm_atomic_state *state,
>> +			       struct drm_mode_set *set)
>> +{
>> +	struct drm_device *dev = set->crtc->dev;
>> +	struct drm_crtc *crtc;
>> +	struct drm_crtc_state *new_crtc_state;
>> +	struct drm_connector *connector;
>> +	struct drm_connector_state *new_conn_state;
>> +	int ret, i;
>> +
>> +	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
>> +			       state->acquire_ctx);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* First disable all connectors on the target crtc. */
>> +	ret = drm_atomic_add_affected_connectors(state, set->crtc);
>> +	if (ret)
>> +		return ret;
>> +
>> +	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
>> +		if (new_conn_state->crtc == set->crtc) {
>> +			ret = drm_atomic_set_crtc_for_connector(new_conn_state,
>> +								NULL);
>> +			if (ret)
>> +				return ret;
>> +
>> +			/* Make sure legacy setCrtc always re-trains */
>> +			new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
>> +		}
>> +	}
>> +
>> +	/* Then set all connectors from set->connectors on the target crtc */
>> +	for (i = 0; i < set->num_connectors; i++) {
>> +		new_conn_state = drm_atomic_get_connector_state(state,
>> +								set->connectors[i]);
>> +		if (IS_ERR(new_conn_state))
>> +			return PTR_ERR(new_conn_state);
>> +
>> +		ret = drm_atomic_set_crtc_for_connector(new_conn_state,
>> +							set->crtc);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
>> +		/*
>> +		 * Don't update ->enable for the CRTC in the set_config request,
>> +		 * since a mismatch would indicate a bug in the upper layers.
>> +		 * The actual modeset code later on will catch any
>> +		 * inconsistencies here.
>> +		 */
>> +		if (crtc == set->crtc)
>> +			continue;
>> +
>> +		if (!new_crtc_state->connector_mask) {
>> +			ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
>> +								NULL);
>> +			if (ret < 0)
>> +				return ret;
>> +
>> +			new_crtc_state->active = false;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/* just used from drm-client and atomic-helper: */
>> +int __drm_atomic_helper_set_config(struct drm_mode_set *set,
>> +				   struct drm_atomic_state *state)
>> +{
>> +	struct drm_crtc_state *crtc_state;
>> +	struct drm_plane_state *primary_state;
>> +	struct drm_crtc *crtc = set->crtc;
>> +	int hdisplay, vdisplay;
>> +	int ret;
>> +
>> +	crtc_state = drm_atomic_get_crtc_state(state, crtc);
>> +	if (IS_ERR(crtc_state))
>> +		return PTR_ERR(crtc_state);
>> +
>> +	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
>> +	if (IS_ERR(primary_state))
>> +		return PTR_ERR(primary_state);
>> +
>> +	if (!set->mode) {
>> +		WARN_ON(set->fb);
>> +		WARN_ON(set->num_connectors);
>> +
>> +		ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
>> +		if (ret != 0)
>> +			return ret;
>> +
>> +		crtc_state->active = false;
>> +
>> +		ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
>> +		if (ret != 0)
>> +			return ret;
>> +
>> +		drm_atomic_set_fb_for_plane(primary_state, NULL);
>> +
>> +		goto commit;
>> +	}
>> +
>> +	WARN_ON(!set->fb);
>> +	WARN_ON(!set->num_connectors);
>> +
>> +	ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
>> +	if (ret != 0)
>> +		return ret;
>> +
>> +	crtc_state->active = true;
>> +
>> +	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
>> +	if (ret != 0)
>> +		return ret;
>> +
>> +	drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
>> +
>> +	drm_atomic_set_fb_for_plane(primary_state, set->fb);
>> +	primary_state->crtc_x = 0;
>> +	primary_state->crtc_y = 0;
>> +	primary_state->crtc_w = hdisplay;
>> +	primary_state->crtc_h = vdisplay;
>> +	primary_state->src_x = set->x << 16;
>> +	primary_state->src_y = set->y << 16;
>> +	if (drm_rotation_90_or_270(primary_state->rotation)) {
>> +		primary_state->src_w = vdisplay << 16;
>> +		primary_state->src_h = hdisplay << 16;
>> +	} else {
>> +		primary_state->src_w = hdisplay << 16;
>> +		primary_state->src_h = vdisplay << 16;
>> +	}
>> +
>> +commit:
>> +	ret = update_output_state(state, set);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(__drm_atomic_helper_set_config);
>> +
>>  void drm_atomic_print_state(const struct drm_atomic_state *state)
>>  {
>>  	struct drm_printer p = drm_info_printer(state->dev->dev);
>> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
>> index 2453678d1186..b0d960da53cb 100644
>> --- a/drivers/gpu/drm/drm_atomic_helper.c
>> +++ b/drivers/gpu/drm/drm_atomic_helper.c
>> @@ -2831,95 +2831,6 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane,
>>  }
>>  EXPORT_SYMBOL(drm_atomic_helper_disable_plane);
>>  
>> -/* just used from fb-helper and atomic-helper: */
>> -int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
>> -		struct drm_plane_state *plane_state)
>> -{
>> -	int ret;
>> -
>> -	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
>> -	if (ret != 0)
>> -		return ret;
>> -
>> -	drm_atomic_set_fb_for_plane(plane_state, NULL);
>> -	plane_state->crtc_x = 0;
>> -	plane_state->crtc_y = 0;
>> -	plane_state->crtc_w = 0;
>> -	plane_state->crtc_h = 0;
>> -	plane_state->src_x = 0;
>> -	plane_state->src_y = 0;
>> -	plane_state->src_w = 0;
>> -	plane_state->src_h = 0;
>> -
>> -	return 0;
>> -}
>> -
>> -static int update_output_state(struct drm_atomic_state *state,
>> -			       struct drm_mode_set *set)
>> -{
>> -	struct drm_device *dev = set->crtc->dev;
>> -	struct drm_crtc *crtc;
>> -	struct drm_crtc_state *new_crtc_state;
>> -	struct drm_connector *connector;
>> -	struct drm_connector_state *new_conn_state;
>> -	int ret, i;
>> -
>> -	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
>> -			       state->acquire_ctx);
>> -	if (ret)
>> -		return ret;
>> -
>> -	/* First disable all connectors on the target crtc. */
>> -	ret = drm_atomic_add_affected_connectors(state, set->crtc);
>> -	if (ret)
>> -		return ret;
>> -
>> -	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
>> -		if (new_conn_state->crtc == set->crtc) {
>> -			ret = drm_atomic_set_crtc_for_connector(new_conn_state,
>> -								NULL);
>> -			if (ret)
>> -				return ret;
>> -
>> -			/* Make sure legacy setCrtc always re-trains */
>> -			new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
>> -		}
>> -	}
>> -
>> -	/* Then set all connectors from set->connectors on the target crtc */
>> -	for (i = 0; i < set->num_connectors; i++) {
>> -		new_conn_state = drm_atomic_get_connector_state(state,
>> -							    set->connectors[i]);
>> -		if (IS_ERR(new_conn_state))
>> -			return PTR_ERR(new_conn_state);
>> -
>> -		ret = drm_atomic_set_crtc_for_connector(new_conn_state,
>> -							set->crtc);
>> -		if (ret)
>> -			return ret;
>> -	}
>> -
>> -	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
>> -		/* Don't update ->enable for the CRTC in the set_config request,
>> -		 * since a mismatch would indicate a bug in the upper layers.
>> -		 * The actual modeset code later on will catch any
>> -		 * inconsistencies here. */
>> -		if (crtc == set->crtc)
>> -			continue;
>> -
>> -		if (!new_crtc_state->connector_mask) {
>> -			ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
>> -								NULL);
>> -			if (ret < 0)
>> -				return ret;
>> -
>> -			new_crtc_state->active = false;
>> -		}
>> -	}
>> -
>> -	return 0;
>> -}
>> -
>>  /**
>>   * drm_atomic_helper_set_config - set a new config from userspace
>>   * @set: mode set configuration
>> @@ -2964,81 +2875,6 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set,
>>  }
>>  EXPORT_SYMBOL(drm_atomic_helper_set_config);
>>  
>> -/* just used from fb-helper and atomic-helper: */
>> -int __drm_atomic_helper_set_config(struct drm_mode_set *set,
>> -		struct drm_atomic_state *state)
>> -{
>> -	struct drm_crtc_state *crtc_state;
>> -	struct drm_plane_state *primary_state;
>> -	struct drm_crtc *crtc = set->crtc;
>> -	int hdisplay, vdisplay;
>> -	int ret;
>> -
>> -	crtc_state = drm_atomic_get_crtc_state(state, crtc);
>> -	if (IS_ERR(crtc_state))
>> -		return PTR_ERR(crtc_state);
>> -
>> -	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
>> -	if (IS_ERR(primary_state))
>> -		return PTR_ERR(primary_state);
>> -
>> -	if (!set->mode) {
>> -		WARN_ON(set->fb);
>> -		WARN_ON(set->num_connectors);
>> -
>> -		ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
>> -		if (ret != 0)
>> -			return ret;
>> -
>> -		crtc_state->active = false;
>> -
>> -		ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
>> -		if (ret != 0)
>> -			return ret;
>> -
>> -		drm_atomic_set_fb_for_plane(primary_state, NULL);
>> -
>> -		goto commit;
>> -	}
>> -
>> -	WARN_ON(!set->fb);
>> -	WARN_ON(!set->num_connectors);
>> -
>> -	ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
>> -	if (ret != 0)
>> -		return ret;
>> -
>> -	crtc_state->active = true;
>> -
>> -	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
>> -	if (ret != 0)
>> -		return ret;
>> -
>> -	drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
>> -
>> -	drm_atomic_set_fb_for_plane(primary_state, set->fb);
>> -	primary_state->crtc_x = 0;
>> -	primary_state->crtc_y = 0;
>> -	primary_state->crtc_w = hdisplay;
>> -	primary_state->crtc_h = vdisplay;
>> -	primary_state->src_x = set->x << 16;
>> -	primary_state->src_y = set->y << 16;
>> -	if (drm_rotation_90_or_270(primary_state->rotation)) {
>> -		primary_state->src_w = vdisplay << 16;
>> -		primary_state->src_h = hdisplay << 16;
>> -	} else {
>> -		primary_state->src_w = hdisplay << 16;
>> -		primary_state->src_h = vdisplay << 16;
>> -	}
>> -
>> -commit:
>> -	ret = update_output_state(state, set);
>> -	if (ret)
>> -		return ret;
>> -
>> -	return 0;
>> -}
>> -
>>  static int __drm_atomic_helper_disable_all(struct drm_device *dev,
>>  					   struct drm_modeset_acquire_ctx *ctx,
>>  					   bool clean_old_fbs)
>> diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
>> index 216f2a9ee3d4..22a63a544ec7 100644
>> --- a/drivers/gpu/drm/drm_crtc_internal.h
>> +++ b/drivers/gpu/drm/drm_crtc_internal.h
>> @@ -207,6 +207,11 @@ struct drm_minor;
>>  int drm_atomic_debugfs_init(struct drm_minor *minor);
>>  #endif
>>  
>> +int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
>> +				      struct drm_plane_state *plane_state);
>> +int __drm_atomic_helper_set_config(struct drm_mode_set *set,
>> +				   struct drm_atomic_state *state);
>> +
>>  void drm_atomic_print_state(const struct drm_atomic_state *state);
>>  
>>  /* drm_atomic_uapi.c */
>> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
>> index 58214be3bf3d..bf4e07141d81 100644
>> --- a/include/drm/drm_atomic_helper.h
>> +++ b/include/drm/drm_atomic_helper.h
>> @@ -117,12 +117,8 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
>>  				   struct drm_modeset_acquire_ctx *ctx);
>>  int drm_atomic_helper_disable_plane(struct drm_plane *plane,
>>  				    struct drm_modeset_acquire_ctx *ctx);
>> -int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
>> -		struct drm_plane_state *plane_state);
>>  int drm_atomic_helper_set_config(struct drm_mode_set *set,
>>  				 struct drm_modeset_acquire_ctx *ctx);
>> -int __drm_atomic_helper_set_config(struct drm_mode_set *set,
>> -		struct drm_atomic_state *state);
>>  
>>  int drm_atomic_helper_disable_all(struct drm_device *dev,
>>  				  struct drm_modeset_acquire_ctx *ctx);
>> -- 
>> 2.20.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (15 preceding siblings ...)
  2019-03-26 17:55 ` [PATCH 16/16] drm/vc4: Call drm_dev_register() after all setup is done Noralf Trønnes
@ 2019-03-27 13:45 ` Noralf Trønnes
  2019-03-27 13:52   ` Thomas Zimmermann
  2019-03-28  9:31 ` [Intel-gfx] " Daniel Vetter
  17 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-27 13:45 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx



Den 26.03.2019 18.55, skrev Noralf Trønnes:
> This moves the modesetting code from drm_fb_helper to drm_client so it
> can be shared by all internal clients.
> 
> I have also added a client display abstraction and a bootsplash example
> client to show where this might be heading. Hopefully Max Staudt will be
> able to pick up his bootsplash work now.

I get 'User has moved to <unknown>' failure on Max's email address. If
someone knows his new address, please cc him this cover letter.

Noralf.

> 
> Noralf.
> 
> Noralf Trønnes (16):
>   drm/fb-helper: Remove unused gamma_size variable
>   drm/fb-helper: dpms_legacy(): Only set on connectors in use
>   drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
>   drm/fb-helper: No need to cache rotation and sw_rotations
>   drm/fb-helper: Remove drm_fb_helper_crtc->{x,y,desired_mode}
>   drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
>   drm/fb-helper: Remove drm_fb_helper_crtc
>   drm/fb-helper: Prepare to move out commit code
>   drm/fb-helper: Move out commit code
>   drm/fb-helper: Remove drm_fb_helper_connector
>   drm/fb-helper: Prepare to move out modeset config code
>   drm/fb-helper: Move out modeset config code
>   drm/fb-helper: Avoid race with DRM userspace
>   drm/client: Add display abstraction
>   drm/client: Hack: Add bootsplash example
>   drm/vc4: Call drm_dev_register() after all setup is done
> 
>  Documentation/gpu/todo.rst          |   10 +
>  drivers/gpu/drm/Kconfig             |    5 +
>  drivers/gpu/drm/Makefile            |    1 +
>  drivers/gpu/drm/drm_atomic.c        |  168 ++++
>  drivers/gpu/drm/drm_atomic_helper.c |  164 ---
>  drivers/gpu/drm/drm_auth.c          |   20 +
>  drivers/gpu/drm/drm_bootsplash.c    |  216 ++++
>  drivers/gpu/drm/drm_client.c        | 1449 +++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_crtc_internal.h |    5 +
>  drivers/gpu/drm/drm_drv.c           |    4 +
>  drivers/gpu/drm/drm_fb_helper.c     | 1151 ++-------------------
>  drivers/gpu/drm/drm_internal.h      |    2 +
>  drivers/gpu/drm/i915/intel_fbdev.c  |  218 ----
>  drivers/gpu/drm/vc4/vc4_drv.c       |    6 +-
>  include/drm/drm_atomic_helper.h     |    4 -
>  include/drm/drm_client.h            |  117 +++
>  include/drm/drm_fb_helper.h         |  127 +--
>  17 files changed, 2128 insertions(+), 1539 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_bootsplash.c
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client
  2019-03-27 13:45 ` [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
@ 2019-03-27 13:52   ` Thomas Zimmermann
  0 siblings, 0 replies; 42+ messages in thread
From: Thomas Zimmermann @ 2019-03-27 13:52 UTC (permalink / raw)
  To: Noralf Trønnes, dri-devel; +Cc: intel-gfx


[-- Attachment #1.1.1: Type: text/plain, Size: 3005 bytes --]

Hi

Am 27.03.19 um 14:45 schrieb Noralf Trønnes:
> 
> 
> Den 26.03.2019 18.55, skrev Noralf Trønnes:
>> This moves the modesetting code from drm_fb_helper to drm_client so it
>> can be shared by all internal clients.
>>
>> I have also added a client display abstraction and a bootsplash example
>> client to show where this might be heading. Hopefully Max Staudt will be
>> able to pick up his bootsplash work now.
> 
> I get 'User has moved to <unknown>' failure on Max's email address. If
> someone knows his new address, please cc him this cover letter.

He left SUSE quiet a while ago.

Best regards
Thomas

> 
> Noralf.
> 
>>
>> Noralf.
>>
>> Noralf Trønnes (16):
>>   drm/fb-helper: Remove unused gamma_size variable
>>   drm/fb-helper: dpms_legacy(): Only set on connectors in use
>>   drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
>>   drm/fb-helper: No need to cache rotation and sw_rotations
>>   drm/fb-helper: Remove drm_fb_helper_crtc->{x,y,desired_mode}
>>   drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
>>   drm/fb-helper: Remove drm_fb_helper_crtc
>>   drm/fb-helper: Prepare to move out commit code
>>   drm/fb-helper: Move out commit code
>>   drm/fb-helper: Remove drm_fb_helper_connector
>>   drm/fb-helper: Prepare to move out modeset config code
>>   drm/fb-helper: Move out modeset config code
>>   drm/fb-helper: Avoid race with DRM userspace
>>   drm/client: Add display abstraction
>>   drm/client: Hack: Add bootsplash example
>>   drm/vc4: Call drm_dev_register() after all setup is done
>>
>>  Documentation/gpu/todo.rst          |   10 +
>>  drivers/gpu/drm/Kconfig             |    5 +
>>  drivers/gpu/drm/Makefile            |    1 +
>>  drivers/gpu/drm/drm_atomic.c        |  168 ++++
>>  drivers/gpu/drm/drm_atomic_helper.c |  164 ---
>>  drivers/gpu/drm/drm_auth.c          |   20 +
>>  drivers/gpu/drm/drm_bootsplash.c    |  216 ++++
>>  drivers/gpu/drm/drm_client.c        | 1449 +++++++++++++++++++++++++++
>>  drivers/gpu/drm/drm_crtc_internal.h |    5 +
>>  drivers/gpu/drm/drm_drv.c           |    4 +
>>  drivers/gpu/drm/drm_fb_helper.c     | 1151 ++-------------------
>>  drivers/gpu/drm/drm_internal.h      |    2 +
>>  drivers/gpu/drm/i915/intel_fbdev.c  |  218 ----
>>  drivers/gpu/drm/vc4/vc4_drv.c       |    6 +-
>>  include/drm/drm_atomic_helper.h     |    4 -
>>  include/drm/drm_client.h            |  117 +++
>>  include/drm/drm_fb_helper.h         |  127 +--
>>  17 files changed, 2128 insertions(+), 1539 deletions(-)
>>  create mode 100644 drivers/gpu/drm/drm_bootsplash.c
>>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah
HRB 21284 (AG Nürnberg)


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 03/16] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  2019-03-27 13:41     ` [Intel-gfx] " Noralf Trønnes
@ 2019-03-27 13:55       ` Daniel Vetter
  2019-03-27 14:27         ` [Intel-gfx] " Noralf Trønnes
  0 siblings, 1 reply; 42+ messages in thread
From: Daniel Vetter @ 2019-03-27 13:55 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, 'Max Staudt, dri-devel

On Wed, Mar 27, 2019 at 2:42 PM Noralf Trønnes <noralf@tronnes.org> wrote:
>
>
>
> Den 26.03.2019 21.48, skrev Daniel Vetter:
> > On Tue, Mar 26, 2019 at 06:55:33PM +0100, Noralf Trønnes wrote:
> >> Prepare for moving drm_fb_helper modesetting code to drm_client.
> >> drm_client will be linked to drm.ko, so move
> >> __drm_atomic_helper_disable_plane() and __drm_atomic_helper_set_config()
> >> out of drm_kms_helper.ko.
> >>
> >> While at it, fix two checkpatch complaints:
> >> - WARNING: Block comments use a trailing */ on a separate line
> >> - CHECK: Alignment should match open parenthesis
> >>
> >> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> >
> > Triggers a bit my midlayer ocd, but I can't come up with a better idea
> > either.
> >
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >
>
> The Intel CI informed me that this patch didn't apply..
>
> Turns out there's a patch in drm-next by Sean:
>
> drm: Merge __drm_atomic_helper_disable_all() into
> drm_atomic_helper_disable_all()
>
> https://cgit.freedesktop.org/drm/drm/commit?id=37406a60fac7de336dec331a8707a94462ac5a5e
>
> Should I move the whole function with the kerneldoc to drm_atomic.c, or
> should I keep the doc and function in drm_atomic_helper.c and just
> recreate __drm_atomic_helper_disable_all() and call that ?

So my longterm goal with all these compat helpers is to move them into
the core anyway, and make them at least the default, if not only the
only accepted choice for atomic drivers. We've already done that for
the dpms hook. We can't make it the enforced default yet for planes
because of cursors, but I think we could just move both of these into
the core (disable_plane and update_plane), make it the default option,
and remove all driver users that just set it as the default hook.

Would need to be renamed to something like drm_atomic_default_* ofc.

Not sure why you're talking about disable_all here though, since that
doesn't seem to be touched in this patch at all?
-Daniel

>
> Noralf.
>
> >> ---
> >>  drivers/gpu/drm/drm_atomic.c        | 168 ++++++++++++++++++++++++++++
> >>  drivers/gpu/drm/drm_atomic_helper.c | 164 ---------------------------
> >>  drivers/gpu/drm/drm_crtc_internal.h |   5 +
> >>  include/drm/drm_atomic_helper.h     |   4 -
> >>  4 files changed, 173 insertions(+), 168 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >> index 5eb40130fafb..c3a9ffbf2310 100644
> >> --- a/drivers/gpu/drm/drm_atomic.c
> >> +++ b/drivers/gpu/drm/drm_atomic.c
> >> @@ -1130,6 +1130,174 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
> >>  }
> >>  EXPORT_SYMBOL(drm_atomic_nonblocking_commit);
> >>
> >> +/* just used from drm-client and atomic-helper: */
> >> +int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
> >> +                                  struct drm_plane_state *plane_state)
> >> +{
> >> +    int ret;
> >> +
> >> +    ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
> >> +    if (ret != 0)
> >> +            return ret;
> >> +
> >> +    drm_atomic_set_fb_for_plane(plane_state, NULL);
> >> +    plane_state->crtc_x = 0;
> >> +    plane_state->crtc_y = 0;
> >> +    plane_state->crtc_w = 0;
> >> +    plane_state->crtc_h = 0;
> >> +    plane_state->src_x = 0;
> >> +    plane_state->src_y = 0;
> >> +    plane_state->src_w = 0;
> >> +    plane_state->src_h = 0;
> >> +
> >> +    return 0;
> >> +}
> >> +EXPORT_SYMBOL(__drm_atomic_helper_disable_plane);
> >> +
> >> +static int update_output_state(struct drm_atomic_state *state,
> >> +                           struct drm_mode_set *set)
> >> +{
> >> +    struct drm_device *dev = set->crtc->dev;
> >> +    struct drm_crtc *crtc;
> >> +    struct drm_crtc_state *new_crtc_state;
> >> +    struct drm_connector *connector;
> >> +    struct drm_connector_state *new_conn_state;
> >> +    int ret, i;
> >> +
> >> +    ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
> >> +                           state->acquire_ctx);
> >> +    if (ret)
> >> +            return ret;
> >> +
> >> +    /* First disable all connectors on the target crtc. */
> >> +    ret = drm_atomic_add_affected_connectors(state, set->crtc);
> >> +    if (ret)
> >> +            return ret;
> >> +
> >> +    for_each_new_connector_in_state(state, connector, new_conn_state, i) {
> >> +            if (new_conn_state->crtc == set->crtc) {
> >> +                    ret = drm_atomic_set_crtc_for_connector(new_conn_state,
> >> +                                                            NULL);
> >> +                    if (ret)
> >> +                            return ret;
> >> +
> >> +                    /* Make sure legacy setCrtc always re-trains */
> >> +                    new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
> >> +            }
> >> +    }
> >> +
> >> +    /* Then set all connectors from set->connectors on the target crtc */
> >> +    for (i = 0; i < set->num_connectors; i++) {
> >> +            new_conn_state = drm_atomic_get_connector_state(state,
> >> +                                                            set->connectors[i]);
> >> +            if (IS_ERR(new_conn_state))
> >> +                    return PTR_ERR(new_conn_state);
> >> +
> >> +            ret = drm_atomic_set_crtc_for_connector(new_conn_state,
> >> +                                                    set->crtc);
> >> +            if (ret)
> >> +                    return ret;
> >> +    }
> >> +
> >> +    for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
> >> +            /*
> >> +             * Don't update ->enable for the CRTC in the set_config request,
> >> +             * since a mismatch would indicate a bug in the upper layers.
> >> +             * The actual modeset code later on will catch any
> >> +             * inconsistencies here.
> >> +             */
> >> +            if (crtc == set->crtc)
> >> +                    continue;
> >> +
> >> +            if (!new_crtc_state->connector_mask) {
> >> +                    ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
> >> +                                                            NULL);
> >> +                    if (ret < 0)
> >> +                            return ret;
> >> +
> >> +                    new_crtc_state->active = false;
> >> +            }
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +/* just used from drm-client and atomic-helper: */
> >> +int __drm_atomic_helper_set_config(struct drm_mode_set *set,
> >> +                               struct drm_atomic_state *state)
> >> +{
> >> +    struct drm_crtc_state *crtc_state;
> >> +    struct drm_plane_state *primary_state;
> >> +    struct drm_crtc *crtc = set->crtc;
> >> +    int hdisplay, vdisplay;
> >> +    int ret;
> >> +
> >> +    crtc_state = drm_atomic_get_crtc_state(state, crtc);
> >> +    if (IS_ERR(crtc_state))
> >> +            return PTR_ERR(crtc_state);
> >> +
> >> +    primary_state = drm_atomic_get_plane_state(state, crtc->primary);
> >> +    if (IS_ERR(primary_state))
> >> +            return PTR_ERR(primary_state);
> >> +
> >> +    if (!set->mode) {
> >> +            WARN_ON(set->fb);
> >> +            WARN_ON(set->num_connectors);
> >> +
> >> +            ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
> >> +            if (ret != 0)
> >> +                    return ret;
> >> +
> >> +            crtc_state->active = false;
> >> +
> >> +            ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
> >> +            if (ret != 0)
> >> +                    return ret;
> >> +
> >> +            drm_atomic_set_fb_for_plane(primary_state, NULL);
> >> +
> >> +            goto commit;
> >> +    }
> >> +
> >> +    WARN_ON(!set->fb);
> >> +    WARN_ON(!set->num_connectors);
> >> +
> >> +    ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
> >> +    if (ret != 0)
> >> +            return ret;
> >> +
> >> +    crtc_state->active = true;
> >> +
> >> +    ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
> >> +    if (ret != 0)
> >> +            return ret;
> >> +
> >> +    drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
> >> +
> >> +    drm_atomic_set_fb_for_plane(primary_state, set->fb);
> >> +    primary_state->crtc_x = 0;
> >> +    primary_state->crtc_y = 0;
> >> +    primary_state->crtc_w = hdisplay;
> >> +    primary_state->crtc_h = vdisplay;
> >> +    primary_state->src_x = set->x << 16;
> >> +    primary_state->src_y = set->y << 16;
> >> +    if (drm_rotation_90_or_270(primary_state->rotation)) {
> >> +            primary_state->src_w = vdisplay << 16;
> >> +            primary_state->src_h = hdisplay << 16;
> >> +    } else {
> >> +            primary_state->src_w = hdisplay << 16;
> >> +            primary_state->src_h = vdisplay << 16;
> >> +    }
> >> +
> >> +commit:
> >> +    ret = update_output_state(state, set);
> >> +    if (ret)
> >> +            return ret;
> >> +
> >> +    return 0;
> >> +}
> >> +EXPORT_SYMBOL(__drm_atomic_helper_set_config);
> >> +
> >>  void drm_atomic_print_state(const struct drm_atomic_state *state)
> >>  {
> >>      struct drm_printer p = drm_info_printer(state->dev->dev);
> >> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> >> index 2453678d1186..b0d960da53cb 100644
> >> --- a/drivers/gpu/drm/drm_atomic_helper.c
> >> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> >> @@ -2831,95 +2831,6 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane,
> >>  }
> >>  EXPORT_SYMBOL(drm_atomic_helper_disable_plane);
> >>
> >> -/* just used from fb-helper and atomic-helper: */
> >> -int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
> >> -            struct drm_plane_state *plane_state)
> >> -{
> >> -    int ret;
> >> -
> >> -    ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
> >> -    if (ret != 0)
> >> -            return ret;
> >> -
> >> -    drm_atomic_set_fb_for_plane(plane_state, NULL);
> >> -    plane_state->crtc_x = 0;
> >> -    plane_state->crtc_y = 0;
> >> -    plane_state->crtc_w = 0;
> >> -    plane_state->crtc_h = 0;
> >> -    plane_state->src_x = 0;
> >> -    plane_state->src_y = 0;
> >> -    plane_state->src_w = 0;
> >> -    plane_state->src_h = 0;
> >> -
> >> -    return 0;
> >> -}
> >> -
> >> -static int update_output_state(struct drm_atomic_state *state,
> >> -                           struct drm_mode_set *set)
> >> -{
> >> -    struct drm_device *dev = set->crtc->dev;
> >> -    struct drm_crtc *crtc;
> >> -    struct drm_crtc_state *new_crtc_state;
> >> -    struct drm_connector *connector;
> >> -    struct drm_connector_state *new_conn_state;
> >> -    int ret, i;
> >> -
> >> -    ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
> >> -                           state->acquire_ctx);
> >> -    if (ret)
> >> -            return ret;
> >> -
> >> -    /* First disable all connectors on the target crtc. */
> >> -    ret = drm_atomic_add_affected_connectors(state, set->crtc);
> >> -    if (ret)
> >> -            return ret;
> >> -
> >> -    for_each_new_connector_in_state(state, connector, new_conn_state, i) {
> >> -            if (new_conn_state->crtc == set->crtc) {
> >> -                    ret = drm_atomic_set_crtc_for_connector(new_conn_state,
> >> -                                                            NULL);
> >> -                    if (ret)
> >> -                            return ret;
> >> -
> >> -                    /* Make sure legacy setCrtc always re-trains */
> >> -                    new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
> >> -            }
> >> -    }
> >> -
> >> -    /* Then set all connectors from set->connectors on the target crtc */
> >> -    for (i = 0; i < set->num_connectors; i++) {
> >> -            new_conn_state = drm_atomic_get_connector_state(state,
> >> -                                                        set->connectors[i]);
> >> -            if (IS_ERR(new_conn_state))
> >> -                    return PTR_ERR(new_conn_state);
> >> -
> >> -            ret = drm_atomic_set_crtc_for_connector(new_conn_state,
> >> -                                                    set->crtc);
> >> -            if (ret)
> >> -                    return ret;
> >> -    }
> >> -
> >> -    for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
> >> -            /* Don't update ->enable for the CRTC in the set_config request,
> >> -             * since a mismatch would indicate a bug in the upper layers.
> >> -             * The actual modeset code later on will catch any
> >> -             * inconsistencies here. */
> >> -            if (crtc == set->crtc)
> >> -                    continue;
> >> -
> >> -            if (!new_crtc_state->connector_mask) {
> >> -                    ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
> >> -                                                            NULL);
> >> -                    if (ret < 0)
> >> -                            return ret;
> >> -
> >> -                    new_crtc_state->active = false;
> >> -            }
> >> -    }
> >> -
> >> -    return 0;
> >> -}
> >> -
> >>  /**
> >>   * drm_atomic_helper_set_config - set a new config from userspace
> >>   * @set: mode set configuration
> >> @@ -2964,81 +2875,6 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set,
> >>  }
> >>  EXPORT_SYMBOL(drm_atomic_helper_set_config);
> >>
> >> -/* just used from fb-helper and atomic-helper: */
> >> -int __drm_atomic_helper_set_config(struct drm_mode_set *set,
> >> -            struct drm_atomic_state *state)
> >> -{
> >> -    struct drm_crtc_state *crtc_state;
> >> -    struct drm_plane_state *primary_state;
> >> -    struct drm_crtc *crtc = set->crtc;
> >> -    int hdisplay, vdisplay;
> >> -    int ret;
> >> -
> >> -    crtc_state = drm_atomic_get_crtc_state(state, crtc);
> >> -    if (IS_ERR(crtc_state))
> >> -            return PTR_ERR(crtc_state);
> >> -
> >> -    primary_state = drm_atomic_get_plane_state(state, crtc->primary);
> >> -    if (IS_ERR(primary_state))
> >> -            return PTR_ERR(primary_state);
> >> -
> >> -    if (!set->mode) {
> >> -            WARN_ON(set->fb);
> >> -            WARN_ON(set->num_connectors);
> >> -
> >> -            ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
> >> -            if (ret != 0)
> >> -                    return ret;
> >> -
> >> -            crtc_state->active = false;
> >> -
> >> -            ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
> >> -            if (ret != 0)
> >> -                    return ret;
> >> -
> >> -            drm_atomic_set_fb_for_plane(primary_state, NULL);
> >> -
> >> -            goto commit;
> >> -    }
> >> -
> >> -    WARN_ON(!set->fb);
> >> -    WARN_ON(!set->num_connectors);
> >> -
> >> -    ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
> >> -    if (ret != 0)
> >> -            return ret;
> >> -
> >> -    crtc_state->active = true;
> >> -
> >> -    ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
> >> -    if (ret != 0)
> >> -            return ret;
> >> -
> >> -    drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
> >> -
> >> -    drm_atomic_set_fb_for_plane(primary_state, set->fb);
> >> -    primary_state->crtc_x = 0;
> >> -    primary_state->crtc_y = 0;
> >> -    primary_state->crtc_w = hdisplay;
> >> -    primary_state->crtc_h = vdisplay;
> >> -    primary_state->src_x = set->x << 16;
> >> -    primary_state->src_y = set->y << 16;
> >> -    if (drm_rotation_90_or_270(primary_state->rotation)) {
> >> -            primary_state->src_w = vdisplay << 16;
> >> -            primary_state->src_h = hdisplay << 16;
> >> -    } else {
> >> -            primary_state->src_w = hdisplay << 16;
> >> -            primary_state->src_h = vdisplay << 16;
> >> -    }
> >> -
> >> -commit:
> >> -    ret = update_output_state(state, set);
> >> -    if (ret)
> >> -            return ret;
> >> -
> >> -    return 0;
> >> -}
> >> -
> >>  static int __drm_atomic_helper_disable_all(struct drm_device *dev,
> >>                                         struct drm_modeset_acquire_ctx *ctx,
> >>                                         bool clean_old_fbs)
> >> diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
> >> index 216f2a9ee3d4..22a63a544ec7 100644
> >> --- a/drivers/gpu/drm/drm_crtc_internal.h
> >> +++ b/drivers/gpu/drm/drm_crtc_internal.h
> >> @@ -207,6 +207,11 @@ struct drm_minor;
> >>  int drm_atomic_debugfs_init(struct drm_minor *minor);
> >>  #endif
> >>
> >> +int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
> >> +                                  struct drm_plane_state *plane_state);
> >> +int __drm_atomic_helper_set_config(struct drm_mode_set *set,
> >> +                               struct drm_atomic_state *state);
> >> +
> >>  void drm_atomic_print_state(const struct drm_atomic_state *state);
> >>
> >>  /* drm_atomic_uapi.c */
> >> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> >> index 58214be3bf3d..bf4e07141d81 100644
> >> --- a/include/drm/drm_atomic_helper.h
> >> +++ b/include/drm/drm_atomic_helper.h
> >> @@ -117,12 +117,8 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
> >>                                 struct drm_modeset_acquire_ctx *ctx);
> >>  int drm_atomic_helper_disable_plane(struct drm_plane *plane,
> >>                                  struct drm_modeset_acquire_ctx *ctx);
> >> -int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
> >> -            struct drm_plane_state *plane_state);
> >>  int drm_atomic_helper_set_config(struct drm_mode_set *set,
> >>                               struct drm_modeset_acquire_ctx *ctx);
> >> -int __drm_atomic_helper_set_config(struct drm_mode_set *set,
> >> -            struct drm_atomic_state *state);
> >>
> >>  int drm_atomic_helper_disable_all(struct drm_device *dev,
> >>                                struct drm_modeset_acquire_ctx *ctx);
> >> --
> >> 2.20.1
> >>
> >> _______________________________________________
> >> Intel-gfx mailing list
> >> Intel-gfx@lists.freedesktop.org
> >> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> >



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 09/16] drm/fb-helper: Move out commit code
  2019-03-26 17:55 ` [PATCH 09/16] drm/fb-helper: Move " Noralf Trønnes
@ 2019-03-27 14:13   ` Emmanuel Vadot
  2019-03-27 15:01     ` Noralf Trønnes
  0 siblings, 1 reply; 42+ messages in thread
From: Emmanuel Vadot @ 2019-03-27 14:13 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, mstaudt, dri-devel


 Hi Noralf,

On Tue, 26 Mar 2019 18:55:39 +0100
Noralf Trønnes <noralf@tronnes.org> wrote:

> Move the modeset commit code to drm_client.
> No changes except exporting API.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  drivers/gpu/drm/drm_client.c    | 236 ++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_fb_helper.c | 232 -------------------------------
>  include/drm/drm_client.h        |   3 +
>  3 files changed, 239 insertions(+), 232 deletions(-)
> 

 It looks like you are moving MIT licenced code to a GPL-only
licenced file.

 Cheers,

-- 
Emmanuel Vadot <manu@bidouilliste.com> <manu@freebsd.org>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Intel-gfx] [PATCH 03/16] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  2019-03-27 13:55       ` Daniel Vetter
@ 2019-03-27 14:27         ` Noralf Trønnes
  0 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-27 14:27 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, 'Max Staudt, dri-devel



Den 27.03.2019 14.55, skrev Daniel Vetter:
> On Wed, Mar 27, 2019 at 2:42 PM Noralf Trønnes <noralf@tronnes.org> wrote:
>>
>>
>>
>> Den 26.03.2019 21.48, skrev Daniel Vetter:
>>> On Tue, Mar 26, 2019 at 06:55:33PM +0100, Noralf Trønnes wrote:
>>>> Prepare for moving drm_fb_helper modesetting code to drm_client.
>>>> drm_client will be linked to drm.ko, so move
>>>> __drm_atomic_helper_disable_plane() and __drm_atomic_helper_set_config()
>>>> out of drm_kms_helper.ko.
>>>>
>>>> While at it, fix two checkpatch complaints:
>>>> - WARNING: Block comments use a trailing */ on a separate line
>>>> - CHECK: Alignment should match open parenthesis
>>>>
>>>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>>>
>>> Triggers a bit my midlayer ocd, but I can't come up with a better idea
>>> either.
>>>
>>> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>>
>>
>> The Intel CI informed me that this patch didn't apply..
>>
>> Turns out there's a patch in drm-next by Sean:
>>
>> drm: Merge __drm_atomic_helper_disable_all() into
>> drm_atomic_helper_disable_all()
>>
>> https://cgit.freedesktop.org/drm/drm/commit?id=37406a60fac7de336dec331a8707a94462ac5a5e
>>
>> Should I move the whole function with the kerneldoc to drm_atomic.c, or
>> should I keep the doc and function in drm_atomic_helper.c and just
>> recreate __drm_atomic_helper_disable_all() and call that ?
> 
> So my longterm goal with all these compat helpers is to move them into
> the core anyway, and make them at least the default, if not only the
> only accepted choice for atomic drivers. We've already done that for
> the dpms hook. We can't make it the enforced default yet for planes
> because of cursors, but I think we could just move both of these into
> the core (disable_plane and update_plane), make it the default option,
> and remove all driver users that just set it as the default hook.
> 
> Would need to be renamed to something like drm_atomic_default_* ofc.
> 
> Not sure why you're talking about disable_all here though, since that
> doesn't seem to be touched in this patch at all?

Sorry my bad, I was just confused. Looking at it again, I see that I can
just rebase on top of that patch.

Noralf.

> -Daniel
> 
>>
>> Noralf.
>>
>>>> ---
>>>>  drivers/gpu/drm/drm_atomic.c        | 168 ++++++++++++++++++++++++++++
>>>>  drivers/gpu/drm/drm_atomic_helper.c | 164 ---------------------------
>>>>  drivers/gpu/drm/drm_crtc_internal.h |   5 +
>>>>  include/drm/drm_atomic_helper.h     |   4 -
>>>>  4 files changed, 173 insertions(+), 168 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>>>> index 5eb40130fafb..c3a9ffbf2310 100644
>>>> --- a/drivers/gpu/drm/drm_atomic.c
>>>> +++ b/drivers/gpu/drm/drm_atomic.c
>>>> @@ -1130,6 +1130,174 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
>>>>  }
>>>>  EXPORT_SYMBOL(drm_atomic_nonblocking_commit);
>>>>
>>>> +/* just used from drm-client and atomic-helper: */
>>>> +int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
>>>> +                                  struct drm_plane_state *plane_state)
>>>> +{
>>>> +    int ret;
>>>> +
>>>> +    ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
>>>> +    if (ret != 0)
>>>> +            return ret;
>>>> +
>>>> +    drm_atomic_set_fb_for_plane(plane_state, NULL);
>>>> +    plane_state->crtc_x = 0;
>>>> +    plane_state->crtc_y = 0;
>>>> +    plane_state->crtc_w = 0;
>>>> +    plane_state->crtc_h = 0;
>>>> +    plane_state->src_x = 0;
>>>> +    plane_state->src_y = 0;
>>>> +    plane_state->src_w = 0;
>>>> +    plane_state->src_h = 0;
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +EXPORT_SYMBOL(__drm_atomic_helper_disable_plane);
>>>> +
>>>> +static int update_output_state(struct drm_atomic_state *state,
>>>> +                           struct drm_mode_set *set)
>>>> +{
>>>> +    struct drm_device *dev = set->crtc->dev;
>>>> +    struct drm_crtc *crtc;
>>>> +    struct drm_crtc_state *new_crtc_state;
>>>> +    struct drm_connector *connector;
>>>> +    struct drm_connector_state *new_conn_state;
>>>> +    int ret, i;
>>>> +
>>>> +    ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
>>>> +                           state->acquire_ctx);
>>>> +    if (ret)
>>>> +            return ret;
>>>> +
>>>> +    /* First disable all connectors on the target crtc. */
>>>> +    ret = drm_atomic_add_affected_connectors(state, set->crtc);
>>>> +    if (ret)
>>>> +            return ret;
>>>> +
>>>> +    for_each_new_connector_in_state(state, connector, new_conn_state, i) {
>>>> +            if (new_conn_state->crtc == set->crtc) {
>>>> +                    ret = drm_atomic_set_crtc_for_connector(new_conn_state,
>>>> +                                                            NULL);
>>>> +                    if (ret)
>>>> +                            return ret;
>>>> +
>>>> +                    /* Make sure legacy setCrtc always re-trains */
>>>> +                    new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
>>>> +            }
>>>> +    }
>>>> +
>>>> +    /* Then set all connectors from set->connectors on the target crtc */
>>>> +    for (i = 0; i < set->num_connectors; i++) {
>>>> +            new_conn_state = drm_atomic_get_connector_state(state,
>>>> +                                                            set->connectors[i]);
>>>> +            if (IS_ERR(new_conn_state))
>>>> +                    return PTR_ERR(new_conn_state);
>>>> +
>>>> +            ret = drm_atomic_set_crtc_for_connector(new_conn_state,
>>>> +                                                    set->crtc);
>>>> +            if (ret)
>>>> +                    return ret;
>>>> +    }
>>>> +
>>>> +    for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
>>>> +            /*
>>>> +             * Don't update ->enable for the CRTC in the set_config request,
>>>> +             * since a mismatch would indicate a bug in the upper layers.
>>>> +             * The actual modeset code later on will catch any
>>>> +             * inconsistencies here.
>>>> +             */
>>>> +            if (crtc == set->crtc)
>>>> +                    continue;
>>>> +
>>>> +            if (!new_crtc_state->connector_mask) {
>>>> +                    ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
>>>> +                                                            NULL);
>>>> +                    if (ret < 0)
>>>> +                            return ret;
>>>> +
>>>> +                    new_crtc_state->active = false;
>>>> +            }
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +/* just used from drm-client and atomic-helper: */
>>>> +int __drm_atomic_helper_set_config(struct drm_mode_set *set,
>>>> +                               struct drm_atomic_state *state)
>>>> +{
>>>> +    struct drm_crtc_state *crtc_state;
>>>> +    struct drm_plane_state *primary_state;
>>>> +    struct drm_crtc *crtc = set->crtc;
>>>> +    int hdisplay, vdisplay;
>>>> +    int ret;
>>>> +
>>>> +    crtc_state = drm_atomic_get_crtc_state(state, crtc);
>>>> +    if (IS_ERR(crtc_state))
>>>> +            return PTR_ERR(crtc_state);
>>>> +
>>>> +    primary_state = drm_atomic_get_plane_state(state, crtc->primary);
>>>> +    if (IS_ERR(primary_state))
>>>> +            return PTR_ERR(primary_state);
>>>> +
>>>> +    if (!set->mode) {
>>>> +            WARN_ON(set->fb);
>>>> +            WARN_ON(set->num_connectors);
>>>> +
>>>> +            ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
>>>> +            if (ret != 0)
>>>> +                    return ret;
>>>> +
>>>> +            crtc_state->active = false;
>>>> +
>>>> +            ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
>>>> +            if (ret != 0)
>>>> +                    return ret;
>>>> +
>>>> +            drm_atomic_set_fb_for_plane(primary_state, NULL);
>>>> +
>>>> +            goto commit;
>>>> +    }
>>>> +
>>>> +    WARN_ON(!set->fb);
>>>> +    WARN_ON(!set->num_connectors);
>>>> +
>>>> +    ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
>>>> +    if (ret != 0)
>>>> +            return ret;
>>>> +
>>>> +    crtc_state->active = true;
>>>> +
>>>> +    ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
>>>> +    if (ret != 0)
>>>> +            return ret;
>>>> +
>>>> +    drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
>>>> +
>>>> +    drm_atomic_set_fb_for_plane(primary_state, set->fb);
>>>> +    primary_state->crtc_x = 0;
>>>> +    primary_state->crtc_y = 0;
>>>> +    primary_state->crtc_w = hdisplay;
>>>> +    primary_state->crtc_h = vdisplay;
>>>> +    primary_state->src_x = set->x << 16;
>>>> +    primary_state->src_y = set->y << 16;
>>>> +    if (drm_rotation_90_or_270(primary_state->rotation)) {
>>>> +            primary_state->src_w = vdisplay << 16;
>>>> +            primary_state->src_h = hdisplay << 16;
>>>> +    } else {
>>>> +            primary_state->src_w = hdisplay << 16;
>>>> +            primary_state->src_h = vdisplay << 16;
>>>> +    }
>>>> +
>>>> +commit:
>>>> +    ret = update_output_state(state, set);
>>>> +    if (ret)
>>>> +            return ret;
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +EXPORT_SYMBOL(__drm_atomic_helper_set_config);
>>>> +
>>>>  void drm_atomic_print_state(const struct drm_atomic_state *state)
>>>>  {
>>>>      struct drm_printer p = drm_info_printer(state->dev->dev);
>>>> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
>>>> index 2453678d1186..b0d960da53cb 100644
>>>> --- a/drivers/gpu/drm/drm_atomic_helper.c
>>>> +++ b/drivers/gpu/drm/drm_atomic_helper.c
>>>> @@ -2831,95 +2831,6 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane,
>>>>  }
>>>>  EXPORT_SYMBOL(drm_atomic_helper_disable_plane);
>>>>
>>>> -/* just used from fb-helper and atomic-helper: */
>>>> -int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
>>>> -            struct drm_plane_state *plane_state)
>>>> -{
>>>> -    int ret;
>>>> -
>>>> -    ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
>>>> -    if (ret != 0)
>>>> -            return ret;
>>>> -
>>>> -    drm_atomic_set_fb_for_plane(plane_state, NULL);
>>>> -    plane_state->crtc_x = 0;
>>>> -    plane_state->crtc_y = 0;
>>>> -    plane_state->crtc_w = 0;
>>>> -    plane_state->crtc_h = 0;
>>>> -    plane_state->src_x = 0;
>>>> -    plane_state->src_y = 0;
>>>> -    plane_state->src_w = 0;
>>>> -    plane_state->src_h = 0;
>>>> -
>>>> -    return 0;
>>>> -}
>>>> -
>>>> -static int update_output_state(struct drm_atomic_state *state,
>>>> -                           struct drm_mode_set *set)
>>>> -{
>>>> -    struct drm_device *dev = set->crtc->dev;
>>>> -    struct drm_crtc *crtc;
>>>> -    struct drm_crtc_state *new_crtc_state;
>>>> -    struct drm_connector *connector;
>>>> -    struct drm_connector_state *new_conn_state;
>>>> -    int ret, i;
>>>> -
>>>> -    ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
>>>> -                           state->acquire_ctx);
>>>> -    if (ret)
>>>> -            return ret;
>>>> -
>>>> -    /* First disable all connectors on the target crtc. */
>>>> -    ret = drm_atomic_add_affected_connectors(state, set->crtc);
>>>> -    if (ret)
>>>> -            return ret;
>>>> -
>>>> -    for_each_new_connector_in_state(state, connector, new_conn_state, i) {
>>>> -            if (new_conn_state->crtc == set->crtc) {
>>>> -                    ret = drm_atomic_set_crtc_for_connector(new_conn_state,
>>>> -                                                            NULL);
>>>> -                    if (ret)
>>>> -                            return ret;
>>>> -
>>>> -                    /* Make sure legacy setCrtc always re-trains */
>>>> -                    new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
>>>> -            }
>>>> -    }
>>>> -
>>>> -    /* Then set all connectors from set->connectors on the target crtc */
>>>> -    for (i = 0; i < set->num_connectors; i++) {
>>>> -            new_conn_state = drm_atomic_get_connector_state(state,
>>>> -                                                        set->connectors[i]);
>>>> -            if (IS_ERR(new_conn_state))
>>>> -                    return PTR_ERR(new_conn_state);
>>>> -
>>>> -            ret = drm_atomic_set_crtc_for_connector(new_conn_state,
>>>> -                                                    set->crtc);
>>>> -            if (ret)
>>>> -                    return ret;
>>>> -    }
>>>> -
>>>> -    for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
>>>> -            /* Don't update ->enable for the CRTC in the set_config request,
>>>> -             * since a mismatch would indicate a bug in the upper layers.
>>>> -             * The actual modeset code later on will catch any
>>>> -             * inconsistencies here. */
>>>> -            if (crtc == set->crtc)
>>>> -                    continue;
>>>> -
>>>> -            if (!new_crtc_state->connector_mask) {
>>>> -                    ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
>>>> -                                                            NULL);
>>>> -                    if (ret < 0)
>>>> -                            return ret;
>>>> -
>>>> -                    new_crtc_state->active = false;
>>>> -            }
>>>> -    }
>>>> -
>>>> -    return 0;
>>>> -}
>>>> -
>>>>  /**
>>>>   * drm_atomic_helper_set_config - set a new config from userspace
>>>>   * @set: mode set configuration
>>>> @@ -2964,81 +2875,6 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set,
>>>>  }
>>>>  EXPORT_SYMBOL(drm_atomic_helper_set_config);
>>>>
>>>> -/* just used from fb-helper and atomic-helper: */
>>>> -int __drm_atomic_helper_set_config(struct drm_mode_set *set,
>>>> -            struct drm_atomic_state *state)
>>>> -{
>>>> -    struct drm_crtc_state *crtc_state;
>>>> -    struct drm_plane_state *primary_state;
>>>> -    struct drm_crtc *crtc = set->crtc;
>>>> -    int hdisplay, vdisplay;
>>>> -    int ret;
>>>> -
>>>> -    crtc_state = drm_atomic_get_crtc_state(state, crtc);
>>>> -    if (IS_ERR(crtc_state))
>>>> -            return PTR_ERR(crtc_state);
>>>> -
>>>> -    primary_state = drm_atomic_get_plane_state(state, crtc->primary);
>>>> -    if (IS_ERR(primary_state))
>>>> -            return PTR_ERR(primary_state);
>>>> -
>>>> -    if (!set->mode) {
>>>> -            WARN_ON(set->fb);
>>>> -            WARN_ON(set->num_connectors);
>>>> -
>>>> -            ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
>>>> -            if (ret != 0)
>>>> -                    return ret;
>>>> -
>>>> -            crtc_state->active = false;
>>>> -
>>>> -            ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
>>>> -            if (ret != 0)
>>>> -                    return ret;
>>>> -
>>>> -            drm_atomic_set_fb_for_plane(primary_state, NULL);
>>>> -
>>>> -            goto commit;
>>>> -    }
>>>> -
>>>> -    WARN_ON(!set->fb);
>>>> -    WARN_ON(!set->num_connectors);
>>>> -
>>>> -    ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
>>>> -    if (ret != 0)
>>>> -            return ret;
>>>> -
>>>> -    crtc_state->active = true;
>>>> -
>>>> -    ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
>>>> -    if (ret != 0)
>>>> -            return ret;
>>>> -
>>>> -    drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
>>>> -
>>>> -    drm_atomic_set_fb_for_plane(primary_state, set->fb);
>>>> -    primary_state->crtc_x = 0;
>>>> -    primary_state->crtc_y = 0;
>>>> -    primary_state->crtc_w = hdisplay;
>>>> -    primary_state->crtc_h = vdisplay;
>>>> -    primary_state->src_x = set->x << 16;
>>>> -    primary_state->src_y = set->y << 16;
>>>> -    if (drm_rotation_90_or_270(primary_state->rotation)) {
>>>> -            primary_state->src_w = vdisplay << 16;
>>>> -            primary_state->src_h = hdisplay << 16;
>>>> -    } else {
>>>> -            primary_state->src_w = hdisplay << 16;
>>>> -            primary_state->src_h = vdisplay << 16;
>>>> -    }
>>>> -
>>>> -commit:
>>>> -    ret = update_output_state(state, set);
>>>> -    if (ret)
>>>> -            return ret;
>>>> -
>>>> -    return 0;
>>>> -}
>>>> -
>>>>  static int __drm_atomic_helper_disable_all(struct drm_device *dev,
>>>>                                         struct drm_modeset_acquire_ctx *ctx,
>>>>                                         bool clean_old_fbs)
>>>> diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
>>>> index 216f2a9ee3d4..22a63a544ec7 100644
>>>> --- a/drivers/gpu/drm/drm_crtc_internal.h
>>>> +++ b/drivers/gpu/drm/drm_crtc_internal.h
>>>> @@ -207,6 +207,11 @@ struct drm_minor;
>>>>  int drm_atomic_debugfs_init(struct drm_minor *minor);
>>>>  #endif
>>>>
>>>> +int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
>>>> +                                  struct drm_plane_state *plane_state);
>>>> +int __drm_atomic_helper_set_config(struct drm_mode_set *set,
>>>> +                               struct drm_atomic_state *state);
>>>> +
>>>>  void drm_atomic_print_state(const struct drm_atomic_state *state);
>>>>
>>>>  /* drm_atomic_uapi.c */
>>>> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
>>>> index 58214be3bf3d..bf4e07141d81 100644
>>>> --- a/include/drm/drm_atomic_helper.h
>>>> +++ b/include/drm/drm_atomic_helper.h
>>>> @@ -117,12 +117,8 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
>>>>                                 struct drm_modeset_acquire_ctx *ctx);
>>>>  int drm_atomic_helper_disable_plane(struct drm_plane *plane,
>>>>                                  struct drm_modeset_acquire_ctx *ctx);
>>>> -int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
>>>> -            struct drm_plane_state *plane_state);
>>>>  int drm_atomic_helper_set_config(struct drm_mode_set *set,
>>>>                               struct drm_modeset_acquire_ctx *ctx);
>>>> -int __drm_atomic_helper_set_config(struct drm_mode_set *set,
>>>> -            struct drm_atomic_state *state);
>>>>
>>>>  int drm_atomic_helper_disable_all(struct drm_device *dev,
>>>>                                struct drm_modeset_acquire_ctx *ctx);
>>>> --
>>>> 2.20.1
>>>>
>>>> _______________________________________________
>>>> Intel-gfx mailing list
>>>> Intel-gfx@lists.freedesktop.org
>>>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>
> 
> 
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 09/16] drm/fb-helper: Move out commit code
  2019-03-27 14:13   ` Emmanuel Vadot
@ 2019-03-27 15:01     ` Noralf Trønnes
  2019-03-27 15:12       ` Emmanuel Vadot
  0 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-27 15:01 UTC (permalink / raw)
  To: Emmanuel Vadot; +Cc: intel-gfx, dri-devel



Den 27.03.2019 15.13, skrev Emmanuel Vadot:
> 
>  Hi Noralf,
> 
> On Tue, 26 Mar 2019 18:55:39 +0100
> Noralf Trønnes <noralf@tronnes.org> wrote:
> 
>> Move the modeset commit code to drm_client.
>> No changes except exporting API.
>>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>> ---
>>  drivers/gpu/drm/drm_client.c    | 236 ++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/drm_fb_helper.c | 232 -------------------------------
>>  include/drm/drm_client.h        |   3 +
>>  3 files changed, 239 insertions(+), 232 deletions(-)
>>
> 
>  It looks like you are moving MIT licenced code to a GPL-only
> licenced file.
> 

I had planned to copy over the copyrights, but forgot. Didn't know it
was MIT though. I think I'll just copy over the whole copyrights section
from drm_fb_helper to drm_client and drop GPL. I wrote the whole of
drm_client so that should be fine.

Thanks,
Noralf

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 09/16] drm/fb-helper: Move out commit code
  2019-03-27 15:01     ` Noralf Trønnes
@ 2019-03-27 15:12       ` Emmanuel Vadot
  0 siblings, 0 replies; 42+ messages in thread
From: Emmanuel Vadot @ 2019-03-27 15:12 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Wed, 27 Mar 2019 16:01:01 +0100
Noralf Trønnes <noralf@tronnes.org> wrote:

> 
> 
> Den 27.03.2019 15.13, skrev Emmanuel Vadot:
> > 
> >  Hi Noralf,
> > 
> > On Tue, 26 Mar 2019 18:55:39 +0100
> > Noralf Trønnes <noralf@tronnes.org> wrote:
> > 
> >> Move the modeset commit code to drm_client.
> >> No changes except exporting API.
> >>
> >> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> >> ---
> >>  drivers/gpu/drm/drm_client.c    | 236 ++++++++++++++++++++++++++++++++
> >>  drivers/gpu/drm/drm_fb_helper.c | 232 -------------------------------
> >>  include/drm/drm_client.h        |   3 +
> >>  3 files changed, 239 insertions(+), 232 deletions(-)
> >>
> > 
> >  It looks like you are moving MIT licenced code to a GPL-only
> > licenced file.
> > 
> 
> I had planned to copy over the copyrights, but forgot. Didn't know it
> was MIT though. I think I'll just copy over the whole copyrights section
> from drm_fb_helper to drm_client and drop GPL. I wrote the whole of
> drm_client so that should be fine.

 That would be awesome if you relicence drm_client.

 Thanks,

> Thanks,
> Noralf
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Emmanuel Vadot <manu@bidouilliste.com> <manu@freebsd.org>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 16/16] drm/vc4: Call drm_dev_register() after all setup is done
  2019-03-26 17:55 ` [PATCH 16/16] drm/vc4: Call drm_dev_register() after all setup is done Noralf Trønnes
  2019-03-26 20:40   ` Daniel Vetter
@ 2019-03-27 16:36   ` Eric Anholt
  2019-04-03  9:20     ` Noralf Trønnes
  1 sibling, 1 reply; 42+ messages in thread
From: Eric Anholt @ 2019-03-27 16:36 UTC (permalink / raw)
  To: Noralf Trønnes, dri-devel; +Cc: intel-gfx, mstaudt


[-- Attachment #1.1: Type: text/plain, Size: 445 bytes --]

Noralf Trønnes <noralf@tronnes.org> writes:

> drm_dev_register() initializes internal clients like bootsplash as the
> last thing it does, so all setup needs to be done at this point.
>
> Fix by calling vc4_kms_load() before registering.
> Also check the error code returned from that function.
>
> Cc: Eric Anholt <eric@anholt.net>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

Reviewed-by: Eric Anholt <eric@anholt.net>

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 04/16] drm/fb-helper: No need to cache rotation and sw_rotations
  2019-03-26 17:55 ` [PATCH 04/16] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
@ 2019-03-28  8:03   ` Daniel Vetter
  0 siblings, 0 replies; 42+ messages in thread
From: Daniel Vetter @ 2019-03-28  8:03 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: Hans de Goede, intel-gfx, mstaudt, dri-devel

On Tue, Mar 26, 2019 at 06:55:34PM +0100, Noralf Trønnes wrote:
> Getting rotation info is cheap so we can do it on demand.
> 
> This is done in preparation for the removal of struct drm_fb_helper_crtc.
> 
> Cc: Hans de Goede <hdegoede@redhat.com>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
> 
> Hans, 
> 
> You had this comment inline in restore_fbdev_mode_atomic() the last time
> I sent this out:
> 
>   We want plane_state->rotation to be set to DRM_MODE_ROTATE_0 in the else
>   case, AFAIK new_plane_state starts with the current state and rotation
>   may have a different value there.
>   
>   Otherwise this looks good to me.
> 
> Rotation is reset for each plane in the code section above the one I'm
> changing.

I think best to let Hans review/test this in detail. lgtm at a glance.
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Noralf.
> 
>  drivers/gpu/drm/drm_fb_helper.c | 131 ++++++++++++++++----------------
>  include/drm/drm_fb_helper.h     |   8 --
>  2 files changed, 65 insertions(+), 74 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index b91df658db59..e1b147fdd3f9 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -387,6 +387,49 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
>  }
>  EXPORT_SYMBOL(drm_fb_helper_debug_leave);
>  
> +/* Check if the plane can hw rotate to match panel orientation */
> +static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
> +					 unsigned int *rotation)
> +{
> +	struct drm_connector *connector = modeset->connectors[0];
> +	struct drm_plane *plane = modeset->crtc->primary;
> +	u64 valid_mask = 0;
> +	unsigned int i;
> +
> +	if (!modeset->num_connectors)
> +		return false;
> +
> +	switch (connector->display_info.panel_orientation) {
> +	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
> +		*rotation = DRM_MODE_ROTATE_180;
> +		break;
> +	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
> +		*rotation = DRM_MODE_ROTATE_90;
> +		break;
> +	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
> +		*rotation = DRM_MODE_ROTATE_270;
> +		break;
> +	default:
> +		*rotation = DRM_MODE_ROTATE_0;
> +	}
> +
> +	/*
> +	 * TODO: support 90 / 270 degree hardware rotation,
> +	 * depending on the hardware this may require the framebuffer
> +	 * to be in a specific tiling format.
> +	 */
> +	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
> +		return false;
> +
> +	for (i = 0; i < plane->rotation_property->num_values; i++)
> +		valid_mask |= (1ULL << plane->rotation_property->values[i]);
> +
> +	if (!(*rotation & valid_mask))
> +		return false;
> +
> +	return true;
> +}
> +
>  static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
>  {
>  	struct drm_device *dev = fb_helper->dev;
> @@ -427,10 +470,13 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
>  	for (i = 0; i < fb_helper->crtc_count; i++) {
>  		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
>  		struct drm_plane *primary = mode_set->crtc->primary;
> +		unsigned int rotation;
>  
> -		/* Cannot fail as we've already gotten the plane state above */
> -		plane_state = drm_atomic_get_new_plane_state(state, primary);
> -		plane_state->rotation = fb_helper->crtc_info[i].rotation;
> +		if (drm_fb_helper_panel_rotation(mode_set, &rotation)) {
> +			/* Cannot fail as we've already gotten the plane state above */
> +			plane_state = drm_atomic_get_new_plane_state(state, primary);
> +			plane_state->rotation = rotation;
> +		}
>  
>  		ret = __drm_atomic_helper_set_config(mode_set, state);
>  		if (ret != 0)
> @@ -881,7 +927,6 @@ int drm_fb_helper_init(struct drm_device *dev,
>  		if (!fb_helper->crtc_info[i].mode_set.connectors)
>  			goto out_free;
>  		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
> -		fb_helper->crtc_info[i].rotation = DRM_MODE_ROTATE_0;
>  	}
>  
>  	i = 0;
> @@ -2500,62 +2545,6 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
>  	return best_score;
>  }
>  
> -/*
> - * This function checks if rotation is necessary because of panel orientation
> - * and if it is, if it is supported.
> - * If rotation is necessary and supported, it gets set in fb_crtc.rotation.
> - * If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets
> - * or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only
> - * one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do
> - * the unsupported rotation.
> - */
> -static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
> -				    struct drm_fb_helper_crtc *fb_crtc,
> -				    struct drm_connector *connector)
> -{
> -	struct drm_plane *plane = fb_crtc->mode_set.crtc->primary;
> -	uint64_t valid_mask = 0;
> -	int i, rotation;
> -
> -	fb_crtc->rotation = DRM_MODE_ROTATE_0;
> -
> -	switch (connector->display_info.panel_orientation) {
> -	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
> -		rotation = DRM_MODE_ROTATE_180;
> -		break;
> -	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
> -		rotation = DRM_MODE_ROTATE_90;
> -		break;
> -	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
> -		rotation = DRM_MODE_ROTATE_270;
> -		break;
> -	default:
> -		rotation = DRM_MODE_ROTATE_0;
> -	}
> -
> -	/*
> -	 * TODO: support 90 / 270 degree hardware rotation,
> -	 * depending on the hardware this may require the framebuffer
> -	 * to be in a specific tiling format.
> -	 */
> -	if (rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property) {
> -		fb_helper->sw_rotations |= rotation;
> -		return;
> -	}
> -
> -	for (i = 0; i < plane->rotation_property->num_values; i++)
> -		valid_mask |= (1ULL << plane->rotation_property->values[i]);
> -
> -	if (!(rotation & valid_mask)) {
> -		fb_helper->sw_rotations |= rotation;
> -		return;
> -	}
> -
> -	fb_crtc->rotation = rotation;
> -	/* Rotating in hardware, fbcon should not rotate */
> -	fb_helper->sw_rotations |= DRM_MODE_ROTATE_0;
> -}
> -
>  static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  			    u32 width, u32 height)
>  {
> @@ -2615,7 +2604,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  		drm_fb_helper_modeset_release(fb_helper,
>  					      &fb_helper->crtc_info[i].mode_set);
>  
> -	fb_helper->sw_rotations = 0;
>  	drm_fb_helper_for_each_connector(fb_helper, i) {
>  		struct drm_display_mode *mode = modes[i];
>  		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
> @@ -2635,7 +2623,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  			modeset->mode = drm_mode_duplicate(dev,
>  							   fb_crtc->desired_mode);
>  			drm_connector_get(connector);
> -			drm_setup_crtc_rotation(fb_helper, fb_crtc, connector);
>  			modeset->connectors[modeset->num_connectors++] = connector;
>  			modeset->x = offset->x;
>  			modeset->y = offset->y;
> @@ -2658,11 +2645,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
>  {
>  	struct fb_info *info = fb_helper->fbdev;
> +	unsigned int rotation, sw_rotations = 0;
>  	int i;
>  
> -	for (i = 0; i < fb_helper->crtc_count; i++)
> -		if (fb_helper->crtc_info[i].mode_set.num_connectors)
> -			fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
> +	for (i = 0; i < fb_helper->crtc_count; i++) {
> +		struct drm_mode_set *modeset = &fb_helper->crtc_info[i].mode_set;
> +
> +		if (!modeset->num_connectors)
> +			continue;
> +
> +		modeset->fb = fb_helper->fb;
> +
> +		if (drm_fb_helper_panel_rotation(modeset, &rotation))
> +			/* Rotating in hardware, fbcon should not rotate */
> +			sw_rotations |= DRM_MODE_ROTATE_0;
> +		else
> +			sw_rotations |= rotation;
> +	}
>  
>  	mutex_lock(&fb_helper->dev->mode_config.mutex);
>  	drm_fb_helper_for_each_connector(fb_helper, i) {
> @@ -2678,7 +2677,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
>  	}
>  	mutex_unlock(&fb_helper->dev->mode_config.mutex);
>  
> -	switch (fb_helper->sw_rotations) {
> +	switch (sw_rotations) {
>  	case DRM_MODE_ROTATE_0:
>  		info->fbcon_rotate_hint = FB_ROTATE_UR;
>  		break;
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index bb9acea61369..cff1aa222886 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -50,7 +50,6 @@ struct drm_fb_helper_crtc {
>  	struct drm_mode_set mode_set;
>  	struct drm_display_mode *desired_mode;
>  	int x, y;
> -	int rotation;
>  };
>  
>  /**
> @@ -175,13 +174,6 @@ struct drm_fb_helper {
>  	struct drm_fb_helper_crtc *crtc_info;
>  	int connector_count;
>  	int connector_info_alloc_count;
> -	/**
> -	 * @sw_rotations:
> -	 * Bitmask of all rotations requested for panel-orientation which
> -	 * could not be handled in hardware. If only one bit is set
> -	 * fbdev->fbcon_rotate_hint gets set to the requested rotation.
> -	 */
> -	int sw_rotations;
>  	/**
>  	 * @connector_info:
>  	 *
> -- 
> 2.20.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 13/16] drm/fb-helper: Avoid race with DRM userspace
  2019-03-26 17:55 ` [PATCH 13/16] drm/fb-helper: Avoid race with DRM userspace Noralf Trønnes
@ 2019-03-28  8:17   ` Daniel Vetter
  2019-03-30 21:07     ` Noralf Trønnes
  0 siblings, 1 reply; 42+ messages in thread
From: Daniel Vetter @ 2019-03-28  8:17 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: Daniel Vetter, intel-gfx, mstaudt, dri-devel

On Tue, Mar 26, 2019 at 06:55:43PM +0100, Noralf Trønnes wrote:
> drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
> This is done by looking at the fb on the primary plane. By the time
> fb-helper gets around to committing, it's possible that the facts have
> changed.
> 
> Avoid this race by holding the drm_device->master_mutex lock while
> committing. When DRM userspace does its first open, it will now wait
> until fb-helper is done. The helper will stay away if there's a master.
> 
> Locking rule: Always take the fb-helper lock first.
> 
> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

I think it'd be good to reorder this earlier in the series. And I'm
wondering why you didn't replace all occurences of the _is_bound()
function. With the consistent master state check we're doing with this I
don't think any of the fbdev checking is still needed. Plus looking at
crtc->primary->fb without any locks is racy, so would be good to ditch
that hack.
-Daniel

> ---
>  drivers/gpu/drm/drm_auth.c      | 20 ++++++++++++++
>  drivers/gpu/drm/drm_fb_helper.c | 49 ++++++++++++++++++++++++---------
>  drivers/gpu/drm/drm_internal.h  |  2 ++
>  3 files changed, 58 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> index 1669c42c40ed..db199807b7dc 100644
> --- a/drivers/gpu/drm/drm_auth.c
> +++ b/drivers/gpu/drm/drm_auth.c
> @@ -368,3 +368,23 @@ void drm_master_put(struct drm_master **master)
>  	*master = NULL;
>  }
>  EXPORT_SYMBOL(drm_master_put);
> +
> +/* Used by drm_client and drm_fb_helper */
> +bool drm_master_internal_acquire(struct drm_device *dev)
> +{
> +	mutex_lock(&dev->master_mutex);
> +	if (dev->master) {
> +		mutex_unlock(&dev->master_mutex);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL(drm_master_internal_acquire);
> +
> +/* Used by drm_client and drm_fb_helper */
> +void drm_master_internal_release(struct drm_device *dev)
> +{
> +	mutex_unlock(&dev->master_mutex);
> +}
> +EXPORT_SYMBOL(drm_master_internal_release);
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 4a073cd4e423..9f253fcf3f79 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -41,6 +41,8 @@
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_atomic.h>
>  
> +#include "drm_internal.h"
> +
>  static bool drm_fbdev_emulation = true;
>  module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
>  MODULE_PARM_DESC(fbdev_emulation,
> @@ -235,7 +237,12 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
>  		return 0;
>  
>  	mutex_lock(&fb_helper->lock);
> -	ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
> +	if (drm_master_internal_acquire(fb_helper->dev)) {
> +		ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
> +		drm_master_internal_release(fb_helper->dev);
> +	} else {
> +		ret = -EBUSY;
> +	}
>  
>  	do_delayed = fb_helper->delayed_hotplug;
>  	if (do_delayed)
> @@ -332,13 +339,16 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
>  static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_device *dev = fb_helper->dev;
>  
>  	/*
>  	 * For each CRTC in this fb, turn the connectors on/off.
>  	 */
>  	mutex_lock(&fb_helper->lock);
> -	if (drm_fb_helper_is_bound(fb_helper))
> -		drm_client_modesets_dpms(fb_helper->dev, fb_helper->modesets, dpms_mode);
> +	if (drm_master_internal_acquire(dev)) {
> +		drm_client_modesets_dpms(dev, fb_helper->modesets, dpms_mode);
> +		drm_master_internal_release(dev);
> +	}
>  	mutex_unlock(&fb_helper->lock);
>  }
>  
> @@ -1097,6 +1107,7 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
>  int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_device *dev = fb_helper->dev;
>  	int ret;
>  
>  	if (oops_in_progress)
> @@ -1104,9 +1115,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>  
>  	mutex_lock(&fb_helper->lock);
>  
> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> +	if (!drm_master_internal_acquire(dev)) {
>  		ret = -EBUSY;
> -		goto out;
> +		goto unlock;
>  	}
>  
>  	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
> @@ -1116,7 +1127,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>  	else
>  		ret = setcmap_legacy(cmap, info);
>  
> -out:
> +	drm_master_internal_release(dev);
> +unlock:
>  	mutex_unlock(&fb_helper->lock);
>  
>  	return ret;
> @@ -1136,11 +1148,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>  			unsigned long arg)
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_device *dev = fb_helper->dev;
>  	struct drm_crtc *crtc;
>  	int ret = 0;
>  
>  	mutex_lock(&fb_helper->lock);
> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> +
> +	if (!drm_master_internal_acquire(dev)) {
>  		ret = -EBUSY;
>  		goto unlock;
>  	}
> @@ -1177,13 +1191,15 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>  		}
>  
>  		ret = 0;
> -		goto unlock;
> +		break;
>  	default:
>  		ret = -ENOTTY;
>  	}
>  
> +	drm_master_internal_release(dev);
>  unlock:
>  	mutex_unlock(&fb_helper->lock);
> +
>  	return ret;
>  }
>  EXPORT_SYMBOL(drm_fb_helper_ioctl);
> @@ -1426,15 +1442,19 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
>  		return -EBUSY;
>  
>  	mutex_lock(&fb_helper->lock);
> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> -		mutex_unlock(&fb_helper->lock);
> -		return -EBUSY;
> +
> +	if (!drm_master_internal_acquire(dev)) {
> +		ret = -EBUSY;
> +		goto unlock;
>  	}
>  
>  	if (drm_drv_uses_atomic_modeset(dev))
>  		ret = pan_display_atomic(var, info);
>  	else
>  		ret = pan_display_legacy(var, info);
> +
> +	drm_master_internal_release(dev);
> +unlock:
>  	mutex_unlock(&fb_helper->lock);
>  
>  	return ret;
> @@ -1451,6 +1471,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  	int ret = 0;
>  	int crtc_count = 0;
>  	struct drm_connector_list_iter conn_iter;
> +	struct drm_device *dev = fb_helper->dev;
>  	struct drm_fb_helper_surface_size sizes;
>  	struct drm_connector *connector;
>  	struct drm_mode_set *mode_set;
> @@ -1593,8 +1614,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  		DRM_INFO("Cannot find any crtc or sizes\n");
>  
>  		/* First time: disable all crtc's.. */
> -		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
> -			drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
> +		if (!fb_helper->deferred_setup && drm_master_internal_acquire(dev)) {
> +			drm_client_modesets_commit(dev, fb_helper->modesets);
> +			drm_master_internal_release(dev);
> +		}
>  		return -EAGAIN;
>  	}
>  
> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> index 251d67e04c2d..6d5d1184c084 100644
> --- a/drivers/gpu/drm/drm_internal.h
> +++ b/drivers/gpu/drm/drm_internal.h
> @@ -91,6 +91,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
>  			 struct drm_file *file_priv);
>  int drm_master_open(struct drm_file *file_priv);
>  void drm_master_release(struct drm_file *file_priv);
> +bool drm_master_internal_acquire(struct drm_device *dev);
> +void drm_master_internal_release(struct drm_device *dev);
>  
>  /* drm_sysfs.c */
>  extern struct class *drm_class;
> -- 
> 2.20.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 05/16] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode}
  2019-03-26 17:55 ` [PATCH 05/16] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode} Noralf Trønnes
@ 2019-03-28  8:19   ` Daniel Vetter
  0 siblings, 0 replies; 42+ messages in thread
From: Daniel Vetter @ 2019-03-28  8:19 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, mstaudt, dri-devel

On Tue, Mar 26, 2019 at 06:55:35PM +0100, Noralf Trønnes wrote:
> The values are already present in the modeset.
> 
> This is done in preparation for the removal of struct drm_fb_helper_crtc.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/drm_fb_helper.c | 12 ++++--------
>  include/drm/drm_fb_helper.h     |  2 --
>  2 files changed, 4 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index e1b147fdd3f9..36310901e935 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -2023,16 +2023,16 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  		 */
>  		bool lastv = true, lasth = true;
>  
> -		desired_mode = fb_helper->crtc_info[i].desired_mode;
>  		mode_set = &fb_helper->crtc_info[i].mode_set;
> +		desired_mode = mode_set->mode;
>  
>  		if (!desired_mode)
>  			continue;
>  
>  		crtc_count++;
>  
> -		x = fb_helper->crtc_info[i].x;
> -		y = fb_helper->crtc_info[i].y;
> +		x = mode_set->x;
> +		y = mode_set->y;
>  
>  		sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
>  		sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
> @@ -2617,11 +2617,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
>  				      mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
>  
> -			fb_crtc->desired_mode = mode;
> -			fb_crtc->x = offset->x;
> -			fb_crtc->y = offset->y;
> -			modeset->mode = drm_mode_duplicate(dev,
> -							   fb_crtc->desired_mode);
> +			modeset->mode = drm_mode_duplicate(dev, mode);
>  			drm_connector_get(connector);
>  			modeset->connectors[modeset->num_connectors++] = connector;
>  			modeset->x = offset->x;
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index cff1aa222886..7a095964f6b2 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -48,8 +48,6 @@ struct drm_fb_offset {
>  
>  struct drm_fb_helper_crtc {
>  	struct drm_mode_set mode_set;
> -	struct drm_display_mode *desired_mode;
> -	int x, y;
>  };
>  
>  /**
> -- 
> 2.20.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Intel-gfx] [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client
  2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (16 preceding siblings ...)
  2019-03-27 13:45 ` [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
@ 2019-03-28  9:31 ` Daniel Vetter
  2019-03-31 21:18   ` Noralf Trønnes
  17 siblings, 1 reply; 42+ messages in thread
From: Daniel Vetter @ 2019-03-28  9:31 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, mstaudt, dri-devel

On Tue, Mar 26, 2019 at 06:55:30PM +0100, Noralf Trønnes wrote:
> This moves the modesetting code from drm_fb_helper to drm_client so it
> can be shared by all internal clients.
> 
> I have also added a client display abstraction and a bootsplash example
> client to show where this might be heading. Hopefully Max Staudt will be
> able to pick up his bootsplash work now.

First a fairly unrelated thing that I noticed while reading stuff:

In drm_fbdev_generic_setup() we register the drm_client to the world (with
drm_client_add) before it's fully set up. And the checks in the setup code
aren't safe against a concurrent hotplug call from another thread. Which
can happen, because usually by that point, and definitely by the time the
driver called drm_dev_register() the hotplug handler is running.

Maybe good idea to rename drm_client_add to drm_client_register (to stay
consistent with our naming scheme of _register() = others can start
calling us from any thread).

We need to do the basic setup code _before_ we call drm_client_register.
The kerneldoc for the various fbdev setup functions have explanations for
when exactly it's ok to handle hotplug events.

The other bit is kinda the high-level review on the drm_client modeset
api:
- Allowing multiple different modeset clients per drm_client feels like
  overkill. I think we can just require a 1:1 mapping between drm_client
  and modeset config. If a client wants to have multiple different modeset
  configs per drm_device they can create more drm_clients.

- That also fixes your "do we need embedding" question, since drm_client
  supports that already.

- That means we could clean up the api considerably by embedding all the
  modeset stuff into drm_client, and e.g. allocating the modeset arrays at
  drm_client_init() time.

- Except that wouldn't work with the current fbdev emulation code, because
  that one isn't always using drm_client.

Hence my question/suggestion: Could we rework the fbdev emulation to
always allocate a drm_client, but only use drm_client for buffer
allocation for generic_setup(). That could also provide us with a smoother
upgrade path for other drivers to generic_setup, e.g. we could ditch all
the hotplug handling already.

I'm thinking of embedding a drm_client into drm_fb_helper, and calling
drm_client_init() on it at the right time. But only call drm_client_add()
for generic_setup(). At least as a first step.

Related question: What's the plan for drivers which don't support
generic_setup()? If we eventually have stuff like kmscon running on top of
drm_client, we'd have to somehow port them all ...

And finally the bikeshed: I thik drm_client_modeset would be a good prefix
for all this (maybe even in a separate file):
- we have a pretty clear split between basic drm stuff and kms
- modeset means kms, display usually only means the actual physical
  display. drm_simple_display_pipe always gets me with using display
  instead of modeset, but a bit too late to rename that one :-)

Thoughts on this?

Cheers, Daniel


> 
> Noralf.
> 
> Noralf Trønnes (16):
>   drm/fb-helper: Remove unused gamma_size variable
>   drm/fb-helper: dpms_legacy(): Only set on connectors in use
>   drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
>   drm/fb-helper: No need to cache rotation and sw_rotations
>   drm/fb-helper: Remove drm_fb_helper_crtc->{x,y,desired_mode}
>   drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
>   drm/fb-helper: Remove drm_fb_helper_crtc
>   drm/fb-helper: Prepare to move out commit code
>   drm/fb-helper: Move out commit code
>   drm/fb-helper: Remove drm_fb_helper_connector
>   drm/fb-helper: Prepare to move out modeset config code
>   drm/fb-helper: Move out modeset config code
>   drm/fb-helper: Avoid race with DRM userspace
>   drm/client: Add display abstraction
>   drm/client: Hack: Add bootsplash example
>   drm/vc4: Call drm_dev_register() after all setup is done
> 
>  Documentation/gpu/todo.rst          |   10 +
>  drivers/gpu/drm/Kconfig             |    5 +
>  drivers/gpu/drm/Makefile            |    1 +
>  drivers/gpu/drm/drm_atomic.c        |  168 ++++
>  drivers/gpu/drm/drm_atomic_helper.c |  164 ---
>  drivers/gpu/drm/drm_auth.c          |   20 +
>  drivers/gpu/drm/drm_bootsplash.c    |  216 ++++
>  drivers/gpu/drm/drm_client.c        | 1449 +++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_crtc_internal.h |    5 +
>  drivers/gpu/drm/drm_drv.c           |    4 +
>  drivers/gpu/drm/drm_fb_helper.c     | 1151 ++-------------------
>  drivers/gpu/drm/drm_internal.h      |    2 +
>  drivers/gpu/drm/i915/intel_fbdev.c  |  218 ----
>  drivers/gpu/drm/vc4/vc4_drv.c       |    6 +-
>  include/drm/drm_atomic_helper.h     |    4 -
>  include/drm/drm_client.h            |  117 +++
>  include/drm/drm_fb_helper.h         |  127 +--
>  17 files changed, 2128 insertions(+), 1539 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_bootsplash.c
> 
> -- 
> 2.20.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 06/16] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
  2019-03-27 13:33   ` Jani Nikula
@ 2019-03-30 20:50     ` Noralf Trønnes
  0 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-30 20:50 UTC (permalink / raw)
  To: Jani Nikula, dri-devel; +Cc: Daniel Vetter, intel-gfx, Rodrigo Vivi



Den 27.03.2019 14.33, skrev Jani Nikula:
> On Tue, 26 Mar 2019, Noralf Trønnes <noralf@tronnes.org> wrote:
>> It is generic code and having it in the helper will let other drivers
>> benefit from it.
>>
>> One change was necessary assuming this to be true:
>> INTEL_INFO(dev_priv)->num_pipes == dev->mode_config.num_crtc
> 
> This holds after intel_modeset_init(), in time for the use here.
> 
>> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>> Cc: Jani Nikula <jani.nikula@linux.intel.com>
>> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
>> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
>> Cc: intel-gfx@lists.freedesktop.org
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> 
> Reviewed-by: Jani Nikula <jani.nikula@intel.com>
> 
> and
> 
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> 
> for merging via drm-misc or whichever tree makes most sense.
> 

Thanks, I'll take it through drm-misc.

One of the patches had a conflict with drm-tip, so I didn't get a CI
run. I'll apply this if CI agrees when I submit the next version.

Noralf.

> 
>> ---
>>  drivers/gpu/drm/drm_fb_helper.c    | 194 ++++++++++++++++++++++++-
>>  drivers/gpu/drm/i915/intel_fbdev.c | 218 -----------------------------
>>  include/drm/drm_fb_helper.h        |  23 ---
>>  3 files changed, 190 insertions(+), 245 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>> index 36310901e935..634f4dcf0c41 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -2545,6 +2545,194 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
>>  	return best_score;
>>  }
>>  
>> +static struct drm_fb_helper_crtc *
>> +drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < fb_helper->crtc_count; i++)
>> +		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
>> +			return &fb_helper->crtc_info[i];
>> +
>> +	return NULL;
>> +}
>> +
>> +/* Try to read the BIOS display configuration and use it for the initial config */
>> +static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
>> +					  struct drm_fb_helper_crtc **crtcs,
>> +					  struct drm_display_mode **modes,
>> +					  struct drm_fb_offset *offsets,
>> +					  bool *enabled, int width, int height)
>> +{
>> +	struct drm_device *dev = fb_helper->dev;
>> +	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
>> +	unsigned long conn_configured, conn_seq;
>> +	int i, j;
>> +	bool *save_enabled;
>> +	bool fallback = true, ret = true;
>> +	int num_connectors_enabled = 0;
>> +	int num_connectors_detected = 0;
>> +	struct drm_modeset_acquire_ctx ctx;
>> +
>> +	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
>> +	if (!save_enabled)
>> +		return false;
>> +
>> +	drm_modeset_acquire_init(&ctx, 0);
>> +
>> +	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
>> +		drm_modeset_backoff(&ctx);
>> +
>> +	memcpy(save_enabled, enabled, count);
>> +	conn_seq = GENMASK(count - 1, 0);
>> +	conn_configured = 0;
>> +retry:
>> +	for (i = 0; i < count; i++) {
>> +		struct drm_fb_helper_connector *fb_conn;
>> +		struct drm_connector *connector;
>> +		struct drm_encoder *encoder;
>> +		struct drm_fb_helper_crtc *new_crtc;
>> +
>> +		fb_conn = fb_helper->connector_info[i];
>> +		connector = fb_conn->connector;
>> +
>> +		if (conn_configured & BIT(i))
>> +			continue;
>> +
>> +		/* First pass, only consider tiled connectors */
>> +		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
>> +			continue;
>> +
>> +		if (connector->status == connector_status_connected)
>> +			num_connectors_detected++;
>> +
>> +		if (!enabled[i]) {
>> +			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
>> +				      connector->name);
>> +			conn_configured |= BIT(i);
>> +			continue;
>> +		}
>> +
>> +		if (connector->force == DRM_FORCE_OFF) {
>> +			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
>> +				      connector->name);
>> +			enabled[i] = false;
>> +			continue;
>> +		}
>> +
>> +		encoder = connector->state->best_encoder;
>> +		if (!encoder || WARN_ON(!connector->state->crtc)) {
>> +			if (connector->force > DRM_FORCE_OFF)
>> +				goto bail;
>> +
>> +			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
>> +				      connector->name);
>> +			enabled[i] = false;
>> +			conn_configured |= BIT(i);
>> +			continue;
>> +		}
>> +
>> +		num_connectors_enabled++;
>> +
>> +		new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
>> +
>> +		/*
>> +		 * Make sure we're not trying to drive multiple connectors
>> +		 * with a single CRTC, since our cloning support may not
>> +		 * match the BIOS.
>> +		 */
>> +		for (j = 0; j < count; j++) {
>> +			if (crtcs[j] == new_crtc) {
>> +				DRM_DEBUG_KMS("fallback: cloned configuration\n");
>> +				goto bail;
>> +			}
>> +		}
>> +
>> +		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
>> +			      connector->name);
>> +
>> +		/* go for command line mode first */
>> +		modes[i] = drm_pick_cmdline_mode(fb_conn);
>> +
>> +		/* try for preferred next */
>> +		if (!modes[i]) {
>> +			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
>> +				      connector->name, connector->has_tile);
>> +			modes[i] = drm_has_preferred_mode(fb_conn, width,
>> +							  height);
>> +		}
>> +
>> +		/* No preferred mode marked by the EDID? Are there any modes? */
>> +		if (!modes[i] && !list_empty(&connector->modes)) {
>> +			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
>> +				      connector->name);
>> +			modes[i] = list_first_entry(&connector->modes,
>> +						    struct drm_display_mode,
>> +						    head);
>> +		}
>> +
>> +		/* last resort: use current mode */
>> +		if (!modes[i]) {
>> +			/*
>> +			 * IMPORTANT: We want to use the adjusted mode (i.e.
>> +			 * after the panel fitter upscaling) as the initial
>> +			 * config, not the input mode, which is what crtc->mode
>> +			 * usually contains. But since our current
>> +			 * code puts a mode derived from the post-pfit timings
>> +			 * into crtc->mode this works out correctly.
>> +			 *
>> +			 * This is crtc->mode and not crtc->state->mode for the
>> +			 * fastboot check to work correctly.
>> +			 */
>> +			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
>> +				      connector->name);
>> +			modes[i] = &connector->state->crtc->mode;
>> +		}
>> +		crtcs[i] = new_crtc;
>> +
>> +		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
>> +			      connector->name,
>> +			      connector->state->crtc->base.id,
>> +			      connector->state->crtc->name,
>> +			      modes[i]->hdisplay, modes[i]->vdisplay,
>> +			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
>> +
>> +		fallback = false;
>> +		conn_configured |= BIT(i);
>> +	}
>> +
>> +	if (conn_configured != conn_seq) { /* repeat until no more are found */
>> +		conn_seq = conn_configured;
>> +		goto retry;
>> +	}
>> +
>> +	/*
>> +	 * If the BIOS didn't enable everything it could, fall back to have the
>> +	 * same user experiencing of lighting up as much as possible like the
>> +	 * fbdev helper library.
>> +	 */
>> +	if (num_connectors_enabled != num_connectors_detected &&
>> +	    num_connectors_enabled < dev->mode_config.num_crtc) {
>> +		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
>> +		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
>> +			      num_connectors_detected);
>> +		fallback = true;
>> +	}
>> +
>> +	if (fallback) {
>> +bail:
>> +		DRM_DEBUG_KMS("Not using firmware configuration\n");
>> +		memcpy(enabled, save_enabled, count);
>> +		ret = false;
>> +	}
>> +
>> +	drm_modeset_drop_locks(&ctx);
>> +	drm_modeset_acquire_fini(&ctx);
>> +
>> +	kfree(save_enabled);
>> +	return ret;
>> +}
>> +
>>  static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>>  			    u32 width, u32 height)
>>  {
>> @@ -2577,10 +2765,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>>  		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
>>  	drm_enable_connectors(fb_helper, enabled);
>>  
>> -	if (!(fb_helper->funcs->initial_config &&
>> -	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
>> -					       offsets,
>> -					       enabled, width, height))) {
>> +	if (!drm_fb_helper_firmware_config(fb_helper, crtcs, modes, offsets,
>> +					   enabled, width, height)) {
>>  		memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
>>  		memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
>>  		memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
>> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
>> index e8f694b57b8a..20e91600cf71 100644
>> --- a/drivers/gpu/drm/i915/intel_fbdev.c
>> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
>> @@ -292,225 +292,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
>>  	return ret;
>>  }
>>  
>> -static struct drm_fb_helper_crtc *
>> -intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
>> -{
>> -	int i;
>> -
>> -	for (i = 0; i < fb_helper->crtc_count; i++)
>> -		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
>> -			return &fb_helper->crtc_info[i];
>> -
>> -	return NULL;
>> -}
>> -
>> -/*
>> - * Try to read the BIOS display configuration and use it for the initial
>> - * fb configuration.
>> - *
>> - * The BIOS or boot loader will generally create an initial display
>> - * configuration for us that includes some set of active pipes and displays.
>> - * This routine tries to figure out which pipes and connectors are active
>> - * and stuffs them into the crtcs and modes array given to us by the
>> - * drm_fb_helper code.
>> - *
>> - * The overall sequence is:
>> - *   intel_fbdev_init - from driver load
>> - *     intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data
>> - *     drm_fb_helper_init - build fb helper structs
>> - *     drm_fb_helper_single_add_all_connectors - more fb helper structs
>> - *   intel_fbdev_initial_config - apply the config
>> - *     drm_fb_helper_initial_config - call ->probe then register_framebuffer()
>> - *         drm_setup_crtcs - build crtc config for fbdev
>> - *           intel_fb_initial_config - find active connectors etc
>> - *         drm_fb_helper_single_fb_probe - set up fbdev
>> - *           intelfb_create - re-use or alloc fb, build out fbdev structs
>> - *
>> - * Note that we don't make special consideration whether we could actually
>> - * switch to the selected modes without a full modeset. E.g. when the display
>> - * is in VGA mode we need to recalculate watermarks and set a new high-res
>> - * framebuffer anyway.
>> - */
>> -static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>> -				    struct drm_fb_helper_crtc **crtcs,
>> -				    struct drm_display_mode **modes,
>> -				    struct drm_fb_offset *offsets,
>> -				    bool *enabled, int width, int height)
>> -{
>> -	struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
>> -	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
>> -	unsigned long conn_configured, conn_seq;
>> -	int i, j;
>> -	bool *save_enabled;
>> -	bool fallback = true, ret = true;
>> -	int num_connectors_enabled = 0;
>> -	int num_connectors_detected = 0;
>> -	struct drm_modeset_acquire_ctx ctx;
>> -
>> -	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
>> -	if (!save_enabled)
>> -		return false;
>> -
>> -	drm_modeset_acquire_init(&ctx, 0);
>> -
>> -	while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
>> -		drm_modeset_backoff(&ctx);
>> -
>> -	memcpy(save_enabled, enabled, count);
>> -	conn_seq = GENMASK(count - 1, 0);
>> -	conn_configured = 0;
>> -retry:
>> -	for (i = 0; i < count; i++) {
>> -		struct drm_fb_helper_connector *fb_conn;
>> -		struct drm_connector *connector;
>> -		struct drm_encoder *encoder;
>> -		struct drm_fb_helper_crtc *new_crtc;
>> -
>> -		fb_conn = fb_helper->connector_info[i];
>> -		connector = fb_conn->connector;
>> -
>> -		if (conn_configured & BIT(i))
>> -			continue;
>> -
>> -		/* First pass, only consider tiled connectors */
>> -		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
>> -			continue;
>> -
>> -		if (connector->status == connector_status_connected)
>> -			num_connectors_detected++;
>> -
>> -		if (!enabled[i]) {
>> -			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
>> -				      connector->name);
>> -			conn_configured |= BIT(i);
>> -			continue;
>> -		}
>> -
>> -		if (connector->force == DRM_FORCE_OFF) {
>> -			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
>> -				      connector->name);
>> -			enabled[i] = false;
>> -			continue;
>> -		}
>> -
>> -		encoder = connector->state->best_encoder;
>> -		if (!encoder || WARN_ON(!connector->state->crtc)) {
>> -			if (connector->force > DRM_FORCE_OFF)
>> -				goto bail;
>> -
>> -			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
>> -				      connector->name);
>> -			enabled[i] = false;
>> -			conn_configured |= BIT(i);
>> -			continue;
>> -		}
>> -
>> -		num_connectors_enabled++;
>> -
>> -		new_crtc = intel_fb_helper_crtc(fb_helper,
>> -						connector->state->crtc);
>> -
>> -		/*
>> -		 * Make sure we're not trying to drive multiple connectors
>> -		 * with a single CRTC, since our cloning support may not
>> -		 * match the BIOS.
>> -		 */
>> -		for (j = 0; j < count; j++) {
>> -			if (crtcs[j] == new_crtc) {
>> -				DRM_DEBUG_KMS("fallback: cloned configuration\n");
>> -				goto bail;
>> -			}
>> -		}
>> -
>> -		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
>> -			      connector->name);
>> -
>> -		/* go for command line mode first */
>> -		modes[i] = drm_pick_cmdline_mode(fb_conn);
>> -
>> -		/* try for preferred next */
>> -		if (!modes[i]) {
>> -			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
>> -				      connector->name, connector->has_tile);
>> -			modes[i] = drm_has_preferred_mode(fb_conn, width,
>> -							  height);
>> -		}
>> -
>> -		/* No preferred mode marked by the EDID? Are there any modes? */
>> -		if (!modes[i] && !list_empty(&connector->modes)) {
>> -			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
>> -				      connector->name);
>> -			modes[i] = list_first_entry(&connector->modes,
>> -						    struct drm_display_mode,
>> -						    head);
>> -		}
>> -
>> -		/* last resort: use current mode */
>> -		if (!modes[i]) {
>> -			/*
>> -			 * IMPORTANT: We want to use the adjusted mode (i.e.
>> -			 * after the panel fitter upscaling) as the initial
>> -			 * config, not the input mode, which is what crtc->mode
>> -			 * usually contains. But since our current
>> -			 * code puts a mode derived from the post-pfit timings
>> -			 * into crtc->mode this works out correctly.
>> -			 *
>> -			 * This is crtc->mode and not crtc->state->mode for the
>> -			 * fastboot check to work correctly. crtc_state->mode has
>> -			 * I915_MODE_FLAG_INHERITED, which we clear to force check
>> -			 * state.
>> -			 */
>> -			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
>> -				      connector->name);
>> -			modes[i] = &connector->state->crtc->mode;
>> -		}
>> -		crtcs[i] = new_crtc;
>> -
>> -		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
>> -			      connector->name,
>> -			      connector->state->crtc->base.id,
>> -			      connector->state->crtc->name,
>> -			      modes[i]->hdisplay, modes[i]->vdisplay,
>> -			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :"");
>> -
>> -		fallback = false;
>> -		conn_configured |= BIT(i);
>> -	}
>> -
>> -	if (conn_configured != conn_seq) { /* repeat until no more are found */
>> -		conn_seq = conn_configured;
>> -		goto retry;
>> -	}
>> -
>> -	/*
>> -	 * If the BIOS didn't enable everything it could, fall back to have the
>> -	 * same user experiencing of lighting up as much as possible like the
>> -	 * fbdev helper library.
>> -	 */
>> -	if (num_connectors_enabled != num_connectors_detected &&
>> -	    num_connectors_enabled < INTEL_INFO(dev_priv)->num_pipes) {
>> -		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
>> -		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
>> -			      num_connectors_detected);
>> -		fallback = true;
>> -	}
>> -
>> -	if (fallback) {
>> -bail:
>> -		DRM_DEBUG_KMS("Not using firmware configuration\n");
>> -		memcpy(enabled, save_enabled, count);
>> -		ret = false;
>> -	}
>> -
>> -	drm_modeset_drop_locks(&ctx);
>> -	drm_modeset_acquire_fini(&ctx);
>> -
>> -	kfree(save_enabled);
>> -	return ret;
>> -}
>> -
>>  static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
>> -	.initial_config = intel_fb_initial_config,
>>  	.fb_probe = intelfb_create,
>>  };
>>  
>> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
>> index 7a095964f6b2..bca4b34dc93b 100644
>> --- a/include/drm/drm_fb_helper.h
>> +++ b/include/drm/drm_fb_helper.h
>> @@ -100,29 +100,6 @@ struct drm_fb_helper_funcs {
>>  	 */
>>  	int (*fb_probe)(struct drm_fb_helper *helper,
>>  			struct drm_fb_helper_surface_size *sizes);
>> -
>> -	/**
>> -	 * @initial_config:
>> -	 *
>> -	 * Driver callback to setup an initial fbdev display configuration.
>> -	 * Drivers can use this callback to tell the fbdev emulation what the
>> -	 * preferred initial configuration is. This is useful to implement
>> -	 * smooth booting where the fbdev (and subsequently all userspace) never
>> -	 * changes the mode, but always inherits the existing configuration.
>> -	 *
>> -	 * This callback is optional.
>> -	 *
>> -	 * RETURNS:
>> -	 *
>> -	 * The driver should return true if a suitable initial configuration has
>> -	 * been filled out and false when the fbdev helper should fall back to
>> -	 * the default probing logic.
>> -	 */
>> -	bool (*initial_config)(struct drm_fb_helper *fb_helper,
>> -			       struct drm_fb_helper_crtc **crtcs,
>> -			       struct drm_display_mode **modes,
>> -			       struct drm_fb_offset *offsets,
>> -			       bool *enabled, int width, int height);
>>  };
>>  
>>  struct drm_fb_helper_connector {
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 13/16] drm/fb-helper: Avoid race with DRM userspace
  2019-03-28  8:17   ` Daniel Vetter
@ 2019-03-30 21:07     ` Noralf Trønnes
  2019-04-01  7:12       ` Daniel Vetter
  0 siblings, 1 reply; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-30 21:07 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, intel-gfx, mstaudt, dri-devel



Den 28.03.2019 09.17, skrev Daniel Vetter:
> On Tue, Mar 26, 2019 at 06:55:43PM +0100, Noralf Trønnes wrote:
>> drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
>> This is done by looking at the fb on the primary plane. By the time
>> fb-helper gets around to committing, it's possible that the facts have
>> changed.
>>
>> Avoid this race by holding the drm_device->master_mutex lock while
>> committing. When DRM userspace does its first open, it will now wait
>> until fb-helper is done. The helper will stay away if there's a master.
>>
>> Locking rule: Always take the fb-helper lock first.
>>
>> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> 
> I think it'd be good to reorder this earlier in the series. And I'm
> wondering why you didn't replace all occurences of the _is_bound()
> function. With the consistent master state check we're doing with this I
> don't think any of the fbdev checking is still needed. Plus looking at
> crtc->primary->fb without any locks is racy, so would be good to ditch
> that hack.

_is_bound() is used in drm_fb_helper_hotplug_event() to decide on
delayed hotplug. The master lock won't help here. I have studied
drm_fb_helper for 2 years now, and I still think it is convoluted and
difficult to grasp in places. So I kept this one call site. I'm vary of
making unrelated changes in this series.

The reason I included this patch is because it's used with the
bootsplash example support code. I can move the patch earlier in the series.

Noralf.

> -Daniel
> 
>> ---
>>  drivers/gpu/drm/drm_auth.c      | 20 ++++++++++++++
>>  drivers/gpu/drm/drm_fb_helper.c | 49 ++++++++++++++++++++++++---------
>>  drivers/gpu/drm/drm_internal.h  |  2 ++
>>  3 files changed, 58 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
>> index 1669c42c40ed..db199807b7dc 100644
>> --- a/drivers/gpu/drm/drm_auth.c
>> +++ b/drivers/gpu/drm/drm_auth.c
>> @@ -368,3 +368,23 @@ void drm_master_put(struct drm_master **master)
>>  	*master = NULL;
>>  }
>>  EXPORT_SYMBOL(drm_master_put);
>> +
>> +/* Used by drm_client and drm_fb_helper */
>> +bool drm_master_internal_acquire(struct drm_device *dev)
>> +{
>> +	mutex_lock(&dev->master_mutex);
>> +	if (dev->master) {
>> +		mutex_unlock(&dev->master_mutex);
>> +		return false;
>> +	}
>> +
>> +	return true;
>> +}
>> +EXPORT_SYMBOL(drm_master_internal_acquire);
>> +
>> +/* Used by drm_client and drm_fb_helper */
>> +void drm_master_internal_release(struct drm_device *dev)
>> +{
>> +	mutex_unlock(&dev->master_mutex);
>> +}
>> +EXPORT_SYMBOL(drm_master_internal_release);
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>> index 4a073cd4e423..9f253fcf3f79 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -41,6 +41,8 @@
>>  #include <drm/drm_crtc_helper.h>
>>  #include <drm/drm_atomic.h>
>>  
>> +#include "drm_internal.h"
>> +
>>  static bool drm_fbdev_emulation = true;
>>  module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
>>  MODULE_PARM_DESC(fbdev_emulation,
>> @@ -235,7 +237,12 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
>>  		return 0;
>>  
>>  	mutex_lock(&fb_helper->lock);
>> -	ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
>> +	if (drm_master_internal_acquire(fb_helper->dev)) {
>> +		ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
>> +		drm_master_internal_release(fb_helper->dev);
>> +	} else {
>> +		ret = -EBUSY;
>> +	}
>>  
>>  	do_delayed = fb_helper->delayed_hotplug;
>>  	if (do_delayed)
>> @@ -332,13 +339,16 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
>>  static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
>>  {
>>  	struct drm_fb_helper *fb_helper = info->par;
>> +	struct drm_device *dev = fb_helper->dev;
>>  
>>  	/*
>>  	 * For each CRTC in this fb, turn the connectors on/off.
>>  	 */
>>  	mutex_lock(&fb_helper->lock);
>> -	if (drm_fb_helper_is_bound(fb_helper))
>> -		drm_client_modesets_dpms(fb_helper->dev, fb_helper->modesets, dpms_mode);
>> +	if (drm_master_internal_acquire(dev)) {
>> +		drm_client_modesets_dpms(dev, fb_helper->modesets, dpms_mode);
>> +		drm_master_internal_release(dev);
>> +	}
>>  	mutex_unlock(&fb_helper->lock);
>>  }
>>  
>> @@ -1097,6 +1107,7 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
>>  int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>>  {
>>  	struct drm_fb_helper *fb_helper = info->par;
>> +	struct drm_device *dev = fb_helper->dev;
>>  	int ret;
>>  
>>  	if (oops_in_progress)
>> @@ -1104,9 +1115,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>>  
>>  	mutex_lock(&fb_helper->lock);
>>  
>> -	if (!drm_fb_helper_is_bound(fb_helper)) {
>> +	if (!drm_master_internal_acquire(dev)) {
>>  		ret = -EBUSY;
>> -		goto out;
>> +		goto unlock;
>>  	}
>>  
>>  	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
>> @@ -1116,7 +1127,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>>  	else
>>  		ret = setcmap_legacy(cmap, info);
>>  
>> -out:
>> +	drm_master_internal_release(dev);
>> +unlock:
>>  	mutex_unlock(&fb_helper->lock);
>>  
>>  	return ret;
>> @@ -1136,11 +1148,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>>  			unsigned long arg)
>>  {
>>  	struct drm_fb_helper *fb_helper = info->par;
>> +	struct drm_device *dev = fb_helper->dev;
>>  	struct drm_crtc *crtc;
>>  	int ret = 0;
>>  
>>  	mutex_lock(&fb_helper->lock);
>> -	if (!drm_fb_helper_is_bound(fb_helper)) {
>> +
>> +	if (!drm_master_internal_acquire(dev)) {
>>  		ret = -EBUSY;
>>  		goto unlock;
>>  	}
>> @@ -1177,13 +1191,15 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>>  		}
>>  
>>  		ret = 0;
>> -		goto unlock;
>> +		break;
>>  	default:
>>  		ret = -ENOTTY;
>>  	}
>>  
>> +	drm_master_internal_release(dev);
>>  unlock:
>>  	mutex_unlock(&fb_helper->lock);
>> +
>>  	return ret;
>>  }
>>  EXPORT_SYMBOL(drm_fb_helper_ioctl);
>> @@ -1426,15 +1442,19 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
>>  		return -EBUSY;
>>  
>>  	mutex_lock(&fb_helper->lock);
>> -	if (!drm_fb_helper_is_bound(fb_helper)) {
>> -		mutex_unlock(&fb_helper->lock);
>> -		return -EBUSY;
>> +
>> +	if (!drm_master_internal_acquire(dev)) {
>> +		ret = -EBUSY;
>> +		goto unlock;
>>  	}
>>  
>>  	if (drm_drv_uses_atomic_modeset(dev))
>>  		ret = pan_display_atomic(var, info);
>>  	else
>>  		ret = pan_display_legacy(var, info);
>> +
>> +	drm_master_internal_release(dev);
>> +unlock:
>>  	mutex_unlock(&fb_helper->lock);
>>  
>>  	return ret;
>> @@ -1451,6 +1471,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>>  	int ret = 0;
>>  	int crtc_count = 0;
>>  	struct drm_connector_list_iter conn_iter;
>> +	struct drm_device *dev = fb_helper->dev;
>>  	struct drm_fb_helper_surface_size sizes;
>>  	struct drm_connector *connector;
>>  	struct drm_mode_set *mode_set;
>> @@ -1593,8 +1614,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>>  		DRM_INFO("Cannot find any crtc or sizes\n");
>>  
>>  		/* First time: disable all crtc's.. */
>> -		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
>> -			drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
>> +		if (!fb_helper->deferred_setup && drm_master_internal_acquire(dev)) {
>> +			drm_client_modesets_commit(dev, fb_helper->modesets);
>> +			drm_master_internal_release(dev);
>> +		}
>>  		return -EAGAIN;
>>  	}
>>  
>> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
>> index 251d67e04c2d..6d5d1184c084 100644
>> --- a/drivers/gpu/drm/drm_internal.h
>> +++ b/drivers/gpu/drm/drm_internal.h
>> @@ -91,6 +91,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
>>  			 struct drm_file *file_priv);
>>  int drm_master_open(struct drm_file *file_priv);
>>  void drm_master_release(struct drm_file *file_priv);
>> +bool drm_master_internal_acquire(struct drm_device *dev);
>> +void drm_master_internal_release(struct drm_device *dev);
>>  
>>  /* drm_sysfs.c */
>>  extern struct class *drm_class;
>> -- 
>> 2.20.1
>>
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client
  2019-03-28  9:31 ` [Intel-gfx] " Daniel Vetter
@ 2019-03-31 21:18   ` Noralf Trønnes
  0 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-03-31 21:18 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel



Den 28.03.2019 10.31, skrev Daniel Vetter:
> On Tue, Mar 26, 2019 at 06:55:30PM +0100, Noralf Trønnes wrote:
>> This moves the modesetting code from drm_fb_helper to drm_client so it
>> can be shared by all internal clients.
>>
>> I have also added a client display abstraction and a bootsplash example
>> client to show where this might be heading. Hopefully Max Staudt will be
>> able to pick up his bootsplash work now.
> 
> First a fairly unrelated thing that I noticed while reading stuff:
> 
> In drm_fbdev_generic_setup() we register the drm_client to the world (with
> drm_client_add) before it's fully set up. And the checks in the setup code
> aren't safe against a concurrent hotplug call from another thread. Which
> can happen, because usually by that point, and definitely by the time the
> driver called drm_dev_register() the hotplug handler is running.
> 

Ah, this hasn't crossed my mind. I'll move drm_client_add() after setup.

> Maybe good idea to rename drm_client_add to drm_client_register (to stay
> consistent with our naming scheme of _register() = others can start
> calling us from any thread).
> 

Makes sense, I'll change the name.

> We need to do the basic setup code _before_ we call drm_client_register.
> The kerneldoc for the various fbdev setup functions have explanations for
> when exactly it's ok to handle hotplug events.
> 
> The other bit is kinda the high-level review on the drm_client modeset
> api:
> - Allowing multiple different modeset clients per drm_client feels like
>   overkill. I think we can just require a 1:1 mapping between drm_client
>   and modeset config. If a client wants to have multiple different modeset
>   configs per drm_device they can create more drm_clients.
> 

The reason I ended up doing this is that there can be more than one
display connected. So for me the natural choice was to have each display
represented individually with its own modeset(s).

I did consider having the modeset array attached to drm_client and use a
modesets mask to tell the displays apart. It would have been easier if
we didn't have those tiled monitors driven by multiple outputs, because
that would have given us one modeset per display.

drm_fb_helper uses the same framebuffer for all displays, sizing it to
match the smallest.

Ofc the easy way out is to only support one display per drm_device. I
don't see how multiple drm_clients per drm_device should work. Should
the client keep an array of drm_client for as many displays as it supports?

The bootsplash client example I made, puts a splash on all displays it
can find. But maybe it should do it on only one display? If so we need
some heuristics to determine which is the primary display.

Not sure how kmscon is supposed to work, but I believe it is meant to be
a developer console. So I guess it will also just use the primary display.

> - That also fixes your "do we need embedding" question, since drm_client
>   supports that already.
> 
> - That means we could clean up the api considerably by embedding all the
>   modeset stuff into drm_client, and e.g. allocating the modeset arrays at
>   drm_client_init() time.
> 
> - Except that wouldn't work with the current fbdev emulation code, because
>   that one isn't always using drm_client.
> 
> Hence my question/suggestion: Could we rework the fbdev emulation to
> always allocate a drm_client, but only use drm_client for buffer
> allocation for generic_setup(). That could also provide us with a smoother
> upgrade path for other drivers to generic_setup, e.g. we could ditch all
> the hotplug handling already.
> 
> I'm thinking of embedding a drm_client into drm_fb_helper, and calling
> drm_client_init() on it at the right time. But only call drm_client_add()
> for generic_setup(). At least as a first step.
> 

Yeah, this certainly makes sense if we have the modesets attached to
drm_client_dev.

> Related question: What's the plan for drivers which don't support
> generic_setup()? If we eventually have stuff like kmscon running on top of
> drm_client, we'd have to somehow port them all ...
> 

It should just work as long the driver supports ->dumb_create and
->gem_prime_vmap.

rockchip and mediatek (I think) don't provide a virtual address on its
buffers because of limited virtual address space.
We could add a ->dumb_create_internal hook so these drivers could
provide an address to internal clients. This way they could use the
generic fbdev emualtion as well. Unless Rob finds a way to vmap a dma
buffer after allocation. He has looked at converting rockchip to generic
fbdev.

> And finally the bikeshed: I thik drm_client_modeset would be a good prefix
> for all this (maybe even in a separate file):

I have used prefix drm_client_modesets_ for all functions that operates
on the modeset array.

Emmanuel Vadot alerted me to the fact that dm_fb_helper is MIT licensed.
I was now planning to change drm_client to MIT as well, so I can legally
move over code. If we add drm_client_modeset.c with a MIT license, then
I wouldn't have to change the license of drm_client.c.
I think I would prefer to have it all in one file. drm_client.c is now
421 lines including everything, when I add the modeset code it becomes
1871. But it's not very important to me either way.

Noralf.

> - we have a pretty clear split between basic drm stuff and kms
> - modeset means kms, display usually only means the actual physical
>   display. drm_simple_display_pipe always gets me with using display
>   instead of modeset, but a bit too late to rename that one :-)
> 
> Thoughts on this?
> 
> Cheers, Daniel
> 
> 
>>
>> Noralf.
>>
>> Noralf Trønnes (16):
>>   drm/fb-helper: Remove unused gamma_size variable
>>   drm/fb-helper: dpms_legacy(): Only set on connectors in use
>>   drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
>>   drm/fb-helper: No need to cache rotation and sw_rotations
>>   drm/fb-helper: Remove drm_fb_helper_crtc->{x,y,desired_mode}
>>   drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
>>   drm/fb-helper: Remove drm_fb_helper_crtc
>>   drm/fb-helper: Prepare to move out commit code
>>   drm/fb-helper: Move out commit code
>>   drm/fb-helper: Remove drm_fb_helper_connector
>>   drm/fb-helper: Prepare to move out modeset config code
>>   drm/fb-helper: Move out modeset config code
>>   drm/fb-helper: Avoid race with DRM userspace
>>   drm/client: Add display abstraction
>>   drm/client: Hack: Add bootsplash example
>>   drm/vc4: Call drm_dev_register() after all setup is done
>>
>>  Documentation/gpu/todo.rst          |   10 +
>>  drivers/gpu/drm/Kconfig             |    5 +
>>  drivers/gpu/drm/Makefile            |    1 +
>>  drivers/gpu/drm/drm_atomic.c        |  168 ++++
>>  drivers/gpu/drm/drm_atomic_helper.c |  164 ---
>>  drivers/gpu/drm/drm_auth.c          |   20 +
>>  drivers/gpu/drm/drm_bootsplash.c    |  216 ++++
>>  drivers/gpu/drm/drm_client.c        | 1449 +++++++++++++++++++++++++++
>>  drivers/gpu/drm/drm_crtc_internal.h |    5 +
>>  drivers/gpu/drm/drm_drv.c           |    4 +
>>  drivers/gpu/drm/drm_fb_helper.c     | 1151 ++-------------------
>>  drivers/gpu/drm/drm_internal.h      |    2 +
>>  drivers/gpu/drm/i915/intel_fbdev.c  |  218 ----
>>  drivers/gpu/drm/vc4/vc4_drv.c       |    6 +-
>>  include/drm/drm_atomic_helper.h     |    4 -
>>  include/drm/drm_client.h            |  117 +++
>>  include/drm/drm_fb_helper.h         |  127 +--
>>  17 files changed, 2128 insertions(+), 1539 deletions(-)
>>  create mode 100644 drivers/gpu/drm/drm_bootsplash.c
>>
>> -- 
>> 2.20.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 13/16] drm/fb-helper: Avoid race with DRM userspace
  2019-03-30 21:07     ` Noralf Trønnes
@ 2019-04-01  7:12       ` Daniel Vetter
  2019-04-01 13:31         ` Noralf Trønnes
  0 siblings, 1 reply; 42+ messages in thread
From: Daniel Vetter @ 2019-04-01  7:12 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: Daniel Vetter, intel-gfx, mstaudt, dri-devel

On Sat, Mar 30, 2019 at 10:07:58PM +0100, Noralf Trønnes wrote:
> 
> 
> Den 28.03.2019 09.17, skrev Daniel Vetter:
> > On Tue, Mar 26, 2019 at 06:55:43PM +0100, Noralf Trønnes wrote:
> >> drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
> >> This is done by looking at the fb on the primary plane. By the time
> >> fb-helper gets around to committing, it's possible that the facts have
> >> changed.
> >>
> >> Avoid this race by holding the drm_device->master_mutex lock while
> >> committing. When DRM userspace does its first open, it will now wait
> >> until fb-helper is done. The helper will stay away if there's a master.
> >>
> >> Locking rule: Always take the fb-helper lock first.
> >>
> >> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> > 
> > I think it'd be good to reorder this earlier in the series. And I'm
> > wondering why you didn't replace all occurences of the _is_bound()
> > function. With the consistent master state check we're doing with this I
> > don't think any of the fbdev checking is still needed. Plus looking at
> > crtc->primary->fb without any locks is racy, so would be good to ditch
> > that hack.
> 
> _is_bound() is used in drm_fb_helper_hotplug_event() to decide on
> delayed hotplug. The master lock won't help here. I have studied
> drm_fb_helper for 2 years now, and I still think it is convoluted and
> difficult to grasp in places. So I kept this one call site. I'm vary of
> making unrelated changes in this series.

Hm, why would it not work for the hotplug case? _is_bound already checks
dev->master (but with races, unlike this here). And the other checks are
various levels of cargo-culting. dev->master is (well, has become through
retrofitting) the "who owns the display" tracking, I think fully
standardizing on that makes sense. The only case where there's a
difference is if:
- some compositor dropped master
- but didn't disable it's framebuffers
We actually want that for smooth vt switching, so that the new compositor
could take over in a transition. Having a special case with fbdev where
the compositor has to disable all its fb or fbcon won't take over feels a
bit irky.
-Daniel

> The reason I included this patch is because it's used with the
> bootsplash example support code. I can move the patch earlier in the series.
> 
> Noralf.
> 
> > -Daniel
> > 
> >> ---
> >>  drivers/gpu/drm/drm_auth.c      | 20 ++++++++++++++
> >>  drivers/gpu/drm/drm_fb_helper.c | 49 ++++++++++++++++++++++++---------
> >>  drivers/gpu/drm/drm_internal.h  |  2 ++
> >>  3 files changed, 58 insertions(+), 13 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> >> index 1669c42c40ed..db199807b7dc 100644
> >> --- a/drivers/gpu/drm/drm_auth.c
> >> +++ b/drivers/gpu/drm/drm_auth.c
> >> @@ -368,3 +368,23 @@ void drm_master_put(struct drm_master **master)
> >>  	*master = NULL;
> >>  }
> >>  EXPORT_SYMBOL(drm_master_put);
> >> +
> >> +/* Used by drm_client and drm_fb_helper */
> >> +bool drm_master_internal_acquire(struct drm_device *dev)
> >> +{
> >> +	mutex_lock(&dev->master_mutex);
> >> +	if (dev->master) {
> >> +		mutex_unlock(&dev->master_mutex);
> >> +		return false;
> >> +	}
> >> +
> >> +	return true;
> >> +}
> >> +EXPORT_SYMBOL(drm_master_internal_acquire);
> >> +
> >> +/* Used by drm_client and drm_fb_helper */
> >> +void drm_master_internal_release(struct drm_device *dev)
> >> +{
> >> +	mutex_unlock(&dev->master_mutex);
> >> +}
> >> +EXPORT_SYMBOL(drm_master_internal_release);
> >> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> >> index 4a073cd4e423..9f253fcf3f79 100644
> >> --- a/drivers/gpu/drm/drm_fb_helper.c
> >> +++ b/drivers/gpu/drm/drm_fb_helper.c
> >> @@ -41,6 +41,8 @@
> >>  #include <drm/drm_crtc_helper.h>
> >>  #include <drm/drm_atomic.h>
> >>  
> >> +#include "drm_internal.h"
> >> +
> >>  static bool drm_fbdev_emulation = true;
> >>  module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
> >>  MODULE_PARM_DESC(fbdev_emulation,
> >> @@ -235,7 +237,12 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
> >>  		return 0;
> >>  
> >>  	mutex_lock(&fb_helper->lock);
> >> -	ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
> >> +	if (drm_master_internal_acquire(fb_helper->dev)) {
> >> +		ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
> >> +		drm_master_internal_release(fb_helper->dev);
> >> +	} else {
> >> +		ret = -EBUSY;
> >> +	}
> >>  
> >>  	do_delayed = fb_helper->delayed_hotplug;
> >>  	if (do_delayed)
> >> @@ -332,13 +339,16 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
> >>  static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
> >>  {
> >>  	struct drm_fb_helper *fb_helper = info->par;
> >> +	struct drm_device *dev = fb_helper->dev;
> >>  
> >>  	/*
> >>  	 * For each CRTC in this fb, turn the connectors on/off.
> >>  	 */
> >>  	mutex_lock(&fb_helper->lock);
> >> -	if (drm_fb_helper_is_bound(fb_helper))
> >> -		drm_client_modesets_dpms(fb_helper->dev, fb_helper->modesets, dpms_mode);
> >> +	if (drm_master_internal_acquire(dev)) {
> >> +		drm_client_modesets_dpms(dev, fb_helper->modesets, dpms_mode);
> >> +		drm_master_internal_release(dev);
> >> +	}
> >>  	mutex_unlock(&fb_helper->lock);
> >>  }
> >>  
> >> @@ -1097,6 +1107,7 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
> >>  int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
> >>  {
> >>  	struct drm_fb_helper *fb_helper = info->par;
> >> +	struct drm_device *dev = fb_helper->dev;
> >>  	int ret;
> >>  
> >>  	if (oops_in_progress)
> >> @@ -1104,9 +1115,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
> >>  
> >>  	mutex_lock(&fb_helper->lock);
> >>  
> >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> >> +	if (!drm_master_internal_acquire(dev)) {
> >>  		ret = -EBUSY;
> >> -		goto out;
> >> +		goto unlock;
> >>  	}
> >>  
> >>  	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
> >> @@ -1116,7 +1127,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
> >>  	else
> >>  		ret = setcmap_legacy(cmap, info);
> >>  
> >> -out:
> >> +	drm_master_internal_release(dev);
> >> +unlock:
> >>  	mutex_unlock(&fb_helper->lock);
> >>  
> >>  	return ret;
> >> @@ -1136,11 +1148,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
> >>  			unsigned long arg)
> >>  {
> >>  	struct drm_fb_helper *fb_helper = info->par;
> >> +	struct drm_device *dev = fb_helper->dev;
> >>  	struct drm_crtc *crtc;
> >>  	int ret = 0;
> >>  
> >>  	mutex_lock(&fb_helper->lock);
> >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> >> +
> >> +	if (!drm_master_internal_acquire(dev)) {
> >>  		ret = -EBUSY;
> >>  		goto unlock;
> >>  	}
> >> @@ -1177,13 +1191,15 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
> >>  		}
> >>  
> >>  		ret = 0;
> >> -		goto unlock;
> >> +		break;
> >>  	default:
> >>  		ret = -ENOTTY;
> >>  	}
> >>  
> >> +	drm_master_internal_release(dev);
> >>  unlock:
> >>  	mutex_unlock(&fb_helper->lock);
> >> +
> >>  	return ret;
> >>  }
> >>  EXPORT_SYMBOL(drm_fb_helper_ioctl);
> >> @@ -1426,15 +1442,19 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
> >>  		return -EBUSY;
> >>  
> >>  	mutex_lock(&fb_helper->lock);
> >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> >> -		mutex_unlock(&fb_helper->lock);
> >> -		return -EBUSY;
> >> +
> >> +	if (!drm_master_internal_acquire(dev)) {
> >> +		ret = -EBUSY;
> >> +		goto unlock;
> >>  	}
> >>  
> >>  	if (drm_drv_uses_atomic_modeset(dev))
> >>  		ret = pan_display_atomic(var, info);
> >>  	else
> >>  		ret = pan_display_legacy(var, info);
> >> +
> >> +	drm_master_internal_release(dev);
> >> +unlock:
> >>  	mutex_unlock(&fb_helper->lock);
> >>  
> >>  	return ret;
> >> @@ -1451,6 +1471,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
> >>  	int ret = 0;
> >>  	int crtc_count = 0;
> >>  	struct drm_connector_list_iter conn_iter;
> >> +	struct drm_device *dev = fb_helper->dev;
> >>  	struct drm_fb_helper_surface_size sizes;
> >>  	struct drm_connector *connector;
> >>  	struct drm_mode_set *mode_set;
> >> @@ -1593,8 +1614,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
> >>  		DRM_INFO("Cannot find any crtc or sizes\n");
> >>  
> >>  		/* First time: disable all crtc's.. */
> >> -		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
> >> -			drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
> >> +		if (!fb_helper->deferred_setup && drm_master_internal_acquire(dev)) {
> >> +			drm_client_modesets_commit(dev, fb_helper->modesets);
> >> +			drm_master_internal_release(dev);
> >> +		}
> >>  		return -EAGAIN;
> >>  	}
> >>  
> >> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> >> index 251d67e04c2d..6d5d1184c084 100644
> >> --- a/drivers/gpu/drm/drm_internal.h
> >> +++ b/drivers/gpu/drm/drm_internal.h
> >> @@ -91,6 +91,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
> >>  			 struct drm_file *file_priv);
> >>  int drm_master_open(struct drm_file *file_priv);
> >>  void drm_master_release(struct drm_file *file_priv);
> >> +bool drm_master_internal_acquire(struct drm_device *dev);
> >> +void drm_master_internal_release(struct drm_device *dev);
> >>  
> >>  /* drm_sysfs.c */
> >>  extern struct class *drm_class;
> >> -- 
> >> 2.20.1
> >>
> > 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 13/16] drm/fb-helper: Avoid race with DRM userspace
  2019-04-01  7:12       ` Daniel Vetter
@ 2019-04-01 13:31         ` Noralf Trønnes
  0 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-04-01 13:31 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, intel-gfx, dri-devel



Den 01.04.2019 09.12, skrev Daniel Vetter:
> On Sat, Mar 30, 2019 at 10:07:58PM +0100, Noralf Trønnes wrote:
>>
>>
>> Den 28.03.2019 09.17, skrev Daniel Vetter:
>>> On Tue, Mar 26, 2019 at 06:55:43PM +0100, Noralf Trønnes wrote:
>>>> drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
>>>> This is done by looking at the fb on the primary plane. By the time
>>>> fb-helper gets around to committing, it's possible that the facts have
>>>> changed.
>>>>
>>>> Avoid this race by holding the drm_device->master_mutex lock while
>>>> committing. When DRM userspace does its first open, it will now wait
>>>> until fb-helper is done. The helper will stay away if there's a master.
>>>>
>>>> Locking rule: Always take the fb-helper lock first.
>>>>
>>>> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>>>
>>> I think it'd be good to reorder this earlier in the series. And I'm
>>> wondering why you didn't replace all occurences of the _is_bound()
>>> function. With the consistent master state check we're doing with this I
>>> don't think any of the fbdev checking is still needed. Plus looking at
>>> crtc->primary->fb without any locks is racy, so would be good to ditch
>>> that hack.
>>
>> _is_bound() is used in drm_fb_helper_hotplug_event() to decide on
>> delayed hotplug. The master lock won't help here. I have studied
>> drm_fb_helper for 2 years now, and I still think it is convoluted and
>> difficult to grasp in places. So I kept this one call site. I'm vary of
>> making unrelated changes in this series.
> 
> Hm, why would it not work for the hotplug case? _is_bound already checks
> dev->master (but with races, unlike this here). And the other checks are
> various levels of cargo-culting. dev->master is (well, has become through
> retrofitting) the "who owns the display" tracking, I think fully
> standardizing on that makes sense. The only case where there's a
> difference is if:
> - some compositor dropped master
> - but didn't disable it's framebuffers
> We actually want that for smooth vt switching, so that the new compositor
> could take over in a transition. Having a special case with fbdev where
> the compositor has to disable all its fb or fbcon won't take over feels a
> bit irky.

You're right ofc.
I read '->deferred_setup = true' when in fact it is '->delayed_hotplug =
true', so I assumed there was something that _is_bound() was protecting
wrt. to setup state.
I'll fix it in the next version.

Noralf.

> -Daniel
> 
>> The reason I included this patch is because it's used with the
>> bootsplash example support code. I can move the patch earlier in the series.
>>
>> Noralf.
>>
>>> -Daniel
>>>
>>>> ---
>>>>  drivers/gpu/drm/drm_auth.c      | 20 ++++++++++++++
>>>>  drivers/gpu/drm/drm_fb_helper.c | 49 ++++++++++++++++++++++++---------
>>>>  drivers/gpu/drm/drm_internal.h  |  2 ++
>>>>  3 files changed, 58 insertions(+), 13 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
>>>> index 1669c42c40ed..db199807b7dc 100644
>>>> --- a/drivers/gpu/drm/drm_auth.c
>>>> +++ b/drivers/gpu/drm/drm_auth.c
>>>> @@ -368,3 +368,23 @@ void drm_master_put(struct drm_master **master)
>>>>  	*master = NULL;
>>>>  }
>>>>  EXPORT_SYMBOL(drm_master_put);
>>>> +
>>>> +/* Used by drm_client and drm_fb_helper */
>>>> +bool drm_master_internal_acquire(struct drm_device *dev)
>>>> +{
>>>> +	mutex_lock(&dev->master_mutex);
>>>> +	if (dev->master) {
>>>> +		mutex_unlock(&dev->master_mutex);
>>>> +		return false;
>>>> +	}
>>>> +
>>>> +	return true;
>>>> +}
>>>> +EXPORT_SYMBOL(drm_master_internal_acquire);
>>>> +
>>>> +/* Used by drm_client and drm_fb_helper */
>>>> +void drm_master_internal_release(struct drm_device *dev)
>>>> +{
>>>> +	mutex_unlock(&dev->master_mutex);
>>>> +}
>>>> +EXPORT_SYMBOL(drm_master_internal_release);
>>>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>>>> index 4a073cd4e423..9f253fcf3f79 100644
>>>> --- a/drivers/gpu/drm/drm_fb_helper.c
>>>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>>>> @@ -41,6 +41,8 @@
>>>>  #include <drm/drm_crtc_helper.h>
>>>>  #include <drm/drm_atomic.h>
>>>>  
>>>> +#include "drm_internal.h"
>>>> +
>>>>  static bool drm_fbdev_emulation = true;
>>>>  module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
>>>>  MODULE_PARM_DESC(fbdev_emulation,
>>>> @@ -235,7 +237,12 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
>>>>  		return 0;
>>>>  
>>>>  	mutex_lock(&fb_helper->lock);
>>>> -	ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
>>>> +	if (drm_master_internal_acquire(fb_helper->dev)) {
>>>> +		ret = drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
>>>> +		drm_master_internal_release(fb_helper->dev);
>>>> +	} else {
>>>> +		ret = -EBUSY;
>>>> +	}
>>>>  
>>>>  	do_delayed = fb_helper->delayed_hotplug;
>>>>  	if (do_delayed)
>>>> @@ -332,13 +339,16 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
>>>>  static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
>>>>  {
>>>>  	struct drm_fb_helper *fb_helper = info->par;
>>>> +	struct drm_device *dev = fb_helper->dev;
>>>>  
>>>>  	/*
>>>>  	 * For each CRTC in this fb, turn the connectors on/off.
>>>>  	 */
>>>>  	mutex_lock(&fb_helper->lock);
>>>> -	if (drm_fb_helper_is_bound(fb_helper))
>>>> -		drm_client_modesets_dpms(fb_helper->dev, fb_helper->modesets, dpms_mode);
>>>> +	if (drm_master_internal_acquire(dev)) {
>>>> +		drm_client_modesets_dpms(dev, fb_helper->modesets, dpms_mode);
>>>> +		drm_master_internal_release(dev);
>>>> +	}
>>>>  	mutex_unlock(&fb_helper->lock);
>>>>  }
>>>>  
>>>> @@ -1097,6 +1107,7 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
>>>>  int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>>>>  {
>>>>  	struct drm_fb_helper *fb_helper = info->par;
>>>> +	struct drm_device *dev = fb_helper->dev;
>>>>  	int ret;
>>>>  
>>>>  	if (oops_in_progress)
>>>> @@ -1104,9 +1115,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>>>>  
>>>>  	mutex_lock(&fb_helper->lock);
>>>>  
>>>> -	if (!drm_fb_helper_is_bound(fb_helper)) {
>>>> +	if (!drm_master_internal_acquire(dev)) {
>>>>  		ret = -EBUSY;
>>>> -		goto out;
>>>> +		goto unlock;
>>>>  	}
>>>>  
>>>>  	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
>>>> @@ -1116,7 +1127,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>>>>  	else
>>>>  		ret = setcmap_legacy(cmap, info);
>>>>  
>>>> -out:
>>>> +	drm_master_internal_release(dev);
>>>> +unlock:
>>>>  	mutex_unlock(&fb_helper->lock);
>>>>  
>>>>  	return ret;
>>>> @@ -1136,11 +1148,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>>>>  			unsigned long arg)
>>>>  {
>>>>  	struct drm_fb_helper *fb_helper = info->par;
>>>> +	struct drm_device *dev = fb_helper->dev;
>>>>  	struct drm_crtc *crtc;
>>>>  	int ret = 0;
>>>>  
>>>>  	mutex_lock(&fb_helper->lock);
>>>> -	if (!drm_fb_helper_is_bound(fb_helper)) {
>>>> +
>>>> +	if (!drm_master_internal_acquire(dev)) {
>>>>  		ret = -EBUSY;
>>>>  		goto unlock;
>>>>  	}
>>>> @@ -1177,13 +1191,15 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>>>>  		}
>>>>  
>>>>  		ret = 0;
>>>> -		goto unlock;
>>>> +		break;
>>>>  	default:
>>>>  		ret = -ENOTTY;
>>>>  	}
>>>>  
>>>> +	drm_master_internal_release(dev);
>>>>  unlock:
>>>>  	mutex_unlock(&fb_helper->lock);
>>>> +
>>>>  	return ret;
>>>>  }
>>>>  EXPORT_SYMBOL(drm_fb_helper_ioctl);
>>>> @@ -1426,15 +1442,19 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
>>>>  		return -EBUSY;
>>>>  
>>>>  	mutex_lock(&fb_helper->lock);
>>>> -	if (!drm_fb_helper_is_bound(fb_helper)) {
>>>> -		mutex_unlock(&fb_helper->lock);
>>>> -		return -EBUSY;
>>>> +
>>>> +	if (!drm_master_internal_acquire(dev)) {
>>>> +		ret = -EBUSY;
>>>> +		goto unlock;
>>>>  	}
>>>>  
>>>>  	if (drm_drv_uses_atomic_modeset(dev))
>>>>  		ret = pan_display_atomic(var, info);
>>>>  	else
>>>>  		ret = pan_display_legacy(var, info);
>>>> +
>>>> +	drm_master_internal_release(dev);
>>>> +unlock:
>>>>  	mutex_unlock(&fb_helper->lock);
>>>>  
>>>>  	return ret;
>>>> @@ -1451,6 +1471,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>>>>  	int ret = 0;
>>>>  	int crtc_count = 0;
>>>>  	struct drm_connector_list_iter conn_iter;
>>>> +	struct drm_device *dev = fb_helper->dev;
>>>>  	struct drm_fb_helper_surface_size sizes;
>>>>  	struct drm_connector *connector;
>>>>  	struct drm_mode_set *mode_set;
>>>> @@ -1593,8 +1614,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>>>>  		DRM_INFO("Cannot find any crtc or sizes\n");
>>>>  
>>>>  		/* First time: disable all crtc's.. */
>>>> -		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
>>>> -			drm_client_modesets_commit(fb_helper->dev, fb_helper->modesets);
>>>> +		if (!fb_helper->deferred_setup && drm_master_internal_acquire(dev)) {
>>>> +			drm_client_modesets_commit(dev, fb_helper->modesets);
>>>> +			drm_master_internal_release(dev);
>>>> +		}
>>>>  		return -EAGAIN;
>>>>  	}
>>>>  
>>>> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
>>>> index 251d67e04c2d..6d5d1184c084 100644
>>>> --- a/drivers/gpu/drm/drm_internal.h
>>>> +++ b/drivers/gpu/drm/drm_internal.h
>>>> @@ -91,6 +91,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
>>>>  			 struct drm_file *file_priv);
>>>>  int drm_master_open(struct drm_file *file_priv);
>>>>  void drm_master_release(struct drm_file *file_priv);
>>>> +bool drm_master_internal_acquire(struct drm_device *dev);
>>>> +void drm_master_internal_release(struct drm_device *dev);
>>>>  
>>>>  /* drm_sysfs.c */
>>>>  extern struct class *drm_class;
>>>> -- 
>>>> 2.20.1
>>>>
>>>
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Intel-gfx] [PATCH 01/16] drm/fb-helper: Remove unused gamma_size variable
  2019-03-26 18:23   ` Daniel Vetter
@ 2019-04-03  9:19     ` Noralf Trønnes
  0 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-04-03  9:19 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, mstaudt, dri-devel



Den 26.03.2019 19.23, skrev Daniel Vetter:
> On Tue, Mar 26, 2019 at 06:55:31PM +0100, Noralf Trønnes wrote:
>> The gamma_size variable has not been used since
>> commit 4abe35204af8 ("drm/kms/fb: use slow work mechanism for normal hotplug also.")
>>
>> While in the area move a comment back to its code block.
>> They got separated by
>> commit d50ba256b5f1 ("drm/kms: start adding command line interface using fb.").
>>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Thanks, patches 1 & 2 applied to drm-misc-next.

Noralf.

> 
>> ---
>>  drivers/gpu/drm/drm_fb_helper.c | 6 +-----
>>  1 file changed, 1 insertion(+), 5 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>> index 04d23cb430bf..eea15465da7a 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -1873,7 +1873,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>>  	int crtc_count = 0;
>>  	int i;
>>  	struct drm_fb_helper_surface_size sizes;
>> -	int gamma_size = 0;
>>  	int best_depth = 0;
>>  
>>  	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
>> @@ -1889,7 +1888,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>>  	if (preferred_bpp != sizes.surface_bpp)
>>  		sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
>>  
>> -	/* first up get a count of crtcs now in use and new min/maxes width/heights */
>>  	drm_fb_helper_for_each_connector(fb_helper, i) {
>>  		struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
>>  		struct drm_cmdline_mode *cmdline_mode;
>> @@ -1969,6 +1967,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>>  		sizes.surface_depth = best_depth;
>>  	}
>>  
>> +	/* first up get a count of crtcs now in use and new min/maxes width/heights */
>>  	crtc_count = 0;
>>  	for (i = 0; i < fb_helper->crtc_count; i++) {
>>  		struct drm_display_mode *desired_mode;
>> @@ -1991,9 +1990,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>>  		x = fb_helper->crtc_info[i].x;
>>  		y = fb_helper->crtc_info[i].y;
>>  
>> -		if (gamma_size == 0)
>> -			gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
>> -
>>  		sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
>>  		sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
>>  
>> -- 
>> 2.20.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 16/16] drm/vc4: Call drm_dev_register() after all setup is done
  2019-03-27 16:36   ` Eric Anholt
@ 2019-04-03  9:20     ` Noralf Trønnes
  0 siblings, 0 replies; 42+ messages in thread
From: Noralf Trønnes @ 2019-04-03  9:20 UTC (permalink / raw)
  To: Eric Anholt, dri-devel; +Cc: intel-gfx



Den 27.03.2019 17.36, skrev Eric Anholt:
> Noralf Trønnes <noralf@tronnes.org> writes:
> 
>> drm_dev_register() initializes internal clients like bootsplash as the
>> last thing it does, so all setup needs to be done at this point.
>>
>> Fix by calling vc4_kms_load() before registering.
>> Also check the error code returned from that function.
>>
>> Cc: Eric Anholt <eric@anholt.net>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> 
> Reviewed-by: Eric Anholt <eric@anholt.net>
> 

Applied to drm-misc-next.

Noralf.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2019-04-03  9:20 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-26 17:55 [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
2019-03-26 17:55 ` [PATCH 01/16] drm/fb-helper: Remove unused gamma_size variable Noralf Trønnes
2019-03-26 18:23   ` Daniel Vetter
2019-04-03  9:19     ` [Intel-gfx] " Noralf Trønnes
2019-03-26 17:55 ` [PATCH 02/16] drm/fb-helper: dpms_legacy(): Only set on connectors in use Noralf Trønnes
2019-03-26 18:26   ` Daniel Vetter
2019-03-26 17:55 ` [PATCH 03/16] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
2019-03-26 20:48   ` Daniel Vetter
2019-03-27 13:41     ` [Intel-gfx] " Noralf Trønnes
2019-03-27 13:55       ` Daniel Vetter
2019-03-27 14:27         ` [Intel-gfx] " Noralf Trønnes
2019-03-26 17:55 ` [PATCH 04/16] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
2019-03-28  8:03   ` Daniel Vetter
2019-03-26 17:55 ` [PATCH 05/16] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode} Noralf Trønnes
2019-03-28  8:19   ` Daniel Vetter
2019-03-26 17:55 ` [PATCH 06/16] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper Noralf Trønnes
2019-03-27 13:33   ` Jani Nikula
2019-03-30 20:50     ` Noralf Trønnes
2019-03-26 17:55 ` [PATCH 07/16] drm/fb-helper: Remove drm_fb_helper_crtc Noralf Trønnes
2019-03-26 17:55 ` [PATCH 08/16] drm/fb-helper: Prepare to move out commit code Noralf Trønnes
2019-03-26 17:55 ` [PATCH 09/16] drm/fb-helper: Move " Noralf Trønnes
2019-03-27 14:13   ` Emmanuel Vadot
2019-03-27 15:01     ` Noralf Trønnes
2019-03-27 15:12       ` Emmanuel Vadot
2019-03-26 17:55 ` [PATCH 10/16] drm/fb-helper: Remove drm_fb_helper_connector Noralf Trønnes
2019-03-26 17:55 ` [PATCH 11/16] drm/fb-helper: Prepare to move out modeset config code Noralf Trønnes
2019-03-26 17:55 ` [PATCH 12/16] drm/fb-helper: Move " Noralf Trønnes
2019-03-26 17:55 ` [PATCH 13/16] drm/fb-helper: Avoid race with DRM userspace Noralf Trønnes
2019-03-28  8:17   ` Daniel Vetter
2019-03-30 21:07     ` Noralf Trønnes
2019-04-01  7:12       ` Daniel Vetter
2019-04-01 13:31         ` Noralf Trønnes
2019-03-26 17:55 ` [PATCH 14/16] drm/client: Add display abstraction Noralf Trønnes
2019-03-26 17:55 ` [PATCH 15/16] drm/client: Hack: Add bootsplash example Noralf Trønnes
2019-03-26 17:55 ` [PATCH 16/16] drm/vc4: Call drm_dev_register() after all setup is done Noralf Trønnes
2019-03-26 20:40   ` Daniel Vetter
2019-03-27 16:36   ` Eric Anholt
2019-04-03  9:20     ` Noralf Trønnes
2019-03-27 13:45 ` [PATCH 00/16] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
2019-03-27 13:52   ` Thomas Zimmermann
2019-03-28  9:31 ` [Intel-gfx] " Daniel Vetter
2019-03-31 21:18   ` Noralf Trønnes

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).