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

Commit 74dff282 authored by Jesse Barnes's avatar Jesse Barnes Committed by Eric Anholt
Browse files

drm/i915: framebuffer compression for GM45+



Add support for framebuffer compression on GM45 and above.  Removes
some unnecessary I915_HAS_FBC checks as well (this is now part of the
FBC display function).

Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent e70236a8
Loading
Loading
Loading
Loading
+32 −19
Original line number Diff line number Diff line
@@ -1119,7 +1119,15 @@ static void i915_setup_compression(struct drm_device *dev, int size)
		return;
	}

	compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096, 4096, 0);
	cfb_base = i915_gtt_to_phys(dev, compressed_fb->start);
	if (!cfb_base) {
		DRM_ERROR("failed to get stolen phys addr, disabling FBC\n");
		drm_mm_put_block(compressed_fb);
	}

	if (!IS_GM45(dev)) {
		compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096,
						    4096, 0);
		if (!compressed_llb) {
			i915_warn_stolen(dev);
			return;
@@ -1131,22 +1139,27 @@ static void i915_setup_compression(struct drm_device *dev, int size)
			return;
		}

	dev_priv->cfb_size = size;

	cfb_base = i915_gtt_to_phys(dev, compressed_fb->start);
		ll_base = i915_gtt_to_phys(dev, compressed_llb->start);
	if (!cfb_base || !ll_base) {
		if (!ll_base) {
			DRM_ERROR("failed to get stolen phys addr, disabling FBC\n");
			drm_mm_put_block(compressed_fb);
			drm_mm_put_block(compressed_llb);
		}
	}

	dev_priv->cfb_size = size;

	if (IS_GM45(dev)) {
		g4x_disable_fbc(dev);
		I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
	} else {
		i8xx_disable_fbc(dev);
		I915_WRITE(FBC_CFB_BASE, cfb_base);
		I915_WRITE(FBC_LL_BASE, ll_base);
	}

	DRM_DEBUG("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base,
		  ll_base, size >> 20);
	I915_WRITE(FBC_CFB_BASE, cfb_base);
	I915_WRITE(FBC_LL_BASE, ll_base);
}

static int i915_load_modeset_init(struct drm_device *dev,
@@ -1194,7 +1207,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
		goto out;

	/* Try to set up FBC with a reasonable compressed buffer size */
	if (IS_MOBILE(dev) && (IS_I9XX(dev) || IS_I965G(dev)) &&
	if (IS_MOBILE(dev) && (IS_I9XX(dev) || IS_I965G(dev) || IS_GM45(dev)) &&
	    i915_powersave) {
		int cfb_size;

+1 −0
Original line number Diff line number Diff line
@@ -827,6 +827,7 @@ static inline void opregion_enable_asle(struct drm_device *dev) { return; }
extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_cleanup(struct drm_device *dev);
extern void i8xx_disable_fbc(struct drm_device *dev);
extern void g4x_disable_fbc(struct drm_device *dev);

/**
 * Lock test for when it's just for synchronization of ring access.
+27 −0
Original line number Diff line number Diff line
@@ -351,6 +351,33 @@

#define FBC_LL_SIZE		(1536)

/* Framebuffer compression for GM45+ */
#define DPFC_CB_BASE		0x3200
#define DPFC_CONTROL		0x3208
#define   DPFC_CTL_EN		(1<<31)
#define   DPFC_CTL_PLANEA	(0<<30)
#define   DPFC_CTL_PLANEB	(1<<30)
#define   DPFC_CTL_FENCE_EN	(1<<29)
#define   DPFC_SR_EN		(1<<10)
#define   DPFC_CTL_LIMIT_1X	(0<<6)
#define   DPFC_CTL_LIMIT_2X	(1<<6)
#define   DPFC_CTL_LIMIT_4X	(2<<6)
#define DPFC_RECOMP_CTL		0x320c
#define   DPFC_RECOMP_STALL_EN	(1<<27)
#define   DPFC_RECOMP_STALL_WM_SHIFT (16)
#define   DPFC_RECOMP_STALL_WM_MASK (0x07ff0000)
#define   DPFC_RECOMP_TIMER_COUNT_SHIFT (0)
#define   DPFC_RECOMP_TIMER_COUNT_MASK (0x0000003f)
#define DPFC_STATUS		0x3210
#define   DPFC_INVAL_SEG_SHIFT  (16)
#define   DPFC_INVAL_SEG_MASK	(0x07ff0000)
#define   DPFC_COMP_SEG_SHIFT	(0)
#define   DPFC_COMP_SEG_MASK	(0x000003ff)
#define DPFC_STATUS2		0x3214
#define DPFC_FENCE_YOFF		0x3218
#define DPFC_CHICKEN		0x3224
#define   DPFC_HT_MODIFY	(1<<31)

/*
 * GPIO regs
 */
+72 −7
Original line number Diff line number Diff line
@@ -1030,6 +1030,65 @@ static bool i8xx_fbc_enabled(struct drm_crtc *crtc)
	return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
}

static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
{
	struct drm_device *dev = crtc->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_framebuffer *fb = crtc->fb;
	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
	struct drm_i915_gem_object *obj_priv = intel_fb->obj->driver_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA :
		     DPFC_CTL_PLANEB);
	unsigned long stall_watermark = 200;
	u32 dpfc_ctl;

	dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
	dev_priv->cfb_fence = obj_priv->fence_reg;
	dev_priv->cfb_plane = intel_crtc->plane;

	dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
	if (obj_priv->tiling_mode != I915_TILING_NONE) {
		dpfc_ctl |= DPFC_CTL_FENCE_EN | dev_priv->cfb_fence;
		I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
	} else {
		I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY);
	}

	I915_WRITE(DPFC_CONTROL, dpfc_ctl);
	I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
		   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
		   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
	I915_WRITE(DPFC_FENCE_YOFF, crtc->y);

	/* enable it... */
	I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN);

	DRM_DEBUG("enabled fbc on plane %d\n", intel_crtc->plane);
}

void g4x_disable_fbc(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 dpfc_ctl;

	/* Disable compression */
	dpfc_ctl = I915_READ(DPFC_CONTROL);
	dpfc_ctl &= ~DPFC_CTL_EN;
	I915_WRITE(DPFC_CONTROL, dpfc_ctl);
	intel_wait_for_vblank(dev);

	DRM_DEBUG("disabled FBC\n");
}

static bool g4x_fbc_enabled(struct drm_crtc *crtc)
{
	struct drm_device *dev = crtc->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;

	return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
}

/**
 * intel_update_fbc - enable/disable FBC as needed
 * @crtc: CRTC to point the compressor at
@@ -1097,7 +1156,7 @@ static void intel_update_fbc(struct drm_crtc *crtc,
		DRM_DEBUG("mode too large for compression, disabling\n");
		goto out_disable;
	}
	if (IS_I9XX(dev) && plane != 0) {
	if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
		DRM_DEBUG("plane not 0, disabling compression\n");
		goto out_disable;
	}
@@ -1265,7 +1324,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
		I915_READ(dspbase);
	}

	if (I915_HAS_FBC(dev) && (IS_I965G(dev) || plane == 0))
	if ((IS_I965G(dev) || plane == 0))
		intel_update_fbc(crtc, &crtc->mode);

	intel_wait_for_vblank(dev);
@@ -1774,6 +1833,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)

		intel_crtc_load_lut(crtc);

		if ((IS_I965G(dev) || plane == 0))
			intel_update_fbc(crtc, &crtc->mode);

		/* Give the overlay scaler a chance to enable if it's on this pipe */
@@ -2988,6 +3048,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
	/* Flush the plane changes */
	ret = intel_pipe_set_base(crtc, x, y, old_fb);

	if ((IS_I965G(dev) || plane == 0))
		intel_update_fbc(crtc, &crtc->mode);

	intel_update_watermarks(dev);
@@ -3121,7 +3182,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
		drm_gem_object_unreference(intel_crtc->cursor_bo);
	}

	if (I915_HAS_FBC(dev) && (IS_I965G(dev) || plane == 0))
	if ((IS_I965G(dev) || plane == 0))
		intel_update_fbc(crtc, &crtc->mode);

	mutex_unlock(&dev->struct_mutex);
@@ -4108,12 +4169,16 @@ static void intel_init_display(struct drm_device *dev)

	/* Only mobile has FBC, leave pointers NULL for other chips */
	if (IS_MOBILE(dev)) {
		/* 855GM needs testing */
		if (IS_I965GM(dev) || IS_I945GM(dev) || IS_I915GM(dev)) {
		if (IS_GM45(dev)) {
			dev_priv->display.fbc_enabled = g4x_fbc_enabled;
			dev_priv->display.enable_fbc = g4x_enable_fbc;
			dev_priv->display.disable_fbc = g4x_disable_fbc;
		} else if (IS_I965GM(dev) || IS_I945GM(dev) || IS_I915GM(dev)) {
			dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
			dev_priv->display.enable_fbc = i8xx_enable_fbc;
			dev_priv->display.disable_fbc = i8xx_disable_fbc;
		}
		/* 855GM needs testing */
	}

	/* Returns the core display clock speed */