static void intel_mst_pre_enable_dp(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); struct intel_digital_port *intel_dig_port = intel_mst->primary; struct intel_dp *intel_dp = &intel_dig_port->dp; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = intel_dig_port->port; struct intel_connector *connector = to_intel_connector(conn_state->connector); int ret; uint32_t temp; int slots; /* MST encoders are bound to a crtc, not to a connector, * force the mapping here for get_hw_state. */ connector->encoder = encoder; intel_mst->connector = connector; DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links); if (intel_dp->active_mst_links == 0) { intel_ddi_clk_select(&intel_dig_port->base, pipe_config); intel_prepare_dp_ddi_buffers(&intel_dig_port->base); intel_dp_set_link_params(intel_dp, pipe_config); intel_ddi_init_dp_buf_reg(&intel_dig_port->base); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); intel_dp_stop_link_train(intel_dp); } ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr, connector->port, pipe_config->pbn, &slots); if (ret == false) { DRM_ERROR("failed to allocate vcpi\n"); return; } intel_dp->active_mst_links++; temp = I915_READ(DP_TP_STATUS(port)); I915_WRITE(DP_TP_STATUS(port), temp); ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); }
static void intel_mst_enable_dp(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); struct intel_digital_port *intel_dig_port = intel_mst->primary; struct intel_dp *intel_dp = &intel_dig_port->dp; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = intel_dig_port->base.port; DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); if (intel_wait_for_register(&dev_priv->uncore, DP_TP_STATUS(port), DP_TP_STATUS_ACT_SENT, DP_TP_STATUS_ACT_SENT, 1)) DRM_ERROR("Timed out waiting for ACT sent\n"); drm_dp_check_act_status(&intel_dp->mst_mgr); drm_dp_update_payload_part2(&intel_dp->mst_mgr); if (pipe_config->has_audio) intel_audio_codec_enable(encoder, pipe_config, conn_state); }
static void intel_mst_pre_enable_dp(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); struct intel_digital_port *intel_dig_port = intel_mst->primary; struct intel_dp *intel_dp = &intel_dig_port->dp; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = intel_dig_port->base.port; struct intel_connector *connector = to_intel_connector(conn_state->connector); int ret; uint32_t temp; /* MST encoders are bound to a crtc, not to a connector, * force the mapping here for get_hw_state. */ connector->encoder = encoder; intel_mst->connector = connector; DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); if (intel_dp->active_mst_links == 0) intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true); if (intel_dp->active_mst_links == 0) intel_dig_port->base.pre_enable(&intel_dig_port->base, pipe_config, NULL); ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr, connector->port, pipe_config->pbn, pipe_config->dp_m_n.tu); if (ret == false) { DRM_ERROR("failed to allocate vcpi\n"); return; } intel_dp->active_mst_links++; temp = I915_READ(DP_TP_STATUS(port)); I915_WRITE(DP_TP_STATUS(port), temp); ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); }
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"); }
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); int pipe = intel_crtc->pipe; u32 reg, temp, i; /* Configure CPU PLL, wait for warmup */ I915_WRITE(SPLL_CTL, SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SCC); /* Use SPLL to drive the output when in FDI mode */ I915_WRITE(PORT_CLK_SEL(PORT_E), PORT_CLK_SEL_SPLL); I915_WRITE(PIPE_CLK_SEL(pipe), PIPE_CLK_SEL_PORT(PORT_E)); DELAY(20); /* Start the training iterating through available voltages and emphasis */ for (i=0; i < DRM_ARRAY_SIZE(hsw_ddi_buf_ctl_values); 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 */ temp = I915_READ(DDI_BUF_CTL(PORT_E)); temp = (temp & ~DDI_BUF_EMP_MASK); I915_WRITE(DDI_BUF_CTL(PORT_E), temp | DDI_BUF_CTL_ENABLE | DDI_PORT_WIDTH_X2 | hsw_ddi_buf_ctl_values[i]); DELAY(600); /* Enable CPU FDI Receiver with auto-training */ reg = FDI_RX_CTL(pipe); I915_WRITE(reg, I915_READ(reg) | FDI_LINK_TRAIN_AUTO | FDI_RX_ENABLE | FDI_LINK_TRAIN_PATTERN_1_CPT | FDI_RX_ENHANCE_FRAME_ENABLE | FDI_PORT_WIDTH_2X_LPT | FDI_RX_PLL_ENABLE); POSTING_READ(reg); DELAY(100); temp = I915_READ(DP_TP_STATUS(PORT_E)); if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) { DRM_DEBUG_DRIVER("BUF_CTL training done on %d step\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); /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in FDI mode */ temp = I915_READ(DDI_FUNC_CTL(pipe)); temp &= ~PIPE_DDI_PORT_MASK; temp |= PIPE_DDI_SELECT_PORT(PORT_E) | PIPE_DDI_MODE_SELECT_FDI | PIPE_DDI_FUNC_ENABLE | PIPE_DDI_PORT_WIDTH_X2; I915_WRITE(DDI_FUNC_CTL(pipe), temp); break; } else { DRM_ERROR("Error training BUF_CTL %d\n", i); /* Disable DP_TP_CTL and FDI_RX_CTL) and retry */ I915_WRITE(DP_TP_CTL(PORT_E), I915_READ(DP_TP_CTL(PORT_E)) & ~DP_TP_CTL_ENABLE); I915_WRITE(FDI_RX_CTL(pipe), I915_READ(FDI_RX_CTL(pipe)) & ~FDI_RX_PLL_ENABLE); continue; } } DRM_DEBUG_KMS("FDI train done.\n"); }