diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_psr.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_psr.c | 748 |
1 files changed, 499 insertions, 249 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 0b021acb330f..430ad4ef7146 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -26,6 +26,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_debugfs.h> +#include <drm/drm_vblank.h> #include "i915_drv.h" #include "i915_reg.h" @@ -36,7 +37,9 @@ #include "intel_ddi.h" #include "intel_de.h" #include "intel_display_irq.h" +#include "intel_display_rpm.h" #include "intel_display_types.h" +#include "intel_dmc.h" #include "intel_dp.h" #include "intel_dp_aux.h" #include "intel_frontbuffer.h" @@ -44,6 +47,8 @@ #include "intel_psr.h" #include "intel_psr_regs.h" #include "intel_snps_phy.h" +#include "intel_vblank.h" +#include "intel_vrr.h" #include "skl_universal_plane.h" /** @@ -154,7 +159,7 @@ * * Unfortunately CHICKEN_TRANS itself seems to be double buffered * and thus won't latch until the first vblank. So with DC states - * enabled the register effctively uses the reset value during DC5 + * enabled the register effectively uses the reset value during DC5 * exit+PSR exit sequence, and thus the bit does nothing until * latched by the vblank that it was trying to prevent from being * generated in the first place. So we should probably call this @@ -171,7 +176,7 @@ * CHICKEN_PIPESL_1[15]/HSW_UNMASK_VBL_TO_REGS_IN_SRD (hsw): * * On BDW without this bit is no vblanks whatsoever are - * generated after PSR exit. On HSW this has no apparant effect. + * generated after PSR exit. On HSW this has no apparent effect. * WaPsrDPRSUnmaskVBlankInSRD says to set this. * * The rest of the bits are more self-explanatory and/or @@ -185,7 +190,7 @@ * has_psr + has_panel_replay: Panel Replay * has_psr + has_panel_replay + has_sel_update: Panel Replay Selective Update * - * Description of some intel_psr varibles. enabled, panel_replay_enabled, + * Description of some intel_psr variables. enabled, panel_replay_enabled, * sel_update_enabled * * enabled (alone): PSR1 @@ -462,8 +467,8 @@ void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir) if (DISPLAY_VER(display) >= 9) { u32 val; - val = intel_de_rmw(dev_priv, - PSR_EVENT(dev_priv, cpu_transcoder), + val = intel_de_rmw(display, + PSR_EVENT(display, cpu_transcoder), 0, 0); psr_event_print(display, val, intel_dp->psr.sel_update_enabled); @@ -688,7 +693,6 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) static void hsw_psr_setup_aux(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); enum transcoder cpu_transcoder = intel_dp->psr.transcoder; u32 aux_clock_divider, aux_ctl; /* write DP_SET_POWER=D0 */ @@ -703,7 +707,7 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp) BUILD_BUG_ON(sizeof(aux_msg) > 20); for (i = 0; i < sizeof(aux_msg); i += 4) - intel_de_write(dev_priv, + intel_de_write(display, psr_aux_data_reg(display, cpu_transcoder, i >> 2), intel_dp_aux_pack(&aux_msg[i], sizeof(aux_msg) - i)); @@ -793,31 +797,10 @@ static void _psr_enable_sink(struct intel_dp *intel_dp, drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, val); } -static void intel_psr_enable_sink_alpm(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) -{ - u8 val; - - /* - * eDP Panel Replay uses always ALPM - * PSR2 uses ALPM but PSR1 doesn't - */ - if (!intel_dp_is_edp(intel_dp) || (!crtc_state->has_panel_replay && - !crtc_state->has_sel_update)) - return; - - val = DP_ALPM_ENABLE | DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE; - - if (crtc_state->has_panel_replay) - val |= DP_ALPM_MODE_AUX_LESS; - - drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, val); -} - -void intel_psr_enable_sink(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) +static void intel_psr_enable_sink(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { - intel_psr_enable_sink_alpm(intel_dp, crtc_state); + intel_alpm_enable_sink(intel_dp, crtc_state); crtc_state->has_panel_replay ? _panel_replay_enable_sink(intel_dp, crtc_state) : @@ -827,11 +810,17 @@ void intel_psr_enable_sink(struct intel_dp *intel_dp, drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); } +void intel_psr_panel_replay_enable_sink(struct intel_dp *intel_dp) +{ + if (CAN_PANEL_REPLAY(intel_dp)) + drm_dp_dpcd_writeb(&intel_dp->aux, PANEL_REPLAY_CONFIG, + DP_PANEL_REPLAY_ENABLE); +} + static u32 intel_psr1_get_tp_time(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); struct intel_connector *connector = intel_dp->attached_connector; - struct drm_i915_private *dev_priv = to_i915(display->drm); u32 val = 0; if (DISPLAY_VER(display) >= 11) @@ -865,7 +854,7 @@ static u32 intel_psr1_get_tp_time(struct intel_dp *intel_dp) * WA 0479: hsw,bdw * "Do not skip both TP1 and TP2/TP3" */ - if (DISPLAY_VER(dev_priv) < 9 && + if (DISPLAY_VER(display) < 9 && connector->panel.vbt.psr.tp1_wakeup_time_us == 0 && connector->panel.vbt.psr.tp2_tp3_wakeup_time_us == 0) val |= EDP_PSR_TP2_TP3_TIME_100us; @@ -898,10 +887,21 @@ static u8 psr_compute_idle_frames(struct intel_dp *intel_dp) return idle_frames; } +static bool is_dc5_dc6_blocked(struct intel_dp *intel_dp) +{ + struct intel_display *display = to_intel_display(intel_dp); + u32 current_dc_state = intel_display_power_get_current_dc_state(display); + struct drm_vblank_crtc *vblank = &display->drm->vblank[intel_dp->psr.pipe]; + + return (current_dc_state != DC_STATE_EN_UPTO_DC5 && + current_dc_state != DC_STATE_EN_UPTO_DC6) || + intel_dp->psr.active_non_psr_pipes || + READ_ONCE(vblank->enabled); +} + static void hsw_activate_psr1(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); enum transcoder cpu_transcoder = intel_dp->psr.transcoder; u32 max_sleep_time = 0x1f; u32 val = EDP_PSR_ENABLE; @@ -911,7 +911,7 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) if (DISPLAY_VER(display) < 20) val |= EDP_PSR_MAX_SLEEP_TIME(max_sleep_time); - if (IS_HASWELL(dev_priv)) + if (display->platform.haswell) val |= EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; if (intel_dp->psr.link_standby) @@ -927,6 +927,14 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) intel_de_rmw(display, psr_ctl_reg(display, cpu_transcoder), ~EDP_PSR_RESTORE_PSR_ACTIVE_CTX_MASK, val); + + /* Wa_16025596647 */ + if ((DISPLAY_VER(display) == 20 || + IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) && + is_dc5_dc6_blocked(intel_dp)) + intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank(display, + intel_dp->psr.pipe, + true); } static u32 intel_psr2_get_tp_time(struct intel_dp *intel_dp) @@ -1005,14 +1013,21 @@ static void dg2_activate_panel_replay(struct intel_dp *intel_dp) static void hsw_activate_psr2(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); enum transcoder cpu_transcoder = intel_dp->psr.transcoder; u32 val = EDP_PSR2_ENABLE; u32 psr_val = 0; + u8 idle_frames; - val |= EDP_PSR2_IDLE_FRAMES(psr_compute_idle_frames(intel_dp)); + /* Wa_16025596647 */ + if ((DISPLAY_VER(display) == 20 || + IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) && + is_dc5_dc6_blocked(intel_dp)) + idle_frames = 0; + else + idle_frames = psr_compute_idle_frames(intel_dp); + val |= EDP_PSR2_IDLE_FRAMES(idle_frames); - if (DISPLAY_VER(display) < 14 && !IS_ALDERLAKE_P(dev_priv)) + if (DISPLAY_VER(display) < 14 && !display->platform.alderlake_p) val |= EDP_SU_TRACK_ENABLE; if (DISPLAY_VER(display) >= 10 && DISPLAY_VER(display) < 13) @@ -1030,7 +1045,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) } /* Wa_22012278275:adl-p */ - if (IS_ALDERLAKE_P(dev_priv) && IS_DISPLAY_STEP(display, STEP_A0, STEP_E0)) { + if (display->platform.alderlake_p && IS_DISPLAY_STEP(display, STEP_A0, STEP_E0)) { static const u8 map[] = { 2, /* 5 lines */ 1, /* 6 lines */ @@ -1043,7 +1058,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) }; /* * Still using the default IO_BUFFER_WAKE and FAST_WAKE, see - * comments bellow for more information + * comments below for more information */ int tmp; @@ -1095,9 +1110,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) static bool transcoder_has_psr2(struct intel_display *display, enum transcoder cpu_transcoder) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - - if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(display) >= 14) + if (display->platform.alderlake_p || DISPLAY_VER(display) >= 14) return cpu_transcoder == TRANSCODER_A || cpu_transcoder == TRANSCODER_B; else if (DISPLAY_VER(display) >= 12) return cpu_transcoder == TRANSCODER_A; @@ -1175,10 +1188,9 @@ dc3co_is_pipe_port_compatible(struct intel_dp *intel_dp, struct intel_display *display = to_intel_display(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; - struct drm_i915_private *dev_priv = to_i915(display->drm); enum port port = dig_port->base.port; - if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(display) >= 14) + if (display->platform.alderlake_p || DISPLAY_VER(display) >= 14) return pipe <= PIPE_B && port <= PORT_B; else return pipe == PIPE_A && port == PORT_A; @@ -1189,7 +1201,6 @@ tgl_dc3co_exitline_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); const u32 crtc_vdisplay = crtc_state->uapi.adjusted_mode.crtc_vdisplay; struct i915_power_domains *power_domains = &display->power.domains; u32 exit_scanlines; @@ -1215,7 +1226,7 @@ tgl_dc3co_exitline_compute_config(struct intel_dp *intel_dp, return; /* Wa_16011303918:adl-p */ - if (IS_ALDERLAKE_P(dev_priv) && IS_DISPLAY_STEP(display, STEP_A0, STEP_B0)) + if (display->platform.alderlake_p && IS_DISPLAY_STEP(display, STEP_A0, STEP_B0)) return; /* @@ -1256,7 +1267,6 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; const int crtc_hdisplay = crtc_state->hw.adjusted_mode.crtc_hdisplay; const int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay; @@ -1278,7 +1288,7 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp, * For other platforms with SW tracking we can adjust the y coordinates * to match sink requirement if multiple of 4. */ - if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(display) >= 14) + if (display->platform.alderlake_p || DISPLAY_VER(display) >= 14) y_granularity = intel_dp->psr.su_y_granularity; else if (intel_dp->psr.su_y_granularity <= 2) y_granularity = 4; @@ -1404,7 +1414,6 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); int crtc_hdisplay = crtc_state->hw.adjusted_mode.crtc_hdisplay; int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay; int psr_max_h = 0, psr_max_v = 0, max_bpp = 0; @@ -1413,20 +1422,20 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return false; /* JSL and EHL only supports eDP 1.3 */ - if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) { + if (display->platform.jasperlake || display->platform.elkhartlake) { drm_dbg_kms(display->drm, "PSR2 not supported by phy\n"); return false; } /* Wa_16011181250 */ - if (IS_ROCKETLAKE(dev_priv) || IS_ALDERLAKE_S(dev_priv) || - IS_DG2(dev_priv)) { + if (display->platform.rocketlake || display->platform.alderlake_s || + display->platform.dg2) { drm_dbg_kms(display->drm, "PSR2 is defeatured for this platform\n"); return false; } - if (IS_ALDERLAKE_P(dev_priv) && IS_DISPLAY_STEP(display, STEP_A0, STEP_B0)) { + if (display->platform.alderlake_p && IS_DISPLAY_STEP(display, STEP_A0, STEP_B0)) { drm_dbg_kms(display->drm, "PSR2 not completely functional in this stepping\n"); return false; @@ -1445,7 +1454,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, * over PSR2. */ if (crtc_state->dsc.compression_enable && - (DISPLAY_VER(display) < 14 && !IS_ALDERLAKE_P(dev_priv))) { + (DISPLAY_VER(display) < 14 && !display->platform.alderlake_p)) { drm_dbg_kms(display->drm, "PSR2 cannot be enabled since DSC is enabled\n"); return false; @@ -1478,7 +1487,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, /* Wa_16011303918:adl-p */ if (crtc_state->vrr.enable && - IS_ALDERLAKE_P(dev_priv) && IS_DISPLAY_STEP(display, STEP_A0, STEP_B0)) { + display->platform.alderlake_p && IS_DISPLAY_STEP(display, STEP_A0, STEP_B0)) { drm_dbg_kms(display->drm, "PSR2 not enabled, not compatible with HW stepping + VRR\n"); return false; @@ -1596,6 +1605,12 @@ _panel_replay_compute_config(struct intel_dp *intel_dp, return false; } + if (crtc_state->crc_enabled) { + drm_dbg_kms(display->drm, + "Panel Replay not enabled because it would inhibit pipe CRC calculation\n"); + return false; + } + if (!intel_dp_is_edp(intel_dp)) return true; @@ -1626,12 +1641,6 @@ _panel_replay_compute_config(struct intel_dp *intel_dp, if (!alpm_config_valid(intel_dp, crtc_state, true)) return false; - if (crtc_state->crc_enabled) { - drm_dbg_kms(display->drm, - "Panel Replay not enabled because it would inhibit pipe CRC calculation\n"); - return false; - } - return true; } @@ -1650,6 +1659,9 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, { struct intel_display *display = to_intel_display(intel_dp); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->uapi.state); + struct intel_crtc *crtc; + u8 active_pipes = 0; if (!psr_global_enabled(intel_dp)) { drm_dbg_kms(display->drm, "PSR disabled by flag\n"); @@ -1703,6 +1715,24 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, drm_dbg_kms(display->drm, "PSR disabled to workaround PSR FSM hang issue\n"); } + + /* Rest is for Wa_16025596647 */ + if (DISPLAY_VER(display) != 20 && + !IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) + return; + + /* Not needed by Panel Replay */ + if (crtc_state->has_panel_replay) + return; + + /* We ignore possible secondary PSR/Panel Replay capable eDP */ + for_each_intel_crtc(display->drm, crtc) + active_pipes |= crtc->active ? BIT(crtc->pipe) : 0; + + active_pipes = intel_calc_active_pipes(state, active_pipes); + + crtc_state->active_non_psr_pipes = active_pipes & + ~BIT(to_intel_crtc(crtc_state->uapi.crtc)->pipe); } void intel_psr_get_config(struct intel_encoder *encoder, @@ -1819,7 +1849,6 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); enum transcoder cpu_transcoder = intel_dp->psr.transcoder; u32 mask = 0; @@ -1858,7 +1887,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, * As a workaround leave LPSP unmasked to prevent PSR entry * when external displays are active. */ - if (DISPLAY_VER(display) >= 8 || IS_HASWELL_ULT(dev_priv)) + if (DISPLAY_VER(display) >= 8 || display->platform.haswell_ult) mask |= EDP_PSR_DEBUG_MASK_LPSP; if (DISPLAY_VER(display) < 20) @@ -1872,7 +1901,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, mask |= EDP_PSR_DEBUG_MASK_DISP_REG_WRITE; /* allow PSR with sprite enabled */ - if (IS_HASWELL(dev_priv)) + if (display->platform.haswell) mask |= EDP_PSR_DEBUG_MASK_SPRITE_ENABLE; } @@ -1895,9 +1924,6 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, intel_dp->psr.psr2_sel_fetch_enabled ? IGNORE_PSR2_HW_TRACKING : 0); - if (intel_dp_is_edp(intel_dp)) - intel_alpm_configure(intel_dp, crtc_state); - /* * Wa_16013835468 * Wa_14015648006 @@ -1917,7 +1943,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, */ if (!intel_dp->psr.panel_replay_enabled && (IS_DISPLAY_VERx100_STEP(display, 1400, STEP_A0, STEP_B0) || - IS_ALDERLAKE_P(dev_priv))) + display->platform.alderlake_p)) intel_de_rmw(display, CHICKEN_TRANS(display, cpu_transcoder), 0, ADLP_1_BASED_X_GRANULARITY); @@ -1928,10 +1954,18 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, MTL_CLKGATE_DIS_TRANS(display, cpu_transcoder), 0, MTL_CLKGATE_DIS_TRANS_DMASC_GATING_DIS); - else if (IS_ALDERLAKE_P(dev_priv)) + else if (display->platform.alderlake_p) intel_de_rmw(display, CLKGATE_DIS_MISC, 0, CLKGATE_DIS_MISC_DMASC_GATING_DIS); } + + /* Wa_16025596647 */ + if ((DISPLAY_VER(display) == 20 || + IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) && + !intel_dp->psr.panel_replay_enabled) + intel_dmc_block_pkgc(display, intel_dp->psr.pipe, true); + + intel_alpm_configure(intel_dp, crtc_state); } static bool psr_interrupt_error_check(struct intel_dp *intel_dp) @@ -1987,29 +2021,38 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, intel_dp->psr.psr2_sel_fetch_cff_enabled = false; intel_dp->psr.req_psr2_sdp_prior_scanline = crtc_state->req_psr2_sdp_prior_scanline; + intel_dp->psr.active_non_psr_pipes = crtc_state->active_non_psr_pipes; if (!psr_interrupt_error_check(intel_dp)) return; - if (intel_dp->psr.panel_replay_enabled) { + if (intel_dp->psr.panel_replay_enabled) drm_dbg_kms(display->drm, "Enabling Panel Replay\n"); - } else { + else drm_dbg_kms(display->drm, "Enabling PSR%s\n", intel_dp->psr.sel_update_enabled ? "2" : "1"); - /* - * Panel replay has to be enabled before link training: doing it - * only for PSR here. - */ - intel_psr_enable_sink(intel_dp, crtc_state); - } + /* + * Enabling sink PSR/Panel Replay here only for PSR. Panel Replay enable + * bit is already written at this point. Sink ALPM is enabled here for + * PSR and Panel Replay. See + * intel_psr_panel_replay_enable_sink. Modifiers/options: + * - Selective Update + * - Region Early Transport + * - Selective Update Region Scanline Capture + * - VSC_SDP_CRC + * - HPD on different Errors + * - CRC verification + * are written for PSR and Panel Replay here. + */ + intel_psr_enable_sink(intel_dp, crtc_state); if (intel_dp_is_edp(intel_dp)) intel_snps_phy_update_psr_power_state(&dig_port->base, true); intel_psr_enable_source(intel_dp, crtc_state); intel_dp->psr.enabled = true; - intel_dp->psr.paused = false; + intel_dp->psr.pause_counter = 0; /* * Link_ok is sticky and set here on PSR enable. We can assume link @@ -2055,6 +2098,12 @@ static void intel_psr_exit(struct intel_dp *intel_dp) drm_WARN_ON(display->drm, !(val & EDP_PSR2_ENABLE)); } else { + if (DISPLAY_VER(display) == 20 || + IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) + intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank(display, + intel_dp->psr.pipe, + false); + val = intel_de_rmw(display, psr_ctl_reg(display, cpu_transcoder), EDP_PSR_ENABLE, 0); @@ -2089,7 +2138,6 @@ static void intel_psr_wait_exit_locked(struct intel_dp *intel_dp) static void intel_psr_disable_locked(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); enum transcoder cpu_transcoder = intel_dp->psr.transcoder; lockdep_assert_held(&intel_dp->psr.lock); @@ -2121,7 +2169,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) intel_de_rmw(display, MTL_CLKGATE_DIS_TRANS(display, cpu_transcoder), MTL_CLKGATE_DIS_TRANS_DMASC_GATING_DIS, 0); - else if (IS_ALDERLAKE_P(dev_priv)) + else if (display->platform.alderlake_p) intel_de_rmw(display, CLKGATE_DIS_MISC, CLKGATE_DIS_MISC_DMASC_GATING_DIS, 0); } @@ -2129,16 +2177,8 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) if (intel_dp_is_edp(intel_dp)) intel_snps_phy_update_psr_power_state(&dp_to_dig_port(intel_dp)->base, false); - /* Panel Replay on eDP is always using ALPM aux less. */ - if (intel_dp->psr.panel_replay_enabled && intel_dp_is_edp(intel_dp)) { - intel_de_rmw(display, ALPM_CTL(display, cpu_transcoder), - ALPM_CTL_ALPM_ENABLE | - ALPM_CTL_ALPM_AUX_LESS_ENABLE, 0); - - intel_de_rmw(display, - PORT_ALPM_CTL(cpu_transcoder), - PORT_ALPM_CTL_ALPM_AUX_LESS_ENABLE, 0); - } + if (intel_dp->psr.panel_replay_enabled && intel_dp_is_edp(intel_dp)) + intel_alpm_disable(intel_dp); /* Disable PSR on Sink */ if (!intel_dp->psr.panel_replay_enabled) { @@ -2149,12 +2189,19 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) DP_RECEIVER_ALPM_CONFIG, 0); } + /* Wa_16025596647 */ + if ((DISPLAY_VER(display) == 20 || + IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) && + !intel_dp->psr.panel_replay_enabled) + intel_dmc_block_pkgc(display, intel_dp->psr.pipe, false); + intel_dp->psr.enabled = false; intel_dp->psr.panel_replay_enabled = false; intel_dp->psr.sel_update_enabled = false; intel_dp->psr.psr2_sel_fetch_enabled = false; intel_dp->psr.su_region_et_enabled = false; intel_dp->psr.psr2_sel_fetch_cff_enabled = false; + intel_dp->psr.active_non_psr_pipes = 0; } /** @@ -2172,7 +2219,8 @@ void intel_psr_disable(struct intel_dp *intel_dp, if (!old_crtc_state->has_psr) return; - if (drm_WARN_ON(display->drm, !CAN_PSR(intel_dp))) + if (drm_WARN_ON(display->drm, !CAN_PSR(intel_dp) && + !CAN_PANEL_REPLAY(intel_dp))) return; mutex_lock(&intel_dp->psr.lock); @@ -2194,7 +2242,6 @@ void intel_psr_disable(struct intel_dp *intel_dp, */ void intel_psr_pause(struct intel_dp *intel_dp) { - struct intel_display *display = to_intel_display(intel_dp); struct intel_psr *psr = &intel_dp->psr; if (!CAN_PSR(intel_dp) && !CAN_PANEL_REPLAY(intel_dp)) @@ -2207,12 +2254,10 @@ void intel_psr_pause(struct intel_dp *intel_dp) return; } - /* If we ever hit this, we will need to add refcount to pause/resume */ - drm_WARN_ON(display->drm, psr->paused); - - intel_psr_exit(intel_dp); - intel_psr_wait_exit_locked(intel_dp); - psr->paused = true; + if (intel_dp->psr.pause_counter++ == 0) { + intel_psr_exit(intel_dp); + intel_psr_wait_exit_locked(intel_dp); + } mutex_unlock(&psr->lock); @@ -2228,6 +2273,7 @@ void intel_psr_pause(struct intel_dp *intel_dp) */ void intel_psr_resume(struct intel_dp *intel_dp) { + struct intel_display *display = to_intel_display(intel_dp); struct intel_psr *psr = &intel_dp->psr; if (!CAN_PSR(intel_dp) && !CAN_PANEL_REPLAY(intel_dp)) @@ -2235,28 +2281,36 @@ void intel_psr_resume(struct intel_dp *intel_dp) mutex_lock(&psr->lock); - if (!psr->paused) - goto unlock; + if (!psr->enabled) + goto out; - psr->paused = false; - intel_psr_activate(intel_dp); + if (!psr->pause_counter) { + drm_warn(display->drm, "Unbalanced PSR pause/resume!\n"); + goto out; + } -unlock: + if (--intel_dp->psr.pause_counter == 0) + intel_psr_activate(intel_dp); + +out: mutex_unlock(&psr->lock); } /** - * intel_psr_needs_block_dc_vblank - Check if block dc entry is needed + * intel_psr_needs_vblank_notification - Check if PSR need vblank enable/disable + * notification. * @crtc_state: CRTC status * * We need to block DC6 entry in case of Panel Replay as enabling VBI doesn't * prevent it in case of Panel Replay. Panel Replay switches main link off on * DC entry. This means vblank interrupts are not fired and is a problem if - * user-space is polling for vblank events. + * user-space is polling for vblank events. Also Wa_16025596647 needs + * information when vblank is enabled/disabled. */ -bool intel_psr_needs_block_dc_vblank(const struct intel_crtc_state *crtc_state) +bool intel_psr_needs_vblank_notification(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct intel_display *display = to_intel_display(crtc_state); struct intel_encoder *encoder; for_each_encoder_on_crtc(crtc->base.dev, &crtc->base, encoder) { @@ -2267,61 +2321,119 @@ bool intel_psr_needs_block_dc_vblank(const struct intel_crtc_state *crtc_state) intel_dp = enc_to_intel_dp(encoder); - if (intel_dp_is_edp(intel_dp) && - CAN_PANEL_REPLAY(intel_dp)) + if (!intel_dp_is_edp(intel_dp)) + continue; + + if (CAN_PANEL_REPLAY(intel_dp)) + return true; + + if ((DISPLAY_VER(display) == 20 || + IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) && + CAN_PSR(intel_dp)) return true; } return false; } -static u32 man_trk_ctl_enable_bit_get(struct intel_display *display) +/** + * intel_psr_trigger_frame_change_event - Trigger "Frame Change" event + * @dsb: DSB context + * @state: the atomic state + * @crtc: the CRTC + * + * Generate PSR "Frame Change" event. + */ +void intel_psr_trigger_frame_change_event(struct intel_dsb *dsb, + struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(display->drm); + const struct intel_crtc_state *crtc_state = + intel_pre_commit_crtc_state(state, crtc); + struct intel_display *display = to_intel_display(crtc); - return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(display) >= 14 ? 0 : + if (crtc_state->has_psr) + intel_de_write_dsb(display, dsb, + CURSURFLIVE(display, crtc->pipe), 0); +} + +/** + * intel_psr_min_vblank_delay - Minimum vblank delay needed by PSR + * @crtc_state: the crtc state + * + * Return minimum vblank delay needed by PSR. + */ +int intel_psr_min_vblank_delay(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + if (!crtc_state->has_psr) + return 0; + + /* Wa_14015401596 */ + if (intel_vrr_possible(crtc_state) && IS_DISPLAY_VER(display, 13, 14)) + return 1; + + /* Rest is for SRD_STATUS needed on LunarLake and onwards */ + if (DISPLAY_VER(display) < 20) + return 0; + + /* + * Comment on SRD_STATUS register in Bspec for LunarLake and onwards: + * + * To deterministically capture the transition of the state machine + * going from SRDOFFACK to IDLE, the delayed V. Blank should be at least + * one line after the non-delayed V. Blank. + * + * Legacy TG: TRANS_SET_CONTEXT_LATENCY > 0 + * VRR TG: TRANS_VRR_CTL[ VRR Guardband ] < (TRANS_VRR_VMAX[ VRR Vmax ] + * - TRANS_VTOTAL[ Vertical Active ]) + * + * SRD_STATUS is used only by PSR1 on PantherLake. + * SRD_STATUS is used by PSR1 and Panel Replay DP on LunarLake. + */ + + if (DISPLAY_VER(display) >= 30 && (crtc_state->has_panel_replay || + crtc_state->has_sel_update)) + return 0; + else if (DISPLAY_VER(display) < 30 && (crtc_state->has_sel_update || + intel_crtc_has_type(crtc_state, + INTEL_OUTPUT_EDP))) + return 0; + else + return 1; +} + +static u32 man_trk_ctl_enable_bit_get(struct intel_display *display) +{ + return display->platform.alderlake_p || DISPLAY_VER(display) >= 14 ? 0 : PSR2_MAN_TRK_CTL_ENABLE; } static u32 man_trk_ctl_single_full_frame_bit_get(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - - return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(display) >= 14 ? + return display->platform.alderlake_p || DISPLAY_VER(display) >= 14 ? ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME : PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME; } static u32 man_trk_ctl_partial_frame_bit_get(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - - return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(display) >= 14 ? + return display->platform.alderlake_p || DISPLAY_VER(display) >= 14 ? ADLP_PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE : PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE; } static u32 man_trk_ctl_continuos_full_frame(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - - return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(display) >= 14 ? + return display->platform.alderlake_p || DISPLAY_VER(display) >= 14 ? ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME : PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME; } -static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp) +static void intel_psr_force_update(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - enum transcoder cpu_transcoder = intel_dp->psr.transcoder; - - if (intel_dp->psr.psr2_sel_fetch_enabled) - intel_de_write(display, - PSR2_MAN_TRK_CTL(display, cpu_transcoder), - man_trk_ctl_enable_bit_get(display) | - man_trk_ctl_partial_frame_bit_get(display) | - man_trk_ctl_single_full_frame_bit_get(display) | - man_trk_ctl_continuos_full_frame(display)); /* * Display WA #0884: skl+ @@ -2339,7 +2451,8 @@ static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp) intel_de_write(display, CURSURFLIVE(display, intel_dp->psr.pipe), 0); } -void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state) +void intel_psr2_program_trans_man_trk_ctl(struct intel_dsb *dsb, + const struct 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); @@ -2353,35 +2466,35 @@ void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_st crtc_state->uapi.encoder_mask) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - lockdep_assert_held(&intel_dp->psr.lock); - if (intel_dp->psr.psr2_sel_fetch_cff_enabled) + if (!dsb) + lockdep_assert_held(&intel_dp->psr.lock); + + if (DISPLAY_VER(display) < 20 && intel_dp->psr.psr2_sel_fetch_cff_enabled) return; break; } - intel_de_write(display, PSR2_MAN_TRK_CTL(display, cpu_transcoder), - crtc_state->psr2_man_track_ctl); + intel_de_write_dsb(display, dsb, + PSR2_MAN_TRK_CTL(display, cpu_transcoder), + crtc_state->psr2_man_track_ctl); if (!crtc_state->enable_psr2_su_region_et) return; - intel_de_write(display, PIPE_SRCSZ_ERLY_TPT(crtc->pipe), - crtc_state->pipe_srcsz_early_tpt); + intel_de_write_dsb(display, dsb, PIPE_SRCSZ_ERLY_TPT(crtc->pipe), + crtc_state->pipe_srcsz_early_tpt); } static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, bool full_update) { struct intel_display *display = to_intel_display(crtc_state); - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 val = man_trk_ctl_enable_bit_get(display); /* SF partial frame enable has to be set even on full update */ val |= man_trk_ctl_partial_frame_bit_get(display); if (full_update) { - val |= man_trk_ctl_single_full_frame_bit_get(display); val |= man_trk_ctl_continuos_full_frame(display); goto exit; } @@ -2389,7 +2502,7 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, if (crtc_state->psr2_su_area.y1 == -1) goto exit; - if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(display) >= 14) { + if (display->platform.alderlake_p || DISPLAY_VER(display) >= 14) { val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(crtc_state->psr2_su_area.y1); val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(crtc_state->psr2_su_area.y2 - 1); } else { @@ -2443,13 +2556,12 @@ static void clip_area_update(struct drm_rect *overlap_damage_area, static void intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; u16 y_alignment; /* ADLP aligns the SU region to vdsc slice height in case dsc is enabled */ if (crtc_state->dsc.compression_enable && - (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(display) >= 14)) + (display->platform.alderlake_p || DISPLAY_VER(display) >= 14)) y_alignment = vdsc_cfg->slice_height; else y_alignment = crtc_state->su_y_granularity; @@ -2570,12 +2682,11 @@ static void intel_psr_apply_su_area_workarounds(struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); /* Wa_14014971492 */ if (!crtc_state->has_panel_replay && ((IS_DISPLAY_VERx100_STEP(display, 1400, STEP_A0, STEP_B0) || - IS_ALDERLAKE_P(i915) || IS_TIGERLAKE(i915))) && + display->platform.alderlake_p || display->platform.tigerlake)) && crtc_state->splitter.enable) crtc_state->psr2_su_area.y1 = 0; @@ -2776,7 +2887,6 @@ void intel_psr_pre_plane_update(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct intel_display *display = to_intel_display(state); - struct drm_i915_private *i915 = to_i915(state->base.dev); const struct intel_crtc_state *old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc); const struct intel_crtc_state *new_crtc_state = @@ -2790,32 +2900,30 @@ void intel_psr_pre_plane_update(struct intel_atomic_state *state, old_crtc_state->uapi.encoder_mask) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_psr *psr = &intel_dp->psr; - bool needs_to_disable = false; mutex_lock(&psr->lock); - /* - * Reasons to disable: - * - PSR disabled in new state - * - All planes will go inactive - * - Changing between PSR versions - * - Region Early Transport changing - * - Display WA #1136: skl, bxt - */ - needs_to_disable |= intel_crtc_needs_modeset(new_crtc_state); - needs_to_disable |= !new_crtc_state->has_psr; - needs_to_disable |= !new_crtc_state->active_planes; - needs_to_disable |= new_crtc_state->has_sel_update != psr->sel_update_enabled; - needs_to_disable |= new_crtc_state->enable_psr2_su_region_et != - psr->su_region_et_enabled; - needs_to_disable |= DISPLAY_VER(i915) < 11 && - new_crtc_state->wm_level_disabled; - - if (psr->enabled && needs_to_disable) - intel_psr_disable_locked(intel_dp); - else if (psr->enabled && new_crtc_state->wm_level_disabled) - /* Wa_14015648006 */ - wm_optimization_wa(intel_dp, new_crtc_state); + if (psr->enabled) { + /* + * Reasons to disable: + * - PSR disabled in new state + * - All planes will go inactive + * - Changing between PSR versions + * - Region Early Transport changing + * - Display WA #1136: skl, bxt + */ + if (intel_crtc_needs_modeset(new_crtc_state) || + !new_crtc_state->has_psr || + !new_crtc_state->active_planes || + new_crtc_state->has_sel_update != psr->sel_update_enabled || + new_crtc_state->enable_psr2_su_region_et != psr->su_region_et_enabled || + new_crtc_state->has_panel_replay != psr->panel_replay_enabled || + (DISPLAY_VER(display) < 11 && new_crtc_state->wm_level_disabled)) + intel_psr_disable_locked(intel_dp); + else if (new_crtc_state->wm_level_disabled) + /* Wa_14015648006 */ + wm_optimization_wa(intel_dp, new_crtc_state); + } mutex_unlock(&psr->lock); } @@ -2858,7 +2966,7 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state, /* Force a PSR exit when enabling CRC to avoid CRC timeouts */ if (crtc_state->crc_enabled && psr->enabled) - psr_force_hw_tracking_exit(intel_dp); + intel_psr_force_update(intel_dp); /* * Clear possible busy bits in case we have @@ -3120,31 +3228,35 @@ unlock: mutex_unlock(&intel_dp->psr.lock); } -static void _psr_invalidate_handle(struct intel_dp *intel_dp) +static void intel_psr_configure_full_frame_update(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); enum transcoder cpu_transcoder = intel_dp->psr.transcoder; - if (intel_dp->psr.psr2_sel_fetch_enabled) { - u32 val; - - if (intel_dp->psr.psr2_sel_fetch_cff_enabled) { - /* Send one update otherwise lag is observed in screen */ - intel_de_write(display, - CURSURFLIVE(display, intel_dp->psr.pipe), - 0); - return; - } + if (!intel_dp->psr.psr2_sel_fetch_enabled) + return; - val = man_trk_ctl_enable_bit_get(display) | - man_trk_ctl_partial_frame_bit_get(display) | - man_trk_ctl_continuos_full_frame(display); + if (DISPLAY_VER(display) >= 20) + intel_de_write(display, LNL_SFF_CTL(cpu_transcoder), + LNL_SFF_CTL_SF_SINGLE_FULL_FRAME); + else intel_de_write(display, PSR2_MAN_TRK_CTL(display, cpu_transcoder), - val); - intel_de_write(display, - CURSURFLIVE(display, intel_dp->psr.pipe), 0); - intel_dp->psr.psr2_sel_fetch_cff_enabled = true; + man_trk_ctl_enable_bit_get(display) | + man_trk_ctl_partial_frame_bit_get(display) | + man_trk_ctl_single_full_frame_bit_get(display) | + man_trk_ctl_continuos_full_frame(display)); +} + +static void _psr_invalidate_handle(struct intel_dp *intel_dp) +{ + if (intel_dp->psr.psr2_sel_fetch_enabled) { + if (!intel_dp->psr.psr2_sel_fetch_cff_enabled) { + intel_dp->psr.psr2_sel_fetch_cff_enabled = true; + intel_psr_configure_full_frame_update(intel_dp); + } + + intel_psr_force_update(intel_dp); } else { intel_psr_exit(intel_dp); } @@ -3225,44 +3337,31 @@ static void _psr_flush_handle(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); struct drm_i915_private *dev_priv = to_i915(display->drm); - enum transcoder cpu_transcoder = intel_dp->psr.transcoder; if (intel_dp->psr.psr2_sel_fetch_enabled) { if (intel_dp->psr.psr2_sel_fetch_cff_enabled) { /* can we turn CFF off? */ - if (intel_dp->psr.busy_frontbuffer_bits == 0) { - u32 val = man_trk_ctl_enable_bit_get(display) | - man_trk_ctl_partial_frame_bit_get(display) | - man_trk_ctl_single_full_frame_bit_get(display) | - man_trk_ctl_continuos_full_frame(display); - - /* - * Set psr2_sel_fetch_cff_enabled as false to allow selective - * updates. Still keep cff bit enabled as we don't have proper - * SU configuration in case update is sent for any reason after - * sff bit gets cleared by the HW on next vblank. - */ - intel_de_write(display, - PSR2_MAN_TRK_CTL(display, cpu_transcoder), - val); - intel_de_write(display, - CURSURFLIVE(display, intel_dp->psr.pipe), - 0); + if (intel_dp->psr.busy_frontbuffer_bits == 0) intel_dp->psr.psr2_sel_fetch_cff_enabled = false; - } - } else { - /* - * continuous full frame is disabled, only a single full - * frame is required - */ - psr_force_hw_tracking_exit(intel_dp); } - } else { - psr_force_hw_tracking_exit(intel_dp); - if (!intel_dp->psr.active && !intel_dp->psr.busy_frontbuffer_bits) - queue_work(dev_priv->unordered_wq, &intel_dp->psr.work); + /* + * Still keep cff bit enabled as we don't have proper SU + * configuration in case update is sent for any reason after + * sff bit gets cleared by the HW on next vblank. + * + * NOTE: Setting cff bit is not needed for LunarLake onwards as + * we have own register for SFF bit and we are not overwriting + * existing SU configuration + */ + intel_psr_configure_full_frame_update(intel_dp); } + + intel_psr_force_update(intel_dp); + + if (!intel_dp->psr.psr2_sel_fetch_enabled && !intel_dp->psr.active && + !intel_dp->psr.busy_frontbuffer_bits) + queue_work(dev_priv->unordered_wq, &intel_dp->psr.work); } /** @@ -3302,7 +3401,7 @@ void intel_psr_flush(struct intel_display *display, * we have to ensure that the PSR is not activated until * intel_psr_resume() is called. */ - if (intel_dp->psr.paused) + if (intel_dp->psr.pause_counter) goto unlock; if (origin == ORIGIN_FLIP || @@ -3399,29 +3498,14 @@ static int psr_get_status_and_error_status(struct intel_dp *intel_dp, static void psr_alpm_check(struct intel_dp *intel_dp) { - struct intel_display *display = to_intel_display(intel_dp); - struct drm_dp_aux *aux = &intel_dp->aux; struct intel_psr *psr = &intel_dp->psr; - u8 val; - int r; if (!psr->sel_update_enabled) return; - r = drm_dp_dpcd_readb(aux, DP_RECEIVER_ALPM_STATUS, &val); - if (r != 1) { - drm_err(display->drm, "Error reading ALPM status\n"); - return; - } - - if (val & DP_ALPM_LOCK_TIMEOUT_ERROR) { + if (intel_alpm_get_error(intel_dp)) { intel_psr_disable_locked(intel_dp); psr->sink_not_reliable = true; - drm_dbg_kms(display->drm, - "ALPM lock timeout error, disabling PSR\n"); - - /* Clearing error */ - drm_dp_dpcd_writeb(aux, DP_RECEIVER_ALPM_STATUS, val); } } @@ -3606,6 +3690,168 @@ void intel_psr_unlock(const struct intel_crtc_state *crtc_state) } } +/* Wa_16025596647 */ +static void intel_psr_apply_underrun_on_idle_wa_locked(struct intel_dp *intel_dp) +{ + struct intel_display *display = to_intel_display(intel_dp); + bool dc5_dc6_blocked; + + if (!intel_dp->psr.active) + return; + + dc5_dc6_blocked = is_dc5_dc6_blocked(intel_dp); + + if (intel_dp->psr.sel_update_enabled) + psr2_program_idle_frames(intel_dp, dc5_dc6_blocked ? 0 : + psr_compute_idle_frames(intel_dp)); + else + intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank(display, + intel_dp->psr.pipe, + dc5_dc6_blocked); +} + +static void psr_dc5_dc6_wa_work(struct work_struct *work) +{ + struct intel_display *display = container_of(work, typeof(*display), + psr_dc5_dc6_wa_work); + struct intel_encoder *encoder; + + for_each_intel_encoder_with_psr(display->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + mutex_lock(&intel_dp->psr.lock); + + if (intel_dp->psr.enabled && !intel_dp->psr.panel_replay_enabled) + intel_psr_apply_underrun_on_idle_wa_locked(intel_dp); + + mutex_unlock(&intel_dp->psr.lock); + } +} + +/** + * intel_psr_notify_dc5_dc6 - Notify PSR about enable/disable dc5/dc6 + * @display: intel atomic state + * + * This is targeted for underrun on idle PSR HW bug (Wa_16025596647) to schedule + * psr_dc5_dc6_wa_work used for applying/removing the workaround. + */ +void intel_psr_notify_dc5_dc6(struct intel_display *display) +{ + if (DISPLAY_VER(display) != 20 && + !IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) + return; + + schedule_work(&display->psr_dc5_dc6_wa_work); +} + +/** + * intel_psr_dc5_dc6_wa_init - Init work for underrun on idle PSR HW bug wa + * @display: intel atomic state + * + * This is targeted for underrun on idle PSR HW bug (Wa_16025596647) to init + * psr_dc5_dc6_wa_work used for applying the workaround. + */ +void intel_psr_dc5_dc6_wa_init(struct intel_display *display) +{ + if (DISPLAY_VER(display) != 20 && + !IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) + return; + + INIT_WORK(&display->psr_dc5_dc6_wa_work, psr_dc5_dc6_wa_work); +} + +/** + * intel_psr_notify_pipe_change - Notify PSR about enable/disable of a pipe + * @state: intel atomic state + * @crtc: intel crtc + * @enable: enable/disable + * + * This is targeted for underrun on idle PSR HW bug (Wa_16025596647) to apply + * remove the workaround when pipe is getting enabled/disabled + */ +void intel_psr_notify_pipe_change(struct intel_atomic_state *state, + struct intel_crtc *crtc, bool enable) +{ + struct intel_display *display = to_intel_display(state); + struct intel_encoder *encoder; + + if (DISPLAY_VER(display) != 20 && + !IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) + return; + + for_each_intel_encoder_with_psr(display->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + u8 active_non_psr_pipes; + + mutex_lock(&intel_dp->psr.lock); + + if (!intel_dp->psr.enabled || intel_dp->psr.panel_replay_enabled) + goto unlock; + + active_non_psr_pipes = intel_dp->psr.active_non_psr_pipes; + + if (enable) + active_non_psr_pipes |= BIT(crtc->pipe); + else + active_non_psr_pipes &= ~BIT(crtc->pipe); + + if (active_non_psr_pipes == intel_dp->psr.active_non_psr_pipes) + goto unlock; + + if ((enable && intel_dp->psr.active_non_psr_pipes) || + (!enable && !intel_dp->psr.active_non_psr_pipes)) { + intel_dp->psr.active_non_psr_pipes = active_non_psr_pipes; + goto unlock; + } + + intel_dp->psr.active_non_psr_pipes = active_non_psr_pipes; + + intel_psr_apply_underrun_on_idle_wa_locked(intel_dp); +unlock: + mutex_unlock(&intel_dp->psr.lock); + } +} + +/** + * intel_psr_notify_vblank_enable_disable - Notify PSR about enable/disable of vblank + * @display: intel display struct + * @enable: enable/disable + * + * This is targeted for underrun on idle PSR HW bug (Wa_16025596647) to apply + * remove the workaround when vblank is getting enabled/disabled + */ +void intel_psr_notify_vblank_enable_disable(struct intel_display *display, + bool enable) +{ + struct intel_encoder *encoder; + + for_each_intel_encoder_with_psr(display->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + mutex_lock(&intel_dp->psr.lock); + if (intel_dp->psr.panel_replay_enabled) { + mutex_unlock(&intel_dp->psr.lock); + break; + } + + if (intel_dp->psr.enabled) + intel_psr_apply_underrun_on_idle_wa_locked(intel_dp); + + mutex_unlock(&intel_dp->psr.lock); + return; + } + + /* + * NOTE: intel_display_power_set_target_dc_state is used + * only by PSR * code for DC3CO handling. DC3CO target + * state is currently disabled in * PSR code. If DC3CO + * is taken into use we need take that into account here + * as well. + */ + intel_display_power_set_target_dc_state(display, enable ? DC_STATE_DISABLE : + DC_STATE_EN_UPTO_DC6); +} + static void psr_source_status(struct intel_dp *intel_dp, struct seq_file *m) { @@ -3614,8 +3860,8 @@ psr_source_status(struct intel_dp *intel_dp, struct seq_file *m) const char *status = "unknown"; u32 val, status_val; - if (intel_dp_is_edp(intel_dp) && (intel_dp->psr.sel_update_enabled || - intel_dp->psr.panel_replay_enabled)) { + if ((intel_dp_is_edp(intel_dp) || DISPLAY_VER(display) >= 30) && + (intel_dp->psr.sel_update_enabled || intel_dp->psr.panel_replay_enabled)) { static const char * const live_status[] = { "IDLE", "CAPTURE", @@ -3708,10 +3954,9 @@ static void intel_psr_print_mode(struct intel_dp *intel_dp, static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct drm_i915_private *dev_priv = to_i915(display->drm); enum transcoder cpu_transcoder = intel_dp->psr.transcoder; struct intel_psr *psr = &intel_dp->psr; - intel_wakeref_t wakeref; + struct ref_tracker *wakeref; bool enabled; u32 val, psr2_ctl; @@ -3720,7 +3965,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) if (!(psr->sink_support || psr->sink_panel_replay_support)) return 0; - wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); + wakeref = intel_display_rpm_get(display); mutex_lock(&psr->lock); intel_psr_print_mode(intel_dp, m); @@ -3802,7 +4047,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) unlock: mutex_unlock(&psr->lock); - intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); + intel_display_rpm_put(display, wakeref); return 0; } @@ -3833,9 +4078,7 @@ static int i915_edp_psr_debug_set(void *data, u64 val) { struct intel_display *display = data; - struct drm_i915_private *dev_priv = to_i915(display->drm); struct intel_encoder *encoder; - intel_wakeref_t wakeref; int ret = -ENODEV; if (!HAS_PSR(display)) @@ -3846,12 +4089,9 @@ i915_edp_psr_debug_set(void *data, u64 val) drm_dbg_kms(display->drm, "Setting PSR debug to %llx\n", val); - wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); - // TODO: split to each transcoder's PSR debug state - ret = intel_psr_debug_set(intel_dp, val); - - intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); + with_intel_display_rpm(display) + ret = intel_psr_debug_set(intel_dp, val); } return ret; @@ -3984,3 +4224,13 @@ void intel_psr_connector_debugfs_add(struct intel_connector *connector) debugfs_create_file("i915_psr_status", 0444, root, connector, &i915_psr_status_fops); } + +bool intel_psr_needs_alpm(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) +{ + /* + * eDP Panel Replay uses always ALPM + * PSR2 uses ALPM but PSR1 doesn't + */ + return intel_dp_is_edp(intel_dp) && (crtc_state->has_sel_update || + crtc_state->has_panel_replay); +} |