struct intel_framebuffer *intel_fb =
to_intel_framebuffer(intel_crtc->base.primary->fb);
struct drm_i915_gem_object *obj = intel_fb->obj;
+ bool atomic_update;
+ u32 start_vbl_count;
u32 dspcntr;
u32 reg;
intel_mark_page_flip_active(intel_crtc);
+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
+
reg = DSPCNTR(intel_crtc->plane);
dspcntr = I915_READ(reg);
I915_WRITE(DSPSURF(intel_crtc->plane),
intel_crtc->unpin_work->gtt_offset);
POSTING_READ(DSPSURF(intel_crtc->plane));
+
+ if (atomic_update)
+ intel_pipe_update_end(intel_crtc, start_vbl_count);
+
+ spin_lock_irq(&dev_priv->mmio_flip_lock);
+ intel_crtc->mmio_flip.status = INTEL_MMIO_FLIP_IDLE;
+ spin_unlock_irq(&dev_priv->mmio_flip_lock);
+}
+
+static void intel_mmio_flip_work_func(struct work_struct *work)
+{
+ struct intel_crtc *intel_crtc =
+ container_of(work, struct intel_crtc, mmio_flip.work);
+
+ intel_do_mmio_flip(intel_crtc);
}
static int intel_postpone_flip(struct drm_i915_gem_object *obj)
struct intel_mmio_flip *mmio_flip;
mmio_flip = &intel_crtc->mmio_flip;
- if (mmio_flip->seqno == 0)
+ if (mmio_flip->status != INTEL_MMIO_FLIP_WAIT_RING)
continue;
if (ring->id != mmio_flip->ring_id)
continue;
if (i915_seqno_passed(seqno, mmio_flip->seqno)) {
- intel_do_mmio_flip(intel_crtc);
- mmio_flip->seqno = 0;
+ schedule_work(&intel_crtc->mmio_flip.work);
+ mmio_flip->status = INTEL_MMIO_FLIP_WORK_SCHEDULED;
ring->irq_put(ring);
}
}
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int ret;
- if (WARN_ON(intel_crtc->mmio_flip.seqno))
+ if (WARN_ON(intel_crtc->mmio_flip.status != INTEL_MMIO_FLIP_IDLE))
return -EBUSY;
ret = intel_postpone_flip(obj);
}
spin_lock_irq(&dev_priv->mmio_flip_lock);
+ intel_crtc->mmio_flip.status = INTEL_MMIO_FLIP_WAIT_RING;
intel_crtc->mmio_flip.seqno = obj->last_write_seqno;
intel_crtc->mmio_flip.ring_id = obj->ring->id;
spin_unlock_irq(&dev_priv->mmio_flip_lock);
dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
+ INIT_WORK(&intel_crtc->mmio_flip.work, intel_mmio_flip_work_func);
+
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe);
bool sprites_scaled;
};
+enum intel_mmio_flip_status {
+ INTEL_MMIO_FLIP_IDLE = 0,
+ INTEL_MMIO_FLIP_WAIT_RING,
+ INTEL_MMIO_FLIP_WORK_SCHEDULED,
+};
+
struct intel_mmio_flip {
u32 seqno;
u32 ring_id;
+ enum intel_mmio_flip_status status;
+ struct work_struct work;
};
struct intel_crtc {
struct drm_file *file_priv);
int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-
+bool intel_pipe_update_start(struct intel_crtc *crtc,
+ uint32_t *start_vbl_count);
+void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count);
/* intel_tv.c */
void intel_tv_init(struct drm_device *dev);
*
* Return: true if the call was successful
*/
-static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
+bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
{
struct drm_device *dev = crtc->base.dev;
const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
* re-enables interrupts and verifies the update was actually completed
* before a vblank using the value of @start_vbl_count.
*/
-static void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count)
+void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count)
{
struct drm_device *dev = crtc->base.dev;
enum pipe pipe = crtc->pipe;