diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_sprite.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_sprite.c | 197 | 
1 files changed, 116 insertions, 81 deletions
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index ad6ec4b39005..b9fabf826f7d 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -260,14 +260,14 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  	if (obj->tiling_mode != I915_TILING_NONE)  		sprctl |= SPRITE_TILED; -	if (IS_HASWELL(dev)) +	if (IS_HASWELL(dev) || IS_BROADWELL(dev))  		sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE;  	else  		sprctl |= SPRITE_TRICKLE_FEED_DISABLE;  	sprctl |= SPRITE_ENABLE; -	if (IS_HASWELL(dev)) +	if (IS_HASWELL(dev) || IS_BROADWELL(dev))  		sprctl |= SPRITE_PIPE_CSC_ENABLE;  	intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true, @@ -288,7 +288,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  		dev_priv->sprite_scaling_enabled |= 1 << pipe;  		if (!scaling_was_enabled) { -			intel_update_watermarks(dev); +			intel_update_watermarks(crtc);  			intel_wait_for_vblank(dev, pipe);  		}  		sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; @@ -306,7 +306,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  	/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET  	 * register */ -	if (IS_HASWELL(dev)) +	if (IS_HASWELL(dev) || IS_BROADWELL(dev))  		I915_WRITE(SPROFFSET(pipe), (y << 16) | x);  	else if (obj->tiling_mode != I915_TILING_NONE)  		I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); @@ -323,7 +323,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  	/* potentially re-enable LP watermarks */  	if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) -		intel_update_watermarks(dev); +		intel_update_watermarks(crtc);  }  static void @@ -349,7 +349,7 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)  	/* potentially re-enable LP watermarks */  	if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) -		intel_update_watermarks(dev); +		intel_update_watermarks(crtc);  }  static int @@ -521,13 +521,28 @@ intel_enable_primary(struct drm_crtc *crtc)  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);  	int reg = DSPCNTR(intel_crtc->plane); -	if (!intel_crtc->primary_disabled) +	if (intel_crtc->primary_enabled)  		return; -	intel_crtc->primary_disabled = false; -	intel_update_fbc(dev); +	intel_crtc->primary_enabled = true;  	I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); +	intel_flush_primary_plane(dev_priv, intel_crtc->plane); + +	/* +	 * FIXME IPS should be fine as long as one plane is +	 * enabled, but in practice it seems to have problems +	 * when going from primary only to sprite only and vice +	 * versa. +	 */ +	if (intel_crtc->config.ips_enabled) { +		intel_wait_for_vblank(dev, intel_crtc->pipe); +		hsw_enable_ips(intel_crtc); +	} + +	mutex_lock(&dev->struct_mutex); +	intel_update_fbc(dev); +	mutex_unlock(&dev->struct_mutex);  }  static void @@ -538,13 +553,26 @@ intel_disable_primary(struct drm_crtc *crtc)  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);  	int reg = DSPCNTR(intel_crtc->plane); -	if (intel_crtc->primary_disabled) +	if (!intel_crtc->primary_enabled)  		return; -	I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); +	intel_crtc->primary_enabled = false; -	intel_crtc->primary_disabled = true; -	intel_update_fbc(dev); +	mutex_lock(&dev->struct_mutex); +	if (dev_priv->fbc.plane == intel_crtc->plane) +		intel_disable_fbc(dev); +	mutex_unlock(&dev->struct_mutex); + +	/* +	 * FIXME IPS should be fine as long as one plane is +	 * enabled, but in practice it seems to have problems +	 * when going from primary only to sprite only and vice +	 * versa. +	 */ +	hsw_disable_ips(intel_crtc); + +	I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); +	intel_flush_primary_plane(dev_priv, intel_crtc->plane);  }  static int @@ -623,15 +651,12 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  		   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; -	enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, -								      pipe); -	int ret = 0; +	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); +	struct drm_i915_gem_object *obj = intel_fb->obj; +	struct drm_i915_gem_object *old_obj = intel_plane->obj; +	int ret;  	bool disable_primary = false;  	bool visible;  	int hscale, vscale; @@ -652,29 +677,23 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  		.y2 = crtc_y + crtc_h,  	};  	const struct drm_rect clip = { -		.x2 = crtc->mode.hdisplay, -		.y2 = crtc->mode.vdisplay, +		.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0, +		.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0, +	}; +	const struct { +		int crtc_x, crtc_y; +		unsigned int crtc_w, crtc_h; +		uint32_t src_x, src_y, src_w, src_h; +	} orig = { +		.crtc_x = crtc_x, +		.crtc_y = crtc_y, +		.crtc_w = crtc_w, +		.crtc_h = crtc_h, +		.src_x = src_x, +		.src_y = src_y, +		.src_w = src_w, +		.src_h = src_h,  	}; - -	intel_fb = to_intel_framebuffer(fb); -	obj = intel_fb->obj; - -	old_obj = intel_plane->obj; - -	intel_plane->crtc_x = crtc_x; -	intel_plane->crtc_y = crtc_y; -	intel_plane->crtc_w = crtc_w; -	intel_plane->crtc_h = crtc_h; -	intel_plane->src_x = src_x; -	intel_plane->src_y = src_y; -	intel_plane->src_w = src_w; -	intel_plane->src_h = src_h; - -	/* Pipe must be running... */ -	if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE)) { -		DRM_DEBUG_KMS("Pipe disabled\n"); -		return -EINVAL; -	}  	/* Don't modify another pipe's plane */  	if (intel_plane->pipe != intel_crtc->pipe) { @@ -810,7 +829,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  	 * we can disable the primary and save power.  	 */  	disable_primary = drm_rect_equals(&dst, &clip); -	WARN_ON(disable_primary && !visible); +	WARN_ON(disable_primary && !visible && intel_crtc->active);  	mutex_lock(&dev->struct_mutex); @@ -820,27 +839,40 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  	 * the sprite planes only require 128KiB alignment and 32 PTE padding.  	 */  	ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); + +	mutex_unlock(&dev->struct_mutex); +  	if (ret) -		goto out_unlock; +		return ret; +	intel_plane->crtc_x = orig.crtc_x; +	intel_plane->crtc_y = orig.crtc_y; +	intel_plane->crtc_w = orig.crtc_w; +	intel_plane->crtc_h = orig.crtc_h; +	intel_plane->src_x = orig.src_x; +	intel_plane->src_y = orig.src_y; +	intel_plane->src_w = orig.src_w; +	intel_plane->src_h = orig.src_h;  	intel_plane->obj = obj; -	/* -	 * Be sure to re-enable the primary before the sprite is no longer -	 * covering it fully. -	 */ -	if (!disable_primary) -		intel_enable_primary(crtc); +	if (intel_crtc->active) { +		/* +		 * Be sure to re-enable the primary before the sprite is no longer +		 * covering it fully. +		 */ +		if (!disable_primary) +			intel_enable_primary(crtc); -	if (visible) -		intel_plane->update_plane(plane, crtc, fb, obj, -					  crtc_x, crtc_y, crtc_w, crtc_h, -					  src_x, src_y, src_w, src_h); -	else -		intel_plane->disable_plane(plane, crtc); +		if (visible) +			intel_plane->update_plane(plane, crtc, fb, obj, +						  crtc_x, crtc_y, crtc_w, crtc_h, +						  src_x, src_y, src_w, src_h); +		else +			intel_plane->disable_plane(plane, crtc); -	if (disable_primary) -		intel_disable_primary(crtc); +		if (disable_primary) +			intel_disable_primary(crtc); +	}  	/* Unpin old obj after new one is active to avoid ugliness */  	if (old_obj) { @@ -850,17 +882,15 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,  		 * 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); -		} +		if (old_obj != obj && intel_crtc->active) +			intel_wait_for_vblank(dev, intel_crtc->pipe); + +		mutex_lock(&dev->struct_mutex);  		intel_unpin_fb_obj(old_obj); +		mutex_unlock(&dev->struct_mutex);  	} -out_unlock: -	mutex_unlock(&dev->struct_mutex); -	return ret; +	return 0;  }  static int @@ -868,7 +898,7 @@ 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; +	struct intel_crtc *intel_crtc;  	if (!plane->fb)  		return 0; @@ -876,21 +906,25 @@ intel_disable_plane(struct drm_plane *plane)  	if (WARN_ON(!plane->crtc))  		return -EINVAL; -	intel_enable_primary(plane->crtc); -	intel_plane->disable_plane(plane, plane->crtc); +	intel_crtc = to_intel_crtc(plane->crtc); -	if (!intel_plane->obj) -		goto out; +	if (intel_crtc->active) { +		intel_enable_primary(plane->crtc); +		intel_plane->disable_plane(plane, plane->crtc); +	} -	intel_wait_for_vblank(dev, intel_plane->pipe); +	if (intel_plane->obj) { +		if (intel_crtc->active) +			intel_wait_for_vblank(dev, intel_plane->pipe); -	mutex_lock(&dev->struct_mutex); -	intel_unpin_fb_obj(intel_plane->obj); -	intel_plane->obj = NULL; -	mutex_unlock(&dev->struct_mutex); -out: +		mutex_lock(&dev->struct_mutex); +		intel_unpin_fb_obj(intel_plane->obj); +		mutex_unlock(&dev->struct_mutex); -	return ret; +		intel_plane->obj = NULL; +	} + +	return 0;  }  static void intel_destroy_plane(struct drm_plane *plane) @@ -921,7 +955,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,  	obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);  	if (!obj) { -		ret = -EINVAL; +		ret = -ENOENT;  		goto out_unlock;  	} @@ -950,7 +984,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,  	obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE);  	if (!obj) { -		ret = -EINVAL; +		ret = -ENOENT;  		goto out_unlock;  	} @@ -1034,7 +1068,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)  	if (INTEL_INFO(dev)->gen < 5)  		return -ENODEV; -	intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL); +	intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL);  	if (!intel_plane)  		return -ENOMEM; @@ -1058,6 +1092,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)  		break;  	case 7: +	case 8:  		if (IS_IVYBRIDGE(dev)) {  			intel_plane->can_scale = true;  			intel_plane->max_downscale = 2;  | 
