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; TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock); 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 (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 { 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; 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.min.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; 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; if (error == 0) break; } } } } } *divisors = bestDivisors; 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) { 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; } } 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; } else { // fast DAC timing divisors->post2 = limits.max.post2; divisors->post2_high = limits.max.post2_high; } } 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++) { divisors->m = compute_pll_m(divisors); divisors->post = compute_pll_p(divisors); if (!valid_pll_divisors(divisors, &limits)) continue; float error = fabs(requestedPixelClock - ((referenceClock * divisors->m) / divisors->n) / divisors->post); if (error < best) { best = error; bestDivisors = *divisors; if (error == 0) break; } } } } } *divisors = bestDivisors; TRACE("%s: found: %g MHz, 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->m, divisors->m1, divisors->m2); }