diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index ad6e129..e31d66d 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -642,8 +642,8 @@ int i915_dispatch_batchbuffer(struct drm_device * dev, static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) { drm_i915_private_t *dev_priv = dev->dev_private; - u32 num_pages, current_page, next_page, dspbase; - int shift = 2 * plane, x, y; + u32 num_pages, current_page, next_page, base, offset; + int shift = 2 * plane, x, y, pipe = i915_get_pipe(dev, plane); RING_LOCALS; /* Calculate display base offset */ @@ -654,13 +654,13 @@ static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) switch (next_page) { default: case 0: - dspbase = dev_priv->sarea_priv->front_offset; + base = dev_priv->sarea_priv->front_offset; break; case 1: - dspbase = dev_priv->sarea_priv->back_offset; + base = dev_priv->sarea_priv->back_offset; break; case 2: - dspbase = dev_priv->sarea_priv->third_offset; + base = dev_priv->sarea_priv->third_offset; break; } @@ -672,20 +672,37 @@ static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) y = dev_priv->sarea_priv->planeB_y; } - dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; + offset = (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; - DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page, - dspbase); + DRM_ERROR("plane=%d current_page=%d dspbase=0x%x sync=%d\n", plane, + current_page, base + offset, sync); - BEGIN_LP_RING(4); - OUT_RING(sync ? 0 : - (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP : - MI_WAIT_FOR_PLANE_A_FLIP))); - OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) | - (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); - OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); - OUT_RING(dspbase); - ADVANCE_LP_RING(); + if (IS_I965G(dev)) { + BEGIN_LP_RING(6); + if (sync) + OUT_RING(MI_WAIT_FOR_EVENT | + (pipe ? MI_WAIT_FOR_PIPE_B_VBLANK : + MI_WAIT_FOR_PIPE_A_VBLANK)); + else + OUT_RING(MI_NOOP); + OUT_RING(MI_DISPLAY_FLIP | (sync ? 0 : DISPLAY_FLIP_ASYNC) | + (plane ? DISPLAY_FLIP_PLANE_B : 0)); + OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); + OUT_RING((base + offset) | DISPLAY_FLIP_TILED); + OUT_RING(x << DISPLAY_FLIP_HSIZE_SHIFT | y); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(4); + OUT_RING(sync ? 0 : + (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP : + MI_WAIT_FOR_PLANE_A_FLIP))); + OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) | + (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); + OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); + OUT_RING(base + offset); + ADVANCE_LP_RING(); + } dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); dev_priv->sarea_priv->pf_current_page |= next_page << shift; @@ -696,14 +713,15 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) drm_i915_private_t *dev_priv = dev->dev_private; int i; - DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n", + DRM_ERROR("planes=0x%x pfCurrentPage=%d\n", planes, dev_priv->sarea_priv->pf_current_page); i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); for (i = 0; i < 2; i++) - if (planes & (1 << i)) + if (planes & (1 << i)) { i915_do_dispatch_flip(dev, i, sync); + } i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 421572c..41354ec 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -302,6 +302,7 @@ extern int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int i915_get_pipe(struct drm_device *dev, int plane); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(struct drm_device * dev); @@ -510,7 +511,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define MI_NOOP MI_INSTR(0, 0) #define MI_USER_INTERRUPT MI_INSTR(0x02, 0) #define MI_WAIT_FOR_EVENT MI_INSTR(0x03, 0) +#define MI_WAIT_FOR_PIPE_B_VBLANK (1<<7) #define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) +#define MI_WAIT_FOR_PIPE_A_VBLANK (1<<3) #define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) #define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) #define MI_FLUSH MI_INSTR(0x04, 0) @@ -521,6 +524,15 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ #define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) #define MI_REPORT_HEAD MI_INSTR(0x07, 0) +#define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) +#define DISPLAY_FLIP_ASYNC (1<<22) +#define DISPLAY_FLIP_PLANE_B (1<<20) +#define DISPLAY_FLIP_PITCH_SHIFT (3) +#define DISPLAY_FLIP_BASE_SHIFT (12) +#define DISPLAY_FLIP_TILED (1) +#define DISPLAY_FLIP_PFIT (1<<31) +#define DISPLAY_FLIP_PFIT_3X3 (1<<30) +#define DISPLAY_FLIP_HSIZE_SHIFT (16) #define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0) #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) #define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index b95d0f1..43bdca3 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -42,7 +42,7 @@ * rather than a pipe number, since they may not always be equal. This routine * maps the given @plane back to a pipe number. */ -static int +int i915_get_pipe(struct drm_device *dev, int plane) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -614,10 +614,10 @@ int i915_enable_vblank(struct drm_device *dev, int plane) * Older chips didn't have the start vblank interrupt, * but */ + pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE; if (IS_I965G (dev)) pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE; - else - pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE; + /* * Clear any pending status */ @@ -812,6 +812,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data, return -EINVAL; } + DRM_ERROR("dispatch flip on plane %d\n", plane); + i915_dispatch_vsync_flip(dev, drw, plane); DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags);