[coreboot-gerrit] Patch set updated for coreboot: i945/gma.c use linux code to calculate divisors

Arthur Heymans (arthur@aheymans.xyz) gerrit at coreboot.org
Mon Sep 5 23:26:08 CEST 2016


Arthur Heymans (arthur at aheymans.xyz) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16504

-gerrit

commit 6b20db2d0004449aad24982c1caf093f263e4cae
Author: Arthur Heymans <arthur at aheymans.xyz>
Date:   Fri Sep 2 22:35:32 2016 +0200

    i945/gma.c use linux code to calculate divisors
    
    The code to compute n, m1, m2, p1 divisors is not correct in coreboot and
    on some targets hits a working mode at lower refresh rate, which is why
    display is working on some targets.
    The divors must be such "refclk *(5 * (m1 + 2) + (m2 + 2))/ (n + 2)
    / (p1 * p2)" is as close as possible to the target frequency (which
    defined by the resolution and refresh rate.
    
    This patch also fixes the reference frequency.
    
    This patch reuses linux (4.1) code from drivers/gpu/drm/i915/intel_display.c
    to correctly compute divisors.
    
    The result is that some previously not working displays (Lenovo T60 with
    1024x786, 1400x1050, 2048x1536) might work now.
    
    Tested on T60 with 1024x786.
    
    Change-Id: I2c7f3bb0024ac005029eaebe3ecdc70c38ac777e
    Signed-off-by: Arthur Heymans <arthur at aheymans.xyz>
---
 src/northbridge/intel/i945/gma.c | 83 +++++++++++++++++++---------------------
 1 file changed, 39 insertions(+), 44 deletions(-)

diff --git a/src/northbridge/intel/i945/gma.c b/src/northbridge/intel/i945/gma.c
index 02caa0a..3f57e55 100644
--- a/src/northbridge/intel/i945/gma.c
+++ b/src/northbridge/intel/i945/gma.c
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <pc80/vga.h>
 #include <pc80/vga_io.h>
+#include <commonlib/helpers.h>
 
 #include "i945.h"
 #include "chip.h"
@@ -43,7 +44,7 @@
 #define PGETBL_CTL	0x2020
 #define PGETBL_ENABLED	0x00000001
 
-#define BASE_FREQUENCY 120000
+#define BASE_FREQUENCY 100000
 
 #if CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT
 
@@ -85,10 +86,10 @@ static int intel_gma_init(struct northbridge_intel_i945_config *conf,
 	u8 edid_data[128];
 	unsigned long temp;
 	int hpolarity, vpolarity;
-	u32 candp1, candn;
-	u32 best_delta = 0xffffffff;
+	u32 err_most = 0xffffffff;
 	u32 target_frequency;
 	u32 pixel_p1 = 1;
+	u32 pixel_p2;
 	u32 pixel_n = 1;
 	u32 pixel_m1 = 1;
 	u32 pixel_m2 = 1;
@@ -158,43 +159,39 @@ static int intel_gma_init(struct northbridge_intel_i945_config *conf,
 	write32(pmmio + PORT_HOTPLUG_EN, conf->gpu_hotplug);
 	write32(pmmio + INSTPM, 0x08000000 | INSTPM_AGPBUSY_DIS);
 
-	target_frequency = mode->lvds_dual_channel ? mode->pixel_clock
-		: (2 * mode->pixel_clock);
-
-	/* Find suitable divisors.  */
-	for (candp1 = 1; candp1 <= 8; candp1++) {
-		for (candn = 5; candn <= 10; candn++) {
-			u32 cur_frequency;
-			u32 m; /* 77 - 131.  */
-			u32 denom; /* 35 - 560.  */
-			u32 current_delta;
-
-			denom = candn * candp1 * 7;
-			/* Doesnt overflow for up to
-			   5000000 kHz = 5 GHz.  */
-			m = (target_frequency * denom
-			     + BASE_FREQUENCY / 2) / BASE_FREQUENCY;
-
-			if (m < 77 || m > 131)
-				continue;
-
-			cur_frequency = (BASE_FREQUENCY * m) / denom;
-			if (target_frequency > cur_frequency)
-				current_delta = target_frequency - cur_frequency;
-			else
-				current_delta = cur_frequency - target_frequency;
-
-			if (best_delta > current_delta) {
-				best_delta = current_delta;
-				pixel_n = candn;
-				pixel_p1 = candp1;
-				pixel_m2 = ((m + 3) % 5) + 7;
-				pixel_m1 = (m - pixel_m2) / 5;
+	/* p2 divisor must 7 for dual channel LVDS */
+	/* and 14 for single channel LVDS */
+	pixel_p2 = mode->lvds_dual_channel ? 7 : 14;
+	target_frequency = mode->pixel_clock;
+
+	/* Find suitable divisors, m1, m2, p1, n.  */
+	/* refclock * (5 * (m1 + 2) + (m1 + 2)) / (n + 2) / p1 / p2 */
+	/* should be closest to target frequency as possible */
+	u32 candn, candm1, candm2, candp1;
+	for (candm1 = 8; candm1 <= 18; candm1++) {
+		for (candm2 = 3; candm2 <= 7; candm2++) {
+			for (candn = 1; candn <= 6; candn++) {
+				for (candp1 = 1; candp1 <= 8; candp1++) {
+					u32 m = 5 * (candm1 + 2) + (candm2 + 2);
+					u32 p = candp1 * pixel_p2;
+					u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUENCY * m, candn + 2);
+					u32 dot = DIV_ROUND_CLOSEST(vco, p);
+					u32 this_err = ABS(dot - target_frequency);
+					if ((m < 70) || (m > 120))
+						continue;
+					if (this_err < err_most) {
+						err_most = this_err;
+						pixel_n = candn;
+						pixel_m1 = candm1;
+						pixel_m2 = candm2;
+						pixel_p1 = candp1;
+					}
+				}
 			}
 		}
 	}
 
-	if (best_delta == 0xffffffff) {
+	if (err_most == 0xffffffff) {
 		printk (BIOS_ERR, "Couldn't find GFX clock divisors\n");
 		return -1;
 	}
@@ -216,8 +213,8 @@ static int intel_gma_init(struct northbridge_intel_i945_config *conf,
 	printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
 	       pixel_n, pixel_m1, pixel_m2, pixel_p1);
 	printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
-	       BASE_FREQUENCY * (5 * pixel_m1 + pixel_m2) / pixel_n
-	       / (pixel_p1 * 7));
+	       BASE_FREQUENCY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2)) /
+	       (pixel_n + 2) / (pixel_p1 * pixel_p2));
 
 #if !IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)
 	write32(pmmio + PF_WIN_SZ(0), vactive | (hactive << 16));
@@ -242,8 +239,8 @@ static int intel_gma_init(struct northbridge_intel_i945_config *conf,
 	write32(pmmio + PP_CONTROL, PANEL_UNLOCK_REGS
 		| (read32(pmmio + PP_CONTROL) & ~PANEL_UNLOCK_MASK));
 	write32(pmmio + FP0(1),
-		((pixel_n - 2) << 16)
-		| ((pixel_m1 - 2) << 8) | pixel_m2);
+		(pixel_n << 16)
+		| (pixel_m1 << 8) | pixel_m2);
 	write32(pmmio + DPLL(1),
 		DPLL_VGA_MODE_DIS |
 		DPLL_VCO_ENABLE | DPLLB_MODE_LVDS
@@ -252,8 +249,7 @@ static int intel_gma_init(struct northbridge_intel_i945_config *conf,
 		| (conf->gpu_lvds_use_spread_spectrum_clock
 		   ? DPLL_INTEGRATED_CLOCK_VLV | DPLL_INTEGRATED_CRI_CLK_VLV
 		   : 0)
-		| (pixel_p1 << 16)
-		| (pixel_p1));
+		| (0x10000 << pixel_p1));
 	mdelay(1);
 	write32(pmmio + DPLL(1),
 		DPLL_VGA_MODE_DIS |
@@ -261,8 +257,7 @@ static int intel_gma_init(struct northbridge_intel_i945_config *conf,
 		| (mode->lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7
 		   : DPLLB_LVDS_P2_CLOCK_DIV_14)
 		| ((conf->gpu_lvds_use_spread_spectrum_clock ? 3 : 0) << 13)
-		| (pixel_p1 << 16)
-		| (pixel_p1));
+		| (0x10000 << pixel_p1));
 	mdelay(1);
 	write32(pmmio + HTOTAL(1),
 		((hactive + right_border + hblank - 1) << 16)



More information about the coreboot-gerrit mailing list