diff mbox

i915: Dealing with 90° rotated display ?

Message ID 17d93e1d-72e8-af3c-3ffd-6dcfad129721@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Hans de Goede Feb. 25, 2017, 6:28 p.m. UTC
Hi,

On 20-02-17 14:24, Hans de Goede wrote:

<snip>

>>> So when userspace
>>> (e.g. the Xorg server + modesetting driver) asks for 0° degree
>>> rotation under the hood they get 90 applied, when they aks for
>>> the panel resolution they get 1280x720 instead of 720x1280.
>>
>> The idea was that userspace will inherit the initial rotation.
>> That does work correctly at least with the intel ddx.
>
> Ah (userspace will inherit the initial rotation) I've yet to patch the
> kernel to set up an initial rotation for this, I will give this a
> try and see if that helps.

Ok, so for my case this does not help because only skylake and
later support 90 / 270 degree rotation and I'm on cherrytrail.

In case anyone is interested I've attached a rebased version
of the fbcon inherit wip patch (with the unrelated changes
to fb-helper's clone code removed).

Regards,

Hans
diff mbox

Patch

From d6baf99228e6ce78f0a7e86feee48c34309e9b1c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com>
Date: Sun, 29 Nov 2015 17:56:03 +0200
Subject: [PATCH] drm/fb-helper: Inherit rotation wip

---
 drivers/gpu/drm/drm_fb_helper.c      | 48 ++++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_display.c | 30 +++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_drv.h     |  1 +
 include/drm/drm_fb_helper.h          |  2 ++
 4 files changed, 78 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index f6d4d97..07de6d1 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -159,6 +159,8 @@  int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
 {
 	struct drm_fb_helper_connector **temp;
 	struct drm_fb_helper_connector *fb_helper_connector;
+	struct drm_crtc *crtc = connector->encoder ?
+				connector->encoder->crtc : NULL;
 
 	if (!drm_fbdev_emulation)
 		return 0;
@@ -180,6 +182,11 @@  int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
 
 	drm_connector_reference(connector);
 	fb_helper_connector->connector = connector;
+	if (crtc && crtc->primary->state)
+		fb_helper_connector->rotation = crtc->primary->state->rotation;
+	if (!fb_helper_connector->rotation)
+		fb_helper_connector->rotation = DRM_ROTATE_0;
+
 	fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
 	return 0;
 }
@@ -333,6 +340,35 @@  int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
+static int fbdev_plane_index(struct drm_fb_helper *fb_helper,
+			     struct drm_plane *plane)
+{
+	int i;
+
+	if (plane->type != DRM_PLANE_TYPE_PRIMARY)
+		return -ENODEV;
+
+	for (i = 0; i < fb_helper->crtc_count; i++) {
+		struct drm_crtc *crtc = fb_helper->crtc_info[i].mode_set.crtc;
+
+		if (crtc && crtc->primary == plane)
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+static unsigned int fbdev_plane_rotation(struct drm_fb_helper *fb_helper,
+					 struct drm_plane *plane)
+{
+	int i = fbdev_plane_index(fb_helper, plane);
+
+	if (i < 0)
+		return DRM_ROTATE_0;
+	else
+		return fb_helper->crtc_info[i].rotation;
+}
+
 static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
 {
 	struct drm_device *dev = fb_helper->dev;
@@ -357,7 +393,7 @@  static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
 			goto fail;
 		}
 
-		plane_state->rotation = DRM_ROTATE_0;
+		plane_state->rotation = fbdev_plane_rotation(fb_helper, plane);
 
 		plane->old_fb = plane->fb;
 		plane_mask |= 1 << drm_plane_index(plane);
@@ -415,7 +451,7 @@  static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
 		if (plane->rotation_property)
 			drm_mode_plane_set_obj_prop(plane,
 						    plane->rotation_property,
-						    DRM_ROTATE_0);
+						    fbdev_plane_rotation(fb_helper, plane));
 	}
 
 	for (i = 0; i < fb_helper->crtc_count; i++) {
@@ -760,6 +796,7 @@  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_ROTATE_0;
 	}
 
 	i = 0;
@@ -2090,8 +2127,14 @@  static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 
 			if (!drm_mode_equal(modes[o], modes[n]))
 				continue;
+
+			if (crtc->rotation &&
+			    crtc->rotation != fb_helper_conn->rotation)
+				continue;
 		}
 
+		crtc->rotation = fb_helper_conn->rotation;
+
 		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,
@@ -2182,6 +2225,7 @@  static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			fb_crtc->desired_mode = mode;
 			fb_crtc->x = offset->x;
 			fb_crtc->y = offset->y;
+			fb_crtc->rotation = fb_helper->connector_info[i]->rotation;
 			modeset->mode = drm_mode_duplicate(dev,
 							   fb_crtc->desired_mode);
 			drm_connector_reference(connector);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e1e828a..29addfe 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2757,6 +2757,8 @@  intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
 	plane_state->crtc_w = fb->width;
 	plane_state->crtc_h = fb->height;
 
+	plane_state->rotation = plane_config->rotation;
+
 	intel_state->base.src = drm_plane_state_src(plane_state);
 	intel_state->base.dst = drm_plane_state_dest(plane_state);
 
@@ -7407,6 +7409,9 @@  i9xx_get_initial_plane_config(struct intel_crtc *crtc,
 			plane_config->tiling = I915_TILING_X;
 			fb->modifier = I915_FORMAT_MOD_X_TILED;
 		}
+
+		if (val & DISPPLANE_ROTATE_180)
+			plane_config->rotation = DRM_ROTATE_180;
 	}
 
 	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
@@ -8459,6 +8464,24 @@  skylake_get_initial_plane_config(struct intel_crtc *crtc,
 		goto error;
 	}
 
+	/*
+	 * DRM_ROTATE_ is counter clockwise to stay compatible with Xrandr
+	 * while i915 HW rotation is clockwise, thats why this swapping.
+	 */
+	switch (val & PLANE_CTL_ROTATE_MASK) {
+	case PLANE_CTL_ROTATE_0:
+		break;
+	case PLANE_CTL_ROTATE_90:
+		plane_config->rotation = DRM_ROTATE_270;
+		break;
+	case PLANE_CTL_ROTATE_180:
+		plane_config->rotation = DRM_ROTATE_180;
+		break;
+	case PLANE_CTL_ROTATE_270:
+		plane_config->rotation = DRM_ROTATE_90;
+		break;
+	}
+
 	base = I915_READ(PLANE_SURF(pipe, 0)) & 0xfffff000;
 	plane_config->base = base;
 
@@ -8548,6 +8571,9 @@  ironlake_get_initial_plane_config(struct intel_crtc *crtc,
 			plane_config->tiling = I915_TILING_X;
 			fb->modifier = I915_FORMAT_MOD_X_TILED;
 		}
+
+		if (val & DISPPLANE_ROTATE_180)
+			plane_config->rotation = DRM_ROTATE_180;
 	}
 
 	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
@@ -15045,7 +15071,9 @@  int intel_modeset_init(struct drm_device *dev)
 	drm_modeset_unlock_all(dev);
 
 	for_each_intel_crtc(dev, crtc) {
-		struct intel_initial_plane_config plane_config = {};
+		struct intel_initial_plane_config plane_config = {
+			.rotation = DRM_ROTATE_0
+		};
 
 		if (!crtc->active)
 			continue;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 11f2e41..c1dcd87 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -421,6 +421,7 @@  struct intel_initial_plane_config {
 	unsigned int tiling;
 	int size;
 	u32 base;
+	uint8_t rotation;
 };
 
 #define SKL_MIN_SRC_W 8
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 6f5aceb..19fc313 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -48,6 +48,7 @@  struct drm_fb_helper_crtc {
 	struct drm_mode_set mode_set;
 	struct drm_display_mode *desired_mode;
 	int x, y;
+	uint8_t rotation;
 };
 
 /**
@@ -159,6 +160,7 @@  struct drm_fb_helper_funcs {
 
 struct drm_fb_helper_connector {
 	struct drm_connector *connector;
+	uint8_t rotation;
 };
 
 /**
-- 
2.9.3