Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02e792fb authored by Daniel Vetter's avatar Daniel Vetter Committed by Eric Anholt
Browse files

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: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
[anholt: Resolved against the MADVISE ioctl going in before this one]
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent f0f8a9ce
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
	  intel_fb.o \
	  intel_tv.o \
	  intel_dvo.o \
	  intel_overlay.o \
	  dvo_ch7xxx.o \
	  dvo_ch7017.o \
	  dvo_ivch.o \
+7 −0
Original line number Diff line number Diff line
@@ -807,6 +807,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
	case I915_PARAM_NUM_FENCES_AVAIL:
		value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
		break;
	case I915_PARAM_HAS_OVERLAY:
		value = dev_priv->overlay ? 1 : 0;
		break;
	default:
		DRM_DEBUG_DRIVER("Unknown parameter %d\n",
					param->param);
@@ -1548,6 +1551,8 @@ int i915_driver_unload(struct drm_device *dev)
		mutex_unlock(&dev->struct_mutex);
		drm_mm_takedown(&dev_priv->vram);
		i915_gem_lastclose(dev);

		intel_cleanup_overlay(dev);
	}

	pci_dev_put(dev_priv->bridge_dev);
@@ -1656,6 +1661,8 @@ struct drm_ioctl_desc i915_ioctls[] = {
	DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, 0),
	DRM_IOCTL_DEF(DRM_I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0),
	DRM_IOCTL_DEF(DRM_I915_GEM_MADVISE, i915_gem_madvise_ioctl, 0),
	DRM_IOCTL_DEF(DRM_I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW),
	DRM_IOCTL_DEF(DRM_I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW),
};

int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
+5 −0
Original line number Diff line number Diff line
@@ -170,6 +170,8 @@ struct drm_i915_display_funcs {
	/* clock gating init */
};

struct intel_overlay;

typedef struct drm_i915_private {
	struct drm_device *dev;

@@ -241,6 +243,9 @@ typedef struct drm_i915_private {

	struct intel_opregion opregion;

	/* overlay */
	struct intel_overlay *overlay;

	/* LVDS info */
	int backlight_duty_cycle;  /* restore backlight to this value */
	bool panel_wants_dither;
+5 −0
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@
#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_OVERLAY_FLIP	(1<<16)
#define   MI_WAIT_FOR_PLANE_B_FLIP      (1<<6)
#define   MI_WAIT_FOR_PLANE_A_FLIP      (1<<2)
#define   MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
@@ -151,6 +152,10 @@
#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_OVERLAY_FLIP		MI_INSTR(0x11,0)
#define   MI_OVERLAY_CONTINUE	(0x0<<21)
#define   MI_OVERLAY_ON		(0x1<<21)
#define   MI_OVERLAY_OFF	(0x2<<21)
#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 */
+22 −3
Original line number Diff line number Diff line
@@ -1781,6 +1781,22 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
	}
}

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 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
			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 @@ static int i830_get_display_clock_speed(struct drm_device *dev)
 * 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 @@ void intel_modeset_init(struct drm_device *dev)
	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)
Loading