> -----Original Message-----
> From: intel-gfx-
> bounces+vijay.a.purushothaman=intel....@lists.freedesktop.org [mailto:intel-
> gfx-bounces+vijay.a.purushothaman=intel....@lists.freedesktop.org] On
> Behalf Of Daniel Vetter
> Sent: Wednesday, June 13, 2012 1:37 PM
> To: Jesse Barnes
> Cc: intel-gfx@lists.freedesktop.org
> Subject: Re: [Intel-gfx] [PATCH 1/7] drm/i915: ValleyView mode setting limits
> and PLL functions
> 
> 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.ku...@intel.com>
> > Signed-off-by: Vijay Purushothaman <vijay.a.purushotha...@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
> 

We decided to rework this patch once we have a platform to test. Just today I 
was able to bring up my system with a test bios version - Thanks to Jesse.

I will post a cleaned up version of this patch soon.

Thanks,
Vijay

> > ---
> >  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: dan...@ffwll.ch
> Mobile: +41 (0)79 365 57 48
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to