diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 161 | 
1 files changed, 86 insertions, 75 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bbdd72909a11..a2834276cb38 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -90,12 +90,12 @@ typedef struct {  #define I9XX_DOT_MAX		 400000  #define I9XX_VCO_MIN		1400000  #define I9XX_VCO_MAX		2800000 -#define I9XX_N_MIN		      3 -#define I9XX_N_MAX		      8 +#define I9XX_N_MIN		      1 +#define I9XX_N_MAX		      6  #define I9XX_M_MIN		     70  #define I9XX_M_MAX		    120  #define I9XX_M1_MIN		     10 -#define I9XX_M1_MAX		     20 +#define I9XX_M1_MAX		     22  #define I9XX_M2_MIN		      5  #define I9XX_M2_MAX		      9  #define I9XX_P_SDVO_DAC_MIN	      5 @@ -189,9 +189,7 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)  	return limit;  } -/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ - -static void i8xx_clock(int refclk, intel_clock_t *clock) +static void intel_clock(int refclk, intel_clock_t *clock)  {  	clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);  	clock->p = clock->p1 * clock->p2; @@ -199,25 +197,6 @@ static void i8xx_clock(int refclk, intel_clock_t *clock)  	clock->dot = clock->vco / clock->p;  } -/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */ - -static void i9xx_clock(int refclk, intel_clock_t *clock) -{ -	clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); -	clock->p = clock->p1 * clock->p2; -	clock->vco = refclk * clock->m / (clock->n + 2); -	clock->dot = clock->vco / clock->p; -} - -static void intel_clock(struct drm_device *dev, int refclk, -			intel_clock_t *clock) -{ -	if (IS_I9XX(dev)) -		i9xx_clock (refclk, clock); -	else -		i8xx_clock (refclk, clock); -} -  /**   * Returns whether any output on the specified pipe is of the specified type   */ @@ -238,7 +217,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)      return false;  } -#define INTELPllInvalid(s)   { /* ErrorF (s) */; return false; } +#define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)  /**   * Returns whether the given set of divisors are valid for a given refclk with   * the given connectors. @@ -318,7 +297,7 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,  				     clock.p1 <= limit->p1.max; clock.p1++) {  					int this_err; -					intel_clock(dev, refclk, &clock); +					intel_clock(refclk, &clock);  					if (!intel_PLL_is_valid(crtc, &clock))  						continue; @@ -343,7 +322,7 @@ intel_wait_for_vblank(struct drm_device *dev)  	udelay(20000);  } -static void +static int  intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,  		    struct drm_framebuffer *old_fb)  { @@ -361,11 +340,21 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,  	int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;  	int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;  	u32 dspcntr, alignment; +	int ret;  	/* no fb bound */  	if (!crtc->fb) {  		DRM_DEBUG("No FB bound\n"); -		return; +		return 0; +	} + +	switch (pipe) { +	case 0: +	case 1: +		break; +	default: +		DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); +		return -EINVAL;  	}  	intel_fb = to_intel_framebuffer(crtc->fb); @@ -377,28 +366,30 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,  		alignment = 64 * 1024;  		break;  	case I915_TILING_X: -		if (IS_I9XX(dev)) -			alignment = 1024 * 1024; -		else -			alignment = 512 * 1024; +		/* pin() will align the object as required by fence */ +		alignment = 0;  		break;  	case I915_TILING_Y:  		/* FIXME: Is this true? */  		DRM_ERROR("Y tiled not allowed for scan out buffers\n"); -		return; +		return -EINVAL;  	default:  		BUG();  	} -	if (i915_gem_object_pin(intel_fb->obj, alignment)) -		return; - -	i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1); - -	Start = obj_priv->gtt_offset; -	Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); +	mutex_lock(&dev->struct_mutex); +	ret = i915_gem_object_pin(intel_fb->obj, alignment); +	if (ret != 0) { +		mutex_unlock(&dev->struct_mutex); +		return ret; +	} -	I915_WRITE(dspstride, crtc->fb->pitch); +	ret = i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1); +	if (ret != 0) { +		i915_gem_object_unpin(intel_fb->obj); +		mutex_unlock(&dev->struct_mutex); +		return ret; +	}  	dspcntr = I915_READ(dspcntr_reg);  	/* Mask out pixel format bits in case we change it */ @@ -419,11 +410,17 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,  		break;  	default:  		DRM_ERROR("Unknown color depth\n"); -		return; +		i915_gem_object_unpin(intel_fb->obj); +		mutex_unlock(&dev->struct_mutex); +		return -EINVAL;  	}  	I915_WRITE(dspcntr_reg, dspcntr); +	Start = obj_priv->gtt_offset; +	Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); +  	DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); +	I915_WRITE(dspstride, crtc->fb->pitch);  	if (IS_I965G(dev)) {  		I915_WRITE(dspbase, Offset);  		I915_READ(dspbase); @@ -440,27 +437,24 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,  		intel_fb = to_intel_framebuffer(old_fb);  		i915_gem_object_unpin(intel_fb->obj);  	} +	mutex_unlock(&dev->struct_mutex);  	if (!dev->primary->master) -		return; +		return 0;  	master_priv = dev->primary->master->driver_priv;  	if (!master_priv->sarea_priv) -		return; +		return 0; -	switch (pipe) { -	case 0: -		master_priv->sarea_priv->pipeA_x = x; -		master_priv->sarea_priv->pipeA_y = y; -		break; -	case 1: +	if (pipe) {  		master_priv->sarea_priv->pipeB_x = x;  		master_priv->sarea_priv->pipeB_y = y; -		break; -	default: -		DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); -		break; +	} else { +		master_priv->sarea_priv->pipeA_x = x; +		master_priv->sarea_priv->pipeA_y = y;  	} + +	return 0;  } @@ -708,11 +702,11 @@ static int intel_panel_fitter_pipe (struct drm_device *dev)  	return 1;  } -static void intel_crtc_mode_set(struct drm_crtc *crtc, -				struct drm_display_mode *mode, -				struct drm_display_mode *adjusted_mode, -				int x, int y, -				struct drm_framebuffer *old_fb) +static int intel_crtc_mode_set(struct drm_crtc *crtc, +			       struct drm_display_mode *mode, +			       struct drm_display_mode *adjusted_mode, +			       int x, int y, +			       struct drm_framebuffer *old_fb)  {  	struct drm_device *dev = crtc->dev;  	struct drm_i915_private *dev_priv = dev->dev_private; @@ -732,13 +726,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,  	int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;  	int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;  	int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; -	int refclk; +	int refclk, num_outputs = 0;  	intel_clock_t clock;  	u32 dpll = 0, fp = 0, dspcntr, pipeconf;  	bool ok, is_sdvo = false, is_dvo = false;  	bool is_crt = false, is_lvds = false, is_tv = false;  	struct drm_mode_config *mode_config = &dev->mode_config;  	struct drm_connector *connector; +	int ret;  	drm_vblank_pre_modeset(dev, pipe); @@ -768,9 +763,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,  			is_crt = true;  			break;  		} + +		num_outputs++;  	} -	if (IS_I9XX(dev)) { +	if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2) { +		refclk = dev_priv->lvds_ssc_freq * 1000; +		DRM_DEBUG("using SSC reference clock of %d MHz\n", refclk / 1000); +	} else if (IS_I9XX(dev)) {  		refclk = 96000;  	} else {  		refclk = 48000; @@ -779,7 +779,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,  	ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock);  	if (!ok) {  		DRM_ERROR("Couldn't find PLL settings for mode!\n"); -		return; +		return -EINVAL;  	}  	fp = clock.n << 16 | clock.m1 << 8 | clock.m2; @@ -829,11 +829,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,  		}  	} -	if (is_tv) { +	if (is_sdvo && is_tv) +		dpll |= PLL_REF_INPUT_TVCLKINBC; +	else if (is_tv)  		/* XXX: just matching BIOS for now */ -/*	dpll |= PLL_REF_INPUT_TVCLKINBC; */ +		/*	dpll |= PLL_REF_INPUT_TVCLKINBC; */  		dpll |= 3; -	} +	else if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2) +		dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;  	else  		dpll |= PLL_REF_INPUT_DREFCLK; @@ -950,9 +953,13 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,  	I915_WRITE(dspcntr_reg, dspcntr);  	/* Flush the plane changes */ -	intel_pipe_set_base(crtc, x, y, old_fb); +	ret = intel_pipe_set_base(crtc, x, y, old_fb); +	if (ret != 0) +	    return ret;  	drm_vblank_post_modeset(dev, pipe); + +	return 0;  }  /** Loads the palette/gamma unit for the CRTC with the prepared values */ @@ -1001,6 +1008,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,  		temp = CURSOR_MODE_DISABLE;  		addr = 0;  		bo = NULL; +		mutex_lock(&dev->struct_mutex);  		goto finish;  	} @@ -1023,18 +1031,19 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,  	}  	/* we only need to pin inside GTT if cursor is non-phy */ +	mutex_lock(&dev->struct_mutex);  	if (!dev_priv->cursor_needs_physical) {  		ret = i915_gem_object_pin(bo, PAGE_SIZE);  		if (ret) {  			DRM_ERROR("failed to pin cursor bo\n"); -			goto fail; +			goto fail_locked;  		}  		addr = obj_priv->gtt_offset;  	} else {  		ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);  		if (ret) {  			DRM_ERROR("failed to attach phys object\n"); -			goto fail; +			goto fail_locked;  		}  		addr = obj_priv->phys_obj->handle->busaddr;  	} @@ -1054,10 +1063,9 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,  				i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);  		} else  			i915_gem_object_unpin(intel_crtc->cursor_bo); -		mutex_lock(&dev->struct_mutex);  		drm_gem_object_unreference(intel_crtc->cursor_bo); -		mutex_unlock(&dev->struct_mutex);  	} +	mutex_unlock(&dev->struct_mutex);  	intel_crtc->cursor_addr = addr;  	intel_crtc->cursor_bo = bo; @@ -1065,6 +1073,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,  	return 0;  fail:  	mutex_lock(&dev->struct_mutex); +fail_locked:  	drm_gem_object_unreference(bo);  	mutex_unlock(&dev->struct_mutex);  	return ret; @@ -1292,7 +1301,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)  		}  		/* XXX: Handle the 100Mhz refclk */ -		i9xx_clock(96000, &clock); +		intel_clock(96000, &clock);  	} else {  		bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN); @@ -1304,9 +1313,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)  			if ((dpll & PLL_REF_INPUT_MASK) ==  			    PLLB_REF_INPUT_SPREADSPECTRUMIN) {  				/* XXX: might not be 66MHz */ -				i8xx_clock(66000, &clock); +				intel_clock(66000, &clock);  			} else -				i8xx_clock(48000, &clock); +				intel_clock(48000, &clock);  		} else {  			if (dpll & PLL_P1_DIVIDE_BY_TWO)  				clock.p1 = 2; @@ -1319,7 +1328,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)  			else  				clock.p2 = 2; -			i8xx_clock(48000, &clock); +			intel_clock(48000, &clock);  		}  	} @@ -1598,7 +1607,9 @@ intel_user_framebuffer_create(struct drm_device *dev,  	ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj);  	if (ret) { +		mutex_lock(&dev->struct_mutex);  		drm_gem_object_unreference(obj); +		mutex_unlock(&dev->struct_mutex);  		return NULL;  	}  |