Commit 8f0cb418 authored by Hans de Goede's avatar Hans de Goede Committed by Hans de Goede

drm/fb-helper: Apply panel orientation connector prop to the primary plane, v6.

Apply the "panel orientation" drm connector prop to the primary plane so
that fbcon and fbdev using userspace programs display the right way up.

Changes in v3:
-Use a rotation member in struct drm_fb_helper_crtc and set that from
 drm_setup_crtcs instead of looping over all crtc's to find the right one
 later
-Since we now no longer look at rotation quirks directly in the fbcon
 code, set fb_info.fbcon_rotate_hint when the panel is not mounted upright
 and we cannot use hardware rotation

Changes in v4:
-Make drm_fb_helper_init() init drm_fb_helper_crtc.rotation to
 DRM_MODE_ROTATE_0 for all crtcs, so that we do not end up setting the
 plane_state's rotation to an invalid value for disabled crtcs
 (caught by Fi.CI)

Changes in v5:
-Only use hardware (crtc primary plane) rotation for DRM_ROTATE_180,
 90 / 270 degree rotation requires special handling which we lack atm
-Add a TODO comment for 90 / 270 degree hardware rotation
-Add some comments to better document the default case when mapping
 sw_rotations to fbcon_rotate_hints

Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=94894Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171125193553.23986-5-hdegoede@redhat.com
parent 8d70f395
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include "drm_crtc_internal.h"
#include "drm_crtc_helper_internal.h" #include "drm_crtc_helper_internal.h"
static bool drm_fbdev_emulation = true; static bool drm_fbdev_emulation = true;
...@@ -356,6 +357,7 @@ EXPORT_SYMBOL(drm_fb_helper_debug_leave); ...@@ -356,6 +357,7 @@ EXPORT_SYMBOL(drm_fb_helper_debug_leave);
static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active) static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
{ {
struct drm_device *dev = fb_helper->dev; struct drm_device *dev = fb_helper->dev;
struct drm_plane_state *plane_state;
struct drm_plane *plane; struct drm_plane *plane;
struct drm_atomic_state *state; struct drm_atomic_state *state;
int i, ret; int i, ret;
...@@ -374,8 +376,6 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ ...@@ -374,8 +376,6 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
retry: retry:
plane_mask = 0; plane_mask = 0;
drm_for_each_plane(plane, dev) { drm_for_each_plane(plane, dev) {
struct drm_plane_state *plane_state;
plane_state = drm_atomic_get_plane_state(state, plane); plane_state = drm_atomic_get_plane_state(state, plane);
if (IS_ERR(plane_state)) { if (IS_ERR(plane_state)) {
ret = PTR_ERR(plane_state); ret = PTR_ERR(plane_state);
...@@ -398,6 +398,11 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ ...@@ -398,6 +398,11 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
for (i = 0; i < fb_helper->crtc_count; i++) { for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
struct drm_plane *primary = mode_set->crtc->primary;
/* 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;
ret = __drm_atomic_helper_set_config(mode_set, state); ret = __drm_atomic_helper_set_config(mode_set, state);
if (ret != 0) if (ret != 0)
...@@ -829,6 +834,7 @@ int drm_fb_helper_init(struct drm_device *dev, ...@@ -829,6 +834,7 @@ int drm_fb_helper_init(struct drm_device *dev,
if (!fb_helper->crtc_info[i].mode_set.connectors) if (!fb_helper->crtc_info[i].mode_set.connectors)
goto out_free; goto out_free;
fb_helper->crtc_info[i].mode_set.num_connectors = 0; fb_helper->crtc_info[i].mode_set.num_connectors = 0;
fb_helper->crtc_info[i].rotation = DRM_MODE_ROTATE_0;
} }
i = 0; i = 0;
...@@ -2357,6 +2363,62 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, ...@@ -2357,6 +2363,62 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
return best_score; 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, its 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, static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
u32 width, u32 height) u32 width, u32 height)
{ {
...@@ -2416,6 +2478,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, ...@@ -2416,6 +2478,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
drm_fb_helper_modeset_release(fb_helper, drm_fb_helper_modeset_release(fb_helper,
&fb_helper->crtc_info[i].mode_set); &fb_helper->crtc_info[i].mode_set);
fb_helper->sw_rotations = 0;
drm_fb_helper_for_each_connector(fb_helper, i) { drm_fb_helper_for_each_connector(fb_helper, i) {
struct drm_display_mode *mode = modes[i]; struct drm_display_mode *mode = modes[i];
struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
...@@ -2435,6 +2498,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, ...@@ -2435,6 +2498,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
modeset->mode = drm_mode_duplicate(dev, modeset->mode = drm_mode_duplicate(dev,
fb_crtc->desired_mode); fb_crtc->desired_mode);
drm_connector_get(connector); drm_connector_get(connector);
drm_setup_crtc_rotation(fb_helper, fb_crtc, connector);
modeset->connectors[modeset->num_connectors++] = connector; modeset->connectors[modeset->num_connectors++] = connector;
modeset->x = offset->x; modeset->x = offset->x;
modeset->y = offset->y; modeset->y = offset->y;
...@@ -2476,6 +2540,28 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper) ...@@ -2476,6 +2540,28 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
} }
} }
mutex_unlock(&fb_helper->dev->mode_config.mutex); mutex_unlock(&fb_helper->dev->mode_config.mutex);
switch (fb_helper->sw_rotations) {
case DRM_MODE_ROTATE_0:
info->fbcon_rotate_hint = FB_ROTATE_UR;
break;
case DRM_MODE_ROTATE_90:
info->fbcon_rotate_hint = FB_ROTATE_CCW;
break;
case DRM_MODE_ROTATE_180:
info->fbcon_rotate_hint = FB_ROTATE_UD;
break;
case DRM_MODE_ROTATE_270:
info->fbcon_rotate_hint = FB_ROTATE_CW;
break;
default:
/*
* Multiple bits are set / multiple rotations requested
* fbcon cannot handle separate rotation settings per
* output, so fallback to unrotated.
*/
info->fbcon_rotate_hint = FB_ROTATE_UR;
}
} }
/* Note: Drops fb_helper->lock before returning. */ /* Note: Drops fb_helper->lock before returning. */
......
...@@ -48,6 +48,7 @@ struct drm_fb_helper_crtc { ...@@ -48,6 +48,7 @@ struct drm_fb_helper_crtc {
struct drm_mode_set mode_set; struct drm_mode_set mode_set;
struct drm_display_mode *desired_mode; struct drm_display_mode *desired_mode;
int x, y; int x, y;
int rotation;
}; };
/** /**
...@@ -158,6 +159,13 @@ struct drm_fb_helper { ...@@ -158,6 +159,13 @@ struct drm_fb_helper {
struct drm_fb_helper_crtc *crtc_info; struct drm_fb_helper_crtc *crtc_info;
int connector_count; int connector_count;
int connector_info_alloc_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: * @connector_info:
* *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment