/* * From Gen 11, in case of dsi cmd mode, frame counter wouldn't * have updated at the beginning of TE, if we want to use * the hw counter, then we would find it updated in only * the next TE, hence switching to sw counter.
*/ if (crtc_state->mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 |
I915_MODE_FLAG_DSI_USE_TE1)) return 0;
/* * On i965gm the hardware frame counter reads * zero when the TV encoder is enabled :(
*/ if (display->platform.i965gm &&
(crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT))) return 0;
if (DISPLAY_VER(display) >= 5 || display->platform.g4x) return 0xffffffff; /* full 32 bit counter */ elseif (DISPLAY_VER(display) >= 3) return 0xffffff; /* only 24 bits of frame count */ else return 0; /* Gen2 doesn't have a hardware frame counter */
}
/* * Should really happen exactly when we enable the pipe * but we want the frame counters in the trace, and that * requires vblank support on some platforms/outputs.
*/
trace_intel_pipe_enable(crtc);
}
/* * Should really happen exactly when we disable the pipe * but we want the frame counters in the trace, and that * requires vblank support on some platforms/outputs.
*/
trace_intel_pipe_disable(crtc);
drm_vblank_work_init(&crtc_state->vblank_work, &crtc->base,
intel_crtc_vblank_work); /* * Interrupt latency is critical for getting the vblank * work executed as early as possible during the vblank.
*/
cpu_latency_qos_update_request(&crtc->vblank_pm_qos, 0);
}
/** * intel_pipe_update_start() - start update of a set of display registers * @state: the atomic state * @crtc: the crtc * * Mark the start of an update to pipe registers that should be updated * atomically regarding vblank. If the next vblank will happens within * the next 100 us, this function waits until the vblank passes. * * After a successful call to this function, interrupts will be disabled * until a subsequent call to intel_pipe_update_end(). That is done to * avoid random delays.
*/ void intel_pipe_update_start(struct intel_atomic_state *state, struct intel_crtc *crtc)
{ struct intel_display *display = to_intel_display(state); conststruct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc); struct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc); struct intel_vblank_evade_ctx evade; int scanline;
if (drm_WARN_ON(display->drm, drm_crtc_vblank_get(&crtc->base))) goto irq_disable;
/* * Wait for psr to idle out after enabling the VBL interrupts * VBL interrupts will start the PSR exit and prevent a PSR * re-entry as well.
*/
intel_psr_wait_for_idle_locked(new_crtc_state);
/** * intel_pipe_update_end() - end update of a set of display registers * @state: the atomic state * @crtc: the crtc * * Mark the end of an update started with intel_pipe_update_start(). This * re-enables interrupts and verifies the update was actually completed * before a vblank.
*/ void intel_pipe_update_end(struct intel_atomic_state *state, struct intel_crtc *crtc)
{ struct intel_display *display = to_intel_display(state); struct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc); enum pipe pipe = crtc->pipe; int scanline_end = intel_get_crtc_scanline(crtc);
u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
ktime_t end_vbl_time = ktime_get(); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
/* * Incase of mipi dsi command mode, we need to set frame update * request for every commit.
*/ if (DISPLAY_VER(display) >= 11 &&
intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI))
icl_dsi_frame_update(new_crtc_state);
/* We're still in the vblank-evade critical section, this can't race. * Would be slightly nice to just grab the vblank count and arm the * event outside of the critical section - the spinlock might spin for a
* while ... */ if (intel_crtc_needs_vblank_work(new_crtc_state)) {
drm_vblank_work_schedule(&new_crtc_state->vblank_work,
drm_crtc_accurate_vblank_count(&crtc->base) + 1, false);
} else {
intel_crtc_arm_vblank_event(new_crtc_state);
}
if (state->base.legacy_cursor_update) { struct intel_plane *plane; struct intel_plane_state *old_plane_state; int i;
/* Remove plane from atomic state, cleanup/free is done from vblank worker. */
memset(&state->base.planes[i], 0, sizeof(state->base.planes[i]));
}
}
}
/* * Send VRR Push to terminate Vblank. If we are already in vblank * this has to be done _after_ sampling the frame counter, as * otherwise the push would immediately terminate the vblank and * the sampled frame counter would correspond to the next frame * instead of the current frame. * * There is a tiny race here (iff vblank evasion failed us) where * we might sample the frame counter just before vmax vblank start * but the push would be sent just after it. That would cause the * push to affect the next frame instead of the current frame, * which would cause the next frame to terminate already at vmin * vblank start instead of vmax vblank start.
*/ if (!state->base.legacy_cursor_update)
intel_vrr_send_push(NULL, new_crtc_state);
local_irq_enable();
if (intel_vgpu_active(dev_priv)) goto out;
if (crtc->debug.start_vbl_count &&
crtc->debug.start_vbl_count != end_vbl_count) {
drm_err(display->drm, "Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n",
pipe_name(pipe), crtc->debug.start_vbl_count,
end_vbl_count,
ktime_us_delta(end_vbl_time,
crtc->debug.start_vbl_time),
crtc->debug.min_vbl, crtc->debug.max_vbl,
crtc->debug.scanline_start, scanline_end);
}
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.