/* * 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);
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.