/* * Starting with Haswell, DDI port buffers must be programmed with correct * values in advance. This function programs the correct values for * DP/eDP/FDI use cases.
*/ void hsw_prepare_dp_ddi_buffers(struct intel_encoder *encoder, conststruct intel_crtc_state *crtc_state)
{ struct intel_display *display = to_intel_display(encoder);
u32 iboost_bit = 0; int i, n_entries; enum port port = encoder->port; conststruct intel_ddi_buf_trans *trans;
trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(display->drm, !trans)) return;
/* If we're boosting the current, set bit 31 of trans1 */ if (has_iboost(display) &&
intel_bios_dp_boost_level(encoder->devdata))
iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE;
for (i = 0; i < n_entries; i++) {
intel_de_write(display, DDI_BUF_TRANS_LO(port, i),
trans->entries[i].hsw.trans1 | iboost_bit);
intel_de_write(display, DDI_BUF_TRANS_HI(port, i),
trans->entries[i].hsw.trans2);
}
}
/* * Starting with Haswell, DDI port buffers must be programmed with correct * values in advance. This function programs the correct values for * HDMI/DVI use cases.
*/ staticvoid hsw_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, conststruct intel_crtc_state *crtc_state)
{ struct intel_display *display = to_intel_display(encoder); int level = intel_ddi_level(encoder, crtc_state, 0);
u32 iboost_bit = 0; int n_entries; enum port port = encoder->port; conststruct intel_ddi_buf_trans *trans;
trans = encoder->get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(display->drm, !trans)) return;
/* If we're boosting the current, set bit 31 of trans1 */ if (has_iboost(display) &&
intel_bios_hdmi_boost_level(encoder->devdata))
iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE;
/* Entry 9 is for HDMI: */
intel_de_write(display, DDI_BUF_TRANS_LO(port, 9),
trans->entries[level].hsw.trans1 | iboost_bit);
intel_de_write(display, DDI_BUF_TRANS_HI(port, 9),
trans->entries[level].hsw.trans2);
}
static i915_reg_t intel_ddi_buf_status_reg(struct intel_display *display, enum port port)
{ if (DISPLAY_VER(display) >= 14) return XELPDP_PORT_BUF_CTL1(display, port); else return DDI_BUF_CTL(port);
}
void intel_wait_ddi_buf_idle(struct intel_display *display, enum port port)
{ /* * Bspec's platform specific timeouts: * MTL+ : 100 us * BXT : fixed 16 us * HSW-ADL: 8 us * * FIXME: MTL requires 10 ms based on tests, find out why 100 us is too short
*/ if (display->platform.broxton) {
udelay(16); return;
}
static_assert(DDI_BUF_IS_IDLE == XELPDP_PORT_BUF_PHY_IDLE); if (intel_de_wait_for_set(display, intel_ddi_buf_status_reg(display, port),
DDI_BUF_IS_IDLE, 10))
drm_err(display->drm, "Timeout waiting for DDI BUF %c to get idle\n",
port_name(port));
}
staticvoid intel_wait_ddi_buf_active(struct intel_encoder *encoder)
{ struct intel_display *display = to_intel_display(encoder); enum port port = encoder->port;
/* * Bspec's platform specific timeouts: * MTL+ : 10000 us * DG2 : 1200 us * TGL-ADL combo PHY: 1000 us * TGL-ADL TypeC PHY: 3000 us * HSW-ICL : fixed 518 us
*/ if (DISPLAY_VER(display) < 10) {
usleep_range(518, 1000); return;
}
static_assert(DDI_BUF_IS_IDLE == XELPDP_PORT_BUF_PHY_IDLE); if (intel_de_wait_for_clear(display, intel_ddi_buf_status_reg(display, port),
DDI_BUF_IS_IDLE, 10))
drm_err(display->drm, "Timeout waiting for DDI BUF %c to get active\n",
port_name(port));
}
static u32 hsw_pll_to_ddi_pll_sel(conststruct intel_dpll *pll)
{ switch (pll->info->id) { case DPLL_ID_WRPLL1: return PORT_CLK_SEL_WRPLL1; case DPLL_ID_WRPLL2: return PORT_CLK_SEL_WRPLL2; case DPLL_ID_SPLL: return PORT_CLK_SEL_SPLL; case DPLL_ID_LCPLL_810: return PORT_CLK_SEL_LCPLL_810; case DPLL_ID_LCPLL_1350: return PORT_CLK_SEL_LCPLL_1350; case DPLL_ID_LCPLL_2700: return PORT_CLK_SEL_LCPLL_2700; default:
MISSING_CASE(pll->info->id); return PORT_CLK_SEL_NONE;
}
}
switch (id) { default: /* * DPLL_ID_ICL_DPLL0 and DPLL_ID_ICL_DPLL1 should not be used * here, so do warn if this get passed in
*/
MISSING_CASE(id); return DDI_CLK_SEL_NONE; case DPLL_ID_ICL_TBTPLL: switch (clock) { case 162000: return DDI_CLK_SEL_TBT_162; case 270000: return DDI_CLK_SEL_TBT_270; case 540000: return DDI_CLK_SEL_TBT_540; case 810000: return DDI_CLK_SEL_TBT_810; default:
MISSING_CASE(clock); return DDI_CLK_SEL_NONE;
} case DPLL_ID_ICL_MGPLL1: case DPLL_ID_ICL_MGPLL2: case DPLL_ID_ICL_MGPLL3: case DPLL_ID_ICL_MGPLL4: case DPLL_ID_TGL_MGPLL5: case DPLL_ID_TGL_MGPLL6: return DDI_CLK_SEL_MG;
}
}
static u32 ddi_buf_phy_link_rate(int port_clock)
{ switch (port_clock) { case 162000: return DDI_BUF_PHY_LINK_RATE(0); case 216000: return DDI_BUF_PHY_LINK_RATE(4); case 243000: return DDI_BUF_PHY_LINK_RATE(5); case 270000: return DDI_BUF_PHY_LINK_RATE(1); case 324000: return DDI_BUF_PHY_LINK_RATE(6); case 432000: return DDI_BUF_PHY_LINK_RATE(7); case 540000: return DDI_BUF_PHY_LINK_RATE(2); case 810000: return DDI_BUF_PHY_LINK_RATE(3); default:
MISSING_CASE(port_clock); return DDI_BUF_PHY_LINK_RATE(0);
}
}
staticint dp_phy_lane_stagger_delay(int port_clock)
{ /* * Return the number of symbol clocks delay used to stagger the * assertion/desassertion of the port lane enables. The target delay * time is 100 ns or greater, return the number of symbols specific to * the provided port_clock (aka link clock) corresponding to this delay * time, i.e. so that * * number_of_symbols * duration_of_one_symbol >= 100 ns * * The delay must be applied only on TypeC DP outputs, for everything else * the delay must be set to 0. * * Return the number of link symbols per 100 ns: * port_clock (10 kHz) -> bits / 100 us * / symbol_size -> symbols / 100 us * / 1000 -> symbols / 100 ns
*/ return DIV_ROUND_UP(port_clock, intel_dp_link_symbol_size(port_clock) * 1000);
}
/* DDI_BUF_CTL_ENABLE will be set by intel_ddi_prepare_link_retrain() later */
intel_dp->DP = DDI_PORT_WIDTH(crtc_state->lane_count) |
DDI_BUF_TRANS_SELECT(0);
if (dig_port->lane_reversal)
intel_dp->DP |= DDI_BUF_PORT_REVERSAL; if (dig_port->ddi_a_4_lanes)
intel_dp->DP |= DDI_A_4_LANES;
if (DISPLAY_VER(display) >= 14) { if (intel_dp_is_uhbr(crtc_state))
intel_dp->DP |= DDI_BUF_PORT_DATA_40BIT; else
intel_dp->DP |= DDI_BUF_PORT_DATA_10BIT;
}
if (display->platform.alderlake_p && intel_encoder_is_tc(encoder)) {
intel_dp->DP |= ddi_buf_phy_link_rate(crtc_state->port_clock); if (!intel_tc_port_in_tbt_alt_mode(dig_port))
intel_dp->DP |= DDI_BUF_CTL_TC_PHY_OWNERSHIP;
}
if (IS_DISPLAY_VER(display, 11, 13) && intel_encoder_is_tc(encoder)) { int delay = dp_phy_lane_stagger_delay(crtc_state->port_clock);
staticint icl_calc_tbt_pll_link(struct intel_display *display, enum port port)
{
u32 val = intel_de_read(display, DDI_CLK_SEL(port)) & DDI_CLK_SEL_MASK;
switch (val) { case DDI_CLK_SEL_NONE: return 0; case DDI_CLK_SEL_TBT_162: return 162000; case DDI_CLK_SEL_TBT_270: return 270000; case DDI_CLK_SEL_TBT_540: return 540000; case DDI_CLK_SEL_TBT_810: return 810000; default:
MISSING_CASE(val); return 0;
}
}
staticvoid ddi_dotclock_get(struct intel_crtc_state *pipe_config)
{ /* CRT dotclock is determined via other means */ if (pipe_config->has_pch_encoder) return;
if (crtc_state->limited_color_range)
temp |= DP_MSA_MISC_COLOR_CEA_RGB;
/* * As per DP 1.2 spec section 2.3.4.3 while sending * YCBCR 444 signals we should program MSA MISC1/0 fields with * colorspace information.
*/ if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
temp |= DP_MSA_MISC_COLOR_YCBCR_444_BT709;
/* * As per DP 1.4a spec section 2.2.4.3 [MSA Field for Indication * of Color Encoding Format and Content Color Gamut] while sending * YCBCR 420, HDR BT.2020 signals we should program MSA MISC1 fields * which indicate VSC SDP for the Pixel Encoding/Colorimetry Format.
*/ if (intel_dp_needs_vsc_sdp(crtc_state, conn_state))
temp |= DP_MSA_MISC_COLOR_VSC_SDP;
/* * Returns the TRANS_DDI_FUNC_CTL value based on CRTC state. * * Only intended to be used by intel_ddi_enable_transcoder_func() and * intel_ddi_config_transcoder_func().
*/ static u32
intel_ddi_transcoder_func_reg_val_get(struct intel_encoder *encoder, conststruct intel_crtc_state *crtc_state)
{ struct intel_display *display = to_intel_display(crtc_state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum pipe pipe = crtc->pipe; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; enum port port = encoder->port;
u32 temp;
/* Enable TRANS_DDI_FUNC_CTL for the pipe to work in HDMI mode */
temp = TRANS_DDI_FUNC_ENABLE; if (DISPLAY_VER(display) >= 12)
temp |= TGL_TRANS_DDI_SELECT_PORT(port); else
temp |= TRANS_DDI_SELECT_PORT(port);
switch (crtc_state->pipe_bpp) { default:
MISSING_CASE(crtc_state->pipe_bpp);
fallthrough; case 18:
temp |= TRANS_DDI_BPC_6; break; case 24:
temp |= TRANS_DDI_BPC_8; break; case 30:
temp |= TRANS_DDI_BPC_10; break; case 36:
temp |= TRANS_DDI_BPC_12; break;
}
if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_PVSYNC)
temp |= TRANS_DDI_PVSYNC; if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_PHSYNC)
temp |= TRANS_DDI_PHSYNC;
if (cpu_transcoder == TRANSCODER_EDP) { switch (pipe) { default:
MISSING_CASE(pipe);
fallthrough; case PIPE_A: /* On Haswell, can only use the always-on power well for * eDP when not using the panel fitter, and when not * using motion blur mitigation (which we don't
* support). */ if (crtc_state->pch_pfit.force_thru)
temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; else
temp |= TRANS_DDI_EDP_INPUT_A_ON; break; case PIPE_B:
temp |= TRANS_DDI_EDP_INPUT_B_ONOFF; break; case PIPE_C:
temp |= TRANS_DDI_EDP_INPUT_C_ONOFF; break;
}
}
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { if (crtc_state->has_hdmi_sink)
temp |= TRANS_DDI_MODE_SELECT_HDMI; else
temp |= TRANS_DDI_MODE_SELECT_DVI;
/* * Same as intel_ddi_enable_transcoder_func(), but it does not set the enable * bit for the DDI function and enables the DP2 configuration. Called for all * transcoder types.
*/ void
intel_ddi_config_transcoder_func(struct intel_encoder *encoder, conststruct intel_crtc_state *crtc_state)
{ struct intel_display *display = to_intel_display(crtc_state); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u32 ctl;
/* * Disable the DDI function and port syncing. * For SST, pre-TGL MST, TGL+ MST-slave transcoders: deselect the DDI port, * SST/MST mode and disable the DP2 configuration. For TGL+ MST-master * transcoders these are done later in intel_ddi_post_disable_dp().
*/ void intel_ddi_disable_transcoder_func(conststruct intel_crtc_state *crtc_state)
{ struct intel_display *display = to_intel_display(crtc_state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u32 ctl;
if (DISPLAY_VER(display) >= 11)
intel_de_write(display,
TRANS_DDI_FUNC_CTL2(display, cpu_transcoder),
0);
if (ddi_mode == TRANS_DDI_MODE_SELECT_HDMI ||
ddi_mode == TRANS_DDI_MODE_SELECT_DVI) {
ret = type == DRM_MODE_CONNECTOR_HDMIA;
} elseif (ddi_mode == TRANS_DDI_MODE_SELECT_FDI_OR_128B132B && !HAS_DP20(display)) {
ret = type == DRM_MODE_CONNECTOR_VGA;
} elseif (ddi_mode == TRANS_DDI_MODE_SELECT_DP_SST) {
ret = type == DRM_MODE_CONNECTOR_eDP ||
type == DRM_MODE_CONNECTOR_DisplayPort;
} elseif (ddi_mode == TRANS_DDI_MODE_SELECT_FDI_OR_128B132B && HAS_DP20(display)) { /* * encoder->get_hw_state() should have bailed out on MST. This * must be SST and non-eDP.
*/
ret = type == DRM_MODE_CONNECTOR_DisplayPort;
} elseif (drm_WARN_ON(display->drm, ddi_mode == TRANS_DDI_MODE_SELECT_DP_MST)) { /* encoder->get_hw_state() should have bailed out on MST. */
ret = false;
} else {
ret = false;
}
if (!*pipe_mask)
drm_dbg_kms(display->drm, "No pipe for [ENCODER:%d:%s] found\n",
encoder->base.base.id, encoder->base.name);
if (!mst_pipe_mask && dp128b132b_pipe_mask) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
/* * If we don't have 8b/10b MST, but have more than one * transcoder in 128b/132b mode, we know it must be 128b/132b * MST. * * Otherwise, we fall back to checking the current MST * state. It's not accurate for hardware takeover at probe, but * we don't expect MST to have been enabled at that point, and * can assume it's SST.
*/ if (hweight8(dp128b132b_pipe_mask) > 1 ||
intel_dp_mst_active_streams(intel_dp))
mst_pipe_mask = dp128b132b_pipe_mask;
}
/* * ICL+ HW requires corresponding AUX IOs to be powered up for PSR with * DC states enabled at the same time, while for driver initiated AUX * transfers we need the same AUX IOs to be powered but with DC states * disabled. Accordingly use the AUX_IO_<port> power domain here which * leaves DC states enabled. * * Before MTL TypeC PHYs (in all TypeC modes and both DP/HDMI) also require * AUX IO to be enabled, but all these require DC_OFF to be enabled as * well, so we can acquire a wider AUX_<port> power domain reference * instead of a specific AUX_IO_<port> reference without powering up any * extra wells.
*/ if (intel_psr_needs_aux_io_power(&dig_port->base, crtc_state)) return intel_display_power_aux_io_domain(display, dig_port->aux_ch); elseif (DISPLAY_VER(display) < 14 &&
(intel_crtc_has_dp_encoder(crtc_state) ||
intel_encoder_is_tc(&dig_port->base))) return intel_aux_power_domain(dig_port); else return POWER_DOMAIN_INVALID;
}
/* * TODO: Add support for MST encoders. Atm, the following should never * happen since fake-MST encoders don't set their get_power_domains() * hook.
*/ if (drm_WARN_ON(display->drm,
intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))) return;
dig_port = enc_to_dig_port(encoder);
if (!intel_tc_port_in_tbt_alt_mode(dig_port)) {
drm_WARN_ON(display->drm, dig_port->ddi_io_wakeref);
dig_port->ddi_io_wakeref = intel_display_power_get(display,
dig_port->ddi_io_power_domain);
}
if (DISPLAY_VER(display) >= 13)
val = TGL_TRANS_CLK_SEL_PORT(phy); elseif (DISPLAY_VER(display) >= 12)
val = TGL_TRANS_CLK_SEL_PORT(encoder->port); else
val = TRANS_CLK_SEL_PORT(encoder->port);
/* * We assume that the full set of pre-emphasis values can be * used on all DDI platforms. Should that change we need to * rethink this code.
*/ static u8 intel_ddi_dp_preemph_max(struct intel_dp *intel_dp)
{ return DP_TRAIN_PRE_EMPH_LEVEL_3;
}
static u32 icl_combo_phy_loadgen_select(conststruct intel_crtc_state *crtc_state, int lane)
{ if (crtc_state->port_clock > 600000) return 0;
if (crtc_state->lane_count == 4) return lane >= 1 ? LOADGEN_SELECT : 0; else return lane == 1 || lane == 2 ? LOADGEN_SELECT : 0;
}
/* Program PORT_TX_DW4 */ /* We cannot write to GRP. It would overwrite individual loadgen. */ for (ln = 0; ln < 4; ln++) { int level = intel_ddi_level(encoder, crtc_state, ln);
/* * 1. If port type is eDP or DP, * set PORT_PCS_DW1 cmnkeeper_enable to 1b, * else clear to 0b.
*/
val = intel_de_read(display, ICL_PORT_PCS_DW1_LN(0, phy)); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
val &= ~COMMON_KEEPER_EN; else
val |= COMMON_KEEPER_EN;
intel_de_write(display, ICL_PORT_PCS_DW1_GRP(phy), val);
/* 2. Program loadgen select */ /* * Program PORT_TX_DW4 depending on Bit rate and used lanes * <= 6 GHz and 4 lanes (LN0=0, LN1=1, LN2=1, LN3=1) * <= 6 GHz and 1,2 lanes (LN0=0, LN1=1, LN2=1, LN3=0) * > 6 GHz (LN0=0, LN1=0, LN2=0, LN3=0)
*/ for (ln = 0; ln < 4; ln++) {
intel_de_rmw(display, ICL_PORT_TX_DW4_LN(ln, phy),
LOADGEN_SELECT,
icl_combo_phy_loadgen_select(crtc_state, ln));
}
/* 3. Set PORT_CL_DW5 SUS Clock Config to 11b */
intel_de_rmw(display, ICL_PORT_CL_DW5(phy),
0, SUS_CLOCK_CONFIG);
/* 4. Clear training enable to change swing values */
val = intel_de_read(display, ICL_PORT_TX_DW5_LN(0, phy));
val &= ~TX_TRAINING_EN;
intel_de_write(display, ICL_PORT_TX_DW5_GRP(phy), val);
/* 5. Program swing and de-emphasis */
icl_ddi_combo_vswing_program(encoder, crtc_state);
/* 6. Set training enable to trigger update */
val = intel_de_read(display, ICL_PORT_TX_DW5_LN(0, phy));
val |= TX_TRAINING_EN;
intel_de_write(display, ICL_PORT_TX_DW5_GRP(phy), val);
}
/* FIXME: Program CRI_LOADGEN_SEL after the spec is updated */
}
/* * Program MG_CLKHUB<LN, port being used> with value from frequency table * In case of Legacy mode on MG PHY, both TX1 and TX2 enabled so use the * values from table for which TX1 and TX2 enabled.
*/ for (ln = 0; ln < 2; ln++) {
intel_de_rmw(display, MG_CLKHUB(ln, tc_port),
CFG_LOW_RATE_LKREN_EN,
crtc_state->port_clock < 300000 ? CFG_LOW_RATE_LKREN_EN : 0);
}
/* Program the MG_TX_DCC<LN, port being used> based on the link frequency */ for (ln = 0; ln < 2; ln++) {
intel_de_rmw(display, MG_TX1_DCC(ln, tc_port),
CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK |
CFG_AMI_CK_DIV_OVERRIDE_EN,
crtc_state->port_clock > 500000 ?
CFG_AMI_CK_DIV_OVERRIDE_VAL(1) |
CFG_AMI_CK_DIV_OVERRIDE_EN : 0);
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { if (ln == 0) {
val = DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1(0);
val |= DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(2);
} else {
val = DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1(3);
val |= DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(3);
}
} else {
val = DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1(0);
val |= DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(0);
}
/* * If we fail this, something went very wrong: first 2 PLLs should be * used by first 2 phys and last 2 PLLs by last phys
*/ if (drm_WARN_ON(display->drm,
(pll->info->id < DPLL_ID_DG1_DPLL2 && phy >= PHY_C) ||
(pll->info->id >= DPLL_ID_DG1_DPLL2 && phy < PHY_C))) return;
val = intel_de_read(display, DG1_DPCLKA_CFGCR0(phy));
val &= DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
val >>= DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy);
id = val;
/* * _DG1_DPCLKA0_CFGCR0 maps between DPLL 0 and 1 with one bit for phy A * and B while _DG1_DPCLKA1_CFGCR0 maps between DPLL 2 and 3 with one * bit for phy C and D.
*/ if (phy >= PHY_C)
id += DPLL_ID_DG1_DPLL2;
/* * "For DDIC and DDID, program DDI_CLK_SEL to map the MG clock to the port. * MG does not exist, but the programming is required to ungate DDIC and DDID."
*/
intel_de_write(display, DDI_CLK_SEL(port), DDI_CLK_SEL_MG);
switch (tmp & DDI_CLK_SEL_MASK) { case DDI_CLK_SEL_TBT_162: case DDI_CLK_SEL_TBT_270: case DDI_CLK_SEL_TBT_540: case DDI_CLK_SEL_TBT_810:
id = DPLL_ID_ICL_TBTPLL; break; case DDI_CLK_SEL_MG:
id = icl_tc_port_to_pll_id(tc_port); break; default:
MISSING_CASE(tmp);
fallthrough; case DDI_CLK_SEL_NONE: return NULL;
}
switch (encoder->port) { case PORT_A:
id = DPLL_ID_SKL_DPLL0; break; case PORT_B:
id = DPLL_ID_SKL_DPLL1; break; case PORT_C:
id = DPLL_ID_SKL_DPLL2; break; default:
MISSING_CASE(encoder->port); return NULL;
}
staticbool skl_ddi_is_clock_enabled(struct intel_encoder *encoder)
{ struct intel_display *display = to_intel_display(encoder); enum port port = encoder->port;
/* * FIXME Not sure if the override affects both * the PLL selection and the CLK_OFF bit.
*/ return !(intel_de_read(display, DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_OFF(port));
}
/* * FIXME Not sure if the override affects both * the PLL selection and the CLK_OFF bit.
*/ if ((tmp & DPLL_CTRL2_DDI_SEL_OVERRIDE(port)) == 0) return NULL;
id = (tmp & DPLL_CTRL2_DDI_CLK_SEL_MASK(port)) >>
DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port);
switch (tmp & PORT_CLK_SEL_MASK) { case PORT_CLK_SEL_WRPLL1:
id = DPLL_ID_WRPLL1; break; case PORT_CLK_SEL_WRPLL2:
id = DPLL_ID_WRPLL2; break; case PORT_CLK_SEL_SPLL:
id = DPLL_ID_SPLL; break; case PORT_CLK_SEL_LCPLL_810:
id = DPLL_ID_LCPLL_810; break; case PORT_CLK_SEL_LCPLL_1350:
id = DPLL_ID_LCPLL_1350; break; case PORT_CLK_SEL_LCPLL_2700:
id = DPLL_ID_LCPLL_2700; break; default:
MISSING_CASE(tmp);
fallthrough; case PORT_CLK_SEL_NONE: return NULL;
}
/* * In case of DP MST, we sanitize the primary encoder only, not the * virtual ones.
*/ if (encoder->type == INTEL_OUTPUT_DP_MST) return;
if (!encoder->base.crtc && intel_encoder_is_dp(encoder)) {
u8 pipe_mask; bool is_mst;
intel_ddi_get_encoder_pipes(encoder, &pipe_mask, &is_mst); /* * In the unlikely case that BIOS enables DP in MST mode, just * warn since our MST HW readout is incomplete.
*/ if (drm_WARN_ON(display->drm, is_mst)) return;
}
if (encoder->type == INTEL_OUTPUT_DSI) { struct intel_encoder *other_encoder;
port_mask = intel_dsi_encoder_ports(encoder); /* * Sanity check that we haven't incorrectly registered another * encoder using any of the ports of this DSI encoder.
*/
for_each_intel_encoder(display->drm, other_encoder) { if (other_encoder == encoder) continue;
if (drm_WARN_ON(display->drm,
port_mask & BIT(other_encoder->port))) return;
} /* * For DSI we keep the ddi clocks gated * except during enable/disable sequence.
*/
ddi_clk_needed = false;
}
if (ddi_clk_needed || !encoder->is_clock_enabled ||
!encoder->is_clock_enabled(encoder)) return;
drm_dbg_kms(display->drm, "[ENCODER:%d:%s] is disabled/in DSI mode with an ungated DDI clock, gate it\n",
encoder->base.base.id, encoder->base.name);
if (intel_de_wait_for_set(display, dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_ACT_SENT, 1))
drm_err(display->drm, "Timed out waiting for ACT sent\n");
}
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_DOWNSPREAD_CTRL,
enable ? DP_MSA_TIMING_PAR_IGNORE_EN : 0) <= 0)
drm_dbg_kms(display->drm, "Failed to %s MSA_TIMING_PAR_IGNORE in the sink\n",
str_enable_disable(enable));
}
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION,
enable ? DP_FEC_READY : 0) <= 0)
drm_dbg_kms(display->drm, "Failed to set FEC_READY to %s in the sink\n",
str_enabled_disabled(enable));
if (enable &&
drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_STATUS,
DP_FEC_DECODE_EN_DETECTED | DP_FEC_DECODE_DIS_DETECTED) <= 0)
drm_dbg_kms(display->drm, "Failed to clear FEC detected flags\n");
}
staticint read_fec_detected_status(struct drm_dp_aux *aux)
{ int ret;
u8 status;
ret = drm_dp_dpcd_readb(aux, DP_FEC_STATUS, &status); if (ret < 0) return ret;
return status;
}
staticint wait_for_fec_detected(struct drm_dp_aux *aux, bool enabled)
{ struct intel_display *display = to_intel_display(aux->drm_dev); int mask = enabled ? DP_FEC_DECODE_EN_DETECTED : DP_FEC_DECODE_DIS_DETECTED; int status; int err;
err = readx_poll_timeout(read_fec_detected_status, aux, status,
status & mask || status < 0,
10000, 200000);
if (err || status < 0) {
drm_dbg_kms(display->drm, "Failed waiting for FEC %s to get detected: %d (status %d)\n",
str_enabled_disabled(enabled), err, status); return err ? err : status;
}
if (enabled)
ret = intel_de_wait_for_set(display, dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_FEC_ENABLE_LIVE, 1); else
ret = intel_de_wait_for_clear(display, dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_FEC_ENABLE_LIVE, 1);
if (ret) {
drm_err(display->drm, "Timeout waiting for FEC live state to get %s\n",
str_enabled_disabled(enabled)); return ret;
} /* * At least the Synoptics MST hub doesn't set the detected flag for * FEC decoding disabling so skip waiting for that.
*/ if (enabled) {
ret = wait_for_fec_detected(&intel_dp->aux, enabled); if (ret) return ret;
}
return 0;
}
staticvoid intel_ddi_enable_fec(struct intel_encoder *encoder, conststruct intel_crtc_state *crtc_state)
{ struct intel_display *display = to_intel_display(encoder); int i; int ret;
/* * We only configure what the register value will be here. Actual * enabling happens during link training farther down.
*/
intel_ddi_init_dp_buf_reg(encoder, crtc_state);
/* * 1. Enable Power Wells * * This was handled at the beginning of intel_atomic_commit_tail(), * before we called down into this function.
*/
intel_dp_configure_protocol_converter(intel_dp, crtc_state); if (!is_mst)
intel_dp_sink_enable_decompression(state,
to_intel_connector(conn_state->connector),
crtc_state);
/* * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit * in the FEC_CONFIGURATION register to 1 before initiating link * training
*/
intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true);
/* * 6. The rest of the below are substeps under the bspec's "Enable and * Train Display Port" step. Note that steps that are specific to * MST will be handled by intel_mst_pre_enable_dp() before/after it * calls into this function. Also intel_mst_pre_enable_dp() only calls * us when active_mst_links==0, so any steps designated for "single * stream or multi-stream master transcoder" can just be performed * unconditionally here. * * mtl_ddi_prepare_link_retrain() that is called by * intel_dp_start_link_train() will execute steps: 6.d, 6.f, 6.g, 6.h, * 6.i and 6.j * * 6.k Follow DisplayPort specification training sequence (see notes for * failure handling) * 6.m If DisplayPort multi-stream - Set DP_TP_CTL link training to Idle * Pattern, wait for 5 idle patterns (DP_TP_STATUS Min_Idles_Sent) * (timeout after 800 us)
*/
intel_dp_start_link_train(state, intel_dp, crtc_state);
/* 6.n Set DP_TP_CTL link training to Normal */ if (!is_trans_port_sync_mode(crtc_state))
intel_dp_stop_link_train(intel_dp, crtc_state);
/* 6.o Configure and enable FEC if needed */
intel_ddi_enable_fec(encoder, crtc_state);
/* 7.a 128b/132b SST. */ if (!is_mst && intel_dp_is_uhbr(crtc_state)) { /* VCPID 1, start slot 0 for 128b/132b, tu slots */
ret = drm_dp_dpcd_write_payload(&intel_dp->aux, 1, 0, crtc_state->dp_m_n.tu); if (ret < 0)
intel_dp_queue_modeset_retry_for_link(state, encoder, crtc_state);
}
if (!is_mst)
intel_dsc_dp_pps_write(encoder, crtc_state);
}
/* * We only configure what the register value will be here. Actual * enabling happens during link training farther down.
*/
intel_ddi_init_dp_buf_reg(encoder, crtc_state);
/* * 1. Enable Power Wells * * This was handled at the beginning of intel_atomic_commit_tail(), * before we called down into this function.
*/
/* 2. Enable Panel Power if PPS is required */
intel_pps_on(intel_dp);
/* * 3. For non-TBT Type-C ports, set FIA lane count * (DFLEXDPSP.DPX4TXLATC) * * This was done before tgl_ddi_pre_enable_dp by * hsw_crtc_enable()->intel_encoders_pre_pll_enable().
*/
/* * 4. Enable the port PLL. * * The PLL enabling itself was already done before this function by * hsw_crtc_enable()->intel_enable_dpll(). We need only * configure the PLL to port mapping here.
*/
intel_ddi_enable_clock(encoder, crtc_state);
/* 5. If IO power is controlled through PWR_WELL_CTL, Enable IO Power */ if (!intel_tc_port_in_tbt_alt_mode(dig_port)) {
drm_WARN_ON(display->drm, dig_port->ddi_io_wakeref);
dig_port->ddi_io_wakeref = intel_display_power_get(display,
dig_port->ddi_io_power_domain);
}
/* 6. Program DP_MODE */
icl_program_mg_dp_mode(dig_port, crtc_state);
/* * 7. The rest of the below are substeps under the bspec's "Enable and * Train Display Port" step. Note that steps that are specific to * MST will be handled by intel_mst_pre_enable_dp() before/after it * calls into this function. Also intel_mst_pre_enable_dp() only calls * us when active_mst_links==0, so any steps designated for "single * stream or multi-stream master transcoder" can just be performed * unconditionally here.
*/
/* * 7.a Configure Transcoder Clock Select to direct the Port clock to the * Transcoder.
*/
intel_ddi_enable_transcoder_clock(encoder, crtc_state);
/* * 7.c Configure & enable DP_TP_CTL with link training pattern 1 * selected * * This will be handled by the intel_dp_start_link_train() farther * down this function.
*/
/* 7.e Configure voltage swing and related IO settings */
encoder->set_signal_levels(encoder, crtc_state);
/* * 7.f Combo PHY: Configure PORT_CL_DW10 Static Power Down to power up * the used lanes of the DDI.
*/
intel_ddi_power_up_lanes(encoder, crtc_state);
/* * 7.g Program CoG/MSO configuration bits in DSS_CTL1 if selected.
*/
intel_ddi_mso_configure(crtc_state);
if (!is_mst)
intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_configure_protocol_converter(intel_dp, crtc_state); if (!is_mst)
intel_dp_sink_enable_decompression(state,
to_intel_connector(conn_state->connector),
crtc_state); /* * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit * in the FEC_CONFIGURATION register to 1 before initiating link * training
*/
intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true);
/* * 7.i Follow DisplayPort specification training sequence (see notes for * failure handling) * 7.j If DisplayPort multi-stream - Set DP_TP_CTL link training to Idle * Pattern, wait for 5 idle patterns (DP_TP_STATUS Min_Idles_Sent) * (timeout after 800 us)
*/
intel_dp_start_link_train(state, intel_dp, crtc_state);
/* 7.k Set DP_TP_CTL link training to Normal */ if (!is_trans_port_sync_mode(crtc_state))
intel_dp_stop_link_train(intel_dp, crtc_state);
/* 7.l Configure and enable FEC if needed */
intel_ddi_enable_fec(encoder, crtc_state);
if (!is_mst && intel_dp_is_uhbr(crtc_state)) { /* VCPID 1, start slot 0 for 128b/132b, tu slots */
ret = drm_dp_dpcd_write_payload(&intel_dp->aux, 1, 0, crtc_state->dp_m_n.tu); if (ret < 0)
intel_dp_queue_modeset_retry_for_link(state, encoder, crtc_state);
}
if (!is_mst)
intel_dsc_dp_pps_write(encoder, crtc_state);
}
/* * We only configure what the register value will be here. Actual * enabling happens during link training farther down.
*/
intel_ddi_init_dp_buf_reg(encoder, crtc_state);
intel_pps_on(intel_dp);
intel_ddi_enable_clock(encoder, crtc_state);
if (!intel_tc_port_in_tbt_alt_mode(dig_port)) {
drm_WARN_ON(display->drm, dig_port->ddi_io_wakeref);
dig_port->ddi_io_wakeref = intel_display_power_get(display,
dig_port->ddi_io_power_domain);
}
icl_program_mg_dp_mode(dig_port, crtc_state);
if (has_buf_trans_select(display))
hsw_prepare_dp_ddi_buffers(encoder, crtc_state);
encoder->set_signal_levels(encoder, crtc_state);
intel_ddi_power_up_lanes(encoder, crtc_state);
if (!is_mst)
intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_configure_protocol_converter(intel_dp, crtc_state); if (!is_mst)
intel_dp_sink_enable_decompression(state,
to_intel_connector(conn_state->connector),
crtc_state);
intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true);
intel_dp_start_link_train(state, intel_dp, crtc_state); if ((port != PORT_A || DISPLAY_VER(display) >= 9) &&
!is_trans_port_sync_mode(crtc_state))
intel_dp_stop_link_train(intel_dp, crtc_state);
intel_ddi_enable_fec(encoder, crtc_state);
if (!is_mst) {
intel_ddi_enable_transcoder_clock(encoder, crtc_state);
intel_dsc_dp_pps_write(encoder, crtc_state);
}
}
/* MST will call a setting of MSA after an allocating of Virtual Channel * from MST encoder pre_enable callback.
*/ if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))
intel_ddi_set_dp_msa(crtc_state, conn_state);
}
/* * Note: Also called from the ->pre_enable of the first active MST stream * encoder on its primary encoder. * * When called from DP MST code: * * - conn_state will be NULL * * - encoder will be the primary encoder (i.e. mst->primary) * * - the main connector associated with this port won't be active or linked to a * crtc * * - crtc_state will be the state of the first stream to be activated on this * port, and it may not be the same stream that will be deactivated last, but * each stream should have a state that is identical when it comes to the DP * link parameters.
*/ staticvoid intel_ddi_pre_enable(struct intel_atomic_state *state, struct intel_encoder *encoder, conststruct intel_crtc_state *crtc_state, conststruct drm_connector_state *conn_state)
{ struct intel_display *display = to_intel_display(state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum pipe pipe = crtc->pipe;
if (!is_mst)
intel_dp_set_infoframes(encoder, false,
old_crtc_state, old_conn_state);
/* * Power down sink before disabling the port, otherwise we end * up getting interrupts from the sink on detecting link loss.
*/
intel_dp_set_power(intel_dp, DP_SET_POWER_D3);
if (DISPLAY_VER(display) >= 12) { if (is_mst || intel_dp_is_uhbr(old_crtc_state)) { enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
/* * From TGL spec: "If single stream or multi-stream master transcoder: * Configure Transcoder Clock select to direct no clock to the * transcoder"
*/ if (DISPLAY_VER(display) >= 12)
intel_ddi_disable_transcoder_clock(old_crtc_state);
if (DISPLAY_VER(display) >= 9)
skl_scaler_disable(old_pipe_crtc_state); else
ilk_pfit_disable(old_pipe_crtc_state);
}
}
/* * Note: Also called from the ->post_disable of the last active MST stream * encoder on its primary encoder. See also the comment for * intel_ddi_pre_enable().
*/ staticvoid intel_ddi_post_disable(struct intel_atomic_state *state, struct intel_encoder *encoder, conststruct intel_crtc_state *old_crtc_state, conststruct drm_connector_state *old_conn_state)
{ if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST))
intel_ddi_post_disable_hdmi_or_sst(state, encoder, old_crtc_state,
old_conn_state);
/* * When called from DP MST code: * - old_conn_state will be NULL * - encoder will be the main encoder (ie. mst->primary) * - the main connector associated with this port * won't be active or linked to a crtc * - old_crtc_state will be the state of the last stream to * be deactivated on this port, and it may not be the same * stream that was activated last, but each stream * should have a state that is identical when it comes to * the DP link parameters
*/
/* * Note: Also called from the ->post_pll_disable of the last active MST stream * encoder on its primary encoder. See also the comment for * intel_ddi_pre_enable().
*/ staticvoid intel_ddi_post_pll_disable(struct intel_atomic_state *state, struct intel_encoder *encoder, conststruct intel_crtc_state *old_crtc_state, conststruct drm_connector_state *old_conn_state)
{ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
if (!intel_hdmi_handle_sink_scrambling(encoder, connector,
crtc_state->hdmi_high_tmds_clock_ratio,
crtc_state->hdmi_scrambling))
drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s] Failed to configure sink scrambling/TMDS bit clock ratio\n",
connector->base.id, connector->name);
if (has_buf_trans_select(display))
hsw_prepare_hdmi_ddi_buffers(encoder, crtc_state);
/* e. Enable D2D Link for C10/C20 Phy */
mtl_ddi_enable_d2d(encoder);
encoder->set_signal_levels(encoder, crtc_state);
/* Display WA #1143: skl,kbl,cfl */ if (DISPLAY_VER(display) == 9 && !display->platform.broxton) { /* * For some reason these chicken bits have been * stuffed into a transcoder register, event though * the bits affect a specific DDI port rather than * a specific transcoder.
*/
i915_reg_t reg = gen9_chicken_trans_reg_by_port(display, port);
u32 val;
val = intel_de_read(display, reg);
if (port == PORT_E)
val |= DDIE_TRAINING_OVERRIDE_ENABLE |
DDIE_TRAINING_OVERRIDE_VALUE; else
val |= DDI_TRAINING_OVERRIDE_ENABLE |
DDI_TRAINING_OVERRIDE_VALUE;
if (port == PORT_E)
val &= ~(DDIE_TRAINING_OVERRIDE_ENABLE |
DDIE_TRAINING_OVERRIDE_VALUE); else
val &= ~(DDI_TRAINING_OVERRIDE_ENABLE |
DDI_TRAINING_OVERRIDE_VALUE);
intel_de_write(display, reg, val);
}
intel_ddi_power_up_lanes(encoder, crtc_state);
/* In HDMI/DVI mode, the port width, and swing/emphasis values * are ignored so nothing special needs to be done besides * enabling the port. * * On ADL_P the PHY link rate and lane count must be programmed but * these are both 0 for HDMI. * * But MTL onwards HDMI2.1 is supported and in TMDS mode this * is filled with lane count, already set in the crtc_state. * The same is required to be filled in PORT_BUF_CTL for C10/20 Phy.
*/ if (dig_port->lane_reversal)
buf_ctl |= DDI_BUF_PORT_REVERSAL; if (dig_port->ddi_a_4_lanes)
buf_ctl |= DDI_A_4_LANES;
if (DISPLAY_VER(display) >= 14) {
u32 port_buf = 0;
/* * Note: Also called from the ->pre_pll_enable of the first active MST stream * encoder on its primary encoder. See also the comment for * intel_ddi_pre_enable().
*/ staticvoid
intel_ddi_pre_pll_enable(struct intel_atomic_state *state, struct intel_encoder *encoder, conststruct intel_crtc_state *crtc_state, conststruct drm_connector_state *conn_state)
{ struct intel_display *display = to_intel_display(encoder); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); bool is_tc_port = intel_encoder_is_tc(encoder);
if (is_tc_port) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
if (is_tc_port && !intel_tc_port_in_tbt_alt_mode(dig_port)) /* * Program the lane count for static/dynamic connections on * Type-C ports. Skip this step for TBT.
*/
intel_tc_port_set_fia_lane_count(dig_port, crtc_state->lane_count); elseif (display->platform.geminilake || display->platform.broxton)
bxt_dpio_phy_set_lane_optim_mask(encoder,
crtc_state->lane_lat_optim_mask);
}
/* * TODO: To train with only a different voltage swing entry is not * necessary disable and enable port
*/
dp_tp_ctl = intel_de_read(display, dp_tp_ctl_reg(encoder, crtc_state));
/* 6.i Configure and enable DDI_CTL_DE to start sending valid data to port slice */ if (DISPLAY_VER(display) >= 20)
intel_dp->DP |= XE2LPD_DDI_BUF_D2D_LINK_ENABLE;
/* * 6.k If AUX-Less ALPM is going to be enabled: * i. Configure PORT_ALPM_CTL and PORT_ALPM_LFPS_CTL here
*/
intel_alpm_port_configure(intel_dp, crtc_state);
/* * ii. Enable MAC Transmits LFPS in the "PHY Common Control 0" PIPE * register
*/
intel_lnl_mac_transmit_lfps(encoder, crtc_state);
}
/* * Until TGL on PORT_A we can have only eDP in SST mode. There the only * reason we need to set idle transmission mode is to work around a HW * issue where we enable the pipe while not in idle link-training mode. * In this case there is requirement to wait for a minimum number of * idle patterns to be sent.
*/ if (port == PORT_A && DISPLAY_VER(display) < 12) return;
if (intel_de_wait_for_set(display,
dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_IDLE_DONE, 2))
drm_err(display->drm, "Timed out waiting for DP idle patterns\n");
}
/* * If this is true, we know we're being called from mst stream * encoder's ->get_config().
*/ if (intel_dp_mst_active_streams(intel_dp))
intel_ddi_read_func_ctl_dp_mst(encoder, pipe_config, ddi_func_ctl); else
intel_ddi_read_func_ctl_dp_sst(encoder, pipe_config, ddi_func_ctl);
}
}
/* * Note: Also called from the ->get_config of the MST stream encoders on their * primary encoder, via the platform specific hooks here. See also the comment * for intel_ddi_pre_enable().
*/ staticvoid intel_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config)
{ struct intel_display *display = to_intel_display(encoder); enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
/* XXX: DSI transcoder paranoia */ if (drm_WARN_ON(display->drm, transcoder_is_dsi(cpu_transcoder))) return;
/* * We don't enable port sync on BDW due to missing w/as and * due to not having adjusted the modeset sequence appropriately.
*/ if (DISPLAY_VER(display) < 9) return 0;
if (!intel_crtc_has_type(ref_crtc_state, INTEL_OUTPUT_DP)) return 0;
if (connector->has_tile)
port_sync_transcoders = intel_ddi_port_sync_transcoders(crtc_state,
connector->tile_group->id);
/* * EDP Transcoders cannot be ensalved * make them a master always when present
*/ if (port_sync_transcoders & BIT(TRANSCODER_EDP))
crtc_state->master_transcoder = TRANSCODER_EDP; else
crtc_state->master_transcoder = ffs(port_sync_transcoders) - 1;
intel_dp_encoder_flush_work(encoder); if (intel_encoder_is_tc(&dig_port->base))
intel_tc_port_cleanup(dig_port);
intel_display_power_flush_work(display);
/* * HDMI 2.0 says that one should not send scrambled data * prior to configuring the sink scrambling, and that * TMDS clock/data transmission should be suspended when * changing the TMDS clock rate in the sink. So let's * just do a full modeset here, even though some sinks * would be perfectly happy if were to just reconfigure * the SCDC settings on the fly.
*/ return intel_modeset_commit_pipes(display, BIT(crtc->pipe), ctx);
}
if (intel_dp_test_phy(intel_dp)) return INTEL_HOTPLUG_UNCHANGED;
state = intel_encoder_hotplug(encoder, connector);
if (!intel_tc_port_link_reset(dig_port)) { if (connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIA) {
intel_modeset_lock_ctx_retry(&ctx, NULL, 0, ret)
ret = intel_hdmi_reset_link(encoder, &ctx);
drm_WARN_ON(encoder->base.dev, ret);
} else {
intel_dp_check_link_state(intel_dp);
}
}
/* * Unpowered type-c dongles can take some time to boot and be * responsible, so here giving some time to those dongles to power up * and then retrying the probe. * * On many platforms the HDMI live state signal is known to be * unreliable, so we can't use it to detect if a sink is connected or * not. Instead we detect if it's connected based on whether we can * read the EDID or not. That in turn has a problem during disconnect, * since the HPD interrupt may be raised before the DDC lines get * disconnected (due to how the required length of DDC vs. HPD * connector pins are specified) and so we'll still be able to get a * valid EDID. To solve this schedule another detection cycle if this * time around we didn't detect any change in the sink's connection * status. * * Type-c connectors which get their HPD signal deasserted then * reasserted, without unplugging/replugging the sink from the * connector, introduce a delay until the AUX channel communication * becomes functional. Retry the detection for 5 seconds on type-c * connectors to account for this delay.
*/ if (state == INTEL_HOTPLUG_UNCHANGED &&
connector->hotplug_retries < (is_tc ? 5 : 1) &&
!dig_port->dp.is_mst)
state = INTEL_HOTPLUG_RETRY;
staticint intel_ddi_init_hdmi_connector(struct intel_digital_port *dig_port)
{ struct intel_connector *connector; enum port port = dig_port->base.port;
connector = intel_connector_alloc(); if (!connector) return -ENOMEM;
dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port);
if (!intel_hdmi_init_connector(dig_port, connector)) { /* * HDMI connector init failures may just mean conflicting DDC * pins or not having enough lanes. Handle them gracefully, but * don't fail the entire DDI init.
*/
dig_port->hdmi.hdmi_reg = INVALID_MMIO_REG;
kfree(connector);
}
/* Broxton/Geminilake: Bspec says that DDI_A_4_LANES is the only * supported configuration
*/ if (display->platform.geminilake || display->platform.broxton) returntrue;
returnfalse;
}
staticint
intel_ddi_max_lanes(struct intel_digital_port *dig_port)
{ struct intel_display *display = to_intel_display(dig_port); enum port port = dig_port->base.port; int max_lanes = 4;
if (DISPLAY_VER(display) >= 11) return max_lanes;
if (port == PORT_A || port == PORT_E) { if (intel_de_read(display, DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES)
max_lanes = port == PORT_A ? 4 : 0; else /* Both A and E share 2 lanes */
max_lanes = 2;
}
/* * Some BIOS might fail to set this bit on port A if eDP * wasn't lit up at boot. Force this bit set when needed * so we use the proper lane count for our calculations.
*/ if (intel_ddi_a_force_4_lanes(dig_port)) {
drm_dbg_kms(display->drm, "Forcing DDI_A_4_LANES for port A\n");
dig_port->ddi_a_4_lanes = true;
max_lanes = 4;
}
return max_lanes;
}
staticenum hpd_pin xelpd_hpd_pin(struct intel_display *display, enum port port)
{ if (port >= PORT_D_XELPD) return HPD_PORT_D + port - PORT_D_XELPD; elseif (port >= PORT_TC1) return HPD_PORT_TC1 + port - PORT_TC1; else return HPD_PORT_A + port - PORT_A;
}
staticenum hpd_pin dg1_hpd_pin(struct intel_display *display, enum port port)
{ if (port >= PORT_TC1) return HPD_PORT_C + port - PORT_TC1; else return HPD_PORT_A + port - PORT_A;
}
staticenum hpd_pin tgl_hpd_pin(struct intel_display *display, enum port port)
{ if (port >= PORT_TC1) return HPD_PORT_TC1 + port - PORT_TC1; else return HPD_PORT_A + port - PORT_A;
}
staticenum hpd_pin rkl_hpd_pin(struct intel_display *display, enum port port)
{ if (HAS_PCH_TGP(display)) return tgl_hpd_pin(display, port);
if (port >= PORT_TC1) return HPD_PORT_C + port - PORT_TC1; else return HPD_PORT_A + port - PORT_A;
}
staticenum hpd_pin icl_hpd_pin(struct intel_display *display, enum port port)
{ if (port >= PORT_C) return HPD_PORT_TC1 + port - PORT_C; else return HPD_PORT_A + port - PORT_A;
}
staticenum hpd_pin ehl_hpd_pin(struct intel_display *display, enum port port)
{ if (port == PORT_D) return HPD_PORT_A;
if (HAS_PCH_TGP(display)) return icl_hpd_pin(display, port);
return HPD_PORT_A + port - PORT_A;
}
staticenum hpd_pin skl_hpd_pin(struct intel_display *display, enum port port)
{ if (HAS_PCH_TGP(display)) return icl_hpd_pin(display, port);
return HPD_PORT_A + port - PORT_A;
}
staticbool intel_ddi_is_tc(struct intel_display *display, enum port port)
{ if (DISPLAY_VER(display) >= 12) return port >= PORT_TC1; elseif (DISPLAY_VER(display) >= 11) return port >= PORT_C; else returnfalse;
}
/* * TODO: Move this to intel_dp_encoder_suspend(), * once modeset locking around that is removed.
*/
intel_encoder_link_check_flush_work(encoder);
intel_tc_port_suspend(dig_port);
}
staticvoid intel_ddi_encoder_shutdown(struct intel_encoder *encoder)
{ if (intel_encoder_is_dp(encoder))
intel_dp_encoder_shutdown(encoder); if (intel_encoder_is_hdmi(encoder))
intel_hdmi_encoder_shutdown(encoder);
}
staticbool port_strap_detected(struct intel_display *display, enum port port)
{ /* straps not used on skl+ */ if (DISPLAY_VER(display) >= 9) returntrue;
switch (port) { case PORT_A: return intel_de_read(display, DDI_BUF_CTL(PORT_A)) & DDI_INIT_DISPLAY_DETECTED; case PORT_B: return intel_de_read(display, SFUSE_STRAP) & SFUSE_STRAP_DDIB_DETECTED; case PORT_C: return intel_de_read(display, SFUSE_STRAP) & SFUSE_STRAP_DDIC_DETECTED; case PORT_D: return intel_de_read(display, SFUSE_STRAP) & SFUSE_STRAP_DDID_DETECTED; case PORT_E: returntrue; /* no strap for DDI-E */ default:
MISSING_CASE(port); returnfalse;
}
}
if (intel_bios_encoder_supports_dsi(devdata)) { /* BXT/GLK handled elsewhere, for now at least */ if (!assert_has_icl_dsi(display)) return;
icl_dsi_init(display, devdata); return;
}
phy = intel_port_to_phy(display, port);
/* * On platforms with HTI (aka HDPORT), if it's enabled at boot it may * have taken over some of the PHYs and made them unavailable to the * driver. In that case we should skip initializing the corresponding * outputs.
*/ if (intel_hti_uses_phy(display, phy)) {
drm_dbg_kms(display->drm, "PORT %c / PHY %c reserved by HTI\n",
port_name(port), phy_name(phy)); return;
}
if (intel_bios_encoder_is_lspcon(devdata)) { /* * Lspcon device needs to be driven with DP connector * with special detection sequence. So make sure DP * is initialized before lspcon.
*/
init_dp = true;
init_hdmi = false;
drm_dbg_kms(display->drm, "VBT says port %c has lspcon\n",
port_name(port));
}
if (!init_dp && !init_hdmi) {
drm_dbg_kms(display->drm, "VBT says port %c is not DVI/HDMI/DP compatible, respect it\n",
port_name(port)); return;
}
if (intel_phy_is_snps(display, phy) &&
display->snps.phy_failed_calibration & BIT(phy)) {
drm_dbg_kms(display->drm, "SNPS PHY %c failed to calibrate, proceeding anyway\n",
phy_name(phy));
}
dig_port = kzalloc(sizeof(*dig_port), GFP_KERNEL); if (!dig_port) return;
if (init_dp) { if (intel_ddi_init_dp_connector(dig_port)) goto err;
dig_port->hpd_pulse = intel_dp_hpd_pulse;
if (dig_port->dp.mso_link_count)
encoder->pipe_mask = intel_ddi_splitter_pipe_mask(display);
}
/* * In theory we don't need the encoder->type check, * but leave it just in case we have some really bad VBTs...
*/ if (encoder->type != INTEL_OUTPUT_EDP && init_hdmi) { if (intel_ddi_init_hdmi_connector(dig_port)) goto err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.