linux/drivers/gpu/drm/i915/display/intel_vblank.c

// SPDX-License-Identifier: MIT
/*
 * Copyright © 2022-2023 Intel Corporation
 */

#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_color.h"
#include "intel_crtc.h"
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_vblank.h"
#include "intel_vrr.h"

/*
 * This timing diagram depicts the video signal in and
 * around the vertical blanking period.
 *
 * Assumptions about the fictitious mode used in this example:
 *  vblank_start >= 3
 *  vsync_start = vblank_start + 1
 *  vsync_end = vblank_start + 2
 *  vtotal = vblank_start + 3
 *
 *           start of vblank:
 *           latch double buffered registers
 *           increment frame counter (ctg+)
 *           generate start of vblank interrupt (gen4+)
 *           |
 *           |          frame start:
 *           |          generate frame start interrupt (aka. vblank interrupt) (gmch)
 *           |          may be shifted forward 1-3 extra lines via TRANSCONF
 *           |          |
 *           |          |  start of vsync:
 *           |          |  generate vsync interrupt
 *           |          |  |
 * ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx
 *       .   \hs/   .      \hs/          \hs/          \hs/   .      \hs/
 * ----va---> <-----------------vb--------------------> <--------va-------------
 *       |          |       <----vs----->                     |
 * -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2)
 * -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+)
 * -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi)
 *       |          |                                         |
 *       last visible pixel                                   first visible pixel
 *                  |                                         increment frame counter (gen3/4)
 *                  pixel counter = vblank_start * htotal     pixel counter = 0 (gen3/4)
 *
 * x  = horizontal active
 * _  = horizontal blanking
 * hs = horizontal sync
 * va = vertical active
 * vb = vertical blanking
 * vs = vertical sync
 * vbs = vblank_start (number)
 *
 * Summary:
 * - most events happen at the start of horizontal sync
 * - frame start happens at the start of horizontal blank, 1-4 lines
 *   (depending on TRANSCONF settings) after the start of vblank
 * - gen3/4 pixel and frame counter are synchronized with the start
 *   of horizontal active on the first line of vertical active
 */

/*
 * Called from drm generic code, passed a 'crtc', which we use as a pipe index.
 */
u32 i915_get_vblank_counter(struct drm_crtc *crtc)
{}

u32 g4x_get_vblank_counter(struct drm_crtc *crtc)
{}

static u32 intel_crtc_scanlines_since_frame_timestamp(struct intel_crtc *crtc)
{}

/*
 * On certain encoders on certain platforms, pipe
 * scanline register will not work to get the scanline,
 * since the timings are driven from the PORT or issues
 * with scanline register updates.
 * This function will use Framestamp and current
 * timestamp registers to calculate the scanline.
 */
static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
{}

int intel_crtc_scanline_offset(const struct intel_crtc_state *crtc_state)
{}

/*
 * intel_de_read_fw(), only for fast reads of display block, no need for
 * forcewake etc.
 */
static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
{}

/*
 * The uncore version of the spin lock functions is used to decide
 * whether we need to lock the uncore lock or not.  This is only
 * needed in i915, not in Xe.
 *
 * This lock in i915 is needed because some old platforms (at least
 * IVB and possibly HSW as well), which are not supported in Xe, need
 * all register accesses to the same cacheline to be serialized,
 * otherwise they may hang.
 */
#ifdef I915
static void intel_vblank_section_enter(struct intel_display *display)
	__acquires(i915->uncore.lock)
{}

static void intel_vblank_section_exit(struct intel_display *display)
	__releases(i915->uncore.lock)
{}
#else
static void intel_vblank_section_enter(struct intel_display *display)
{
}

static void intel_vblank_section_exit(struct intel_display *display)
{
}
#endif

static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc,
				     bool in_vblank_irq,
				     int *vpos, int *hpos,
				     ktime_t *stime, ktime_t *etime,
				     const struct drm_display_mode *mode)
{}

bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
				     ktime_t *vblank_time, bool in_vblank_irq)
{}

int intel_get_crtc_scanline(struct intel_crtc *crtc)
{}

static bool pipe_scanline_is_moving(struct intel_display *display,
				    enum pipe pipe)
{}

static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state)
{}

void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc)
{}

void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc)
{}

void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state,
				      bool vrr_enable)
{}

int intel_mode_vdisplay(const struct drm_display_mode *mode)
{}

int intel_mode_vblank_start(const struct drm_display_mode *mode)
{}

int intel_mode_vblank_end(const struct drm_display_mode *mode)
{}

int intel_mode_vtotal(const struct drm_display_mode *mode)
{}

void intel_vblank_evade_init(const struct intel_crtc_state *old_crtc_state,
			     const struct intel_crtc_state *new_crtc_state,
			     struct intel_vblank_evade_ctx *evade)
{}

/* must be called with vblank interrupt already enabled! */
int intel_vblank_evade(struct intel_vblank_evade_ctx *evade)
{}