diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_sprite.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_sprite.c | 664 | 
1 files changed, 664 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c new file mode 100644 index 00000000000..2288abf88cc --- /dev/null +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -0,0 +1,664 @@ +/* + * Copyright © 2011 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + *   Jesse Barnes <jbarnes@virtuousgeek.org> + * + * New plane/sprite handling. + * + * The older chips had a separate interface for programming plane related + * registers; newer ones are much simpler and we can use the new DRM plane + * support. + */ +#include "drmP.h" +#include "drm_crtc.h" +#include "drm_fourcc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +static void +ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, +		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, +		 unsigned int crtc_w, unsigned int crtc_h, +		 uint32_t x, uint32_t y, +		 uint32_t src_w, uint32_t src_h) +{ +	struct drm_device *dev = plane->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_plane *intel_plane = to_intel_plane(plane); +	int pipe = intel_plane->pipe; +	u32 sprctl, sprscale = 0; +	int pixel_size; + +	sprctl = I915_READ(SPRCTL(pipe)); + +	/* Mask out pixel format bits in case we change it */ +	sprctl &= ~SPRITE_PIXFORMAT_MASK; +	sprctl &= ~SPRITE_RGB_ORDER_RGBX; +	sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; + +	switch (fb->pixel_format) { +	case DRM_FORMAT_XBGR8888: +		sprctl |= SPRITE_FORMAT_RGBX888; +		pixel_size = 4; +		break; +	case DRM_FORMAT_XRGB8888: +		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; +		pixel_size = 4; +		break; +	case DRM_FORMAT_YUYV: +		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; +		pixel_size = 2; +		break; +	case DRM_FORMAT_YVYU: +		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; +		pixel_size = 2; +		break; +	case DRM_FORMAT_UYVY: +		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; +		pixel_size = 2; +		break; +	case DRM_FORMAT_VYUY: +		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; +		pixel_size = 2; +		break; +	default: +		DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n"); +		sprctl |= DVS_FORMAT_RGBX888; +		pixel_size = 4; +		break; +	} + +	if (obj->tiling_mode != I915_TILING_NONE) +		sprctl |= SPRITE_TILED; + +	/* must disable */ +	sprctl |= SPRITE_TRICKLE_FEED_DISABLE; +	sprctl |= SPRITE_ENABLE; +	sprctl |= SPRITE_DEST_KEY; + +	/* Sizes are 0 based */ +	src_w--; +	src_h--; +	crtc_w--; +	crtc_h--; + +	intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); + +	/* +	 * IVB workaround: must disable low power watermarks for at least +	 * one frame before enabling scaling.  LP watermarks can be re-enabled +	 * when scaling is disabled. +	 */ +	if (crtc_w != src_w || crtc_h != src_h) { +		dev_priv->sprite_scaling_enabled = true; +		sandybridge_update_wm(dev); +		intel_wait_for_vblank(dev, pipe); +		sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; +	} else { +		dev_priv->sprite_scaling_enabled = false; +		/* potentially re-enable LP watermarks */ +		sandybridge_update_wm(dev); +	} + +	I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); +	I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); +	if (obj->tiling_mode != I915_TILING_NONE) { +		I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); +	} else { +		unsigned long offset; + +		offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); +		I915_WRITE(SPRLINOFF(pipe), offset); +	} +	I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); +	I915_WRITE(SPRSCALE(pipe), sprscale); +	I915_WRITE(SPRCTL(pipe), sprctl); +	I915_WRITE(SPRSURF(pipe), obj->gtt_offset); +	POSTING_READ(SPRSURF(pipe)); +} + +static void +ivb_disable_plane(struct drm_plane *plane) +{ +	struct drm_device *dev = plane->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_plane *intel_plane = to_intel_plane(plane); +	int pipe = intel_plane->pipe; + +	I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); +	/* Can't leave the scaler enabled... */ +	I915_WRITE(SPRSCALE(pipe), 0); +	/* Activate double buffered register update */ +	I915_WRITE(SPRSURF(pipe), 0); +	POSTING_READ(SPRSURF(pipe)); +} + +static int +ivb_update_colorkey(struct drm_plane *plane, +		    struct drm_intel_sprite_colorkey *key) +{ +	struct drm_device *dev = plane->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_plane *intel_plane; +	u32 sprctl; +	int ret = 0; + +	intel_plane = to_intel_plane(plane); + +	I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value); +	I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value); +	I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask); + +	sprctl = I915_READ(SPRCTL(intel_plane->pipe)); +	sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); +	if (key->flags & I915_SET_COLORKEY_DESTINATION) +		sprctl |= SPRITE_DEST_KEY; +	else if (key->flags & I915_SET_COLORKEY_SOURCE) +		sprctl |= SPRITE_SOURCE_KEY; +	I915_WRITE(SPRCTL(intel_plane->pipe), sprctl); + +	POSTING_READ(SPRKEYMSK(intel_plane->pipe)); + +	return ret; +} + +static void +ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) +{ +	struct drm_device *dev = plane->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_plane *intel_plane; +	u32 sprctl; + +	intel_plane = to_intel_plane(plane); + +	key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe)); +	key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe)); +	key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe)); +	key->flags = 0; + +	sprctl = I915_READ(SPRCTL(intel_plane->pipe)); + +	if (sprctl & SPRITE_DEST_KEY) +		key->flags = I915_SET_COLORKEY_DESTINATION; +	else if (sprctl & SPRITE_SOURCE_KEY) +		key->flags = I915_SET_COLORKEY_SOURCE; +	else +		key->flags = I915_SET_COLORKEY_NONE; +} + +static void +snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, +		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, +		 unsigned int crtc_w, unsigned int crtc_h, +		 uint32_t x, uint32_t y, +		 uint32_t src_w, uint32_t src_h) +{ +	struct drm_device *dev = plane->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_plane *intel_plane = to_intel_plane(plane); +	int pipe = intel_plane->pipe, pixel_size; +	u32 dvscntr, dvsscale = 0; + +	dvscntr = I915_READ(DVSCNTR(pipe)); + +	/* Mask out pixel format bits in case we change it */ +	dvscntr &= ~DVS_PIXFORMAT_MASK; +	dvscntr &= ~DVS_RGB_ORDER_RGBX; +	dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; + +	switch (fb->pixel_format) { +	case DRM_FORMAT_XBGR8888: +		dvscntr |= DVS_FORMAT_RGBX888; +		pixel_size = 4; +		break; +	case DRM_FORMAT_XRGB8888: +		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_RGBX; +		pixel_size = 4; +		break; +	case DRM_FORMAT_YUYV: +		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; +		pixel_size = 2; +		break; +	case DRM_FORMAT_YVYU: +		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; +		pixel_size = 2; +		break; +	case DRM_FORMAT_UYVY: +		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; +		pixel_size = 2; +		break; +	case DRM_FORMAT_VYUY: +		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; +		pixel_size = 2; +		break; +	default: +		DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n"); +		dvscntr |= DVS_FORMAT_RGBX888; +		pixel_size = 4; +		break; +	} + +	if (obj->tiling_mode != I915_TILING_NONE) +		dvscntr |= DVS_TILED; + +	/* must disable */ +	dvscntr |= DVS_TRICKLE_FEED_DISABLE; +	dvscntr |= DVS_ENABLE; + +	/* Sizes are 0 based */ +	src_w--; +	src_h--; +	crtc_w--; +	crtc_h--; + +	intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); + +	if (crtc_w != src_w || crtc_h != src_h) +		dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; + +	I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); +	I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); +	if (obj->tiling_mode != I915_TILING_NONE) { +		I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); +	} else { +		unsigned long offset; + +		offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); +		I915_WRITE(DVSLINOFF(pipe), offset); +	} +	I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); +	I915_WRITE(DVSSCALE(pipe), dvsscale); +	I915_WRITE(DVSCNTR(pipe), dvscntr); +	I915_WRITE(DVSSURF(pipe), obj->gtt_offset); +	POSTING_READ(DVSSURF(pipe)); +} + +static void +snb_disable_plane(struct drm_plane *plane) +{ +	struct drm_device *dev = plane->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_plane *intel_plane = to_intel_plane(plane); +	int pipe = intel_plane->pipe; + +	I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); +	/* Disable the scaler */ +	I915_WRITE(DVSSCALE(pipe), 0); +	/* Flush double buffered register updates */ +	I915_WRITE(DVSSURF(pipe), 0); +	POSTING_READ(DVSSURF(pipe)); +} + +static void +intel_enable_primary(struct drm_crtc *crtc) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc); +	int reg = DSPCNTR(intel_crtc->plane); + +	I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); +} + +static void +intel_disable_primary(struct drm_crtc *crtc) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc); +	int reg = DSPCNTR(intel_crtc->plane); + +	I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); +} + +static int +snb_update_colorkey(struct drm_plane *plane, +		    struct drm_intel_sprite_colorkey *key) +{ +	struct drm_device *dev = plane->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_plane *intel_plane; +	u32 dvscntr; +	int ret = 0; + +	intel_plane = to_intel_plane(plane); + +	I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value); +	I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value); +	I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask); + +	dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); +	dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); +	if (key->flags & I915_SET_COLORKEY_DESTINATION) +		dvscntr |= DVS_DEST_KEY; +	else if (key->flags & I915_SET_COLORKEY_SOURCE) +		dvscntr |= DVS_SOURCE_KEY; +	I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr); + +	POSTING_READ(DVSKEYMSK(intel_plane->pipe)); + +	return ret; +} + +static void +snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) +{ +	struct drm_device *dev = plane->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_plane *intel_plane; +	u32 dvscntr; + +	intel_plane = to_intel_plane(plane); + +	key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe)); +	key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe)); +	key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe)); +	key->flags = 0; + +	dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); + +	if (dvscntr & DVS_DEST_KEY) +		key->flags = I915_SET_COLORKEY_DESTINATION; +	else if (dvscntr & DVS_SOURCE_KEY) +		key->flags = I915_SET_COLORKEY_SOURCE; +	else +		key->flags = I915_SET_COLORKEY_NONE; +} + +static int +intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, +		   struct drm_framebuffer *fb, int crtc_x, int crtc_y, +		   unsigned int crtc_w, unsigned int crtc_h, +		   uint32_t src_x, uint32_t src_y, +		   uint32_t src_w, uint32_t src_h) +{ +	struct drm_device *dev = plane->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc); +	struct intel_plane *intel_plane = to_intel_plane(plane); +	struct intel_framebuffer *intel_fb; +	struct drm_i915_gem_object *obj, *old_obj; +	int pipe = intel_plane->pipe; +	int ret = 0; +	int x = src_x >> 16, y = src_y >> 16; +	int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay; +	bool disable_primary = false; + +	intel_fb = to_intel_framebuffer(fb); +	obj = intel_fb->obj; + +	old_obj = intel_plane->obj; + +	/* Pipe must be running... */ +	if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE)) +		return -EINVAL; + +	if (crtc_x >= primary_w || crtc_y >= primary_h) +		return -EINVAL; + +	/* Don't modify another pipe's plane */ +	if (intel_plane->pipe != intel_crtc->pipe) +		return -EINVAL; + +	/* +	 * Clamp the width & height into the visible area.  Note we don't +	 * try to scale the source if part of the visible region is offscreen. +	 * The caller must handle that by adjusting source offset and size. +	 */ +	if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) { +		crtc_w += crtc_x; +		crtc_x = 0; +	} +	if ((crtc_x + crtc_w) <= 0) /* Nothing to display */ +		goto out; +	if ((crtc_x + crtc_w) > primary_w) +		crtc_w = primary_w - crtc_x; + +	if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) { +		crtc_h += crtc_y; +		crtc_y = 0; +	} +	if ((crtc_y + crtc_h) <= 0) /* Nothing to display */ +		goto out; +	if (crtc_y + crtc_h > primary_h) +		crtc_h = primary_h - crtc_y; + +	if (!crtc_w || !crtc_h) /* Again, nothing to display */ +		goto out; + +	/* +	 * We can take a larger source and scale it down, but +	 * only so much...  16x is the max on SNB. +	 */ +	if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale) +		return -EINVAL; + +	/* +	 * If the sprite is completely covering the primary plane, +	 * we can disable the primary and save power. +	 */ +	if ((crtc_x == 0) && (crtc_y == 0) && +	    (crtc_w == primary_w) && (crtc_h == primary_h)) +		disable_primary = true; + +	mutex_lock(&dev->struct_mutex); + +	ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); +	if (ret) +		goto out_unlock; + +	intel_plane->obj = obj; + +	/* +	 * Be sure to re-enable the primary before the sprite is no longer +	 * covering it fully. +	 */ +	if (!disable_primary && intel_plane->primary_disabled) { +		intel_enable_primary(crtc); +		intel_plane->primary_disabled = false; +	} + +	intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y, +				  crtc_w, crtc_h, x, y, src_w, src_h); + +	if (disable_primary) { +		intel_disable_primary(crtc); +		intel_plane->primary_disabled = true; +	} + +	/* Unpin old obj after new one is active to avoid ugliness */ +	if (old_obj) { +		/* +		 * It's fairly common to simply update the position of +		 * an existing object.  In that case, we don't need to +		 * wait for vblank to avoid ugliness, we only need to +		 * do the pin & ref bookkeeping. +		 */ +		if (old_obj != obj) { +			mutex_unlock(&dev->struct_mutex); +			intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); +			mutex_lock(&dev->struct_mutex); +		} +		i915_gem_object_unpin(old_obj); +	} + +out_unlock: +	mutex_unlock(&dev->struct_mutex); +out: +	return ret; +} + +static int +intel_disable_plane(struct drm_plane *plane) +{ +	struct drm_device *dev = plane->dev; +	struct intel_plane *intel_plane = to_intel_plane(plane); +	int ret = 0; + +	if (intel_plane->primary_disabled) { +		intel_enable_primary(plane->crtc); +		intel_plane->primary_disabled = false; +	} + +	intel_plane->disable_plane(plane); + +	if (!intel_plane->obj) +		goto out; + +	mutex_lock(&dev->struct_mutex); +	i915_gem_object_unpin(intel_plane->obj); +	intel_plane->obj = NULL; +	mutex_unlock(&dev->struct_mutex); +out: + +	return ret; +} + +static void intel_destroy_plane(struct drm_plane *plane) +{ +	struct intel_plane *intel_plane = to_intel_plane(plane); +	intel_disable_plane(plane); +	drm_plane_cleanup(plane); +	kfree(intel_plane); +} + +int intel_sprite_set_colorkey(struct drm_device *dev, void *data, +			      struct drm_file *file_priv) +{ +	struct drm_intel_sprite_colorkey *set = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_mode_object *obj; +	struct drm_plane *plane; +	struct intel_plane *intel_plane; +	int ret = 0; + +	if (!dev_priv) +		return -EINVAL; + +	/* Make sure we don't try to enable both src & dest simultaneously */ +	if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) +		return -EINVAL; + +	mutex_lock(&dev->mode_config.mutex); + +	obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); +	if (!obj) { +		ret = -EINVAL; +		goto out_unlock; +	} + +	plane = obj_to_plane(obj); +	intel_plane = to_intel_plane(plane); +	ret = intel_plane->update_colorkey(plane, set); + +out_unlock: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +int intel_sprite_get_colorkey(struct drm_device *dev, void *data, +			      struct drm_file *file_priv) +{ +	struct drm_intel_sprite_colorkey *get = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_mode_object *obj; +	struct drm_plane *plane; +	struct intel_plane *intel_plane; +	int ret = 0; + +	if (!dev_priv) +		return -EINVAL; + +	mutex_lock(&dev->mode_config.mutex); + +	obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); +	if (!obj) { +		ret = -EINVAL; +		goto out_unlock; +	} + +	plane = obj_to_plane(obj); +	intel_plane = to_intel_plane(plane); +	intel_plane->get_colorkey(plane, get); + +out_unlock: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +static const struct drm_plane_funcs intel_plane_funcs = { +	.update_plane = intel_update_plane, +	.disable_plane = intel_disable_plane, +	.destroy = intel_destroy_plane, +}; + +static uint32_t snb_plane_formats[] = { +	DRM_FORMAT_XBGR8888, +	DRM_FORMAT_XRGB8888, +	DRM_FORMAT_YUYV, +	DRM_FORMAT_YVYU, +	DRM_FORMAT_UYVY, +	DRM_FORMAT_VYUY, +}; + +int +intel_plane_init(struct drm_device *dev, enum pipe pipe) +{ +	struct intel_plane *intel_plane; +	unsigned long possible_crtcs; +	int ret; + +	if (!(IS_GEN6(dev) || IS_GEN7(dev))) +		return -ENODEV; + +	intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL); +	if (!intel_plane) +		return -ENOMEM; + +	if (IS_GEN6(dev)) { +		intel_plane->max_downscale = 16; +		intel_plane->update_plane = snb_update_plane; +		intel_plane->disable_plane = snb_disable_plane; +		intel_plane->update_colorkey = snb_update_colorkey; +		intel_plane->get_colorkey = snb_get_colorkey; +	} else if (IS_GEN7(dev)) { +		intel_plane->max_downscale = 2; +		intel_plane->update_plane = ivb_update_plane; +		intel_plane->disable_plane = ivb_disable_plane; +		intel_plane->update_colorkey = ivb_update_colorkey; +		intel_plane->get_colorkey = ivb_get_colorkey; +	} + +	intel_plane->pipe = pipe; +	possible_crtcs = (1 << pipe); +	ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, +			     &intel_plane_funcs, snb_plane_formats, +			     ARRAY_SIZE(snb_plane_formats), false); +	if (ret) +		kfree(intel_plane); + +	return ret; +} +  | 
