Patrick Rudolph (siro@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@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@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