[Intel-gfx] [RFC PATCH] drm/i915: move limits, pll find functions to a new file

Daniel Vetter daniel at ffwll.ch
Fri May 24 17:16:26 CEST 2013


On Fri, May 24, 2013 at 4:19 PM, Jani Nikula <jani.nikula at intel.com> wrote:
> This was a quick patch to see if it would be easy to extract the limit
> and pll stuff from intel_display.c to a separate file. Turns out it's
> trivial, and reduces the size of overbloated intel_display.c nicely:

I know, but I'd like to do that as part of the general pipe config
refactoring. I.e. your patch here will conflict madly with my
outstanding pll patches :(
-Daniel

>
>  drivers/gpu/drm/i915/Makefile        |    1 +
>  drivers/gpu/drm/i915/intel_display.c |  645 +--------------------------------
>  drivers/gpu/drm/i915/intel_drv.h     |    7 +
>  drivers/gpu/drm/i915/intel_limits.c  |  648 ++++++++++++++++++++++++++++++++++
>  4 files changed, 670 insertions(+), 631 deletions(-)
>
> Opinions, bikesheds?
>
> Signed-off-by: Jani Nikula <jani.nikula at intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile        |    1 +
>  drivers/gpu/drm/i915/intel_display.c |  645 +--------------------------------
>  drivers/gpu/drm/i915/intel_drv.h     |    7 +
>  drivers/gpu/drm/i915/intel_limits.c  |  648 ++++++++++++++++++++++++++++++++++
>  4 files changed, 670 insertions(+), 631 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/intel_limits.c
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 40034ec..b9d7426 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -21,6 +21,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
>           intel_crt.o \
>           intel_lvds.o \
>           intel_bios.o \
> +         intel_limits.o \
>           intel_ddi.o \
>           intel_dp.o \
>           intel_hdmi.o \
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index d63bb3f..721d461 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -45,40 +45,6 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
>  static void intel_increase_pllclock(struct drm_crtc *crtc);
>  static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
>
> -typedef struct {
> -       int     min, max;
> -} intel_range_t;
> -
> -typedef struct {
> -       int     dot_limit;
> -       int     p2_slow, p2_fast;
> -} intel_p2_t;
> -
> -#define INTEL_P2_NUM                 2
> -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;
> -       /**
> -        * find_pll() - Find the best values for the PLL
> -        * @limit: limits for the PLL
> -        * @crtc: current CRTC
> -        * @target: target frequency in kHz
> -        * @refclk: reference clock frequency in kHz
> -        * @match_clock: if provided, @best_clock P divider must
> -        *               match the P divider from @match_clock
> -        *               used for LVDS downclocking
> -        * @best_clock: best PLL values found
> -        *
> -        * Returns true on success, false on failure.
> -        */
> -       bool (*find_pll)(const intel_limit_t *limit,
> -                        struct drm_crtc *crtc,
> -                        int target, int refclk,
> -                        intel_clock_t *match_clock,
> -                        intel_clock_t *best_clock);
> -};
> -
>  /* FDI */
>  #define IRONLAKE_FDI_FREQ              2700000 /* in kHz for mode->clock */
>
> @@ -92,20 +58,6 @@ intel_pch_rawclk(struct drm_device *dev)
>         return I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK;
>  }
>
> -static bool
> -intel_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 bool
> -intel_g4x_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 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)
>  {
> @@ -116,351 +68,6 @@ intel_fdi_link_freq(struct drm_device *dev)
>                 return 27;
>  }
>
> -static const intel_limit_t intel_limits_i8xx_dvo = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 930000, .max = 1400000 },
> -       .n = { .min = 3, .max = 16 },
> -       .m = { .min = 96, .max = 140 },
> -       .m1 = { .min = 18, .max = 26 },
> -       .m2 = { .min = 6, .max = 16 },
> -       .p = { .min = 4, .max = 128 },
> -       .p1 = { .min = 2, .max = 33 },
> -       .p2 = { .dot_limit = 165000,
> -               .p2_slow = 4, .p2_fast = 2 },
> -       .find_pll = intel_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_i8xx_lvds = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 930000, .max = 1400000 },
> -       .n = { .min = 3, .max = 16 },
> -       .m = { .min = 96, .max = 140 },
> -       .m1 = { .min = 18, .max = 26 },
> -       .m2 = { .min = 6, .max = 16 },
> -       .p = { .min = 4, .max = 128 },
> -       .p1 = { .min = 1, .max = 6 },
> -       .p2 = { .dot_limit = 165000,
> -               .p2_slow = 14, .p2_fast = 7 },
> -       .find_pll = intel_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_i9xx_sdvo = {
> -       .dot = { .min = 20000, .max = 400000 },
> -       .vco = { .min = 1400000, .max = 2800000 },
> -       .n = { .min = 1, .max = 6 },
> -       .m = { .min = 70, .max = 120 },
> -       .m1 = { .min = 8, .max = 18 },
> -       .m2 = { .min = 3, .max = 7 },
> -       .p = { .min = 5, .max = 80 },
> -       .p1 = { .min = 1, .max = 8 },
> -       .p2 = { .dot_limit = 200000,
> -               .p2_slow = 10, .p2_fast = 5 },
> -       .find_pll = intel_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_i9xx_lvds = {
> -       .dot = { .min = 20000, .max = 400000 },
> -       .vco = { .min = 1400000, .max = 2800000 },
> -       .n = { .min = 1, .max = 6 },
> -       .m = { .min = 70, .max = 120 },
> -       .m1 = { .min = 8, .max = 18 },
> -       .m2 = { .min = 3, .max = 7 },
> -       .p = { .min = 7, .max = 98 },
> -       .p1 = { .min = 1, .max = 8 },
> -       .p2 = { .dot_limit = 112000,
> -               .p2_slow = 14, .p2_fast = 7 },
> -       .find_pll = intel_find_best_PLL,
> -};
> -
> -
> -static const intel_limit_t intel_limits_g4x_sdvo = {
> -       .dot = { .min = 25000, .max = 270000 },
> -       .vco = { .min = 1750000, .max = 3500000},
> -       .n = { .min = 1, .max = 4 },
> -       .m = { .min = 104, .max = 138 },
> -       .m1 = { .min = 17, .max = 23 },
> -       .m2 = { .min = 5, .max = 11 },
> -       .p = { .min = 10, .max = 30 },
> -       .p1 = { .min = 1, .max = 3},
> -       .p2 = { .dot_limit = 270000,
> -               .p2_slow = 10,
> -               .p2_fast = 10
> -       },
> -       .find_pll = intel_g4x_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_g4x_hdmi = {
> -       .dot = { .min = 22000, .max = 400000 },
> -       .vco = { .min = 1750000, .max = 3500000},
> -       .n = { .min = 1, .max = 4 },
> -       .m = { .min = 104, .max = 138 },
> -       .m1 = { .min = 16, .max = 23 },
> -       .m2 = { .min = 5, .max = 11 },
> -       .p = { .min = 5, .max = 80 },
> -       .p1 = { .min = 1, .max = 8},
> -       .p2 = { .dot_limit = 165000,
> -               .p2_slow = 10, .p2_fast = 5 },
> -       .find_pll = intel_g4x_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
> -       .dot = { .min = 20000, .max = 115000 },
> -       .vco = { .min = 1750000, .max = 3500000 },
> -       .n = { .min = 1, .max = 3 },
> -       .m = { .min = 104, .max = 138 },
> -       .m1 = { .min = 17, .max = 23 },
> -       .m2 = { .min = 5, .max = 11 },
> -       .p = { .min = 28, .max = 112 },
> -       .p1 = { .min = 2, .max = 8 },
> -       .p2 = { .dot_limit = 0,
> -               .p2_slow = 14, .p2_fast = 14
> -       },
> -       .find_pll = intel_g4x_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
> -       .dot = { .min = 80000, .max = 224000 },
> -       .vco = { .min = 1750000, .max = 3500000 },
> -       .n = { .min = 1, .max = 3 },
> -       .m = { .min = 104, .max = 138 },
> -       .m1 = { .min = 17, .max = 23 },
> -       .m2 = { .min = 5, .max = 11 },
> -       .p = { .min = 14, .max = 42 },
> -       .p1 = { .min = 2, .max = 6 },
> -       .p2 = { .dot_limit = 0,
> -               .p2_slow = 7, .p2_fast = 7
> -       },
> -       .find_pll = intel_g4x_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_pineview_sdvo = {
> -       .dot = { .min = 20000, .max = 400000},
> -       .vco = { .min = 1700000, .max = 3500000 },
> -       /* Pineview's Ncounter is a ring counter */
> -       .n = { .min = 3, .max = 6 },
> -       .m = { .min = 2, .max = 256 },
> -       /* Pineview only has one combined m divider, which we treat as m2. */
> -       .m1 = { .min = 0, .max = 0 },
> -       .m2 = { .min = 0, .max = 254 },
> -       .p = { .min = 5, .max = 80 },
> -       .p1 = { .min = 1, .max = 8 },
> -       .p2 = { .dot_limit = 200000,
> -               .p2_slow = 10, .p2_fast = 5 },
> -       .find_pll = intel_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_pineview_lvds = {
> -       .dot = { .min = 20000, .max = 400000 },
> -       .vco = { .min = 1700000, .max = 3500000 },
> -       .n = { .min = 3, .max = 6 },
> -       .m = { .min = 2, .max = 256 },
> -       .m1 = { .min = 0, .max = 0 },
> -       .m2 = { .min = 0, .max = 254 },
> -       .p = { .min = 7, .max = 112 },
> -       .p1 = { .min = 1, .max = 8 },
> -       .p2 = { .dot_limit = 112000,
> -               .p2_slow = 14, .p2_fast = 14 },
> -       .find_pll = intel_find_best_PLL,
> -};
> -
> -/* Ironlake / Sandybridge
> - *
> - * We calculate clock using (register_value + 2) for N/M1/M2, so here
> - * the range value for them is (actual_value - 2).
> - */
> -static const intel_limit_t intel_limits_ironlake_dac = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 1760000, .max = 3510000 },
> -       .n = { .min = 1, .max = 5 },
> -       .m = { .min = 79, .max = 127 },
> -       .m1 = { .min = 12, .max = 22 },
> -       .m2 = { .min = 5, .max = 9 },
> -       .p = { .min = 5, .max = 80 },
> -       .p1 = { .min = 1, .max = 8 },
> -       .p2 = { .dot_limit = 225000,
> -               .p2_slow = 10, .p2_fast = 5 },
> -       .find_pll = intel_g4x_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_ironlake_single_lvds = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 1760000, .max = 3510000 },
> -       .n = { .min = 1, .max = 3 },
> -       .m = { .min = 79, .max = 118 },
> -       .m1 = { .min = 12, .max = 22 },
> -       .m2 = { .min = 5, .max = 9 },
> -       .p = { .min = 28, .max = 112 },
> -       .p1 = { .min = 2, .max = 8 },
> -       .p2 = { .dot_limit = 225000,
> -               .p2_slow = 14, .p2_fast = 14 },
> -       .find_pll = intel_g4x_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_ironlake_dual_lvds = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 1760000, .max = 3510000 },
> -       .n = { .min = 1, .max = 3 },
> -       .m = { .min = 79, .max = 127 },
> -       .m1 = { .min = 12, .max = 22 },
> -       .m2 = { .min = 5, .max = 9 },
> -       .p = { .min = 14, .max = 56 },
> -       .p1 = { .min = 2, .max = 8 },
> -       .p2 = { .dot_limit = 225000,
> -               .p2_slow = 7, .p2_fast = 7 },
> -       .find_pll = intel_g4x_find_best_PLL,
> -};
> -
> -/* LVDS 100mhz refclk limits. */
> -static const intel_limit_t intel_limits_ironlake_single_lvds_100m = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 1760000, .max = 3510000 },
> -       .n = { .min = 1, .max = 2 },
> -       .m = { .min = 79, .max = 126 },
> -       .m1 = { .min = 12, .max = 22 },
> -       .m2 = { .min = 5, .max = 9 },
> -       .p = { .min = 28, .max = 112 },
> -       .p1 = { .min = 2, .max = 8 },
> -       .p2 = { .dot_limit = 225000,
> -               .p2_slow = 14, .p2_fast = 14 },
> -       .find_pll = intel_g4x_find_best_PLL,
> -};
> -
> -static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 1760000, .max = 3510000 },
> -       .n = { .min = 1, .max = 3 },
> -       .m = { .min = 79, .max = 126 },
> -       .m1 = { .min = 12, .max = 22 },
> -       .m2 = { .min = 5, .max = 9 },
> -       .p = { .min = 14, .max = 42 },
> -       .p1 = { .min = 2, .max = 6 },
> -       .p2 = { .dot_limit = 225000,
> -               .p2_slow = 7, .p2_fast = 7 },
> -       .find_pll = intel_g4x_find_best_PLL,
> -};
> -
> -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 = 1, .max = 3 },
> -       .p2 = { .dot_limit = 270000,
> -               .p2_slow = 2, .p2_fast = 20 },
> -       .find_pll = intel_vlv_find_best_pll,
> -};
> -
> -static const intel_limit_t intel_limits_vlv_hdmi = {
> -       .dot = { .min = 25000, .max = 270000 },
> -       .vco = { .min = 4000000, .max = 6000000 },
> -       .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 = 2, .p2_fast = 20 },
> -       .find_pll = intel_vlv_find_best_pll,
> -};
> -
> -static const intel_limit_t intel_limits_vlv_dp = {
> -       .dot = { .min = 25000, .max = 270000 },
> -       .vco = { .min = 4000000, .max = 6000000 },
> -       .n = { .min = 1, .max = 7 },
> -       .m = { .min = 22, .max = 450 },
> -       .m1 = { .min = 2, .max = 3 },
> -       .m2 = { .min = 11, .max = 156 },
> -       .p = { .min = 10, .max = 30 },
> -       .p1 = { .min = 1, .max = 3 },
> -       .p2 = { .dot_limit = 270000,
> -               .p2_slow = 2, .p2_fast = 20 },
> -       .find_pll = intel_vlv_find_best_pll,
> -};
> -
> -static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
> -                                               int refclk)
> -{
> -       struct drm_device *dev = crtc->dev;
> -       const intel_limit_t *limit;
> -
> -       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
> -               if (intel_is_dual_link_lvds(dev)) {
> -                       if (refclk == 100000)
> -                               limit = &intel_limits_ironlake_dual_lvds_100m;
> -                       else
> -                               limit = &intel_limits_ironlake_dual_lvds;
> -               } else {
> -                       if (refclk == 100000)
> -                               limit = &intel_limits_ironlake_single_lvds_100m;
> -                       else
> -                               limit = &intel_limits_ironlake_single_lvds;
> -               }
> -       } else
> -               limit = &intel_limits_ironlake_dac;
> -
> -       return limit;
> -}
> -
> -static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
> -{
> -       struct drm_device *dev = crtc->dev;
> -       const intel_limit_t *limit;
> -
> -       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
> -               if (intel_is_dual_link_lvds(dev))
> -                       limit = &intel_limits_g4x_dual_channel_lvds;
> -               else
> -                       limit = &intel_limits_g4x_single_channel_lvds;
> -       } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) ||
> -                  intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
> -               limit = &intel_limits_g4x_hdmi;
> -       } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
> -               limit = &intel_limits_g4x_sdvo;
> -       } else /* The option is for other outputs */
> -               limit = &intel_limits_i9xx_sdvo;
> -
> -       return limit;
> -}
> -
> -static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk)
> -{
> -       struct drm_device *dev = crtc->dev;
> -       const intel_limit_t *limit;
> -
> -       if (HAS_PCH_SPLIT(dev))
> -               limit = intel_ironlake_limit(crtc, refclk);
> -       else if (IS_G4X(dev)) {
> -               limit = intel_g4x_limit(crtc);
> -       } else if (IS_PINEVIEW(dev)) {
> -               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
> -                       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;
> -               else
> -                       limit = &intel_limits_i9xx_sdvo;
> -       } else {
> -               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
> -                       limit = &intel_limits_i8xx_lvds;
> -               else
> -                       limit = &intel_limits_i8xx_dvo;
> -       }
> -       return limit;
> -}
> -
>  /* m1 is reserved as 0 in Pineview, n is a ring counter */
>  static void pineview_clock(int refclk, intel_clock_t *clock)
>  {
> @@ -475,7 +82,7 @@ static uint32_t i9xx_dpll_compute_m(struct dpll *dpll)
>         return 5 * (dpll->m1 + 2) + (dpll->m2 + 2);
>  }
>
> -static void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock)
> +void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock)
>  {
>         if (IS_PINEVIEW(dev)) {
>                 pineview_clock(refclk, clock);
> @@ -502,230 +109,6 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type)
>         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.
> - */
> -
> -static bool intel_PLL_is_valid(struct drm_device *dev,
> -                              const intel_limit_t *limit,
> -                              const intel_clock_t *clock)
> -{
> -       if (clock->p1  < limit->p1.min  || limit->p1.max  < clock->p1)
> -               INTELPllInvalid("p1 out of range\n");
> -       if (clock->p   < limit->p.min   || limit->p.max   < clock->p)
> -               INTELPllInvalid("p out of range\n");
> -       if (clock->m2  < limit->m2.min  || limit->m2.max  < clock->m2)
> -               INTELPllInvalid("m2 out of range\n");
> -       if (clock->m1  < limit->m1.min  || limit->m1.max  < clock->m1)
> -               INTELPllInvalid("m1 out of range\n");
> -       if (clock->m1 <= clock->m2 && !IS_PINEVIEW(dev))
> -               INTELPllInvalid("m1 <= m2\n");
> -       if (clock->m   < limit->m.min   || limit->m.max   < clock->m)
> -               INTELPllInvalid("m out of range\n");
> -       if (clock->n   < limit->n.min   || limit->n.max   < clock->n)
> -               INTELPllInvalid("n out of range\n");
> -       if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
> -               INTELPllInvalid("vco out of range\n");
> -       /* XXX: We may need to be checking "Dot clock" depending on the multiplier,
> -        * connector, etc., rather than just a single range.
> -        */
> -       if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
> -               INTELPllInvalid("dot out of range\n");
> -
> -       return true;
> -}
> -
> -static bool
> -intel_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)
> -
> -{
> -       struct drm_device *dev = crtc->dev;
> -       intel_clock_t clock;
> -       int err = target;
> -
> -       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
> -               /*
> -                * For LVDS just rely on its current settings for dual-channel.
> -                * We haven't figured out how to reliably set up different
> -                * single/dual channel state, if we even can.
> -                */
> -               if (intel_is_dual_link_lvds(dev))
> -                       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));
> -
> -       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
> -            clock.m1++) {
> -               for (clock.m2 = limit->m2.min;
> -                    clock.m2 <= limit->m2.max; clock.m2++) {
> -                       /* m1 is always 0 in Pineview */
> -                       if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev))
> -                               break;
> -                       for (clock.n = limit->n.min;
> -                            clock.n <= limit->n.max; clock.n++) {
> -                               for (clock.p1 = limit->p1.min;
> -                                       clock.p1 <= limit->p1.max; clock.p1++) {
> -                                       int this_err;
> -
> -                                       intel_clock(dev, refclk, &clock);
> -                                       if (!intel_PLL_is_valid(dev, limit,
> -                                                               &clock))
> -                                               continue;
> -                                       if (match_clock &&
> -                                           clock.p != match_clock->p)
> -                                               continue;
> -
> -                                       this_err = abs(clock.dot - target);
> -                                       if (this_err < err) {
> -                                               *best_clock = clock;
> -                                               err = this_err;
> -                                       }
> -                               }
> -                       }
> -               }
> -       }
> -
> -       return (err != target);
> -}
> -
> -static bool
> -intel_g4x_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)
> -{
> -       struct drm_device *dev = crtc->dev;
> -       intel_clock_t clock;
> -       int max_n;
> -       bool found;
> -       /* approximately equals target * 0.00585 */
> -       int err_most = (target >> 8) + (target >> 9);
> -       found = false;
> -
> -       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
> -               if (intel_is_dual_link_lvds(dev))
> -                       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 requirement, prefer smaller n to precision */
> -       for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
> -               /* based on hardware requirement, prefere larger m1,m2 */
> -               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(dev, refclk, &clock);
> -                                       if (!intel_PLL_is_valid(dev, limit,
> -                                                               &clock))
> -                                               continue;
> -
> -                                       this_err = abs(clock.dot - target);
> -                                       if (this_err < err_most) {
> -                                               *best_clock = clock;
> -                                               err_most = this_err;
> -                                               max_n = clock.n;
> -                                               found = true;
> -                                       }
> -                               }
> -                       }
> -               }
> -       }
> -       return found;
> -}
> -
> -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;
> -       u32 updrate, minupdate, fracbits, p;
> -       unsigned long bestppm, ppm, absppm;
> -       int dotclk, flag;
> -
> -       flag = 0;
> -       dotclk = target * 1000;
> -       bestppm = 1000000;
> -       ppm = absppm = 0;
> -       fastclk = dotclk / (2*100);
> -       updrate = 0;
> -       minupdate = 19200;
> -       fracbits = 1;
> -       n = p = p1 = p2 = m = m1 = m2 = vco = bestn = 0;
> -       bestm1 = bestm2 = bestp1 = bestp2 = 0;
> -
> -       /* based on hardware requirement, prefer smaller n to precision */
> -       for (n = limit->n.min; n <= ((refclk) / minupdate); n++) {
> -               updrate = refclk / n;
> -               for (p1 = limit->p1.max; p1 > limit->p1.min; p1--) {
> -                       for (p2 = limit->p2.p2_fast+1; p2 > 0; p2--) {
> -                               if (p2 > 10)
> -                                       p2 = p2 - 1;
> -                               p = p1 * p2;
> -                               /* based on hardware requirement, prefer bigger m1,m2 values */
> -                               for (m1 = limit->m1.min; m1 <= limit->m1.max; m1++) {
> -                                       m2 = (((2*(fastclk * p * n / m1 )) +
> -                                              refclk) / (2*refclk));
> -                                       m = m1 * m2;
> -                                       vco = updrate * m;
> -                                       if (vco >= limit->vco.min && vco < limit->vco.max) {
> -                                               ppm = 1000000 * ((vco / p) - fastclk) / fastclk;
> -                                               absppm = (ppm > 0) ? ppm : (-ppm);
> -                                               if (absppm < 100 && ((p1 * p2) > (bestp1 * bestp2))) {
> -                                                       bestppm = 0;
> -                                                       flag = 1;
> -                                               }
> -                                               if (absppm < bestppm - 10) {
> -                                                       bestppm = absppm;
> -                                                       flag = 1;
> -                                               }
> -                                               if (flag) {
> -                                                       bestn = n;
> -                                                       bestm1 = m1;
> -                                                       bestm2 = m2;
> -                                                       bestp1 = p1;
> -                                                       bestp2 = p2;
> -                                                       flag = 0;
> -                                               }
> -                                       }
> -                               }
> -                       }
> -               }
> -       }
> -       best_clock->n = bestn;
> -       best_clock->m1 = bestm1;
> -       best_clock->m2 = bestm2;
> -       best_clock->p1 = bestp1;
> -       best_clock->p2 = bestp2;
> -
> -       return true;
> -}
> -
>  enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
>                                              enum pipe pipe)
>  {
> @@ -4815,7 +4198,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
>          * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
>          */
>         limit = intel_limit(crtc, refclk);
> -       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
> +       ok = intel_find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
>                              &clock);
>         if (!ok) {
>                 DRM_ERROR("Couldn't find PLL settings for mode!\n");
> @@ -4832,11 +4215,11 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
>                  * by using the FP0/FP1. In such case we will disable the LVDS
>                  * downclock feature.
>                 */
> -               has_reduced_clock = limit->find_pll(limit, crtc,
> -                                                   dev_priv->lvds_downclock,
> -                                                   refclk,
> -                                                   &clock,
> -                                                   &reduced_clock);
> +               has_reduced_clock = intel_find_pll(limit, crtc,
> +                                                  dev_priv->lvds_downclock,
> +                                                  refclk,
> +                                                  &clock,
> +                                                  &reduced_clock);
>         }
>         /* Compat-code for transition, will disappear. */
>         if (!intel_crtc->config.clock_set) {
> @@ -5452,8 +4835,8 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
>          * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
>          */
>         limit = intel_limit(crtc, refclk);
> -       ret = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
> -                             clock);
> +       ret = intel_find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
> +                            clock);
>         if (!ret)
>                 return false;
>
> @@ -5464,11 +4847,11 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
>                  * by using the FP0/FP1. In such case we will disable the LVDS
>                  * downclock feature.
>                 */
> -               *has_reduced_clock = limit->find_pll(limit, crtc,
> -                                                    dev_priv->lvds_downclock,
> -                                                    refclk,
> -                                                    clock,
> -                                                    reduced_clock);
> +               *has_reduced_clock = intel_find_pll(limit, crtc,
> +                                                   dev_priv->lvds_downclock,
> +                                                   refclk,
> +                                                   clock,
> +                                                   reduced_clock);
>         }
>
>         return true;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 83b4fe4..fcd4570 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -191,6 +191,13 @@ typedef struct dpll {
>         int     m;
>         int     p;
>  } intel_clock_t;
> +void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock);
> +
> +typedef struct intel_limit intel_limit_t;
> +const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk);
> +bool intel_find_pll(const intel_limit_t *limit, struct drm_crtc *crtc,
> +                   int target, int refclk, intel_clock_t *match_clock,
> +                   intel_clock_t *best_clock);
>
>  struct intel_crtc_config {
>         struct drm_display_mode requested_mode;
> diff --git a/drivers/gpu/drm/i915/intel_limits.c b/drivers/gpu/drm/i915/intel_limits.c
> new file mode 100644
> index 0000000..2865b70f
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_limits.c
> @@ -0,0 +1,648 @@
> +/*
> + * Copyright © 2013 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + *
> + */
> +
> +#include <linux/dmi.h>
> +#include <linux/module.h>
> +#include <linux/input.h>
> +#include <linux/i2c.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/vgaarb.h>
> +#include <drm/drm_edid.h>
> +#include <drm/drmP.h>
> +#include "intel_drv.h"
> +#include <drm/i915_drm.h>
> +#include "i915_drv.h"
> +#include "i915_trace.h"
> +#include <drm/drm_dp_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <linux/dma_remapping.h>
> +
> +typedef struct {
> +       int     min, max;
> +} intel_range_t;
> +
> +typedef struct {
> +       int     dot_limit;
> +       int     p2_slow, p2_fast;
> +} intel_p2_t;
> +
> +struct intel_limit {
> +       intel_range_t   dot, vco, n, m, m1, m2, p, p1;
> +       intel_p2_t          p2;
> +       /**
> +        * find_pll() - Find the best values for the PLL
> +        * @limit: limits for the PLL
> +        * @crtc: current CRTC
> +        * @target: target frequency in kHz
> +        * @refclk: reference clock frequency in kHz
> +        * @match_clock: if provided, @best_clock P divider must
> +        *               match the P divider from @match_clock
> +        *               used for LVDS downclocking
> +        * @best_clock: best PLL values found
> +        *
> +        * Returns true on success, false on failure.
> +        */
> +       bool (*find_pll)(const struct intel_limit *limit,
> +                        struct drm_crtc *crtc,
> +                        int target, int refclk,
> +                        intel_clock_t *match_clock,
> +                        intel_clock_t *best_clock);
> +};
> +
> +#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.
> + */
> +
> +static bool intel_PLL_is_valid(struct drm_device *dev,
> +                              const struct intel_limit *limit,
> +                              const intel_clock_t *clock)
> +{
> +       if (clock->p1  < limit->p1.min  || limit->p1.max  < clock->p1)
> +               INTELPllInvalid("p1 out of range\n");
> +       if (clock->p   < limit->p.min   || limit->p.max   < clock->p)
> +               INTELPllInvalid("p out of range\n");
> +       if (clock->m2  < limit->m2.min  || limit->m2.max  < clock->m2)
> +               INTELPllInvalid("m2 out of range\n");
> +       if (clock->m1  < limit->m1.min  || limit->m1.max  < clock->m1)
> +               INTELPllInvalid("m1 out of range\n");
> +       if (clock->m1 <= clock->m2 && !IS_PINEVIEW(dev))
> +               INTELPllInvalid("m1 <= m2\n");
> +       if (clock->m   < limit->m.min   || limit->m.max   < clock->m)
> +               INTELPllInvalid("m out of range\n");
> +       if (clock->n   < limit->n.min   || limit->n.max   < clock->n)
> +               INTELPllInvalid("n out of range\n");
> +       if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
> +               INTELPllInvalid("vco out of range\n");
> +       /* XXX: We may need to be checking "Dot clock" depending on the multiplier,
> +        * connector, etc., rather than just a single range.
> +        */
> +       if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
> +               INTELPllInvalid("dot out of range\n");
> +
> +       return true;
> +}
> +
> +static bool
> +intel_find_best_PLL(const struct intel_limit *limit, struct drm_crtc *crtc,
> +                   int target, int refclk, intel_clock_t *match_clock,
> +                   intel_clock_t *best_clock)
> +
> +{
> +       struct drm_device *dev = crtc->dev;
> +       intel_clock_t clock;
> +       int err = target;
> +
> +       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
> +               /*
> +                * For LVDS just rely on its current settings for dual-channel.
> +                * We haven't figured out how to reliably set up different
> +                * single/dual channel state, if we even can.
> +                */
> +               if (intel_is_dual_link_lvds(dev))
> +                       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));
> +
> +       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
> +            clock.m1++) {
> +               for (clock.m2 = limit->m2.min;
> +                    clock.m2 <= limit->m2.max; clock.m2++) {
> +                       /* m1 is always 0 in Pineview */
> +                       if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev))
> +                               break;
> +                       for (clock.n = limit->n.min;
> +                            clock.n <= limit->n.max; clock.n++) {
> +                               for (clock.p1 = limit->p1.min;
> +                                       clock.p1 <= limit->p1.max; clock.p1++) {
> +                                       int this_err;
> +
> +                                       intel_clock(dev, refclk, &clock);
> +                                       if (!intel_PLL_is_valid(dev, limit,
> +                                                               &clock))
> +                                               continue;
> +                                       if (match_clock &&
> +                                           clock.p != match_clock->p)
> +                                               continue;
> +
> +                                       this_err = abs(clock.dot - target);
> +                                       if (this_err < err) {
> +                                               *best_clock = clock;
> +                                               err = this_err;
> +                                       }
> +                               }
> +                       }
> +               }
> +       }
> +
> +       return (err != target);
> +}
> +
> +static bool
> +intel_g4x_find_best_PLL(const struct intel_limit *limit, struct drm_crtc *crtc,
> +                       int target, int refclk, intel_clock_t *match_clock,
> +                       intel_clock_t *best_clock)
> +{
> +       struct drm_device *dev = crtc->dev;
> +       intel_clock_t clock;
> +       int max_n;
> +       bool found;
> +       /* approximately equals target * 0.00585 */
> +       int err_most = (target >> 8) + (target >> 9);
> +       found = false;
> +
> +       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
> +               if (intel_is_dual_link_lvds(dev))
> +                       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 requirement, prefer smaller n to precision */
> +       for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
> +               /* based on hardware requirement, prefere larger m1,m2 */
> +               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(dev, refclk, &clock);
> +                                       if (!intel_PLL_is_valid(dev, limit,
> +                                                               &clock))
> +                                               continue;
> +
> +                                       this_err = abs(clock.dot - target);
> +                                       if (this_err < err_most) {
> +                                               *best_clock = clock;
> +                                               err_most = this_err;
> +                                               max_n = clock.n;
> +                                               found = true;
> +                                       }
> +                               }
> +                       }
> +               }
> +       }
> +       return found;
> +}
> +
> +static bool
> +intel_vlv_find_best_pll(const struct intel_limit *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;
> +       u32 updrate, minupdate, fracbits, p;
> +       unsigned long bestppm, ppm, absppm;
> +       int dotclk, flag;
> +
> +       flag = 0;
> +       dotclk = target * 1000;
> +       bestppm = 1000000;
> +       ppm = absppm = 0;
> +       fastclk = dotclk / (2*100);
> +       updrate = 0;
> +       minupdate = 19200;
> +       fracbits = 1;
> +       n = p = p1 = p2 = m = m1 = m2 = vco = bestn = 0;
> +       bestm1 = bestm2 = bestp1 = bestp2 = 0;
> +
> +       /* based on hardware requirement, prefer smaller n to precision */
> +       for (n = limit->n.min; n <= ((refclk) / minupdate); n++) {
> +               updrate = refclk / n;
> +               for (p1 = limit->p1.max; p1 > limit->p1.min; p1--) {
> +                       for (p2 = limit->p2.p2_fast+1; p2 > 0; p2--) {
> +                               if (p2 > 10)
> +                                       p2 = p2 - 1;
> +                               p = p1 * p2;
> +                               /* based on hardware requirement, prefer bigger m1,m2 values */
> +                               for (m1 = limit->m1.min; m1 <= limit->m1.max; m1++) {
> +                                       m2 = (((2*(fastclk * p * n / m1 )) +
> +                                              refclk) / (2*refclk));
> +                                       m = m1 * m2;
> +                                       vco = updrate * m;
> +                                       if (vco >= limit->vco.min && vco < limit->vco.max) {
> +                                               ppm = 1000000 * ((vco / p) - fastclk) / fastclk;
> +                                               absppm = (ppm > 0) ? ppm : (-ppm);
> +                                               if (absppm < 100 && ((p1 * p2) > (bestp1 * bestp2))) {
> +                                                       bestppm = 0;
> +                                                       flag = 1;
> +                                               }
> +                                               if (absppm < bestppm - 10) {
> +                                                       bestppm = absppm;
> +                                                       flag = 1;
> +                                               }
> +                                               if (flag) {
> +                                                       bestn = n;
> +                                                       bestm1 = m1;
> +                                                       bestm2 = m2;
> +                                                       bestp1 = p1;
> +                                                       bestp2 = p2;
> +                                                       flag = 0;
> +                                               }
> +                                       }
> +                               }
> +                       }
> +               }
> +       }
> +       best_clock->n = bestn;
> +       best_clock->m1 = bestm1;
> +       best_clock->m2 = bestm2;
> +       best_clock->p1 = bestp1;
> +       best_clock->p2 = bestp2;
> +
> +       return true;
> +}
> +
> +static const struct intel_limit intel_limits_i8xx_dvo = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 930000, .max = 1400000 },
> +       .n = { .min = 3, .max = 16 },
> +       .m = { .min = 96, .max = 140 },
> +       .m1 = { .min = 18, .max = 26 },
> +       .m2 = { .min = 6, .max = 16 },
> +       .p = { .min = 4, .max = 128 },
> +       .p1 = { .min = 2, .max = 33 },
> +       .p2 = { .dot_limit = 165000,
> +               .p2_slow = 4, .p2_fast = 2 },
> +       .find_pll = intel_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_i8xx_lvds = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 930000, .max = 1400000 },
> +       .n = { .min = 3, .max = 16 },
> +       .m = { .min = 96, .max = 140 },
> +       .m1 = { .min = 18, .max = 26 },
> +       .m2 = { .min = 6, .max = 16 },
> +       .p = { .min = 4, .max = 128 },
> +       .p1 = { .min = 1, .max = 6 },
> +       .p2 = { .dot_limit = 165000,
> +               .p2_slow = 14, .p2_fast = 7 },
> +       .find_pll = intel_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_i9xx_sdvo = {
> +       .dot = { .min = 20000, .max = 400000 },
> +       .vco = { .min = 1400000, .max = 2800000 },
> +       .n = { .min = 1, .max = 6 },
> +       .m = { .min = 70, .max = 120 },
> +       .m1 = { .min = 8, .max = 18 },
> +       .m2 = { .min = 3, .max = 7 },
> +       .p = { .min = 5, .max = 80 },
> +       .p1 = { .min = 1, .max = 8 },
> +       .p2 = { .dot_limit = 200000,
> +               .p2_slow = 10, .p2_fast = 5 },
> +       .find_pll = intel_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_i9xx_lvds = {
> +       .dot = { .min = 20000, .max = 400000 },
> +       .vco = { .min = 1400000, .max = 2800000 },
> +       .n = { .min = 1, .max = 6 },
> +       .m = { .min = 70, .max = 120 },
> +       .m1 = { .min = 8, .max = 18 },
> +       .m2 = { .min = 3, .max = 7 },
> +       .p = { .min = 7, .max = 98 },
> +       .p1 = { .min = 1, .max = 8 },
> +       .p2 = { .dot_limit = 112000,
> +               .p2_slow = 14, .p2_fast = 7 },
> +       .find_pll = intel_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_g4x_sdvo = {
> +       .dot = { .min = 25000, .max = 270000 },
> +       .vco = { .min = 1750000, .max = 3500000},
> +       .n = { .min = 1, .max = 4 },
> +       .m = { .min = 104, .max = 138 },
> +       .m1 = { .min = 17, .max = 23 },
> +       .m2 = { .min = 5, .max = 11 },
> +       .p = { .min = 10, .max = 30 },
> +       .p1 = { .min = 1, .max = 3},
> +       .p2 = { .dot_limit = 270000,
> +               .p2_slow = 10,
> +               .p2_fast = 10
> +       },
> +       .find_pll = intel_g4x_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_g4x_hdmi = {
> +       .dot = { .min = 22000, .max = 400000 },
> +       .vco = { .min = 1750000, .max = 3500000},
> +       .n = { .min = 1, .max = 4 },
> +       .m = { .min = 104, .max = 138 },
> +       .m1 = { .min = 16, .max = 23 },
> +       .m2 = { .min = 5, .max = 11 },
> +       .p = { .min = 5, .max = 80 },
> +       .p1 = { .min = 1, .max = 8},
> +       .p2 = { .dot_limit = 165000,
> +               .p2_slow = 10, .p2_fast = 5 },
> +       .find_pll = intel_g4x_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_g4x_single_channel_lvds = {
> +       .dot = { .min = 20000, .max = 115000 },
> +       .vco = { .min = 1750000, .max = 3500000 },
> +       .n = { .min = 1, .max = 3 },
> +       .m = { .min = 104, .max = 138 },
> +       .m1 = { .min = 17, .max = 23 },
> +       .m2 = { .min = 5, .max = 11 },
> +       .p = { .min = 28, .max = 112 },
> +       .p1 = { .min = 2, .max = 8 },
> +       .p2 = { .dot_limit = 0,
> +               .p2_slow = 14, .p2_fast = 14
> +       },
> +       .find_pll = intel_g4x_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_g4x_dual_channel_lvds = {
> +       .dot = { .min = 80000, .max = 224000 },
> +       .vco = { .min = 1750000, .max = 3500000 },
> +       .n = { .min = 1, .max = 3 },
> +       .m = { .min = 104, .max = 138 },
> +       .m1 = { .min = 17, .max = 23 },
> +       .m2 = { .min = 5, .max = 11 },
> +       .p = { .min = 14, .max = 42 },
> +       .p1 = { .min = 2, .max = 6 },
> +       .p2 = { .dot_limit = 0,
> +               .p2_slow = 7, .p2_fast = 7
> +       },
> +       .find_pll = intel_g4x_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_pineview_sdvo = {
> +       .dot = { .min = 20000, .max = 400000},
> +       .vco = { .min = 1700000, .max = 3500000 },
> +       /* Pineview's Ncounter is a ring counter */
> +       .n = { .min = 3, .max = 6 },
> +       .m = { .min = 2, .max = 256 },
> +       /* Pineview only has one combined m divider, which we treat as m2. */
> +       .m1 = { .min = 0, .max = 0 },
> +       .m2 = { .min = 0, .max = 254 },
> +       .p = { .min = 5, .max = 80 },
> +       .p1 = { .min = 1, .max = 8 },
> +       .p2 = { .dot_limit = 200000,
> +               .p2_slow = 10, .p2_fast = 5 },
> +       .find_pll = intel_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_pineview_lvds = {
> +       .dot = { .min = 20000, .max = 400000 },
> +       .vco = { .min = 1700000, .max = 3500000 },
> +       .n = { .min = 3, .max = 6 },
> +       .m = { .min = 2, .max = 256 },
> +       .m1 = { .min = 0, .max = 0 },
> +       .m2 = { .min = 0, .max = 254 },
> +       .p = { .min = 7, .max = 112 },
> +       .p1 = { .min = 1, .max = 8 },
> +       .p2 = { .dot_limit = 112000,
> +               .p2_slow = 14, .p2_fast = 14 },
> +       .find_pll = intel_find_best_PLL,
> +};
> +
> +/* Ironlake / Sandybridge
> + *
> + * We calculate clock using (register_value + 2) for N/M1/M2, so here
> + * the range value for them is (actual_value - 2).
> + */
> +static const struct intel_limit intel_limits_ironlake_dac = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 1760000, .max = 3510000 },
> +       .n = { .min = 1, .max = 5 },
> +       .m = { .min = 79, .max = 127 },
> +       .m1 = { .min = 12, .max = 22 },
> +       .m2 = { .min = 5, .max = 9 },
> +       .p = { .min = 5, .max = 80 },
> +       .p1 = { .min = 1, .max = 8 },
> +       .p2 = { .dot_limit = 225000,
> +               .p2_slow = 10, .p2_fast = 5 },
> +       .find_pll = intel_g4x_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_ironlake_single_lvds = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 1760000, .max = 3510000 },
> +       .n = { .min = 1, .max = 3 },
> +       .m = { .min = 79, .max = 118 },
> +       .m1 = { .min = 12, .max = 22 },
> +       .m2 = { .min = 5, .max = 9 },
> +       .p = { .min = 28, .max = 112 },
> +       .p1 = { .min = 2, .max = 8 },
> +       .p2 = { .dot_limit = 225000,
> +               .p2_slow = 14, .p2_fast = 14 },
> +       .find_pll = intel_g4x_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_ironlake_dual_lvds = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 1760000, .max = 3510000 },
> +       .n = { .min = 1, .max = 3 },
> +       .m = { .min = 79, .max = 127 },
> +       .m1 = { .min = 12, .max = 22 },
> +       .m2 = { .min = 5, .max = 9 },
> +       .p = { .min = 14, .max = 56 },
> +       .p1 = { .min = 2, .max = 8 },
> +       .p2 = { .dot_limit = 225000,
> +               .p2_slow = 7, .p2_fast = 7 },
> +       .find_pll = intel_g4x_find_best_PLL,
> +};
> +
> +/* LVDS 100mhz refclk limits. */
> +static const struct intel_limit intel_limits_ironlake_single_lvds_100m = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 1760000, .max = 3510000 },
> +       .n = { .min = 1, .max = 2 },
> +       .m = { .min = 79, .max = 126 },
> +       .m1 = { .min = 12, .max = 22 },
> +       .m2 = { .min = 5, .max = 9 },
> +       .p = { .min = 28, .max = 112 },
> +       .p1 = { .min = 2, .max = 8 },
> +       .p2 = { .dot_limit = 225000,
> +               .p2_slow = 14, .p2_fast = 14 },
> +       .find_pll = intel_g4x_find_best_PLL,
> +};
> +
> +static const struct intel_limit intel_limits_ironlake_dual_lvds_100m = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 1760000, .max = 3510000 },
> +       .n = { .min = 1, .max = 3 },
> +       .m = { .min = 79, .max = 126 },
> +       .m1 = { .min = 12, .max = 22 },
> +       .m2 = { .min = 5, .max = 9 },
> +       .p = { .min = 14, .max = 42 },
> +       .p1 = { .min = 2, .max = 6 },
> +       .p2 = { .dot_limit = 225000,
> +               .p2_slow = 7, .p2_fast = 7 },
> +       .find_pll = intel_g4x_find_best_PLL,
> +};
> +
> +static const struct intel_limit 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 = 1, .max = 3 },
> +       .p2 = { .dot_limit = 270000,
> +               .p2_slow = 2, .p2_fast = 20 },
> +       .find_pll = intel_vlv_find_best_pll,
> +};
> +
> +static const struct intel_limit intel_limits_vlv_hdmi = {
> +       .dot = { .min = 25000, .max = 270000 },
> +       .vco = { .min = 4000000, .max = 6000000 },
> +       .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 = 2, .p2_fast = 20 },
> +       .find_pll = intel_vlv_find_best_pll,
> +};
> +
> +static const struct intel_limit intel_limits_vlv_dp = {
> +       .dot = { .min = 25000, .max = 270000 },
> +       .vco = { .min = 4000000, .max = 6000000 },
> +       .n = { .min = 1, .max = 7 },
> +       .m = { .min = 22, .max = 450 },
> +       .m1 = { .min = 2, .max = 3 },
> +       .m2 = { .min = 11, .max = 156 },
> +       .p = { .min = 10, .max = 30 },
> +       .p1 = { .min = 1, .max = 3 },
> +       .p2 = { .dot_limit = 270000,
> +               .p2_slow = 2, .p2_fast = 20 },
> +       .find_pll = intel_vlv_find_best_pll,
> +};
> +
> +static const struct intel_limit *intel_ironlake_limit(struct drm_crtc *crtc,
> +                                               int refclk)
> +{
> +       struct drm_device *dev = crtc->dev;
> +       const struct intel_limit *limit;
> +
> +       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
> +               if (intel_is_dual_link_lvds(dev)) {
> +                       if (refclk == 100000)
> +                               limit = &intel_limits_ironlake_dual_lvds_100m;
> +                       else
> +                               limit = &intel_limits_ironlake_dual_lvds;
> +               } else {
> +                       if (refclk == 100000)
> +                               limit = &intel_limits_ironlake_single_lvds_100m;
> +                       else
> +                               limit = &intel_limits_ironlake_single_lvds;
> +               }
> +       } else
> +               limit = &intel_limits_ironlake_dac;
> +
> +       return limit;
> +}
> +
> +static const struct intel_limit *intel_g4x_limit(struct drm_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->dev;
> +       const struct intel_limit *limit;
> +
> +       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
> +               if (intel_is_dual_link_lvds(dev))
> +                       limit = &intel_limits_g4x_dual_channel_lvds;
> +               else
> +                       limit = &intel_limits_g4x_single_channel_lvds;
> +       } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) ||
> +                  intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
> +               limit = &intel_limits_g4x_hdmi;
> +       } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
> +               limit = &intel_limits_g4x_sdvo;
> +       } else /* The option is for other outputs */
> +               limit = &intel_limits_i9xx_sdvo;
> +
> +       return limit;
> +}
> +
> +const struct intel_limit *intel_limit(struct drm_crtc *crtc, int refclk)
> +{
> +       struct drm_device *dev = crtc->dev;
> +       const struct intel_limit *limit;
> +
> +       if (HAS_PCH_SPLIT(dev))
> +               limit = intel_ironlake_limit(crtc, refclk);
> +       else if (IS_G4X(dev)) {
> +               limit = intel_g4x_limit(crtc);
> +       } else if (IS_PINEVIEW(dev)) {
> +               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
> +                       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;
> +               else
> +                       limit = &intel_limits_i9xx_sdvo;
> +       } else {
> +               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
> +                       limit = &intel_limits_i8xx_lvds;
> +               else
> +                       limit = &intel_limits_i8xx_dvo;
> +       }
> +       return limit;
> +}
> +
> +bool intel_find_pll(const struct intel_limit *limit, struct drm_crtc *crtc,
> +                   int target, int refclk, intel_clock_t *match_clock,
> +                   intel_clock_t *best_clock)
> +{
> +       return limit->find_pll(limit, crtc, target, refclk,
> +                              match_clock, best_clock);
> +}
> --
> 1.7.9.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch



More information about the Intel-gfx mailing list