blob: f447150ff7bc03e4726613789678d47ece812e87 [file] [edit]
// SPDX-License-Identifier: MIT
/*
* Copyright © 2026 Intel Corporation
*
*/
#include <drm/drm_print.h>
#include "intel_de.h"
#include "intel_dip.h"
#include "intel_dip_regs.h"
#include "intel_display_types.h"
#include "intel_hdmi.h"
static int intel_dip_get_as_sdp_transmission_line(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
if (!HAS_EMP_AS_SDP_TL(display))
return 0;
/*
* EMP_AS_SDP_TL defines the T1 position as the default AS SDP
* Transmission Line, which corresponds to the start of the
* VSYNC pulse.
*
* Use the T1 position for now.
*/
return crtc_state->vrr.vsync_start;
}
u16 intel_dip_read_emp_as_sdp_tl(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u32 val;
if (!HAS_EMP_AS_SDP_TL(display))
return 0;
val = intel_de_read(display, EMP_AS_SDP_TL(display, cpu_transcoder));
return REG_FIELD_GET(EMP_AS_SDP_DB_TL_MASK, val);
}
void intel_dip_write_emp_as_sdp_tl(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
if (!HAS_EMP_AS_SDP_TL(display))
return;
intel_de_write(display,
EMP_AS_SDP_TL(display, cpu_transcoder),
EMP_AS_SDP_DB_TL(crtc_state->dip.emp_as_sdp_tl));
}
static int intel_dip_sdp_stagger_to_tl(struct intel_crtc_state *crtc_state,
int stagger)
{
return crtc_state->dip.cmn_sdp_tl + stagger;
}
static
void intel_dip_cmn_sdp_tl_compute_config_late(struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
bool as_sdp;
if (!HAS_COMMON_SDP_TL(display))
return;
as_sdp = crtc_state->infoframes.enable &
intel_hdmi_infoframe_enable(DP_SDP_ADAPTIVE_SYNC);
/*
* When AS SDP is enabled :
* - The common SDP Transmission Line matches the EMP SDP Transmission Line.
*
* When AS SDP is disabled:
* - Bspec mentions the positions as lines of delayed vblank.
* - Guardband = 1st line of delayed vblank
* - Common SDP Transmission line is set to 2nd line of delayed vblank.
*/
if (as_sdp)
crtc_state->dip.cmn_sdp_tl = crtc_state->dip.emp_as_sdp_tl;
else
crtc_state->dip.cmn_sdp_tl = crtc_state->vrr.guardband - 1;
if (drm_WARN_ON(display->drm,
crtc_state->dip.cmn_sdp_tl >=
crtc_state->vrr.guardband + crtc_state->set_context_latency))
return;
/*
* Currently we are programming the default stagger values, but these
* can be optimized if required, based on number of SDPs enabled.
*
* Default values of the Transmission lines for SDPs other than AS SDP:
* VSC : CMN SDP Transmission line
* GMP : CMN SDP Transmission line
* PPS : CMN SDP Transmission line + 1
* VSC_EXT: CMN SDP Transmission line + 2
*/
crtc_state->dip.vsc_sdp_tl = crtc_state->dip.cmn_sdp_tl;
crtc_state->dip.gmp_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, GMP_STAGGER_DEFAULT);
crtc_state->dip.pps_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, PPS_STAGGER_DEFAULT);
crtc_state->dip.vsc_ext_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, VSC_EXT_STAGGER_DEFAULT);
}
void intel_dip_sdp_tl_compute_config_late(struct intel_crtc_state *crtc_state)
{
crtc_state->dip.emp_as_sdp_tl = intel_dip_get_as_sdp_transmission_line(crtc_state);
intel_dip_cmn_sdp_tl_compute_config_late(crtc_state);
}
static
void intel_dip_cmn_sdp_transmission_line_get_config(struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u16 vsc_ext_stagger, pps_stagger, gmp_stagger;
u32 val;
if (!HAS_COMMON_SDP_TL(display))
return;
val = intel_de_read(display, CMN_SDP_TL(display, cpu_transcoder));
if (!(val & TRANSMISSION_LINE_ENABLE))
return;
crtc_state->dip.cmn_sdp_tl = REG_FIELD_GET(BASE_TRANSMISSION_LINE_MASK, val);
/* SDP VSC uses same transmission line as CMN base transmission line */
crtc_state->dip.vsc_sdp_tl = crtc_state->dip.cmn_sdp_tl;
val = intel_de_read(display, CMN_SDP_TL_STGR_CTL(display, cpu_transcoder));
vsc_ext_stagger = REG_FIELD_GET(VSC_EXT_STAGGER_MASK, val);
pps_stagger = REG_FIELD_GET(PPS_STAGGER_MASK, val);
gmp_stagger = REG_FIELD_GET(GMP_STAGGER_MASK, val);
crtc_state->dip.vsc_ext_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, vsc_ext_stagger);
crtc_state->dip.pps_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, pps_stagger);
crtc_state->dip.gmp_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, gmp_stagger);
}
void intel_dip_sdp_transmission_line_get_config(struct intel_crtc_state *crtc_state)
{
crtc_state->dip.emp_as_sdp_tl = intel_dip_read_emp_as_sdp_tl(crtc_state);
intel_dip_cmn_sdp_transmission_line_get_config(crtc_state);
}
static int intel_dip_sdp_tl_to_stagger(const struct intel_crtc_state *crtc_state,
u16 sdp_transmission_line)
{
return sdp_transmission_line - crtc_state->dip.cmn_sdp_tl;
}
void intel_dip_cmn_sdp_transmission_line_enable(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
int gmp_stagger;
int pps_stagger;
int vsc_ext_stagger;
if (!HAS_COMMON_SDP_TL(display))
return;
gmp_stagger = intel_dip_sdp_tl_to_stagger(crtc_state,
crtc_state->dip.gmp_sdp_tl);
pps_stagger = intel_dip_sdp_tl_to_stagger(crtc_state,
crtc_state->dip.pps_sdp_tl);
vsc_ext_stagger = intel_dip_sdp_tl_to_stagger(crtc_state,
crtc_state->dip.vsc_ext_sdp_tl);
if (drm_WARN_ON(display->drm, gmp_stagger < 0))
return;
if (drm_WARN_ON(display->drm, pps_stagger < 0))
return;
if (drm_WARN_ON(display->drm, vsc_ext_stagger < 0))
return;
intel_de_write(display, CMN_SDP_TL_STGR_CTL(display, cpu_transcoder),
GMP_STAGGER(gmp_stagger) |
PPS_STAGGER(pps_stagger) |
VSC_EXT_STAGGER(vsc_ext_stagger));
intel_de_write(display, CMN_SDP_TL(display, cpu_transcoder),
TRANSMISSION_LINE_ENABLE |
BASE_TRANSMISSION_LINE(crtc_state->dip.cmn_sdp_tl));
}
void intel_dip_cmn_sdp_transmission_line_disable(const struct intel_crtc_state *old_crtc_state)
{
struct intel_display *display = to_intel_display(old_crtc_state);
enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
if (!HAS_COMMON_SDP_TL(display))
return;
intel_de_write(display, CMN_SDP_TL(display, cpu_transcoder), 0);
}