From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> Use the drm_flip helper to implement atomic page flipping. Work in progress. Ignore the huge mess in intel_sprite.c for now. --- drivers/gpu/drm/i915/i915_drv.h | 4 + drivers/gpu/drm/i915/i915_irq.c | 10 +- drivers/gpu/drm/i915/intel_atomic.c | 449 +++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_display.c | 171 +++++++++---- drivers/gpu/drm/i915/intel_drv.h | 29 +++ drivers/gpu/drm/i915/intel_sprite.c | 386 ++++++++++++++++++----------- 6 files changed, 841 insertions(+), 208 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 57e4894..e29994f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -41,6 +41,8 @@ #include <linux/intel-iommu.h> #include <linux/kref.h> +#include "drm_flip.h" + /* General customization: */ @@ -845,6 +847,8 @@ typedef struct drm_i915_private { struct work_struct parity_error_work; bool hw_contexts_disabled; uint32_t hw_context_size; + + struct drm_flip_driver flip_driver; } drm_i915_private_t; /* Iterate over initialised rings */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 23f2ea0..78ff3e0 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -37,6 +37,8 @@ #include "i915_trace.h" #include "intel_drv.h" +void intel_handle_vblank(struct drm_device *dev, int pipe); + /* For display hotplug interrupt */ static void ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) @@ -548,7 +550,7 @@ static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS) for_each_pipe(pipe) { if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS) - drm_handle_vblank(dev, pipe); + intel_handle_vblank(dev, pipe); if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) { intel_prepare_page_flip(dev, pipe); @@ -686,7 +688,7 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) intel_finish_page_flip_plane(dev, i); } if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i))) - drm_handle_vblank(dev, i); + intel_handle_vblank(dev, i); } /* check event from PCH */ @@ -779,10 +781,10 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) } if (de_iir & DE_PIPEA_VBLANK) - drm_handle_vblank(dev, 0); + intel_handle_vblank(dev, 0); if (de_iir & DE_PIPEB_VBLANK) - drm_handle_vblank(dev, 1); + intel_handle_vblank(dev, 1); /* check event from PCH */ if (de_iir & DE_PCH_EVENT) { diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 0a96d15..6d8d7d3 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -3,6 +3,7 @@ #include <drm/drmP.h> #include <drm/drm_crtc.h> +#include <drm/drm_flip.h> #include "intel_drv.h" @@ -1309,6 +1310,46 @@ static void update_props(const struct drm_device *dev, } } +static int atomic_pipe_commit(struct drm_device *dev, + struct intel_atomic_state *state, + int pipe); + +static int try_atomic_commit(struct drm_device *dev, struct intel_atomic_state *s) +{ + int ret; + int i; + u32 pipes = 0; + + for (i = 0; i < dev->mode_config.num_crtc; i++) { + struct intel_crtc_state *st = &s->crtc[i]; + + if (st->mode_dirty) + return -EAGAIN; + + if (st->fb_dirty) + pipes |= 1 << to_intel_crtc(st->crtc)->pipe; + } + + for (i = 0; i < dev->mode_config.num_plane; i++) { + struct intel_plane_state *st = &s->plane[i]; + + if (st->dirty) + pipes |= 1 << to_intel_plane(st->plane)->pipe; + } + + if (hweight32(pipes) != 1) + return -EAGAIN; + + ret = atomic_pipe_commit(dev, s, ffs(pipes) - 1); + if (ret) + return ret; + + /* don't restore the old state in end() */ + s->dirty = false; + + return 0; +} + static int intel_atomic_commit(struct drm_device *dev, void *state) { struct intel_atomic_state *s = state; @@ -1325,17 +1366,23 @@ static int intel_atomic_commit(struct drm_device *dev, void *state) if (ret) return ret; - ret = apply_config(dev, s); + /* try to apply asynchronously and atomically */ + ret = try_atomic_commit(dev, s); + + /* fall back to sync/non-atomic */ if (ret) { - unpin_fbs(dev, s); - unpin_cursors(dev, s); - s->restore_hw = true; - return ret; - } + ret = apply_config(dev, s); + if (ret) { + unpin_fbs(dev, s); + unpin_cursors(dev, s); + s->restore_hw = true; + return ret; + } - unpin_old_fbs(dev, s); + unpin_old_fbs(dev, s); - unpin_old_cursors(dev, s); + unpin_old_cursors(dev, s); + } update_plane_obj(dev, s); @@ -1390,6 +1437,9 @@ static struct { { &prop_cursor_y, "CURSOR_Y", INT_MIN, INT_MAX }, }; +static void intel_flip_init(struct drm_device *dev); +static void intel_flip_fini(struct drm_device *dev); + int intel_atomic_init(struct drm_device *dev) { struct drm_crtc *crtc; @@ -1452,6 +1502,8 @@ int intel_atomic_init(struct drm_device *dev) unpin_workqueue = create_workqueue("i915_fb_unpin"); + intel_flip_init(dev); + return 0; out: @@ -1465,6 +1517,8 @@ void intel_atomic_fini(struct drm_device *dev) { struct drm_crtc *crtc; + intel_flip_fini(dev); + destroy_workqueue(unpin_workqueue); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) @@ -1485,3 +1539,382 @@ void intel_atomic_fini(struct drm_device *dev) drm_property_destroy(dev, prop_src_y); drm_property_destroy(dev, prop_src_x); } + +void intel_plane_calc(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y); +void intel_plane_prepare(struct drm_crtc *crtc); +void intel_plane_commit(struct drm_crtc *crtc); +void intel_sprite_calc(struct drm_plane *plane, struct drm_framebuffer *fb, const struct intel_plane_coords *coords); +void intel_sprite_prepare(struct drm_plane *plane); +void intel_sprite_commit(struct drm_plane *plane); + +enum { + /* somwehat arbitrary value */ + INTEL_VBL_CNT_TIMEOUT = 5, +}; + +struct intel_flip +{ + struct drm_flip base; + u32 vbl_count; + bool vblank_ref; + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_i915_gem_object *old_bo; +}; + +static void intel_flip_complete(struct drm_flip *flip) +{ + struct intel_flip *intel_flip = + container_of(flip, struct intel_flip, base); + struct drm_device *dev = intel_flip->crtc->dev; + int pipe = to_intel_crtc(intel_flip->crtc)->pipe; + + // send flip event + + if (intel_flip->vblank_ref) + drm_vblank_put(dev, pipe); + + // allow GPU to render to old_obj +} + +static void intel_flip_finish(struct drm_flip *flip) +{ + struct intel_flip *intel_flip = + container_of(flip, struct intel_flip, base); + struct drm_device *dev = intel_flip->crtc->dev; + + if (intel_flip->old_bo) { + mutex_lock(&dev->struct_mutex); + + intel_finish_fb(intel_flip->old_bo); + intel_unpin_fb_obj(intel_flip->old_bo); + + mutex_unlock(&dev->struct_mutex); + } + +} + +static void intel_flip_cleanup(struct drm_flip *flip) +{ + struct intel_flip *intel_flip = + container_of(flip, struct intel_flip, base); + + kfree(intel_flip); +} + +static void intel_flip_driver_flush(struct drm_flip_driver *driver) +{ + struct drm_i915_private *dev_priv = + container_of(driver, struct drm_i915_private, flip_driver); + + /* Flush posted writes */ + I915_READ(PIPESTAT(PIPE_A)); +} + +static u32 get_vbl_count(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + int pipe = intel_crtc->pipe; + u32 high, low1, low2, dsl; + unsigned int timeout = 0; + + /* + * FIXME check where the frame counter increments, and if + * it happens in the middle of some line, take appropriate + * measures to get a sensible reading. + */ + + /* All reads must be satisfied during the same frame */ + do { + low1 = I915_READ(PIPEFRAMEPIXEL(pipe)) >> PIPE_FRAME_LOW_SHIFT; + high = I915_READ(PIPEFRAME(pipe)) << 8; + dsl = I915_READ(PIPEDSL(pipe)); + low2 = I915_READ(PIPEFRAMEPIXEL(pipe)) >> PIPE_FRAME_LOW_SHIFT; + } while (low1 != low2 && timeout++ < INTEL_VBL_CNT_TIMEOUT); + + if (timeout >= INTEL_VBL_CNT_TIMEOUT) + dev_warn(crtc->dev->dev, + "Timed out while determining VBL count for pipe %d\n", + intel_crtc->pipe); + + return ((high | low2) + + ((dsl >= crtc->hwmode.crtc_vdisplay) && + (dsl < crtc->hwmode.crtc_vtotal - 1))) & 0xffffff; +} + +static unsigned int usecs_to_scanlines(struct drm_crtc *crtc, + unsigned int usecs) +{ + /* paranoia */ + if (!crtc->hwmode.crtc_htotal) + return 1; + + return DIV_ROUND_UP(usecs * crtc->hwmode.clock, + 1000 * crtc->hwmode.crtc_htotal); +} + +static void intel_pipe_vblank_evade(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + /* FIXME needs to be calibrated sensibly */ + u32 min = crtc->hwmode.crtc_vdisplay - usecs_to_scanlines(crtc, 60); + u32 max = crtc->hwmode.crtc_vdisplay - 1; + long timeout = msecs_to_jiffies(1); + u32 val; + + bool vblank_ref = drm_vblank_get(dev, pipe) == 0; + + intel_crtc->vbl_received = false; + + val = I915_READ(PIPEDSL(pipe)); + + while (val >= min && val <= max && timeout > 0) { + local_irq_enable(); + + timeout = wait_event_timeout(intel_crtc->vbl_wait, + intel_crtc->vbl_received, + timeout); + + local_irq_disable(); + + intel_crtc->vbl_received = false; + + val = I915_READ(PIPEDSL(pipe)); + } + + if (vblank_ref) + drm_vblank_put(dev, pipe); + + if (val >= min && val <= max) + dev_warn(dev->dev, + "Page flipping close to vblank start (DSL=%u, VBL=%u)\n", + val, crtc->hwmode.crtc_vdisplay); +} + +static bool vbl_count_after_eq(u32 a, u32 b) +{ + return !((a - b) & 0x800000); +} + +static bool intel_vbl_check(struct drm_flip *pending_flip, u32 vbl_count) +{ + struct intel_flip *old_intel_flip = + container_of(pending_flip, struct intel_flip, base); + + return vbl_count_after_eq(vbl_count, old_intel_flip->vbl_count); +} + +static void intel_flip_prepare(struct drm_flip *flip) +{ + struct intel_flip *intel_flip = + container_of(flip, struct intel_flip, base); + + /* FIXME some other pipe/pf stuff could be performed here as well. */ + + /* stage double buffer updates which need arming by something else */ + if (intel_flip->plane) + intel_sprite_prepare(intel_flip->plane); + else + intel_plane_prepare(intel_flip->crtc); +} + +static bool intel_flip_flip(struct drm_flip *flip, + struct drm_flip *pending_flip) +{ + struct intel_flip *intel_flip = container_of(flip, struct intel_flip, base); + struct drm_crtc *crtc = intel_flip->crtc; + struct drm_device *dev = crtc->dev; + int pipe = to_intel_crtc(crtc)->pipe; + u32 vbl_count; + + struct intel_flip *old_intel_flip = NULL; + if (pending_flip) + old_intel_flip = container_of(pending_flip, struct intel_flip, base); + + intel_flip->vblank_ref = drm_vblank_get(dev, pipe) == 0; + + vbl_count = get_vbl_count(crtc); + + /* arm all the double buffer registers */ + if (intel_flip->plane) + intel_sprite_commit(intel_flip->plane); + else + intel_plane_commit(crtc); + + /* This flip will happen on the next vblank */ + intel_flip->vbl_count = (vbl_count + 1) & 0xffffff; + + /* FIXME oops in unpin when swapping old bos */ +#if 0 + if (pending_flip) { + struct intel_flip *old_intel_flip = + container_of(pending_flip, struct intel_flip, base); + bool flipped = intel_vbl_check(pending_flip, vbl_count); + + if (!flipped) + swap(intel_flip->old_bo, old_intel_flip->old_bo); + + return flipped; + } +#endif + + return false; +} + +static bool intel_flip_vblank(struct drm_flip *pending_flip) +{ + struct intel_flip *old_intel_flip = + container_of(pending_flip, struct intel_flip, base); + + u32 vbl_count = get_vbl_count(old_intel_flip->crtc); + + return intel_vbl_check(pending_flip, vbl_count); +} + +static const struct drm_flip_helper_funcs intel_flip_funcs = { + .prepare = intel_flip_prepare, + .flip = intel_flip_flip, + .vblank = intel_flip_vblank, + .complete = intel_flip_complete, + .finish = intel_flip_finish, + .cleanup = intel_flip_cleanup, +}; + +static const struct drm_flip_driver_funcs intel_flip_driver_funcs = { + .flush = intel_flip_driver_flush, +}; + +static void intel_flip_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc; + struct intel_plane *intel_plane; + + drm_flip_driver_init(&dev_priv->flip_driver, &intel_flip_driver_funcs); + + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { + init_waitqueue_head(&intel_crtc->vbl_wait); + + drm_flip_helper_init(&intel_crtc->flip_helper, + &dev_priv->flip_driver, &intel_flip_funcs); + } + + list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head) + drm_flip_helper_init(&intel_plane->flip_helper, + &dev_priv->flip_driver, &intel_flip_funcs); +} + +static void intel_flip_fini(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + struct drm_plane *plane; + + list_for_each_entry(plane, &dev->mode_config.plane_list, head) + drm_flip_helper_fini(&to_intel_plane(plane)->flip_helper); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + drm_flip_helper_fini(&to_intel_crtc(crtc)->flip_helper); + + drm_flip_driver_fini(&dev_priv->flip_driver); +} + +static int atomic_pipe_commit(struct drm_device *dev, + struct intel_atomic_state *state, + int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_flip *intel_flip, *next; + LIST_HEAD(flips); + int i; + + for (i = 0; i < dev->mode_config.num_crtc; i++) { + struct intel_crtc_state *st = &state->crtc[i]; + struct drm_crtc *crtc = st->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + if (!st->fb_dirty) + continue; + + if (intel_crtc->pipe != pipe) + continue; + + intel_flip = kzalloc(sizeof *intel_flip, GFP_KERNEL); + if (!intel_flip) + goto out; + + intel_plane_calc(crtc, crtc->fb, crtc->x, crtc->y); + + drm_flip_init(&intel_flip->base, &intel_crtc->flip_helper); + intel_flip->crtc = crtc; + if (st->old_fb) + intel_flip->old_bo = to_intel_framebuffer(st->old_fb)->obj; + + list_add_tail(&intel_flip->base.list, &flips); + } + + for (i = 0; i < dev->mode_config.num_plane; i++) { + struct intel_plane_state *st = &state->plane[i]; + struct drm_plane *plane = st->plane; + struct intel_plane *intel_plane = to_intel_plane(plane); + + if (!st->dirty) + continue; + + if (intel_plane->pipe != pipe) + continue; + + intel_flip = kzalloc(sizeof *intel_flip, GFP_KERNEL); + if (!intel_flip) + goto out; + + intel_sprite_calc(plane, plane->fb, &st->coords); + + drm_flip_init(&intel_flip->base, &intel_plane->flip_helper); + intel_flip->crtc = intel_get_crtc_for_pipe(dev, pipe); + intel_flip->plane = plane; + if (st->old_fb) + intel_flip->old_bo = to_intel_framebuffer(st->old_fb)->obj; + + list_add_tail(&intel_flip->base.list, &flips); + } + + /* FIXME if pipe is not enabled complete flip immediately */ + + drm_flip_driver_prepare_flips(&dev_priv->flip_driver, &flips); + + local_irq_disable(); + + intel_pipe_vblank_evade(intel_get_crtc_for_pipe(dev, pipe)); + + drm_flip_driver_schedule_flips(&dev_priv->flip_driver, &flips); + + local_irq_enable(); + + return 0; + + out: + list_for_each_entry_safe(intel_flip, next, &flips, base.list) + kfree(intel_flip); + + return -ENOMEM; +} + +void intel_handle_vblank(struct drm_device *dev, int pipe) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe)); + struct intel_plane *intel_plane; + + drm_handle_vblank(dev, pipe); + + drm_flip_helper_vblank(&intel_crtc->flip_helper); + + list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head) { + if (intel_plane->pipe == pipe) + drm_flip_helper_vblank(&intel_plane->flip_helper); + } +} diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 01c1a19..23fbc0b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1988,8 +1988,36 @@ static unsigned long gen4_compute_dspaddr_offset_xtiled(int *x, int *y, return tile_rows * pitch * 8 + tiles * 4096; } -static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, - int x, int y) +void intel_plane_prepare(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = intel_crtc->plane; + const struct intel_plane_regs *regs = &intel_crtc->primary_regs; + + I915_WRITE(DSPCNTR(plane), regs->cntr); + I915_WRITE(DSPSTRIDE(plane), regs->stride); +} + +void intel_plane_commit(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = intel_crtc->plane; + const struct intel_plane_regs *regs = &intel_crtc->primary_regs; + + if (INTEL_INFO(dev)->gen >= 4) { + I915_WRITE(DSPSURF(plane), regs->surf); + I915_WRITE(DSPTILEOFF(plane), regs->tileoff); + I915_WRITE(DSPLINOFF(plane), regs->linoff); + } else + I915_WRITE(DSPADDR(plane), regs->addr); +} + +static int i9xx_calc_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, + int x, int y) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1998,9 +2026,8 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj; int plane = intel_crtc->plane; unsigned long linear_offset; - u32 dspcntr; - u32 reg; unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0); + struct intel_plane_regs *regs = &intel_crtc->primary_regs; switch (plane) { case 0: @@ -2014,36 +2041,35 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; - reg = DSPCNTR(plane); - dspcntr = I915_READ(reg); + regs->cntr = I915_READ(DSPCNTR(plane)); /* Mask out pixel format bits in case we change it */ - dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + regs->cntr &= ~DISPPLANE_PIXFORMAT_MASK; switch (fb->pixel_format) { case DRM_FORMAT_C8: - dspcntr |= DISPPLANE_8BPP; + regs->cntr |= DISPPLANE_8BPP; break; case DRM_FORMAT_XRGB1555: case DRM_FORMAT_ARGB1555: - dspcntr |= DISPPLANE_BGRX555; + regs->cntr |= DISPPLANE_BGRX555; break; case DRM_FORMAT_RGB565: - dspcntr |= DISPPLANE_BGRX565; + regs->cntr |= DISPPLANE_BGRX565; break; case DRM_FORMAT_XRGB8888: case DRM_FORMAT_ARGB8888: - dspcntr |= DISPPLANE_BGRX888; + regs->cntr |= DISPPLANE_BGRX888; break; case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ABGR8888: - dspcntr |= DISPPLANE_RGBX888; + regs->cntr |= DISPPLANE_RGBX888; break; case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_ARGB2101010: - dspcntr |= DISPPLANE_BGRX101010; + regs->cntr |= DISPPLANE_BGRX101010; break; case DRM_FORMAT_XBGR2101010: case DRM_FORMAT_ABGR2101010: - dspcntr |= DISPPLANE_RGBX101010; + regs->cntr |= DISPPLANE_RGBX101010; break; default: DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format); @@ -2052,13 +2078,11 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, if (INTEL_INFO(dev)->gen >= 4) { if (obj->tiling_mode != I915_TILING_NONE) - dspcntr |= DISPPLANE_TILED; + regs->cntr |= DISPPLANE_TILED; else - dspcntr &= ~DISPPLANE_TILED; + regs->cntr &= ~DISPPLANE_TILED; } - I915_WRITE(reg, dspcntr); - linear_offset = fb->offsets[0] + y * fb->pitches[0] + x * cpp; if (INTEL_INFO(dev)->gen >= 4) { @@ -2072,21 +2096,42 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n", obj->gtt_offset, linear_offset, x, y, fb->pitches[0]); - I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); + + regs->stride = fb->pitches[0]; + if (INTEL_INFO(dev)->gen >= 4) { - I915_MODIFY_DISPBASE(DSPSURF(plane), - obj->gtt_offset + intel_crtc->dspaddr_offset); - I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); - I915_WRITE(DSPLINOFF(plane), linear_offset); + regs->surf = I915_LO_DISPBASE(I915_READ(DSPSURF(plane))); + regs->surf |= obj->gtt_offset + intel_crtc->dspaddr_offset; + regs->tileoff = (y << 16) | x; + regs->linoff = linear_offset; } else - I915_WRITE(DSPADDR(plane), obj->gtt_offset + linear_offset); - POSTING_READ(reg); + regs->addr = obj->gtt_offset + linear_offset; return 0; } -static int ironlake_update_plane(struct drm_crtc *crtc, - struct drm_framebuffer *fb, int x, int y) +static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, + int x, int y) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = intel_crtc->plane; + int ret; + + ret = i9xx_calc_plane(crtc, fb, x, y); + if (ret) + return ret; + + intel_plane_prepare(crtc); + intel_plane_commit(crtc); + + POSTING_READ(DSPCNTR(plane)); + + return 0; +} + +static int ironlake_calc_plane(struct drm_crtc *crtc, + struct drm_framebuffer *fb, int x, int y) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2095,9 +2140,8 @@ static int ironlake_update_plane(struct drm_crtc *crtc, struct drm_i915_gem_object *obj; int plane = intel_crtc->plane; unsigned long linear_offset; - u32 dspcntr; - u32 reg; unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0); + struct intel_plane_regs *regs = &intel_crtc->primary_regs; switch (plane) { case 0: @@ -2112,32 +2156,31 @@ static int ironlake_update_plane(struct drm_crtc *crtc, intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; - reg = DSPCNTR(plane); - dspcntr = I915_READ(reg); + regs->cntr = I915_READ(DSPCNTR(plane)); /* Mask out pixel format bits in case we change it */ - dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + regs->cntr &= ~DISPPLANE_PIXFORMAT_MASK; switch (fb->pixel_format) { case DRM_FORMAT_C8: - dspcntr |= DISPPLANE_8BPP; + regs->cntr |= DISPPLANE_8BPP; break; case DRM_FORMAT_RGB565: - dspcntr |= DISPPLANE_BGRX565; + regs->cntr |= DISPPLANE_BGRX565; break; case DRM_FORMAT_XRGB8888: case DRM_FORMAT_ARGB8888: - dspcntr |= DISPPLANE_BGRX888; + regs->cntr |= DISPPLANE_BGRX888; break; case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ABGR8888: - dspcntr |= DISPPLANE_RGBX888; + regs->cntr |= DISPPLANE_RGBX888; break; case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_ARGB2101010: - dspcntr |= DISPPLANE_BGRX101010; + regs->cntr |= DISPPLANE_BGRX101010; break; case DRM_FORMAT_XBGR2101010: case DRM_FORMAT_ABGR2101010: - dspcntr |= DISPPLANE_RGBX101010; + regs->cntr |= DISPPLANE_RGBX101010; break; default: DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format); @@ -2145,33 +2188,57 @@ static int ironlake_update_plane(struct drm_crtc *crtc, } if (obj->tiling_mode != I915_TILING_NONE) - dspcntr |= DISPPLANE_TILED; + regs->cntr |= DISPPLANE_TILED; else - dspcntr &= ~DISPPLANE_TILED; + regs->cntr &= ~DISPPLANE_TILED; /* must disable */ - dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; - - I915_WRITE(reg, dspcntr); + regs->cntr |= DISPPLANE_TRICKLE_FEED_DISABLE; linear_offset = fb->offsets[0] + y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); - intel_crtc->dspaddr_offset = - gen4_compute_dspaddr_offset_xtiled(&x, &y, - cpp, fb->pitches[0]); + intel_crtc->dspaddr_offset = gen4_compute_dspaddr_offset_xtiled(&x, &y, cpp, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n", obj->gtt_offset, linear_offset, x, y, fb->pitches[0]); - I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); - I915_MODIFY_DISPBASE(DSPSURF(plane), - obj->gtt_offset + intel_crtc->dspaddr_offset); - I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); - I915_WRITE(DSPLINOFF(plane), linear_offset); - POSTING_READ(reg); + regs->stride = fb->pitches[0]; + regs->surf = I915_LO_DISPBASE(I915_READ(DSPSURF(plane))); + regs->surf |= obj->gtt_offset + intel_crtc->dspaddr_offset; + regs->tileoff = (y << 16) | x; + regs->linoff = linear_offset; return 0; } +static int ironlake_update_plane(struct drm_crtc *crtc, + struct drm_framebuffer *fb, int x, int y) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = intel_crtc->plane; + int ret; + + ret = ironlake_calc_plane(crtc, fb, x, y); + if (ret) + return ret; + + intel_plane_prepare(crtc); + intel_plane_commit(crtc); + + POSTING_READ(DSPCNTR(plane)); + + return 0; +} + +int intel_plane_calc(struct drm_crtc *crtc, + struct drm_framebuffer *fb, int x, int y) +{ + if (HAS_PCH_SPLIT(crtc->dev)) + return ironlake_calc_plane(crtc, fb, x, y); + else + return i9xx_calc_plane(crtc, fb, x, y); +} + /* Assume fb object is pinned & idle & fenced and just update base pointers */ static int intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fa81676..52b0cc7 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -31,6 +31,7 @@ #include "drm_crtc.h" #include "drm_crtc_helper.h" #include "drm_fb_helper.h" +#include "drm_flip.h" #define _wait_for(COND, MS, W) ({ \ unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ @@ -162,6 +163,21 @@ struct intel_connector { struct intel_encoder *encoder; }; +struct intel_plane_regs { + u32 cntr; + u32 addr; + u32 linoff; + u32 stride; + u32 pos; + u32 size; + u32 keyval; + u32 keymsk; + u32 surf; + u32 keymaxval; + u32 tileoff; + u32 scale; +}; + struct intel_crtc { struct drm_crtc base; enum pipe pipe; @@ -191,6 +207,12 @@ struct intel_crtc { /* We can share PLLs across outputs if the timings match */ struct intel_pch_pll *pch_pll; + + struct intel_plane_regs primary_regs; + + struct drm_flip_helper flip_helper; + wait_queue_head_t vbl_wait; + bool vbl_received; }; struct intel_plane_coords { @@ -208,6 +230,7 @@ struct intel_plane { struct drm_i915_gem_object *obj; int max_downscale; u32 lut_r[1024], lut_g[1024], lut_b[1024]; + struct intel_plane_regs regs; void (*update_plane)(struct drm_plane *plane, struct drm_framebuffer *fb, const struct intel_plane_coords *clip); @@ -216,6 +239,7 @@ struct intel_plane { struct drm_intel_sprite_colorkey *key); void (*get_colorkey)(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key); + struct drm_flip_helper flip_helper; }; struct intel_watermark_params { @@ -525,4 +549,9 @@ extern void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle, struct drm_i915_gem_object *obj, uint32_t addr); +extern int intel_calc_primary(struct drm_crtc *crtc, + struct drm_framebuffer *fb, int x, int y); +extern void intel_prepare_primary(struct drm_crtc *crtc); +extern void intel_commit_primary(struct drm_crtc *crtc); + #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index d456cd2..3049a62 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -187,12 +187,10 @@ int intel_check_plane(const struct drm_plane *plane, } static void -ivb_update_plane(struct drm_plane *plane, - struct drm_framebuffer *fb, - const struct intel_plane_coords *coords) +ivb_calc_plane(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct intel_plane_coords *coords) { - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); const struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj; int crtc_x = coords->crtc_x; @@ -203,47 +201,48 @@ ivb_update_plane(struct drm_plane *plane, uint32_t y = coords->src_y; uint32_t src_w = coords->src_w; uint32_t src_h = coords->src_h; - int pipe = intel_plane->pipe; - u32 sprctl, sprscale = 0; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - - sprctl = I915_READ(SPRCTL(pipe)); + struct intel_plane_regs *regs = &intel_plane->regs; /* Mask out pixel format bits in case we change it */ - sprctl &= ~SPRITE_PIXFORMAT_MASK; - sprctl &= ~SPRITE_RGB_ORDER_RGBX; - sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; - sprctl &= ~SPRITE_TILED; + regs->cntr &= ~(SPRITE_PIXFORMAT_MASK | + SPRITE_RGB_ORDER_RGBX | + SPRITE_YUV_BYTE_ORDER_MASK | + SPRITE_TRICKLE_FEED_DISABLE | + SPRITE_TILED | + SPRITE_ENABLE); switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: - sprctl |= SPRITE_FORMAT_RGBX888; + regs->cntr |= SPRITE_FORMAT_RGBX888; break; case DRM_FORMAT_XRGB8888: - sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; + regs->cntr |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; break; case DRM_FORMAT_YUYV: - sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; + regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; break; case DRM_FORMAT_YVYU: - sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; + regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; break; case DRM_FORMAT_UYVY: - sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; + regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; break; case DRM_FORMAT_VYUY: - sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; + regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; break; default: BUG(); } if (obj->tiling_mode != I915_TILING_NONE) - sprctl |= SPRITE_TILED; + regs->cntr |= SPRITE_TILED; /* must disable */ - sprctl |= SPRITE_TRICKLE_FEED_DISABLE; - sprctl |= SPRITE_ENABLE; + regs->cntr |= SPRITE_TRICKLE_FEED_DISABLE; + + if (coords->visible) + regs->cntr |= SPRITE_ENABLE; /* Sizes are 0 based */ src_w--; @@ -251,20 +250,54 @@ ivb_update_plane(struct drm_plane *plane, crtc_w--; crtc_h--; - intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); + /* + * IVB workaround: must disable low power watermarks for at least + * one frame before enabling scaling. LP watermarks can be re-enabled + * when scaling is disabled. + */ + if (coords->visible && (crtc_w != src_w || crtc_h != src_h)) + regs->scale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; + else + regs->scale = 0; + + regs->stride = fb->pitches[0]; + regs->pos = (crtc_y << 16) | crtc_x; + + if (obj->tiling_mode != I915_TILING_NONE) { + y += fb->offsets[0] / fb->pitches[0]; + x += fb->offsets[0] % fb->pitches[0] / pixel_size; + + regs->tileoff = (y << 16) | x; + } else + regs->linoff = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size; + + regs->size = (crtc_h << 16) | crtc_w; + regs->surf = I915_LO_DISPBASE(regs->surf) | obj->gtt_offset; +} + +static void +ivb_commit_plane(struct drm_plane *plane, struct drm_framebuffer *fb) +{ + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane *intel_plane = to_intel_plane(plane); + int pipe = intel_plane->pipe; + int pixel_size = fb ? drm_format_plane_cpp(fb->pixel_format, 0) : 0; + const struct intel_plane_regs *regs = &intel_plane->regs; + + intel_update_sprite_watermarks(dev, pipe, regs->size & 0xffff, pixel_size); /* * IVB workaround: must disable low power watermarks for at least * one frame before enabling scaling. LP watermarks can be re-enabled * when scaling is disabled. */ - if (crtc_w != src_w || crtc_h != src_h) { + if (regs->scale & SPRITE_SCALE_ENABLE) { if (!dev_priv->sprite_scaling_enabled) { dev_priv->sprite_scaling_enabled = true; intel_update_watermarks(dev); intel_wait_for_vblank(dev, pipe); } - sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; } else { if (dev_priv->sprite_scaling_enabled) { dev_priv->sprite_scaling_enabled = false; @@ -273,23 +306,31 @@ ivb_update_plane(struct drm_plane *plane, } } - I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); - I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); - if (obj->tiling_mode != I915_TILING_NONE) { - y += fb->offsets[0] / fb->pitches[0]; - x += fb->offsets[0] % fb->pitches[0] / pixel_size; + I915_WRITE(SPRKEYVAL(pipe), regs->keyval); + I915_WRITE(SPRKEYMAX(pipe), regs->keymaxval); + I915_WRITE(SPRKEYMSK(pipe), regs->keymsk); + I915_WRITE(SPRSTRIDE(pipe), regs->stride); + I915_WRITE(SPRPOS(pipe), regs->pos); + I915_WRITE(SPRTILEOFF(pipe), regs->tileoff); + I915_WRITE(SPRLINOFF(pipe), regs->linoff); + I915_WRITE(SPRSIZE(pipe), regs->size); + I915_WRITE(SPRSCALE(pipe), regs->scale); + I915_WRITE(SPRCTL(pipe), regs->cntr); + I915_WRITE(SPRSURF(pipe), regs->surf); +} - I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); - } else { - unsigned long offset; +static void +ivb_update_plane(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct intel_plane_coords *coords) +{ + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = to_intel_plane(plane)->pipe; + + ivb_calc_plane(plane, fb, coords); + ivb_commit_plane(plane, fb); - offset = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size; - I915_WRITE(SPRLINOFF(pipe), offset); - } - I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); - I915_WRITE(SPRSCALE(pipe), sprscale); - I915_WRITE(SPRCTL(pipe), sprctl); - I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset); POSTING_READ(SPRSURF(pipe)); } @@ -300,12 +341,13 @@ ivb_disable_plane(struct drm_plane *plane) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; + struct intel_plane_regs *regs = &intel_plane->regs; - I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); + regs->cntr &= ~SPRITE_ENABLE; /* Can't leave the scaler enabled... */ - I915_WRITE(SPRSCALE(pipe), 0); - /* Activate double buffered register update */ - I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); + regs->scale = 0; + + ivb_commit_plane(plane, plane->fb); POSTING_READ(SPRSURF(pipe)); dev_priv->sprite_scaling_enabled = false; @@ -318,61 +360,50 @@ ivb_update_colorkey(struct drm_plane *plane, { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane; - u32 sprctl; - int ret = 0; - - intel_plane = to_intel_plane(plane); + struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_plane_regs *regs = &intel_plane->regs; - I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value); - I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value); - I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask); + regs->keyval = key->min_value; + regs->keymaxval = key->max_value; + regs->keymsk = key->channel_mask; - sprctl = I915_READ(SPRCTL(intel_plane->pipe)); - sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); + regs->cntr &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); if (key->flags & I915_SET_COLORKEY_DESTINATION) - sprctl |= SPRITE_DEST_KEY; + regs->cntr |= SPRITE_DEST_KEY; else if (key->flags & I915_SET_COLORKEY_SOURCE) - sprctl |= SPRITE_SOURCE_KEY; - I915_WRITE(SPRCTL(intel_plane->pipe), sprctl); + regs->cntr |= SPRITE_SOURCE_KEY; + ivb_commit_plane(plane, plane->fb); POSTING_READ(SPRKEYMSK(intel_plane->pipe)); - return ret; + return 0; } static void ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) { - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane; - u32 sprctl; - - intel_plane = to_intel_plane(plane); + struct intel_plane *intel_plane = to_intel_plane(plane); + const struct intel_plane_regs *regs = &intel_plane->regs; - key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe)); - key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe)); - key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe)); + key->min_value = regs->keyval; + key->max_value = regs->keymaxval; + key->channel_mask = regs->keymsk; key->flags = 0; - sprctl = I915_READ(SPRCTL(intel_plane->pipe)); - - if (sprctl & SPRITE_DEST_KEY) + if (regs->cntr & SPRITE_DEST_KEY) key->flags = I915_SET_COLORKEY_DESTINATION; - else if (sprctl & SPRITE_SOURCE_KEY) + else if (regs->cntr & SPRITE_SOURCE_KEY) key->flags = I915_SET_COLORKEY_SOURCE; else key->flags = I915_SET_COLORKEY_NONE; } static void -ilk_update_plane(struct drm_plane *plane, - struct drm_framebuffer *fb, - const struct intel_plane_coords *coords) +ilk_calc_plane(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct intel_plane_coords *coords) { struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); const struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj; int crtc_x = coords->crtc_x; @@ -383,46 +414,48 @@ ilk_update_plane(struct drm_plane *plane, uint32_t y = coords->src_y; uint32_t src_w = coords->src_w; uint32_t src_h = coords->src_h; - int pipe = intel_plane->pipe; - u32 dvscntr, dvsscale; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - - dvscntr = I915_READ(DVSCNTR(pipe)); + struct intel_plane_regs *regs = &intel_plane->regs; /* Mask out pixel format bits in case we change it */ - dvscntr &= ~DVS_PIXFORMAT_MASK; - dvscntr &= ~DVS_RGB_ORDER_XBGR; - dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; + regs->cntr &= ~(DVS_PIXFORMAT_MASK | + DVS_RGB_ORDER_XBGR | + DVS_YUV_BYTE_ORDER_MASK | + DVS_TRICKLE_FEED_DISABLE | + DVS_TILED | + DVS_ENABLE); switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: - dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; + regs->cntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; break; case DRM_FORMAT_XRGB8888: - dvscntr |= DVS_FORMAT_RGBX888; + regs->cntr |= DVS_FORMAT_RGBX888; break; case DRM_FORMAT_YUYV: - dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; + regs->cntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; break; case DRM_FORMAT_YVYU: - dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; + regs->cntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; break; case DRM_FORMAT_UYVY: - dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; + regs->cntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; break; case DRM_FORMAT_VYUY: - dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; + regs->cntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; break; default: BUG(); } if (obj->tiling_mode != I915_TILING_NONE) - dvscntr |= DVS_TILED; + regs->cntr |= DVS_TILED; if (IS_GEN6(dev)) - dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ - dvscntr |= DVS_ENABLE; + regs->cntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ + + if (coords->visible) + regs->cntr |= DVS_ENABLE; /* Sizes are 0 based */ src_w--; @@ -430,29 +463,64 @@ ilk_update_plane(struct drm_plane *plane, crtc_w--; crtc_h--; - intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); + if (coords->visible && (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h)) + regs->scale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; + else + regs->scale = 0; - dvsscale = 0; - if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h) - dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; + regs->stride = fb->pitches[0]; + regs->pos = (crtc_y << 16) | crtc_x; - I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); - I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); if (obj->tiling_mode != I915_TILING_NONE) { y += fb->offsets[0] / fb->pitches[0]; x += fb->offsets[0] % fb->pitches[0] / pixel_size; - I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); - } else { - unsigned long offset; + regs->tileoff = (y << 16) | x; + } else + regs->linoff = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size; + + regs->size = (crtc_h << 16) | crtc_w; + regs->surf = I915_LO_DISPBASE(regs->surf) | obj->gtt_offset; +} + +static void +ilk_commit_plane(struct drm_plane *plane, struct drm_framebuffer *fb) +{ + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane *intel_plane = to_intel_plane(plane); + int pipe = intel_plane->pipe; + int pixel_size = fb ? drm_format_plane_cpp(fb->pixel_format, 0) : 0; + const struct intel_plane_regs *regs = &intel_plane->regs; + + /* FIXME move somewhere appropriate */ + intel_update_sprite_watermarks(dev, pipe, regs->size & 0xffff, pixel_size); + + I915_WRITE(DVSKEYVAL(pipe), regs->keyval); + I915_WRITE(DVSKEYMAX(pipe), regs->keymaxval); + I915_WRITE(DVSKEYMSK(pipe), regs->keymsk); + I915_WRITE(DVSSTRIDE(pipe), regs->stride); + I915_WRITE(DVSPOS(pipe), regs->pos); + I915_WRITE(DVSTILEOFF(pipe), regs->tileoff); + I915_WRITE(DVSLINOFF(pipe), regs->linoff); + I915_WRITE(DVSSIZE(pipe), regs->size); + I915_WRITE(DVSSCALE(pipe), regs->scale); + I915_WRITE(DVSCNTR(pipe), regs->cntr); + I915_WRITE(DVSSURF(pipe), regs->surf); +} + +static void +ilk_update_plane(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct intel_plane_coords *coords) +{ + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = to_intel_plane(plane)->pipe; + + ilk_calc_plane(plane, fb, coords); + ilk_commit_plane(plane, fb); - offset = fb->offsets[0] + y * fb->pitches[0] + x * pixel_size; - I915_WRITE(DVSLINOFF(pipe), offset); - } - I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); - I915_WRITE(DVSSCALE(pipe), dvsscale); - I915_WRITE(DVSCNTR(pipe), dvscntr); - I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset); POSTING_READ(DVSSURF(pipe)); } @@ -463,22 +531,50 @@ ilk_disable_plane(struct drm_plane *plane) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; + struct intel_plane_regs *regs = &intel_plane->regs; - I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); + regs->cntr &= ~DVS_ENABLE; /* Disable the scaler */ - I915_WRITE(DVSSCALE(pipe), 0); - /* Flush double buffered register updates */ - I915_MODIFY_DISPBASE(DVSSURF(pipe), 0); + regs->scale = 0; + + ilk_commit_plane(plane, NULL); POSTING_READ(DVSSURF(pipe)); } + +void intel_sprite_calc(struct drm_plane *plane, struct drm_framebuffer *fb, + const struct intel_plane_coords *coords) +{ + struct drm_device *dev = plane->dev; + + if (INTEL_INFO(dev)->gen == 7) + ivb_calc_plane(plane, fb, coords); + else + ilk_calc_plane(plane, fb, coords); +} + +void intel_sprite_prepare(struct drm_plane *plane) +{ +} + +void intel_sprite_commit(struct drm_plane *plane) +{ + struct drm_device *dev = plane->dev; + + if (INTEL_INFO(dev)->gen == 7) + ivb_commit_plane(plane, plane->fb); + else + ilk_commit_plane(plane, plane->fb); +} + +void intel_plane_commit(struct drm_crtc *crtc); + static void intel_enable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int reg = DSPCNTR(intel_crtc->plane); + struct intel_plane_regs *regs = &intel_crtc->primary_regs; if (!intel_crtc->primary_disabled) return; @@ -486,21 +582,26 @@ intel_enable_primary(struct drm_crtc *crtc) intel_crtc->primary_disabled = false; intel_update_fbc(dev); - I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); + regs->cntr |= DISPLAY_PLANE_ENABLE; + + // FIXME + intel_plane_commit(crtc); } static void intel_disable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int reg = DSPCNTR(intel_crtc->plane); + struct intel_plane_regs *regs = &intel_crtc->primary_regs; if (intel_crtc->primary_disabled) return; - I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); + regs->cntr &= ~DISPLAY_PLANE_ENABLE; + + // FIXME + intel_plane_commit(crtc); intel_crtc->primary_disabled = true; intel_update_fbc(dev); @@ -512,49 +613,39 @@ ilk_update_colorkey(struct drm_plane *plane, { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane; - u32 dvscntr; - int ret = 0; - - intel_plane = to_intel_plane(plane); + struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_plane_regs *regs = &intel_plane->regs; - I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value); - I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value); - I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask); + regs->keyval = key->min_value; + regs->keymaxval = key->max_value; + regs->keymsk = key->channel_mask; - dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); - dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); + regs->cntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); if (key->flags & I915_SET_COLORKEY_DESTINATION) - dvscntr |= DVS_DEST_KEY; + regs->cntr |= DVS_DEST_KEY; else if (key->flags & I915_SET_COLORKEY_SOURCE) - dvscntr |= DVS_SOURCE_KEY; - I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr); + regs->cntr |= DVS_SOURCE_KEY; + ilk_commit_plane(plane, plane->fb); POSTING_READ(DVSKEYMSK(intel_plane->pipe)); - return ret; + return 0; } static void ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) { - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane; - u32 dvscntr; - - intel_plane = to_intel_plane(plane); + struct intel_plane *intel_plane = to_intel_plane(plane); + const struct intel_plane_regs *regs = &intel_plane->regs; - key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe)); - key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe)); - key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe)); + key->min_value = regs->keyval; + key->max_value = regs->keymaxval; + key->channel_mask = regs->keymsk; key->flags = 0; - dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); - - if (dvscntr & DVS_DEST_KEY) + if (regs->cntr & DVS_DEST_KEY) key->flags = I915_SET_COLORKEY_DESTINATION; - else if (dvscntr & DVS_SOURCE_KEY) + else if (regs->cntr & DVS_SOURCE_KEY) key->flags = I915_SET_COLORKEY_SOURCE; else key->flags = I915_SET_COLORKEY_NONE; @@ -803,6 +894,7 @@ static uint32_t snb_plane_formats[] = { int intel_plane_init(struct drm_device *dev, enum pipe pipe) { + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane; unsigned long possible_crtcs; const uint32_t *plane_formats; @@ -825,6 +917,9 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) intel_plane->update_colorkey = ilk_update_colorkey; intel_plane->get_colorkey = ilk_get_colorkey; + intel_plane->regs.cntr = I915_READ(DVSCNTR(pipe)); + intel_plane->regs.surf = I915_READ(DVSSURF(pipe)); + if (IS_GEN6(dev)) { plane_formats = snb_plane_formats; num_plane_formats = ARRAY_SIZE(snb_plane_formats); @@ -841,6 +936,9 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) intel_plane->update_colorkey = ivb_update_colorkey; intel_plane->get_colorkey = ivb_get_colorkey; + intel_plane->regs.cntr = I915_READ(SPRCTL(pipe)); + intel_plane->regs.surf = I915_READ(SPRSURF(pipe)); + plane_formats = snb_plane_formats; num_plane_formats = ARRAY_SIZE(snb_plane_formats); break; -- 1.7.8.6 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel