[coreboot-gerrit] New patch to review for coreboot: nb/intel/sandybridge/gma: rework FDI link training

Patrick Rudolph (siro@das-labor.org) gerrit at coreboot.org
Wed Apr 20 18:12:22 CEST 2016


Patrick Rudolph (siro at das-labor.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14438

-gerrit

commit 05680e7c0e2039aa5c78fcfdb41ad8a72d4ff48d
Author: Patrick Rudolph <siro at das-labor.org>
Date:   Wed Apr 13 14:55:47 2016 +0200

    nb/intel/sandybridge/gma: rework FDI link training
    
    Deblob the FDI link training function by using existing
    defines from i915_reg.h.
    All register writes are the same but has been extended to
    iterate over all possible values and it reads back
    the interrupt status registers to probe for successful
    link training.
    
    The functionality is very similar to the i915 Intel kernel
    module, but instead of a variable count of lanes the
    VBIOS trains all FDI lanes.
    
    Tested on T520: Intel Sandybridge and Cougar Point PCH
    Needs test on: Intel Sandybridge and Panther Point PCH
    
    Change-Id: Iafe2b0bcb6a386b2ed02d33558edb3928da96487
    Signed-off-by: Patrick Rudolph <siro at das-labor.org>
---
 src/drivers/intel/gma/i915_reg.h                   |   4 +
 .../intel/sandybridge/gma_sandybridge_lvds.c       | 201 ++++++++++++++++++---
 2 files changed, 175 insertions(+), 30 deletions(-)

diff --git a/src/drivers/intel/gma/i915_reg.h b/src/drivers/intel/gma/i915_reg.h
index 2ee5748..5c917d2 100644
--- a/src/drivers/intel/gma/i915_reg.h
+++ b/src/drivers/intel/gma/i915_reg.h
@@ -3404,6 +3404,8 @@
 #define	 TRANSC_DPLLB_SEL	(1<<8)
 #define	 TRANSC_DPLLA_SEL	(0)
 
+#define HAS_PCH_CPT(dev) ((dev->device & 0xff00) == 0x1c00)
+
 /* transcoder */
 
 #define _TRANS_HTOTAL_A          0xe0000
@@ -3623,6 +3625,8 @@
 #define  FDI_LINK_TRAIN_600MV_3_5DB_SNB_B	(0x39<<22)
 #define  FDI_LINK_TRAIN_800MV_0DB_SNB_B		(0x38<<22)
 #define  FDI_LINK_TRAIN_VOL_EMP_MASK		(0x3f<<22)
+#define  FDI_DP_PORT_WIDTH_SHIFT		19
+#define  FDI_DP_PORT_WIDTH_MASK			(7 << FDI_DP_PORT_WIDTH_SHIFT)
 #define  FDI_DP_PORT_WIDTH_X1           (0<<19)
 #define  FDI_DP_PORT_WIDTH_X2           (1<<19)
 #define  FDI_DP_PORT_WIDTH_X3           (2<<19)
diff --git a/src/northbridge/intel/sandybridge/gma_sandybridge_lvds.c b/src/northbridge/intel/sandybridge/gma_sandybridge_lvds.c
index 3b4b64c..906d148 100644
--- a/src/northbridge/intel/sandybridge/gma_sandybridge_lvds.c
+++ b/src/northbridge/intel/sandybridge/gma_sandybridge_lvds.c
@@ -30,37 +30,180 @@
 #include <device/pci_def.h>
 #include <device/pci_rom.h>
 
-static void train_link(u8 *mmio)
+static const int snb_b_fdi_train_param[] = {
+	FDI_LINK_TRAIN_400MV_0DB_SNB_B,
+	FDI_LINK_TRAIN_400MV_6DB_SNB_B,
+	FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
+	FDI_LINK_TRAIN_800MV_0DB_SNB_B,
+};
+
+static void fdi_normal_train(u8 *mmio, struct device *dev)
 {
-	/* Clear interrupts. */
-	write32(mmio + DEIIR, 0xffffffff);
-
-	write32(mmio + 0xf000c, 0x2040);
-	write32(mmio + 0xf000c, 0x2050);
-	write32(mmio + 0x60100, 0x44000);
-	write32(mmio + 0xf000c, 0x22050);
+	u32 temp;
+
+	/* enable normal train */
+	temp = read32(mmio + FDI_TX_CTL(0));
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_NONE;
+	temp |= FDI_TX_ENHANCE_FRAME_ENABLE;
+	write32(mmio + FDI_TX_CTL(0), temp);
+
+	temp = read32(mmio + FDI_RX_CTL(0));
+	if (HAS_PCH_CPT(dev)) {
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+	} else {
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_NONE;
+	}
+	temp |= FDI_DP_PORT_WIDTH_X4;
+	temp |= FDI_RX_ENHANCE_FRAME_ENABLE;
+	temp |= FDI_6BPC;
+	write32(mmio + FDI_RX_CTL(0), temp);
 
 	mdelay(1);
+}
 
-	write32(mmio + 0x000f0018, 0x0000008ff);
-	write32(mmio + 0x000f1018, 0x0000008ff);
-
-	write32(mmio + 0x000f000c, 0x001a2050);
-	write32(mmio + 0x00060100, 0x001c4000);
-
-	write32(mmio + 0x00060100, 0x801c4000);
-	write32(mmio + 0x000f000c, 0x801a2050);
+/* this function is similar to the GNU/Linux i915 kernel module:
+ * drivers/gpu/drm/i915/intel_display.c
+ */
+static void fdi_train_link(u8 *mmio, struct device *dev)
+{
+	u32 temp;
+	int retry, i;
 
-	write32(mmio + 0x00060100, 0x801c4000);
-	write32(mmio + 0x000f000c, 0x801a2050);
-	mdelay(1);
+	/* Clear interrupts. */
+	write32(mmio + DEIIR, 0xffffffff);
 
-	read32(mmio + 0x000f0014); // = 0x00000100
-	write32(mmio + 0x000f0014, 0x00000100);
-	write32(mmio + 0x00060100, 0x901c4000);
-	write32(mmio + 0x000f000c, 0x801a2150);
-	mdelay(1);
-	read32(mmio + 0x000f0014); // = 0x00000600
+	/* disable FDI RX and configure pipe */
+	temp = FDI_RX_PLL_ENABLE | FDI_RX_ENHANCE_FRAME_ENABLE;
+	write32(mmio + FDI_RX_CTL(0), temp);
+
+	temp |= FDI_PCDCLK;
+	write32(mmio + FDI_RX_CTL(0), temp);
+
+	temp = FDI_TX_ENHANCE_FRAME_ENABLE | FDI_TX_PLL_ENABLE;
+	write32(mmio + FDI_TX_CTL(0), temp);
+
+	temp = FDI_6BPC | FDI_PCDCLK | FDI_RX_PLL_ENABLE | FDI_RX_ENHANCE_FRAME_ENABLE;
+	write32(mmio + FDI_RX_CTL(0), temp);
+
+	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+		for train result */
+	temp = read32(mmio + FDI_RX_IMR(0));
+	temp &= ~FDI_RX_SYMBOL_LOCK;
+	temp &= ~FDI_RX_BIT_LOCK;
+	temp &= ~FDI_RX_INTER_LANE_ALIGN;
+	write32(mmio + FDI_RX_IMR(0), temp);
+
+	/* Setup CPU FDI TX and PCH FDI RX */
+	temp = read32(mmio + FDI_TX_CTL(0));
+	temp &= ~FDI_DP_PORT_WIDTH_MASK;
+	temp |= FDI_DP_PORT_WIDTH_X4;
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_1;
+	temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+	/* SNB-B */
+	temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+	write32(mmio + FDI_TX_CTL(0), temp);
+
+	temp = read32(mmio + FDI_RX_CTL(0));
+	temp &= ~FDI_DP_PORT_WIDTH_MASK;
+	temp |= FDI_DP_PORT_WIDTH_X4;
+	if (HAS_PCH_CPT(dev)) {
+		 temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		 temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+	} else {
+		 temp &= ~FDI_LINK_TRAIN_NONE;
+		 temp |= FDI_LINK_TRAIN_PATTERN_1;
+	}
+	write32(mmio + FDI_RX_CTL(0), temp);
+
+	/* Enable CPU FDI TX and PCH FDI RX */
+	temp = read32(mmio + FDI_TX_CTL(0));
+	temp |= FDI_TX_ENABLE;
+	write32(mmio + FDI_TX_CTL(0), temp);
+
+	temp = read32(mmio + FDI_RX_CTL(0));
+	temp |= FDI_RX_ENABLE;
+	write32(mmio + FDI_RX_CTL(0), temp);
+	udelay(150);
+
+	for (i = 0; i < 4; i++) {
+		printk(BIOS_INFO, "trying FDI param %d\n", i);
+
+		temp = read32(mmio + FDI_TX_CTL(0));
+		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+		temp |= snb_b_fdi_train_param[i];
+		write32(mmio + FDI_TX_CTL(0), temp);
+
+		read32(mmio + FDI_TX_CTL(0));
+		udelay(500);
+
+		for (retry = 0; retry < 5; retry++) {
+			temp = read32(mmio + FDI_RX_IIR(0));
+			printk(BIOS_INFO, "FDI_RX_IIR 0x%x\n", temp);
+				if (temp & FDI_RX_BIT_LOCK) {
+					write32(mmio + FDI_RX_IIR(0), temp | FDI_RX_BIT_LOCK);
+					printk(BIOS_INFO, "FDI train 1 done.\n");
+					break;
+				}
+				udelay(50);
+		}
+		if (retry < 5)
+			break;
+	}
+	if (i == 4)
+		printk(BIOS_CRIT, "FDI train 1 fail!\n");
+
+	/* Train 2 */
+	temp = read32(mmio + FDI_TX_CTL(0));
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_2;
+
+	temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+	/* SNB-B */
+	temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+	write32(mmio + FDI_TX_CTL(0), temp);
+
+	temp = read32(mmio + FDI_RX_CTL(0));
+	if (HAS_PCH_CPT(dev)) {
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
+	} else {
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_2;
+	}
+	write32(mmio + FDI_RX_CTL(0), temp);
+
+	read32(mmio + FDI_RX_CTL(0));
+	udelay(150);
+
+	for (i = 0; i < 4; i++) {
+		printk(BIOS_INFO, "trying FDI param %d\n", i);
+
+		temp = read32(mmio + FDI_TX_CTL(0));
+		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+		temp |= snb_b_fdi_train_param[i];
+		write32(mmio + FDI_TX_CTL(0), temp);
+		udelay(500);
+
+		for (retry = 0; retry < 5; retry++) {
+				temp = read32(mmio + FDI_RX_IIR(0));
+				printk(BIOS_INFO, "FDI_RX_IIR 0x%x\n", temp);
+				if (temp & FDI_RX_SYMBOL_LOCK) {
+					write32(mmio + FDI_RX_IIR(0), temp | FDI_RX_SYMBOL_LOCK);
+					printk(BIOS_INFO, "FDI train 2 done.\n");
+					break;
+				}
+				udelay(50);
+		}
+		if (retry < 5)
+			break;
+	}
+	if (i == 4)
+		printk(BIOS_CRIT, "FDI train 2 fail!\n");
+	printk(BIOS_DEBUG, "FDI train done.\n");
 }
 
 static void power_port(u8 *mmio)
@@ -139,6 +282,7 @@ int i915lightup_sandy(const struct i915_gpu_controller_info *info,
 	u32 data_n1 = 0x00800000;
 	u32 link_m1;
 	u32 link_n1 = 0x00080000;
+	struct device *pch_dev = dev_find_slot(0, PCI_DEVFN(0x1f, 0));
 
 	if (!IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT))
 		return 0;
@@ -259,7 +403,6 @@ int i915lightup_sandy(const struct i915_gpu_controller_info *info,
 			else
 				current_delta = cur_frequency - target_frequency;
 
-
 			if (best_delta > current_delta) {
 				best_delta = current_delta;
 				pixel_n = candn;
@@ -402,7 +545,7 @@ int i915lightup_sandy(const struct i915_gpu_controller_info *info,
 	else
 		write32(mmio + CPU_VGACNTRL, 0x20298e);
 
-	train_link(mmio);
+	fdi_train_link(mmio, pch_dev);
 
 	if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
 		write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
@@ -429,9 +572,7 @@ int i915lightup_sandy(const struct i915_gpu_controller_info *info,
 		(vactive + bottom_border + vfront_porch + vsync - 1)
 		| (vactive + bottom_border + vfront_porch - 1));
 
-	write32(mmio + 0x00060100, 0xb01c4000);
-	write32(mmio + 0x000f000c, 0x801a2350);
-	mdelay(1);
+	fdi_normal_train(mmio, pch_dev);
 
 	if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE))
 		write32(mmio + TRANSCONF(0), TRANS_ENABLE | TRANS_6BPC



More information about the coreboot-gerrit mailing list