@@ -116,6 +116,7 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
struct intel_plane *intel_plane = to_intel_plane(plane);
const struct drm_display_mode *adjusted_mode =
&crtc_state->base.adjusted_mode;
+ unsigned int rotation = intel_plane_get_rotation(state);
int ret;
/*
@@ -135,7 +136,7 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
intel_state->clip.y2 =
crtc_state->base.enable ? crtc_state->pipe_src_h : 0;
- if (state->fb && drm_rotation_90_or_270(state->rotation)) {
+ if (state->fb && drm_rotation_90_or_270(rotation)) {
struct drm_format_name_buf format_name;
if (state->fb->modifier != I915_FORMAT_MOD_Y_TILED &&
@@ -164,8 +165,8 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
/* CHV ignores the mirror bit when the rotate bit is set :( */
if (IS_CHERRYVIEW(dev_priv) &&
- state->rotation & DRM_MODE_ROTATE_180 &&
- state->rotation & DRM_MODE_REFLECT_X) {
+ rotation & DRM_MODE_ROTATE_180 &&
+ rotation & DRM_MODE_REFLECT_X) {
DRM_DEBUG_KMS("Cannot rotate and reflect at the same time\n");
return -EINVAL;
}
@@ -2277,7 +2277,7 @@ void intel_add_fb_offsets(int *x, int *y,
{
const struct intel_framebuffer *intel_fb = to_intel_framebuffer(state->base.fb);
- unsigned int rotation = state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&state->base);
if (drm_rotation_90_or_270(rotation)) {
*x += intel_fb->rotated[plane].x;
@@ -2330,7 +2330,7 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
const struct drm_i915_private *dev_priv = to_i915(state->base.plane->dev);
const struct drm_framebuffer *fb = state->base.fb;
unsigned int cpp = fb->format->cpp[plane];
- unsigned int rotation = state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&state->base);
unsigned int pitch = intel_fb_pitch(fb, plane, rotation);
WARN_ON(new_offset > old_offset);
@@ -2434,7 +2434,7 @@ u32 intel_compute_tile_offset(int *x, int *y,
struct intel_plane *intel_plane = to_intel_plane(state->base.plane);
struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
const struct drm_framebuffer *fb = state->base.fb;
- unsigned int rotation = state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&state->base);
int pitch = intel_fb_pitch(fb, plane, rotation);
u32 alignment;
@@ -2792,6 +2792,46 @@ intel_set_plane_visible(struct intel_crtc_state *crtc_state,
}
static void
+intel_fixup_initial_subpixel_order(struct drm_connector *connector,
+ u8 initial_rotation)
+{
+ enum subpixel_order new_order;
+
+ /* We only support an initial rotation of DRM_MODE_ROTATE_180 for now */
+ if (initial_rotation != DRM_MODE_ROTATE_180)
+ return;
+
+ switch (connector->display_info.subpixel_order) {
+ case SubPixelHorizontalRGB: new_order = SubPixelHorizontalBGR; break;
+ case SubPixelHorizontalBGR: new_order = SubPixelHorizontalRGB; break;
+ case SubPixelVerticalRGB: new_order = SubPixelVerticalBGR; break;
+ case SubPixelVerticalBGR: new_order = SubPixelVerticalRGB; break;
+ default:
+ return; /* Leave none / unkown subpixel order unchanged. */
+ }
+
+ connector->display_info.subpixel_order = new_order;
+}
+
+static void
+intel_set_initial_rotation(struct intel_crtc *intel_crtc, u8 rotation)
+{
+ struct drm_crtc_state *state = intel_crtc->base.state;
+ struct drm_device *dev = intel_crtc->base.dev;
+ struct drm_connector_list_iter conn_iter;
+ struct drm_connector *conn;
+
+ intel_crtc->initial_rotation = rotation;
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(conn, &conn_iter) {
+ if (state->connector_mask & (1 << drm_connector_index(conn)))
+ intel_fixup_initial_subpixel_order(conn, rotation);
+ }
+ drm_connector_list_iter_end(&conn_iter);
+}
+
+static void
intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
struct intel_initial_plane_config *plane_config)
{
@@ -2858,9 +2898,11 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
return;
valid_fb:
+ intel_set_initial_rotation(intel_crtc, plane_config->rotation);
+
mutex_lock(&dev->struct_mutex);
intel_state->vma =
- intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
+ intel_pin_and_fence_fb_obj(fb, intel_crtc->initial_rotation);
mutex_unlock(&dev->struct_mutex);
if (IS_ERR(intel_state->vma)) {
DRM_ERROR("failed to pin boot fb on pipe %d: %li\n",
@@ -2986,7 +3028,7 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
static int skl_check_main_surface(struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->base.fb;
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
int x = plane_state->base.src.x1 >> 16;
int y = plane_state->base.src.y1 >> 16;
int w = drm_rect_width(&plane_state->base.src) >> 16;
@@ -3064,7 +3106,7 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->base.fb;
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
int max_width = skl_max_plane_width(fb, 1, rotation);
int max_height = 4096;
int x = plane_state->base.src.x1 >> 17;
@@ -3095,6 +3137,7 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
struct intel_crtc *crtc = to_intel_crtc(plane_state->base.crtc);
const struct drm_framebuffer *fb = plane_state->base.fb;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
int src_x = plane_state->base.src.x1 >> 16;
int src_y = plane_state->base.src.y1 >> 16;
int hsub = fb->format->hsub;
@@ -3117,7 +3160,7 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
return -EINVAL;
}
- if (plane_state->base.rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180)) {
+ if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180)) {
DRM_DEBUG_KMS("RC support only with 0/180 degree rotation %x\n",
plane_state->base.rotation);
return -EINVAL;
@@ -3136,7 +3179,7 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
int skl_check_plane_surface(struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->base.fb;
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
int ret;
if (!plane_state->base.visible)
@@ -3181,7 +3224,7 @@ static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
to_i915(plane_state->base.plane->dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
const struct drm_framebuffer *fb = plane_state->base.fb;
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
u32 dspcntr;
dspcntr = DISPLAY_PLANE_ENABLE | DISPPLANE_GAMMA_ENABLE;
@@ -3254,7 +3297,8 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
/* HSW/BDW do this automagically in hardware */
if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) {
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation =
+ intel_plane_get_rotation(&plane_state->base);
int src_w = drm_rect_width(&plane_state->base.src) >> 16;
int src_h = drm_rect_height(&plane_state->base.src) >> 16;
@@ -3508,7 +3552,7 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
struct drm_i915_private *dev_priv =
to_i915(plane_state->base.plane->dev);
const struct drm_framebuffer *fb = plane_state->base.fb;
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 plane_ctl;
@@ -3543,7 +3587,7 @@ static void skylake_update_primary_plane(struct intel_plane *plane,
enum plane_id plane_id = plane->id;
enum pipe pipe = plane->pipe;
u32 plane_ctl = plane_state->ctl;
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
u32 stride = skl_plane_stride(fb, 0, rotation);
u32 aux_stride = skl_plane_stride(fb, 1, rotation);
u32 surf_addr = plane_state->main.offset;
@@ -7506,6 +7550,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_MODE_ROTATE_180;
}
pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
@@ -8559,6 +8606,9 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
goto error;
}
+ if ((val & PLANE_CTL_ROTATE_MASK) == PLANE_CTL_ROTATE_180)
+ plane_config->rotation = DRM_MODE_ROTATE_180;
+
base = I915_READ(PLANE_SURF(pipe, 0)) & 0xfffff000;
plane_config->base = base;
@@ -8644,6 +8694,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_MODE_ROTATE_180;
}
pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
@@ -9349,7 +9402,7 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
/* ILK+ do this automagically */
if (HAS_GMCH_DISPLAY(dev_priv) &&
- plane_state->base.rotation & DRM_MODE_ROTATE_180)
+ intel_plane_get_rotation(&plane_state->base) & DRM_MODE_ROTATE_180)
base += (plane_state->base.crtc_h *
plane_state->base.crtc_w - 1) * fb->format->cpp[0];
@@ -9571,7 +9624,7 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
return 0;
}
- if (plane_state->base.rotation & DRM_MODE_ROTATE_180)
+ if (intel_plane_get_rotation(&plane_state->base) & DRM_MODE_ROTATE_180)
cntl |= CURSOR_ROTATE_180;
return cntl;
@@ -9604,7 +9657,7 @@ static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
* cursors.
*/
if (HAS_CUR_FBC(dev_priv) &&
- plane_state->base.rotation & DRM_MODE_ROTATE_0) {
+ intel_plane_get_rotation(&plane_state->base) & DRM_MODE_ROTATE_0) {
if (height < 8 || height > width)
return false;
} else {
@@ -12775,7 +12828,8 @@ intel_prepare_plane_fb(struct drm_plane *plane,
} else {
struct i915_vma *vma;
- vma = intel_pin_and_fence_fb_obj(fb, new_state->rotation);
+ vma = intel_pin_and_fence_fb_obj(fb,
+ intel_plane_get_rotation(new_state));
if (!IS_ERR(vma))
to_intel_plane_state(new_state)->vma = vma;
else
@@ -13155,7 +13209,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
goto out_unlock;
}
} else {
- vma = intel_pin_and_fence_fb_obj(fb, new_plane_state->rotation);
+ vma = intel_pin_and_fence_fb_obj(fb,
+ intel_plane_get_rotation(new_plane_state));
if (IS_ERR(vma)) {
DRM_DEBUG_KMS("failed to pin object\n");
@@ -14625,7 +14680,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_MODE_ROTATE_0
+ };
if (!crtc->active)
continue;
@@ -447,6 +447,7 @@ struct intel_initial_plane_config {
unsigned int tiling;
int size;
u32 base;
+ uint8_t rotation; /* DRM_MODE_ROTATE_* */
};
#define SKL_MIN_SRC_W 8
@@ -802,6 +803,12 @@ struct intel_crtc {
unsigned long long enabled_power_domains;
struct intel_overlay *overlay;
+ /*
+ * Initial DRM_MODE_ROTATE_* as read back from the hardware at init,
+ * this is used to compensate for e.g. upside-down mounted lcd-panels.
+ */
+ uint8_t initial_rotation;
+
/* Display surface base address adjustement for pageflips. Note that on
* gen4+ this only adjusts up to a tile, offsets within a tile are
* handled in the hw itself (with the TILEOFF register). */
@@ -1464,6 +1471,31 @@ static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
return i915_ggtt_offset(state->vma);
}
+static inline unsigned int
+intel_plane_get_rotation(const struct drm_plane_state *plane_state)
+{
+ unsigned int rotation = plane_state->rotation;
+ unsigned int new_rotation = DRM_MODE_ROTATE_0;
+ struct intel_crtc *intel_crtc;
+
+ if (!plane_state->crtc)
+ return rotation;
+
+ /* We only support an initial rotation of DRM_MODE_ROTATE_180 for now */
+ intel_crtc = to_intel_crtc(plane_state->crtc);
+ if (intel_crtc->initial_rotation != DRM_MODE_ROTATE_180)
+ return rotation;
+
+ switch (rotation & DRM_MODE_ROTATE_MASK) {
+ case DRM_MODE_ROTATE_0: new_rotation = DRM_MODE_ROTATE_180; break;
+ case DRM_MODE_ROTATE_90: new_rotation = DRM_MODE_ROTATE_270; break;
+ case DRM_MODE_ROTATE_180: new_rotation = DRM_MODE_ROTATE_0; break;
+ case DRM_MODE_ROTATE_270: new_rotation = DRM_MODE_ROTATE_90; break;
+ }
+
+ return (rotation & ~DRM_MODE_ROTATE_MASK) | new_rotation;
+}
+
u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
@@ -737,7 +737,7 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
cache->crtc.hsw_bdw_pixel_rate = crtc_state->pixel_rate;
- cache->plane.rotation = plane_state->base.rotation;
+ cache->plane.rotation = intel_plane_get_rotation(&plane_state->base);
/*
* Src coordinates are already rotated by 270 degrees for
* the 90/270 degree plane rotation cases (to match the
@@ -4080,6 +4080,7 @@ skl_ddb_min_alloc(const struct drm_plane_state *pstate,
{
struct drm_framebuffer *fb = pstate->fb;
struct intel_plane_state *intel_pstate = to_intel_plane_state(pstate);
+ unsigned int rotation = intel_plane_get_rotation(pstate);
uint32_t src_w, src_h;
uint32_t min_scanlines = 8;
uint8_t plane_bpp;
@@ -4117,7 +4118,7 @@ skl_ddb_min_alloc(const struct drm_plane_state *pstate,
else
plane_bpp = fb->format->cpp[0];
- if (drm_rotation_90_or_270(pstate->rotation)) {
+ if (drm_rotation_90_or_270(rotation)) {
switch (plane_bpp) {
case 1:
min_scanlines = 32;
@@ -4382,6 +4383,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
struct intel_plane *plane = to_intel_plane(intel_pstate->base.plane);
const struct drm_plane_state *pstate = &intel_pstate->base;
const struct drm_framebuffer *fb = pstate->fb;
+ unsigned int rotation = intel_plane_get_rotation(pstate);
uint32_t latency = dev_priv->wm.skl_latency[level];
uint_fixed_16_16_t method1, method2;
uint_fixed_16_16_t plane_blocks_per_line;
@@ -4434,7 +4436,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
fb->format->cpp[0];
plane_pixel_rate = skl_adjusted_plane_pixel_rate(cstate, intel_pstate);
- if (drm_rotation_90_or_270(pstate->rotation)) {
+ if (drm_rotation_90_or_270(rotation)) {
switch (cpp) {
case 1:
@@ -237,7 +237,7 @@ skl_update_plane(struct intel_plane *plane,
u32 plane_ctl = plane_state->ctl;
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 surf_addr = plane_state->main.offset;
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
u32 stride = skl_plane_stride(fb, 0, rotation);
u32 aux_stride = skl_plane_stride(fb, 1, rotation);
int crtc_x = plane_state->base.dst.x1;
@@ -367,7 +367,7 @@ static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->base.fb;
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 sprctl;
@@ -507,7 +507,7 @@ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,
struct drm_i915_private *dev_priv =
to_i915(plane_state->base.plane->dev);
const struct drm_framebuffer *fb = plane_state->base.fb;
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 sprctl;
@@ -647,7 +647,7 @@ static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state,
struct drm_i915_private *dev_priv =
to_i915(plane_state->base.plane->dev);
const struct drm_framebuffer *fb = plane_state->base.fb;
- unsigned int rotation = plane_state->base.rotation;
+ unsigned int rotation = intel_plane_get_rotation(&plane_state->base);
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 dvscntr;
@@ -780,6 +780,7 @@ intel_check_sprite_plane(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_framebuffer *fb = state->base.fb;
+ unsigned int rotation = intel_plane_get_rotation(&state->base);
int crtc_x, crtc_y;
unsigned int crtc_w, crtc_h;
uint32_t src_x, src_y, src_w, src_h;
@@ -834,8 +835,7 @@ intel_check_sprite_plane(struct intel_plane *plane,
* coordinates and sizes. We probably need some way to decide whether
* more strict checking should be done instead.
*/
- drm_rect_rotate(src, fb->width << 16, fb->height << 16,
- state->base.rotation);
+ drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation);
hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale);
BUG_ON(hscale < 0);
@@ -876,7 +876,7 @@ intel_check_sprite_plane(struct intel_plane *plane,
drm_rect_height(dst) * vscale - drm_rect_height(src));
drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16,
- state->base.rotation);
+ rotation);
/* sanity check to make sure the src viewport wasn't enlarged */
WARN_ON(src->x1 < (int) state->base.src_x ||
On some (Bay Trail) devices the LCD panel is mounted upside-down. This commit uses the code to read back the initial rotation of the primary plane in get_initial_plane_config from Ville Syrjala's "drm/fb-helper: Inherit rotation wip" patch and when re-using the initial fb it stores that in intel_crtc.initial_rotation. It adds an intel_plane_get_rotation helper which combines this initial_rotation with any rotation requested by userspace and uses this in all places which look at a planes rotation, thus transparently dealing with upside-down LCD panels without requiring any user-space or fbcon changes. This fixes 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, as well as any graphics displayed by userspace being upside-down. Note this only deals with upside-down LCD panels / 180 degrees rotation as the hardware in question only supports 180 degrees rotation in hardware. The one model known which has a panel mounted with 90/270 degrees rotation will need to be fully dealt with in userspace, even the firmware boot screen / menus are rotated 90 degrees on this one and there simply is nothing the kernel can do about this. BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=94894 Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- Changes in v2: -Fix brown paperbag bug s/val & mask/val & ~mask/ to clear old rotation bits Changes in v3: -Rebase on current (2017 aug. 22) drm-intel-next-queued Changes in v4: -Fix compiler warning from unhandled case in intel_fixup_initial_subpixel_order --- drivers/gpu/drm/i915/intel_atomic_plane.c | 7 ++- drivers/gpu/drm/i915/intel_display.c | 93 +++++++++++++++++++++++++------ drivers/gpu/drm/i915/intel_drv.h | 32 +++++++++++ drivers/gpu/drm/i915/intel_fbc.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 6 +- drivers/gpu/drm/i915/intel_sprite.c | 14 ++--- 6 files changed, 123 insertions(+), 31 deletions(-)