Commit 1afe3e9d authored by Jesse Barnes's avatar Jesse Barnes Committed by Eric Anholt

drm/i915: gen3 page flipping fixes

Gen3 chips have slightly different flip commands, and also contain a bit
that indicates whether a "flip pending" interrupt means the flip has
been queued or has been completed.

So implement support for the gen3 flip command, and make sure we use the
flip pending interrupt correctly depending on the value of ECOSKPD bit
0.
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent 83f7fd05
...@@ -1408,6 +1408,10 @@ static int i915_load_modeset_init(struct drm_device *dev, ...@@ -1408,6 +1408,10 @@ static int i915_load_modeset_init(struct drm_device *dev,
if (ret) if (ret)
goto destroy_ringbuffer; goto destroy_ringbuffer;
/* IIR "flip pending" bit means done if this bit is set */
if (IS_GEN3(dev) && (I915_READ(ECOSKPD) & ECO_FLIP_DONE))
dev_priv->flip_pending_is_done = true;
intel_modeset_init(dev); intel_modeset_init(dev);
ret = drm_irq_install(dev); ret = drm_irq_install(dev);
......
...@@ -595,6 +595,7 @@ typedef struct drm_i915_private { ...@@ -595,6 +595,7 @@ typedef struct drm_i915_private {
struct drm_crtc *plane_to_crtc_mapping[2]; struct drm_crtc *plane_to_crtc_mapping[2];
struct drm_crtc *pipe_to_crtc_mapping[2]; struct drm_crtc *pipe_to_crtc_mapping[2];
wait_queue_head_t pending_flip_queue; wait_queue_head_t pending_flip_queue;
bool flip_pending_is_done;
/* Reclocking support */ /* Reclocking support */
bool render_reclock_avail; bool render_reclock_avail;
......
...@@ -940,22 +940,30 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -940,22 +940,30 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT)) if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT))
DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
intel_prepare_page_flip(dev, 0); intel_prepare_page_flip(dev, 0);
if (dev_priv->flip_pending_is_done)
intel_finish_page_flip_plane(dev, 0);
}
if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) {
if (dev_priv->flip_pending_is_done)
intel_finish_page_flip_plane(dev, 1);
intel_prepare_page_flip(dev, 1); intel_prepare_page_flip(dev, 1);
}
if (pipea_stats & vblank_status) { if (pipea_stats & vblank_status) {
vblank++; vblank++;
drm_handle_vblank(dev, 0); drm_handle_vblank(dev, 0);
intel_finish_page_flip(dev, 0); if (!dev_priv->flip_pending_is_done)
intel_finish_page_flip(dev, 0);
} }
if (pipeb_stats & vblank_status) { if (pipeb_stats & vblank_status) {
vblank++; vblank++;
drm_handle_vblank(dev, 1); drm_handle_vblank(dev, 1);
intel_finish_page_flip(dev, 1); if (!dev_priv->flip_pending_is_done)
intel_finish_page_flip(dev, 1);
} }
if ((pipea_stats & I915_LEGACY_BLC_EVENT_STATUS) || if ((pipea_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
......
...@@ -178,6 +178,7 @@ ...@@ -178,6 +178,7 @@
#define MI_OVERLAY_OFF (0x2<<21) #define MI_OVERLAY_OFF (0x2<<21)
#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0) #define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0)
#define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) #define MI_DISPLAY_FLIP MI_INSTR(0x14, 2)
#define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1)
#define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20) #define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20)
#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1)
#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ #define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */
...@@ -368,6 +369,9 @@ ...@@ -368,6 +369,9 @@
#define CM0_RC_OP_FLUSH_DISABLE (1<<0) #define CM0_RC_OP_FLUSH_DISABLE (1<<0)
#define BB_ADDR 0x02140 /* 8 bytes */ #define BB_ADDR 0x02140 /* 8 bytes */
#define GFX_FLSH_CNTL 0x02170 /* 915+ only */ #define GFX_FLSH_CNTL 0x02170 /* 915+ only */
#define ECOSKPD 0x021d0
#define ECO_GATING_CX_ONLY (1<<3)
#define ECO_FLIP_DONE (1<<0)
/* GEN6 interrupt control */ /* GEN6 interrupt control */
#define GEN6_RENDER_HWSTAM 0x2098 #define GEN6_RENDER_HWSTAM 0x2098
......
...@@ -4603,10 +4603,10 @@ static void intel_unpin_work_fn(struct work_struct *__work) ...@@ -4603,10 +4603,10 @@ static void intel_unpin_work_fn(struct work_struct *__work)
kfree(work); kfree(work);
} }
void intel_finish_page_flip(struct drm_device *dev, int pipe) static void do_intel_finish_page_flip(struct drm_device *dev,
struct drm_crtc *crtc)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_unpin_work *work; struct intel_unpin_work *work;
struct drm_i915_gem_object *obj_priv; struct drm_i915_gem_object *obj_priv;
...@@ -4650,6 +4650,22 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) ...@@ -4650,6 +4650,22 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
schedule_work(&work->work); schedule_work(&work->work);
} }
void intel_finish_page_flip(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
do_intel_finish_page_flip(dev, crtc);
}
void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
do_intel_finish_page_flip(dev, crtc);
}
void intel_prepare_page_flip(struct drm_device *dev, int plane) void intel_prepare_page_flip(struct drm_device *dev, int plane)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
...@@ -4745,14 +4761,17 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, ...@@ -4745,14 +4761,17 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
; ;
BEGIN_LP_RING(4); BEGIN_LP_RING(4);
OUT_RING(MI_DISPLAY_FLIP |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
if (IS_I965G(dev)) { if (IS_I965G(dev)) {
OUT_RING(MI_DISPLAY_FLIP |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode); OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);
pipesrc = I915_READ(pipesrc_reg); pipesrc = I915_READ(pipesrc_reg);
OUT_RING(pipesrc & 0x0fff0fff); OUT_RING(pipesrc & 0x0fff0fff);
} else { } else {
OUT_RING(MI_DISPLAY_FLIP_I915 |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
OUT_RING(obj_priv->gtt_offset); OUT_RING(obj_priv->gtt_offset);
OUT_RING(MI_NOOP); OUT_RING(MI_NOOP);
} }
......
...@@ -224,6 +224,7 @@ extern void intel_fbdev_fini(struct drm_device *dev); ...@@ -224,6 +224,7 @@ extern void intel_fbdev_fini(struct drm_device *dev);
extern void intel_prepare_page_flip(struct drm_device *dev, int plane); extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
extern void intel_finish_page_flip(struct drm_device *dev, int pipe); extern void intel_finish_page_flip(struct drm_device *dev, int pipe);
extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
extern void intel_setup_overlay(struct drm_device *dev); extern void intel_setup_overlay(struct drm_device *dev);
extern void intel_cleanup_overlay(struct drm_device *dev); extern void intel_cleanup_overlay(struct drm_device *dev);
......
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