diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_pm.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_pm.c | 171 | 
1 files changed, 151 insertions, 20 deletions
| diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 496caa73eb70..e83a11794172 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -44,6 +44,14 @@   * i915.i915_enable_fbc parameter   */ +static bool intel_crtc_active(struct drm_crtc *crtc) +{ +	/* Be paranoid as we can arrive here with only partial +	 * state retrieved from the hardware during setup. +	 */ +	return to_intel_crtc(crtc)->active && crtc->fb && crtc->mode.clock; +} +  static void i8xx_disable_fbc(struct drm_device *dev)  {  	struct drm_i915_private *dev_priv = dev->dev_private; @@ -405,9 +413,8 @@ void intel_update_fbc(struct drm_device *dev)  	 *   - going to an unsupported config (interlace, pixel multiply, etc.)  	 */  	list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { -		if (tmp_crtc->enabled && -		    !to_intel_crtc(tmp_crtc)->primary_disabled && -		    tmp_crtc->fb) { +		if (intel_crtc_active(tmp_crtc) && +		    !to_intel_crtc(tmp_crtc)->primary_disabled) {  			if (crtc) {  				DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");  				dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; @@ -992,7 +999,7 @@ static struct drm_crtc *single_enabled_crtc(struct drm_device *dev)  	struct drm_crtc *crtc, *enabled = NULL;  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -		if (crtc->enabled && crtc->fb) { +		if (intel_crtc_active(crtc)) {  			if (enabled)  				return NULL;  			enabled = crtc; @@ -1086,7 +1093,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,  	int entries, tlb_miss;  	crtc = intel_get_crtc_for_plane(dev, plane); -	if (crtc->fb == NULL || !crtc->enabled) { +	if (!intel_crtc_active(crtc)) {  		*cursor_wm = cursor->guard_size;  		*plane_wm = display->guard_size;  		return false; @@ -1215,7 +1222,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev,  	int entries;  	crtc = intel_get_crtc_for_plane(dev, plane); -	if (crtc->fb == NULL || !crtc->enabled) +	if (!intel_crtc_active(crtc))  		return false;  	clock = crtc->mode.clock;	/* VESA DOT Clock */ @@ -1286,6 +1293,7 @@ static void valleyview_update_wm(struct drm_device *dev)  	struct drm_i915_private *dev_priv = dev->dev_private;  	int planea_wm, planeb_wm, cursora_wm, cursorb_wm;  	int plane_sr, cursor_sr; +	int ignore_plane_sr, ignore_cursor_sr;  	unsigned int enabled = 0;  	vlv_update_drain_latency(dev); @@ -1302,17 +1310,23 @@ static void valleyview_update_wm(struct drm_device *dev)  			    &planeb_wm, &cursorb_wm))  		enabled |= 2; -	plane_sr = cursor_sr = 0;  	if (single_plane_enabled(enabled) &&  	    g4x_compute_srwm(dev, ffs(enabled) - 1,  			     sr_latency_ns,  			     &valleyview_wm_info,  			     &valleyview_cursor_wm_info, -			     &plane_sr, &cursor_sr)) +			     &plane_sr, &ignore_cursor_sr) && +	    g4x_compute_srwm(dev, ffs(enabled) - 1, +			     2*sr_latency_ns, +			     &valleyview_wm_info, +			     &valleyview_cursor_wm_info, +			     &ignore_plane_sr, &cursor_sr)) {  		I915_WRITE(FW_BLC_SELF_VLV, FW_CSPWRDWNEN); -	else +	} else {  		I915_WRITE(FW_BLC_SELF_VLV,  			   I915_READ(FW_BLC_SELF_VLV) & ~FW_CSPWRDWNEN); +		plane_sr = cursor_sr = 0; +	}  	DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",  		      planea_wm, cursora_wm, @@ -1352,17 +1366,18 @@ static void g4x_update_wm(struct drm_device *dev)  			    &planeb_wm, &cursorb_wm))  		enabled |= 2; -	plane_sr = cursor_sr = 0;  	if (single_plane_enabled(enabled) &&  	    g4x_compute_srwm(dev, ffs(enabled) - 1,  			     sr_latency_ns,  			     &g4x_wm_info,  			     &g4x_cursor_wm_info, -			     &plane_sr, &cursor_sr)) +			     &plane_sr, &cursor_sr)) {  		I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); -	else +	} else {  		I915_WRITE(FW_BLC_SELF,  			   I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN); +		plane_sr = cursor_sr = 0; +	}  	DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",  		      planea_wm, cursora_wm, @@ -1468,7 +1483,7 @@ static void i9xx_update_wm(struct drm_device *dev)  	fifo_size = dev_priv->display.get_fifo_size(dev, 0);  	crtc = intel_get_crtc_for_plane(dev, 0); -	if (crtc->enabled && crtc->fb) { +	if (intel_crtc_active(crtc)) {  		int cpp = crtc->fb->bits_per_pixel / 8;  		if (IS_GEN2(dev))  			cpp = 4; @@ -1482,7 +1497,7 @@ static void i9xx_update_wm(struct drm_device *dev)  	fifo_size = dev_priv->display.get_fifo_size(dev, 1);  	crtc = intel_get_crtc_for_plane(dev, 1); -	if (crtc->enabled && crtc->fb) { +	if (intel_crtc_active(crtc)) {  		int cpp = crtc->fb->bits_per_pixel / 8;  		if (IS_GEN2(dev))  			cpp = 4; @@ -1811,8 +1826,110 @@ static void sandybridge_update_wm(struct drm_device *dev)  		enabled |= 2;  	} -	if ((dev_priv->num_pipe == 3) && -	    g4x_compute_wm0(dev, 2, +	/* +	 * Calculate and update the self-refresh watermark only when one +	 * display plane is used. +	 * +	 * SNB support 3 levels of watermark. +	 * +	 * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, +	 * and disabled in the descending order +	 * +	 */ +	I915_WRITE(WM3_LP_ILK, 0); +	I915_WRITE(WM2_LP_ILK, 0); +	I915_WRITE(WM1_LP_ILK, 0); + +	if (!single_plane_enabled(enabled) || +	    dev_priv->sprite_scaling_enabled) +		return; +	enabled = ffs(enabled) - 1; + +	/* WM1 */ +	if (!ironlake_compute_srwm(dev, 1, enabled, +				   SNB_READ_WM1_LATENCY() * 500, +				   &sandybridge_display_srwm_info, +				   &sandybridge_cursor_srwm_info, +				   &fbc_wm, &plane_wm, &cursor_wm)) +		return; + +	I915_WRITE(WM1_LP_ILK, +		   WM1_LP_SR_EN | +		   (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | +		   (fbc_wm << WM1_LP_FBC_SHIFT) | +		   (plane_wm << WM1_LP_SR_SHIFT) | +		   cursor_wm); + +	/* WM2 */ +	if (!ironlake_compute_srwm(dev, 2, enabled, +				   SNB_READ_WM2_LATENCY() * 500, +				   &sandybridge_display_srwm_info, +				   &sandybridge_cursor_srwm_info, +				   &fbc_wm, &plane_wm, &cursor_wm)) +		return; + +	I915_WRITE(WM2_LP_ILK, +		   WM2_LP_EN | +		   (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | +		   (fbc_wm << WM1_LP_FBC_SHIFT) | +		   (plane_wm << WM1_LP_SR_SHIFT) | +		   cursor_wm); + +	/* WM3 */ +	if (!ironlake_compute_srwm(dev, 3, enabled, +				   SNB_READ_WM3_LATENCY() * 500, +				   &sandybridge_display_srwm_info, +				   &sandybridge_cursor_srwm_info, +				   &fbc_wm, &plane_wm, &cursor_wm)) +		return; + +	I915_WRITE(WM3_LP_ILK, +		   WM3_LP_EN | +		   (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) | +		   (fbc_wm << WM1_LP_FBC_SHIFT) | +		   (plane_wm << WM1_LP_SR_SHIFT) | +		   cursor_wm); +} + +static void ivybridge_update_wm(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	int latency = SNB_READ_WM0_LATENCY() * 100;	/* In unit 0.1us */ +	u32 val; +	int fbc_wm, plane_wm, cursor_wm; +	int ignore_fbc_wm, ignore_plane_wm, ignore_cursor_wm; +	unsigned int enabled; + +	enabled = 0; +	if (g4x_compute_wm0(dev, 0, +			    &sandybridge_display_wm_info, latency, +			    &sandybridge_cursor_wm_info, latency, +			    &plane_wm, &cursor_wm)) { +		val = I915_READ(WM0_PIPEA_ILK); +		val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); +		I915_WRITE(WM0_PIPEA_ILK, val | +			   ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); +		DRM_DEBUG_KMS("FIFO watermarks For pipe A -" +			      " plane %d, " "cursor: %d\n", +			      plane_wm, cursor_wm); +		enabled |= 1; +	} + +	if (g4x_compute_wm0(dev, 1, +			    &sandybridge_display_wm_info, latency, +			    &sandybridge_cursor_wm_info, latency, +			    &plane_wm, &cursor_wm)) { +		val = I915_READ(WM0_PIPEB_ILK); +		val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); +		I915_WRITE(WM0_PIPEB_ILK, val | +			   ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); +		DRM_DEBUG_KMS("FIFO watermarks For pipe B -" +			      " plane %d, cursor: %d\n", +			      plane_wm, cursor_wm); +		enabled |= 2; +	} + +	if (g4x_compute_wm0(dev, 2,  			    &sandybridge_display_wm_info, latency,  			    &sandybridge_cursor_wm_info, latency,  			    &plane_wm, &cursor_wm)) { @@ -1875,12 +1992,17 @@ static void sandybridge_update_wm(struct drm_device *dev)  		   (plane_wm << WM1_LP_SR_SHIFT) |  		   cursor_wm); -	/* WM3 */ +	/* WM3, note we have to correct the cursor latency */  	if (!ironlake_compute_srwm(dev, 3, enabled,  				   SNB_READ_WM3_LATENCY() * 500,  				   &sandybridge_display_srwm_info,  				   &sandybridge_cursor_srwm_info, -				   &fbc_wm, &plane_wm, &cursor_wm)) +				   &fbc_wm, &plane_wm, &ignore_cursor_wm) || +	    !ironlake_compute_srwm(dev, 3, enabled, +				   2 * SNB_READ_WM3_LATENCY() * 500, +				   &sandybridge_display_srwm_info, +				   &sandybridge_cursor_srwm_info, +				   &ignore_fbc_wm, &ignore_plane_wm, &cursor_wm))  		return;  	I915_WRITE(WM3_LP_ILK, @@ -1929,7 +2051,7 @@ sandybridge_compute_sprite_wm(struct drm_device *dev, int plane,  	int entries, tlb_miss;  	crtc = intel_get_crtc_for_plane(dev, plane); -	if (crtc->fb == NULL || !crtc->enabled) { +	if (!intel_crtc_active(crtc)) {  		*sprite_wm = display->guard_size;  		return false;  	} @@ -3471,6 +3593,15 @@ static void gen6_init_clock_gating(struct drm_device *dev)  		   I915_READ(ILK_DISPLAY_CHICKEN2) |  		   ILK_ELPIN_409_SELECT); +	/* WaDisableHiZPlanesWhenMSAAEnabled */ +	I915_WRITE(_3D_CHICKEN, +		   _MASKED_BIT_ENABLE(_3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB)); + +	/* WaSetupGtModeTdRowDispatch */ +	if (IS_SNB_GT1(dev)) +		I915_WRITE(GEN6_GT_MODE, +			   _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE)); +  	I915_WRITE(WM3_LP_ILK, 0);  	I915_WRITE(WM2_LP_ILK, 0);  	I915_WRITE(WM1_LP_ILK, 0); @@ -3999,7 +4130,7 @@ void intel_init_pm(struct drm_device *dev)  		} else if (IS_IVYBRIDGE(dev)) {  			/* FIXME: detect B0+ stepping and use auto training */  			if (SNB_READ_WM0_LATENCY()) { -				dev_priv->display.update_wm = sandybridge_update_wm; +				dev_priv->display.update_wm = ivybridge_update_wm;  				dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;  			} else {  				DRM_DEBUG_KMS("Failed to read display plane latency. " |