void FDIReceiver::EnablePLL(uint32 lanes) { CALLED(); uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; uint32 value = read32(targetRegister); if ((value & FDI_RX_PLL_ENABLED) != 0) { // already enabled, possibly IronLake where it always is TRACE("%s: Already enabled.\n", __func__); return; } value &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16)); value |= FDI_DP_PORT_WIDTH(lanes); //value |= (read32(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; write32(targetRegister, value | FDI_RX_PLL_ENABLED); read32(targetRegister); spin(200); // warmup 10us + dmi delay 20us, be generous }
status_t FDILink::_SnbTrain(uint32 lanes) { CALLED(); uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; // Train 1 uint32 imrControl = Receiver().Base() + PCH_FDI_RX_IMR; uint32 tmp = read32(imrControl); tmp &= ~FDI_RX_SYMBOL_LOCK; tmp &= ~FDI_RX_BIT_LOCK; write32(imrControl, tmp); read32(imrControl); spin(150); tmp = read32(txControl); tmp &= ~FDI_DP_PORT_WIDTH_MASK; tmp |= FDI_DP_PORT_WIDTH(lanes); tmp &= ~FDI_LINK_TRAIN_NONE; tmp |= FDI_LINK_TRAIN_PATTERN_1; tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; tmp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; write32(txControl, tmp); write32(Receiver().Base() + PCH_FDI_RX_MISC, FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); tmp = read32(rxControl); if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; tmp |= FDI_LINK_TRAIN_PATTERN_1_CPT; } else { tmp &= ~FDI_LINK_TRAIN_NONE; tmp |= FDI_LINK_TRAIN_PATTERN_1; } write32(rxControl, rxControl); Receiver().Enable(); uint32 iirControl = Receiver().Base() + PCH_FDI_RX_IIR; TRACE("%s: FDI RX IIR Control @ 0x%" B_PRIx32 "\n", __func__, iirControl); int i = 0; for (i = 0; i < 4; i++) { tmp = read32(txControl); tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; tmp |= gSnbBFDITrainParam[i]; write32(txControl, tmp); read32(txControl); spin(500); int retry = 0; for (retry = 0; retry < 5; retry++) { tmp = read32(iirControl); TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); if (tmp & FDI_RX_BIT_LOCK) { TRACE("%s: FDI train 1 done\n", __func__); write32(iirControl, tmp | FDI_RX_BIT_LOCK); break; } spin(50); } if (retry < 5) break; } if (i == 4) { ERROR("%s: FDI train 1 failure!\n", __func__); return B_ERROR; } // Train 2 tmp = read32(txControl); tmp &= ~FDI_LINK_TRAIN_NONE; tmp |= FDI_LINK_TRAIN_PATTERN_2; // if gen6? It's always gen6 tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; tmp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; write32(txControl, tmp); tmp = read32(rxControl); if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; tmp |= FDI_LINK_TRAIN_PATTERN_2_CPT; } else { tmp &= ~FDI_LINK_TRAIN_NONE; tmp |= FDI_LINK_TRAIN_PATTERN_2; } write32(rxControl, tmp); read32(rxControl); spin(150); for (i = 0; i < 4; i++) { tmp = read32(txControl); tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; tmp |= gSnbBFDITrainParam[i]; write32(txControl, tmp); read32(txControl); spin(500); int retry = 0; for (retry = 0; retry < 5; retry++) { tmp = read32(iirControl); TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); if (tmp & FDI_RX_SYMBOL_LOCK) { TRACE("%s: FDI train 2 done\n", __func__); write32(iirControl, tmp | FDI_RX_SYMBOL_LOCK); break; } spin(50); } if (retry < 5) break; } if (i == 4) { ERROR("%s: FDI train 1 failure!\n", __func__); return B_ERROR; } return B_OK; }
status_t FDILink::_IlkTrain(uint32 lanes) { CALLED(); uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; // Train 1: unmask FDI RX Interrupt symbol_lock and bit_lock uint32 tmp = read32(Receiver().Base() + PCH_FDI_RX_IMR); tmp &= ~FDI_RX_SYMBOL_LOCK; tmp &= ~FDI_RX_BIT_LOCK; write32(Receiver().Base() + PCH_FDI_RX_IMR, tmp); spin(150); // Enable CPU FDI TX and RX tmp = read32(txControl); tmp &= ~FDI_DP_PORT_WIDTH_MASK; tmp |= FDI_DP_PORT_WIDTH(lanes); tmp &= ~FDI_LINK_TRAIN_NONE; tmp |= FDI_LINK_TRAIN_PATTERN_1; write32(txControl, tmp); Transmitter().Enable(); tmp = read32(rxControl); tmp &= ~FDI_LINK_TRAIN_NONE; tmp |= FDI_LINK_TRAIN_PATTERN_1; write32(rxControl, tmp); Receiver().Enable(); // ILK Workaround, enable clk after FDI enable if (fPipeIndex == INTEL_PIPE_B) { write32(PCH_FDI_RXB_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR); write32(PCH_FDI_RXB_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR | FDI_RX_PHASE_SYNC_POINTER_EN); } else { write32(PCH_FDI_RXA_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR); write32(PCH_FDI_RXA_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR | FDI_RX_PHASE_SYNC_POINTER_EN); } uint32 iirControl = Receiver().Base() + PCH_FDI_RX_IIR; TRACE("%s: FDI RX IIR Control @ 0x%" B_PRIx32 "\n", __func__, iirControl); int tries = 0; for (tries = 0; tries < 5; tries++) { tmp = read32(iirControl); TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); if ((tmp & FDI_RX_BIT_LOCK)) { TRACE("%s: FDI train 1 done\n", __func__); write32(iirControl, tmp | FDI_RX_BIT_LOCK); break; } } if (tries == 5) { ERROR("%s: FDI train 1 failure!\n", __func__); return B_ERROR; } // Train 2 tmp = read32(txControl); tmp &= ~FDI_LINK_TRAIN_NONE; tmp |= FDI_LINK_TRAIN_PATTERN_2; write32(txControl, tmp); tmp = read32(rxControl); tmp &= ~FDI_LINK_TRAIN_NONE; tmp |= FDI_LINK_TRAIN_PATTERN_2; write32(rxControl, tmp); read32(rxControl); spin(150); for (tries = 0; tries < 5; tries++) { tmp = read32(iirControl); TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); if (tmp & FDI_RX_SYMBOL_LOCK) { TRACE("%s: FDI train 2 done\n", __func__); write32(iirControl, tmp | FDI_RX_SYMBOL_LOCK); break; } } if (tries == 5) { ERROR("%s: FDI train 2 failure!\n", __func__); return B_ERROR; } return B_OK; }
void hsw_fdi_link_train(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 temp, i, rx_ctl_val; /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the * mode set "sequence for CRT port" document: * - TP1 to TP2 time with the default value * - FDI delay to 90h * * WaFDIAutoLinkSetTimingOverrride:hsw */ I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2) | FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); /* Enable the PCH Receiver FDI PLL */ rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | FDI_RX_PLL_ENABLE | FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); POSTING_READ(_FDI_RXA_CTL); udelay(220); /* Switch from Rawclk to PCDclk */ rx_ctl_val |= FDI_PCDCLK; I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); /* Configure Port Clock Select */ I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->ddi_pll_sel); /* Start the training iterating through available voltages and emphasis, * testing each value twice. */ for (i = 0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values) * 2; i++) { /* Configure DP_TP_CTL with auto-training */ I915_WRITE(DP_TP_CTL(PORT_E), DP_TP_CTL_FDI_AUTOTRAIN | DP_TP_CTL_ENHANCED_FRAME_ENABLE | DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_ENABLE); /* Configure and enable DDI_BUF_CTL for DDI E with next voltage. * DDI E does not support port reversal, the functionality is * achieved on the PCH side in FDI_RX_CTL, so no need to set the * port reversal bit */ I915_WRITE(DDI_BUF_CTL(PORT_E), DDI_BUF_CTL_ENABLE | ((intel_crtc->config.fdi_lanes - 1) << 1) | hsw_ddi_buf_ctl_values[i / 2]); POSTING_READ(DDI_BUF_CTL(PORT_E)); udelay(600); /* Program PCH FDI Receiver TU */ I915_WRITE(_FDI_RXA_TUSIZE1, TU_SIZE(64)); /* Enable PCH FDI Receiver with auto-training */ rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO; I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); POSTING_READ(_FDI_RXA_CTL); /* Wait for FDI receiver lane calibration */ udelay(30); /* Unset FDI_RX_MISC pwrdn lanes */ temp = I915_READ(_FDI_RXA_MISC); temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); I915_WRITE(_FDI_RXA_MISC, temp); POSTING_READ(_FDI_RXA_MISC); /* Wait for FDI auto training time */ udelay(5); temp = I915_READ(DP_TP_STATUS(PORT_E)); if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) { DRM_DEBUG_KMS("FDI link training done on step %d\n", i); /* Enable normal pixel sending for FDI */ I915_WRITE(DP_TP_CTL(PORT_E), DP_TP_CTL_FDI_AUTOTRAIN | DP_TP_CTL_LINK_TRAIN_NORMAL | DP_TP_CTL_ENHANCED_FRAME_ENABLE | DP_TP_CTL_ENABLE); return; } temp = I915_READ(DDI_BUF_CTL(PORT_E)); temp &= ~DDI_BUF_CTL_ENABLE; I915_WRITE(DDI_BUF_CTL(PORT_E), temp); POSTING_READ(DDI_BUF_CTL(PORT_E)); /* Disable DP_TP_CTL and FDI_RX_CTL and retry */ temp = I915_READ(DP_TP_CTL(PORT_E)); temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); temp |= DP_TP_CTL_LINK_TRAIN_PAT1; I915_WRITE(DP_TP_CTL(PORT_E), temp); POSTING_READ(DP_TP_CTL(PORT_E)); intel_wait_ddi_buf_idle(dev_priv, PORT_E); rx_ctl_val &= ~FDI_RX_ENABLE; I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); POSTING_READ(_FDI_RXA_CTL); /* Reset FDI_RX_MISC pwrdn lanes */ temp = I915_READ(_FDI_RXA_MISC); temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); I915_WRITE(_FDI_RXA_MISC, temp); POSTING_READ(_FDI_RXA_MISC); } DRM_ERROR("FDI link training failed!\n"); }