From b8f6e4813d2befd024b556e6dec98398489b69b5 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sat, 5 Oct 2019 19:03:20 +0200 Subject: [PATCH] intel_extreme: fix PLL limits for G4x As for other devices, N=1 makes no sense because N-2 is eventually written to the hardware register, so wherever these values come from, they can't be correct. Replace with the values from the Intel manual. Also fix confusion as to when the + 2 or - 2 is applied to M1 and M2 values. The documentation says M1+2 and M2+2 are used in frequency computations, but we instead write M1-2 and M2-2 to the registers, so the M1 and M2 in our limit structs has an offset of 2 from the docs. Should fix #13694. Change-Id: I87157154d22a5e6caf622d71a2f0e0b9ff21a2fa Reviewed-on: https://review.haiku-os.org/c/haiku/+/1902 Reviewed-by: waddlesplash --- src/add-ons/accelerants/intel_extreme/pll.cpp | 158 ++++++++++-------- 1 file changed, 89 insertions(+), 69 deletions(-) diff --git a/src/add-ons/accelerants/intel_extreme/pll.cpp b/src/add-ons/accelerants/intel_extreme/pll.cpp index e319253c83..1933d44cdf 100644 --- a/src/add-ons/accelerants/intel_extreme/pll.cpp +++ b/src/add-ons/accelerants/intel_extreme/pll.cpp @@ -39,45 +39,115 @@ #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) +// PLL limits, taken from programming manual when available, and from Linux KMS +// drivers otherwise. However, note that we use the values of N+2, M1+2 and +// M2+2 here, the - 2 being applied when we write the values to the registers. -// Static pll limits taken from Linux kernel KMS +static pll_limits kLimits85x = { + // p, p1, p2, n, m, m1, m2 + { 4, 2, 4, 5, 96, 20, 8}, + {128, 33, 2, 18, 140, 28, 18}, + 165000, 930000, 1400000 +}; + +// TODO according to the docs, the limits for 9xx anf G45 should be the same. +// For Iron Lake, a new set of timings is introduced along with the FDI system, +// and carried on to later cards with just one further change (to the P2 cutoff +// frequency) in Sandy Bridge. +// +// So, it makes no sense to have separa limits and algorithm for 9xx and G45. + +static pll_limits kLimits9xxSdvo = { + // p, p1, p2, n, m, m1, m2 + { 5, 1, 10, 5, 70, 12, 7}, // min + { 80, 8, 5, 10, 120, 22, 11}, // max + 200000, 1400000, 2800000 +}; + +static pll_limits kLimits9xxLvds = { + // p, p1, p2, n, m, m1, m2 + { 7, 1, 14, 1, 70, 8, 3}, // min + { 98, 8, 7, 6, 120, 18, 7}, // max + 112000, 1400000, 2800000 +}; + +// Limits for G45 cards taken from g45_vlo3_register_0_0_0.pdf, page 46 +// Note that n here is actually n+2, but m1 and m2 are as in the datasheet. + +static pll_limits kLimitsG4xSdvo = { + // p, p1, p2, n, m, m1, m2 + { 5, 1, 5, 5, 70, 12, 7}, // min + { 80, 8, 10, 10, 120, 22, 11}, // max + 270000, 1400000, 2800000 +}; + +#if 0 +static pll_limits kLimitsG4xHdmi = { + // p, p1, p2, n, m, m1, m2 + { 5, 1, 10, 5, 70, 12, 7}, // min + { 80, 8, 5, 10, 120, 22, 11}, // max + 165000, 1400000, 2800000 +}; +#endif + +static pll_limits kLimitsG4xLvdsSingle = { + // p, p1, p2, n, m, m1, m2 + { 7, 1, 14, 5, 70, 12, 7}, // min + { 98, 8, 14, 10, 120, 22, 11}, // max + 0, 1400000, 2800000 +}; + +static pll_limits kLimitsG4xLvdsDual = { + // p, p1, p2, n, m, m1, m2 + { 14, 2, 7, 5, 70, 12, 7}, // min + { 42, 6, 7, 10, 120, 22, 11}, // max + 0, 1400000, 2800000 +}; static pll_limits kLimitsIlkDac = { // p, p1, p2, n, m, m1, m2 - { 5, 1, 5, 3, 79, 12, 5}, // min - { 80, 8, 10, 8, 118, 22, 9}, // max + { 5, 1, 5, 3, 79, 14, 7}, // min + { 80, 8, 10, 8, 118, 24, 11}, // max 225000, 1760000, 3510000 }; static pll_limits kLimitsIlkLvdsSingle = { // p, p1, p2, n, m, m1, m2 - { 28, 2, 14, 3, 79, 12, 5}, // min - {112, 8, 14, 8, 118, 22, 9}, // max + { 28, 2, 14, 3, 79, 14, 7}, // min + {112, 8, 14, 8, 118, 24, 11}, // max 225000, 1760000, 3510000 }; static pll_limits kLimitsIlkLvdsDual = { // p, p1, p2, n, m, m1, m2 - { 14, 2, 7, 3, 79, 12, 5}, // min - { 56, 8, 7, 8, 127, 22, 9}, // max + { 14, 2, 7, 3, 79, 14, 7}, // min + { 56, 8, 7, 8, 127, 24, 11}, // max 225000, 1760000, 3510000 }; // 100Mhz RefClock static pll_limits kLimitsIlkLvdsSingle100 = { // p, p1, p2, n, m, m1, m2 - { 28, 2, 14, 3, 79, 12, 5}, // min - {112, 8, 14, 8, 126, 22, 9}, // max + { 28, 2, 14, 3, 79, 14, 7}, // min + {112, 8, 14, 8, 126, 24, 11}, // max 225000, 1760000, 3510000 }; static pll_limits kLimitsIlkLvdsDual100 = { // p, p1, p2, n, m, m1, m2 - { 14, 2, 7, 3, 79, 12, 5}, // min - { 42, 6, 7, 8, 126, 22, 9}, // max + { 14, 2, 7, 3, 79, 14, 7}, // min + { 42, 6, 7, 8, 126, 24, 11}, // max 225000, 1760000, 3510000 }; +// TODO From haswell onwards, a completely different PLL design is used +// (intel_gfx-prm-osrc-hsw-display_0.pdf, page 268 for VGA). It uses a "virtual +// root frequency" and one just has to set a single divider (integer and +// fractional parts), so it makes no sense to reuse the same code and limit +// structures there. +// +// For other display connections, the clock is handled differently, as there is +// no need for a precise timing to send things in sync with the display. #if 0 static pll_limits kLimitsChv = { // p, p1, p2, n, m, m1, m2 @@ -101,50 +171,6 @@ static pll_limits kLimitsBxt = { }; #endif -static pll_limits kLimits9xxSdvo = { - // p, p1, p2, n, m, m1, m2 - { 5, 1, 10, 5, 70, 12, 7}, // min - { 80, 8, 5, 10, 120, 22, 11}, // max - 200000, 1400000, 2800000 -}; - -static pll_limits kLimits9xxLvds = { - // p, p1, p2, n, m, m1, m2 - { 7, 1, 14, 1, 70, 8, 3}, // min - { 98, 8, 7, 6, 120, 18, 7}, // max - 112000, 1400000, 2800000 -}; - -static pll_limits kLimitsG4xSdvo = { - // p, p1, p2, n, m, m1, m2 - { 10, 1, 10, 1, 104, 17, 5}, // min - { 30, 3, 10, 4, 138, 23, 11}, // max - 270000, 1750000, 3500000 -}; - -#if 0 -static pll_limits kLimitsG4xHdmi = { - // p, p1, p2, n, m, m1, m2 - { 5, 1, 10, 1, 104, 16, 5}, // min - { 80, 8, 5, 4, 138, 23, 11}, // max - 165000, 1750000, 3500000 -}; -#endif - -static pll_limits kLimitsG4xLvdsSingle = { - // p, p1, p2, n, m, m1, m2 - { 28, 2, 14, 1, 104, 17, 5}, // min - { 112, 8, 14, 3, 138, 23, 11}, // max - 0, 1750000, 3500000 -}; - -static pll_limits kLimitsG4xLvdsDual = { - // p, p1, p2, n, m, m1, m2 - { 14, 2, 7, 1, 104, 17, 5}, // min - { 42, 6, 7, 3, 138, 23, 11}, // max - 0, 1750000, 3500000 -}; - static pll_limits kLimitsPinSdvo = { // p, p1, p2, n, m, m1, m2 { 5, 1, 10, 3, 2, 0, 0}, // min @@ -159,13 +185,6 @@ static pll_limits kLimitsPinLvds = { 112000, 1700000, 3500000 }; -static pll_limits kLimits85x = { - // p, p1, p2, n, m, m1, m2 - { 4, 2, 4, 5, 96, 20, 8}, - {128, 33, 2, 18, 140, 28, 18}, - 165000, 930000, 1400000 -}; - static bool lvds_dual_link(display_mode* current) @@ -222,6 +241,13 @@ compute_pll_p2(display_mode* current, pll_divisors* divisors, } +// TODO we can simplify this computation, with the way the dividers are set, we +// know that all values in the valid range for M are reachable. M1 allows to +// generate any multiple of 5 in the range and M2 allows to reach the 4 next +// values. Therefore, we don't need to loop over the range of values for M1 and +// M2 separately, we could instead just loop over possible values for M. +// For this to work, the logic of this function must be reversed: for a given M, +// it should give the resulting M1 and M2 values for programming the registers. static uint32 compute_pll_m(pll_divisors* divisors) { @@ -232,13 +258,7 @@ compute_pll_m(pll_divisors* divisors) // Pineview, m1 is reserved if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) - return divisors->m2 + 2; - - if (gInfo->shared_info->device_type.Generation() >= 3) - return 5 * (divisors->m1 + 2) + (divisors->m2 + 2); - - // TODO: This logic needs validated... PLL's were calculated differently - // on 8xx chipsets + return divisors->m2; return 5 * divisors->m1 + divisors->m2; }