From: Ville Syrjälä <ville.syrj...@linux.intel.com> The current PKG_C_LATENCY stuff looks busted in several ways: - doesn't account for multiple pipes from different commits correctly - WM_LINETIME is in units of 0.125usec, PKG_C_LATENCY wants units on 1 usec - weird VRR state stuff being checked - use of pointless RMW
Fix it all up. Note that it's still a bit unclear how all this works, especially how the added_wake_time ties into the flipq triggers in DMC, and how we need to sequence updates to PKG_C_LATENCY when enabling/disabling pipes/etc. We may also need to think what to about the WM1+ disabling and the related PSR chicken bits when we can use PKG_C_LATENCY for early wake... Signed-off-by: Ville Syrjälä <ville.syrj...@linux.intel.com> --- drivers/gpu/drm/i915/display/intel_display.c | 1 + .../gpu/drm/i915/display/intel_display_core.h | 6 ++ drivers/gpu/drm/i915/display/skl_watermark.c | 97 +++++++++++-------- 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index de8bf292897c..72407cfffb60 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7393,6 +7393,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) /* 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); diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 32cb0e59c81e..ad4d29e2af1b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -479,6 +479,12 @@ struct intel_display { u32 pipestat_irq_mask[I915_MAX_PIPES]; } irq; + struct { + /* protected by wm.wm_mutex */ + u16 linetime[I915_MAX_PIPES]; + bool disable[I915_MAX_PIPES]; + } pkgc; + struct { wait_queue_head_t waitqueue; diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index a71605e3a535..8184ec2611e2 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -2903,64 +2903,75 @@ static int skl_wm_add_affected_planes(struct intel_atomic_state *state, return 0; } -/* - * If Fixed Refresh Rate or For VRR case Vmin = Vmax = Flipline: - * Program DEEP PKG_C_LATENCY Pkg C with highest valid latency from - * watermark level1 and up and above. If watermark level 1 is - * invalid program it with all 1's. - * Program PKG_C_LATENCY Added Wake Time = DSB execution time - * If Variable Refresh Rate where Vmin != Vmax != Flipline: - * Program DEEP PKG_C_LATENCY Pkg C with all 1's. - * Program PKG_C_LATENCY Added Wake Time = 0 - */ +static int pkgc_max_linetime(struct intel_atomic_state *state) +{ + struct intel_display *display = to_intel_display(state); + const struct intel_crtc_state *crtc_state; + struct intel_crtc *crtc; + int i, max_linetime; + + /* + * Apparenty the hardware uses WM_LINETIME internally for + * this stuff, compute everything based on that. + */ + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { + display->pkgc.disable[crtc->pipe] = crtc_state->vrr.enable; + display->pkgc.linetime[crtc->pipe] = DIV_ROUND_UP(crtc_state->linetime, 8); + } + + max_linetime = 0; + for_each_intel_crtc(display->drm, crtc) { + if (display->pkgc.disable[crtc->pipe]) + return 0; + + max_linetime = max(display->pkgc.linetime[crtc->pipe], max_linetime); + } + + return max_linetime; +} + void intel_program_dpkgc_latency(struct intel_atomic_state *state) { struct intel_display *display = to_intel_display(state); - struct intel_crtc *crtc; - struct intel_crtc_state *new_crtc_state; - u32 latency = LNL_PKG_C_LATENCY_MASK; - u32 added_wake_time = 0; - u32 max_linetime = 0; - u32 clear, val; - bool fixed_refresh_rate = false; - int i; + int max_linetime, latency, added_wake_time = 0; if (DISPLAY_VER(display) < 20) return; - for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { - if (!new_crtc_state->vrr.enable || - (new_crtc_state->vrr.vmin == new_crtc_state->vrr.vmax && - new_crtc_state->vrr.vmin == new_crtc_state->vrr.flipline)) - fixed_refresh_rate = true; + mutex_lock(&display->wm.wm_mutex); - max_linetime = max(new_crtc_state->linetime, max_linetime); - } + latency = skl_watermark_max_latency(display, 1); - if (fixed_refresh_rate) { - latency = skl_watermark_max_latency(display, 1); + /* + * Wa_22020432604 + * "PKG_C_LATENCY Added Wake Time field is not working" + */ + if (latency && (DISPLAY_VER(display) == 20 || DISPLAY_VER(display) == 30)) { + latency += added_wake_time; + added_wake_time = 0; + } - /* Wa_22020432604 */ - if ((DISPLAY_VER(display) == 20 || DISPLAY_VER(display) == 30) && !latency) { - latency += added_wake_time; - added_wake_time = 0; - } + max_linetime = pkgc_max_linetime(state); - /* Wa_22020299601 */ - if ((latency && max_linetime) && - (DISPLAY_VER(display) == 20 || DISPLAY_VER(display) == 30)) { - latency = max_linetime * DIV_ROUND_UP(latency, max_linetime); - } else if (!latency) { - latency = LNL_PKG_C_LATENCY_MASK; - } + if (max_linetime == 0 || latency == 0) { + latency = REG_FIELD_GET(LNL_PKG_C_LATENCY_MASK, + LNL_PKG_C_LATENCY_MASK); + added_wake_time = 0; + } else { + /* + * Wa_22020299601 + * "Increase the latency programmed in PKG_C_LATENCY Pkg C Latency to be a + * multiple of the pipeline time from WM_LINETIME" + */ + latency = roundup(latency, max_linetime); } - clear = LNL_ADDED_WAKE_TIME_MASK | LNL_PKG_C_LATENCY_MASK; - val = REG_FIELD_PREP(LNL_PKG_C_LATENCY_MASK, latency) | - REG_FIELD_PREP(LNL_ADDED_WAKE_TIME_MASK, added_wake_time); + intel_de_write(display, LNL_PKG_C_LATENCY, + REG_FIELD_PREP(LNL_ADDED_WAKE_TIME_MASK, added_wake_time) | + REG_FIELD_PREP(LNL_PKG_C_LATENCY_MASK, latency)); - intel_de_rmw(display, LNL_PKG_C_LATENCY, clear, val); + mutex_unlock(&display->wm.wm_mutex); } static int -- 2.49.0