diff options
author | Chon Ming Lee <chon.ming.lee@intel.com> | 2014-04-09 06:28:18 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-05-12 13:50:14 -0400 |
commit | ef9348c8605264342513f78d6256262886b63eab (patch) | |
tree | 8c80602b54b81d069d5c2584d49eb769de8c82fb /drivers/gpu/drm/i915/intel_display.c | |
parent | 076ed3b2955e5934e137abff39fe9e7180f236fe (diff) |
drm/i915/chv: find the best divisor for the target clock v4
Based on the chv clock limit, find the best divisor.
The divisor data has been verified with this spreadsheet.
P1273_DPLL_Programming Spreadsheet.
v2: Rebase the code and change the chv_find_best_dpll based on new
standard way to use intel_PLL_is_valid. Besides, clean up some extra
variables.
v3: Ville suggest better fixed point for m2 calculation.
v4: -Add comment for the limit is compute using fast clock. (Ville)
-Don't pass the request clock to chv_clock, as the same function will
be use clock readout, which doens't have request clock. (Ville)
-Add and use DIV_ROUND_CLOSEST_ULL to consistent with other clock
calculation. (Ville)
-Fix the dp m2 after m2 has stored fixed point. (Ville)
Signed-off-by: Chon Ming Lee <chon.ming.lee@intel.com>
[vsyrjala: Avoid div-by-zero in chv_clock()]
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8942f393b791..13330fd7b21c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -41,6 +41,9 @@ | |||
41 | #include <drm/drm_crtc_helper.h> | 41 | #include <drm/drm_crtc_helper.h> |
42 | #include <linux/dma_remapping.h> | 42 | #include <linux/dma_remapping.h> |
43 | 43 | ||
44 | #define DIV_ROUND_CLOSEST_ULL(ll, d) \ | ||
45 | ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; }) | ||
46 | |||
44 | static void intel_increase_pllclock(struct drm_crtc *crtc); | 47 | static void intel_increase_pllclock(struct drm_crtc *crtc); |
45 | static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); | 48 | static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); |
46 | 49 | ||
@@ -328,6 +331,22 @@ static const intel_limit_t intel_limits_vlv = { | |||
328 | .p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ | 331 | .p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */ |
329 | }; | 332 | }; |
330 | 333 | ||
334 | static const intel_limit_t intel_limits_chv = { | ||
335 | /* | ||
336 | * These are the data rate limits (measured in fast clocks) | ||
337 | * since those are the strictest limits we have. The fast | ||
338 | * clock and actual rate limits are more relaxed, so checking | ||
339 | * them would make no difference. | ||
340 | */ | ||
341 | .dot = { .min = 25000 * 5, .max = 540000 * 5}, | ||
342 | .vco = { .min = 4860000, .max = 6700000 }, | ||
343 | .n = { .min = 1, .max = 1 }, | ||
344 | .m1 = { .min = 2, .max = 2 }, | ||
345 | .m2 = { .min = 24 << 22, .max = 175 << 22 }, | ||
346 | .p1 = { .min = 2, .max = 4 }, | ||
347 | .p2 = { .p2_slow = 1, .p2_fast = 14 }, | ||
348 | }; | ||
349 | |||
331 | static void vlv_clock(int refclk, intel_clock_t *clock) | 350 | static void vlv_clock(int refclk, intel_clock_t *clock) |
332 | { | 351 | { |
333 | clock->m = clock->m1 * clock->m2; | 352 | clock->m = clock->m1 * clock->m2; |
@@ -412,6 +431,8 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk) | |||
412 | limit = &intel_limits_pineview_lvds; | 431 | limit = &intel_limits_pineview_lvds; |
413 | else | 432 | else |
414 | limit = &intel_limits_pineview_sdvo; | 433 | limit = &intel_limits_pineview_sdvo; |
434 | } else if (IS_CHERRYVIEW(dev)) { | ||
435 | limit = &intel_limits_chv; | ||
415 | } else if (IS_VALLEYVIEW(dev)) { | 436 | } else if (IS_VALLEYVIEW(dev)) { |
416 | limit = &intel_limits_vlv; | 437 | limit = &intel_limits_vlv; |
417 | } else if (!IS_GEN2(dev)) { | 438 | } else if (!IS_GEN2(dev)) { |
@@ -456,6 +477,17 @@ static void i9xx_clock(int refclk, intel_clock_t *clock) | |||
456 | clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); | 477 | clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); |
457 | } | 478 | } |
458 | 479 | ||
480 | static void chv_clock(int refclk, intel_clock_t *clock) | ||
481 | { | ||
482 | clock->m = clock->m1 * clock->m2; | ||
483 | clock->p = clock->p1 * clock->p2; | ||
484 | if (WARN_ON(clock->n == 0 || clock->p == 0)) | ||
485 | return; | ||
486 | clock->vco = DIV_ROUND_CLOSEST_ULL((uint64_t)refclk * clock->m, | ||
487 | clock->n << 22); | ||
488 | clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); | ||
489 | } | ||
490 | |||
459 | #define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) | 491 | #define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) |
460 | /** | 492 | /** |
461 | * Returns whether the given set of divisors are valid for a given refclk with | 493 | * Returns whether the given set of divisors are valid for a given refclk with |
@@ -731,6 +763,58 @@ vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, | |||
731 | return found; | 763 | return found; |
732 | } | 764 | } |
733 | 765 | ||
766 | static bool | ||
767 | chv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, | ||
768 | int target, int refclk, intel_clock_t *match_clock, | ||
769 | intel_clock_t *best_clock) | ||
770 | { | ||
771 | struct drm_device *dev = crtc->dev; | ||
772 | intel_clock_t clock; | ||
773 | uint64_t m2; | ||
774 | int found = false; | ||
775 | |||
776 | memset(best_clock, 0, sizeof(*best_clock)); | ||
777 | |||
778 | /* | ||
779 | * Based on hardware doc, the n always set to 1, and m1 always | ||
780 | * set to 2. If requires to support 200Mhz refclk, we need to | ||
781 | * revisit this because n may not 1 anymore. | ||
782 | */ | ||
783 | clock.n = 1, clock.m1 = 2; | ||
784 | target *= 5; /* fast clock */ | ||
785 | |||
786 | for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { | ||
787 | for (clock.p2 = limit->p2.p2_fast; | ||
788 | clock.p2 >= limit->p2.p2_slow; | ||
789 | clock.p2 -= clock.p2 > 10 ? 2 : 1) { | ||
790 | |||
791 | clock.p = clock.p1 * clock.p2; | ||
792 | |||
793 | m2 = DIV_ROUND_CLOSEST_ULL(((uint64_t)target * clock.p * | ||
794 | clock.n) << 22, refclk * clock.m1); | ||
795 | |||
796 | if (m2 > INT_MAX/clock.m1) | ||
797 | continue; | ||
798 | |||
799 | clock.m2 = m2; | ||
800 | |||
801 | chv_clock(refclk, &clock); | ||
802 | |||
803 | if (!intel_PLL_is_valid(dev, limit, &clock)) | ||
804 | continue; | ||
805 | |||
806 | /* based on hardware requirement, prefer bigger p | ||
807 | */ | ||
808 | if (clock.p > best_clock->p) { | ||
809 | *best_clock = clock; | ||
810 | found = true; | ||
811 | } | ||
812 | } | ||
813 | } | ||
814 | |||
815 | return found; | ||
816 | } | ||
817 | |||
734 | bool intel_crtc_active(struct drm_crtc *crtc) | 818 | bool intel_crtc_active(struct drm_crtc *crtc) |
735 | { | 819 | { |
736 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | 820 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
@@ -11004,6 +11088,8 @@ static void intel_init_display(struct drm_device *dev) | |||
11004 | 11088 | ||
11005 | if (HAS_PCH_SPLIT(dev) || IS_G4X(dev)) | 11089 | if (HAS_PCH_SPLIT(dev) || IS_G4X(dev)) |
11006 | dev_priv->display.find_dpll = g4x_find_best_dpll; | 11090 | dev_priv->display.find_dpll = g4x_find_best_dpll; |
11091 | else if (IS_CHERRYVIEW(dev)) | ||
11092 | dev_priv->display.find_dpll = chv_find_best_dpll; | ||
11007 | else if (IS_VALLEYVIEW(dev)) | 11093 | else if (IS_VALLEYVIEW(dev)) |
11008 | dev_priv->display.find_dpll = vlv_find_best_dpll; | 11094 | dev_priv->display.find_dpll = vlv_find_best_dpll; |
11009 | else if (IS_PINEVIEW(dev)) | 11095 | else if (IS_PINEVIEW(dev)) |