Skip to content

Commit

Permalink
drm/i915: Fix offset page-flips on i965+
Browse files Browse the repository at this point in the history
i965 uses the Display Registers to compute the offset from the display
base so the new base does not need adjusting when flipping. The older
chipsets use a fence to access the display and so do perceive the
surface as linear and have a single base register which is reprogrammed
using the flip.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Reported-by: Marty Jack <martyj19@comcast.net>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
  • Loading branch information
Chris Wilson committed Sep 7, 2010
1 parent c96c3a8 commit 52e6863
Showing 1 changed file with 48 additions and 19 deletions.
67 changes: 48 additions & 19 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -5042,9 +5042,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_unpin_work *work;
unsigned long flags, offset;
int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC;
int ret, pipesrc;
u32 flip_mask;
int pipe = intel_crtc->pipe;
u32 pf, pipesrc;
int ret;

work = kzalloc(sizeof *work, GFP_KERNEL);
if (work == NULL)
Expand Down Expand Up @@ -5093,42 +5093,71 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
atomic_inc(&obj_priv->pending_flip);
work->pending_flip_obj = obj;

if (intel_crtc->plane)
flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
else
flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;

if (IS_GEN3(dev) || IS_GEN2(dev)) {
u32 flip_mask;

if (intel_crtc->plane)
flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
else
flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;

BEGIN_LP_RING(2);
OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
OUT_RING(0);
ADVANCE_LP_RING();
}

/* Offset into the new buffer for cases of shared fbs between CRTCs */
offset = obj_priv->gtt_offset;
offset += (crtc->y * fb->pitch) + (crtc->x * (fb->bits_per_pixel) / 8);
offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8;

BEGIN_LP_RING(4);
if (IS_I965G(dev)) {
switch(INTEL_INFO(dev)->gen) {
case 2:
OUT_RING(MI_DISPLAY_FLIP |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
OUT_RING(offset | obj_priv->tiling_mode);
pipesrc = I915_READ(pipesrc_reg);
OUT_RING(pipesrc & 0x0fff0fff);
} else if (IS_GEN3(dev)) {
OUT_RING(obj_priv->gtt_offset + offset);
OUT_RING(MI_NOOP);
break;

case 3:
OUT_RING(MI_DISPLAY_FLIP_I915 |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
OUT_RING(offset);
OUT_RING(obj_priv->gtt_offset + offset);
OUT_RING(MI_NOOP);
} else {
break;

case 4:
case 5:
/* i965+ uses the linear or tiled offsets from the
* Display Registers (which do not change across a page-flip)
* so we need only reprogram the base address.
*/
OUT_RING(MI_DISPLAY_FLIP |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
OUT_RING(offset);
OUT_RING(MI_NOOP);
OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);

/* XXX Enabling the panel-fitter across page-flip is so far
* untested on non-native modes, so ignore it for now.
* pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
*/
pf = 0;
pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff;
OUT_RING(pf | pipesrc);
break;

case 6:
OUT_RING(MI_DISPLAY_FLIP |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch | obj_priv->tiling_mode);
OUT_RING(obj_priv->gtt_offset);

pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff;
OUT_RING(pf | pipesrc);
break;
}
ADVANCE_LP_RING();

Expand Down

0 comments on commit 52e6863

Please sign in to comment.