public inbox for intel-gfx@lists.freedesktop.org
 help / color / mirror / Atom feed
From: Daniel Vetter <daniel@ffwll.ch>
To: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: intel-gfx@lists.freedesktop.org
Subject: Re: [PATCH 1/7] drm/i915: ValleyView mode setting limits and PLL functions
Date: Wed, 13 Jun 2012 10:06:46 +0200	[thread overview]
Message-ID: <20120613080646.GB4829@phenom.ffwll.local> (raw)
In-Reply-To: <1339537655-5792-2-git-send-email-jbarnes@virtuousgeek.org>

On Tue, Jun 12, 2012 at 02:47:29PM -0700, Jesse Barnes wrote:
> Add some VLV limit structures and update the PLL code.
> 
> v2: resolve conflicts, Vijay to re-post with PLL valid checks and fixed limits
> v3: re-add dpio write function
> 
> Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com>
> Signed-off-by: Vijay Purushothaman <vijay.a.purushothaman@intel.com>

Your sob-line is missing, and iirc a few people puked over that
massively-nested pll computation loop. I dunno what we've ultimately
decided about it, though.
-Daniel

> ---
>  drivers/gpu/drm/i915/i915_reg.h      |    1 +
>  drivers/gpu/drm/i915/intel_display.c |  250 +++++++++++++++++++++++++++++++++-
>  2 files changed, 249 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 7dcc04f..281446d 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -900,6 +900,7 @@
>  #define   DPLL_P2_CLOCK_DIV_MASK	0x03000000 /* i915 */
>  #define   DPLL_FPA01_P1_POST_DIV_MASK	0x00ff0000 /* i915 */
>  #define   DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW	0x00ff8000 /* Pineview */
> +#define   DPLL_LOCK_VLV			(1<<15)
>  #define   DPLL_INTEGRATED_CLOCK_VLV	(1<<13)
>  
>  #define SRX_INDEX		0x3c4
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 0161d94..5006928 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -98,6 +98,11 @@ intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
>  			   int target, int refclk, intel_clock_t *match_clock,
>  			   intel_clock_t *best_clock);
>  
> +static bool
> +intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc,
> +			int target, int refclk, intel_clock_t *match_clock,
> +			intel_clock_t *best_clock);
> +
>  static inline u32 /* units of 100MHz */
>  intel_fdi_link_freq(struct drm_device *dev)
>  {
> @@ -359,6 +364,48 @@ static const intel_limit_t intel_limits_ironlake_display_port = {
>  	.find_pll = intel_find_pll_ironlake_dp,
>  };
>  
> +static const intel_limit_t intel_limits_vlv_dac = {
> +	.dot = { .min = 25000, .max = 270000 },
> +	.vco = { .min = 4000000, .max = 6000000 },
> +	.n = { .min = 1, .max = 7 },
> +	.m = { .min = 22, .max = 450 }, /* guess */
> +	.m1 = { .min = 2, .max = 3 },
> +	.m2 = { .min = 11, .max = 156 },
> +	.p = { .min = 10, .max = 30 },
> +	.p1 = { .min = 2, .max = 3 },
> +	.p2 = { .dot_limit = 270000,
> +		.p2_slow = 10, .p2_fast = 5 },
> +	.find_pll = intel_vlv_find_best_pll,
> +};
> +
> +static const intel_limit_t intel_limits_vlv_hdmi = {
> +	.dot = { .min = 20000, .max = 165000 },
> +	.vco = { .min = 5994000, .max = 4000000 },
> +	.n = { .min = 1, .max = 7 },
> +	.m = { .min = 60, .max = 300 }, /* guess */
> +	.m1 = { .min = 2, .max = 3 },
> +	.m2 = { .min = 11, .max = 156 },
> +	.p = { .min = 10, .max = 30 },
> +	.p1 = { .min = 2, .max = 3 },
> +	.p2 = { .dot_limit = 270000,
> +		.p2_slow = 10, .p2_fast = 5 },
> +	.find_pll = intel_vlv_find_best_pll,
> +};
> +
> +static const intel_limit_t intel_limits_vlv_dp = {
> +	.dot = { .min = 162000, .max = 270000 },
> +	.vco = { .min = 5994000, .max = 4000000 },
> +	.n = { .min = 1, .max = 7 },
> +	.m = { .min = 60, .max = 300 }, /* guess */
> +	.m1 = { .min = 2, .max = 3 },
> +	.m2 = { .min = 11, .max = 156 },
> +	.p = { .min = 10, .max = 30 },
> +	.p1 = { .min = 2, .max = 3 },
> +	.p2 = { .dot_limit = 270000,
> +		.p2_slow = 10, .p2_fast = 5 },
> +	.find_pll = intel_vlv_find_best_pll,
> +};
> +
>  u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg)
>  {
>  	unsigned long flags;
> @@ -384,6 +431,28 @@ out_unlock:
>  	return val;
>  }
>  
> +static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg,
> +			     u32 val)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dev_priv->dpio_lock, flags);
> +	if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
> +		DRM_ERROR("DPIO idle wait timed out\n");
> +		goto out_unlock;
> +	}
> +
> +	I915_WRITE(DPIO_DATA, val);
> +	I915_WRITE(DPIO_REG, reg);
> +	I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_WRITE | DPIO_PORTID |
> +		   DPIO_BYTE);
> +	if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100))
> +		DRM_ERROR("DPIO write wait timed out\n");
> +
> +out_unlock:
> +       spin_unlock_irqrestore(&dev_priv->dpio_lock, flags);
> +}
> +
>  static void vlv_init_dpio(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -510,6 +579,13 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk)
>  			limit = &intel_limits_pineview_lvds;
>  		else
>  			limit = &intel_limits_pineview_sdvo;
> +	} else if (IS_VALLEYVIEW(dev)) {
> +		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG))
> +			limit = &intel_limits_vlv_dac;
> +		else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI))
> +			limit = &intel_limits_vlv_hdmi;
> +		else
> +			limit = &intel_limits_vlv_dp;
>  	} else if (!IS_GEN2(dev)) {
>  		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
>  			limit = &intel_limits_i9xx_lvds;
> @@ -783,6 +859,83 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
>  	memcpy(best_clock, &clock, sizeof(intel_clock_t));
>  	return true;
>  }
> +static bool
> +intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc,
> +			int target, int refclk, intel_clock_t *match_clock,
> +			intel_clock_t *best_clock)
> +{
> +	u32 p1, p2, m1, m2, vco, bestn, bestm1, bestm2, bestp1, bestp2;
> +	u32 m, n, fastclk, minvco, maxvco;
> +	u32 updrate, minupdate, fracbits, p;
> +	unsigned long bestppm, ppm, absppm;
> +	int dotclk;
> +
> +	dotclk = target * 1000;
> +
> +	bestppm = 1000000;
> +	ppm = 0;
> +	absppm = 0;
> +
> +	fastclk = dotclk / (2*100);
> +	minvco = limit->vco.min;
> +	maxvco = limit->vco.max;
> +	updrate = 0;
> +	minupdate = 19200;
> +	fracbits = 1;
> +
> +	n = p = p1 = p2 = m = m1 = m2 = vco = bestn = 0;
> +	bestm1 = bestm2 = bestp1 = bestp2 = 0;
> +
> +	for(n = 1; n <= ((refclk) / minupdate); n++) {
> +		updrate = refclk / n;
> +		for (p1 = 3; p1 > 1; p1--) {
> +			for (p2 = 21; p2 > 0; p2--) {
> +				if (p2 > 10)
> +					p2 = p2 - 1;
> +				p = p1 * p2;
> +
> +				for( m1=2; m1 <= 3; m1++) {
> +					m2 = (((2*(fastclk * p * n / m1 )) +
> +					       refclk) / (2*refclk));
> +					m = m1 * m2;
> +					vco = updrate * m;
> +					if(vco >= minvco && vco < maxvco) {
> +						ppm = 1000000 *((vco / p) -
> +								fastclk) /
> +							fastclk;
> +						absppm = (ppm > 0)? ppm: (-ppm);
> +						if (absppm < 100 &&
> +						    ((p1 * p2) >
> +						     (bestp1 * bestp2))) {
> +							bestppm = 0;
> +							bestn = n;
> +							bestm1 = m1;
> +							bestm2 = m2;
> +							bestp1 = p1;
> +							bestp2 = p2;
> +						}
> +						if (absppm < bestppm - 10) {
> +							bestppm = absppm;
> +							bestn = n;
> +							bestm1 = m1;
> +							bestm2 = m2;
> +							bestp1 = p1;
> +							bestp2 = p2;
> +						}
> +					}
> +				}
> +			} /* Next p2 */
> +		} /* Next p1 */
> +	}/* Next n */
> +
> +	best_clock->n = bestn;
> +	best_clock->m1 = bestm1;
> +	best_clock->m2 = bestm2;
> +	best_clock->p1 = bestp1;
> +	best_clock->p2 = bestp2;
> +
> +	return true;
> +}
>  
>  static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe)
>  {
> @@ -1287,7 +1440,7 @@ static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
>  	u32 val;
>  
>  	/* No really, not for ILK+ */
> -	BUG_ON(dev_priv->info->gen >= 5);
> +	BUG_ON(!IS_VALLEYVIEW(dev_priv->dev) && dev_priv->info->gen >= 5);
>  
>  	/* PLL is protected by panel, make sure we can write it */
>  	if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev))
> @@ -3666,13 +3819,37 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
>  	return display_bpc != bpc;
>  }
>  
> +static int vlv_get_refclk(struct drm_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	int refclk = 27000; /* for DP & HDMI */
> +
> +	return 100000; /* only one validated so far */
> +
> +	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
> +		refclk = 96000;
> +	} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
> +		if (intel_panel_use_ssc(dev_priv))
> +			refclk = 100000;
> +		else
> +			refclk = 96000;
> +	} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) {
> +		refclk = 100000;
> +	}
> +
> +	return refclk;
> +}
> +
>  static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
>  {
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	int refclk;
>  
> -	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
> +	if (IS_VALLEYVIEW(dev)) {
> +		refclk = vlv_get_refclk(crtc);
> +	} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
>  	    intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
>  		refclk = dev_priv->lvds_ssc_freq * 1000;
>  		DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
> @@ -3787,6 +3964,72 @@ static void intel_update_lvds(struct drm_crtc *crtc, intel_clock_t *clock,
>  	I915_WRITE(LVDS, temp);
>  }
>  
> +static void vlv_update_pll(struct drm_crtc *crtc,
> +			   struct drm_display_mode *mode,
> +			   struct drm_display_mode *adjusted_mode,
> +			   intel_clock_t *clock, intel_clock_t *reduced_clock,
> +			   int refclk, int num_connectors)
> +{
> +	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 pipe = intel_crtc->pipe;
> +	u32 dpll, mdiv, pdiv;
> +	u32 bestn, bestm1, bestm2, bestp1, bestp2;
> +	bool is_hdmi;
> +
> +	is_hdmi = intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI);
> +
> +	bestn = clock->n;
> +	bestm1 = clock->m1;
> +	bestm2 = clock->m2;
> +	bestp1 = clock->p1;
> +	bestp2 = clock->p2;
> +
> +	/* Enable DPIO clock input */
> +	dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV |
> +		DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV;
> +	I915_WRITE(DPLL(pipe), dpll);
> +	POSTING_READ(DPLL(pipe));
> +
> +	mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK));
> +	mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT));
> +	mdiv |= ((bestn << DPIO_N_SHIFT));
> +	mdiv |= (1 << DPIO_POST_DIV_SHIFT);
> +	mdiv |= (1 << DPIO_K_SHIFT);
> +	mdiv |= DPIO_ENABLE_CALIBRATION;
> +	intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
> +
> +	intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), 0x01000000);
> +
> +	pdiv = DPIO_REFSEL_OVERRIDE | (5 << DPIO_PLL_MODESEL_SHIFT) |
> +		(3 << DPIO_BIAS_CURRENT_CTL_SHIFT) | (1<<20) |
> +		(8 << DPIO_DRIVER_CTL_SHIFT) | (5 << DPIO_CLK_BIAS_CTL_SHIFT);
> +	intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), pdiv);
> +
> +	intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x009f0051);
> +
> +	dpll |= DPLL_VCO_ENABLE;
> +	I915_WRITE(DPLL(pipe), dpll);
> +	POSTING_READ(DPLL(pipe));
> +	if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
> +		DRM_ERROR("DPLL %d failed to lock\n", pipe);
> +
> +	if (is_hdmi) {
> +		u32 temp = intel_mode_get_pixel_multiplier(adjusted_mode);
> +
> +		if (temp > 1)
> +			temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
> +		else
> +			temp = 0;
> +
> +		I915_WRITE(DPLL_MD(pipe), temp);
> +		POSTING_READ(DPLL_MD(pipe));
> +	}
> +
> +	intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x641); /* ??? */
> +}
> +
>  static void i9xx_update_pll(struct drm_crtc *crtc,
>  			    struct drm_display_mode *mode,
>  			    struct drm_display_mode *adjusted_mode,
> @@ -4044,6 +4287,9 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
>  
>  	if (IS_GEN2(dev))
>  		i8xx_update_pll(crtc, adjusted_mode, &clock, num_connectors);
> +	else if (IS_VALLEYVIEW(dev))
> +		vlv_update_pll(crtc, mode,adjusted_mode, &clock, NULL,
> +			       refclk, num_connectors);
>  	else
>  		i9xx_update_pll(crtc, mode, adjusted_mode, &clock,
>  				has_reduced_clock ? &reduced_clock : NULL,
> -- 
> 1.7.9.5
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48

  reply	other threads:[~2012-06-13  8:05 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-06-12 21:47 Remaining VLV patches Jesse Barnes
2012-06-12 21:47 ` [PATCH 1/7] drm/i915: ValleyView mode setting limits and PLL functions Jesse Barnes
2012-06-13  8:06   ` Daniel Vetter [this message]
2012-06-13 15:04     ` Purushothaman, Vijay A
2012-06-12 21:47 ` [PATCH 2/7] drm/i915: Enable DP panel power sequencing for ValleyView Jesse Barnes
2012-06-13  8:05   ` Daniel Vetter
2012-06-13 16:10     ` Shobhit Kumar
2012-06-12 21:47 ` [PATCH 3/7] drm/i915: add ValleyView specific CRT detect function Jesse Barnes
2012-06-12 21:47 ` [PATCH 4/7] drm/i915: add HDMI and DP port enumeration on ValleyView Jesse Barnes
2012-06-13  8:11   ` Daniel Vetter
2012-06-13 17:19     ` Jesse Barnes
2012-06-12 21:47 ` [PATCH 5/7] drm/i915: access VLV regs through read/write switch Jesse Barnes
2012-06-13  8:14   ` Daniel Vetter
2012-06-12 21:47 ` [PATCH 6/7] drm/i915: bind driver to ValleyView chipsets Jesse Barnes
2012-06-12 21:47 ` [PATCH 7/7] drm/i915: VLV VGA port only handles on & off, like PCH VGA Jesse Barnes
2012-06-13  8:36   ` Daniel Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120613080646.GB4829@phenom.ffwll.local \
    --to=daniel@ffwll.ch \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jbarnes@virtuousgeek.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox