diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 3f4fd1b..b4d6505 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_DEBUG("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)) { + i915_enable_vblank(dev, plane); + 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); + } 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; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 32e90d2..d61b6d4 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -276,6 +276,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); @@ -440,6 +441,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) #define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) +#define MI_NOOP 0 + #define CMD_MI_FLUSH (0x04 << 23) #define MI_NO_WRITE_FLUSH (1 << 2) #define MI_READ_FLUSH (1 << 0) @@ -758,7 +761,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define MI_BATCH_NON_SECURE_I965 (1<<8) #define MI_WAIT_FOR_EVENT ((0x3<<23)) +#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) @@ -769,6 +774,16 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define DISPLAY_PLANE_A (0<<20) #define DISPLAY_PLANE_B (1<<20) +#define MI_DISPLAY_FLIP ((0x0<<29)|(0x14<<23)|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) + /* Display regs */ #define DSPACNTR 0x70180 #define DSPBCNTR 0x71180 diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 2287cd0..4f6d50d 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; @@ -425,13 +425,6 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) if (i915_in_vblank(dev, pipe)) count++; #endif - /* count may be reset by other driver(e.g. 2D driver), - we have no way to know if it is wrapped or resetted - when count is zero. do a rough guess. - */ - if (count == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2) - dev->last_vblank[pipe] = 0; - return count; } @@ -642,10 +635,9 @@ int i915_enable_vblank(struct drm_device *dev, int plane) * Older chips didn't have the start vblank interrupt, * but */ + pipestat |= I915_VBLANK_INTERRUPT_ENABLE; if (IS_I965G (dev)) pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE; - else - pipestat |= I915_VBLANK_INTERRUPT_ENABLE; /* * Clear any pending status */ @@ -841,6 +833,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data, return -EINVAL; } + DRM_DEBUG("dispatch flip on plane %d\n", plane); + i915_dispatch_vsync_flip(dev, drw, plane); DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags);