[Intel-gfx] [PATCH 2/2]drm/i915: Use?best PLL timing values for G4X chipsets

Zhenyu Wang zhenyu.z.wang at intel.com
Thu Mar 12 02:43:31 CET 2009


On 2009.03.10 21:00:25 +0800, Ma Ling wrote:
> construct function to find precise parameters from internal spreadsheet table.
> 
> Signed-off-by: Ma Ling <ling.ma at intel.com>
> ---
>  drivers/gpu/drm/i915/intel_display.c |  103 ++++++++++++++++++++++++++++++----
>  1 files changed, 91 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index ce3864d..7c6d359 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -56,11 +56,13 @@ typedef struct {
>  } intel_p2_t;
>  
>  #define INTEL_P2_NUM		      2
> -
> -typedef struct {
> +typedef struct intel_limit intel_limit_t;
> +struct intel_limit {
>      intel_range_t   dot, vco, n, m, m1, m2, p, p1;
>      intel_p2_t	    p2;
> -} intel_limit_t;
> +    bool (* find_pll)(intel_limit_t *, struct drm_crtc *,
> +	              int, int, intel_clock_t *);
> +};
>  
>  #define I8XX_DOT_MIN		  25000
>  #define I8XX_DOT_MAX		 350000
> @@ -198,6 +200,12 @@ typedef struct {
>  #define G4X_P2_DUAL_CHANNEL_LVDS_FAST           7
>  #define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT          0
>  
> +static bool
> +intel_find_best_PLL(intel_limit_t *limit, struct drm_crtc *crtc,
> +		    int target, int refclk, intel_clock_t *best_clock);
> +static bool
> +intel_g4x_find_best_PLL(intel_limit_t *limit, struct drm_crtc *crtc,
> +			int target, int refclk, intel_clock_t *best_clock);
>  
>  static const intel_limit_t intel_limits[] = {
>      { /* INTEL_LIMIT_I8XX_DVO_DAC */
> @@ -211,6 +219,7 @@ static const intel_limit_t intel_limits[] = {
>          .p1  = { .min = I8XX_P1_MIN,		.max = I8XX_P1_MAX },
>  	.p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
>  		 .p2_slow = I8XX_P2_SLOW,	.p2_fast = I8XX_P2_FAST },
> +	.find_pll = intel_find_best_PLL,
>      },
>      { /* INTEL_LIMIT_I8XX_LVDS */
>          .dot = { .min = I8XX_DOT_MIN,		.max = I8XX_DOT_MAX },
> @@ -223,6 +232,7 @@ static const intel_limit_t intel_limits[] = {
>          .p1  = { .min = I8XX_P1_LVDS_MIN,	.max = I8XX_P1_LVDS_MAX },
>  	.p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
>  		 .p2_slow = I8XX_P2_LVDS_SLOW,	.p2_fast = I8XX_P2_LVDS_FAST },
> +	.find_pll = intel_find_best_PLL,
>      },
>      { /* INTEL_LIMIT_I9XX_SDVO_DAC */
>          .dot = { .min = I9XX_DOT_MIN,		.max = I9XX_DOT_MAX },
> @@ -235,6 +245,7 @@ static const intel_limit_t intel_limits[] = {
>          .p1  = { .min = I9XX_P1_MIN,		.max = I9XX_P1_MAX },
>  	.p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
>  		 .p2_slow = I9XX_P2_SDVO_DAC_SLOW,	.p2_fast = I9XX_P2_SDVO_DAC_FAST },
> +	.find_pll = intel_find_best_PLL,
>      },
>      { /* INTEL_LIMIT_I9XX_LVDS */
>          .dot = { .min = I9XX_DOT_MIN,		.max = I9XX_DOT_MAX },
> @@ -250,6 +261,7 @@ static const intel_limit_t intel_limits[] = {
>  	 */
>  	.p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
>  		 .p2_slow = I9XX_P2_LVDS_SLOW,	.p2_fast = I9XX_P2_LVDS_FAST },
> +	.find_pll = intel_find_best_PLL,
>      },
>      /* below parameter and function is for G4X Chipset Family*/
>      { /* INTEL_LIMIT_G4X_SDVO */
> @@ -265,6 +277,7 @@ static const intel_limit_t intel_limits[] = {
>  		 .p2_slow = G4X_P2_SDVO_SLOW,
>  		 .p2_fast = G4X_P2_SDVO_FAST
>  	},
> +	.find_pll = intel_g4x_find_best_PLL,
>      },
>      { /* INTEL_LIMIT_G4X_HDMI_DAC */
>  	.dot = { .min = G4X_DOT_HDMI_DAC_MIN,	.max = G4X_DOT_HDMI_DAC_MAX },
> @@ -279,6 +292,7 @@ static const intel_limit_t intel_limits[] = {
>  		 .p2_slow = G4X_P2_HDMI_DAC_SLOW,
>  		 .p2_fast = G4X_P2_HDMI_DAC_FAST
>  	},
> +	.find_pll = intel_g4x_find_best_PLL,
>      },
>      { /* INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS */
>  	.dot = { .min = G4X_DOT_SINGLE_CHANNEL_LVDS_MIN,
> @@ -301,6 +315,7 @@ static const intel_limit_t intel_limits[] = {
>  		 .p2_slow = G4X_P2_SINGLE_CHANNEL_LVDS_SLOW,
>  		 .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
>  	},
> +	.find_pll = intel_g4x_find_best_PLL,
>      },
>      { /* INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS */
>  	.dot = { .min = G4X_DOT_DUAL_CHANNEL_LVDS_MIN,
> @@ -323,6 +338,7 @@ static const intel_limit_t intel_limits[] = {
>  		 .p2_slow = G4X_P2_DUAL_CHANNEL_LVDS_SLOW,
>  		 .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
>  	},
> +	.find_pll = intel_g4x_find_best_PLL,
>       },
>  };
>  
> @@ -441,18 +457,14 @@ static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock)
>  	return true;
>  }
>  
> -/**
> - * Returns a set of divisors for the desired target clock with the given
> - * refclk, or FALSE.  The returned values represent the clock equation:
> - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> - */
> -static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,
> -				int refclk, intel_clock_t *best_clock)
> +static bool
> +intel_find_best_PLL(intel_limit_t *limit, struct drm_crtc *crtc,
> +		    int target, int refclk, intel_clock_t *best_clock)
> +
>  {
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	intel_clock_t clock;
> -	const intel_limit_t *limit = intel_limit(crtc);
>  	int err = target;
>  
>  	if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
> @@ -504,6 +516,66 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,
>  	return (err != target);
>  }
>  
> +static bool
> +intel_g4x_find_best_PLL(intel_limit_t *limit, struct drm_crtc *crtc,
> +			int target, int refclk, intel_clock_t *best_clock)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	intel_clock_t clock;
> +	int max_n;
> +	bool found;
> +
> +	/* approximately equals target * 0.00488 */
> +	int err_most = (target >> 8) + (target >> 10);
> +	/* return value defult false */
> +	found = false;
> +
> +	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
> +		if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
> +		    LVDS_CLKB_POWER_UP)
> +			clock.p2 = limit->p2.p2_fast;
> +		else
> +			clock.p2 = limit->p2.p2_slow;
> +	} else {
> +		if (target < limit->p2.dot_limit)
> +			clock.p2 = limit->p2.p2_slow;
> +		else
> +			clock.p2 = limit->p2.p2_fast;
> +	}
> +
> +	memset (best_clock, 0, sizeof (*best_clock));
> +	max_n = limit->n.max;
> +	/* based on hardware requriment prefer smaller n to precision */
> +	for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
> +		/* based on hardware requirment prefere larger m1,m2, p1 */
> +		for (clock.m1 = limit->m1.max;
> +		     clock.m1 >= limit->m1.min; clock.m1--) {
> +			for (clock.m2 = limit->m2.max;
> +			     clock.m2 >= limit->m2.min; clock.m2--) {
> +				for (clock.p1 = limit->p1.max;
> +				     clock.p1 >= limit->p1.min; clock.p1--) {
> +					int this_err;
> +
> +					intel_clock (refclk, &clock);
> +					if (!intel_PLL_is_valid(crtc, &clock))
> +						continue;
> +					this_err = abs(clock.dot - target) ;
> +					if (this_err < err_most) {
> +						*best_clock = clock;
> +						err_most = this_err;
> +						/*chose smaller n*/
> +						max_n = clock.n;
> +						found = true;

If we should prefer larger m1,m2,p1, why not exit the cycle here and return? 
Here we still try to look for the smallest error for target but might not be preferred
largest m1,m2,p1?
And is it possible if no clock can be found that meets the error precision of target?
Should we guard for that case?

And how about your test result on g4x with KMS?

> +					}
> +				}
> +			}
> +		}
> +	}
> +
> +	return found;
> +}
> +
>  void
>  intel_wait_for_vblank(struct drm_device *dev)
>  {
> @@ -922,6 +994,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
>  	bool is_crt = false, is_lvds = false, is_tv = false;
>  	struct drm_mode_config *mode_config = &dev->mode_config;
>  	struct drm_connector *connector;
> +	intel_limit_t *limit;
>  	int ret;
>  
>  	drm_vblank_pre_modeset(dev, pipe);
> @@ -965,7 +1038,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
>  		refclk = 48000;
>  	}
>  
> -	ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock);
> +	/*
> +	 * Returns a set of divisors for the desired target clock with the given
> +	 * refclk, or FALSE.  The returned values represent the clock equation:
> +	 * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> +	 */
> +	limit = intel_limit (crtc);
> +	ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
>  	if (!ok) {
>  		DRM_ERROR("Couldn't find PLL settings for mode!\n");
>  		return -EINVAL;
> -- 
> 1.5.4.4
> 
> 
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Open Source Technology Center, Intel ltd.

$gpg --keyserver wwwkeys.pgp.net --recv-keys 4D781827
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 197 bytes
Desc: Digital signature
URL: <http://lists.freedesktop.org/archives/intel-gfx/attachments/20090312/4b35d776/attachment.sig>


More information about the Intel-gfx mailing list