/* * The following helper functions, despite being named for bigjoiner, * are applicable to both bigjoiner and uncompressed joiner configurations.
*/ staticbool is_bigjoiner(conststruct intel_crtc_state *crtc_state)
{ return hweight8(crtc_state->joiner_pipes) >= 2;
}
static u8 bigjoiner_primary_pipes(conststruct intel_crtc_state *crtc_state)
{ if (!is_bigjoiner(crtc_state)) return 0;
/* * The ultrajoiner enable bit doesn't seem to follow primary/secondary logic or * any other logic, so lets just add helper function to * at least hide this hassle..
*/ static u8 ultrajoiner_enable_pipes(conststruct intel_crtc_state *crtc_state)
{ if (!intel_crtc_is_ultrajoiner(crtc_state)) return 0;
if (DISPLAY_VER(display) >= 4) { enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
/* Wait for the Pipe State to go off */ if (intel_de_wait_for_clear(display, TRANSCONF(display, cpu_transcoder),
TRANSCONF_STATE_ENABLE, 100))
drm_WARN(display->drm, 1, "pipe_off wait timed out\n");
} else {
intel_wait_for_pipe_scanline_stopped(crtc);
}
}
/* * A pipe without a PLL won't actually be able to drive bits from * a plane. On ILK+ the pipe PLLs are integrated, so we don't * need the check.
*/ if (HAS_GMCH(display)) { if (intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI))
assert_dsi_pll_enabled(display); else
assert_pll_enabled(display, pipe);
} else { if (new_crtc_state->has_pch_encoder) { /* if driving the PCH, we need FDI enabled */
assert_fdi_rx_pll_enabled(display,
intel_crtc_pch_transcoder(crtc));
assert_fdi_tx_pll_enabled(display,
(enum pipe) cpu_transcoder);
} /* FIXME: assert CPU port conditions for SNB+ */
}
val = intel_de_read(display, TRANSCONF(display, cpu_transcoder)); if (val & TRANSCONF_ENABLE) { /* we keep both pipes enabled on 830 */
drm_WARN_ON(display->drm, !display->platform.i830); return;
}
/* Wa_1409098942:adlp+ */ if (DISPLAY_VER(display) >= 13 &&
new_crtc_state->dsc.compression_enable) {
val &= ~TRANSCONF_PIXEL_COUNT_SCALING_MASK;
val |= REG_FIELD_PREP(TRANSCONF_PIXEL_COUNT_SCALING_MASK,
TRANSCONF_PIXEL_COUNT_SCALING_X4);
}
intel_de_write(display, TRANSCONF(display, cpu_transcoder),
val | TRANSCONF_ENABLE);
intel_de_posting_read(display, TRANSCONF(display, cpu_transcoder));
/* * Until the pipe starts PIPEDSL reads will return a stale value, * which causes an apparent vblank timestamp jump when PIPEDSL * resets to its proper value. That also messes up the frame count * when it's derived from the timestamps. So let's wait for the * pipe to start properly before we call drm_crtc_vblank_on()
*/ if (intel_crtc_max_vblank_count(new_crtc_state) == 0)
intel_wait_for_pipe_scanline_moving(crtc);
}
/* * Make sure planes won't keep trying to pump pixels to us, * or we might hang the display.
*/
assert_planes_disabled(crtc);
val = intel_de_read(display, TRANSCONF(display, cpu_transcoder)); if ((val & TRANSCONF_ENABLE) == 0) return;
/* * Double wide has implications for planes * so best keep it disabled when not needed.
*/ if (old_crtc_state->double_wide)
val &= ~TRANSCONF_DOUBLE_WIDE;
/* Don't disable pipe or pipe PLLs if needed */ if (!display->platform.i830)
val &= ~TRANSCONF_ENABLE;
/* Wa_1409098942:adlp+ */ if (DISPLAY_VER(display) >= 13 &&
old_crtc_state->dsc.compression_enable)
val &= ~TRANSCONF_PIXEL_COUNT_SCALING_MASK;
/* * We assume the primary plane for pipe A has * the highest stride limits of them all, * if in case pipe A is disabled, use the first pipe from pipe_mask.
*/
crtc = intel_first_crtc(display); if (!crtc) return 0;
/* * Active_planes aliases if multiple "primary" or cursor planes * have been used on the same (or wrong) pipe. plane_mask uses * unique ids, hence we can use that to reconstruct active_planes.
*/
crtc_state->enabled_planes = 0;
crtc_state->active_planes = 0;
/* * Vblank time updates from the shadow to live plane control register * are blocked if the memory self-refresh mode is active at that * moment. So to make sure the plane gets truly disabled, disable * first the self-refresh mode. The self-refresh enable bit in turn * will be checked/applied by the HW only at the next frame start * event which is after the vblank start event, so we need to have a * wait-for-vblank between disabling the plane and the pipe.
*/ if (HAS_GMCH(display) &&
intel_set_memory_cxsr(display, false))
intel_plane_initial_vblank_wait(crtc);
/* * Gen2 reports pipe underruns whenever all planes are disabled. * So disable underrun reporting before all the planes get disabled.
*/ if (DISPLAY_VER(display) == 2 && !crtc_state->active_planes)
intel_set_cpu_fifo_underrun_reporting(display, crtc->pipe, false);
/* * Display WA #1153: icl * enable hardware to bypass the alpha math * and rounding for per-pixel values 00 and 0xff
*/
tmp |= PER_PIXEL_ALPHA_BYPASS_EN; /* * Display WA # 1605353570: icl * Set the pixel rounding bit to 1 for allowing * passthrough of Frame buffer pixels unmodified * across pipe
*/
tmp |= PIXEL_ROUNDING_TRUNC_FB_PASSTHRU;
/* * Underrun recovery must always be disabled on display 13+. * DG2 chicken bit meaning is inverted compared to other platforms.
*/ if (display->platform.dg2)
tmp &= ~UNDERRUN_RECOVERY_ENABLE_DG2; elseif ((DISPLAY_VER(display) >= 13) && (DISPLAY_VER(display) < 30))
tmp |= UNDERRUN_RECOVERY_DISABLE_ADLP;
/* Wa_14010547955:dg2 */ if (display->platform.dg2)
tmp |= DG2_RENDER_CCSTAG_4_3_EN;
/* * Finds the encoder associated with the given CRTC. This can only be * used when we know that the CRTC isn't feeding multiple encoders!
*/ struct intel_encoder *
intel_get_crtc_new_encoder(conststruct intel_atomic_state *state, conststruct intel_crtc_state *crtc_state)
{ conststruct drm_connector_state *connector_state; conststruct drm_connector *connector; struct intel_encoder *encoder = NULL; struct intel_crtc *primary_crtc; int num_encoders = 0; int i;
primary_crtc = intel_primary_crtc(crtc_state);
for_each_new_connector_in_state(&state->base, connector, connector_state, i) { if (connector_state->crtc != &primary_crtc->base) continue;
for_each_old_intel_plane_in_state(state, plane, old_plane_state, i) { if (plane->need_async_flip_toggle_wa &&
plane->pipe == crtc->pipe &&
disable_async_flip_planes & BIT(plane->id)) { /* * Apart from the async flip bit we want to * preserve the old state for the plane.
*/
intel_plane_async_flip(NULL, plane,
old_crtc_state, old_plane_state, false);
need_vbl_wait = true;
}
}
if (need_vbl_wait)
intel_crtc_wait_for_next_vblank(crtc);
}
if (intel_crtc_vrr_disabling(state, crtc)) {
intel_vrr_disable(old_crtc_state);
intel_crtc_update_active_timings(old_crtc_state, false);
}
if (audio_disabling(old_crtc_state, new_crtc_state))
intel_encoders_audio_disable(state, crtc);
intel_drrs_deactivate(old_crtc_state);
if (hsw_ips_pre_update(state, crtc))
intel_crtc_wait_for_next_vblank(crtc);
if (intel_fbc_pre_update(state, crtc))
intel_crtc_wait_for_next_vblank(crtc);
if (!needs_async_flip_vtd_wa(old_crtc_state) &&
needs_async_flip_vtd_wa(new_crtc_state))
intel_async_flip_vtd_wa(display, pipe, true);
/* Display WA 827 */ if (!needs_nv12_wa(old_crtc_state) &&
needs_nv12_wa(new_crtc_state))
skl_wa_827(display, pipe, true);
/* Wa_2006604312:icl,ehl */ if (!needs_scalerclk_wa(old_crtc_state) &&
needs_scalerclk_wa(new_crtc_state))
icl_wa_scalerclkgating(display, pipe, true);
/* Wa_1604331009:icl,jsl,ehl */ if (!needs_cursorclk_wa(old_crtc_state) &&
needs_cursorclk_wa(new_crtc_state))
icl_wa_cursorclkgating(display, pipe, true);
/* * Vblank time updates from the shadow to live plane control register * are blocked if the memory self-refresh mode is active at that * moment. So to make sure the plane gets truly disabled, disable * first the self-refresh mode. The self-refresh enable bit in turn * will be checked/applied by the HW only at the next frame start * event which is after the vblank start event, so we need to have a * wait-for-vblank between disabling the plane and the pipe.
*/ if (HAS_GMCH(display) && old_crtc_state->hw.active &&
new_crtc_state->disable_cxsr && intel_set_memory_cxsr(display, false))
intel_crtc_wait_for_next_vblank(crtc);
/* * IVB workaround: must disable low power watermarks for at least * one frame before enabling scaling. LP watermarks can be re-enabled * when scaling is disabled. * * WaCxSRDisabledForSpriteScaling:ivb
*/ if (!HAS_GMCH(display) && old_crtc_state->hw.active &&
new_crtc_state->disable_cxsr && ilk_disable_cxsr(display))
intel_crtc_wait_for_next_vblank(crtc);
/* * If we're doing a modeset we don't need to do any * pre-vblank watermark programming here.
*/ if (!intel_crtc_needs_modeset(new_crtc_state)) { /* * For platforms that support atomic watermarks, program the * 'intermediate' watermarks immediately. On pre-gen9 platforms, these * will be the intermediate values that are safe for both pre- and * post- vblank; when vblank happens, the 'active' values will be set * to the final 'target' values and we'll do this again to get the * optimal watermarks. For gen9+ platforms, the values we program here * will be the final target values which will get automatically latched * at vblank time; no further programming will be necessary. * * If a platform hasn't been transitioned to atomic watermarks yet, * we'll continue to update watermarks the old way, if flags tell * us to.
*/ if (!intel_initial_watermarks(state, crtc)) if (new_crtc_state->update_wm_pre)
intel_update_watermarks(display);
}
/* * Gen2 reports pipe underruns whenever all planes are disabled. * So disable underrun reporting before all the planes get disabled. * * We do this after .initial_watermarks() so that we have a * chance of catching underruns with the intermediate watermarks * vs. the old plane configuration.
*/ if (DISPLAY_VER(display) == 2 && planes_disabling(old_crtc_state, new_crtc_state))
intel_set_cpu_fifo_underrun_reporting(display, pipe, false);
/* * WA for platforms where async address update enable bit * is double buffered and only latched at start of vblank.
*/ if (old_crtc_state->async_flip_planes & ~new_crtc_state->async_flip_planes)
intel_crtc_async_flip_disable_wa(state, crtc);
}
/* * Make sure the DPLL state is up-to-date for fastset TypeC ports after non-blocking commits. * TODO: Update the DPLL state for all cases in the encoder->update_prepare() hook.
*/ if (display->dpll.mgr) {
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { if (intel_crtc_needs_modeset(new_crtc_state)) continue;
if (drm_WARN_ON(display->drm, crtc->active)) return;
/* * Sometimes spurious CPU pipe underruns happen during FDI * training, at least with VGA+HDMI cloning. Suppress them. * * On ILK we get an occasional spurious CPU pipe underruns * between eDP port A enable and vdd enable. Also PCH port * enable seems to result in the occasional CPU pipe underrun. * * Spurious PCH underruns also occur during PCH enabling.
*/
intel_set_cpu_fifo_underrun_reporting(display, pipe, false);
intel_set_pch_fifo_underrun_reporting(display, pipe, false);
if (new_crtc_state->has_pch_encoder)
ilk_pch_enable(state, crtc);
intel_crtc_vblank_on(new_crtc_state);
intel_encoders_enable(state, crtc);
if (HAS_PCH_CPT(display))
intel_wait_for_pipe_scanline_moving(crtc);
/* * Must wait for vblank to avoid spurious PCH FIFO underruns. * And a second vblank wait is needed at least on ILK with * some interlaced HDMI modes. Let's do the double wait always * in case there are more corner cases we don't know about.
*/ if (new_crtc_state->has_pch_encoder) {
intel_crtc_wait_for_next_vblank(crtc);
intel_crtc_wait_for_next_vblank(crtc);
}
intel_set_cpu_fifo_underrun_reporting(display, pipe, true);
intel_set_pch_fifo_underrun_reporting(display, pipe, true);
}
if (glk_need_scaler_clock_gating_wa(pipe_crtc_state)) {
intel_crtc_wait_for_next_vblank(pipe_crtc);
glk_pipe_scaler_clock_gating_wa(pipe_crtc, false);
}
/* * If we change the relative order between pipe/planes * enabling, we need to change the workaround.
*/
hsw_workaround_pipe = pipe_crtc_state->hsw_workaround_pipe; if (display->platform.haswell && hsw_workaround_pipe != INVALID_PIPE) { struct intel_crtc *wa_crtc =
intel_crtc_for_pipe(display, hsw_workaround_pipe);
/* * Sometimes spurious CPU pipe underruns happen when the * pipe is already disabled, but FDI RX/TX is still enabled. * Happens at least with VGA+HDMI cloning. Suppress them.
*/
intel_set_cpu_fifo_underrun_reporting(display, pipe, false);
intel_set_pch_fifo_underrun_reporting(display, pipe, false);
intel_encoders_disable(state, crtc);
intel_crtc_vblank_off(old_crtc_state);
intel_disable_transcoder(old_crtc_state);
ilk_pfit_disable(old_crtc_state);
if (old_crtc_state->has_pch_encoder)
ilk_pch_disable(state, crtc);
intel_encoders_post_disable(state, crtc);
if (old_crtc_state->has_pch_encoder)
ilk_pch_post_disable(state, crtc);
/* * FIXME collapse everything to one hook. * Need care with mst->ddi interactions.
*/
intel_encoders_disable(state, crtc);
intel_encoders_post_disable(state, crtc);
/* Prefer intel_encoder_is_combo() */ bool intel_phy_is_combo(struct intel_display *display, enum phy phy)
{ if (phy == PHY_NONE) returnfalse; elseif (display->platform.alderlake_s) return phy <= PHY_E; elseif (display->platform.dg1 || display->platform.rocketlake) return phy <= PHY_D; elseif (display->platform.jasperlake || display->platform.elkhartlake) return phy <= PHY_C; elseif (display->platform.alderlake_p || IS_DISPLAY_VER(display, 11, 12)) return phy <= PHY_B; else /* * DG2 outputs labelled as "combo PHY" in the bspec use * SNPS PHYs with completely different programming, * hence we always return false here.
*/ returnfalse;
}
/* Prefer intel_encoder_is_tc() */ bool intel_phy_is_tc(struct intel_display *display, enum phy phy)
{ /* * Discrete GPU phy's are not attached to FIA's to support TC * subsystem Legacy or non-legacy, and only support native DP/HDMI
*/ if (display->platform.dgfx) returnfalse;
/* Prefer intel_encoder_is_snps() */ bool intel_phy_is_snps(struct intel_display *display, enum phy phy)
{ /* * For DG2, and for DG2 only, all four "combo" ports and the TC1 port * (PHY E) use Synopsis PHYs. See intel_phy_is_tc().
*/ return display->platform.dg2 && phy > PHY_NONE && phy <= PHY_E;
}
/* Prefer intel_encoder_to_phy() */ enum phy intel_port_to_phy(struct intel_display *display, enum port port)
{ if (DISPLAY_VER(display) >= 13 && port >= PORT_D_XELPD) return PHY_D + port - PORT_D_XELPD; elseif (DISPLAY_VER(display) >= 13 && port >= PORT_TC1) return PHY_F + port - PORT_TC1; elseif (display->platform.alderlake_s && port >= PORT_TC1) return PHY_B + port - PORT_TC1; elseif ((display->platform.dg1 || display->platform.rocketlake) && port >= PORT_TC1) return PHY_C + port - PORT_TC1; elseif ((display->platform.jasperlake || display->platform.elkhartlake) &&
port == PORT_D) return PHY_A;
return PHY_A + port - PORT_A;
}
/* Prefer intel_encoder_to_tc() */ enum tc_port intel_port_to_tc(struct intel_display *display, enum port port)
{ if (!intel_phy_is_tc(display, intel_port_to_phy(display, port))) return TC_PORT_NONE;
if (DISPLAY_VER(display) >= 12) return TC_PORT_1 + port - PORT_TC1; else return TC_PORT_1 + port - PORT_C;
}
/* * On gen2 planes are double buffered but the pipe isn't, so we must * wait for planes to fully turn off before disabling the pipe.
*/ if (DISPLAY_VER(display) == 2)
intel_crtc_wait_for_next_vblank(crtc);
intel_encoders_disable(state, crtc);
intel_crtc_vblank_off(old_crtc_state);
intel_disable_transcoder(old_crtc_state);
i9xx_pfit_disable(old_crtc_state);
intel_encoders_post_disable(state, crtc);
if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DSI)) { if (display->platform.cherryview)
chv_disable_pll(display, pipe); elseif (display->platform.valleyview)
vlv_disable_pll(display, pipe); else
i9xx_disable_pll(old_crtc_state);
}
intel_encoders_post_pll_disable(state, crtc);
if (DISPLAY_VER(display) != 2)
intel_set_cpu_fifo_underrun_reporting(display, pipe, false);
if (!display->funcs.wm->initial_watermarks)
intel_update_watermarks(display);
/* clock the pipe down to 640x480@60 to potentially save power */ if (display->platform.i830)
i830_enable_pipe(display, pipe);
}
/* * Start with the adjusted_mode crtc timings, which * have been filled with the transcoder timings.
*/
drm_mode_copy(pipe_mode, adjusted_mode);
/* Expand MSO per-segment transcoder timings to full */
intel_splitter_adjust_timings(crtc_state, pipe_mode);
/* * We want the full numbers in adjusted_mode normal timings, * adjusted_mode crtc timings are left with the raw transcoder * timings.
*/
intel_mode_from_crtc_timings(adjusted_mode, pipe_mode);
/* Populate the "user" mode with full numbers */
drm_mode_copy(mode, pipe_mode);
intel_mode_from_crtc_timings(mode, mode);
mode->hdisplay = drm_rect_width(&crtc_state->pipe_src) *
intel_crtc_num_joined_pipes(crtc_state);
mode->vdisplay = drm_rect_height(&crtc_state->pipe_src);
/* Derive per-pipe timings in case joiner is used */
intel_joiner_adjust_timings(crtc_state, pipe_mode);
intel_mode_from_crtc_timings(pipe_mode, pipe_mode);
/* * Start with the adjusted_mode crtc timings, which * have been filled with the transcoder timings.
*/
drm_mode_copy(pipe_mode, adjusted_mode);
/* Expand MSO per-segment transcoder timings to full */
intel_splitter_adjust_timings(crtc_state, pipe_mode);
/* Derive per-pipe timings in case joiner is used */
intel_joiner_adjust_timings(crtc_state, pipe_mode);
intel_mode_from_crtc_timings(pipe_mode, pipe_mode);
void
intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes, int pixel_clock, int link_clock, int bw_overhead, struct intel_link_m_n *m_n)
{
u32 link_symbol_clock = intel_dp_link_symbol_clock(link_clock);
u32 data_m = intel_dp_effective_data_rate(pixel_clock, bits_per_pixel_x16,
bw_overhead);
u32 data_n = drm_dp_max_dprx_data_rate(link_clock, nlanes);
/* * Windows/BIOS uses fixed M/N values always. Follow suit. * * Also several DP dongles in particular seem to be fussy * about too large link M/N values. Presumably the 20bit * value used by Windows/BIOS is acceptable to everyone.
*/
m_n->tu = 64;
compute_m_n(&m_n->data_m, &m_n->data_n,
data_m, data_n,
0x8000000);
void intel_panel_sanitize_ssc(struct intel_display *display)
{ /* * There may be no VBT; and if the BIOS enabled SSC we can * just keep using it to avoid unnecessary flicker. Whereas if the * BIOS isn't using it, don't assume it will work even if the VBT * indicates as much.
*/ if (HAS_PCH_IBX(display) || HAS_PCH_CPT(display)) { bool bios_lvds_use_ssc = intel_de_read(display,
PCH_DREF_CONTROL) &
DREF_SSC1_ENABLE;
if (display->vbt.lvds_use_ssc != bios_lvds_use_ssc) {
drm_dbg_kms(display->drm, "SSC %s by BIOS, overriding VBT which says %s\n",
str_enabled_disabled(bios_lvds_use_ssc),
str_enabled_disabled(display->vbt.lvds_use_ssc));
display->vbt.lvds_use_ssc = bios_lvds_use_ssc;
}
}
}
void intel_zero_m_n(struct intel_link_m_n *m_n)
{ /* corresponds to 0 register value */
memset(m_n, 0, sizeof(*m_n));
m_n->tu = 1;
}
void intel_set_m_n(struct intel_display *display, conststruct intel_link_m_n *m_n,
i915_reg_t data_m_reg, i915_reg_t data_n_reg,
i915_reg_t link_m_reg, i915_reg_t link_n_reg)
{
intel_de_write(display, data_m_reg, TU_SIZE(m_n->tu) | m_n->data_m);
intel_de_write(display, data_n_reg, m_n->data_n);
intel_de_write(display, link_m_reg, m_n->link_m); /* * On BDW+ writing LINK_N arms the double buffered update * of all the M/N registers, so it must be written last.
*/
intel_de_write(display, link_n_reg, m_n->link_n);
}
/* We need to be careful not to changed the adjusted mode, for otherwise
* the hw state checker will get angry at the mismatch. */
crtc_vdisplay = adjusted_mode->crtc_vdisplay;
crtc_vtotal = adjusted_mode->crtc_vtotal;
crtc_vblank_start = adjusted_mode->crtc_vblank_start;
crtc_vblank_end = adjusted_mode->crtc_vblank_end;
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { /* the chip adds 2 halflines automatically */
crtc_vtotal -= 1;
crtc_vblank_end -= 1;
/* * VBLANK_START no longer works on ADL+, instead we must use * TRANS_SET_CONTEXT_LATENCY to configure the pipe vblank start.
*/ if (DISPLAY_VER(display) >= 13) {
intel_de_write(display,
TRANS_SET_CONTEXT_LATENCY(display, cpu_transcoder),
crtc_vblank_start - crtc_vdisplay);
/* * VBLANK_START not used by hw, just clear it * to make it stand out in register dumps.
*/
crtc_vblank_start = 1;
}
if (DISPLAY_VER(display) >= 4)
intel_de_write(display,
TRANS_VSYNCSHIFT(display, cpu_transcoder),
vsyncshift);
/* * For platforms that always use VRR Timing Generator, the VTOTAL.Vtotal * bits are not required. Since the support for these bits is going to * be deprecated in upcoming platforms, avoid writing these bits for the * platforms that do not use legacy Timing Generator.
*/ if (intel_vrr_always_use_vrr_tg(display))
crtc_vtotal = 1;
/* Workaround: when the EDP input selection is B, the VTOTAL_B must be * programmed with the VTOTAL_EDP value. Same for VTOTAL_C. This is * documented on the DDI_FUNC_CTL register description, EDP Input Select
* bits. */ if (display->platform.haswell && cpu_transcoder == TRANSCODER_EDP &&
(pipe == PIPE_B || pipe == PIPE_C))
intel_de_write(display, TRANS_VTOTAL(display, pipe),
VACTIVE(crtc_vdisplay - 1) |
VTOTAL(crtc_vtotal - 1));
if (DISPLAY_VER(display) >= 30) { /* * Address issues for resolutions with high refresh rate that * have small Hblank, specifically where Hblank is smaller than * one MTP. Simulations indicate this will address the * jitter issues that currently causes BS to be immediately * followed by BE which DPRX devices are unable to handle. * https://groups.vesa.org/wg/DP/document/20494
*/
intel_de_write(display, DP_MIN_HBLANK_CTL(cpu_transcoder),
crtc_state->min_hblank);
}
}
/* * VBLANK_START not used by hw, just clear it * to make it stand out in register dumps.
*/
crtc_vblank_start = 1;
}
/* * The hardware actually ignores TRANS_VBLANK.VBLANK_END in DP mode. * But let's write it anyway to keep the state checker happy.
*/
intel_de_write(display, TRANS_VBLANK(display, cpu_transcoder),
VBLANK_START(crtc_vblank_start - 1) |
VBLANK_END(crtc_vblank_end - 1)); /* * For platforms that always use VRR Timing Generator, the VTOTAL.Vtotal * bits are not required. Since the support for these bits is going to * be deprecated in upcoming platforms, avoid writing these bits for the * platforms that do not use legacy Timing Generator.
*/ if (intel_vrr_always_use_vrr_tg(display))
crtc_vtotal = 1;
/* * The double buffer latch point for TRANS_VTOTAL * is the transcoder's undelayed vblank.
*/
intel_de_write(display, TRANS_VTOTAL(display, cpu_transcoder),
VACTIVE(crtc_vdisplay - 1) |
VTOTAL(crtc_vtotal - 1));
/* pipesrc controls the size that is scaled from, which should * always be the user's requested size.
*/
intel_de_write(display, PIPESRC(display, pipe),
PIPESRC_WIDTH(width - 1) | PIPESRC_HEIGHT(height - 1));
}
/* * - We keep both pipes enabled on 830 * - During modeset the pipe is still disabled and must remain so * - During fastset the pipe is already enabled and must remain so
*/ if (display->platform.i830 || !intel_crtc_needs_modeset(crtc_state))
val |= TRANSCONF_ENABLE;
if (crtc_state->double_wide)
val |= TRANSCONF_DOUBLE_WIDE;
/* only g4x and later have fancy bpc/dither controls */ if (display->platform.g4x || display->platform.valleyview ||
display->platform.cherryview) { /* Bspec claims that we can't use dithering for 30bpp pipes. */ if (crtc_state->dither && crtc_state->pipe_bpp != 30)
val |= TRANSCONF_DITHER_EN |
TRANSCONF_DITHER_TYPE_SP;
switch (crtc_state->pipe_bpp) { default: /* Case prevented by intel_choose_pipe_bpp_dither. */
MISSING_CASE(crtc_state->pipe_bpp);
fallthrough; case 18:
val |= TRANSCONF_BPC_6; break; case 24:
val |= TRANSCONF_BPC_8; break; case 30:
val |= TRANSCONF_BPC_10; break;
}
}
if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) { if (DISPLAY_VER(display) < 4 ||
intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO))
val |= TRANSCONF_INTERLACE_W_FIELD_INDICATION; else
val |= TRANSCONF_INTERLACE_W_SYNC_SHIFT;
} else {
val |= TRANSCONF_INTERLACE_PROGRESSIVE;
}
if ((display->platform.valleyview || display->platform.cherryview) &&
crtc_state->limited_color_range)
val |= TRANSCONF_COLOR_RANGE_SELECT;
val |= TRANSCONF_GAMMA_MODE(crtc_state->gamma_mode);
if (crtc_state->wgc_enable)
val |= TRANSCONF_WGC_ENABLE;
val |= TRANSCONF_FRAME_START_DELAY(crtc_state->framestart_delay - 1);
if (tmp & PIPE_MISC_YUV420_ENABLE) { /* * We support 4:2:0 in full blend mode only. * For xe3_lpd+ this is implied in YUV420 Enable bit. * Ensure the same for prior platforms in YUV420 Mode bit.
*/ if (DISPLAY_VER(display) < 30)
drm_WARN_ON(display->drm,
(tmp & PIPE_MISC_YUV420_MODE_FULL_BLEND) == 0);
if (DISPLAY_VER(display) >= 4) {
tmp = pipe_config->dpll_hw_state.i9xx.dpll_md;
pipe_config->pixel_multiplier =
((tmp & DPLL_MD_UDI_MULTIPLIER_MASK)
>> DPLL_MD_UDI_MULTIPLIER_SHIFT) + 1;
} elseif (display->platform.i945g || display->platform.i945gm ||
display->platform.g33 || display->platform.pineview) {
tmp = pipe_config->dpll_hw_state.i9xx.dpll;
pipe_config->pixel_multiplier =
((tmp & SDVO_MULTIPLIER_MASK)
>> SDVO_MULTIPLIER_SHIFT_HIRES) + 1;
} else { /* Note that on i915G/GM the pixel multiplier is in the sdvo * port and will be fixed up in the encoder->get_config
* function. */
pipe_config->pixel_multiplier = 1;
}
if (display->platform.cherryview)
chv_crtc_clock_get(pipe_config); elseif (display->platform.valleyview)
vlv_crtc_clock_get(pipe_config); else
i9xx_crtc_clock_get(pipe_config);
/* * Normally the dotclock is filled in by the encoder .get_config() * but in case the pipe is enabled w/o any ports we need a sane * default.
*/
pipe_config->hw.adjusted_mode.crtc_clock =
pipe_config->port_clock / pipe_config->pixel_multiplier;
/* * - During modeset the pipe is still disabled and must remain so * - During fastset the pipe is already enabled and must remain so
*/ if (!intel_crtc_needs_modeset(crtc_state))
val |= TRANSCONF_ENABLE;
switch (crtc_state->pipe_bpp) { default: /* Case prevented by intel_choose_pipe_bpp_dither. */
MISSING_CASE(crtc_state->pipe_bpp);
fallthrough; case 18:
val |= TRANSCONF_BPC_6; break; case 24:
val |= TRANSCONF_BPC_8; break; case 30:
val |= TRANSCONF_BPC_10; break; case 36:
val |= TRANSCONF_BPC_12; break;
}
if (crtc_state->dither)
val |= TRANSCONF_DITHER_EN | TRANSCONF_DITHER_TYPE_SP;
if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
val |= TRANSCONF_INTERLACE_IF_ID_ILK; else
val |= TRANSCONF_INTERLACE_PF_PD_ILK;
/* * This would end up with an odd purple hue over * the entire display. Make sure we don't do it.
*/
drm_WARN_ON(display->drm, crtc_state->limited_color_range &&
crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB);
if (crtc_state->limited_color_range &&
!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO))
val |= TRANSCONF_COLOR_RANGE_SELECT;
if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB)
val |= TRANSCONF_OUTPUT_COLORSPACE_YUV709;
val |= TRANSCONF_GAMMA_MODE(crtc_state->gamma_mode);
val |= TRANSCONF_FRAME_START_DELAY(crtc_state->framestart_delay - 1);
val |= TRANSCONF_MSA_TIMING_DELAY(crtc_state->msa_timing_delay);
/* * - During modeset the pipe is still disabled and must remain so * - During fastset the pipe is already enabled and must remain so
*/ if (!intel_crtc_needs_modeset(crtc_state))
val |= TRANSCONF_ENABLE;
if (display->platform.haswell && crtc_state->dither)
val |= TRANSCONF_DITHER_EN | TRANSCONF_DITHER_TYPE_SP;
if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
val |= TRANSCONF_INTERLACE_IF_ID_ILK; else
val |= TRANSCONF_INTERLACE_PF_PD_ILK;
if (display->platform.haswell &&
crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB)
val |= TRANSCONF_OUTPUT_COLORSPACE_YUV_HSW;
switch (crtc_state->pipe_bpp) { case 18:
val |= PIPE_MISC_BPC_6; break; case 24:
val |= PIPE_MISC_BPC_8; break; case 30:
val |= PIPE_MISC_BPC_10; break; case 36: /* Port output 12BPC defined for ADLP+ */ if (DISPLAY_VER(display) >= 13)
val |= PIPE_MISC_BPC_12_ADLP; break; default:
MISSING_CASE(crtc_state->pipe_bpp); break;
}
if (crtc_state->dither)
val |= PIPE_MISC_DITHER_ENABLE | PIPE_MISC_DITHER_TYPE_SP;
if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
val |= PIPE_MISC_OUTPUT_COLORSPACE_YUV;
if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
val |= DISPLAY_VER(display) >= 30 ? PIPE_MISC_YUV420_ENABLE :
PIPE_MISC_YUV420_ENABLE | PIPE_MISC_YUV420_MODE_FULL_BLEND;
if (DISPLAY_VER(display) >= 11 && is_hdr_mode(crtc_state))
val |= PIPE_MISC_HDR_MODE_PRECISION;
if (DISPLAY_VER(display) >= 12)
val |= PIPE_MISC_PIXEL_ROUNDING_TRUNC;
/* allow PSR with sprite enabled */ if (display->platform.broadwell)
val |= PIPE_MISC_PSR_MASK_SPRITE_ENABLE;
switch (tmp & PIPE_MISC_BPC_MASK) { case PIPE_MISC_BPC_6: return 18; case PIPE_MISC_BPC_8: return 24; case PIPE_MISC_BPC_10: return 30; /* * PORT OUTPUT 12 BPC defined for ADLP+. * * TODO: * For previous platforms with DSI interface, bits 5:7 * are used for storing pipe_bpp irrespective of dithering. * Since the value of 12 BPC is not defined for these bits * on older platforms, need to find a workaround for 12 BPC * MIPI DSI HW readout.
*/ case PIPE_MISC_BPC_12_ADLP: if (DISPLAY_VER(display) >= 13) return 36;
fallthrough; default:
MISSING_CASE(tmp); return 0;
}
}
int ilk_get_lanes_required(int target_clock, int link_bw, int bpp)
{ /* * Account for spread spectrum to avoid * oversubscribing the link. Max center spread * is 2.5%; use 5% for safety's sake.
*/
u32 bps = target_clock * bpp * 21 / 20; return DIV_ROUND_UP(bps, link_bw * 8);
}
enabled_ultrajoiner_pipes(display, &primary_ultrajoiner_pipes,
&secondary_ultrajoiner_pipes); /* * For some strange reason the last pipe in the set of four * shouldn't have ultrajoiner enable bit set in hardware. * Set the bit anyway to make life easier.
*/
drm_WARN_ON(display->drm,
expected_secondary_pipes(primary_ultrajoiner_pipes, 3) !=
secondary_ultrajoiner_pipes);
secondary_ultrajoiner_pipes =
fixup_ultrajoiner_secondary_pipes(primary_ultrajoiner_pipes,
secondary_ultrajoiner_pipes);
staticvoid assert_enabled_transcoders(struct intel_display *display,
u8 enabled_transcoders)
{ /* Only one type of transcoder please */
drm_WARN_ON(display->drm,
has_edp_transcoders(enabled_transcoders) +
has_dsi_transcoders(enabled_transcoders) +
has_pipe_transcoders(enabled_transcoders) > 1);
/* Only DSI transcoders can be ganged */
drm_WARN_ON(display->drm,
!has_dsi_transcoders(enabled_transcoders) &&
!is_power_of_2(enabled_transcoders));
}
/* * With the exception of DSI we should only ever have * a single enabled transcoder. With DSI let's just * pick the first one.
*/
pipe_config->cpu_transcoder = ffs(enabled_transcoders) - 1;
if (!intel_display_power_get_in_set_if_enabled(display, power_domain_set,
POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder))) returnfalse;
if (hsw_panel_transcoders(display) & BIT(pipe_config->cpu_transcoder)) {
tmp = intel_de_read(display,
TRANS_DDI_FUNC_CTL(display, pipe_config->cpu_transcoder));
if ((tmp & TRANS_DDI_EDP_INPUT_MASK) == TRANS_DDI_EDP_INPUT_A_ONOFF)
pipe_config->pch_pfit.force_thru = true;
}
if (!intel_display_power_get_in_set_if_enabled(display, power_domain_set,
POWER_DOMAIN_TRANSCODER(cpu_transcoder))) continue;
/* * The PLL needs to be enabled with a valid divider * configuration, otherwise accessing DSI registers will hang * the machine. See BSpec North Display Engine * registers/MIPI[BXT]. We can break out here early, since we * need the same DSI PLL to be enabled for both DSI ports.
*/ if (!bxt_dsi_pll_is_enabled(display)) break;
/* XXX: this works for video mode only */
tmp = intel_de_read(display, BXT_MIPI_PORT_CTRL(port)); if (!(tmp & DPI_ENABLE)) continue;
if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) {
tmp = intel_de_read(display, CHICKEN_TRANS(display, pipe_config->cpu_transcoder));
pipe_config->framestart_delay = REG_FIELD_GET(HSW_FRAME_START_DELAY_MASK, tmp) + 1;
} else { /* no idea if this is correct */
pipe_config->framestart_delay = 1;
}
if (!display->funcs.display->get_pipe_config(crtc, crtc_state)) returnfalse;
crtc_state->hw.active = true;
intel_crtc_readout_derived_state(crtc_state);
returntrue;
}
int intel_dotclock_calculate(int link_freq, conststruct intel_link_m_n *m_n)
{ /* * The calculation for the data clock -> pixel clock is: * pixel_clock = ((m/n)*(link_clock * nr_lanes))/bpp * But we want to avoid losing precision if possible, so: * pixel_clock = ((m * link_clock * nr_lanes)/(n*bpp)) * * and for link freq (10kbs units) -> pixel clock it is: * link_symbol_clock = link_freq * 10 / link_symbol_size * pixel_clock = (m * link_symbol_clock) / n * or for more precision: * pixel_clock = (m * link_freq * 10) / (n * link_symbol_size)
*/
if (intel_crtc_needs_modeset(crtc_state)) {
ret = intel_dpll_crtc_get_dpll(state, crtc); if (ret) return ret;
}
ret = intel_color_check(state, crtc); if (ret) return ret;
ret = intel_wm_compute(state, crtc); if (ret) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] watermarks are invalid\n",
crtc->base.base.id, crtc->base.name); return ret;
}
if (DISPLAY_VER(display) >= 9) { if (intel_crtc_needs_modeset(crtc_state) ||
intel_crtc_needs_fastset(crtc_state)) {
ret = skl_update_scaler_crtc(crtc_state); if (ret) return ret;
}
ret = intel_atomic_setup_scalers(state, crtc); if (ret) return ret;
}
if (HAS_IPS(display)) {
ret = hsw_ips_compute_config(state, crtc); if (ret) return ret;
}
if (DISPLAY_VER(display) >= 9 ||
display->platform.broadwell || display->platform.haswell) {
ret = hsw_compute_linetime_wm(state, crtc); if (ret) return ret;
}
ret = intel_psr2_sel_fetch_update(state, crtc); if (ret) return ret;
/* * We're going to peek into connector->state, * hence connection_mutex must be held.
*/
drm_modeset_lock_assert_held(&display->drm->mode_config.connection_mutex);
/* * Walk the connector list instead of the encoder * list to detect the problem on ddi platforms * where there's just one encoder per digital port.
*/
drm_connector_list_iter_begin(display->drm, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) { struct drm_connector_state *connector_state; struct intel_encoder *encoder;
connector_state =
drm_atomic_get_new_connector_state(&state->base,
connector); if (!connector_state)
connector_state = connector->state;
switch (encoder->type) { case INTEL_OUTPUT_DDI: if (drm_WARN_ON(display->drm, !HAS_DDI(display))) break;
fallthrough; case INTEL_OUTPUT_DP: case INTEL_OUTPUT_HDMI: case INTEL_OUTPUT_EDP: /* the same port mustn't appear more than once */ if (used_ports & BIT(encoder->port))
ret = false;
saved_state = kmemdup(primary_crtc_state, sizeof(*saved_state), GFP_KERNEL); if (!saved_state) return -ENOMEM;
/* preserve some things from the slave's original crtc state */
saved_state->uapi = secondary_crtc_state->uapi;
saved_state->scaler_state = secondary_crtc_state->scaler_state;
saved_state->intel_dpll = secondary_crtc_state->intel_dpll;
saved_state->crc_enabled = secondary_crtc_state->crc_enabled;
intel_crtc_free_hw_state(secondary_crtc_state); if (secondary_crtc_state->dp_tunnel_ref.tunnel)
drm_dp_tunnel_ref_put(&secondary_crtc_state->dp_tunnel_ref);
memcpy(secondary_crtc_state, saved_state, sizeof(*secondary_crtc_state));
kfree(saved_state);
/* FIXME: before the switch to atomic started, a new pipe_config was * kzalloc'd. Code that depends on any field being zero should be * fixed, so that the crtc_state can be safely duplicated. For now,
* only fields that are know to not cause problems are preserved. */
/* * Sanitize sync polarity flags based on requested ones. If neither * positive or negative polarity is requested, treat this as meaning * negative polarity.
*/ if (!(crtc_state->hw.adjusted_mode.flags &
(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC)))
crtc_state->hw.adjusted_mode.flags |= DRM_MODE_FLAG_NHSYNC;
if (!(crtc_state->hw.adjusted_mode.flags &
(DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)))
crtc_state->hw.adjusted_mode.flags |= DRM_MODE_FLAG_NVSYNC;
ret = compute_baseline_pipe_bpp(state, crtc); if (ret) return ret;
if (crtc_state->pipe_bpp > fxp_q4_to_int(crtc_state->max_link_bpp_x16)) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] Link bpp limited to " FXP_Q4_FMT "\n",
crtc->base.base.id, crtc->base.name,
FXP_Q4_ARGS(crtc_state->max_link_bpp_x16));
crtc_state->bw_constrained = true;
}
base_bpp = crtc_state->pipe_bpp;
/* * Determine the real pipe dimensions. Note that stereo modes can * increase the actual pipe size due to the frame doubling and * insertion of additional space for blanks between the frame. This * is stored in the crtc timings. We use the requested mode to do this * computation to clearly distinguish it from the adjusted mode, which * can be changed by the connectors in the below retry loop.
*/
drm_mode_get_hv_timing(&crtc_state->hw.mode,
&pipe_src_w, &pipe_src_h);
drm_rect_init(&crtc_state->pipe_src, 0, 0,
pipe_src_w, pipe_src_h);
/* * Determine output_types before calling the .compute_config() * hooks so that the hooks can use this information safely.
*/ if (encoder->compute_output_type)
crtc_state->output_types |=
BIT(encoder->compute_output_type(encoder, crtc_state,
connector_state)); else
crtc_state->output_types |= BIT(encoder->type);
}
/* Ensure the port clock defaults are reset when retrying. */
crtc_state->port_clock = 0;
crtc_state->pixel_multiplier = 1;
/* Fill in default crtc timings, allow encoders to overwrite them. */
drm_mode_set_crtcinfo(&crtc_state->hw.adjusted_mode,
CRTC_STEREO_DOUBLE);
/* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely.
*/
for_each_new_connector_in_state(&state->base, connector, connector_state, i) { struct intel_encoder *encoder =
to_intel_encoder(connector_state->best_encoder);
if (connector_state->crtc != &crtc->base) continue;
ret = encoder->compute_config(encoder, crtc_state,
connector_state); if (ret == -EDEADLK) return ret; if (ret < 0) {
drm_dbg_kms(display->drm, "[ENCODER:%d:%s] config failure: %d\n",
encoder->base.base.id, encoder->base.name, ret); return ret;
}
}
/* Set default port clock if not overwritten by the encoder. Needs to be
* done afterwards in case the encoder adjusts the mode. */ if (!crtc_state->port_clock)
crtc_state->port_clock = crtc_state->hw.adjusted_mode.crtc_clock
* crtc_state->pixel_multiplier;
ret = intel_crtc_compute_config(state, crtc); if (ret == -EDEADLK) return ret; if (ret < 0) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] config failure: %d\n",
crtc->base.base.id, crtc->base.name, ret); return ret;
}
/* Dithering seems to not pass-through bits correctly when it should, so * only enable it on 6bpc panels and when its not a compliance * test requesting 6bpc video pattern.
*/
crtc_state->dither = (crtc_state->pipe_bpp == 6*3) &&
!crtc_state->dither_force_disable;
drm_dbg_kms(display->drm, "[CRTC:%d:%s] hw max bpp: %i, pipe bpp: %i, dithering: %i\n",
crtc->base.base.id, crtc->base.name,
base_bpp, crtc_state->pipe_bpp, crtc_state->dither);
/* * Allow fastboot to fix up vblank delay (handled via LRR * codepaths), a bit dodgy as the registers aren't * double buffered but seems to be working more or less...
*/ return HAS_LRR(display) && old_crtc_state->inherited &&
!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DSI);
}
if (!fastset) {
PIPE_CONF_CHECK_BOOL(has_audio);
PIPE_CONF_CHECK_BUFFER(eld, MAX_ELD_BYTES);
}
PIPE_CONF_CHECK_X(gmch_pfit.control); /* pfit ratios are autocomputed by the hw on gen4+ */ if (DISPLAY_VER(display) < 4)
PIPE_CONF_CHECK_X(gmch_pfit.pgm_ratios);
PIPE_CONF_CHECK_X(gmch_pfit.lvds_border_bits);
/* * Changing the EDP transcoder input mux * (A_ONOFF vs. A_ON) requires a full modeset.
*/
PIPE_CONF_CHECK_BOOL(pch_pfit.force_thru);
drm_dbg_kms(display->drm, "[CRTC:%d:%s] Full modeset due to %s\n",
crtc->base.base.id, crtc->base.name, reason);
ret = drm_atomic_add_affected_connectors(&state->base,
&crtc->base); if (ret) return ret;
ret = intel_dp_tunnel_atomic_add_state_for_crtc(state, crtc); if (ret) return ret;
ret = intel_dp_mst_add_topology_state_for_crtc(state, crtc); if (ret) return ret;
ret = intel_plane_add_affected(state, crtc); if (ret) return ret;
crtc_state->uapi.mode_changed = true;
return 0;
}
/** * intel_modeset_pipes_in_mask_early - force a full modeset on a set of pipes * @state: intel atomic state * @reason: the reason for the full modeset * @mask: mask of pipes to modeset * * Add pipes in @mask to @state and force a full modeset on the enabled ones * due to the description in @reason. * This function can be called only before new plane states are computed. * * Returns 0 in case of success, negative error code otherwise.
*/ int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state, constchar *reason, u8 mask)
{ struct intel_display *display = to_intel_display(state); struct intel_crtc *crtc;
for_each_intel_crtc_in_pipe_mask(display->drm, crtc, mask) { struct intel_crtc_state *crtc_state; int ret;
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state);
if (!crtc_state->hw.enable ||
intel_crtc_needs_modeset(crtc_state)) continue;
ret = intel_modeset_pipe(state, crtc_state, reason); if (ret) return ret;
}
/** * intel_modeset_all_pipes_late - force a full modeset on all pipes * @state: intel atomic state * @reason: the reason for the full modeset * * Add all pipes to @state and force a full modeset on the active ones due to * the description in @reason. * This function can be called only after new plane states are computed already. * * Returns 0 in case of success, negative error code otherwise.
*/ int intel_modeset_all_pipes_late(struct intel_atomic_state *state, constchar *reason)
{ struct intel_display *display = to_intel_display(state); struct intel_crtc *crtc;
for_each_intel_crtc(display->drm, crtc) { struct intel_crtc_state *crtc_state; int ret;
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state);
if (!crtc_state->hw.active ||
intel_crtc_needs_modeset(crtc_state)) continue;
ret = intel_modeset_pipe(state, crtc_state, reason); if (ret) return ret;
if (IS_ERR(crtc_state)) {
ret = PTR_ERR(crtc_state); goto out;
}
crtc_state->uapi.connectors_changed = true;
}
ret = drm_atomic_commit(state);
out:
drm_atomic_state_put(state);
return ret;
}
/* * This implements the workaround described in the "notes" section of the mode * set sequence documentation. When going from no pipes or single pipe to * multiple pipes, and planes are enabled after the pipe, we need to wait at * least 2 vblanks on the first pipe before enabling planes on the second pipe.
*/ staticint hsw_mode_set_planes_workaround(struct intel_atomic_state *state)
{ struct intel_crtc_state *crtc_state; struct intel_crtc *crtc; struct intel_crtc_state *first_crtc_state = NULL; struct intel_crtc_state *other_crtc_state = NULL; enum pipe first_pipe = INVALID_PIPE, enabled_pipe = INVALID_PIPE; int i;
/* look at all crtc's that are going to be enabled in during modeset */
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { if (!crtc_state->hw.active ||
!intel_crtc_needs_modeset(crtc_state)) continue;
/* only allow LRR when the timings stay within the VRR range */ if (old_crtc_state->vrr.in_range != new_crtc_state->vrr.in_range)
new_crtc_state->update_lrr = false;
if (!intel_pipe_config_compare(old_crtc_state, new_crtc_state, true)) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] fastset requirement not met, forcing full modeset\n",
crtc->base.base.id, crtc->base.name);
} else { if (allow_vblank_delay_fastset(old_crtc_state))
new_crtc_state->update_lrr = true;
new_crtc_state->uapi.mode_changed = false;
}
if (intel_compare_link_m_n(&old_crtc_state->dp_m_n,
&new_crtc_state->dp_m_n))
new_crtc_state->update_m_n = false;
if (!lrr_params_changed(&old_crtc_state->hw.adjusted_mode,
&new_crtc_state->hw.adjusted_mode))
new_crtc_state->update_lrr = false;
if (intel_crtc_needs_modeset(new_crtc_state))
intel_crtc_flag_modeset(new_crtc_state); else
new_crtc_state->update_pipe = true;
}
if (primary_crtc_state->joiner_pipes & ~joiner_pipes(display)) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] Cannot act as joiner primary " "(need 0x%x as pipes, only 0x%x possible)\n",
primary_crtc->base.base.id, primary_crtc->base.name,
primary_crtc_state->joiner_pipes, joiner_pipes(display)); return -EINVAL;
}
for_each_intel_crtc_in_pipe_mask(display->drm, secondary_crtc,
intel_crtc_joiner_secondary_pipes(primary_crtc_state)) { struct intel_crtc_state *secondary_crtc_state; int ret;
secondary_crtc_state = intel_atomic_get_crtc_state(&state->base, secondary_crtc); if (IS_ERR(secondary_crtc_state)) return PTR_ERR(secondary_crtc_state);
/* primary being enabled, secondary was already configured? */ if (secondary_crtc_state->uapi.enable) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] secondary is enabled as normal CRTC, but " "[CRTC:%d:%s] claiming this CRTC for joiner.\n",
secondary_crtc->base.base.id, secondary_crtc->base.name,
primary_crtc->base.base.id, primary_crtc->base.name); return -EINVAL;
}
/* * The state copy logic assumes the primary crtc gets processed * before the secondary crtc during the main compute_config loop. * This works because the crtcs are created in pipe order, * and the hardware requires primary pipe < secondary pipe as well. * Should that change we need to rethink the logic.
*/ if (WARN_ON(drm_crtc_index(&primary_crtc->base) >
drm_crtc_index(&secondary_crtc->base))) return -EINVAL;
drm_dbg_kms(display->drm, "[CRTC:%d:%s] Used as secondary for joiner primary [CRTC:%d:%s]\n",
secondary_crtc->base.base.id, secondary_crtc->base.name,
primary_crtc->base.base.id, primary_crtc->base.name);
/** * DOC: asynchronous flip implementation * * Asynchronous page flip is the implementation for the DRM_MODE_PAGE_FLIP_ASYNC * flag. Currently async flip is only supported via the drmModePageFlip IOCTL. * Correspondingly, support is currently added for primary plane only. * * Async flip can only change the plane surface address, so anything else * changing is rejected from the intel_async_flip_check_hw() function. * Once this check is cleared, flip done interrupt is enabled using * the intel_crtc_enable_flip_done() function. * * As soon as the surface address register is written, flip done interrupt is * generated and the requested events are sent to the userspace in the interrupt * handler itself. The timestamp and sequence sent during the flip done event * correspond to the last vblank and have no relation to the actual time when * the flip done event was sent.
*/ staticint intel_async_flip_check_uapi(struct intel_atomic_state *state, struct intel_crtc *crtc)
{ struct intel_display *display = to_intel_display(state); conststruct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc); conststruct intel_plane_state *old_plane_state; struct intel_plane_state *new_plane_state; struct intel_plane *plane; int i;
if (!new_crtc_state->uapi.async_flip) return 0;
if (!new_crtc_state->uapi.active) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] not active\n",
crtc->base.base.id, crtc->base.name); return -EINVAL;
}
/* * FIXME: joiner+async flip is busted currently. * Remove this check once the issues are fixed.
*/ if (new_crtc_state->joiner_pipes) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] async flip disallowed with joiner\n",
crtc->base.base.id, crtc->base.name); return -EINVAL;
}
/* * TODO: Async flip is only supported through the page flip IOCTL * as of now. So support currently added for primary plane only. * Support for other planes on platforms on which supports * this(vlv/chv and icl+) should be added when async flip is * enabled in the atomic IOCTL path.
*/ if (!plane->async_flip) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] async flip not supported\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
if (!old_plane_state->uapi.fb || !new_plane_state->uapi.fb) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] no old or new framebuffer\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
}
if (old_crtc_state->active_planes != new_crtc_state->active_planes) {
drm_dbg_kms(display->drm, "[CRTC:%d:%s] Active planes cannot be in async flip\n",
crtc->base.base.id, crtc->base.name); return -EINVAL;
}
/* * Only async flip capable planes should be in the state * if we're really about to ask the hardware to perform * an async flip. We should never get this far otherwise.
*/ if (drm_WARN_ON(display->drm,
new_crtc_state->do_async_flip && !plane->async_flip)) return -EINVAL;
/* * Only check async flip capable planes other planes * may be involved in the initial commit due to * the wm0/ddb optimization. * * TODO maybe should track which planes actually * were requested to do the async flip...
*/ if (!plane->async_flip) continue;
if (!intel_plane_can_async_flip(plane, new_plane_state->hw.fb->format->format,
new_plane_state->hw.fb->modifier)) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] pixel format %p4cc / modifier 0x%llx does not support async flip\n",
plane->base.base.id, plane->base.name,
&new_plane_state->hw.fb->format->format,
new_plane_state->hw.fb->modifier); return -EINVAL;
}
/* * We turn the first async flip request into a sync flip * so that we can reconfigure the plane (eg. change modifier).
*/ if (!new_crtc_state->do_async_flip) continue;
if (old_plane_state->view.color_plane[0].mapping_stride !=
new_plane_state->view.color_plane[0].mapping_stride) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] Stride cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
if (old_plane_state->hw.fb->modifier !=
new_plane_state->hw.fb->modifier) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] Modifier cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
if (old_plane_state->hw.fb->format !=
new_plane_state->hw.fb->format) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] Pixel format cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
if (old_plane_state->hw.rotation !=
new_plane_state->hw.rotation) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] Rotation cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
if (skl_plane_aux_dist(old_plane_state, 0) !=
skl_plane_aux_dist(new_plane_state, 0)) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] AUX_DIST cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
if (!drm_rect_equals(&old_plane_state->uapi.src, &new_plane_state->uapi.src) ||
!drm_rect_equals(&old_plane_state->uapi.dst, &new_plane_state->uapi.dst)) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] Size/co-ordinates cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
if (old_plane_state->hw.alpha != new_plane_state->hw.alpha) {
drm_dbg_kms(display->drm, "[PLANES:%d:%s] Alpha value cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
if (old_plane_state->hw.pixel_blend_mode !=
new_plane_state->hw.pixel_blend_mode) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] Pixel blend mode cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
if (old_plane_state->hw.color_encoding != new_plane_state->hw.color_encoding) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] Color encoding cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
if (old_plane_state->hw.color_range != new_plane_state->hw.color_range) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] Color range cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
/* plane decryption is allow to change only in synchronous flips */ if (old_plane_state->decrypt != new_plane_state->decrypt) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] Decryption cannot be changed in async flip\n",
plane->base.base.id, plane->base.name); return -EINVAL;
}
}
/* * Any plane which is in use by the joiner needs its crtc. * Pull those in first as this will not have happened yet * if the plane remains disabled according to uapi.
*/
for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
crtc = to_intel_crtc(plane_state->hw.crtc); if (!crtc) continue;
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state);
}
/* Now pull in all joined crtcs */
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
affected_pipes |= crtc_state->joiner_pipes; if (intel_crtc_needs_modeset(crtc_state))
modeset_pipes |= crtc_state->joiner_pipes;
}
ret = intel_atomic_check_config(state, &new_limits,
&failed_pipe); if (ret) { /* * The bpp limit for a pipe is below the minimum it supports, set the * limit to the minimum and recalculate the config.
*/ if (ret == -EINVAL &&
intel_link_bw_set_bpp_limit_for_pipe(state,
&old_limits,
&new_limits,
failed_pipe)) continue;
break;
}
old_limits = new_limits;
ret = intel_link_bw_atomic_check(state, &new_limits); if (ret != -EAGAIN) break;
}
if (!intel_display_driver_check_access(display)) return -ENODEV;
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) { /* * crtc's state no longer considered to be inherited * after the first userspace/client initiated commit.
*/ if (!state->internal)
new_crtc_state->inherited = false;
if (new_crtc_state->inherited != old_crtc_state->inherited)
new_crtc_state->uapi.mode_changed = true;
if (new_crtc_state->uapi.scaling_filter !=
old_crtc_state->uapi.scaling_filter)
new_crtc_state->uapi.mode_changed = true;
}
intel_vrr_check_modeset(state);
ret = drm_atomic_helper_check_modeset(dev, &state->base); if (ret) goto fail;
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
ret = intel_async_flip_check_uapi(state, crtc); if (ret) return ret;
}
ret = intel_atomic_check_config_and_link(state); if (ret) goto fail;
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { if (!intel_crtc_needs_modeset(new_crtc_state)) continue;
if (intel_crtc_is_joiner_secondary(new_crtc_state)) {
drm_WARN_ON(display->drm, new_crtc_state->uapi.enable); continue;
}
ret = intel_atomic_check_joiner(state, crtc); if (ret) goto fail;
}
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) { if (!intel_crtc_needs_modeset(new_crtc_state)) continue;
/** * Check if fastset is allowed by external dependencies like other * pipes and transcoders. * * Right now it only forces a fullmodeset when the MST master * transcoder did not changed but the pipe of the master transcoder * needs a fullmodeset so all slaves also needs to do a fullmodeset or * in case of port synced crtcs, if one of the synced crtcs * needs a full modeset, all other synced crtcs should be * forced a full modeset.
*/
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { if (!new_crtc_state->hw.enable || intel_crtc_needs_modeset(new_crtc_state)) continue;
if (intel_dp_mst_crtc_needs_modeset(state, crtc))
intel_crtc_flag_modeset(new_crtc_state);
if (intel_dp_mst_is_slave_trans(new_crtc_state)) { enum transcoder master = new_crtc_state->mst_master_transcoder;
if (intel_cpu_transcoders_need_modeset(state, BIT(master)))
intel_crtc_flag_modeset(new_crtc_state);
}
if (is_trans_port_sync_mode(new_crtc_state)) {
u8 trans = new_crtc_state->sync_mode_slaves_mask;
if (new_crtc_state->master_transcoder != INVALID_TRANSCODER)
trans |= BIT(new_crtc_state->master_transcoder);
if (intel_cpu_transcoders_need_modeset(state, trans))
intel_crtc_flag_modeset(new_crtc_state);
}
if (new_crtc_state->joiner_pipes) { if (intel_pipes_need_modeset(state, new_crtc_state->joiner_pipes))
intel_crtc_flag_modeset(new_crtc_state);
}
}
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) { if (!intel_crtc_needs_modeset(new_crtc_state)) continue;
any_ms = true;
intel_dpll_release(state, crtc);
}
if (any_ms && !check_digital_port_conflicts(state)) {
drm_dbg_kms(display->drm, "rejecting conflicting digital port configuration\n");
ret = -EINVAL; goto fail;
}
ret = intel_plane_atomic_check(state); if (ret) goto fail;
ret = intel_compute_global_watermarks(state); if (ret) goto fail;
ret = intel_bw_atomic_check(state, any_ms); if (ret) goto fail;
ret = intel_cdclk_atomic_check(state, &any_ms); if (ret) goto fail;
if (intel_any_crtc_needs_modeset(state))
any_ms = true;
if (any_ms) {
ret = intel_modeset_checks(state); if (ret) goto fail;
ret = intel_modeset_calc_cdclk(state); if (ret) return ret;
}
ret = intel_pmdemand_atomic_check(state); if (ret) goto fail;
ret = intel_atomic_check_crtcs(state); if (ret) goto fail;
ret = intel_fbc_atomic_check(state); if (ret) goto fail;
ret = intel_async_flip_check_hw(state, crtc); if (ret) goto fail;
/* Either full modeset or fastset (or neither), never both */
drm_WARN_ON(display->drm,
intel_crtc_needs_modeset(new_crtc_state) &&
intel_crtc_needs_fastset(new_crtc_state));
if (!intel_crtc_needs_modeset(new_crtc_state) &&
!intel_crtc_needs_fastset(new_crtc_state)) continue;
/* * FIXME would probably be nice to know which crtc specifically * caused the failure, in cases where we can pinpoint it.
*/
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i)
intel_crtc_state_dump(new_crtc_state, state, "failed");
return ret;
}
staticint intel_atomic_prepare_commit(struct intel_atomic_state *state)
{ int ret;
ret = drm_atomic_helper_prepare_planes(state->base.dev, &state->base); if (ret < 0) return ret;
/* * Update pipe size and adjust fitter if needed: the reason for this is * that in compute_mode_changes we check the native mode (not the pfit * mode) to see if we can flip rather than do a full mode set. In the * fastboot case, we'll flip, but if we don't update the pipesrc and * pfit state, we'll end up with a big fb scanned out into the wrong * sized surface.
*/
intel_set_pipe_src_size(new_crtc_state);
/* on skylake this is done by detaching scalers */ if (DISPLAY_VER(display) >= 9) { if (new_crtc_state->pch_pfit.enabled)
skl_pfit_enable(new_crtc_state);
} elseif (HAS_PCH_SPLIT(display)) { if (new_crtc_state->pch_pfit.enabled)
ilk_pfit_enable(new_crtc_state); elseif (old_crtc_state->pch_pfit.enabled)
ilk_pfit_disable(old_crtc_state);
}
/* * The register is supposedly single buffered so perhaps * not 100% correct to do this here. But SKL+ calculate * this based on the adjust pixel rate so pfit changes do * affect it and so it must be updated for fastsets. * HSW/BDW only really need this here for fastboot, after * that the value should not change without a full modeset.
*/ if (DISPLAY_VER(display) >= 9 ||
display->platform.broadwell || display->platform.haswell)
hsw_set_linetime_wm(new_crtc_state);
if (new_crtc_state->update_m_n)
intel_cpu_transcoder_set_m1_n1(crtc, new_crtc_state->cpu_transcoder,
&new_crtc_state->dp_m_n);
if (new_crtc_state->update_lrr)
intel_set_transcoder_timings_lrr(new_crtc_state);
}
/* * During modesets pipe configuration was programmed as the * CRTC was enabled.
*/ if (!modeset) { if (intel_crtc_needs_color_update(new_crtc_state))
intel_color_commit_arm(NULL, new_crtc_state);
if (DISPLAY_VER(display) >= 9 || display->platform.broadwell)
bdw_set_pipe_misc(NULL, new_crtc_state);
if (intel_crtc_needs_fastset(new_crtc_state))
intel_pipe_fastset(old_crtc_state, new_crtc_state);
}
/* * Disable the scaler(s) after the plane(s) so that we don't * get a catastrophic underrun even if the two operations * end up happening in two different frames.
*/ if (DISPLAY_VER(display) >= 9 && !modeset)
skl_detach_scalers(NULL, new_crtc_state);
if (!modeset &&
intel_crtc_needs_color_update(new_crtc_state) &&
!intel_color_uses_dsb(new_crtc_state) &&
HAS_DOUBLE_BUFFERED_LUT(display))
intel_color_load_luts(new_crtc_state);
if (intel_crtc_vrr_enabling(state, crtc))
intel_vrr_enable(new_crtc_state);
}
if (new_crtc_state->dsb_commit)
intel_dsb_commit(new_crtc_state->dsb_commit);
commit_pipe_pre_planes(state, crtc);
intel_crtc_planes_update_arm(NULL, state, crtc);
commit_pipe_post_planes(state, crtc);
intel_pipe_update_end(state, crtc);
}
/* * VRR/Seamless M/N update may need to update frame timings. * * FIXME Should be synchronized with the start of vblank somehow...
*/ if (intel_crtc_vrr_enabling(state, crtc) ||
new_crtc_state->update_m_n || new_crtc_state->update_lrr)
intel_crtc_update_active_timings(new_crtc_state,
new_crtc_state->vrr.enable);
/* * We usually enable FIFO underrun interrupts as part of the * CRTC enable sequence during modesets. But when we inherit a * valid pipe configuration from the BIOS we need to take care * of enabling them on the CRTC's first fastset.
*/ if (intel_crtc_needs_fastset(new_crtc_state) &&
old_crtc_state->inherited)
intel_crtc_arm_fifo_underrun(crtc, new_crtc_state);
}
/* * We need to disable pipe CRC before disabling the pipe, * or we race against vblank off.
*/
for_each_intel_crtc_in_pipe_mask(display->drm, pipe_crtc,
intel_crtc_joined_pipe_mask(old_crtc_state))
intel_crtc_disable_pipe_crc(pipe_crtc);
/* Only disable port sync and MST slaves */
for_each_old_intel_crtc_in_state(state, crtc, old_crtc_state, i) { if ((disable_pipes & BIT(crtc->pipe)) == 0) continue;
if (intel_crtc_is_joiner_secondary(old_crtc_state)) continue;
/* In case of Transcoder port Sync master slave CRTCs can be * assigned in any order and we need to make sure that * slave CRTCs are disabled first and then master CRTC since * Slave vblanks are masked till Master Vblanks.
*/ if (!is_trans_port_sync_slave(old_crtc_state) &&
!intel_dp_mst_is_slave_trans(old_crtc_state)) continue;
/* ignore allocations for crtc's that have been turned off. */ if (!intel_crtc_needs_modeset(new_crtc_state)) {
entries[pipe] = old_crtc_state->wm.skl.ddb;
update_pipes |= BIT(pipe);
} else {
modeset_pipes |= BIT(pipe);
}
}
/* * Whenever the number of active pipes changes, we need to make sure we * update the pipes in the right order so that their ddb allocations * never overlap with each other between CRTC updates. Otherwise we'll * cause pipe underruns and other bad stuff. * * So first lets enable all pipes that do not need a fullmodeset as * those don't have any external dependency.
*/
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { enum pipe pipe = crtc->pipe;
if ((update_pipes & BIT(pipe)) == 0) continue;
intel_pre_update_crtc(state, crtc);
}
intel_dbuf_mbus_pre_ddb_update(state);
while (update_pipes) { /* * Commit in reverse order to make joiner primary * send the uapi events after secondaries are done.
*/
for_each_oldnew_intel_crtc_in_state_reverse(state, crtc, old_crtc_state,
new_crtc_state, i) { enum pipe pipe = crtc->pipe;
if ((update_pipes & BIT(pipe)) == 0) continue;
if (skl_ddb_allocation_overlaps(&new_crtc_state->wm.skl.ddb,
entries, I915_MAX_PIPES, pipe)) continue;
/* * If this is an already active pipe, it's DDB changed, * and this isn't the last pipe that needs updating * then we need to wait for a vblank to pass for the * new ddb allocation to take effect.
*/ if (!skl_ddb_entry_equal(&new_crtc_state->wm.skl.ddb,
&old_crtc_state->wm.skl.ddb) &&
(update_pipes | modeset_pipes))
intel_crtc_wait_for_next_vblank(crtc);
}
}
intel_dbuf_mbus_post_ddb_update(state);
update_pipes = modeset_pipes;
/* * Enable all pipes that needs a modeset and do not depends on other * pipes
*/
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { enum pipe pipe = crtc->pipe;
if ((modeset_pipes & BIT(pipe)) == 0) continue;
if (intel_crtc_is_joiner_secondary(new_crtc_state)) continue;
if (intel_dp_mst_is_slave_trans(new_crtc_state) ||
is_trans_port_sync_master(new_crtc_state)) continue;
/* * Then we enable all remaining pipes that depend on other * pipes: MST slaves and port sync masters
*/
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { enum pipe pipe = crtc->pipe;
if ((modeset_pipes & BIT(pipe)) == 0) continue;
if (intel_crtc_is_joiner_secondary(new_crtc_state)) continue;
/* * Finally we do the plane updates/etc. for all pipes that got enabled.
*/
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { enum pipe pipe = crtc->pipe;
if ((update_pipes & BIT(pipe)) == 0) continue;
intel_pre_update_crtc(state, crtc);
}
/* * Commit in reverse order to make joiner primary * send the uapi events after secondaries are done.
*/
for_each_new_intel_crtc_in_state_reverse(state, crtc, new_crtc_state, i) { enum pipe pipe = crtc->pipe;
for_each_new_intel_plane_in_state(state, plane, plane_state, i) { struct drm_framebuffer *fb = plane_state->hw.fb; int cc_plane; int ret;
if (!fb) continue;
cc_plane = intel_fb_rc_ccs_cc_plane(fb); if (cc_plane < 0) continue;
/* * The layout of the fast clear color value expected by HW * (the DRM ABI requiring this value to be located in fb at * offset 0 of cc plane, plane #2 previous generations or * plane #1 for flat ccs): * - 4 x 4 bytes per-channel value * (in surface type specific float/int format provided by the fb user) * - 8 bytes native color value used by the display * (converted/written by GPU during a fast clear operation using the * above per-channel values) * * The commit's FB prepare hook already ensured that FB obj is pinned and the * caller made sure that the object is synced wrt. the related color clear value * GPU write on it.
*/
ret = intel_bo_read_from_page(intel_fb_bo(fb),
fb->offsets[cc_plane] + 16,
&plane_state->ccval, sizeof(plane_state->ccval)); /* The above could only fail if the FB obj has an unexpected backing store type. */
drm_WARN_ON(display->drm, ret);
}
}
if (!new_crtc_state->use_flipq &&
!new_crtc_state->use_dsb &&
!new_crtc_state->dsb_color) return;
/* * Rough estimate: * ~64 registers per each plane * 8 planes = 512 * Double that for pipe stuff and other overhead.
*/
new_crtc_state->dsb_commit = intel_dsb_prepare(state, crtc, INTEL_DSB_0,
new_crtc_state->use_dsb ||
new_crtc_state->use_flipq ? 1024 : 16); if (!new_crtc_state->dsb_commit) {
new_crtc_state->use_flipq = false;
new_crtc_state->use_dsb = false;
intel_color_cleanup_commit(new_crtc_state); return;
}
if (new_crtc_state->use_flipq || new_crtc_state->use_dsb) { /* Wa_18034343758 */ if (new_crtc_state->use_flipq)
intel_flipq_wait_dmc_halt(new_crtc_state->dsb_commit, crtc);
if (intel_crtc_needs_color_update(new_crtc_state))
intel_color_commit_noarm(new_crtc_state->dsb_commit,
new_crtc_state);
intel_crtc_planes_update_noarm(new_crtc_state->dsb_commit,
state, crtc);
/* * Ensure we have "Frame Change" event when PSR state is * SRDENT(PSR1) or DEEP_SLEEP(PSR2). Otherwise DSB vblank * evasion hangs as PIPEDSL is reading as 0.
*/
intel_psr_trigger_frame_change_event(new_crtc_state->dsb_commit,
state, crtc);
if (new_crtc_state->use_dsb)
intel_dsb_vblank_evade(state, new_crtc_state->dsb_commit);
/* * During full modesets we write a lot of registers, wait * for PLLs, etc. Doing that while DC states are enabled * is not a good idea. * * During fastsets and other updates we also need to * disable DC states due to the following scenario: * 1. DC5 exit and PSR exit happen * 2. Some or all _noarm() registers are written * 3. Due to some long delay PSR is re-entered * 4. DC5 entry -> DMC saves the already written new * _noarm() registers and the old not yet written * _arm() registers * 5. DC5 exit -> DMC restores a mixture of old and * new register values and arms the update * 6. PSR exit -> hardware latches a mixture of old and * new register values -> corrupted frame, or worse * 7. New _arm() registers are finally written * 8. Hardware finally latches a complete set of new * register values, and subsequent frames will be OK again * * Also note that due to the pipe CSC hardware issues on * SKL/GLK DC states must remain off until the pipe CSC * state readout has happened. Otherwise we risk corrupting * the CSC latched register values with the readout (see * skl_read_csc() and skl_color_commit_noarm()).
*/
wakeref = intel_display_power_get(display, POWER_DOMAIN_DC_OFF);
/* FIXME: Eventually get rid of our crtc->config pointer */
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i)
crtc->config = new_crtc_state;
/* * In XE_LPD+ Pmdemand combines many parameters such as voltage index, * plls, cdclk frequency, QGV point selection parameter etc. Voltage * index, cdclk/ddiclk frequencies are supposed to be configured before * the cdclk config is set.
*/
intel_pmdemand_pre_plane_update(state);
if (state->modeset) {
drm_atomic_helper_update_legacy_modeset_state(display->drm, &state->base);
intel_set_cdclk_pre_plane_update(state);
intel_modeset_verify_disabled(state);
}
intel_sagv_pre_plane_update(state);
/* Complete the events for pipes that have now been disabled */
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { bool modeset = intel_crtc_needs_modeset(new_crtc_state);
/* Complete events for now disable pipes here. */ if (modeset && !new_crtc_state->hw.active && new_crtc_state->uapi.event) {
spin_lock_irq(&display->drm->event_lock);
drm_crtc_send_vblank_event(&crtc->base,
new_crtc_state->uapi.event);
spin_unlock_irq(&display->drm->event_lock);
new_crtc_state->uapi.event = NULL;
}
}
intel_encoders_update_prepare(state);
intel_dbuf_pre_plane_update(state);
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { if (new_crtc_state->do_async_flip)
intel_crtc_enable_flip_done(state, crtc);
}
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
display->funcs.display->commit_modeset_enables(state);
/* FIXME probably need to sequence this properly */
intel_program_dpkgc_latency(state);
intel_wait_for_vblank_workers(state);
/* FIXME: We should call drm_atomic_helper_commit_hw_done() here * already, but still need the state for the delayed optimization. To * fix this: * - wrap the optimization/post_plane_update stuff into a per-crtc work. * - schedule that vblank worker _before_ calling hw_done * - at the start of commit_tail, cancel it _synchrously * - switch over to the vblank wait helper in the core after that since * we don't need out special handling any more.
*/
drm_atomic_helper_wait_for_flip_done(display->drm, &state->base);
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { if (new_crtc_state->do_async_flip)
intel_crtc_disable_flip_done(state, crtc);
intel_atomic_dsb_wait_commit(new_crtc_state);
if (!state->base.legacy_cursor_update && !new_crtc_state->use_dsb)
intel_vrr_check_push_sent(NULL, new_crtc_state);
if (new_crtc_state->use_flipq)
intel_flipq_disable(new_crtc_state);
}
/* * Now that the vblank has passed, we can go ahead and program the * optimal watermarks on platforms that need two-step watermark * programming. * * TODO: Move this (and other cleanup) to an async worker eventually.
*/
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) { /* * Gen2 reports pipe underruns whenever all planes are disabled. * So re-enable underrun reporting after some planes get enabled. * * We do this before .optimize_watermarks() so that we have a * chance of catching underruns with the intermediate watermarks * vs. the new plane configuration.
*/ if (DISPLAY_VER(display) == 2 && planes_enabling(old_crtc_state, new_crtc_state))
intel_set_cpu_fifo_underrun_reporting(display, crtc->pipe, true);
/* * DSB cleanup is done in cleanup_work aligning with framebuffer * cleanup. So copy and reset the dsb structure to sync with * commit_done and later do dsb cleanup in cleanup_work. * * FIXME get rid of this funny new->old swapping
*/
old_crtc_state->dsb_color = fetch_and_zero(&new_crtc_state->dsb_color);
old_crtc_state->dsb_commit = fetch_and_zero(&new_crtc_state->dsb_commit);
}
if (state->modeset) { /* As one of the primary mmio accessors, KMS has a high * likelihood of triggering bugs in unclaimed access. After we * finish modesetting, see if an error has been flagged, and if * so enable debugging for the next modeset - and hope we catch * the culprit.
*/
intel_uncore_arm_unclaimed_mmio_detection(&dev_priv->uncore);
} /* * Delay re-enabling DC states by 17 ms to avoid the off->on->off * toggling overhead at and above 60 FPS.
*/
intel_display_power_put_async_delay(display, POWER_DOMAIN_DC_OFF, wakeref, 17);
intel_display_rpm_put(display, state->wakeref);
/* * Defer the cleanup of the old state to a separate worker to not * impede the current task (userspace for blocking modesets) that * are executed inline. For out-of-line asynchronous modesets/flips, * deferring to a new worker seems overkill, but we would place a * schedule point (cond_resched()) here anyway to keep latencies * down.
*/
INIT_WORK(&state->cleanup_work, intel_atomic_cleanup_work);
queue_work(display->wq.cleanup, &state->cleanup_work);
}
staticint intel_atomic_setup_commit(struct intel_atomic_state *state, bool nonblock)
{ int ret;
ret = drm_atomic_helper_setup_commit(&state->base, nonblock); if (ret) return ret;
ret = intel_atomic_global_state_setup_commit(state); if (ret) return ret;
return 0;
}
staticint intel_atomic_swap_state(struct intel_atomic_state *state)
{ int ret;
ret = drm_atomic_helper_swap_state(&state->base, true); if (ret) return ret;
intel_atomic_swap_global_state(state);
intel_dpll_swap_state(state);
intel_atomic_track_fbs(state);
return 0;
}
int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, bool nonblock)
{ struct intel_display *display = to_intel_display(dev); struct intel_atomic_state *state = to_intel_atomic_state(_state); int ret = 0;
state->wakeref = intel_display_rpm_get(display);
/* * The intel_legacy_cursor_update() fast path takes care * of avoiding the vblank waits for simple cursor * movement and flips. For cursor on/off and size changes, * we want to perform the vblank waits so that watermark * updates happen during the correct frames. Gen9+ have * double buffered watermarks and so shouldn't need this. * * Unset state->legacy_cursor_update before the call to * drm_atomic_helper_setup_commit() because otherwise * drm_atomic_helper_wait_for_flip_done() is a noop and * we get FIFO underruns because we didn't wait * for vblank. * * FIXME doing watermarks and fb cleanup from a vblank worker * (assuming we had any) would solve these problems.
*/ if (DISPLAY_VER(display) < 9 && state->base.legacy_cursor_update) { struct intel_crtc_state *new_crtc_state; struct intel_crtc *crtc; int i;
ret = intel_atomic_prepare_commit(state); if (ret) {
drm_dbg_atomic(display->drm, "Preparing state failed with %i\n", ret);
intel_display_rpm_put(display, state->wakeref); return ret;
}
ret = intel_atomic_setup_commit(state, nonblock); if (!ret)
ret = intel_atomic_swap_state(state);
if (ret) {
drm_atomic_helper_unprepare_planes(dev, &state->base);
intel_display_rpm_put(display, state->wakeref); return ret;
}
staticbool ilk_has_edp_a(struct intel_display *display)
{ if (!display->platform.mobile) returnfalse;
if ((intel_de_read(display, DP_A) & DP_DETECTED) == 0) returnfalse;
if (display->platform.ironlake && (intel_de_read(display, FUSE_STRAP) & ILK_eDP_A_DISABLE)) returnfalse;
returntrue;
}
staticbool intel_ddi_crt_present(struct intel_display *display)
{ if (DISPLAY_VER(display) >= 9) returnfalse;
if (display->platform.haswell_ult || display->platform.broadwell_ult) returnfalse;
if (HAS_PCH_LPT_H(display) &&
intel_de_read(display, SFUSE_STRAP) & SFUSE_STRAP_CRT_DISABLED) returnfalse;
/* DDI E can't be used if DDI A requires 4 lanes */ if (intel_de_read(display, DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES) returnfalse;
if (!display->vbt.int_crt_support) returnfalse;
returntrue;
}
bool assert_port_valid(struct intel_display *display, enum port port)
{ return !drm_WARN(display->drm, !(DISPLAY_RUNTIME_INFO(display)->port_mask & BIT(port)), "Platform does not support port %c\n", port_name(port));
}
if (display->platform.geminilake || display->platform.broxton)
vlv_dsi_init(display);
} elseif (HAS_PCH_SPLIT(display)) { int found;
/* * intel_edp_init_connector() depends on this completing first, * to prevent the registration of both eDP and LVDS and the * incorrect sharing of the PPS.
*/
intel_lvds_init(display);
intel_crt_init(display);
if (display->platform.valleyview && display->vbt.int_crt_support)
intel_crt_init(display);
/* * The DP_DETECTED bit is the latched state of the DDC * SDA pin at boot. However since eDP doesn't require DDC * (no way to plug in a DP->HDMI dongle) the DDC pins for * eDP ports may have been muxed to an alternate function. * Thus we can't rely on the DP_DETECTED bit alone to detect * eDP ports. Consult the VBT as well as DP_DETECTED to * detect eDP ports. * * Sadly the straps seem to be missing sometimes even for HDMI * ports (eg. on Voyo V3 - CHT x7-Z8700), so check both strap * and VBT for the presence of the port. Additionally we can't * trust the port type the VBT declares as we've seen at least * HDMI ports that the VBT claim are DP or eDP.
*/
has_edp = intel_dp_is_port_edp(display, PORT_B);
has_port = intel_bios_is_port_present(display, PORT_B); if (intel_de_read(display, VLV_DP_B) & DP_DETECTED || has_port)
has_edp &= g4x_dp_init(display, VLV_DP_B, PORT_B); if ((intel_de_read(display, VLV_HDMIB) & SDVO_DETECTED || has_port) && !has_edp)
g4x_hdmi_init(display, VLV_HDMIB, PORT_B);
if (display->platform.cherryview) { /* * eDP not supported on port D, * so no need to worry about it
*/
has_port = intel_bios_is_port_present(display, PORT_D); if (intel_de_read(display, CHV_DP_D) & DP_DETECTED || has_port)
g4x_dp_init(display, CHV_DP_D, PORT_D); if (intel_de_read(display, CHV_HDMID) & SDVO_DETECTED || has_port)
g4x_hdmi_init(display, CHV_HDMID, PORT_D);
}
enum drm_mode_status intel_mode_valid(struct drm_device *dev, conststruct drm_display_mode *mode)
{ struct intel_display *display = to_intel_display(dev); int hdisplay_max, htotal_max; int vdisplay_max, vtotal_max;
/* * Can't reject DBLSCAN here because Xorg ddxen can add piles * of DBLSCAN modes to the output's mode list when they detect * the scaling mode property on the connector. And they don't * ask the kernel to validate those modes in any way until * modeset time at which point the client gets a protocol error. * So in order to not upset those clients we silently ignore the * DBLSCAN flag on such connectors. For other connectors we will * reject modes with the DBLSCAN flag in encoder->compute_config(). * And we always reject DBLSCAN modes in connector->mode_valid() * as we never want such modes on the connector's mode list.
*/
if (mode->vscan > 1) return MODE_NO_VSCAN;
if (mode->flags & DRM_MODE_FLAG_HSKEW) return MODE_H_ILLEGAL;
if (mode->flags & (DRM_MODE_FLAG_CSYNC |
DRM_MODE_FLAG_NCSYNC |
DRM_MODE_FLAG_PCSYNC)) return MODE_HSYNC;
if (mode->flags & (DRM_MODE_FLAG_BCAST |
DRM_MODE_FLAG_PIXMUX |
DRM_MODE_FLAG_CLKDIV2)) return MODE_BAD;
/* * Reject clearly excessive dotclocks early to * avoid having to worry about huge integers later.
*/ if (mode->clock > max_dotclock(display)) return MODE_CLOCK_HIGH;
if (IS_ERR(crtc_state)) {
ret = PTR_ERR(crtc_state); goto out;
}
if (!crtc_state->hw.active)
crtc_state->inherited = false;
if (crtc_state->hw.active) { struct intel_encoder *encoder;
ret = drm_atomic_add_affected_planes(state, &crtc->base); if (ret) goto out;
/* * FIXME hack to force a LUT update to avoid the * plane update forcing the pipe gamma on without * having a proper LUT loaded. Remove once we * have readout for pipe gamma enable.
*/
crtc_state->uapi.color_mgmt_changed = true;
for_each_intel_encoder_mask(display->drm, encoder,
crtc_state->uapi.encoder_mask) { if (encoder->initial_fastset_check &&
!encoder->initial_fastset_check(encoder, crtc_state)) {
ret = drm_atomic_add_affected_connectors(state,
&crtc->base); if (ret) goto out;
}
}
}
}
/* * Apparently we need to have VGA mode enabled prior to changing * the P1/P2 dividers. Otherwise the DPLL will keep using the old * dividers, even though the register value does change.
*/
intel_de_write(display, DPLL(display, pipe),
dpll & ~DPLL_VGA_MODE_DIS);
intel_de_write(display, DPLL(display, pipe), dpll);
/* Wait for the clocks to stabilize. */
intel_de_posting_read(display, DPLL(display, pipe));
udelay(150);
/* The pixel multiplier can only be updated once the * DPLL is enabled and the clocks are stable. * * So write it again.
*/
intel_de_write(display, DPLL(display, pipe), dpll);
/* We do this three times for luck */ for (i = 0; i < 3 ; i++) {
intel_de_write(display, DPLL(display, pipe), dpll);
intel_de_posting_read(display, DPLL(display, pipe));
udelay(150); /* wait for warmup */
}
¤ 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.0.219Bemerkung:
(vorverarbeitet am 2026-04-25)
¤
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.