On Wed, 21 Mar 2012 12:48:29 -0700
Jesse Barnes <[email protected]> wrote:

> From: Vijay Purushothaman <[email protected]>
> 
> Add some VLV limit structures and update the PLL code.
> 
> Signed-off-by: Shobhit Kumar <[email protected]>
> Signed-off-by: Vijay Purushothaman <[email protected]>
> ---
>  drivers/gpu/drm/i915/i915_reg.h      |    1 +
>  drivers/gpu/drm/i915/intel_display.c |  231 
> +++++++++++++++++++++++++++++++++-
>  2 files changed, 229 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 7d33c49..bb6b49f 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -866,6 +866,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                  (1<<15) /* VLV */
>  #define   DPLL_VOLTAGE_LDO           (1<<14)
>  #define   DPLL_INTEGRATED_CLOCK              (1<<13)
>  #define   DPLL_RATE_SWITCH           (1<<8)
> diff --git a/drivers/gpu/drm/i915/intel_display.c 
> b/drivers/gpu/drm/i915/intel_display.c
> index f9ac7b7..ea64dc8 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -98,6 +98,10 @@ static bool
>  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)
> @@ -360,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,
> +};

is vco.min > vco.max correct? (too lazy to check how it's used).

> +
>  #define wait_for_atomic_us(COND, US) ({ \
>       int i, ret__ = -ETIMEDOUT;      \
>       for (i = 0; i < (US); i++) {    \
> @@ -504,6 +550,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;
> @@ -779,6 +832,84 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct 
> drm_crtc *crtc,
>       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;
> +}
> +

I'm not seeing how this ever returns false; And reading this function
hurts my eyes.

>  /**
>   * intel_wait_for_vblank - wait for vblank on a given pipe
>   * @dev: drm device
> @@ -1221,7 +1352,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))
> @@ -2966,6 +3097,7 @@ static void intel_clear_scanline_wait(struct drm_device 
> *dev)
>               return;
>  
>       ring = LP_RING(dev_priv);
> +
>       tmp = I915_READ_CTL(ring);
>       if (tmp & RING_WAIT)
>               I915_WRITE_CTL(ring, tmp);
> @@ -5169,14 +5301,38 @@ 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) &&
> -         intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
> +     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",
>                             refclk / 1000);
> @@ -5301,6 +5457,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 | DPLL_REFA_CLK_ENABLE |
> +             DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK;
> +     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) == DPLL_LOCK), 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,
> @@ -5555,6 +5777,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,

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to