From 9407ab29c4297af831ac9e6b80768af10fe8a5f4 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Mon, 9 May 2016 23:12:03 -0500 Subject: [PATCH] intel_extreme: Rework PLL calculation * More like linux, improved G4x calculations * Reduce un-needed pll limit complexity * Improved pll limits on ports based on type --- .../accelerants/intel_extreme/Pipes.cpp | 19 +- .../accelerants/intel_extreme/Ports.cpp | 2 +- src/add-ons/accelerants/intel_extreme/pll.cpp | 465 ++++++++++++------ src/add-ons/accelerants/intel_extreme/pll.h | 10 +- 4 files changed, 328 insertions(+), 168 deletions(-) diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.cpp b/src/add-ons/accelerants/intel_extreme/Pipes.cpp index 8f272e70bc..2848d0a449 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.cpp +++ b/src/add-ons/accelerants/intel_extreme/Pipes.cpp @@ -239,7 +239,7 @@ Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock, float refFreq = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) { - float adjusted = ((refFreq * divisors.m) / divisors.n) / divisors.post; + float adjusted = ((refFreq * divisors.m) / divisors.n) / divisors.p; uint32 pixelMultiply = uint32(adjusted / (pixelClock / 1000.0f)); write32(pllMD, (0 << 24) | ((pixelMultiply - 1) << 8)); } @@ -273,34 +273,33 @@ Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock, uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL | extraFlags; if (gInfo->shared_info->device_type.Generation() >= 3) { - // post1 divisor << 1 , 1-8 + // p1 divisor << 1 , 1-8 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) { - pll |= ((1 << (divisors.post1 - 1)) + pll |= ((1 << (divisors.p1 - 1)) << DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT) & DISPLAY_PLL_IGD_POST1_DIVISOR_MASK; } else { - pll |= ((1 << (divisors.post1 - 1)) + pll |= ((1 << (divisors.p1 - 1)) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK; - // pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) + // pll |= ((divisors.p1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) // & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK; } - // p2 clock divider. 5 or 7 high - if (divisors.post2_high) + if (divisors.p2 == 5 || divisors.p2 == 7) pll |= DISPLAY_PLL_DIVIDE_HIGH; if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT; } else { - if (!divisors.post2_high) + if (divisors.p2 != 5 && divisors.p2 != 7) pll |= DISPLAY_PLL_DIVIDE_4X; pll |= DISPLAY_PLL_2X_CLOCK; // TODO: Is this supposed to be DISPLAY_PLL_IGD_POST1_DIVISOR_MASK?? - if (divisors.post1 > 2) { - pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) + if (divisors.p1 > 2) { + pll |= ((divisors.p1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) & DISPLAY_PLL_POST1_DIVISOR_MASK; } else pll |= DISPLAY_PLL_POST1_DIVIDE_2; diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index 7b91200113..14e707d020 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -506,7 +506,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode) // Set the B0-B3 data pairs corresponding to whether we're going to // set the DPLLs for dual-channel mode or not. - if (divisors.post2_high) { + if (divisors.p2 == 5 || divisors.p2 == 7) { TRACE("LVDS: dual channel\n"); lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; } else { diff --git a/src/add-ons/accelerants/intel_extreme/pll.cpp b/src/add-ons/accelerants/intel_extreme/pll.cpp index f6126d72ad..826bcb0fdb 100644 --- a/src/add-ons/accelerants/intel_extreme/pll.cpp +++ b/src/add-ons/accelerants/intel_extreme/pll.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2015, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2016, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -38,117 +38,146 @@ #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) -void -get_pll_limits(pll_limits* limits, bool isLVDS) +// Static pll limits taken from Linux kernel KMS + +static pll_limits kLimitsIlkDac = { + // p, p1, p2, n, m, m1, m2 + { 5, 2, 14, 1, 79, 12, 5}, // min + { 80, 8, 14, 3, 118, 22, 9}, // max + 225000, 1760000, 3510000 +}; + +static pll_limits kLimitsIlkLvdsSingle = { + // p, p1, p2, n, m, m1, m2 + { 28, 2, 14, 1, 79, 12, 5}, // min + {112, 8, 14, 3, 118, 22, 9}, // max + 225000, 1760000, 3510000 +}; + +static pll_limits kLimitsIlkLvdsDual = { + // p, p1, p2, n, m, m1, m2 + { 14, 2, 7, 1, 79, 12, 5}, // min + { 56, 8, 7, 3, 127, 22, 9}, // max + 225000, 1760000, 3510000 +}; + +// 100Mhz RefClock +static pll_limits kLimitsIlkLvdsSingle100 = { + // p, p1, p2, n, m, m1, m2 + { 28, 2, 14, 1, 79, 12, 5}, // min + {112, 8, 14, 2, 126, 22, 9}, // max + 225000, 1760000, 3510000 +}; + +static pll_limits kLimitsIlkLvdsDual100 = { + // p, p1, p2, n, m, m1, m2 + { 14, 2, 7, 1, 79, 12, 5}, // min + { 42, 6, 7, 3, 126, 22, 9}, // max + 225000, 1760000, 3510000 +}; + +#if 0 +static pll_limits kLimitsChv = { + // p, p1, p2, n, m, m1, m2 + { 0, 2, 14, 1, 79, 2, 24 << 22}, // min + { 0, 4, 1, 1, 127, 2, 175 << 22}, // max + 0, 4800000, 6480000 +}; + +static pll_limits kLimitsVlv = { + // p, p1, p2, n, m, m1, m2 + { 0, 2, 20, 1, 79, 2, 11}, // min + { 0, 3, 2, 7, 127, 3, 156}, // max + 0, 4000000, 6000000 +}; + +static pll_limits kLimitsBxt = { + // p, p1, p2, n, m, m1, m2 + { 0, 2, 1, 1, 0, 2, 2 << 22}, // min + { 0, 4, 20, 1, 0, 2, 255 << 22}, // max + 0, 4800000, 6700000 +}; +#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 + { 80, 8, 5, 6, 256, 0, 254}, // max + 200000, 1700000, 3500000 +}; + +static pll_limits kLimitsPinLvds = { + // p, p1, p2, n, m, m1, m2 + { 7, 1, 14, 3, 2, 0, 0}, // min + {112, 8, 14, 6, 256, 0, 254}, // max + 112000, 1700000, 3500000 +}; + +#if 0 +static pll_limits kLimits = { + // p, p1, p2, n, m, m1, m2 + { 4, 2, 4, 5, 96, 20, 8}, + {128, 33, 2, 18, 140, 28, 18}, + 165000, 930000, 1400000 +}; +#endif + + +static bool +lvds_dual_link(display_mode* current) { - // Note, the limits are taken from the X driver; they have not yet been - // tested + float requestedPixelClock = current->timing.pixel_clock / 1000.0f; + if (requestedPixelClock > 112.999) + return true; - // TODO: Breakout BXT + // TODO: Force dual link on MacBookPro6,2 MacBookPro8,2 MacBookPro9,1 - if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) { - pll_limits kLimits = { - // p, p1, p2, high, n, m, m1, m2 - { 5, 2, 14, false, 1, 79, 2, 24 << 22}, // min - { 80, 4, 1, true, 1, 127, 2, 175 << 22}, // max - 225000, 4800000, 6480000 - }; - memcpy(limits, &kLimits, sizeof(pll_limits)); - } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) { - pll_limits kLimits = { - // p, p1, p2, high, n, m, m1, m2 - { 5, 2, 20, false, 1, 79, 2, 11}, // min - { 80, 3, 2, true, 7, 127, 3, 156}, // max - 225000, 4000000, 6000000 - }; - memcpy(limits, &kLimits, sizeof(pll_limits)); - } else if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_SER5) - || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_BXT)) { - pll_limits kLimits = { - // p, p1, p2, high, n, m, m1, m2 - { 5, 1, 10, false, 1, 79, 12, 5}, // min - { 80, 8, 5, true, 5, 127, 22, 9}, // max - 225000, 1760000, 3510000 - }; - // TODO: validate these LVDS dividers! - if (isLVDS) { - kLimits.min.post = 7; - kLimits.max.post = 98; - kLimits.min.post2 = 14; - kLimits.max.post2 = 7; - } - memcpy(limits, &kLimits, sizeof(pll_limits)); - } else if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_9xx)) { - pll_limits kLimits = { - // p, p1, p2, high, n, m, m1, m2 - { 5, 1, 10, false, 1, 70, 8, 3}, // min - { 80, 8, 5, true, 6, 120, 18, 7}, // max - 200000, 1400000, 2800000 - }; - if (isLVDS) { - kLimits.min.post = 7; - kLimits.max.post = 98; - kLimits.min.post2 = 14; - kLimits.max.post2 = 7; - } - memcpy(limits, &kLimits, sizeof(pll_limits)); - } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)) { - pll_limits kLimits = { - // p, p1, p2, high, n, m, m1, m2 - { 10, 1, 10, false, 1, 104, 17, 5}, // min - { 30, 3, 10, true, 4, 138, 23, 11}, // max - 270000, 1750000, 3500000 - }; - // TODO: validate these LVDS dividers! - if (isLVDS) { - kLimits.min.post = 7; - kLimits.max.post = 98; - kLimits.min.post2 = 14; - kLimits.max.post2 = 7; - } - memcpy(limits, &kLimits, sizeof(pll_limits)); - } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) { - // m1 is reserved and must be 0 - pll_limits kLimits = { - // p, p1, p2, high, n, m, m1, m2 - { 5, 1, 10, false, 3, 2, 0, 2}, // min - { 80, 8, 5, true, 6, 256, 0, 254}, // max - 200000, 1700000, 3500000 - }; - if (isLVDS) { - kLimits.min.post = 7; - kLimits.max.post = 112; - kLimits.min.post2 = 14; - kLimits.max.post2 = 14; - } - memcpy(limits, &kLimits, sizeof(pll_limits)); - } else { - static pll_limits kLimits = { - // p, p1, p2, high, n, m, m1, m2 - { 4, 2, 4, false, 5, 96, 20, 8}, - {128, 33, 2, true, 18, 140, 28, 18}, - 165000, 930000, 1400000 - }; - // TODO: Validate these LVDS dividers! - if (isLVDS) { - kLimits.min.post = 7; - kLimits.max.post = 98; - kLimits.min.post2 = 14; - kLimits.max.post2 = 7; - } - memcpy(limits, &kLimits, sizeof(pll_limits)); - } - - TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", " - "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " - "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits->min.post, - limits->min.post1, limits->min.post2, limits->min.n, limits->min.m, - limits->min.m1, limits->min.m2); - TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", " - "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " - "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits->max.post, - limits->max.post1, limits->max.post2, limits->max.n, limits->max.m, - limits->max.m1, limits->max.m2); + return ((read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK) + == LVDS_CLKB_POWER_UP); } @@ -157,9 +186,9 @@ valid_pll_divisors(pll_divisors* divisors, pll_limits* limits) { pll_info &info = gInfo->shared_info->pll_info; uint32 vco = info.reference_frequency * divisors->m / divisors->n; - uint32 frequency = vco / divisors->post; + uint32 frequency = vco / divisors->p; - if (divisors->post < limits->min.post || divisors->post > limits->max.post + if (divisors->p < limits->min.p || divisors->p > limits->max.p || divisors->m < limits->min.m || divisors->m > limits->max.m || vco < limits->min_vco || vco > limits->max_vco || frequency < info.min_frequency || frequency > info.max_frequency) @@ -169,6 +198,30 @@ valid_pll_divisors(pll_divisors* divisors, pll_limits* limits) } +static void +compute_pll_p2(display_mode* current, pll_divisors* divisors, + pll_limits* limits, bool isLVDS) +{ + if (isLVDS) { + if (lvds_dual_link(current)) { + // fast DAC timing via 2 channels (dual link LVDS) + divisors->p2 = limits->max.p2; + } else { + // slow DAC timing + divisors->p2 = limits->min.p2; + } + } else { + if (current->timing.pixel_clock < limits->dot_limit) { + // slow DAC timing + divisors->p2 = limits->min.p2; + } else { + // fast DAC timing + divisors->p2 = limits->max.p2; + } + } +} + + static uint32 compute_pll_m(pll_divisors* divisors) { @@ -194,68 +247,160 @@ compute_pll_m(pll_divisors* divisors) static uint32 compute_pll_p(pll_divisors* divisors) { - return divisors->post1 * divisors->post2; + return divisors->p1 * divisors->p2; } -void -compute_pll_divisors(display_mode* current, pll_divisors* divisors, - bool isLVDS) +static void +compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS) { float requestedPixelClock = current->timing.pixel_clock / 1000.0f; float referenceClock = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; - pll_limits limits; - get_pll_limits(&limits, isLVDS); TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock); - // Calculate p2 - if (isLVDS) { - if (requestedPixelClock > 112.999 - || (read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK) - == LVDS_CLKB_POWER_UP) { - // fast DAC timing via 2 channels - divisors->post2 = limits.max.post2; - divisors->post2_high = limits.max.post2_high; - } else { - // slow DAC timing - divisors->post2 = limits.min.post2; - divisors->post2_high = limits.min.post2_high; - } + pll_limits limits; + if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)) { + // TODO: Pass port type via video_configuration + if (isLVDS) { + if (lvds_dual_link(current)) + memcpy(&limits, &kLimitsG4xLvdsDual, sizeof(pll_limits)); + else + memcpy(&limits, &kLimitsG4xLvdsSingle, sizeof(pll_limits)); + //} else if (type == INTEL_PORT_TYPE_HDMI) { + // memcpy(&limits, &kLimitsG4xHdmi, sizeof(pll_limits)); + } else + memcpy(&limits, &kLimitsG4xSdvo, sizeof(pll_limits)); } else { - if (current->timing.pixel_clock < limits.min_post2_frequency) { - // slow DAC timing - divisors->post2 = limits.min.post2; - divisors->post2_high = limits.min.post2_high; + if (isLVDS) { + if (lvds_dual_link(current)) { + if (referenceClock == 100.0) + memcpy(&limits, &kLimitsIlkLvdsDual100, sizeof(pll_limits)); + else + memcpy(&limits, &kLimitsIlkLvdsDual, sizeof(pll_limits)); + } else { + if (referenceClock == 100.0) { + memcpy(&limits, &kLimitsIlkLvdsSingle100, + sizeof(pll_limits)); + } else { + memcpy(&limits, &kLimitsIlkLvdsSingle, sizeof(pll_limits)); + } + } } else { - // fast DAC timing - divisors->post2 = limits.max.post2; - divisors->post2_high = limits.max.post2_high; + memcpy(&limits, &kLimitsIlkDac, sizeof(pll_limits)); } } + compute_pll_p2(current, divisors, &limits, isLVDS); + + TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", " + "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " + "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p, + limits.min.p1, limits.min.p2, limits.min.n, limits.min.m, + limits.min.m1, limits.min.m2); + TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", " + "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " + "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p, + limits.max.p1, limits.max.p2, limits.max.n, limits.max.m, + limits.max.m1, limits.max.m2); + float best = requestedPixelClock; pll_divisors bestDivisors; - bool is_pine = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN); - for (divisors->m1 = limits.min.m1; divisors->m1 <= limits.max.m1; - divisors->m1++) { - for (divisors->m2 = limits.min.m2; divisors->m2 <= limits.max.m2 - && ((divisors->m2 < divisors->m1) || is_pine); divisors->m2++) { - for (divisors->n = limits.min.n; divisors->n <= limits.max.n; - divisors->n++) { - for (divisors->post1 = limits.min.post1; - divisors->post1 <= limits.max.post1; divisors->post1++) { + uint32 maxn = limits.max.n; + for (divisors->n = limits.min.n; divisors->n <= maxn; divisors->n++) { + for (divisors->m1 = limits.max.m1; divisors->m1 >= limits.min.m1; + divisors->m1--) { + for (divisors->m2 = limits.max.m2; divisors->m2 >= limits.min.m2; + divisors->m2--) { + for (divisors->p1 = limits.max.p1; + divisors->p1 >= limits.max.p1; divisors->p1--) { divisors->m = compute_pll_m(divisors); - divisors->post = compute_pll_p(divisors); + divisors->p = compute_pll_p(divisors); if (!valid_pll_divisors(divisors, &limits)) continue; float error = fabs(requestedPixelClock - ((referenceClock * divisors->m) / divisors->n) - / divisors->post); + / divisors->p); + if (error < best) { + best = error; + bestDivisors = *divisors; + maxn = divisors->n; + + if (error == 0) + break; + } + } + } + } + } + *divisors = bestDivisors; + TRACE("%s: best MHz: %g (error: %g)\n", __func__, + ((referenceClock * divisors->m) / divisors->n) / divisors->p, + best); +} + + +static void +compute_dpll_9xx(display_mode* current, pll_divisors* divisors, bool isLVDS) +{ + float requestedPixelClock = current->timing.pixel_clock / 1000.0f; + float referenceClock + = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; + + TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock); + + pll_limits limits; + if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) { + if (isLVDS) + memcpy(&limits, &kLimitsPinLvds, sizeof(pll_limits)); + else + memcpy(&limits, &kLimitsPinSdvo, sizeof(pll_limits)); + } else { + if (isLVDS) + memcpy(&limits, &kLimits9xxLvds, sizeof(pll_limits)); + else + memcpy(&limits, &kLimits9xxSdvo, sizeof(pll_limits)); + } + + compute_pll_p2(current, divisors, &limits, isLVDS); + + TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", " + "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " + "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p, + limits.min.p1, limits.min.p2, limits.min.n, limits.min.m, + limits.min.m1, limits.min.m2); + TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", " + "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " + "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p, + limits.max.p1, limits.max.p2, limits.max.n, limits.max.m, + limits.max.m1, limits.max.m2); + + bool is_pine = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN); + + float best = requestedPixelClock; + pll_divisors bestDivisors; + + for (divisors->m1 = limits.min.m1; divisors->m1 <= limits.max.m1; + divisors->m1++) { + for (divisors->m2 = limits.min.m2; divisors->m2 <= limits.max.m2 + && ((divisors->m2 < divisors->m1) || is_pine); divisors->m2++) { + for (divisors->n = limits.min.n; divisors->n <= limits.max.n; + divisors->n++) { + for (divisors->p1 = limits.min.p1; + divisors->p1 <= limits.max.p1; divisors->p1++) { + divisors->m = compute_pll_m(divisors); + divisors->p = compute_pll_p(divisors); + + if (!valid_pll_divisors(divisors, &limits)) + continue; + + float error = fabs(requestedPixelClock + - ((referenceClock * divisors->m) / divisors->n) + / divisors->p); if (error < best) { best = error; bestDivisors = *divisors; @@ -270,10 +415,28 @@ compute_pll_divisors(display_mode* current, pll_divisors* divisors, *divisors = bestDivisors; - TRACE("%s: found: %g MHz, p = %" B_PRId32 " (p1 = %" B_PRId32 ", " + TRACE("%s: best MHz: %g (error: %g)\n", __func__, + ((referenceClock * divisors->m) / divisors->n) / divisors->p, + best); +} + + +void +compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS) +{ + if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x) + || gInfo->shared_info->device_type.HasPlatformControlHub()) { + compute_dpll_g4x(current, divisors, isLVDS); + } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) { + // TODO: CherryView + } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) { + // TODO: VallyView + } else + compute_dpll_9xx(current, divisors, isLVDS); + + TRACE("%s: found: p = %" B_PRId32 " (p1 = %" B_PRId32 ", " "p2 = %" B_PRId32 "), n = %" B_PRId32 ", m = %" B_PRId32 " " "(m1 = %" B_PRId32 ", m2 = %" B_PRId32 ")\n", __func__, - ((referenceClock * divisors->m) / divisors->n) / divisors->post, - divisors->post, divisors->post1, divisors->post2, divisors->n, + divisors->p, divisors->p1, divisors->p2, divisors->n, divisors->m, divisors->m1, divisors->m2); } diff --git a/src/add-ons/accelerants/intel_extreme/pll.h b/src/add-ons/accelerants/intel_extreme/pll.h index 706f97b6c1..2b607ce756 100644 --- a/src/add-ons/accelerants/intel_extreme/pll.h +++ b/src/add-ons/accelerants/intel_extreme/pll.h @@ -14,10 +14,9 @@ struct pll_divisors { - uint32 post; - uint32 post1; - uint32 post2; - bool post2_high; + uint32 p; + uint32 p1; + uint32 p2; uint32 n; uint32 m; uint32 m1; @@ -27,13 +26,12 @@ struct pll_divisors { struct pll_limits { pll_divisors min; pll_divisors max; - uint32 min_post2_frequency; + uint32 dot_limit; uint32 min_vco; uint32 max_vco; }; -void get_pll_limits(pll_limits* limits, bool isLVDS); bool valid_pll_divisors(pll_divisors* divisors, pll_limits* limits); void compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS);