drm/i915: implement drmmode overlay support v4

This implements intel overlay support for kms via a device-specific
ioctl. Thomas Hellstrom brought up the idea of a general ioctl (on
dri-devel). We've reached the conclusion that such an infrastructure
only makes sense when multiple kms overlay implementations exists,
which atm don't (and it doesn't look like this is gonna change).

Open issues:
- Runs in sync with the gpu, i.e. unnecessary waiting. I've decided
  to wait on this because the hw tends to hang when changing something
  in this area. I left some dummy functions as infrastructure.
- polyphase filtering uses a static table.
- uses uninterruptible sleeps. Unfortunately the alternatives may
  unnecessarily wedged the hw if/when we timeout too early (and
  userspace only overloaded the batch buffers with stuff worth a few
  secs of gpu time).

Changes since v1:
- fix off-by-one misconception on my side. This fixes fullscreen
  playback.
Changes since v2:
- add underrun detection as spec'ed for i965.
- flush caches properly, fixing visual corruptions.
Changes since v4:
- fix up cache flushing of overlay memory regs.
- killed require_pipe_a logic - it hangs the chip.

Tested-By: diego.abelenda@gmail.com (on a 865G)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
[anholt: Resolved against the MADVISE ioctl going in before this one]
Signed-off-by: Eric Anholt <eric@anholt.net>
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0be624a..6f818fa 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1781,6 +1781,22 @@
 	}
 }
 
+static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
+{
+	struct intel_overlay *overlay;
+
+	if (!enable && intel_crtc->overlay) {
+		overlay = intel_crtc->overlay;
+		mutex_lock(&overlay->dev->struct_mutex);
+		intel_overlay_switch_off(overlay);
+		mutex_unlock(&overlay->dev->struct_mutex);
+	}
+	/* Let userspace switch the overlay on again. In most cases userspace
+	 * has to recompute where to put it anyway. */
+
+	return;
+}
+
 static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
 	struct drm_device *dev = crtc->dev;
@@ -1839,12 +1855,13 @@
 			intel_update_fbc(crtc, &crtc->mode);
 
 		/* Give the overlay scaler a chance to enable if it's on this pipe */
-		//intel_crtc_dpms_video(crtc, true); TODO
+		intel_crtc_dpms_overlay(intel_crtc, true);
 	break;
 	case DRM_MODE_DPMS_OFF:
 		intel_update_watermarks(dev);
+
 		/* Give the overlay scaler a chance to disable if it's on this pipe */
-		//intel_crtc_dpms_video(crtc, FALSE); TODO
+		intel_crtc_dpms_overlay(intel_crtc, false);
 
 		if (dev_priv->cfb_plane == plane &&
 		    dev_priv->display.disable_fbc)
@@ -2039,7 +2056,7 @@
  * Return the pipe currently connected to the panel fitter,
  * or -1 if the panel fitter is not present or not in use
  */
-static int intel_panel_fitter_pipe (struct drm_device *dev)
+int intel_panel_fitter_pipe (struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32  pfit_control;
@@ -4458,6 +4475,8 @@
 	INIT_WORK(&dev_priv->idle_work, intel_idle_update);
 	setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
 		    (unsigned long)dev);
+
+	intel_setup_overlay(dev);
 }
 
 void intel_modeset_cleanup(struct drm_device *dev)