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

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

drm/i915: framebuffer compression for pre-GM45



This patch adds framebuffer compression (good for about ~0.5W power
savings in the best case) support for pre-GM45 chips.  GM45+ have a new,
more flexible FBC scheme that will be added in a separate patch.

FBC can't always be enabled: the compressed buffer must be physically
contiguous and reside in stolen space.  So if you have a large display
and a small amount of stolen memory, you may not be able to take
advantage of FBC.  In some cases, a BIOS setting controls how much
stolen space is available.  Increasing this to 8 or 16M can help.

Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent 06324194
Loading
Loading
Loading
Loading
+157 −4
Original line number Diff line number Diff line
@@ -921,7 +921,8 @@ static int i915_get_bridge_dev(struct drm_device *dev)
 * how much was set aside so we can use it for our own purposes.
 */
static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
			  uint32_t *preallocated_size)
			  uint32_t *preallocated_size,
			  uint32_t *start)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	u16 tmp = 0;
@@ -1008,11 +1009,148 @@ static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
		return -1;
	}
	*preallocated_size = stolen - overhead;
	*start = overhead;

	return 0;
}

#define PTE_ADDRESS_MASK		0xfffff000
#define PTE_ADDRESS_MASK_HIGH		0x000000f0 /* i915+ */
#define PTE_MAPPING_TYPE_UNCACHED	(0 << 1)
#define PTE_MAPPING_TYPE_DCACHE		(1 << 1) /* i830 only */
#define PTE_MAPPING_TYPE_CACHED		(3 << 1)
#define PTE_MAPPING_TYPE_MASK		(3 << 1)
#define PTE_VALID			(1 << 0)

/**
 * i915_gtt_to_phys - take a GTT address and turn it into a physical one
 * @dev: drm device
 * @gtt_addr: address to translate
 *
 * Some chip functions require allocations from stolen space but need the
 * physical address of the memory in question.  We use this routine
 * to get a physical address suitable for register programming from a given
 * GTT address.
 */
static unsigned long i915_gtt_to_phys(struct drm_device *dev,
				      unsigned long gtt_addr)
{
	unsigned long *gtt;
	unsigned long entry, phys;
	int gtt_bar = IS_I9XX(dev) ? 0 : 1;
	int gtt_offset, gtt_size;

	if (IS_I965G(dev)) {
		if (IS_G4X(dev) || IS_IGDNG(dev)) {
			gtt_offset = 2*1024*1024;
			gtt_size = 2*1024*1024;
		} else {
			gtt_offset = 512*1024;
			gtt_size = 512*1024;
		}
	} else {
		gtt_bar = 3;
		gtt_offset = 0;
		gtt_size = pci_resource_len(dev->pdev, gtt_bar);
	}

	gtt = ioremap_wc(pci_resource_start(dev->pdev, gtt_bar) + gtt_offset,
			 gtt_size);
	if (!gtt) {
		DRM_ERROR("ioremap of GTT failed\n");
		return 0;
	}

	entry = *(volatile u32 *)(gtt + (gtt_addr / 1024));

	DRM_DEBUG("GTT addr: 0x%08lx, PTE: 0x%08lx\n", gtt_addr, entry);

	/* Mask out these reserved bits on this hardware. */
	if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev) ||
	    IS_I945G(dev) || IS_I945GM(dev)) {
		entry &= ~PTE_ADDRESS_MASK_HIGH;
	}

	/* If it's not a mapping type we know, then bail. */
	if ((entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED &&
	    (entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_CACHED)	{
		iounmap(gtt);
		return 0;
	}

	if (!(entry & PTE_VALID)) {
		DRM_ERROR("bad GTT entry in stolen space\n");
		iounmap(gtt);
		return 0;
	}

	iounmap(gtt);

	phys =(entry & PTE_ADDRESS_MASK) |
		((uint64_t)(entry & PTE_ADDRESS_MASK_HIGH) << (32 - 4));

	DRM_DEBUG("GTT addr: 0x%08lx, phys addr: 0x%08lx\n", gtt_addr, phys);

	return phys;
}

static void i915_warn_stolen(struct drm_device *dev)
{
	DRM_ERROR("not enough stolen space for compressed buffer, disabling\n");
	DRM_ERROR("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n");
}

static void i915_setup_compression(struct drm_device *dev, int size)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_mm_node *compressed_fb, *compressed_llb;
	unsigned long cfb_base, ll_base;

	/* Leave 1M for line length buffer & misc. */
	compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0);
	if (!compressed_fb) {
		i915_warn_stolen(dev);
		return;
	}

	compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
	if (!compressed_fb) {
		i915_warn_stolen(dev);
		return;
	}

	compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096, 4096, 0);
	if (!compressed_llb) {
		i915_warn_stolen(dev);
		return;
	}

	compressed_llb = drm_mm_get_block(compressed_fb, 4096, 4096);
	if (!compressed_llb) {
		i915_warn_stolen(dev);
		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) {
		DRM_ERROR("failed to get stolen phys addr, disabling FBC\n");
		drm_mm_put_block(compressed_fb);
		drm_mm_put_block(compressed_llb);
	}

	i8xx_disable_fbc(dev);

	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,
				  unsigned long prealloc_start,
				  unsigned long prealloc_size,
				  unsigned long agp_size)
{
@@ -1033,6 +1171,7 @@ static int i915_load_modeset_init(struct drm_device *dev,

	/* Basic memrange allocator for stolen space (aka vram) */
	drm_mm_init(&dev_priv->vram, 0, prealloc_size);
	DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024));

	/* Let GEM Manage from end of prealloc space to end of aperture.
	 *
@@ -1049,6 +1188,19 @@ static int i915_load_modeset_init(struct drm_device *dev,
	if (ret)
		goto out;

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

		/* Try to get an 8M buffer... */
		if (prealloc_size > (9*1024*1024))
			cfb_size = 8*1024*1024;
		else /* fall back to 7/8 of the stolen space */
			cfb_size = prealloc_size * 7 / 8;
		i915_setup_compression(dev, cfb_size);
	}

	/* Allow hardware batchbuffers unless told otherwise.
	 */
	dev_priv->allow_batchbuffer = 1;
@@ -1161,7 +1313,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
	struct drm_i915_private *dev_priv = dev->dev_private;
	resource_size_t base, size;
	int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
	uint32_t agp_size, prealloc_size;
	uint32_t agp_size, prealloc_size, prealloc_start;

	/* i915 has 4 more counters */
	dev->counters += 4;
@@ -1215,7 +1367,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
			 "performance may suffer.\n");
	}

	ret = i915_probe_agp(dev, &agp_size, &prealloc_size);
	ret = i915_probe_agp(dev, &agp_size, &prealloc_size, &prealloc_start);
	if (ret)
		goto out_iomapfree;

@@ -1282,7 +1434,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
	}

	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
		ret = i915_load_modeset_init(dev, prealloc_start,
					     prealloc_size, agp_size);
		if (ret < 0) {
			DRM_ERROR("failed to init modeset\n");
			goto out_workqueue_free;
+12 −0
Original line number Diff line number Diff line
@@ -48,6 +48,11 @@ enum pipe {
	PIPE_B,
};

enum plane {
	PLANE_A = 0,
	PLANE_B,
};

#define I915_NUM_PIPE	2

/* Interface history:
@@ -202,6 +207,11 @@ typedef struct drm_i915_private {

	struct drm_mm vram;

	unsigned long cfb_size;
	unsigned long cfb_pitch;
	int cfb_fence;
	int cfb_plane;

	int irq_enabled;

	struct intel_opregion opregion;
@@ -768,6 +778,7 @@ static inline void opregion_enable_asle(struct drm_device *dev) { return; }
/* modesetting */
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);

/**
 * Lock test for when it's just for synchronization of ring access.
@@ -918,6 +929,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);

#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IGDNG(dev))
#define HAS_PIPE_CXSR(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define I915_HAS_FBC(dev) (IS_I9XX(dev) || IS_I965G(dev))

#define PRIMARY_RINGBUFFER_SIZE         (128*1024)

+1 −0
Original line number Diff line number Diff line
@@ -343,6 +343,7 @@
#define   FBC_CTL_PLANEA	(0<<0)
#define   FBC_CTL_PLANEB	(1<<0)
#define FBC_FENCE_OFF		0x0321b
#define FBC_TAG			0x03300

#define FBC_LL_SIZE		(1536)

+209 −13
Original line number Diff line number Diff line
@@ -954,6 +954,174 @@ intel_wait_for_vblank(struct drm_device *dev)
	mdelay(20);
}

/* Parameters have changed, update FBC info */
static void i8xx_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, i;
	u32 fbc_ctl, fbc_ctl2;

	dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;

	if (fb->pitch < dev_priv->cfb_pitch)
		dev_priv->cfb_pitch = fb->pitch;

	/* FBC_CTL wants 64B units */
	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;
	plane = dev_priv->cfb_plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;

	/* Clear old tags */
	for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
		I915_WRITE(FBC_TAG + (i * 4), 0);

	/* Set it up... */
	fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | plane;
	if (obj_priv->tiling_mode != I915_TILING_NONE)
		fbc_ctl2 |= FBC_CTL_CPU_FENCE;
	I915_WRITE(FBC_CONTROL2, fbc_ctl2);
	I915_WRITE(FBC_FENCE_OFF, crtc->y);

	/* enable it... */
	fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
	fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
	fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
	if (obj_priv->tiling_mode != I915_TILING_NONE)
		fbc_ctl |= dev_priv->cfb_fence;
	I915_WRITE(FBC_CONTROL, fbc_ctl);

	DRM_DEBUG("enabled FBC, pitch %ld, yoff %d, plane %d, ",
		  dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
}

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

	/* Disable compression */
	fbc_ctl = I915_READ(FBC_CONTROL);
	fbc_ctl &= ~FBC_CTL_EN;
	I915_WRITE(FBC_CONTROL, fbc_ctl);

	/* Wait for compressing bit to clear */
	while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING)
		; /* nothing */

	intel_wait_for_vblank(dev);

	DRM_DEBUG("disabled FBC\n");
}

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

	return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
}

/**
 * intel_update_fbc - enable/disable FBC as needed
 * @crtc: CRTC to point the compressor at
 * @mode: mode in use
 *
 * Set up the framebuffer compression hardware at mode set time.  We
 * enable it if possible:
 *   - plane A only (on pre-965)
 *   - no pixel mulitply/line duplication
 *   - no alpha buffer discard
 *   - no dual wide
 *   - framebuffer <= 2048 in width, 1536 in height
 *
 * We can't assume that any compression will take place (worst case),
 * so the compressed buffer has to be the same size as the uncompressed
 * one.  It also must reside (along with the line length buffer) in
 * stolen memory.
 *
 * We need to enable/disable FBC on a global basis.
 */
static void intel_update_fbc(struct drm_crtc *crtc,
			     struct drm_display_mode *mode)
{
	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;
	struct drm_i915_gem_object *obj_priv;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	int plane = intel_crtc->plane;

	if (!i915_powersave)
		return;

	if (!crtc->fb)
		return;

	intel_fb = to_intel_framebuffer(fb);
	obj_priv = intel_fb->obj->driver_private;

	/*
	 * If FBC is already on, we just have to verify that we can
	 * keep it that way...
	 * Need to disable if:
	 *   - changing FBC params (stride, fence, mode)
	 *   - new fb is too large to fit in compressed buffer
	 *   - going to an unsupported config (interlace, pixel multiply, etc.)
	 */
	if (intel_fb->obj->size > dev_priv->cfb_size) {
		DRM_DEBUG("framebuffer too large, disabling compression\n");
		goto out_disable;
	}
	if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
	    (mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
		DRM_DEBUG("mode incompatible with compression, disabling\n");
		goto out_disable;
	}
	if ((mode->hdisplay > 2048) ||
	    (mode->vdisplay > 1536)) {
		DRM_DEBUG("mode too large for compression, disabling\n");
		goto out_disable;
	}
	if (IS_I9XX(dev) && plane != 0) {
		DRM_DEBUG("plane not 0, disabling compression\n");
		goto out_disable;
	}
	if (obj_priv->tiling_mode != I915_TILING_X) {
		DRM_DEBUG("framebuffer not tiled, disabling compression\n");
		goto out_disable;
	}

	if (i8xx_fbc_enabled(crtc)) {
		/* We can re-enable it in this case, but need to update pitch */
		if (fb->pitch > dev_priv->cfb_pitch)
			i8xx_disable_fbc(dev);
		if (obj_priv->fence_reg != dev_priv->cfb_fence)
			i8xx_disable_fbc(dev);
		if (plane != dev_priv->cfb_plane)
			i8xx_disable_fbc(dev);
	}

	if (!i8xx_fbc_enabled(crtc)) {
		/* Now try to turn it back on if possible */
		i8xx_enable_fbc(crtc, 500);
	}

	return;

out_disable:
	DRM_DEBUG("unsupported config, disabling FBC\n");
	/* Multiple disables should be harmless */
	if (i8xx_fbc_enabled(crtc))
		i8xx_disable_fbc(dev);
}

static int
intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
		    struct drm_framebuffer *old_fb)
@@ -966,12 +1134,13 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
	struct drm_i915_gem_object *obj_priv;
	struct drm_gem_object *obj;
	int pipe = intel_crtc->pipe;
	int plane = intel_crtc->plane;
	unsigned long Start, Offset;
	int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR);
	int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
	int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
	int dsptileoff = (pipe == 0 ? DSPATILEOFF : DSPBTILEOFF);
	int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
	int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
	int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
	int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
	int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
	u32 dspcntr, alignment;
	int ret;

@@ -981,12 +1150,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
		return 0;
	}

	switch (pipe) {
	switch (plane) {
	case 0:
	case 1:
		break;
	default:
		DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
		DRM_ERROR("Can't update plane %d in SAREA\n", plane);
		return -EINVAL;
	}

@@ -1114,6 +1283,9 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
		master_priv->sarea_priv->pipeA_y = y;
	}

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

	return 0;
}

@@ -1534,9 +1706,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	int pipe = intel_crtc->pipe;
	int plane = intel_crtc->plane;
	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
	int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
	int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR;
	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
	int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
	u32 temp;

@@ -1579,6 +1752,9 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)

		intel_crtc_load_lut(crtc);

		if (I915_HAS_FBC(dev) && (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 */
		//intel_crtc_dpms_video(crtc, true); TODO
		intel_update_watermarks(dev);
@@ -1588,6 +1764,9 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
		/* Give the overlay scaler a chance to disable if it's on this pipe */
		//intel_crtc_dpms_video(crtc, FALSE); TODO

		if (dev_priv->cfb_plane == plane)
			i8xx_disable_fbc(dev);

		/* Disable the VGA plane that we never use */
		i915_disable_vga(dev);

@@ -2325,10 +2504,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	int pipe = intel_crtc->pipe;
	int plane = intel_crtc->plane;
	int fp_reg = (pipe == 0) ? FPA0 : FPB0;
	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
	int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
	int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
	int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
	int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
@@ -2336,8 +2516,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
	int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
	int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
	int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
	int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
	int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
	int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
	int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
	int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
	int refclk, num_outputs = 0;
	intel_clock_t clock, reduced_clock;
@@ -2570,7 +2750,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
	   enable color space conversion */
	if (!IS_IGDNG(dev)) {
		if (pipe == 0)
			dspcntr |= DISPPLANE_SEL_PIPE_A;
			dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
		else
			dspcntr |= DISPPLANE_SEL_PIPE_B;
	}
@@ -2739,6 +2919,8 @@ 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 (I915_HAS_FBC(dev) && (IS_I965G(dev) || plane == 0))
		intel_update_fbc(crtc, &crtc->mode);
	intel_update_watermarks(dev);

	drm_vblank_post_modeset(dev, pipe);
@@ -2783,6 +2965,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
	struct drm_gem_object *bo;
	struct drm_i915_gem_object *obj_priv;
	int pipe = intel_crtc->pipe;
	int plane = intel_crtc->plane;
	uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
	uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
	uint32_t temp = I915_READ(control);
@@ -2868,6 +3051,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
			i915_gem_object_unpin(intel_crtc->cursor_bo);
		drm_gem_object_unreference(intel_crtc->cursor_bo);
	}

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

	mutex_unlock(&dev->struct_mutex);

	intel_crtc->cursor_addr = addr;
@@ -3549,6 +3736,14 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
		intel_crtc->lut_b[i] = i;
	}

	/* Swap pipes & planes for FBC on pre-965 */
	intel_crtc->pipe = pipe;
	intel_crtc->plane = pipe;
	if (IS_MOBILE(dev) && (IS_I9XX(dev) && !IS_I965G(dev))) {
		DRM_DEBUG("swapping pipes & planes for FBC\n");
		intel_crtc->plane = ((pipe == 0) ? 1 : 0);
	}

	intel_crtc->cursor_addr = 0;
	intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
	drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
@@ -3909,6 +4104,7 @@ void intel_modeset_cleanup(struct drm_device *dev)

	mutex_unlock(&dev->struct_mutex);

	i8xx_disable_fbc(dev);
	drm_mode_config_cleanup(dev);
}

+3 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include "i915_drv.h"
#include "drm_crtc.h"

#include "drm_crtc_helper.h"
@@ -110,8 +111,8 @@ struct intel_output {

struct intel_crtc {
	struct drm_crtc base;
	int pipe;
	int plane;
	enum pipe pipe;
	enum plane plane;
	struct drm_gem_object *cursor_bo;
	uint32_t cursor_addr;
	u8 lut_r[256], lut_g[256], lut_b[256];