Пример #1
0
static void
compute_pll_divisors(const 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);

	TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock);

	if (isLVDS) {
		if ((read32(INTEL_DISPLAY_LVDS_PORT) & LVDS_CLKB_POWER_MASK)
				== LVDS_CLKB_POWER_UP)
			divisors.post2 = LVDS_POST2_RATE_FAST;
		else
			divisors.post2 = LVDS_POST2_RATE_SLOW;
	} 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_igd = gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD);
	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_igd); 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 = 5 * divisors.m1 + divisors.m2;
					divisors.post = divisors.post1 * divisors.post2;

					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 = %lu (p1 = %lu, p2 = %lu), n = %lu, m = %lu "
		"(m1 = %lu, m2 = %lu)\n", __func__,
		((referenceClock * divisors.m) / divisors.n) / divisors.post,
		divisors.post, divisors.post1, divisors.post2, divisors.n,
		divisors.m, divisors.m1, divisors.m2);
}
Пример #2
0
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);
}
Пример #3
0
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);
}
Пример #4
0
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);
}