diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_sprite.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_sprite.c | 101 | 
1 files changed, 62 insertions, 39 deletions
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 82f5e5c7009..827dcd4edf1 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -48,7 +48,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,  	struct intel_plane *intel_plane = to_intel_plane(plane);  	int pipe = intel_plane->pipe;  	u32 sprctl, sprscale = 0; -	int pixel_size; +	unsigned long sprsurf_offset, linear_offset; +	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);  	sprctl = I915_READ(SPRCTL(pipe)); @@ -61,33 +62,24 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,  	switch (fb->pixel_format) {  	case DRM_FORMAT_XBGR8888:  		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; -		pixel_size = 4;  		break;  	case DRM_FORMAT_XRGB8888:  		sprctl |= SPRITE_FORMAT_RGBX888; -		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 |= SPRITE_FORMAT_RGBX888; -		pixel_size = 4; -		break; +		BUG();  	}  	if (obj->tiling_mode != I915_TILING_NONE) @@ -127,18 +119,28 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,  	I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);  	I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); -	if (obj->tiling_mode != I915_TILING_NONE) { + +	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); +	sprsurf_offset = +		intel_gen4_compute_offset_xtiled(&x, &y, +						 fb->bits_per_pixel / 8, +						 fb->pitches[0]); +	linear_offset -= sprsurf_offset; + +	/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET +	 * register */ +	if (IS_HASWELL(dev)) +		I915_WRITE(SPROFFSET(pipe), (y << 16) | x); +	else if (obj->tiling_mode != I915_TILING_NONE)  		I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); -	} else { -		unsigned long offset; +	else +		I915_WRITE(SPRLINOFF(pipe), linear_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); +	if (intel_plane->can_scale) +		I915_WRITE(SPRSCALE(pipe), sprscale);  	I915_WRITE(SPRCTL(pipe), sprctl); -	I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset); +	I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset);  	POSTING_READ(SPRSURF(pipe));  } @@ -152,7 +154,8 @@ ivb_disable_plane(struct drm_plane *plane)  	I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);  	/* Can't leave the scaler enabled... */ -	I915_WRITE(SPRSCALE(pipe), 0); +	if (intel_plane->can_scale) +		I915_WRITE(SPRSCALE(pipe), 0);  	/* Activate double buffered register update */  	I915_MODIFY_DISPBASE(SPRSURF(pipe), 0);  	POSTING_READ(SPRSURF(pipe)); @@ -225,8 +228,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,  	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; +	int pipe = intel_plane->pipe; +	unsigned long dvssurf_offset, linear_offset;  	u32 dvscntr, dvsscale; +	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);  	dvscntr = I915_READ(DVSCNTR(pipe)); @@ -239,33 +244,24 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,  	switch (fb->pixel_format) {  	case DRM_FORMAT_XBGR8888:  		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; -		pixel_size = 4;  		break;  	case DRM_FORMAT_XRGB8888:  		dvscntr |= DVS_FORMAT_RGBX888; -		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; +		BUG();  	}  	if (obj->tiling_mode != I915_TILING_NONE) @@ -289,18 +285,23 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,  	I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);  	I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); -	if (obj->tiling_mode != I915_TILING_NONE) { + +	linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); +	dvssurf_offset = +		intel_gen4_compute_offset_xtiled(&x, &y, +						 fb->bits_per_pixel / 8, +						 fb->pitches[0]); +	linear_offset -= dvssurf_offset; + +	if (obj->tiling_mode != I915_TILING_NONE)  		I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); -	} else { -		unsigned long offset; +	else +		I915_WRITE(DVSLINOFF(pipe), linear_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_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset); +	I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset + dvssurf_offset);  	POSTING_READ(DVSSURF(pipe));  } @@ -422,6 +423,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  	struct intel_framebuffer *intel_fb;  	struct drm_i915_gem_object *obj, *old_obj;  	int pipe = intel_plane->pipe; +	enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, +								      pipe);  	int ret = 0;  	int x = src_x >> 16, y = src_y >> 16;  	int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay; @@ -436,7 +439,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  	src_h = src_h >> 16;  	/* Pipe must be running... */ -	if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE)) +	if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE))  		return -EINVAL;  	if (crtc_x >= primary_w || crtc_y >= primary_h) @@ -446,6 +449,15 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  	if (intel_plane->pipe != intel_crtc->pipe)  		return -EINVAL; +	/* Sprite planes can be linear or x-tiled surfaces */ +	switch (obj->tiling_mode) { +		case I915_TILING_NONE: +		case I915_TILING_X: +			break; +		default: +			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. @@ -473,6 +485,12 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  		goto out;  	/* +	 * We may not have a scaler, eg. HSW does not have it any more +	 */ +	if (!intel_plane->can_scale && (crtc_w != src_w || crtc_h != src_h)) +		return -EINVAL; + +	/*  	 * We can take a larger source and scale it down, but  	 * only so much...  16x is the max on SNB.  	 */ @@ -665,6 +683,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)  	switch (INTEL_INFO(dev)->gen) {  	case 5:  	case 6: +		intel_plane->can_scale = true;  		intel_plane->max_downscale = 16;  		intel_plane->update_plane = ilk_update_plane;  		intel_plane->disable_plane = ilk_disable_plane; @@ -681,6 +700,10 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)  		break;  	case 7: +		if (IS_HASWELL(dev) || IS_VALLEYVIEW(dev)) +			intel_plane->can_scale = false; +		else +			intel_plane->can_scale = true;  		intel_plane->max_downscale = 2;  		intel_plane->update_plane = ivb_update_plane;  		intel_plane->disable_plane = ivb_disable_plane;  |