From: Ville Syrjala <ville.syrjala@xxxxxxxxxxxxxxx> If a connector added through drm_fb_helper_add_one_connector() has a crtc attached and that crtc has a rotation configured make the fbdev inherit the crtc's rotation. This is useful on e.g. some tablets which have their lcd panel mounted upside down, which before this commit would result in the kernel boot messages switching from being shown the right way up in efifb to being shown upside down as soon as a native kms driver loads. BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=94894 Cc: Ville Syrjala <ville.syrjala@xxxxxxxxxxxxxxx> [hdegoede@xxxxxxxxxx: Split the drm/fb-helper bits out of Ville's "drm/fb-helper: Inherit rotation wip" patch] Tested-by: Hans de Goede <hdegoede@xxxxxxxxxx> Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> --- drivers/gpu/drm/drm_fb_helper.c | 51 ++++++++++++++++++++++++++++++++++++++--- include/drm/drm_fb_helper.h | 2 ++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 324a688..c97e00ab 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); @@ -414,8 +450,8 @@ 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); + plane->rotation_property, + 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,8 @@ 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/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 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx