drm/i915: Don't change the blank/sync width when calculating scaled modes
Also, use the border instead of border minus one.
At the same time, make sure the horizontal border and hsync are even for
the LVDS that works in dual-channel mode. So both horizontal border and hsync
start are also changed to be even, even for the LVDS in single-channel mode.
https://bugs.freedesktop.org/show_bug.cgi?id=20951
Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index f416ead..9564ca4 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -246,6 +246,9 @@
bool border = 0;
int panel_ratio, desired_ratio, vert_scale, horiz_scale;
int horiz_ratio, vert_ratio;
+ u32 hsync_width, vsync_width;
+ u32 hblank_width, vblank_width;
+ u32 hsync_pos, vsync_pos;
/* Should never happen!! */
if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
@@ -306,6 +309,14 @@
pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) |
PFIT_FILTER_FUZZY;
+ hsync_width = adjusted_mode->crtc_hsync_end -
+ adjusted_mode->crtc_hsync_start;
+ vsync_width = adjusted_mode->crtc_vsync_end -
+ adjusted_mode->crtc_vsync_start;
+ hblank_width = adjusted_mode->crtc_hblank_end -
+ adjusted_mode->crtc_hblank_start;
+ vblank_width = adjusted_mode->crtc_vblank_end -
+ adjusted_mode->crtc_vblank_start;
/*
* Deal with panel fitting options. Figure out how to stretch the
* image based on its aspect ratio & the current panel fitting mode.
@@ -339,23 +350,39 @@
bottom_border++;
/* Set active & border values */
adjusted_mode->crtc_hdisplay = mode->hdisplay;
+ /* Keep the boder be even */
+ if (right_border & 1)
+ right_border++;
+ /* use the border directly instead of border minuse one */
adjusted_mode->crtc_hblank_start = mode->hdisplay +
- right_border - 1;
- adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_htotal -
- left_border - 1;
+ right_border;
+ /* keep the blank width constant */
+ adjusted_mode->crtc_hblank_end =
+ adjusted_mode->crtc_hblank_start + hblank_width;
+ /* get the hsync pos relative to hblank start */
+ hsync_pos = (hblank_width - hsync_width) / 2;
+ /* keep the hsync pos be even */
+ if (hsync_pos & 1)
+ hsync_pos++;
adjusted_mode->crtc_hsync_start =
- adjusted_mode->crtc_hblank_start;
+ adjusted_mode->crtc_hblank_start + hsync_pos;
+ /* keep the hsync width constant */
adjusted_mode->crtc_hsync_end =
- adjusted_mode->crtc_hblank_end;
+ adjusted_mode->crtc_hsync_start + hsync_width;
adjusted_mode->crtc_vdisplay = mode->vdisplay;
+ /* use the border instead of border minus one */
adjusted_mode->crtc_vblank_start = mode->vdisplay +
- bottom_border - 1;
- adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vtotal -
- top_border - 1;
+ bottom_border;
+ /* keep the vblank width constant */
+ adjusted_mode->crtc_vblank_end =
+ adjusted_mode->crtc_vblank_start + vblank_width;
+ /* get the vsync start postion relative to vblank start */
+ vsync_pos = (vblank_width - vsync_width) / 2;
adjusted_mode->crtc_vsync_start =
- adjusted_mode->crtc_vblank_start;
+ adjusted_mode->crtc_vblank_start + vsync_pos;
+ /* keep the vsync width constant */
adjusted_mode->crtc_vsync_end =
- adjusted_mode->crtc_vblank_end;
+ adjusted_mode->crtc_vblank_start + vsync_width;
border = 1;
break;
case DRM_MODE_SCALE_ASPECT:
@@ -400,15 +427,32 @@
right_border = left_border;
if (mode->hdisplay & 1) /* odd resolutions */
right_border++;
+ /* keep the border be even */
+ if (right_border & 1)
+ right_border++;
adjusted_mode->crtc_hdisplay = scaled_width;
+ /* use border instead of border minus one */
adjusted_mode->crtc_hblank_start =
- scaled_width + right_border - 1;
+ scaled_width + right_border;
+ /* keep the hblank width constant */
adjusted_mode->crtc_hblank_end =
- adjusted_mode->crtc_htotal - left_border - 1;
+ adjusted_mode->crtc_hblank_start +
+ hblank_width;
+ /*
+ * get the hsync start pos relative to
+ * hblank start
+ */
+ hsync_pos = (hblank_width - hsync_width) / 2;
+ /* keep the hsync_pos be even */
+ if (hsync_pos & 1)
+ hsync_pos++;
adjusted_mode->crtc_hsync_start =
- adjusted_mode->crtc_hblank_start;
+ adjusted_mode->crtc_hblank_start +
+ hsync_pos;
+ /* keept hsync width constant */
adjusted_mode->crtc_hsync_end =
- adjusted_mode->crtc_hblank_end;
+ adjusted_mode->crtc_hsync_start +
+ hsync_width;
border = 1;
} else if (panel_ratio < desired_ratio) { /* letter */
u32 scaled_height = mode->vdisplay *
@@ -424,14 +468,25 @@
if (mode->vdisplay & 1)
bottom_border++;
adjusted_mode->crtc_vdisplay = scaled_height;
+ /* use border instead of border minus one */
adjusted_mode->crtc_vblank_start =
- scaled_height + bottom_border - 1;
+ scaled_height + bottom_border;
+ /* keep the vblank width constant */
adjusted_mode->crtc_vblank_end =
- adjusted_mode->crtc_vtotal - top_border - 1;
+ adjusted_mode->crtc_vblank_start +
+ vblank_width;
+ /*
+ * get the vsync start pos relative to
+ * vblank start
+ */
+ vsync_pos = (vblank_width - vsync_width) / 2;
adjusted_mode->crtc_vsync_start =
- adjusted_mode->crtc_vblank_start;
+ adjusted_mode->crtc_vblank_start +
+ vsync_pos;
+ /* keep the vsync width constant */
adjusted_mode->crtc_vsync_end =
- adjusted_mode->crtc_vblank_end;
+ adjusted_mode->crtc_vsync_start +
+ vsync_width;
border = 1;
} else {
/* Aspects match, Let hw scale both directions */