[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