mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
Merge tag 'drm-intel-next-2026-01-15' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-next
Beyond Display: - Make 'guc_hw_reg_state' static as it isn't exported (Ben) - Fix doc build on mei related interface header (Jani) Display related: - Fix ggtt fb alignment on Xe display (Tvrtko) - More display clean-up towards deduplication and full separation (Jani) - Use the consolidated HDMI tables (Suraj) - Account for DSC slice overhead (Ankit) - Prepare GVT for display modularization (Ankit, Jani) - Enable/Disable DC balance along with VRR DSB (Mitul, Ville) - Protection against unsupported modes in LT PHY (Suraj) - Display W/a addition and fixes (Gustavo) - Fix many SPDX identifier comments (Ankit) - Incorporate Xe3_LPD changes for CD2X divider (Gustavo) - Clean up link BW/DSC slice config computation (Imre) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patch.msgid.link/aWkNThVRSkGAfUVv@intel.com
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "i915_reg.h"
|
||||
#include "i9xx_wm.h"
|
||||
#include "i9xx_wm_regs.h"
|
||||
@@ -17,6 +16,7 @@
|
||||
#include "intel_display.h"
|
||||
#include "intel_display_regs.h"
|
||||
#include "intel_display_trace.h"
|
||||
#include "intel_display_utils.h"
|
||||
#include "intel_dram.h"
|
||||
#include "intel_fb.h"
|
||||
#include "intel_mchbar_regs.h"
|
||||
@@ -1863,8 +1863,7 @@ static void vlv_atomic_update_fifo(struct intel_atomic_state *state,
|
||||
struct intel_crtc *crtc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc);
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||
struct intel_uncore *uncore = &dev_priv->uncore;
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
const struct intel_crtc_state *crtc_state =
|
||||
intel_atomic_get_new_crtc_state(state, crtc);
|
||||
const struct vlv_fifo_state *fifo_state =
|
||||
@@ -2743,12 +2742,12 @@ static void ilk_compute_wm_level(struct intel_display *display,
|
||||
|
||||
static void hsw_read_wm_latency(struct intel_display *display, u16 wm[])
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u64 sskpd;
|
||||
|
||||
display->wm.num_levels = 5;
|
||||
|
||||
sskpd = intel_uncore_read64(&i915->uncore, MCH_SSKPD);
|
||||
sskpd = intel_uncore_read64(uncore, MCH_SSKPD);
|
||||
|
||||
wm[0] = REG_FIELD_GET64(SSKPD_NEW_WM0_MASK_HSW, sskpd);
|
||||
if (wm[0] == 0)
|
||||
@@ -2761,12 +2760,12 @@ static void hsw_read_wm_latency(struct intel_display *display, u16 wm[])
|
||||
|
||||
static void snb_read_wm_latency(struct intel_display *display, u16 wm[])
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u32 sskpd;
|
||||
|
||||
display->wm.num_levels = 4;
|
||||
|
||||
sskpd = intel_uncore_read(&i915->uncore, MCH_SSKPD);
|
||||
sskpd = intel_uncore_read(uncore, MCH_SSKPD);
|
||||
|
||||
wm[0] = REG_FIELD_GET(SSKPD_WM0_MASK_SNB, sskpd);
|
||||
wm[1] = REG_FIELD_GET(SSKPD_WM1_MASK_SNB, sskpd);
|
||||
@@ -2776,12 +2775,12 @@ static void snb_read_wm_latency(struct intel_display *display, u16 wm[])
|
||||
|
||||
static void ilk_read_wm_latency(struct intel_display *display, u16 wm[])
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u32 mltr;
|
||||
|
||||
display->wm.num_levels = 3;
|
||||
|
||||
mltr = intel_uncore_read(&i915->uncore, MLTR_ILK);
|
||||
mltr = intel_uncore_read(uncore, MLTR_ILK);
|
||||
|
||||
/* ILK primary LP0 latency is 700 ns */
|
||||
wm[0] = 7;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2024 Intel Corporation
|
||||
*/
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "i915_reg.h"
|
||||
#include "intel_bw.h"
|
||||
#include "intel_crtc.h"
|
||||
@@ -75,11 +74,11 @@ static int dg1_mchbar_read_qgv_point_info(struct intel_display *display,
|
||||
struct intel_qgv_point *sp,
|
||||
int point)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u32 dclk_ratio, dclk_reference;
|
||||
u32 val;
|
||||
|
||||
val = intel_uncore_read(&i915->uncore, SA_PERF_STATUS_0_0_0_MCHBAR_PC);
|
||||
val = intel_uncore_read(uncore, SA_PERF_STATUS_0_0_0_MCHBAR_PC);
|
||||
dclk_ratio = REG_FIELD_GET(DG1_QCLK_RATIO_MASK, val);
|
||||
if (val & DG1_QCLK_REFERENCE)
|
||||
dclk_reference = 6; /* 6 * 16.666 MHz = 100 MHz */
|
||||
@@ -87,18 +86,18 @@ static int dg1_mchbar_read_qgv_point_info(struct intel_display *display,
|
||||
dclk_reference = 8; /* 8 * 16.666 MHz = 133 MHz */
|
||||
sp->dclk = DIV_ROUND_UP((16667 * dclk_ratio * dclk_reference) + 500, 1000);
|
||||
|
||||
val = intel_uncore_read(&i915->uncore, SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU);
|
||||
val = intel_uncore_read(uncore, SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU);
|
||||
if (val & DG1_GEAR_TYPE)
|
||||
sp->dclk *= 2;
|
||||
|
||||
if (sp->dclk == 0)
|
||||
return -EINVAL;
|
||||
|
||||
val = intel_uncore_read(&i915->uncore, MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR);
|
||||
val = intel_uncore_read(uncore, MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR);
|
||||
sp->t_rp = REG_FIELD_GET(DG1_DRAM_T_RP_MASK, val);
|
||||
sp->t_rdpre = REG_FIELD_GET(DG1_DRAM_T_RDPRE_MASK, val);
|
||||
|
||||
val = intel_uncore_read(&i915->uncore, MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR_HIGH);
|
||||
val = intel_uncore_read(uncore, MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR_HIGH);
|
||||
sp->t_rcd = REG_FIELD_GET(DG1_DRAM_T_RCD_MASK, val);
|
||||
sp->t_ras = REG_FIELD_GET(DG1_DRAM_T_RAS_MASK, val);
|
||||
|
||||
@@ -212,14 +211,12 @@ static int icl_pcode_restrict_qgv_points(struct intel_display *display,
|
||||
static int mtl_read_qgv_point_info(struct intel_display *display,
|
||||
struct intel_qgv_point *sp, int point)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u32 val, val2;
|
||||
u16 dclk;
|
||||
|
||||
val = intel_uncore_read(&i915->uncore,
|
||||
MTL_MEM_SS_INFO_QGV_POINT_LOW(point));
|
||||
val2 = intel_uncore_read(&i915->uncore,
|
||||
MTL_MEM_SS_INFO_QGV_POINT_HIGH(point));
|
||||
val = intel_uncore_read(uncore, MTL_MEM_SS_INFO_QGV_POINT_LOW(point));
|
||||
val2 = intel_uncore_read(uncore, MTL_MEM_SS_INFO_QGV_POINT_HIGH(point));
|
||||
dclk = REG_FIELD_GET(MTL_DCLK_MASK, val);
|
||||
sp->dclk = DIV_ROUND_CLOSEST(16667 * dclk, 1000);
|
||||
sp->t_rp = REG_FIELD_GET(MTL_TRP_MASK, val);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "intel_display_regs.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_display_utils.h"
|
||||
#include "intel_display_wa.h"
|
||||
#include "intel_dram.h"
|
||||
#include "intel_mchbar_regs.h"
|
||||
#include "intel_pci_config.h"
|
||||
@@ -1858,6 +1859,20 @@ static void bxt_de_pll_enable(struct intel_display *display, int vco)
|
||||
|
||||
static void icl_cdclk_pll_disable(struct intel_display *display)
|
||||
{
|
||||
/*
|
||||
* Wa_13012396614:
|
||||
* Fixes: A sporadic race condition between MDCLK selection and PLL
|
||||
* enabling.
|
||||
* Workaround:
|
||||
* Change programming of MDCLK source selection in CDCLK_CTL:
|
||||
* - When disabling the CDCLK PLL, first set MDCLK source to be CD2XCLK.
|
||||
* - When enabling the CDCLK PLL, update MDCLK source selection only
|
||||
* after the PLL is enabled (which is already done as part of the
|
||||
* normal flow of _bxt_set_cdclk()).
|
||||
*/
|
||||
if (intel_display_wa(display, 13012396614))
|
||||
intel_de_rmw(display, CDCLK_CTL, MDCLK_SOURCE_SEL_MASK, MDCLK_SOURCE_SEL_CD2XCLK);
|
||||
|
||||
intel_de_rmw(display, BXT_DE_PLL_ENABLE,
|
||||
BXT_DE_PLL_PLL_ENABLE, 0);
|
||||
|
||||
@@ -1933,6 +1948,8 @@ static u32 bxt_cdclk_cd2x_pipe(struct intel_display *display, enum pipe pipe)
|
||||
static u32 bxt_cdclk_cd2x_div_sel(struct intel_display *display,
|
||||
int cdclk, int vco, u16 waveform)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
/* cdclk = vco / 2 / div{1,1.5,2,4} */
|
||||
switch (cdclk_divider(cdclk, vco, waveform)) {
|
||||
default:
|
||||
@@ -1941,14 +1958,27 @@ static u32 bxt_cdclk_cd2x_div_sel(struct intel_display *display,
|
||||
drm_WARN_ON(display->drm, vco != 0);
|
||||
fallthrough;
|
||||
case 2:
|
||||
return BXT_CDCLK_CD2X_DIV_SEL_1;
|
||||
ret = BXT_CDCLK_CD2X_DIV_SEL_1;
|
||||
break;
|
||||
case 3:
|
||||
return BXT_CDCLK_CD2X_DIV_SEL_1_5;
|
||||
ret = BXT_CDCLK_CD2X_DIV_SEL_1_5;
|
||||
break;
|
||||
case 4:
|
||||
return BXT_CDCLK_CD2X_DIV_SEL_2;
|
||||
ret = BXT_CDCLK_CD2X_DIV_SEL_2;
|
||||
break;
|
||||
case 8:
|
||||
return BXT_CDCLK_CD2X_DIV_SEL_4;
|
||||
ret = BXT_CDCLK_CD2X_DIV_SEL_4;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* On Xe3_LPD onward, the expectation is to always have
|
||||
* BXT_CDCLK_CD2X_DIV_SEL_1 as the default.
|
||||
*/
|
||||
if (DISPLAY_VER(display) >= 30)
|
||||
drm_WARN_ON(display->drm, ret != BXT_CDCLK_CD2X_DIV_SEL_1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u16 cdclk_squash_waveform(struct intel_display *display,
|
||||
@@ -2136,8 +2166,10 @@ static u32 bxt_cdclk_ctl(struct intel_display *display,
|
||||
|
||||
waveform = cdclk_squash_waveform(display, cdclk);
|
||||
|
||||
val = bxt_cdclk_cd2x_div_sel(display, cdclk, vco, waveform) |
|
||||
bxt_cdclk_cd2x_pipe(display, pipe);
|
||||
val = bxt_cdclk_cd2x_div_sel(display, cdclk, vco, waveform);
|
||||
|
||||
if (DISPLAY_VER(display) < 30)
|
||||
val |= bxt_cdclk_cd2x_pipe(display, pipe);
|
||||
|
||||
/*
|
||||
* Disable SSA Precharge when CD clock frequency < 500 MHz,
|
||||
@@ -2147,10 +2179,20 @@ static u32 bxt_cdclk_ctl(struct intel_display *display,
|
||||
cdclk >= 500000)
|
||||
val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
|
||||
|
||||
if (DISPLAY_VER(display) >= 20)
|
||||
val |= xe2lpd_mdclk_source_sel(display);
|
||||
else
|
||||
if (DISPLAY_VER(display) >= 20) {
|
||||
/*
|
||||
* Wa_13012396614 requires selecting CD2XCLK as MDCLK source
|
||||
* prior to disabling the PLL, which is already handled by
|
||||
* icl_cdclk_pll_disable(). Here we are just making sure
|
||||
* we keep the expected value.
|
||||
*/
|
||||
if (intel_display_wa(display, 13012396614) && vco == 0)
|
||||
val |= MDCLK_SOURCE_SEL_CD2XCLK;
|
||||
else
|
||||
val |= xe2lpd_mdclk_source_sel(display);
|
||||
} else {
|
||||
val |= skl_cdclk_decimal(cdclk);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "i915_utils.h" /* for i915_inject_probe_failure() */
|
||||
#include "intel_connector.h"
|
||||
#include "intel_display_core.h"
|
||||
#include "intel_display_debugfs.h"
|
||||
|
||||
@@ -303,6 +303,14 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config,
|
||||
drm_printf(&p, "vrr: vmin vblank: %d, vmax vblank: %d, vmin vtotal: %d, vmax vtotal: %d\n",
|
||||
intel_vrr_vmin_vblank_start(pipe_config), intel_vrr_vmax_vblank_start(pipe_config),
|
||||
intel_vrr_vmin_vtotal(pipe_config), intel_vrr_vmax_vtotal(pipe_config));
|
||||
drm_printf(&p, "vrr: dc balance: %s, vmin: %d vmax: %d guardband: %d, slope: %d max increase: %d max decrease: %d vblank target: %d\n",
|
||||
str_yes_no(pipe_config->vrr.dc_balance.enable),
|
||||
pipe_config->vrr.dc_balance.vmin, pipe_config->vrr.dc_balance.vmax,
|
||||
pipe_config->vrr.dc_balance.guardband,
|
||||
pipe_config->vrr.dc_balance.slope,
|
||||
pipe_config->vrr.dc_balance.max_increase,
|
||||
pipe_config->vrr.dc_balance.max_decrease,
|
||||
pipe_config->vrr.dc_balance.vblank_target);
|
||||
|
||||
drm_printf(&p, "requested mode: " DRM_MODE_FMT "\n",
|
||||
DRM_MODE_ARG(&pipe_config->hw.mode));
|
||||
|
||||
@@ -2671,15 +2671,18 @@ static int intel_c20pll_calc_state(const struct intel_crtc_state *crtc_state,
|
||||
hw_state->cx0pll.use_c10 = false;
|
||||
hw_state->cx0pll.lane_count = crtc_state->lane_count;
|
||||
|
||||
/* try computed C20 HDMI tables before using consolidated tables */
|
||||
if (!is_dp)
|
||||
/* TODO: Update SSC state for HDMI as well */
|
||||
err = intel_c20_compute_hdmi_tmds_pll(crtc_state, &hw_state->cx0pll.c20);
|
||||
|
||||
/*
|
||||
* Try the ideal C20 HDMI tables before computing them, since the calculated
|
||||
* values, although correct, may not be optimal.
|
||||
*/
|
||||
if (err)
|
||||
err = intel_c20pll_calc_state_from_table(crtc_state, encoder,
|
||||
&hw_state->cx0pll);
|
||||
|
||||
/* TODO: Update SSC state for HDMI as well */
|
||||
if (!is_dp && err)
|
||||
err = intel_c20_compute_hdmi_tmds_pll(crtc_state, &hw_state->cx0pll.c20);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
#include "g4x_hdmi.h"
|
||||
#include "hsw_ips.h"
|
||||
#include "i915_config.h"
|
||||
#include "i915_drv.h"
|
||||
#include "i915_reg.h"
|
||||
#include "i9xx_plane.h"
|
||||
#include "i9xx_plane_regs.h"
|
||||
@@ -100,6 +99,7 @@
|
||||
#include "intel_frontbuffer.h"
|
||||
#include "intel_hdmi.h"
|
||||
#include "intel_hotplug.h"
|
||||
#include "intel_initial_plane.h"
|
||||
#include "intel_link_bw.h"
|
||||
#include "intel_lt_phy.h"
|
||||
#include "intel_lvds.h"
|
||||
@@ -113,7 +113,6 @@
|
||||
#include "intel_pfit.h"
|
||||
#include "intel_pipe_crc.h"
|
||||
#include "intel_plane.h"
|
||||
#include "intel_plane_initial.h"
|
||||
#include "intel_pmdemand.h"
|
||||
#include "intel_pps.h"
|
||||
#include "intel_psr.h"
|
||||
@@ -639,7 +638,7 @@ void intel_plane_disable_noatomic(struct intel_crtc *crtc,
|
||||
if ((crtc_state->active_planes & ~BIT(PLANE_CURSOR)) == 0 &&
|
||||
hsw_ips_disable(crtc_state)) {
|
||||
crtc_state->ips_enabled = false;
|
||||
intel_plane_initial_vblank_wait(crtc);
|
||||
intel_initial_plane_vblank_wait(crtc);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -653,7 +652,7 @@ void intel_plane_disable_noatomic(struct intel_crtc *crtc,
|
||||
*/
|
||||
if (HAS_GMCH(display) &&
|
||||
intel_set_memory_cxsr(display, false))
|
||||
intel_plane_initial_vblank_wait(crtc);
|
||||
intel_initial_plane_vblank_wait(crtc);
|
||||
|
||||
/*
|
||||
* Gen2 reports pipe underruns whenever all planes are disabled.
|
||||
@@ -663,7 +662,7 @@ void intel_plane_disable_noatomic(struct intel_crtc *crtc,
|
||||
intel_set_cpu_fifo_underrun_reporting(display, crtc->pipe, false);
|
||||
|
||||
intel_plane_disable_arm(NULL, plane, crtc_state);
|
||||
intel_plane_initial_vblank_wait(crtc);
|
||||
intel_initial_plane_vblank_wait(crtc);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
@@ -1158,6 +1157,7 @@ static void intel_pre_plane_update(struct intel_atomic_state *state,
|
||||
|
||||
if (intel_crtc_vrr_disabling(state, crtc)) {
|
||||
intel_vrr_disable(old_crtc_state);
|
||||
intel_vrr_dcb_reset(old_crtc_state, crtc);
|
||||
intel_crtc_update_active_timings(old_crtc_state, false);
|
||||
}
|
||||
|
||||
@@ -5476,6 +5476,13 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
|
||||
PIPE_CONF_CHECK_LLI(cmrr.cmrr_m);
|
||||
PIPE_CONF_CHECK_LLI(cmrr.cmrr_n);
|
||||
PIPE_CONF_CHECK_BOOL(cmrr.enable);
|
||||
PIPE_CONF_CHECK_I(vrr.dc_balance.vmin);
|
||||
PIPE_CONF_CHECK_I(vrr.dc_balance.vmax);
|
||||
PIPE_CONF_CHECK_I(vrr.dc_balance.guardband);
|
||||
PIPE_CONF_CHECK_I(vrr.dc_balance.slope);
|
||||
PIPE_CONF_CHECK_I(vrr.dc_balance.max_increase);
|
||||
PIPE_CONF_CHECK_I(vrr.dc_balance.max_decrease);
|
||||
PIPE_CONF_CHECK_I(vrr.dc_balance.vblank_target);
|
||||
}
|
||||
|
||||
if (!fastset || intel_vrr_always_use_vrr_tg(display)) {
|
||||
@@ -6856,6 +6863,9 @@ static void intel_update_crtc(struct intel_atomic_state *state,
|
||||
intel_crtc_update_active_timings(new_crtc_state,
|
||||
new_crtc_state->vrr.enable);
|
||||
|
||||
if (new_crtc_state->vrr.dc_balance.enable)
|
||||
intel_vrr_dcb_increment_flip_count(new_crtc_state, crtc);
|
||||
|
||||
/*
|
||||
* We usually enable FIFO underrun interrupts as part of the
|
||||
* CRTC enable sequence during modesets. But when we inherit a
|
||||
@@ -7154,7 +7164,6 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
|
||||
|
||||
static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_state)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_state->base.dev);
|
||||
struct drm_plane *plane;
|
||||
struct drm_plane_state *new_plane_state;
|
||||
long ret;
|
||||
@@ -7163,7 +7172,7 @@ static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_stat
|
||||
for_each_new_plane_in_state(&intel_state->base, plane, new_plane_state, i) {
|
||||
if (new_plane_state->fence) {
|
||||
ret = dma_fence_wait_timeout(new_plane_state->fence, false,
|
||||
i915_fence_timeout(i915));
|
||||
i915_fence_timeout());
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
||||
@@ -7319,6 +7328,21 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state,
|
||||
if (new_crtc_state->use_flipq)
|
||||
intel_flipq_wait_dmc_halt(new_crtc_state->dsb_commit, crtc);
|
||||
|
||||
if (new_crtc_state->vrr.dc_balance.enable) {
|
||||
/*
|
||||
* Pause the DMC DC balancing for the remainder of
|
||||
* the commit so that vmin/vmax won't change after
|
||||
* we've baked them into the DSB vblank evasion
|
||||
* commands.
|
||||
*
|
||||
* FIXME maybe need a small delay here to make sure
|
||||
* DMC has finished updating the values? Or we need
|
||||
* a better DMC<->driver protocol that gives is real
|
||||
* guarantees about that...
|
||||
*/
|
||||
intel_pipedmc_dcb_disable(NULL, crtc);
|
||||
}
|
||||
|
||||
if (intel_crtc_needs_color_update(new_crtc_state))
|
||||
intel_color_commit_noarm(new_crtc_state->dsb_commit,
|
||||
new_crtc_state);
|
||||
@@ -7372,6 +7396,10 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state,
|
||||
intel_dsb_wait_for_delayed_vblank(state, new_crtc_state->dsb_commit);
|
||||
intel_vrr_check_push_sent(new_crtc_state->dsb_commit,
|
||||
new_crtc_state);
|
||||
|
||||
if (new_crtc_state->vrr.dc_balance.enable)
|
||||
intel_pipedmc_dcb_enable(new_crtc_state->dsb_commit, crtc);
|
||||
|
||||
intel_dsb_interrupt(new_crtc_state->dsb_commit);
|
||||
}
|
||||
|
||||
@@ -7381,7 +7409,7 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state,
|
||||
static void intel_atomic_commit_tail(struct intel_atomic_state *state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(state);
|
||||
struct drm_i915_private __maybe_unused *dev_priv = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
struct intel_crtc_state *new_crtc_state, *old_crtc_state;
|
||||
struct intel_crtc *crtc;
|
||||
struct intel_power_domain_mask put_domains[I915_MAX_PIPES] = {};
|
||||
@@ -7591,7 +7619,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
|
||||
* so enable debugging for the next modeset - and hope we catch
|
||||
* the culprit.
|
||||
*/
|
||||
intel_uncore_arm_unclaimed_mmio_detection(&dev_priv->uncore);
|
||||
intel_uncore_arm_unclaimed_mmio_detection(uncore);
|
||||
}
|
||||
/*
|
||||
* Delay re-enabling DC states by 17 ms to avoid the off->on->off
|
||||
|
||||
@@ -205,6 +205,7 @@ struct intel_display_platforms {
|
||||
#define HAS_ULTRAJOINER(__display) (((__display)->platform.dgfx && \
|
||||
DISPLAY_VER(__display) == 14) && HAS_DSC(__display))
|
||||
#define HAS_VRR(__display) (DISPLAY_VER(__display) >= 11)
|
||||
#define HAS_VRR_DC_BALANCE(__display) (DISPLAY_VER(__display) >= 30)
|
||||
#define INTEL_NUM_PIPES(__display) (hweight8(DISPLAY_RUNTIME_INFO(__display)->pipe_mask))
|
||||
#define OVERLAY_NEEDS_PHYSICAL(__display) (DISPLAY_INFO(__display)->overlay_needs_physical)
|
||||
#define SUPPORTS_TV(__display) (DISPLAY_INFO(__display)->supports_tv)
|
||||
@@ -260,6 +261,23 @@ struct intel_display_platforms {
|
||||
((id) == ARLS_HOST_BRIDGE_PCI_ID3) || \
|
||||
((id) == ARLS_HOST_BRIDGE_PCI_ID4))
|
||||
|
||||
#define INTEL_DISPLAY_DEVICE_PIPE_OFFSET(display, pipe) \
|
||||
(DISPLAY_INFO((display))->pipe_offsets[(pipe)] - \
|
||||
DISPLAY_INFO((display))->pipe_offsets[PIPE_A] + \
|
||||
DISPLAY_MMIO_BASE((display)))
|
||||
|
||||
#define INTEL_DISPLAY_DEVICE_TRANS_OFFSET(display, trans) \
|
||||
(DISPLAY_INFO((display))->trans_offsets[(trans)] - \
|
||||
DISPLAY_INFO((display))->trans_offsets[TRANSCODER_A] + \
|
||||
DISPLAY_MMIO_BASE((display)))
|
||||
|
||||
#define INTEL_DISPLAY_DEVICE_CURSOR_OFFSET(display, pipe) \
|
||||
(DISPLAY_INFO((display))->cursor_offsets[(pipe)] - \
|
||||
DISPLAY_INFO((display))->cursor_offsets[PIPE_A] + \
|
||||
DISPLAY_MMIO_BASE((display)))
|
||||
|
||||
#define DISPLAY_MMIO_BASE(display) (DISPLAY_INFO((display))->mmio_offset)
|
||||
|
||||
struct intel_display_runtime_info {
|
||||
struct intel_display_ip_ver {
|
||||
u16 ver;
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "i915_utils.h" /* for i915_inject_probe_failure() */
|
||||
#include "i9xx_wm.h"
|
||||
#include "intel_acpi.h"
|
||||
#include "intel_atomic.h"
|
||||
@@ -54,11 +52,11 @@
|
||||
#include "intel_hdcp.h"
|
||||
#include "intel_hotplug.h"
|
||||
#include "intel_hti.h"
|
||||
#include "intel_initial_plane.h"
|
||||
#include "intel_modeset_lock.h"
|
||||
#include "intel_modeset_setup.h"
|
||||
#include "intel_opregion.h"
|
||||
#include "intel_overlay.h"
|
||||
#include "intel_plane_initial.h"
|
||||
#include "intel_pmdemand.h"
|
||||
#include "intel_pps.h"
|
||||
#include "intel_psr.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "i915_reg.h"
|
||||
#include "intel_backlight_regs.h"
|
||||
#include "intel_cdclk.h"
|
||||
@@ -31,6 +30,7 @@
|
||||
#include "intel_pmdemand.h"
|
||||
#include "intel_pps_regs.h"
|
||||
#include "intel_snps_phy.h"
|
||||
#include "intel_step.h"
|
||||
#include "skl_watermark.h"
|
||||
#include "skl_watermark_regs.h"
|
||||
#include "vlv_sideband.h"
|
||||
@@ -1328,7 +1328,6 @@ static void hsw_disable_lcpll(struct intel_display *display,
|
||||
*/
|
||||
static void hsw_restore_lcpll(struct intel_display *display)
|
||||
{
|
||||
struct drm_i915_private __maybe_unused *dev_priv = to_i915(display->drm);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
#include "i915_reg_defs.h"
|
||||
|
||||
#define DISPLAY_MMIO_BASE(dev_priv) (DISPLAY_INFO(dev_priv)->mmio_offset)
|
||||
|
||||
#define VLV_DISPLAY_BASE 0x180000
|
||||
|
||||
/*
|
||||
@@ -36,14 +34,9 @@
|
||||
* Device info offset array based helpers for groups of registers with unevenly
|
||||
* spaced base offsets.
|
||||
*/
|
||||
#define _MMIO_PIPE2(display, pipe, reg) _MMIO(DISPLAY_INFO(display)->pipe_offsets[(pipe)] - \
|
||||
DISPLAY_INFO(display)->pipe_offsets[PIPE_A] + \
|
||||
DISPLAY_MMIO_BASE(display) + (reg))
|
||||
#define _MMIO_TRANS2(display, tran, reg) _MMIO(DISPLAY_INFO(display)->trans_offsets[(tran)] - \
|
||||
DISPLAY_INFO(display)->trans_offsets[TRANSCODER_A] + \
|
||||
DISPLAY_MMIO_BASE(display) + (reg))
|
||||
#define _MMIO_CURSOR2(display, pipe, reg) _MMIO(DISPLAY_INFO(display)->cursor_offsets[(pipe)] - \
|
||||
DISPLAY_INFO(display)->cursor_offsets[PIPE_A] + \
|
||||
DISPLAY_MMIO_BASE(display) + (reg))
|
||||
|
||||
#define _MMIO_PIPE2(display, pipe, reg) _MMIO(INTEL_DISPLAY_DEVICE_PIPE_OFFSET((display), (pipe)) + (reg))
|
||||
#define _MMIO_TRANS2(display, trans, reg) _MMIO(INTEL_DISPLAY_DEVICE_TRANS_OFFSET((display), (trans)) + (reg))
|
||||
#define _MMIO_CURSOR2(display, pipe, reg) _MMIO(INTEL_DISPLAY_DEVICE_CURSOR_OFFSET((display), (pipe)) + (reg))
|
||||
|
||||
#endif /* __INTEL_DISPLAY_REG_DEFS_H__ */
|
||||
|
||||
@@ -1385,6 +1385,13 @@ struct intel_crtc_state {
|
||||
u8 pipeline_full;
|
||||
u16 flipline, vmin, vmax, guardband;
|
||||
u32 vsync_end, vsync_start;
|
||||
struct {
|
||||
bool enable;
|
||||
u16 vmin, vmax;
|
||||
u16 guardband, slope;
|
||||
u16 max_increase, max_decrease;
|
||||
u16 vblank_target;
|
||||
} dc_balance;
|
||||
} vrr;
|
||||
|
||||
/* Content Match Refresh Rate state */
|
||||
@@ -1525,6 +1532,10 @@ struct intel_crtc {
|
||||
struct intel_link_m_n m_n, m2_n2;
|
||||
} drrs;
|
||||
|
||||
struct {
|
||||
u64 flip_count;
|
||||
} dc_balance;
|
||||
|
||||
int scanline_offset;
|
||||
|
||||
struct {
|
||||
|
||||
@@ -9,18 +9,14 @@
|
||||
|
||||
struct intel_display;
|
||||
|
||||
#ifndef MISSING_CASE
|
||||
#define MISSING_CASE(x) WARN(1, "Missing case (%s == %ld)\n", \
|
||||
__stringify(x), (long)(x))
|
||||
#endif
|
||||
|
||||
#ifndef fetch_and_zero
|
||||
#define fetch_and_zero(ptr) ({ \
|
||||
typeof(*ptr) __T = *(ptr); \
|
||||
*(ptr) = (typeof(*ptr))0; \
|
||||
__T; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#define KHz(x) (1000 * (x))
|
||||
#define MHz(x) KHz(1000 * (x))
|
||||
|
||||
@@ -62,18 +62,20 @@ static bool intel_display_needs_wa_16025573575(struct intel_display *display)
|
||||
bool __intel_display_wa(struct intel_display *display, enum intel_display_wa wa, const char *name)
|
||||
{
|
||||
switch (wa) {
|
||||
case INTEL_DISPLAY_WA_13012396614:
|
||||
return DISPLAY_VERx100(display) == 3000;
|
||||
case INTEL_DISPLAY_WA_14011503117:
|
||||
return DISPLAY_VER(display) == 13;
|
||||
case INTEL_DISPLAY_WA_14025769978:
|
||||
return DISPLAY_VER(display) == 35;
|
||||
case INTEL_DISPLAY_WA_15018326506:
|
||||
return display->platform.battlemage;
|
||||
case INTEL_DISPLAY_WA_16023588340:
|
||||
return intel_display_needs_wa_16023588340(display);
|
||||
case INTEL_DISPLAY_WA_16025573575:
|
||||
return intel_display_needs_wa_16025573575(display);
|
||||
case INTEL_DISPLAY_WA_14011503117:
|
||||
return DISPLAY_VER(display) == 13;
|
||||
case INTEL_DISPLAY_WA_22014263786:
|
||||
return IS_DISPLAY_VERx100(display, 1100, 1400);
|
||||
case INTEL_DISPLAY_WA_15018326506:
|
||||
return display->platform.battlemage;
|
||||
case INTEL_DISPLAY_WA_14025769978:
|
||||
return DISPLAY_VER(display) == 35;
|
||||
default:
|
||||
drm_WARN(display->drm, 1, "Missing Wa number: %s\n", name);
|
||||
break;
|
||||
|
||||
@@ -21,13 +21,19 @@ static inline bool intel_display_needs_wa_16023588340(struct intel_display *disp
|
||||
bool intel_display_needs_wa_16023588340(struct intel_display *display);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This enum lists display workarounds; each entry here must have a
|
||||
* corresponding case in __intel_display_wa(). Keep both sorted by lineage
|
||||
* number.
|
||||
*/
|
||||
enum intel_display_wa {
|
||||
INTEL_DISPLAY_WA_13012396614,
|
||||
INTEL_DISPLAY_WA_14011503117,
|
||||
INTEL_DISPLAY_WA_14025769978,
|
||||
INTEL_DISPLAY_WA_15018326506,
|
||||
INTEL_DISPLAY_WA_16023588340,
|
||||
INTEL_DISPLAY_WA_16025573575,
|
||||
INTEL_DISPLAY_WA_14011503117,
|
||||
INTEL_DISPLAY_WA_22014263786,
|
||||
INTEL_DISPLAY_WA_15018326506,
|
||||
INTEL_DISPLAY_WA_14025769978,
|
||||
};
|
||||
|
||||
bool __intel_display_wa(struct intel_display *display, enum intel_display_wa wa, const char *name);
|
||||
|
||||
@@ -859,6 +859,14 @@ static void dmc_configure_event(struct intel_display *display,
|
||||
dmc_id, num_handlers, event_id);
|
||||
}
|
||||
|
||||
void intel_dmc_configure_dc_balance_event(struct intel_display *display,
|
||||
enum pipe pipe, bool enable)
|
||||
{
|
||||
enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(pipe);
|
||||
|
||||
dmc_configure_event(display, dmc_id, PIPEDMC_EVENT_ADAPTIVE_DCB_TRIGGER, enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dmc_block_pkgc() - block PKG C-state
|
||||
* @display: display instance
|
||||
@@ -1755,3 +1763,20 @@ u32 intel_pipedmc_start_mmioaddr(struct intel_crtc *crtc)
|
||||
|
||||
return dmc ? dmc->dmc_info[dmc_id].start_mmioaddr : 0;
|
||||
}
|
||||
|
||||
void intel_pipedmc_dcb_enable(struct intel_dsb *dsb, struct intel_crtc *crtc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
|
||||
intel_de_write_dsb(display, dsb, PIPEDMC_DCB_CTL(pipe),
|
||||
PIPEDMC_ADAPTIVE_DCB_ENABLE);
|
||||
}
|
||||
|
||||
void intel_pipedmc_dcb_disable(struct intel_dsb *dsb, struct intel_crtc *crtc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
|
||||
intel_de_write_dsb(display, dsb, PIPEDMC_DCB_CTL(pipe), 0);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ struct intel_crtc;
|
||||
struct intel_crtc_state;
|
||||
struct intel_display;
|
||||
struct intel_dmc_snapshot;
|
||||
struct intel_dsb;
|
||||
|
||||
void intel_dmc_init(struct intel_display *display);
|
||||
void intel_dmc_load_program(struct intel_display *display);
|
||||
@@ -24,6 +25,8 @@ void intel_dmc_enable_pipe(const struct intel_crtc_state *crtc_state);
|
||||
void intel_dmc_disable_pipe(const struct intel_crtc_state *crtc_state);
|
||||
void intel_dmc_block_pkgc(struct intel_display *display, enum pipe pipe,
|
||||
bool block);
|
||||
void intel_dmc_configure_dc_balance_event(struct intel_display *display,
|
||||
enum pipe pipe, bool enable);
|
||||
void intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank(struct intel_display *display,
|
||||
enum pipe pipe, bool enable);
|
||||
void intel_dmc_fini(struct intel_display *display);
|
||||
@@ -39,6 +42,8 @@ void intel_dmc_update_dc6_allowed_count(struct intel_display *display, bool star
|
||||
void assert_main_dmc_loaded(struct intel_display *display);
|
||||
|
||||
void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe);
|
||||
void intel_pipedmc_dcb_enable(struct intel_dsb *dsb, struct intel_crtc *crtc);
|
||||
void intel_pipedmc_dcb_disable(struct intel_dsb *dsb, struct intel_crtc *crtc);
|
||||
|
||||
u32 intel_pipedmc_start_mmioaddr(struct intel_crtc *crtc);
|
||||
void intel_pipedmc_enable_event(struct intel_crtc *crtc,
|
||||
|
||||
@@ -584,4 +584,64 @@ enum pipedmc_event_id {
|
||||
#define PTL_PIPEDMC_EXEC_TIME_LINES(start_mmioaddr) _MMIO((start_mmioaddr) + 0x6b8)
|
||||
#define PTL_PIPEDMC_END_OF_EXEC_GB(start_mmioaddr) _MMIO((start_mmioaddr) + 0x6c0)
|
||||
|
||||
#define _PIPEDMC_DCB_CTL_A 0x5f1a0
|
||||
#define _PIPEDMC_DCB_CTL_B 0x5f5a0
|
||||
#define PIPEDMC_DCB_CTL(pipe) _MMIO_PIPE((pipe), _PIPEDMC_DCB_CTL_A,\
|
||||
_PIPEDMC_DCB_CTL_B)
|
||||
#define PIPEDMC_ADAPTIVE_DCB_ENABLE REG_BIT(31)
|
||||
|
||||
#define _PIPEDMC_DCB_VBLANK_A 0x5f1bc
|
||||
#define _PIPEDMC_DCB_VBLANK_B 0x5f5bc
|
||||
#define PIPEDMC_DCB_VBLANK(pipe) _MMIO_PIPE((pipe), _PIPEDMC_DCB_VBLANK_A,\
|
||||
_PIPEDMC_DCB_VBLANK_B)
|
||||
|
||||
#define _PIPEDMC_DCB_SLOPE_A 0x5f1b8
|
||||
#define _PIPEDMC_DCB_SLOPE_B 0x5f5b8
|
||||
#define PIPEDMC_DCB_SLOPE(pipe) _MMIO_PIPE((pipe), _PIPEDMC_DCB_SLOPE_A,\
|
||||
_PIPEDMC_DCB_SLOPE_B)
|
||||
|
||||
#define _PIPEDMC_DCB_GUARDBAND_A 0x5f1b4
|
||||
#define _PIPEDMC_DCB_GUARDBAND_B 0x5f5b4
|
||||
#define PIPEDMC_DCB_GUARDBAND(pipe) _MMIO_PIPE((pipe), _PIPEDMC_DCB_GUARDBAND_A,\
|
||||
_PIPEDMC_DCB_GUARDBAND_B)
|
||||
|
||||
#define _PIPEDMC_DCB_MAX_INCREASE_A 0x5f1ac
|
||||
#define _PIPEDMC_DCB_MAX_INCREASE_B 0x5f5ac
|
||||
#define PIPEDMC_DCB_MAX_INCREASE(pipe) _MMIO_PIPE((pipe), _PIPEDMC_DCB_MAX_INCREASE_A,\
|
||||
_PIPEDMC_DCB_MAX_INCREASE_B)
|
||||
|
||||
#define _PIPEDMC_DCB_MAX_DECREASE_A 0x5f1b0
|
||||
#define _PIPEDMC_DCB_MAX_DECREASE_B 0x5f5b0
|
||||
#define PIPEDMC_DCB_MAX_DECREASE(pipe) _MMIO_PIPE((pipe), _PIPEDMC_DCB_MAX_DECREASE_A,\
|
||||
_PIPEDMC_DCB_MAX_DECREASE_B)
|
||||
|
||||
#define _PIPEDMC_DCB_VMIN_A 0x5f1a4
|
||||
#define _PIPEDMC_DCB_VMIN_B 0x5f5a4
|
||||
#define PIPEDMC_DCB_VMIN(pipe) _MMIO_PIPE((pipe), _PIPEDMC_DCB_VMIN_A,\
|
||||
_PIPEDMC_DCB_VMIN_B)
|
||||
|
||||
#define _PIPEDMC_DCB_VMAX_A 0x5f1a8
|
||||
#define _PIPEDMC_DCB_VMAX_B 0x5f5a8
|
||||
#define PIPEDMC_DCB_VMAX(pipe) _MMIO_PIPE((pipe), _PIPEDMC_DCB_VMAX_A,\
|
||||
_PIPEDMC_DCB_VMAX_B)
|
||||
|
||||
#define _PIPEDMC_DCB_DEBUG_A 0x5f1c0
|
||||
#define _PIPEDMC_DCB_DEBUG_B 0x5f5c0
|
||||
#define PIPEDMC_DCB_DEBUG(pipe) _MMIO_PIPE(pipe, _PIPEDMC_DCB_DEBUG_A,\
|
||||
_PIPEDMC_DCB_DEBUG_B)
|
||||
|
||||
#define _PIPEDMC_EVT_CTL_3_A 0x5f040
|
||||
#define _PIPEDMC_EVT_CTL_3_B 0x5f440
|
||||
#define PIPEDMC_EVT_CTL_3(pipe) _MMIO_PIPE(pipe, _PIPEDMC_EVT_CTL_3_A,\
|
||||
_PIPEDMC_EVT_CTL_3_B)
|
||||
|
||||
#define _PIPEDMC_DCB_FLIP_COUNT_A 0x906a4
|
||||
#define _PIPEDMC_DCB_FLIP_COUNT_B 0x986a4
|
||||
#define PIPEDMC_DCB_FLIP_COUNT(pipe) _MMIO_PIPE(pipe, _PIPEDMC_DCB_FLIP_COUNT_A,\
|
||||
_PIPEDMC_DCB_FLIP_COUNT_B)
|
||||
|
||||
#define _PIPEDMC_DCB_BALANCE_RESET_A 0x906a8
|
||||
#define _PIPEDMC_DCB_BALANCE_RESET_B 0x986a8
|
||||
#define PIPEDMC_DCB_BALANCE_RESET(pipe) _MMIO_PIPE(pipe, _PIPEDMC_DCB_BALANCE_RESET_A,\
|
||||
_PIPEDMC_DCB_BALANCE_RESET_B)
|
||||
#endif /* __INTEL_DMC_REGS_H__ */
|
||||
|
||||
@@ -868,50 +868,32 @@ small_joiner_ram_size_bits(struct intel_display *display)
|
||||
return 6144 * 8;
|
||||
}
|
||||
|
||||
static u32 intel_dp_dsc_nearest_valid_bpp(struct intel_display *display, u32 bpp, u32 pipe_bpp)
|
||||
static int align_min_vesa_compressed_bpp_x16(int min_link_bpp_x16)
|
||||
{
|
||||
u32 bits_per_pixel = bpp;
|
||||
int i;
|
||||
|
||||
/* Error out if the max bpp is less than smallest allowed valid bpp */
|
||||
if (bits_per_pixel < valid_dsc_bpp[0]) {
|
||||
drm_dbg_kms(display->drm, "Unsupported BPP %u, min %u\n",
|
||||
bits_per_pixel, valid_dsc_bpp[0]);
|
||||
return 0;
|
||||
for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp); i++) {
|
||||
int vesa_bpp_x16 = fxp_q4_from_int(valid_dsc_bpp[i]);
|
||||
|
||||
if (vesa_bpp_x16 >= min_link_bpp_x16)
|
||||
return vesa_bpp_x16;
|
||||
}
|
||||
|
||||
/* From XE_LPD onwards we support from bpc upto uncompressed bpp-1 BPPs */
|
||||
if (DISPLAY_VER(display) >= 13) {
|
||||
bits_per_pixel = min(bits_per_pixel, pipe_bpp - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to BSpec, 27 is the max DSC output bpp,
|
||||
* 8 is the min DSC output bpp.
|
||||
* While we can still clamp higher bpp values to 27, saving bandwidth,
|
||||
* if it is required to oompress up to bpp < 8, means we can't do
|
||||
* that and probably means we can't fit the required mode, even with
|
||||
* DSC enabled.
|
||||
*/
|
||||
if (bits_per_pixel < 8) {
|
||||
drm_dbg_kms(display->drm,
|
||||
"Unsupported BPP %u, min 8\n",
|
||||
bits_per_pixel);
|
||||
return 0;
|
||||
}
|
||||
bits_per_pixel = min_t(u32, bits_per_pixel, 27);
|
||||
} else {
|
||||
/* Find the nearest match in the array of known BPPs from VESA */
|
||||
for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp) - 1; i++) {
|
||||
if (bits_per_pixel < valid_dsc_bpp[i + 1])
|
||||
break;
|
||||
}
|
||||
drm_dbg_kms(display->drm, "Set dsc bpp from %d to VESA %d\n",
|
||||
bits_per_pixel, valid_dsc_bpp[i]);
|
||||
static int align_max_vesa_compressed_bpp_x16(int max_link_bpp_x16)
|
||||
{
|
||||
int i;
|
||||
|
||||
bits_per_pixel = valid_dsc_bpp[i];
|
||||
for (i = ARRAY_SIZE(valid_dsc_bpp) - 1; i >= 0; i--) {
|
||||
int vesa_bpp_x16 = fxp_q4_from_int(valid_dsc_bpp[i]);
|
||||
|
||||
if (vesa_bpp_x16 <= max_link_bpp_x16)
|
||||
return vesa_bpp_x16;
|
||||
}
|
||||
|
||||
return bits_per_pixel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bigjoiner_interface_bits(struct intel_display *display)
|
||||
@@ -977,64 +959,6 @@ u32 get_max_compressed_bpp_with_joiner(struct intel_display *display,
|
||||
return max_bpp;
|
||||
}
|
||||
|
||||
/* TODO: return a bpp_x16 value */
|
||||
u16 intel_dp_dsc_get_max_compressed_bpp(struct intel_display *display,
|
||||
u32 link_clock, u32 lane_count,
|
||||
u32 mode_clock, u32 mode_hdisplay,
|
||||
int num_joined_pipes,
|
||||
enum intel_output_format output_format,
|
||||
u32 pipe_bpp,
|
||||
u32 timeslots)
|
||||
{
|
||||
u32 bits_per_pixel, joiner_max_bpp;
|
||||
|
||||
/*
|
||||
* Available Link Bandwidth(Kbits/sec) = (NumberOfLanes)*
|
||||
* (LinkSymbolClock)* 8 * (TimeSlots / 64)
|
||||
* for SST -> TimeSlots is 64(i.e all TimeSlots that are available)
|
||||
* for MST -> TimeSlots has to be calculated, based on mode requirements
|
||||
*
|
||||
* Due to FEC overhead, the available bw is reduced to 97.2261%.
|
||||
* To support the given mode:
|
||||
* Bandwidth required should be <= Available link Bandwidth * FEC Overhead
|
||||
* =>ModeClock * bits_per_pixel <= Available Link Bandwidth * FEC Overhead
|
||||
* =>bits_per_pixel <= Available link Bandwidth * FEC Overhead / ModeClock
|
||||
* =>bits_per_pixel <= (NumberOfLanes * LinkSymbolClock) * 8 (TimeSlots / 64) /
|
||||
* (ModeClock / FEC Overhead)
|
||||
* =>bits_per_pixel <= (NumberOfLanes * LinkSymbolClock * TimeSlots) /
|
||||
* (ModeClock / FEC Overhead * 8)
|
||||
*/
|
||||
bits_per_pixel = ((link_clock * lane_count) * timeslots) /
|
||||
(intel_dp_mode_to_fec_clock(mode_clock) * 8);
|
||||
|
||||
/* Bandwidth required for 420 is half, that of 444 format */
|
||||
if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
|
||||
bits_per_pixel *= 2;
|
||||
|
||||
/*
|
||||
* According to DSC 1.2a Section 4.1.1 Table 4.1 the maximum
|
||||
* supported PPS value can be 63.9375 and with the further
|
||||
* mention that for 420, 422 formats, bpp should be programmed double
|
||||
* the target bpp restricting our target bpp to be 31.9375 at max.
|
||||
*/
|
||||
if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
|
||||
bits_per_pixel = min_t(u32, bits_per_pixel, 31);
|
||||
|
||||
drm_dbg_kms(display->drm, "Max link bpp is %u for %u timeslots "
|
||||
"total bw %u pixel clock %u\n",
|
||||
bits_per_pixel, timeslots,
|
||||
(link_clock * lane_count * 8),
|
||||
intel_dp_mode_to_fec_clock(mode_clock));
|
||||
|
||||
joiner_max_bpp = get_max_compressed_bpp_with_joiner(display, mode_clock,
|
||||
mode_hdisplay, num_joined_pipes);
|
||||
bits_per_pixel = min(bits_per_pixel, joiner_max_bpp);
|
||||
|
||||
bits_per_pixel = intel_dp_dsc_nearest_valid_bpp(display, bits_per_pixel, pipe_bpp);
|
||||
|
||||
return bits_per_pixel;
|
||||
}
|
||||
|
||||
u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector,
|
||||
int mode_clock, int mode_hdisplay,
|
||||
int num_joined_pipes)
|
||||
@@ -1555,24 +1479,20 @@ intel_dp_mode_valid(struct drm_connector *_connector,
|
||||
dsc_slice_count =
|
||||
drm_dp_dsc_sink_max_slice_count(connector->dp.dsc_dpcd,
|
||||
true);
|
||||
dsc = dsc_max_compressed_bpp && dsc_slice_count;
|
||||
} else if (drm_dp_sink_supports_fec(connector->dp.fec_capability)) {
|
||||
dsc_max_compressed_bpp =
|
||||
intel_dp_dsc_get_max_compressed_bpp(display,
|
||||
max_link_clock,
|
||||
max_lanes,
|
||||
target_clock,
|
||||
mode->hdisplay,
|
||||
num_joined_pipes,
|
||||
output_format,
|
||||
pipe_bpp, 64);
|
||||
dsc_slice_count =
|
||||
intel_dp_dsc_get_slice_count(connector,
|
||||
target_clock,
|
||||
mode->hdisplay,
|
||||
num_joined_pipes);
|
||||
}
|
||||
unsigned long bw_overhead_flags = 0;
|
||||
|
||||
dsc = dsc_max_compressed_bpp && dsc_slice_count;
|
||||
if (!drm_dp_is_uhbr_rate(max_link_clock))
|
||||
bw_overhead_flags |= DRM_DP_BW_OVERHEAD_FEC;
|
||||
|
||||
dsc = intel_dp_mode_valid_with_dsc(connector,
|
||||
max_link_clock, max_lanes,
|
||||
target_clock, mode->hdisplay,
|
||||
num_joined_pipes,
|
||||
output_format, pipe_bpp,
|
||||
bw_overhead_flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (intel_dp_joiner_needs_dsc(display, num_joined_pipes) && !dsc)
|
||||
@@ -1894,12 +1814,44 @@ int intel_dp_dsc_max_src_input_bpc(struct intel_display *display)
|
||||
return intel_dp_dsc_min_src_input_bpc();
|
||||
}
|
||||
|
||||
static int align_min_sink_dsc_input_bpp(const struct intel_connector *connector,
|
||||
int min_pipe_bpp)
|
||||
{
|
||||
u8 dsc_bpc[3];
|
||||
int num_bpc;
|
||||
int i;
|
||||
|
||||
num_bpc = drm_dp_dsc_sink_supported_input_bpcs(connector->dp.dsc_dpcd,
|
||||
dsc_bpc);
|
||||
for (i = num_bpc - 1; i >= 0; i--) {
|
||||
if (dsc_bpc[i] * 3 >= min_pipe_bpp)
|
||||
return dsc_bpc[i] * 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int align_max_sink_dsc_input_bpp(const struct intel_connector *connector,
|
||||
int max_pipe_bpp)
|
||||
{
|
||||
u8 dsc_bpc[3];
|
||||
int num_bpc;
|
||||
int i;
|
||||
|
||||
num_bpc = drm_dp_dsc_sink_supported_input_bpcs(connector->dp.dsc_dpcd,
|
||||
dsc_bpc);
|
||||
for (i = 0; i < num_bpc; i++) {
|
||||
if (dsc_bpc[i] * 3 <= max_pipe_bpp)
|
||||
return dsc_bpc[i] * 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector,
|
||||
u8 max_req_bpc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(connector);
|
||||
int i, num_bpc;
|
||||
u8 dsc_bpc[3] = {};
|
||||
int dsc_max_bpc;
|
||||
|
||||
dsc_max_bpc = intel_dp_dsc_max_src_input_bpc(display);
|
||||
@@ -1909,14 +1861,7 @@ int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector,
|
||||
|
||||
dsc_max_bpc = min(dsc_max_bpc, max_req_bpc);
|
||||
|
||||
num_bpc = drm_dp_dsc_sink_supported_input_bpcs(connector->dp.dsc_dpcd,
|
||||
dsc_bpc);
|
||||
for (i = 0; i < num_bpc; i++) {
|
||||
if (dsc_max_bpc >= dsc_bpc[i])
|
||||
return dsc_bpc[i] * 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return align_max_sink_dsc_input_bpp(connector, dsc_max_bpc * 3);
|
||||
}
|
||||
|
||||
static int intel_dp_source_dsc_version_minor(struct intel_display *display)
|
||||
@@ -2047,8 +1992,7 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state,
|
||||
const struct link_config_limits *limits,
|
||||
int dsc_bpp_x16,
|
||||
int timeslots)
|
||||
int dsc_bpp_x16)
|
||||
{
|
||||
const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
|
||||
int link_rate, lane_count;
|
||||
@@ -2108,7 +2052,7 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp,
|
||||
|
||||
static
|
||||
u16 intel_dp_dsc_max_sink_compressed_bppx16(const struct intel_connector *connector,
|
||||
const struct intel_crtc_state *pipe_config,
|
||||
enum intel_output_format output_format,
|
||||
int bpc)
|
||||
{
|
||||
u16 max_bppx16 = drm_edp_dsc_sink_output_bpp(connector->dp.dsc_dpcd);
|
||||
@@ -2119,43 +2063,43 @@ u16 intel_dp_dsc_max_sink_compressed_bppx16(const struct intel_connector *connec
|
||||
* If support not given in DPCD 67h, 68h use the Maximum Allowed bit rate
|
||||
* values as given in spec Table 2-157 DP v2.0
|
||||
*/
|
||||
switch (pipe_config->output_format) {
|
||||
switch (output_format) {
|
||||
case INTEL_OUTPUT_FORMAT_RGB:
|
||||
case INTEL_OUTPUT_FORMAT_YCBCR444:
|
||||
return (3 * bpc) << 4;
|
||||
case INTEL_OUTPUT_FORMAT_YCBCR420:
|
||||
return (3 * (bpc / 2)) << 4;
|
||||
default:
|
||||
MISSING_CASE(pipe_config->output_format);
|
||||
MISSING_CASE(output_format);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intel_dp_dsc_sink_min_compressed_bpp(const struct intel_crtc_state *pipe_config)
|
||||
static int intel_dp_dsc_sink_min_compressed_bpp(enum intel_output_format output_format)
|
||||
{
|
||||
/* From Mandatory bit rate range Support Table 2-157 (DP v2.0) */
|
||||
switch (pipe_config->output_format) {
|
||||
switch (output_format) {
|
||||
case INTEL_OUTPUT_FORMAT_RGB:
|
||||
case INTEL_OUTPUT_FORMAT_YCBCR444:
|
||||
return 8;
|
||||
case INTEL_OUTPUT_FORMAT_YCBCR420:
|
||||
return 6;
|
||||
default:
|
||||
MISSING_CASE(pipe_config->output_format);
|
||||
MISSING_CASE(output_format);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intel_dp_dsc_sink_max_compressed_bpp(const struct intel_connector *connector,
|
||||
const struct intel_crtc_state *pipe_config,
|
||||
int bpc)
|
||||
static int intel_dp_dsc_sink_max_compressed_bpp(const struct intel_connector *connector,
|
||||
enum intel_output_format output_format,
|
||||
int bpc)
|
||||
{
|
||||
return intel_dp_dsc_max_sink_compressed_bppx16(connector,
|
||||
pipe_config, bpc) >> 4;
|
||||
output_format, bpc) >> 4;
|
||||
}
|
||||
|
||||
int intel_dp_dsc_min_src_compressed_bpp(void)
|
||||
@@ -2213,7 +2157,6 @@ int intel_dp_dsc_bpp_step_x16(const struct intel_connector *connector)
|
||||
bool intel_dp_dsc_valid_compressed_bpp(struct intel_dp *intel_dp, int bpp_x16)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
int i;
|
||||
|
||||
if (DISPLAY_VER(display) >= 13) {
|
||||
if (intel_dp->force_dsc_fractional_bpp_en && !fxp_q4_to_frac(bpp_x16))
|
||||
@@ -2225,12 +2168,41 @@ bool intel_dp_dsc_valid_compressed_bpp(struct intel_dp *intel_dp, int bpp_x16)
|
||||
if (fxp_q4_to_frac(bpp_x16))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp); i++) {
|
||||
if (fxp_q4_to_int(bpp_x16) == valid_dsc_bpp[i])
|
||||
return true;
|
||||
}
|
||||
return align_max_vesa_compressed_bpp_x16(bpp_x16) == bpp_x16;
|
||||
}
|
||||
|
||||
return false;
|
||||
static int align_min_compressed_bpp_x16(const struct intel_connector *connector, int min_bpp_x16)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(connector);
|
||||
|
||||
if (DISPLAY_VER(display) >= 13) {
|
||||
int bpp_step_x16 = intel_dp_dsc_bpp_step_x16(connector);
|
||||
|
||||
drm_WARN_ON(display->drm, !is_power_of_2(bpp_step_x16));
|
||||
|
||||
return round_up(min_bpp_x16, bpp_step_x16);
|
||||
} else {
|
||||
return align_min_vesa_compressed_bpp_x16(min_bpp_x16);
|
||||
}
|
||||
}
|
||||
|
||||
static int align_max_compressed_bpp_x16(const struct intel_connector *connector,
|
||||
enum intel_output_format output_format,
|
||||
int pipe_bpp, int max_bpp_x16)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(connector);
|
||||
int link_bpp_x16 = intel_dp_output_format_link_bpp_x16(output_format, pipe_bpp);
|
||||
int bpp_step_x16 = intel_dp_dsc_bpp_step_x16(connector);
|
||||
|
||||
max_bpp_x16 = min(max_bpp_x16, link_bpp_x16 - bpp_step_x16);
|
||||
|
||||
if (DISPLAY_VER(display) >= 13) {
|
||||
drm_WARN_ON(display->drm, !is_power_of_2(bpp_step_x16));
|
||||
|
||||
return round_down(max_bpp_x16, bpp_step_x16);
|
||||
} else {
|
||||
return align_max_vesa_compressed_bpp_x16(max_bpp_x16);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2241,26 +2213,28 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state,
|
||||
const struct link_config_limits *limits,
|
||||
int pipe_bpp,
|
||||
int timeslots)
|
||||
int pipe_bpp)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
const struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||
int min_bpp_x16, max_bpp_x16, bpp_step_x16;
|
||||
int link_bpp_x16;
|
||||
int bpp_x16;
|
||||
int ret;
|
||||
|
||||
min_bpp_x16 = limits->link.min_bpp_x16;
|
||||
max_bpp_x16 = limits->link.max_bpp_x16;
|
||||
bpp_step_x16 = intel_dp_dsc_bpp_step_x16(connector);
|
||||
|
||||
/* Compressed BPP should be less than the Input DSC bpp */
|
||||
link_bpp_x16 = intel_dp_output_format_link_bpp_x16(pipe_config->output_format, pipe_bpp);
|
||||
max_bpp_x16 = min(max_bpp_x16, link_bpp_x16 - bpp_step_x16);
|
||||
max_bpp_x16 = align_max_compressed_bpp_x16(connector, pipe_config->output_format,
|
||||
pipe_bpp, max_bpp_x16);
|
||||
if (intel_dp_is_edp(intel_dp)) {
|
||||
pipe_config->port_clock = limits->max_rate;
|
||||
pipe_config->lane_count = limits->max_lane_count;
|
||||
|
||||
drm_WARN_ON(display->drm, !is_power_of_2(bpp_step_x16));
|
||||
min_bpp_x16 = round_up(limits->link.min_bpp_x16, bpp_step_x16);
|
||||
max_bpp_x16 = round_down(max_bpp_x16, bpp_step_x16);
|
||||
pipe_config->dsc.compressed_bpp_x16 = max_bpp_x16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (bpp_x16 = max_bpp_x16; bpp_x16 >= min_bpp_x16; bpp_x16 -= bpp_step_x16) {
|
||||
if (!intel_dp_dsc_valid_compressed_bpp(intel_dp, bpp_x16))
|
||||
@@ -2270,8 +2244,7 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp,
|
||||
pipe_config,
|
||||
conn_state,
|
||||
limits,
|
||||
bpp_x16,
|
||||
timeslots);
|
||||
bpp_x16);
|
||||
if (ret == 0) {
|
||||
pipe_config->dsc.compressed_bpp_x16 = bpp_x16;
|
||||
if (intel_dp->force_dsc_fractional_bpp_en &&
|
||||
@@ -2328,86 +2301,21 @@ int intel_dp_force_dsc_pipe_bpp(struct intel_dp *intel_dp,
|
||||
static int intel_dp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state,
|
||||
const struct link_config_limits *limits,
|
||||
int timeslots)
|
||||
const struct link_config_limits *limits)
|
||||
{
|
||||
const struct intel_connector *connector =
|
||||
to_intel_connector(conn_state->connector);
|
||||
u8 dsc_bpc[3] = {};
|
||||
int forced_bpp, pipe_bpp;
|
||||
int num_bpc, i, ret;
|
||||
int ret;
|
||||
|
||||
forced_bpp = intel_dp_force_dsc_pipe_bpp(intel_dp, limits);
|
||||
|
||||
if (forced_bpp) {
|
||||
ret = dsc_compute_compressed_bpp(intel_dp, pipe_config, conn_state,
|
||||
limits, forced_bpp, timeslots);
|
||||
if (ret == 0) {
|
||||
pipe_config->pipe_bpp = forced_bpp;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the maximum DSC bpc that will be supported by any valid
|
||||
* link configuration and compressed bpp.
|
||||
*/
|
||||
num_bpc = drm_dp_dsc_sink_supported_input_bpcs(connector->dp.dsc_dpcd, dsc_bpc);
|
||||
for (i = 0; i < num_bpc; i++) {
|
||||
pipe_bpp = dsc_bpc[i] * 3;
|
||||
if (pipe_bpp < limits->pipe.min_bpp || pipe_bpp > limits->pipe.max_bpp)
|
||||
continue;
|
||||
|
||||
ret = dsc_compute_compressed_bpp(intel_dp, pipe_config, conn_state,
|
||||
limits, pipe_bpp, timeslots);
|
||||
if (ret == 0) {
|
||||
pipe_config->pipe_bpp = pipe_bpp;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int intel_edp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state,
|
||||
const struct link_config_limits *limits)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
struct intel_connector *connector =
|
||||
to_intel_connector(conn_state->connector);
|
||||
int pipe_bpp, forced_bpp;
|
||||
int dsc_min_bpp;
|
||||
int dsc_max_bpp;
|
||||
|
||||
forced_bpp = intel_dp_force_dsc_pipe_bpp(intel_dp, limits);
|
||||
|
||||
if (forced_bpp) {
|
||||
if (forced_bpp)
|
||||
pipe_bpp = forced_bpp;
|
||||
} else {
|
||||
int max_bpc = limits->pipe.max_bpp / 3;
|
||||
else
|
||||
pipe_bpp = limits->pipe.max_bpp;
|
||||
|
||||
/* For eDP use max bpp that can be supported with DSC. */
|
||||
pipe_bpp = intel_dp_dsc_compute_max_bpp(connector, max_bpc);
|
||||
if (!is_dsc_pipe_bpp_sufficient(limits, pipe_bpp)) {
|
||||
drm_dbg_kms(display->drm,
|
||||
"Computed BPC is not in DSC BPC limits\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
pipe_config->port_clock = limits->max_rate;
|
||||
pipe_config->lane_count = limits->max_lane_count;
|
||||
|
||||
dsc_min_bpp = fxp_q4_to_int_roundup(limits->link.min_bpp_x16);
|
||||
|
||||
dsc_max_bpp = fxp_q4_to_int(limits->link.max_bpp_x16);
|
||||
|
||||
/* Compressed BPP should be less than the Input DSC bpp */
|
||||
dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1);
|
||||
|
||||
pipe_config->dsc.compressed_bpp_x16 =
|
||||
fxp_q4_from_int(max(dsc_min_bpp, dsc_max_bpp));
|
||||
ret = dsc_compute_compressed_bpp(intel_dp, pipe_config, conn_state,
|
||||
limits, pipe_bpp);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
pipe_config->pipe_bpp = pipe_bpp;
|
||||
|
||||
@@ -2465,12 +2373,8 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
|
||||
* figured out for DP MST DSC.
|
||||
*/
|
||||
if (!is_mst) {
|
||||
if (intel_dp_is_edp(intel_dp))
|
||||
ret = intel_edp_dsc_compute_pipe_bpp(intel_dp, pipe_config,
|
||||
conn_state, limits);
|
||||
else
|
||||
ret = intel_dp_dsc_compute_pipe_bpp(intel_dp, pipe_config,
|
||||
conn_state, limits, timeslots);
|
||||
ret = intel_dp_dsc_compute_pipe_bpp(intel_dp, pipe_config,
|
||||
conn_state, limits);
|
||||
if (ret) {
|
||||
drm_dbg_kms(display->drm,
|
||||
"No Valid pipe bpp for given mode ret = %d\n", ret);
|
||||
@@ -2543,11 +2447,8 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
|
||||
|
||||
static int
|
||||
dsc_throughput_quirk_max_bpp_x16(const struct intel_connector *connector,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
int mode_clock)
|
||||
{
|
||||
const struct drm_display_mode *adjusted_mode =
|
||||
&crtc_state->hw.adjusted_mode;
|
||||
|
||||
if (!connector->dp.dsc_throughput_quirk)
|
||||
return INT_MAX;
|
||||
|
||||
@@ -2567,7 +2468,7 @@ dsc_throughput_quirk_max_bpp_x16(const struct intel_connector *connector,
|
||||
* smaller than the YUV422/420 value, but let's not depend on this
|
||||
* assumption.
|
||||
*/
|
||||
if (adjusted_mode->crtc_clock <
|
||||
if (mode_clock <
|
||||
min(connector->dp.dsc_branch_caps.overall_throughput.rgb_yuv444,
|
||||
connector->dp.dsc_branch_caps.overall_throughput.yuv422_420) / 2)
|
||||
return INT_MAX;
|
||||
@@ -2575,18 +2476,106 @@ dsc_throughput_quirk_max_bpp_x16(const struct intel_connector *connector,
|
||||
return fxp_q4_from_int(12);
|
||||
}
|
||||
|
||||
static int compute_min_compressed_bpp_x16(struct intel_connector *connector,
|
||||
enum intel_output_format output_format)
|
||||
{
|
||||
int dsc_src_min_bpp, dsc_sink_min_bpp, dsc_min_bpp;
|
||||
int min_bpp_x16;
|
||||
|
||||
dsc_src_min_bpp = intel_dp_dsc_min_src_compressed_bpp();
|
||||
dsc_sink_min_bpp = intel_dp_dsc_sink_min_compressed_bpp(output_format);
|
||||
dsc_min_bpp = max(dsc_src_min_bpp, dsc_sink_min_bpp);
|
||||
|
||||
min_bpp_x16 = fxp_q4_from_int(dsc_min_bpp);
|
||||
|
||||
min_bpp_x16 = align_min_compressed_bpp_x16(connector, min_bpp_x16);
|
||||
|
||||
return min_bpp_x16;
|
||||
}
|
||||
|
||||
static int compute_max_compressed_bpp_x16(struct intel_connector *connector,
|
||||
int mode_clock, int mode_hdisplay,
|
||||
int num_joined_pipes,
|
||||
enum intel_output_format output_format,
|
||||
int pipe_max_bpp, int max_link_bpp_x16)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(connector);
|
||||
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
||||
int dsc_src_max_bpp, dsc_sink_max_bpp, dsc_max_bpp;
|
||||
int throughput_max_bpp_x16;
|
||||
int joiner_max_bpp;
|
||||
|
||||
dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp);
|
||||
joiner_max_bpp = get_max_compressed_bpp_with_joiner(display,
|
||||
mode_clock,
|
||||
mode_hdisplay,
|
||||
num_joined_pipes);
|
||||
dsc_sink_max_bpp = intel_dp_dsc_sink_max_compressed_bpp(connector,
|
||||
output_format,
|
||||
pipe_max_bpp / 3);
|
||||
dsc_max_bpp = min(dsc_sink_max_bpp, dsc_src_max_bpp);
|
||||
dsc_max_bpp = min(dsc_max_bpp, joiner_max_bpp);
|
||||
|
||||
max_link_bpp_x16 = min(max_link_bpp_x16, fxp_q4_from_int(dsc_max_bpp));
|
||||
|
||||
throughput_max_bpp_x16 = dsc_throughput_quirk_max_bpp_x16(connector,
|
||||
mode_clock);
|
||||
if (throughput_max_bpp_x16 < max_link_bpp_x16) {
|
||||
max_link_bpp_x16 = throughput_max_bpp_x16;
|
||||
|
||||
drm_dbg_kms(display->drm,
|
||||
"[CONNECTOR:%d:%s] Decreasing link max bpp to " FXP_Q4_FMT " due to DSC throughput quirk\n",
|
||||
connector->base.base.id, connector->base.name,
|
||||
FXP_Q4_ARGS(max_link_bpp_x16));
|
||||
}
|
||||
|
||||
max_link_bpp_x16 = align_max_compressed_bpp_x16(connector, output_format,
|
||||
pipe_max_bpp, max_link_bpp_x16);
|
||||
|
||||
return max_link_bpp_x16;
|
||||
}
|
||||
|
||||
bool intel_dp_mode_valid_with_dsc(struct intel_connector *connector,
|
||||
int link_clock, int lane_count,
|
||||
int mode_clock, int mode_hdisplay,
|
||||
int num_joined_pipes,
|
||||
enum intel_output_format output_format,
|
||||
int pipe_bpp, unsigned long bw_overhead_flags)
|
||||
{
|
||||
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
||||
int min_bpp_x16 = compute_min_compressed_bpp_x16(connector, output_format);
|
||||
int max_bpp_x16 = compute_max_compressed_bpp_x16(connector,
|
||||
mode_clock, mode_hdisplay,
|
||||
num_joined_pipes,
|
||||
output_format,
|
||||
pipe_bpp, INT_MAX);
|
||||
int dsc_slice_count = intel_dp_dsc_get_slice_count(connector,
|
||||
mode_clock,
|
||||
mode_hdisplay,
|
||||
num_joined_pipes);
|
||||
|
||||
if (min_bpp_x16 <= 0 || min_bpp_x16 > max_bpp_x16)
|
||||
return false;
|
||||
|
||||
return is_bw_sufficient_for_dsc_config(intel_dp,
|
||||
link_clock, lane_count,
|
||||
mode_clock, mode_hdisplay,
|
||||
dsc_slice_count, min_bpp_x16,
|
||||
bw_overhead_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the output link min, max bpp values in limits based on the pipe bpp
|
||||
* range, crtc_state and dsc mode. Return true on success.
|
||||
*/
|
||||
static bool
|
||||
intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp,
|
||||
const struct intel_connector *connector,
|
||||
intel_dp_compute_config_link_bpp_limits(struct intel_connector *connector,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
bool dsc,
|
||||
struct link_config_limits *limits)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
struct intel_display *display = to_intel_display(connector);
|
||||
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
||||
const struct drm_display_mode *adjusted_mode =
|
||||
&crtc_state->hw.adjusted_mode;
|
||||
const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||
@@ -2604,40 +2593,17 @@ intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp,
|
||||
|
||||
limits->link.min_bpp_x16 = fxp_q4_from_int(limits->pipe.min_bpp);
|
||||
} else {
|
||||
int dsc_src_min_bpp, dsc_sink_min_bpp, dsc_min_bpp;
|
||||
int dsc_src_max_bpp, dsc_sink_max_bpp, dsc_max_bpp;
|
||||
int throughput_max_bpp_x16;
|
||||
int joiner_max_bpp;
|
||||
limits->link.min_bpp_x16 =
|
||||
compute_min_compressed_bpp_x16(connector, crtc_state->output_format);
|
||||
|
||||
dsc_src_min_bpp = intel_dp_dsc_min_src_compressed_bpp();
|
||||
dsc_sink_min_bpp = intel_dp_dsc_sink_min_compressed_bpp(crtc_state);
|
||||
dsc_min_bpp = max(dsc_src_min_bpp, dsc_sink_min_bpp);
|
||||
limits->link.min_bpp_x16 = fxp_q4_from_int(dsc_min_bpp);
|
||||
|
||||
dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp);
|
||||
joiner_max_bpp =
|
||||
get_max_compressed_bpp_with_joiner(display,
|
||||
adjusted_mode->crtc_clock,
|
||||
adjusted_mode->hdisplay,
|
||||
intel_crtc_num_joined_pipes(crtc_state));
|
||||
dsc_sink_max_bpp = intel_dp_dsc_sink_max_compressed_bpp(connector,
|
||||
crtc_state,
|
||||
limits->pipe.max_bpp / 3);
|
||||
dsc_max_bpp = min(dsc_sink_max_bpp, dsc_src_max_bpp);
|
||||
dsc_max_bpp = min(dsc_max_bpp, joiner_max_bpp);
|
||||
|
||||
max_link_bpp_x16 = min(max_link_bpp_x16, fxp_q4_from_int(dsc_max_bpp));
|
||||
|
||||
throughput_max_bpp_x16 = dsc_throughput_quirk_max_bpp_x16(connector, crtc_state);
|
||||
if (throughput_max_bpp_x16 < max_link_bpp_x16) {
|
||||
max_link_bpp_x16 = throughput_max_bpp_x16;
|
||||
|
||||
drm_dbg_kms(display->drm,
|
||||
"[CRTC:%d:%s][CONNECTOR:%d:%s] Decreasing link max bpp to " FXP_Q4_FMT " due to DSC throughput quirk\n",
|
||||
crtc->base.base.id, crtc->base.name,
|
||||
connector->base.base.id, connector->base.name,
|
||||
FXP_Q4_ARGS(max_link_bpp_x16));
|
||||
}
|
||||
max_link_bpp_x16 =
|
||||
compute_max_compressed_bpp_x16(connector,
|
||||
adjusted_mode->crtc_clock,
|
||||
adjusted_mode->hdisplay,
|
||||
intel_crtc_num_joined_pipes(crtc_state),
|
||||
crtc_state->output_format,
|
||||
limits->pipe.max_bpp,
|
||||
max_link_bpp_x16);
|
||||
}
|
||||
|
||||
limits->link.max_bpp_x16 = max_link_bpp_x16;
|
||||
@@ -2671,15 +2637,19 @@ intel_dp_dsc_compute_pipe_bpp_limits(struct intel_connector *connector,
|
||||
int dsc_max_bpc = intel_dp_dsc_max_src_input_bpc(display);
|
||||
|
||||
limits->pipe.min_bpp = max(limits->pipe.min_bpp, dsc_min_bpc * 3);
|
||||
limits->pipe.min_bpp = align_min_sink_dsc_input_bpp(connector, limits->pipe.min_bpp);
|
||||
|
||||
limits->pipe.max_bpp = min(limits->pipe.max_bpp, dsc_max_bpc * 3);
|
||||
limits->pipe.max_bpp = align_max_sink_dsc_input_bpp(connector, limits->pipe.max_bpp);
|
||||
|
||||
if (limits->pipe.min_bpp <= 0 ||
|
||||
limits->pipe.min_bpp > limits->pipe.max_bpp) {
|
||||
drm_dbg_kms(display->drm,
|
||||
"[CONNECTOR:%d:%s] Invalid DSC src/sink input BPP (src:%d-%d pipe:%d-%d)\n",
|
||||
"[CONNECTOR:%d:%s] Invalid DSC src/sink input BPP (src:%d-%d pipe:%d-%d sink-align:%d-%d)\n",
|
||||
connector->base.base.id, connector->base.name,
|
||||
dsc_min_bpc * 3, dsc_max_bpc * 3,
|
||||
orig_limits.pipe.min_bpp, orig_limits.pipe.max_bpp);
|
||||
orig_limits.pipe.min_bpp, orig_limits.pipe.max_bpp,
|
||||
limits->pipe.min_bpp, limits->pipe.max_bpp);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -2745,8 +2715,7 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
|
||||
|
||||
intel_dp_test_compute_config(intel_dp, crtc_state, limits);
|
||||
|
||||
return intel_dp_compute_config_link_bpp_limits(intel_dp,
|
||||
connector,
|
||||
return intel_dp_compute_config_link_bpp_limits(connector,
|
||||
crtc_state,
|
||||
dsc,
|
||||
limits);
|
||||
|
||||
@@ -143,17 +143,12 @@ bool intel_digital_port_connected(struct intel_encoder *encoder);
|
||||
bool intel_digital_port_connected_locked(struct intel_encoder *encoder);
|
||||
int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector,
|
||||
u8 dsc_max_bpc);
|
||||
u16 intel_dp_dsc_get_max_compressed_bpp(struct intel_display *display,
|
||||
u32 link_clock, u32 lane_count,
|
||||
u32 mode_clock, u32 mode_hdisplay,
|
||||
int num_joined_pipes,
|
||||
enum intel_output_format output_format,
|
||||
u32 pipe_bpp,
|
||||
u32 timeslots);
|
||||
int intel_dp_dsc_sink_min_compressed_bpp(const struct intel_crtc_state *pipe_config);
|
||||
int intel_dp_dsc_sink_max_compressed_bpp(const struct intel_connector *connector,
|
||||
const struct intel_crtc_state *pipe_config,
|
||||
int bpc);
|
||||
bool intel_dp_mode_valid_with_dsc(struct intel_connector *connector,
|
||||
int link_clock, int lane_count,
|
||||
int mode_clock, int mode_hdisplay,
|
||||
int num_joined_pipes,
|
||||
enum intel_output_format output_format,
|
||||
int pipe_bpp, unsigned long bw_overhead_flags);
|
||||
bool intel_dp_dsc_valid_compressed_bpp(struct intel_dp *intel_dp, int bpp_x16);
|
||||
u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector,
|
||||
int mode_clock, int mode_hdisplay,
|
||||
|
||||
@@ -463,57 +463,21 @@ static int mst_stream_dsc_compute_link_config(struct intel_dp *intel_dp,
|
||||
{
|
||||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||
int num_bpc;
|
||||
u8 dsc_bpc[3] = {};
|
||||
int min_bpp, max_bpp, sink_min_bpp, sink_max_bpp;
|
||||
int min_compressed_bpp_x16, max_compressed_bpp_x16;
|
||||
int bpp_step_x16;
|
||||
|
||||
max_bpp = limits->pipe.max_bpp;
|
||||
min_bpp = limits->pipe.min_bpp;
|
||||
|
||||
num_bpc = drm_dp_dsc_sink_supported_input_bpcs(connector->dp.dsc_dpcd,
|
||||
dsc_bpc);
|
||||
|
||||
drm_dbg_kms(display->drm, "DSC Source supported min bpp %d max bpp %d\n",
|
||||
min_bpp, max_bpp);
|
||||
|
||||
sink_min_bpp = min_array(dsc_bpc, num_bpc) * 3;
|
||||
sink_max_bpp = max_array(dsc_bpc, num_bpc) * 3;
|
||||
|
||||
drm_dbg_kms(display->drm, "DSC Sink supported min bpp %d max bpp %d\n",
|
||||
sink_min_bpp, sink_max_bpp);
|
||||
|
||||
if (min_bpp < sink_min_bpp)
|
||||
min_bpp = sink_min_bpp;
|
||||
|
||||
if (max_bpp > sink_max_bpp)
|
||||
max_bpp = sink_max_bpp;
|
||||
|
||||
crtc_state->pipe_bpp = max_bpp;
|
||||
|
||||
min_compressed_bpp_x16 = limits->link.min_bpp_x16;
|
||||
max_compressed_bpp_x16 = limits->link.max_bpp_x16;
|
||||
crtc_state->pipe_bpp = limits->pipe.max_bpp;
|
||||
|
||||
drm_dbg_kms(display->drm,
|
||||
"DSC Sink supported compressed min bpp " FXP_Q4_FMT " compressed max bpp " FXP_Q4_FMT "\n",
|
||||
FXP_Q4_ARGS(min_compressed_bpp_x16), FXP_Q4_ARGS(max_compressed_bpp_x16));
|
||||
|
||||
bpp_step_x16 = intel_dp_dsc_bpp_step_x16(connector);
|
||||
|
||||
max_compressed_bpp_x16 = min(max_compressed_bpp_x16, fxp_q4_from_int(crtc_state->pipe_bpp) - bpp_step_x16);
|
||||
|
||||
drm_WARN_ON(display->drm, !is_power_of_2(bpp_step_x16));
|
||||
min_compressed_bpp_x16 = round_up(min_compressed_bpp_x16, bpp_step_x16);
|
||||
max_compressed_bpp_x16 = round_down(max_compressed_bpp_x16, bpp_step_x16);
|
||||
FXP_Q4_ARGS(limits->link.min_bpp_x16), FXP_Q4_ARGS(limits->link.max_bpp_x16));
|
||||
|
||||
crtc_state->lane_count = limits->max_lane_count;
|
||||
crtc_state->port_clock = limits->max_rate;
|
||||
|
||||
return intel_dp_mtp_tu_compute_config(intel_dp, crtc_state, conn_state,
|
||||
min_compressed_bpp_x16,
|
||||
max_compressed_bpp_x16,
|
||||
bpp_step_x16, true);
|
||||
limits->link.min_bpp_x16,
|
||||
limits->link.max_bpp_x16,
|
||||
intel_dp_dsc_bpp_step_x16(connector),
|
||||
true);
|
||||
}
|
||||
|
||||
static int mode_hblank_period_ns(const struct drm_display_mode *mode)
|
||||
@@ -1462,8 +1426,6 @@ mst_connector_mode_valid_ctx(struct drm_connector *_connector,
|
||||
DRM_DP_BW_OVERHEAD_MST | DRM_DP_BW_OVERHEAD_SSC_REF_CLK;
|
||||
int ret;
|
||||
bool dsc = false;
|
||||
u16 dsc_max_compressed_bpp = 0;
|
||||
u8 dsc_slice_count = 0;
|
||||
int target_clock = mode->clock;
|
||||
int num_joined_pipes;
|
||||
|
||||
@@ -1522,31 +1484,22 @@ mst_connector_mode_valid_ctx(struct drm_connector *_connector,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (intel_dp_has_dsc(connector)) {
|
||||
if (intel_dp_has_dsc(connector) && drm_dp_sink_supports_fec(connector->dp.fec_capability)) {
|
||||
/*
|
||||
* TBD pass the connector BPC,
|
||||
* for now U8_MAX so that max BPC on that platform would be picked
|
||||
*/
|
||||
int pipe_bpp = intel_dp_dsc_compute_max_bpp(connector, U8_MAX);
|
||||
|
||||
if (drm_dp_sink_supports_fec(connector->dp.fec_capability)) {
|
||||
dsc_max_compressed_bpp =
|
||||
intel_dp_dsc_get_max_compressed_bpp(display,
|
||||
max_link_clock,
|
||||
max_lanes,
|
||||
target_clock,
|
||||
mode->hdisplay,
|
||||
num_joined_pipes,
|
||||
INTEL_OUTPUT_FORMAT_RGB,
|
||||
pipe_bpp, 64);
|
||||
dsc_slice_count =
|
||||
intel_dp_dsc_get_slice_count(connector,
|
||||
target_clock,
|
||||
mode->hdisplay,
|
||||
num_joined_pipes);
|
||||
}
|
||||
if (!drm_dp_is_uhbr_rate(max_link_clock))
|
||||
bw_overhead_flags |= DRM_DP_BW_OVERHEAD_FEC;
|
||||
|
||||
dsc = dsc_max_compressed_bpp && dsc_slice_count;
|
||||
dsc = intel_dp_mode_valid_with_dsc(connector,
|
||||
max_link_clock, max_lanes,
|
||||
target_clock, mode->hdisplay,
|
||||
num_joined_pipes,
|
||||
INTEL_OUTPUT_FORMAT_RGB, pipe_bpp,
|
||||
bw_overhead_flags);
|
||||
}
|
||||
|
||||
if (intel_dp_joiner_needs_dsc(display, num_joined_pipes) && !dsc) {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "i915_reg.h"
|
||||
#include "intel_display_core.h"
|
||||
#include "intel_display_utils.h"
|
||||
@@ -58,18 +57,18 @@ const char *intel_dram_type_str(enum intel_dram_type type)
|
||||
|
||||
static enum intel_dram_type pnv_dram_type(struct intel_display *display)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
|
||||
return intel_uncore_read(&i915->uncore, CSHRDDR3CTL) & CSHRDDR3CTL_DDR3 ?
|
||||
return intel_uncore_read(uncore, CSHRDDR3CTL) & CSHRDDR3CTL_DDR3 ?
|
||||
INTEL_DRAM_DDR3 : INTEL_DRAM_DDR2;
|
||||
}
|
||||
|
||||
static unsigned int pnv_mem_freq(struct intel_display *display)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u32 tmp;
|
||||
|
||||
tmp = intel_uncore_read(&dev_priv->uncore, CLKCFG);
|
||||
tmp = intel_uncore_read(uncore, CLKCFG);
|
||||
|
||||
switch (tmp & CLKCFG_MEM_MASK) {
|
||||
case CLKCFG_MEM_533:
|
||||
@@ -85,10 +84,10 @@ static unsigned int pnv_mem_freq(struct intel_display *display)
|
||||
|
||||
static unsigned int ilk_mem_freq(struct intel_display *display)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u16 ddrpll;
|
||||
|
||||
ddrpll = intel_uncore_read16(&dev_priv->uncore, DDRMPLL1);
|
||||
ddrpll = intel_uncore_read16(uncore, DDRMPLL1);
|
||||
switch (ddrpll & 0xff) {
|
||||
case 0xc:
|
||||
return 800000;
|
||||
@@ -158,7 +157,7 @@ unsigned int intel_mem_freq(struct intel_display *display)
|
||||
|
||||
static unsigned int i9xx_fsb_freq(struct intel_display *display)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u32 fsb;
|
||||
|
||||
/*
|
||||
@@ -169,7 +168,7 @@ static unsigned int i9xx_fsb_freq(struct intel_display *display)
|
||||
* don't know which registers have that information,
|
||||
* and all the relevant docs have gone to bit heaven :(
|
||||
*/
|
||||
fsb = intel_uncore_read(&i915->uncore, CLKCFG) & CLKCFG_FSB_MASK;
|
||||
fsb = intel_uncore_read(uncore, CLKCFG) & CLKCFG_FSB_MASK;
|
||||
|
||||
if (display->platform.pineview || display->platform.mobile) {
|
||||
switch (fsb) {
|
||||
@@ -214,10 +213,10 @@ static unsigned int i9xx_fsb_freq(struct intel_display *display)
|
||||
|
||||
static unsigned int ilk_fsb_freq(struct intel_display *display)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u16 fsb;
|
||||
|
||||
fsb = intel_uncore_read16(&dev_priv->uncore, CSIPLL0) & 0x3ff;
|
||||
fsb = intel_uncore_read16(uncore, CSIPLL0) & 0x3ff;
|
||||
|
||||
switch (fsb) {
|
||||
case 0x00c:
|
||||
@@ -484,7 +483,7 @@ intel_is_dram_symmetric(const struct dram_channel_info *ch0,
|
||||
static int
|
||||
skl_dram_get_channels_info(struct intel_display *display, struct dram_info *dram_info)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
struct dram_channel_info ch0 = {}, ch1 = {};
|
||||
u32 val;
|
||||
int ret;
|
||||
@@ -492,14 +491,12 @@ skl_dram_get_channels_info(struct intel_display *display, struct dram_info *dram
|
||||
/* Assume 16Gb+ DIMMs are present until proven otherwise */
|
||||
dram_info->has_16gb_dimms = true;
|
||||
|
||||
val = intel_uncore_read(&i915->uncore,
|
||||
SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN);
|
||||
val = intel_uncore_read(uncore, SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN);
|
||||
ret = skl_dram_get_channel_info(display, &ch0, 0, val);
|
||||
if (ret == 0)
|
||||
dram_info->num_channels++;
|
||||
|
||||
val = intel_uncore_read(&i915->uncore,
|
||||
SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN);
|
||||
val = intel_uncore_read(uncore, SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN);
|
||||
ret = skl_dram_get_channel_info(display, &ch1, 1, val);
|
||||
if (ret == 0)
|
||||
dram_info->num_channels++;
|
||||
@@ -530,11 +527,10 @@ skl_dram_get_channels_info(struct intel_display *display, struct dram_info *dram
|
||||
static enum intel_dram_type
|
||||
skl_get_dram_type(struct intel_display *display)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u32 val;
|
||||
|
||||
val = intel_uncore_read(&i915->uncore,
|
||||
SKL_MAD_INTER_CHANNEL_0_0_0_MCHBAR_MCMAIN);
|
||||
val = intel_uncore_read(uncore, SKL_MAD_INTER_CHANNEL_0_0_0_MCHBAR_MCMAIN);
|
||||
|
||||
switch (val & SKL_DRAM_DDR_TYPE_MASK) {
|
||||
case SKL_DRAM_DDR_TYPE_DDR3:
|
||||
@@ -645,7 +641,7 @@ static void bxt_get_dimm_info(struct dram_dimm_info *dimm, u32 val)
|
||||
|
||||
static int bxt_get_dram_info(struct intel_display *display, struct dram_info *dram_info)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u32 val;
|
||||
u8 valid_ranks = 0;
|
||||
int i;
|
||||
@@ -657,7 +653,7 @@ static int bxt_get_dram_info(struct intel_display *display, struct dram_info *dr
|
||||
struct dram_dimm_info dimm;
|
||||
enum intel_dram_type type;
|
||||
|
||||
val = intel_uncore_read(&i915->uncore, BXT_D_CR_DRP0_DUNIT(i));
|
||||
val = intel_uncore_read(uncore, BXT_D_CR_DRP0_DUNIT(i));
|
||||
if (val == 0xFFFFFFFF)
|
||||
continue;
|
||||
|
||||
@@ -770,8 +766,8 @@ static int gen12_get_dram_info(struct intel_display *display, struct dram_info *
|
||||
|
||||
static int xelpdp_get_dram_info(struct intel_display *display, struct dram_info *dram_info)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
u32 val = intel_uncore_read(&i915->uncore, MTL_MEM_SS_INFO_GLOBAL);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
u32 val = intel_uncore_read(uncore, MTL_MEM_SS_INFO_GLOBAL);
|
||||
|
||||
switch (REG_FIELD_GET(MTL_DDR_TYPE_MASK, val)) {
|
||||
case 0:
|
||||
|
||||
@@ -704,7 +704,36 @@ void intel_dsb_vblank_evade(struct intel_atomic_state *state,
|
||||
if (crtc_state->has_psr)
|
||||
intel_dsb_emit_wait_dsl(dsb, DSB_OPCODE_WAIT_DSL_OUT, 0, 0);
|
||||
|
||||
if (pre_commit_is_vrr_active(state, crtc)) {
|
||||
if (pre_commit_is_vrr_active(state, crtc) && crtc_state->vrr.dc_balance.enable) {
|
||||
int vblank_delay = crtc_state->set_context_latency;
|
||||
int vmin_vblank_start, vmax_vblank_start;
|
||||
|
||||
vmin_vblank_start = intel_vrr_dcb_vmin_vblank_start_next(crtc_state);
|
||||
|
||||
if (vmin_vblank_start >= 0) {
|
||||
end = vmin_vblank_start;
|
||||
start = end - vblank_delay - latency;
|
||||
intel_dsb_wait_scanline_out(state, dsb, start, end);
|
||||
}
|
||||
|
||||
vmax_vblank_start = intel_vrr_dcb_vmax_vblank_start_next(crtc_state);
|
||||
|
||||
if (vmax_vblank_start >= 0) {
|
||||
end = vmax_vblank_start;
|
||||
start = end - vblank_delay - latency;
|
||||
intel_dsb_wait_scanline_out(state, dsb, start, end);
|
||||
}
|
||||
|
||||
vmin_vblank_start = intel_vrr_dcb_vmin_vblank_start_final(crtc_state);
|
||||
end = vmin_vblank_start;
|
||||
start = end - vblank_delay - latency;
|
||||
intel_dsb_wait_scanline_out(state, dsb, start, end);
|
||||
|
||||
vmax_vblank_start = intel_vrr_dcb_vmax_vblank_start_final(crtc_state);
|
||||
end = vmax_vblank_start;
|
||||
start = end - vblank_delay - latency;
|
||||
intel_dsb_wait_scanline_out(state, dsb, start, end);
|
||||
} else if (pre_commit_is_vrr_active(state, crtc)) {
|
||||
int vblank_delay = crtc_state->set_context_latency;
|
||||
|
||||
end = intel_vrr_vmin_vblank_start(crtc_state);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
|
||||
|
||||
43
drivers/gpu/drm/i915/display/intel_gvt_api.c
Normal file
43
drivers/gpu/drm/i915/display/intel_gvt_api.c
Normal file
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright © 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "intel_display_core.h"
|
||||
#include "intel_display_regs.h"
|
||||
#include "intel_gvt_api.h"
|
||||
|
||||
u32 intel_display_device_pipe_offset(struct intel_display *display, enum pipe pipe)
|
||||
{
|
||||
return INTEL_DISPLAY_DEVICE_PIPE_OFFSET(display, pipe);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(intel_display_device_pipe_offset, "I915_GVT");
|
||||
|
||||
u32 intel_display_device_trans_offset(struct intel_display *display, enum transcoder trans)
|
||||
{
|
||||
return INTEL_DISPLAY_DEVICE_TRANS_OFFSET(display, trans);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(intel_display_device_trans_offset, "I915_GVT");
|
||||
|
||||
u32 intel_display_device_cursor_offset(struct intel_display *display, enum pipe pipe)
|
||||
{
|
||||
return INTEL_DISPLAY_DEVICE_CURSOR_OFFSET(display, pipe);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(intel_display_device_cursor_offset, "I915_GVT");
|
||||
|
||||
u32 intel_display_device_mmio_base(struct intel_display *display)
|
||||
{
|
||||
return DISPLAY_MMIO_BASE(display);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(intel_display_device_mmio_base, "I915_GVT");
|
||||
|
||||
bool intel_display_device_pipe_valid(struct intel_display *display, enum pipe pipe)
|
||||
{
|
||||
if (pipe < PIPE_A || pipe >= I915_MAX_PIPES)
|
||||
return false;
|
||||
|
||||
return DISPLAY_RUNTIME_INFO(display)->pipe_mask & BIT(pipe);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(intel_display_device_pipe_valid, "I915_GVT");
|
||||
21
drivers/gpu/drm/i915/display/intel_gvt_api.h
Normal file
21
drivers/gpu/drm/i915/display/intel_gvt_api.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __INTEL_GVT_API_H__
|
||||
#define __INTEL_GVT_API_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum pipe;
|
||||
enum transcoder;
|
||||
struct intel_display;
|
||||
|
||||
u32 intel_display_device_pipe_offset(struct intel_display *display, enum pipe pipe);
|
||||
u32 intel_display_device_trans_offset(struct intel_display *display, enum transcoder trans);
|
||||
u32 intel_display_device_cursor_offset(struct intel_display *display, enum pipe pipe);
|
||||
u32 intel_display_device_mmio_base(struct intel_display *display);
|
||||
bool intel_display_device_pipe_valid(struct intel_display *display, enum pipe pipe);
|
||||
|
||||
#endif /* __INTEL_GVT_API_H__ */
|
||||
193
drivers/gpu/drm/i915/display/intel_initial_plane.c
Normal file
193
drivers/gpu/drm/i915/display/intel_initial_plane.c
Normal file
@@ -0,0 +1,193 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/* Copyright © 2025 Intel Corporation */
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/intel/display_parent_interface.h>
|
||||
|
||||
#include "intel_display_core.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_fb.h"
|
||||
#include "intel_frontbuffer.h"
|
||||
#include "intel_initial_plane.h"
|
||||
#include "intel_plane.h"
|
||||
|
||||
void intel_initial_plane_vblank_wait(struct intel_crtc *crtc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc);
|
||||
|
||||
display->parent->initial_plane->vblank_wait(&crtc->base);
|
||||
}
|
||||
|
||||
static const struct intel_plane_state *
|
||||
intel_reuse_initial_plane_obj(struct intel_crtc *this,
|
||||
const struct intel_initial_plane_config plane_configs[])
|
||||
{
|
||||
struct intel_display *display = to_intel_display(this);
|
||||
struct intel_crtc *crtc;
|
||||
|
||||
for_each_intel_crtc(display->drm, crtc) {
|
||||
struct intel_plane *plane =
|
||||
to_intel_plane(crtc->base.primary);
|
||||
const struct intel_plane_state *plane_state =
|
||||
to_intel_plane_state(plane->base.state);
|
||||
const struct intel_crtc_state *crtc_state =
|
||||
to_intel_crtc_state(crtc->base.state);
|
||||
|
||||
if (!crtc_state->hw.active)
|
||||
continue;
|
||||
|
||||
if (!plane_state->ggtt_vma)
|
||||
continue;
|
||||
|
||||
if (plane_configs[this->pipe].base == plane_configs[crtc->pipe].base)
|
||||
return plane_state;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct drm_gem_object *
|
||||
intel_alloc_initial_plane_obj(struct intel_display *display,
|
||||
struct intel_initial_plane_config *plane_config)
|
||||
{
|
||||
struct intel_framebuffer *fb = plane_config->fb;
|
||||
|
||||
switch (fb->base.modifier) {
|
||||
case DRM_FORMAT_MOD_LINEAR:
|
||||
case I915_FORMAT_MOD_X_TILED:
|
||||
case I915_FORMAT_MOD_Y_TILED:
|
||||
case I915_FORMAT_MOD_4_TILED:
|
||||
break;
|
||||
default:
|
||||
drm_dbg_kms(display->drm, "Unsupported modifier for initial FB: 0x%llx\n",
|
||||
fb->base.modifier);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return display->parent->initial_plane->alloc_obj(display->drm, plane_config);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_find_initial_plane_obj(struct intel_crtc *crtc,
|
||||
struct intel_initial_plane_config plane_configs[])
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc);
|
||||
struct intel_initial_plane_config *plane_config = &plane_configs[crtc->pipe];
|
||||
struct intel_plane *plane = to_intel_plane(crtc->base.primary);
|
||||
struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state);
|
||||
struct drm_framebuffer *fb;
|
||||
struct i915_vma *vma;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* Disable planes if get_initial_plane_config() failed.
|
||||
* Make sure things work if the surface base is not page aligned.
|
||||
*/
|
||||
if (!plane_config->fb)
|
||||
return;
|
||||
|
||||
if (intel_alloc_initial_plane_obj(display, plane_config)) {
|
||||
fb = &plane_config->fb->base;
|
||||
vma = plane_config->vma;
|
||||
} else {
|
||||
const struct intel_plane_state *other_plane_state;
|
||||
|
||||
other_plane_state = intel_reuse_initial_plane_obj(crtc, plane_configs);
|
||||
if (!other_plane_state)
|
||||
goto nofb;
|
||||
|
||||
fb = other_plane_state->hw.fb;
|
||||
vma = other_plane_state->ggtt_vma;
|
||||
}
|
||||
|
||||
plane_state->uapi.rotation = plane_config->rotation;
|
||||
intel_fb_fill_view(to_intel_framebuffer(fb),
|
||||
plane_state->uapi.rotation, &plane_state->view);
|
||||
|
||||
ret = display->parent->initial_plane->setup(plane->base.state, plane_config, fb, vma);
|
||||
if (ret)
|
||||
goto nofb;
|
||||
|
||||
plane_state->uapi.src_x = 0;
|
||||
plane_state->uapi.src_y = 0;
|
||||
plane_state->uapi.src_w = fb->width << 16;
|
||||
plane_state->uapi.src_h = fb->height << 16;
|
||||
|
||||
plane_state->uapi.crtc_x = 0;
|
||||
plane_state->uapi.crtc_y = 0;
|
||||
plane_state->uapi.crtc_w = fb->width;
|
||||
plane_state->uapi.crtc_h = fb->height;
|
||||
|
||||
plane_state->uapi.fb = fb;
|
||||
drm_framebuffer_get(fb);
|
||||
|
||||
plane_state->uapi.crtc = &crtc->base;
|
||||
intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc);
|
||||
|
||||
atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits);
|
||||
|
||||
return;
|
||||
|
||||
nofb:
|
||||
/*
|
||||
* We've failed to reconstruct the BIOS FB. Current display state
|
||||
* indicates that the primary plane is visible, but has a NULL FB,
|
||||
* which will lead to problems later if we don't fix it up. The
|
||||
* simplest solution is to just disable the primary plane now and
|
||||
* pretend the BIOS never had it enabled.
|
||||
*/
|
||||
intel_plane_disable_noatomic(crtc, plane);
|
||||
}
|
||||
|
||||
static void plane_config_fini(struct intel_display *display,
|
||||
struct intel_initial_plane_config *plane_config)
|
||||
{
|
||||
if (plane_config->fb) {
|
||||
struct drm_framebuffer *fb = &plane_config->fb->base;
|
||||
|
||||
/* We may only have the stub and not a full framebuffer */
|
||||
if (drm_framebuffer_read_refcount(fb))
|
||||
drm_framebuffer_put(fb);
|
||||
else
|
||||
kfree(fb);
|
||||
}
|
||||
|
||||
display->parent->initial_plane->config_fini(plane_config);
|
||||
}
|
||||
|
||||
void intel_initial_plane_config(struct intel_display *display)
|
||||
{
|
||||
struct intel_initial_plane_config plane_configs[I915_MAX_PIPES] = {};
|
||||
struct intel_crtc *crtc;
|
||||
|
||||
for_each_intel_crtc(display->drm, crtc) {
|
||||
const struct intel_crtc_state *crtc_state =
|
||||
to_intel_crtc_state(crtc->base.state);
|
||||
struct intel_initial_plane_config *plane_config =
|
||||
&plane_configs[crtc->pipe];
|
||||
|
||||
if (!crtc_state->hw.active)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Note that reserving the BIOS fb up front prevents us
|
||||
* from stuffing other stolen allocations like the ring
|
||||
* on top. This prevents some ugliness at boot time, and
|
||||
* can even allow for smooth boot transitions if the BIOS
|
||||
* fb is large enough for the active pipe configuration.
|
||||
*/
|
||||
display->funcs.display->get_initial_plane_config(crtc, plane_config);
|
||||
|
||||
/*
|
||||
* If the fb is shared between multiple heads, we'll
|
||||
* just get the first one.
|
||||
*/
|
||||
intel_find_initial_plane_obj(crtc, plane_configs);
|
||||
|
||||
if (display->funcs.display->fixup_initial_plane_config(crtc, plane_config))
|
||||
intel_initial_plane_vblank_wait(crtc);
|
||||
|
||||
plane_config_fini(display, plane_config);
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,13 @@
|
||||
* Copyright © 2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __INTEL_PLANE_INITIAL_H__
|
||||
#define __INTEL_PLANE_INITIAL_H__
|
||||
#ifndef __INTEL_INITIAL_PLANE_H__
|
||||
#define __INTEL_INITIAL_PLANE_H__
|
||||
|
||||
struct intel_crtc;
|
||||
struct intel_display;
|
||||
|
||||
void intel_initial_plane_config(struct intel_display *display);
|
||||
void intel_plane_initial_vblank_wait(struct intel_crtc *crtc);
|
||||
void intel_initial_plane_vblank_wait(struct intel_crtc *crtc);
|
||||
|
||||
#endif
|
||||
@@ -31,6 +31,7 @@
|
||||
#define INTEL_LT_PHY_BOTH_LANES (INTEL_LT_PHY_LANE1 |\
|
||||
INTEL_LT_PHY_LANE0)
|
||||
#define MODE_DP 3
|
||||
#define MODE_HDMI_20 4
|
||||
#define Q32_TO_INT(x) ((x) >> 32)
|
||||
#define Q32_TO_FRAC(x) ((x) & 0xFFFFFFFF)
|
||||
#define DCO_MIN_FREQ_MHZ 11850
|
||||
@@ -1751,6 +1752,7 @@ int
|
||||
intel_lt_phy_calc_port_clock(struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(encoder);
|
||||
int clk;
|
||||
const struct intel_lt_phy_pll_state *lt_state =
|
||||
&crtc_state->dpll_hw_state.ltpll;
|
||||
@@ -1768,8 +1770,11 @@ intel_lt_phy_calc_port_clock(struct intel_encoder *encoder,
|
||||
rate = REG_FIELD_GET8(LT_PHY_VDR_RATE_ENCODING_MASK,
|
||||
lt_state->config[0]);
|
||||
clk = intel_lt_phy_get_dp_clock(rate);
|
||||
} else {
|
||||
} else if (mode == MODE_HDMI_20) {
|
||||
clk = intel_lt_phy_calc_hdmi_port_clock(crtc_state);
|
||||
} else {
|
||||
drm_WARN_ON(display->drm, "Unsupported LT PHY Mode!\n");
|
||||
clk = xe3plpd_lt_hdmi_252.clock;
|
||||
}
|
||||
|
||||
return clk;
|
||||
@@ -2207,13 +2212,18 @@ bool
|
||||
intel_lt_phy_pll_compare_hw_state(const struct intel_lt_phy_pll_state *a,
|
||||
const struct intel_lt_phy_pll_state *b)
|
||||
{
|
||||
if (memcmp(&a->config, &b->config, sizeof(a->config)) != 0)
|
||||
return false;
|
||||
/*
|
||||
* With LT PHY values other than VDR0_CONFIG and VDR2_CONFIG are
|
||||
* unreliable. They cannot always be read back since internally
|
||||
* after power gating values are not restored back to the
|
||||
* shadow VDR registers. Thus we do not compare the whole state
|
||||
* just the two VDR registers.
|
||||
*/
|
||||
if (a->config[0] == b->config[0] &&
|
||||
a->config[2] == b->config[2])
|
||||
return true;
|
||||
|
||||
if (memcmp(&a->data, &b->data, sizeof(a->data)) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder,
|
||||
@@ -2259,8 +2269,6 @@ void intel_lt_phy_pll_state_verify(struct intel_atomic_state *state,
|
||||
struct intel_encoder *encoder;
|
||||
struct intel_lt_phy_pll_state pll_hw_state = {};
|
||||
const struct intel_lt_phy_pll_state *pll_sw_state = &new_crtc_state->dpll_hw_state.ltpll;
|
||||
int clock;
|
||||
int i, j;
|
||||
|
||||
if (DISPLAY_VER(display) < 35)
|
||||
return;
|
||||
@@ -2275,33 +2283,19 @@ void intel_lt_phy_pll_state_verify(struct intel_atomic_state *state,
|
||||
|
||||
encoder = intel_get_crtc_new_encoder(state, new_crtc_state);
|
||||
intel_lt_phy_pll_readout_hw_state(encoder, new_crtc_state, &pll_hw_state);
|
||||
clock = intel_lt_phy_calc_port_clock(encoder, new_crtc_state);
|
||||
|
||||
dig_port = enc_to_dig_port(encoder);
|
||||
if (intel_tc_port_in_tbt_alt_mode(dig_port))
|
||||
return;
|
||||
|
||||
INTEL_DISPLAY_STATE_WARN(display, pll_hw_state.clock != clock,
|
||||
"[CRTC:%d:%s] mismatch in LT PHY: Register CLOCK (expected %d, found %d)",
|
||||
INTEL_DISPLAY_STATE_WARN(display, pll_hw_state.config[0] != pll_sw_state->config[0],
|
||||
"[CRTC:%d:%s] mismatch in LT PHY PLL CONFIG 0: (expected 0x%04x, found 0x%04x)",
|
||||
crtc->base.base.id, crtc->base.name,
|
||||
pll_sw_state->clock, pll_hw_state.clock);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
INTEL_DISPLAY_STATE_WARN(display, pll_hw_state.config[i] != pll_sw_state->config[i],
|
||||
"[CRTC:%d:%s] mismatch in LT PHY PLL CONFIG%d: (expected 0x%04x, found 0x%04x)",
|
||||
crtc->base.base.id, crtc->base.name, i,
|
||||
pll_sw_state->config[i], pll_hw_state.config[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i <= 12; i++) {
|
||||
for (j = 3; j >= 0; j--)
|
||||
INTEL_DISPLAY_STATE_WARN(display,
|
||||
pll_hw_state.data[i][j] !=
|
||||
pll_sw_state->data[i][j],
|
||||
"[CRTC:%d:%s] mismatch in LT PHY PLL DATA[%d][%d]: (expected 0x%04x, found 0x%04x)",
|
||||
crtc->base.base.id, crtc->base.name, i, j,
|
||||
pll_sw_state->data[i][j], pll_hw_state.data[i][j]);
|
||||
}
|
||||
pll_sw_state->config[0], pll_hw_state.config[0]);
|
||||
INTEL_DISPLAY_STATE_WARN(display, pll_hw_state.config[2] != pll_sw_state->config[2],
|
||||
"[CRTC:%d:%s] mismatch in LT PHY PLL CONFIG 2: (expected 0x%04x, found 0x%04x)",
|
||||
crtc->base.base.id, crtc->base.name,
|
||||
pll_sw_state->config[2], pll_hw_state.config[2]);
|
||||
}
|
||||
|
||||
void intel_xe3plpd_pll_enable(struct intel_encoder *encoder,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,442 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright © 2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "gem/i915_gem_lmem.h"
|
||||
#include "gem/i915_gem_region.h"
|
||||
#include "i915_drv.h"
|
||||
#include "intel_crtc.h"
|
||||
#include "intel_display.h"
|
||||
#include "intel_display_core.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_fb.h"
|
||||
#include "intel_frontbuffer.h"
|
||||
#include "intel_plane.h"
|
||||
#include "intel_plane_initial.h"
|
||||
|
||||
void intel_plane_initial_vblank_wait(struct intel_crtc *crtc)
|
||||
{
|
||||
intel_crtc_wait_for_next_vblank(crtc);
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_reuse_initial_plane_obj(struct intel_crtc *this,
|
||||
const struct intel_initial_plane_config plane_configs[],
|
||||
struct drm_framebuffer **fb,
|
||||
struct i915_vma **vma)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(this);
|
||||
struct intel_crtc *crtc;
|
||||
|
||||
for_each_intel_crtc(display->drm, crtc) {
|
||||
struct intel_plane *plane =
|
||||
to_intel_plane(crtc->base.primary);
|
||||
const struct intel_plane_state *plane_state =
|
||||
to_intel_plane_state(plane->base.state);
|
||||
const struct intel_crtc_state *crtc_state =
|
||||
to_intel_crtc_state(crtc->base.state);
|
||||
|
||||
if (!crtc_state->hw.active)
|
||||
continue;
|
||||
|
||||
if (!plane_state->ggtt_vma)
|
||||
continue;
|
||||
|
||||
if (plane_configs[this->pipe].base == plane_configs[crtc->pipe].base) {
|
||||
*fb = plane_state->hw.fb;
|
||||
*vma = plane_state->ggtt_vma;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum intel_memory_type
|
||||
initial_plane_memory_type(struct intel_display *display)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
|
||||
if (display->platform.dgfx)
|
||||
return INTEL_MEMORY_LOCAL;
|
||||
else if (HAS_LMEMBAR_SMEM_STOLEN(i915))
|
||||
return INTEL_MEMORY_STOLEN_LOCAL;
|
||||
else
|
||||
return INTEL_MEMORY_STOLEN_SYSTEM;
|
||||
}
|
||||
|
||||
static bool
|
||||
initial_plane_phys(struct intel_display *display,
|
||||
struct intel_initial_plane_config *plane_config)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
|
||||
struct intel_memory_region *mem;
|
||||
enum intel_memory_type mem_type;
|
||||
bool is_present, is_local;
|
||||
dma_addr_t dma_addr;
|
||||
u32 base;
|
||||
|
||||
mem_type = initial_plane_memory_type(display);
|
||||
mem = intel_memory_region_by_type(i915, mem_type);
|
||||
if (!mem) {
|
||||
drm_dbg_kms(display->drm,
|
||||
"Initial plane memory region (type %s) not initialized\n",
|
||||
intel_memory_type_str(mem_type));
|
||||
return false;
|
||||
}
|
||||
|
||||
base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT);
|
||||
|
||||
dma_addr = intel_ggtt_read_entry(&ggtt->vm, base, &is_present, &is_local);
|
||||
|
||||
if (!is_present) {
|
||||
drm_err(display->drm,
|
||||
"Initial plane FB PTE not present\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (intel_memory_type_is_local(mem->type) != is_local) {
|
||||
drm_err(display->drm,
|
||||
"Initial plane FB PTE unsuitable for %s\n",
|
||||
mem->region.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dma_addr < mem->region.start || dma_addr > mem->region.end) {
|
||||
drm_err(display->drm,
|
||||
"Initial plane programming using invalid range, dma_addr=%pa (%s [%pa-%pa])\n",
|
||||
&dma_addr, mem->region.name, &mem->region.start, &mem->region.end);
|
||||
return false;
|
||||
}
|
||||
|
||||
drm_dbg(display->drm,
|
||||
"Using dma_addr=%pa, based on initial plane programming\n",
|
||||
&dma_addr);
|
||||
|
||||
plane_config->phys_base = dma_addr - mem->region.start;
|
||||
plane_config->mem = mem;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct i915_vma *
|
||||
initial_plane_vma(struct intel_display *display,
|
||||
struct intel_initial_plane_config *plane_config)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
struct intel_memory_region *mem;
|
||||
struct drm_i915_gem_object *obj;
|
||||
struct drm_mm_node orig_mm = {};
|
||||
struct i915_vma *vma;
|
||||
resource_size_t phys_base;
|
||||
unsigned int tiling;
|
||||
u32 base, size;
|
||||
u64 pinctl;
|
||||
|
||||
if (plane_config->size == 0)
|
||||
return NULL;
|
||||
|
||||
if (!initial_plane_phys(display, plane_config))
|
||||
return NULL;
|
||||
|
||||
phys_base = plane_config->phys_base;
|
||||
mem = plane_config->mem;
|
||||
|
||||
base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT);
|
||||
size = round_up(plane_config->base + plane_config->size,
|
||||
mem->min_page_size);
|
||||
size -= base;
|
||||
|
||||
/*
|
||||
* If the FB is too big, just don't use it since fbdev is not very
|
||||
* important and we should probably use that space with FBC or other
|
||||
* features.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) &&
|
||||
mem == i915->mm.stolen_region &&
|
||||
size * 2 > i915->dsm.usable_size) {
|
||||
drm_dbg_kms(display->drm, "Initial FB size exceeds half of stolen, discarding\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj = i915_gem_object_create_region_at(mem, phys_base, size,
|
||||
I915_BO_ALLOC_USER |
|
||||
I915_BO_PREALLOC);
|
||||
if (IS_ERR(obj)) {
|
||||
drm_dbg_kms(display->drm, "Failed to preallocate initial FB in %s\n",
|
||||
mem->region.name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark it WT ahead of time to avoid changing the
|
||||
* cache_level during fbdev initialization. The
|
||||
* unbind there would get stuck waiting for rcu.
|
||||
*/
|
||||
i915_gem_object_set_cache_coherency(obj, HAS_WT(i915) ?
|
||||
I915_CACHE_WT : I915_CACHE_NONE);
|
||||
|
||||
tiling = intel_fb_modifier_to_tiling(plane_config->fb->base.modifier);
|
||||
|
||||
switch (tiling) {
|
||||
case I915_TILING_NONE:
|
||||
break;
|
||||
case I915_TILING_X:
|
||||
case I915_TILING_Y:
|
||||
obj->tiling_and_stride =
|
||||
plane_config->fb->base.pitches[0] |
|
||||
tiling;
|
||||
break;
|
||||
default:
|
||||
MISSING_CASE(tiling);
|
||||
goto err_obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* MTL GOP likes to place the framebuffer high up in ggtt,
|
||||
* which can cause problems for ggtt_reserve_guc_top().
|
||||
* Try to pin it to a low ggtt address instead to avoid that.
|
||||
*/
|
||||
base = 0;
|
||||
|
||||
if (base != plane_config->base) {
|
||||
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Make sure the original and new locations
|
||||
* can't overlap. That would corrupt the original
|
||||
* PTEs which are still being used for scanout.
|
||||
*/
|
||||
ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &orig_mm,
|
||||
size, plane_config->base,
|
||||
I915_COLOR_UNEVICTABLE, PIN_NOEVICT);
|
||||
if (ret)
|
||||
goto err_obj;
|
||||
}
|
||||
|
||||
vma = i915_vma_instance(obj, &to_gt(i915)->ggtt->vm, NULL);
|
||||
if (IS_ERR(vma))
|
||||
goto err_obj;
|
||||
|
||||
retry:
|
||||
pinctl = PIN_GLOBAL | PIN_OFFSET_FIXED | base;
|
||||
if (!i915_gem_object_is_lmem(obj))
|
||||
pinctl |= PIN_MAPPABLE;
|
||||
if (i915_vma_pin(vma, 0, 0, pinctl)) {
|
||||
if (drm_mm_node_allocated(&orig_mm)) {
|
||||
drm_mm_remove_node(&orig_mm);
|
||||
/*
|
||||
* Try again, but this time pin
|
||||
* it to its original location.
|
||||
*/
|
||||
base = plane_config->base;
|
||||
goto retry;
|
||||
}
|
||||
goto err_obj;
|
||||
}
|
||||
|
||||
if (i915_gem_object_is_tiled(obj) &&
|
||||
!i915_vma_is_map_and_fenceable(vma))
|
||||
goto err_obj;
|
||||
|
||||
if (drm_mm_node_allocated(&orig_mm))
|
||||
drm_mm_remove_node(&orig_mm);
|
||||
|
||||
drm_dbg_kms(display->drm,
|
||||
"Initial plane fb bound to 0x%x in the ggtt (original 0x%x)\n",
|
||||
i915_ggtt_offset(vma), plane_config->base);
|
||||
|
||||
return vma;
|
||||
|
||||
err_obj:
|
||||
if (drm_mm_node_allocated(&orig_mm))
|
||||
drm_mm_remove_node(&orig_mm);
|
||||
i915_gem_object_put(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
|
||||
struct intel_initial_plane_config *plane_config)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc);
|
||||
struct drm_mode_fb_cmd2 mode_cmd = {};
|
||||
struct drm_framebuffer *fb = &plane_config->fb->base;
|
||||
struct i915_vma *vma;
|
||||
|
||||
switch (fb->modifier) {
|
||||
case DRM_FORMAT_MOD_LINEAR:
|
||||
case I915_FORMAT_MOD_X_TILED:
|
||||
case I915_FORMAT_MOD_Y_TILED:
|
||||
case I915_FORMAT_MOD_4_TILED:
|
||||
break;
|
||||
default:
|
||||
drm_dbg(display->drm,
|
||||
"Unsupported modifier for initial FB: 0x%llx\n",
|
||||
fb->modifier);
|
||||
return false;
|
||||
}
|
||||
|
||||
vma = initial_plane_vma(display, plane_config);
|
||||
if (!vma)
|
||||
return false;
|
||||
|
||||
mode_cmd.pixel_format = fb->format->format;
|
||||
mode_cmd.width = fb->width;
|
||||
mode_cmd.height = fb->height;
|
||||
mode_cmd.pitches[0] = fb->pitches[0];
|
||||
mode_cmd.modifier[0] = fb->modifier;
|
||||
mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
|
||||
|
||||
if (intel_framebuffer_init(to_intel_framebuffer(fb),
|
||||
intel_bo_to_drm_bo(vma->obj),
|
||||
fb->format, &mode_cmd)) {
|
||||
drm_dbg_kms(display->drm, "intel fb init failed\n");
|
||||
goto err_vma;
|
||||
}
|
||||
|
||||
plane_config->vma = vma;
|
||||
return true;
|
||||
|
||||
err_vma:
|
||||
i915_vma_put(vma);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_find_initial_plane_obj(struct intel_crtc *crtc,
|
||||
struct intel_initial_plane_config plane_configs[])
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||
struct intel_initial_plane_config *plane_config =
|
||||
&plane_configs[crtc->pipe];
|
||||
struct intel_plane *plane =
|
||||
to_intel_plane(crtc->base.primary);
|
||||
struct intel_plane_state *plane_state =
|
||||
to_intel_plane_state(plane->base.state);
|
||||
struct drm_framebuffer *fb;
|
||||
struct i915_vma *vma;
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* Disable planes if get_initial_plane_config() failed.
|
||||
* Make sure things work if the surface base is not page aligned.
|
||||
*/
|
||||
if (!plane_config->fb)
|
||||
return;
|
||||
|
||||
if (intel_alloc_initial_plane_obj(crtc, plane_config)) {
|
||||
fb = &plane_config->fb->base;
|
||||
vma = plane_config->vma;
|
||||
goto valid_fb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Failed to alloc the obj, check to see if we should share
|
||||
* an fb with another CRTC instead
|
||||
*/
|
||||
if (intel_reuse_initial_plane_obj(crtc, plane_configs, &fb, &vma))
|
||||
goto valid_fb;
|
||||
|
||||
/*
|
||||
* We've failed to reconstruct the BIOS FB. Current display state
|
||||
* indicates that the primary plane is visible, but has a NULL FB,
|
||||
* which will lead to problems later if we don't fix it up. The
|
||||
* simplest solution is to just disable the primary plane now and
|
||||
* pretend the BIOS never had it enabled.
|
||||
*/
|
||||
intel_plane_disable_noatomic(crtc, plane);
|
||||
|
||||
return;
|
||||
|
||||
valid_fb:
|
||||
plane_state->uapi.rotation = plane_config->rotation;
|
||||
intel_fb_fill_view(to_intel_framebuffer(fb),
|
||||
plane_state->uapi.rotation, &plane_state->view);
|
||||
|
||||
__i915_vma_pin(vma);
|
||||
plane_state->ggtt_vma = i915_vma_get(vma);
|
||||
if (intel_plane_uses_fence(plane_state) &&
|
||||
i915_vma_pin_fence(vma) == 0 && vma->fence)
|
||||
plane_state->flags |= PLANE_HAS_FENCE;
|
||||
|
||||
plane_state->surf = i915_ggtt_offset(plane_state->ggtt_vma);
|
||||
|
||||
plane_state->uapi.src_x = 0;
|
||||
plane_state->uapi.src_y = 0;
|
||||
plane_state->uapi.src_w = fb->width << 16;
|
||||
plane_state->uapi.src_h = fb->height << 16;
|
||||
|
||||
plane_state->uapi.crtc_x = 0;
|
||||
plane_state->uapi.crtc_y = 0;
|
||||
plane_state->uapi.crtc_w = fb->width;
|
||||
plane_state->uapi.crtc_h = fb->height;
|
||||
|
||||
if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
|
||||
dev_priv->preserve_bios_swizzle = true;
|
||||
|
||||
plane_state->uapi.fb = fb;
|
||||
drm_framebuffer_get(fb);
|
||||
|
||||
plane_state->uapi.crtc = &crtc->base;
|
||||
intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc);
|
||||
|
||||
atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits);
|
||||
}
|
||||
|
||||
static void plane_config_fini(struct intel_initial_plane_config *plane_config)
|
||||
{
|
||||
if (plane_config->fb) {
|
||||
struct drm_framebuffer *fb = &plane_config->fb->base;
|
||||
|
||||
/* We may only have the stub and not a full framebuffer */
|
||||
if (drm_framebuffer_read_refcount(fb))
|
||||
drm_framebuffer_put(fb);
|
||||
else
|
||||
kfree(fb);
|
||||
}
|
||||
|
||||
if (plane_config->vma)
|
||||
i915_vma_put(plane_config->vma);
|
||||
}
|
||||
|
||||
void intel_initial_plane_config(struct intel_display *display)
|
||||
{
|
||||
struct intel_initial_plane_config plane_configs[I915_MAX_PIPES] = {};
|
||||
struct intel_crtc *crtc;
|
||||
|
||||
for_each_intel_crtc(display->drm, crtc) {
|
||||
const struct intel_crtc_state *crtc_state =
|
||||
to_intel_crtc_state(crtc->base.state);
|
||||
struct intel_initial_plane_config *plane_config =
|
||||
&plane_configs[crtc->pipe];
|
||||
|
||||
if (!crtc_state->hw.active)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Note that reserving the BIOS fb up front prevents us
|
||||
* from stuffing other stolen allocations like the ring
|
||||
* on top. This prevents some ugliness at boot time, and
|
||||
* can even allow for smooth boot transitions if the BIOS
|
||||
* fb is large enough for the active pipe configuration.
|
||||
*/
|
||||
display->funcs.display->get_initial_plane_config(crtc, plane_config);
|
||||
|
||||
/*
|
||||
* If the fb is shared between multiple heads, we'll
|
||||
* just get the first one.
|
||||
*/
|
||||
intel_find_initial_plane_obj(crtc, plane_configs);
|
||||
|
||||
if (display->funcs.display->fixup_initial_plane_config(crtc, plane_config))
|
||||
intel_plane_initial_vblank_wait(crtc);
|
||||
|
||||
plane_config_fini(plane_config);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,10 @@
|
||||
* Copyright © 2024 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <drm/drm_device.h>
|
||||
|
||||
#include "i915_reg.h"
|
||||
|
||||
#include "intel_rom.h"
|
||||
@@ -41,7 +44,6 @@ static u16 spi_read16(struct intel_rom *rom, loff_t offset)
|
||||
|
||||
struct intel_rom *intel_rom_spi(struct drm_device *drm)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(drm);
|
||||
struct intel_rom *rom;
|
||||
u32 static_region;
|
||||
|
||||
@@ -49,7 +51,7 @@ struct intel_rom *intel_rom_spi(struct drm_device *drm)
|
||||
if (!rom)
|
||||
return NULL;
|
||||
|
||||
rom->uncore = &i915->uncore;
|
||||
rom->uncore = to_intel_uncore(drm);
|
||||
|
||||
static_region = intel_uncore_read(rom->uncore, SPI_STATIC_REGIONS);
|
||||
static_region &= OPTIONROM_SPI_REGIONID_MASK;
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "intel_color.h"
|
||||
#include "intel_crtc.h"
|
||||
#include "intel_de.h"
|
||||
@@ -305,17 +304,17 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
|
||||
*/
|
||||
#ifdef I915
|
||||
static void intel_vblank_section_enter(struct intel_display *display)
|
||||
__acquires(i915->uncore.lock)
|
||||
__acquires(uncore->lock)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
spin_lock(&i915->uncore.lock);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
spin_lock(&uncore->lock);
|
||||
}
|
||||
|
||||
static void intel_vblank_section_exit(struct intel_display *display)
|
||||
__releases(i915->uncore.lock)
|
||||
__releases(uncore->lock)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(display->drm);
|
||||
spin_unlock(&i915->uncore.lock);
|
||||
struct intel_uncore *uncore = to_intel_uncore(display->drm);
|
||||
spin_unlock(&uncore->lock);
|
||||
}
|
||||
#else
|
||||
static void intel_vblank_section_enter(struct intel_display *display)
|
||||
@@ -652,6 +651,34 @@ intel_pre_commit_crtc_state(struct intel_atomic_state *state,
|
||||
return pre_commit_crtc_state(old_crtc_state, new_crtc_state);
|
||||
}
|
||||
|
||||
static int vrr_vblank_start(const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
bool is_push_sent = intel_vrr_is_push_sent(crtc_state);
|
||||
int vblank_start;
|
||||
|
||||
if (!crtc_state->vrr.dc_balance.enable) {
|
||||
if (is_push_sent)
|
||||
return intel_vrr_vmin_vblank_start(crtc_state);
|
||||
else
|
||||
return intel_vrr_vmax_vblank_start(crtc_state);
|
||||
}
|
||||
|
||||
if (is_push_sent)
|
||||
vblank_start = intel_vrr_dcb_vmin_vblank_start_next(crtc_state);
|
||||
else
|
||||
vblank_start = intel_vrr_dcb_vmax_vblank_start_next(crtc_state);
|
||||
|
||||
if (vblank_start >= 0)
|
||||
return vblank_start;
|
||||
|
||||
if (is_push_sent)
|
||||
vblank_start = intel_vrr_dcb_vmin_vblank_start_final(crtc_state);
|
||||
else
|
||||
vblank_start = intel_vrr_dcb_vmax_vblank_start_final(crtc_state);
|
||||
|
||||
return vblank_start;
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -678,10 +705,7 @@ void intel_vblank_evade_init(const struct intel_crtc_state *old_crtc_state,
|
||||
drm_WARN_ON(crtc->base.dev, intel_crtc_needs_modeset(new_crtc_state) ||
|
||||
new_crtc_state->update_m_n || new_crtc_state->update_lrr);
|
||||
|
||||
if (intel_vrr_is_push_sent(crtc_state))
|
||||
evade->vblank_start = intel_vrr_vmin_vblank_start(crtc_state);
|
||||
else
|
||||
evade->vblank_start = intel_vrr_vmax_vblank_start(crtc_state);
|
||||
evade->vblank_start = vrr_vblank_start(crtc_state);
|
||||
|
||||
vblank_delay = crtc_state->set_context_latency;
|
||||
} else {
|
||||
|
||||
@@ -1050,15 +1050,40 @@ void intel_vdsc_state_dump(struct drm_printer *p, int indent,
|
||||
drm_dsc_dump_config(p, indent, &crtc_state->dsc.config);
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dsc_get_pixel_rate_with_dsc_bubbles(struct intel_display *display,
|
||||
int pixel_rate, int htotal,
|
||||
int dsc_horizontal_slices)
|
||||
{
|
||||
int dsc_slice_bubbles;
|
||||
u64 num;
|
||||
|
||||
if (drm_WARN_ON(display->drm, !htotal))
|
||||
return pixel_rate;
|
||||
|
||||
dsc_slice_bubbles = 14 * dsc_horizontal_slices;
|
||||
num = mul_u32_u32(pixel_rate, (htotal + dsc_slice_bubbles));
|
||||
|
||||
return DIV_ROUND_UP_ULL(num, htotal);
|
||||
}
|
||||
|
||||
int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state);
|
||||
int htotal = crtc_state->hw.adjusted_mode.crtc_htotal;
|
||||
int dsc_slices = crtc_state->dsc.slice_count;
|
||||
int pixel_rate;
|
||||
int min_cdclk;
|
||||
|
||||
if (!crtc_state->dsc.compression_enable)
|
||||
return 0;
|
||||
|
||||
pixel_rate = intel_dsc_get_pixel_rate_with_dsc_bubbles(display,
|
||||
crtc_state->pixel_rate,
|
||||
htotal,
|
||||
dsc_slices);
|
||||
|
||||
/*
|
||||
* When we decide to use only one VDSC engine, since
|
||||
* each VDSC operates with 1 ppc throughput, pixel clock
|
||||
@@ -1066,7 +1091,7 @@ int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state)
|
||||
* If there 2 VDSC engines, then pixel clock can't be higher than
|
||||
* VDSC clock(cdclk) * 2 and so on.
|
||||
*/
|
||||
min_cdclk = DIV_ROUND_UP(crtc_state->pixel_rate, num_vdsc_instances);
|
||||
min_cdclk = DIV_ROUND_UP(pixel_rate, num_vdsc_instances);
|
||||
|
||||
if (crtc_state->joiner_pipes) {
|
||||
int pixel_clock = intel_dp_mode_to_fec_clock(crtc_state->hw.adjusted_mode.clock);
|
||||
@@ -1084,9 +1109,11 @@ int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state)
|
||||
* => CDCLK >= compressed_bpp * Pixel clock / 2 * Bigjoiner Interface bits
|
||||
*/
|
||||
int bigjoiner_interface_bits = DISPLAY_VER(display) >= 14 ? 36 : 24;
|
||||
int min_cdclk_bj =
|
||||
(fxp_q4_to_int_roundup(crtc_state->dsc.compressed_bpp_x16) *
|
||||
pixel_clock) / (2 * bigjoiner_interface_bits);
|
||||
int adjusted_pixel_rate =
|
||||
intel_dsc_get_pixel_rate_with_dsc_bubbles(display, pixel_clock,
|
||||
htotal, dsc_slices);
|
||||
int min_cdclk_bj = (fxp_q4_to_int_roundup(crtc_state->dsc.compressed_bpp_x16) *
|
||||
adjusted_pixel_rate) / (2 * bigjoiner_interface_bits);
|
||||
|
||||
min_cdclk = max(min_cdclk, min_cdclk_bj);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "intel_crtc.h"
|
||||
#include "intel_de.h"
|
||||
#include "intel_display_regs.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_dmc.h"
|
||||
#include "intel_dmc_regs.h"
|
||||
#include "intel_dp.h"
|
||||
#include "intel_psr.h"
|
||||
#include "intel_vrr.h"
|
||||
@@ -19,6 +22,14 @@
|
||||
#define FIXED_POINT_PRECISION 100
|
||||
#define CMRR_PRECISION_TOLERANCE 10
|
||||
|
||||
/*
|
||||
* Tunable parameters for DC Balance correction.
|
||||
* These are captured based on experimentations.
|
||||
*/
|
||||
#define DCB_CORRECTION_SENSITIVITY 30
|
||||
#define DCB_CORRECTION_AGGRESSIVENESS 1000 /* ms × 100; 10 ms */
|
||||
#define DCB_BLANK_TARGET 50
|
||||
|
||||
bool intel_vrr_is_capable(struct intel_connector *connector)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(connector);
|
||||
@@ -261,6 +272,12 @@ static int intel_vrr_hw_value(const struct intel_crtc_state *crtc_state,
|
||||
return value - crtc_state->set_context_latency;
|
||||
}
|
||||
|
||||
static int intel_vrr_vblank_start(const struct intel_crtc_state *crtc_state,
|
||||
int vmin_vmax)
|
||||
{
|
||||
return intel_vrr_hw_value(crtc_state, vmin_vmax) - crtc_state->vrr.guardband;
|
||||
}
|
||||
|
||||
/*
|
||||
* For fixed refresh rate mode Vmin, Vmax and Flipline all are set to
|
||||
* Vtotal value.
|
||||
@@ -335,6 +352,56 @@ int intel_vrr_compute_vmax(struct intel_connector *connector,
|
||||
return vmax;
|
||||
}
|
||||
|
||||
static bool intel_vrr_dc_balance_possible(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);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
|
||||
/*
|
||||
* FIXME: Currently Firmware supports DC Balancing on PIPE A
|
||||
* and PIPE B. Account those limitation while computing DC
|
||||
* Balance parameters.
|
||||
*/
|
||||
return (HAS_VRR_DC_BALANCE(display) &&
|
||||
((pipe == PIPE_A) || (pipe == PIPE_B)));
|
||||
}
|
||||
|
||||
static void
|
||||
intel_vrr_dc_balance_compute_config(struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
int guardband_usec, adjustment_usec;
|
||||
struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
|
||||
|
||||
if (!intel_vrr_dc_balance_possible(crtc_state) || !crtc_state->vrr.enable)
|
||||
return;
|
||||
|
||||
crtc_state->vrr.dc_balance.vmax = crtc_state->vrr.vmax;
|
||||
crtc_state->vrr.dc_balance.vmin = crtc_state->vrr.vmin;
|
||||
crtc_state->vrr.dc_balance.max_increase =
|
||||
crtc_state->vrr.vmax - crtc_state->vrr.vmin;
|
||||
crtc_state->vrr.dc_balance.max_decrease =
|
||||
crtc_state->vrr.vmax - crtc_state->vrr.vmin;
|
||||
crtc_state->vrr.dc_balance.guardband =
|
||||
DIV_ROUND_UP(crtc_state->vrr.dc_balance.vmax *
|
||||
DCB_CORRECTION_SENSITIVITY, 100);
|
||||
guardband_usec =
|
||||
intel_scanlines_to_usecs(adjusted_mode,
|
||||
crtc_state->vrr.dc_balance.guardband);
|
||||
/*
|
||||
* The correction_aggressiveness/100 is the number of milliseconds to
|
||||
* adjust by when the balance is at twice the guardband.
|
||||
* guardband_slope = correction_aggressiveness / (guardband * 100)
|
||||
*/
|
||||
adjustment_usec = DCB_CORRECTION_AGGRESSIVENESS * 10;
|
||||
crtc_state->vrr.dc_balance.slope =
|
||||
DIV_ROUND_UP(adjustment_usec, guardband_usec);
|
||||
crtc_state->vrr.dc_balance.vblank_target =
|
||||
DIV_ROUND_UP((crtc_state->vrr.vmax - crtc_state->vrr.vmin) *
|
||||
DCB_BLANK_TARGET, 100);
|
||||
crtc_state->vrr.dc_balance.enable = true;
|
||||
}
|
||||
|
||||
void
|
||||
intel_vrr_compute_config(struct intel_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
@@ -392,6 +459,8 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state,
|
||||
(crtc_state->hw.adjusted_mode.crtc_vtotal -
|
||||
crtc_state->hw.adjusted_mode.crtc_vsync_end);
|
||||
}
|
||||
|
||||
intel_vrr_dc_balance_compute_config(crtc_state);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -579,6 +648,34 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state)
|
||||
EMP_AS_SDP_DB_TL(crtc_state->vrr.vsync_start));
|
||||
}
|
||||
|
||||
void
|
||||
intel_vrr_dcb_increment_flip_count(struct intel_crtc_state *crtc_state,
|
||||
struct intel_crtc *crtc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
|
||||
if (!crtc_state->vrr.dc_balance.enable)
|
||||
return;
|
||||
|
||||
intel_de_write(display, PIPEDMC_DCB_FLIP_COUNT(pipe),
|
||||
++crtc->dc_balance.flip_count);
|
||||
}
|
||||
|
||||
void
|
||||
intel_vrr_dcb_reset(const struct intel_crtc_state *old_crtc_state,
|
||||
struct intel_crtc *crtc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(old_crtc_state);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
|
||||
if (!old_crtc_state->vrr.dc_balance.enable)
|
||||
return;
|
||||
|
||||
intel_de_write(display, PIPEDMC_DCB_FLIP_COUNT(pipe), 0);
|
||||
intel_de_write(display, PIPEDMC_DCB_BALANCE_RESET(pipe), 0);
|
||||
}
|
||||
|
||||
void intel_vrr_send_push(struct intel_dsb *dsb,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
@@ -686,6 +783,92 @@ static void intel_vrr_set_vrr_timings(const struct intel_crtc_state *crtc_state)
|
||||
intel_vrr_hw_flipline(crtc_state) - 1);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_vrr_enable_dc_balancing(const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
|
||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
u32 vrr_ctl = intel_de_read(display, TRANS_VRR_CTL(display, cpu_transcoder));
|
||||
|
||||
if (!crtc_state->vrr.dc_balance.enable)
|
||||
return;
|
||||
|
||||
intel_de_write(display, TRANS_VRR_DCB_ADJ_VMAX_CFG(cpu_transcoder),
|
||||
VRR_DCB_ADJ_VMAX(crtc_state->vrr.vmax - 1));
|
||||
intel_de_write(display, TRANS_VRR_DCB_ADJ_VMAX_CFG_LIVE(cpu_transcoder),
|
||||
VRR_DCB_ADJ_VMAX(crtc_state->vrr.vmax - 1));
|
||||
intel_de_write(display, TRANS_VRR_DCB_VMAX(cpu_transcoder),
|
||||
VRR_DCB_VMAX(crtc_state->vrr.vmax - 1));
|
||||
intel_de_write(display, TRANS_VRR_DCB_VMAX_LIVE(cpu_transcoder),
|
||||
VRR_DCB_VMAX(crtc_state->vrr.vmax - 1));
|
||||
intel_de_write(display, TRANS_VRR_DCB_FLIPLINE(cpu_transcoder),
|
||||
VRR_DCB_FLIPLINE(crtc_state->vrr.flipline - 1));
|
||||
intel_de_write(display, TRANS_VRR_DCB_FLIPLINE_LIVE(cpu_transcoder),
|
||||
VRR_DCB_FLIPLINE(crtc_state->vrr.flipline - 1));
|
||||
intel_de_write(display, TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_LIVE(cpu_transcoder),
|
||||
VRR_DCB_ADJ_FLIPLINE(crtc_state->vrr.flipline - 1));
|
||||
intel_de_write(display, TRANS_VRR_DCB_ADJ_FLIPLINE_CFG(cpu_transcoder),
|
||||
VRR_DCB_ADJ_FLIPLINE(crtc_state->vrr.flipline - 1));
|
||||
intel_de_write(display, PIPEDMC_DCB_VMIN(pipe),
|
||||
crtc_state->vrr.dc_balance.vmin - 1);
|
||||
intel_de_write(display, PIPEDMC_DCB_VMAX(pipe),
|
||||
crtc_state->vrr.dc_balance.vmax - 1);
|
||||
intel_de_write(display, PIPEDMC_DCB_MAX_INCREASE(pipe),
|
||||
crtc_state->vrr.dc_balance.max_increase);
|
||||
intel_de_write(display, PIPEDMC_DCB_MAX_DECREASE(pipe),
|
||||
crtc_state->vrr.dc_balance.max_decrease);
|
||||
intel_de_write(display, PIPEDMC_DCB_GUARDBAND(pipe),
|
||||
crtc_state->vrr.dc_balance.guardband);
|
||||
intel_de_write(display, PIPEDMC_DCB_SLOPE(pipe),
|
||||
crtc_state->vrr.dc_balance.slope);
|
||||
intel_de_write(display, PIPEDMC_DCB_VBLANK(pipe),
|
||||
crtc_state->vrr.dc_balance.vblank_target);
|
||||
intel_dmc_configure_dc_balance_event(display, pipe, true);
|
||||
intel_de_write(display, TRANS_ADAPTIVE_SYNC_DCB_CTL(cpu_transcoder),
|
||||
ADAPTIVE_SYNC_COUNTER_EN);
|
||||
intel_pipedmc_dcb_enable(NULL, crtc);
|
||||
|
||||
vrr_ctl |= VRR_CTL_DCB_ADJ_ENABLE;
|
||||
intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), vrr_ctl);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_vrr_disable_dc_balancing(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;
|
||||
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
u32 vrr_ctl = intel_de_read(display, TRANS_VRR_CTL(display, cpu_transcoder));
|
||||
|
||||
if (!old_crtc_state->vrr.dc_balance.enable)
|
||||
return;
|
||||
|
||||
intel_pipedmc_dcb_disable(NULL, crtc);
|
||||
intel_dmc_configure_dc_balance_event(display, pipe, false);
|
||||
intel_de_write(display, TRANS_ADAPTIVE_SYNC_DCB_CTL(cpu_transcoder), 0);
|
||||
intel_de_write(display, PIPEDMC_DCB_VMIN(pipe), 0);
|
||||
intel_de_write(display, PIPEDMC_DCB_VMAX(pipe), 0);
|
||||
intel_de_write(display, PIPEDMC_DCB_MAX_INCREASE(pipe), 0);
|
||||
intel_de_write(display, PIPEDMC_DCB_MAX_DECREASE(pipe), 0);
|
||||
intel_de_write(display, PIPEDMC_DCB_GUARDBAND(pipe), 0);
|
||||
intel_de_write(display, PIPEDMC_DCB_SLOPE(pipe), 0);
|
||||
intel_de_write(display, PIPEDMC_DCB_VBLANK(pipe), 0);
|
||||
intel_de_write(display, TRANS_VRR_DCB_ADJ_VMAX_CFG_LIVE(cpu_transcoder), 0);
|
||||
intel_de_write(display, TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_LIVE(cpu_transcoder), 0);
|
||||
intel_de_write(display, TRANS_VRR_DCB_VMAX_LIVE(cpu_transcoder), 0);
|
||||
intel_de_write(display, TRANS_VRR_DCB_FLIPLINE_LIVE(cpu_transcoder), 0);
|
||||
intel_de_write(display, TRANS_VRR_DCB_ADJ_VMAX_CFG(cpu_transcoder), 0);
|
||||
intel_de_write(display, TRANS_VRR_DCB_ADJ_FLIPLINE_CFG(cpu_transcoder), 0);
|
||||
intel_de_write(display, TRANS_VRR_DCB_VMAX(cpu_transcoder), 0);
|
||||
intel_de_write(display, TRANS_VRR_DCB_FLIPLINE(cpu_transcoder), 0);
|
||||
|
||||
vrr_ctl &= ~VRR_CTL_DCB_ADJ_ENABLE;
|
||||
intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), vrr_ctl);
|
||||
}
|
||||
|
||||
static void intel_vrr_tg_enable(const struct intel_crtc_state *crtc_state,
|
||||
bool cmrr_enable)
|
||||
{
|
||||
@@ -732,6 +915,7 @@ void intel_vrr_enable(const struct intel_crtc_state *crtc_state)
|
||||
return;
|
||||
|
||||
intel_vrr_set_vrr_timings(crtc_state);
|
||||
intel_vrr_enable_dc_balancing(crtc_state);
|
||||
|
||||
if (!intel_vrr_always_use_vrr_tg(display))
|
||||
intel_vrr_tg_enable(crtc_state, crtc_state->cmrr.enable);
|
||||
@@ -747,6 +931,7 @@ void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state)
|
||||
if (!intel_vrr_always_use_vrr_tg(display))
|
||||
intel_vrr_tg_disable(old_crtc_state);
|
||||
|
||||
intel_vrr_disable_dc_balancing(old_crtc_state);
|
||||
intel_vrr_set_fixed_rr_timings(old_crtc_state);
|
||||
}
|
||||
|
||||
@@ -779,6 +964,35 @@ bool intel_vrr_is_fixed_rr(const struct intel_crtc_state *crtc_state)
|
||||
crtc_state->vrr.flipline == crtc_state->vrr.vmin;
|
||||
}
|
||||
|
||||
static
|
||||
void intel_vrr_get_dc_balance_config(struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
u32 reg_val;
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
|
||||
if (!intel_vrr_dc_balance_possible(crtc_state))
|
||||
return;
|
||||
|
||||
reg_val = intel_de_read(display, PIPEDMC_DCB_VMIN(pipe));
|
||||
crtc_state->vrr.dc_balance.vmin = reg_val ? reg_val + 1 : 0;
|
||||
|
||||
reg_val = intel_de_read(display, PIPEDMC_DCB_VMAX(pipe));
|
||||
crtc_state->vrr.dc_balance.vmax = reg_val ? reg_val + 1 : 0;
|
||||
|
||||
crtc_state->vrr.dc_balance.guardband =
|
||||
intel_de_read(display, PIPEDMC_DCB_GUARDBAND(pipe));
|
||||
crtc_state->vrr.dc_balance.max_increase =
|
||||
intel_de_read(display, PIPEDMC_DCB_MAX_INCREASE(pipe));
|
||||
crtc_state->vrr.dc_balance.max_decrease =
|
||||
intel_de_read(display, PIPEDMC_DCB_MAX_DECREASE(pipe));
|
||||
crtc_state->vrr.dc_balance.slope =
|
||||
intel_de_read(display, PIPEDMC_DCB_SLOPE(pipe));
|
||||
crtc_state->vrr.dc_balance.vblank_target =
|
||||
intel_de_read(display, PIPEDMC_DCB_VBLANK(pipe));
|
||||
}
|
||||
|
||||
void intel_vrr_get_config(struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
@@ -860,6 +1074,8 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state)
|
||||
else
|
||||
crtc_state->vrr.enable = vrr_enable;
|
||||
|
||||
intel_vrr_get_dc_balance_config(crtc_state);
|
||||
|
||||
/*
|
||||
* #TODO: For Both VRR and CMRR the flag I915_MODE_FLAG_VRR is set for mode_flags.
|
||||
* Since CMRR is currently disabled, set this flag for VRR for now.
|
||||
@@ -893,8 +1109,69 @@ int intel_vrr_safe_window_start(const struct intel_crtc_state *crtc_state)
|
||||
return crtc_state->hw.adjusted_mode.crtc_vdisplay;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_vrr_dcb_vmin_vblank_start(const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
return (intel_vrr_dcb_vmin_vblank_start_next(crtc_state) < 0) ?
|
||||
intel_vrr_dcb_vmin_vblank_start_final(crtc_state) :
|
||||
intel_vrr_dcb_vmin_vblank_start_next(crtc_state);
|
||||
}
|
||||
|
||||
int intel_vrr_vmin_safe_window_end(const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
return intel_vrr_vmin_vblank_start(crtc_state) -
|
||||
crtc_state->set_context_latency;
|
||||
int vmin_vblank_start = crtc_state->vrr.dc_balance.enable ?
|
||||
intel_vrr_dcb_vmin_vblank_start(crtc_state) :
|
||||
intel_vrr_vmin_vblank_start(crtc_state);
|
||||
|
||||
return vmin_vblank_start - crtc_state->set_context_latency;
|
||||
}
|
||||
|
||||
int intel_vrr_dcb_vmin_vblank_start_next(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 tmp = 0;
|
||||
|
||||
tmp = intel_de_read(display, TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_LIVE(cpu_transcoder));
|
||||
|
||||
if (REG_FIELD_GET(VRR_DCB_ADJ_FLIPLINE_CNT_MASK, tmp) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return intel_vrr_vblank_start(crtc_state, VRR_DCB_ADJ_FLIPLINE(tmp) + 1);
|
||||
}
|
||||
|
||||
int intel_vrr_dcb_vmax_vblank_start_next(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 tmp = 0;
|
||||
|
||||
tmp = intel_de_read(display, TRANS_VRR_DCB_ADJ_VMAX_CFG_LIVE(cpu_transcoder));
|
||||
|
||||
if (REG_FIELD_GET(VRR_DCB_ADJ_VMAX_CNT_MASK, tmp) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return intel_vrr_vblank_start(crtc_state, VRR_DCB_ADJ_VMAX(tmp) + 1);
|
||||
}
|
||||
|
||||
int intel_vrr_dcb_vmin_vblank_start_final(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 tmp = 0;
|
||||
|
||||
tmp = intel_de_read(display, TRANS_VRR_DCB_FLIPLINE_LIVE(cpu_transcoder));
|
||||
|
||||
return intel_vrr_vblank_start(crtc_state, VRR_DCB_FLIPLINE(tmp) + 1);
|
||||
}
|
||||
|
||||
int intel_vrr_dcb_vmax_vblank_start_final(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 tmp = 0;
|
||||
|
||||
tmp = intel_de_read(display, TRANS_VRR_DCB_VMAX_LIVE(cpu_transcoder));
|
||||
|
||||
return intel_vrr_vblank_start(crtc_state, VRR_DCB_VMAX(tmp) + 1);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
struct drm_connector_state;
|
||||
struct intel_atomic_state;
|
||||
struct intel_connector;
|
||||
struct intel_crtc;
|
||||
struct intel_crtc_state;
|
||||
struct intel_dsb;
|
||||
struct intel_display;
|
||||
@@ -28,6 +29,8 @@ void intel_vrr_send_push(struct intel_dsb *dsb,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
void intel_vrr_check_push_sent(struct intel_dsb *dsb,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
void intel_vrr_dcb_increment_flip_count(struct intel_crtc_state *crtc_state,
|
||||
struct intel_crtc *crtc);
|
||||
bool intel_vrr_is_push_sent(const struct intel_crtc_state *crtc_state);
|
||||
void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state);
|
||||
void intel_vrr_get_config(struct intel_crtc_state *crtc_state);
|
||||
@@ -39,8 +42,15 @@ bool intel_vrr_is_fixed_rr(const struct intel_crtc_state *crtc_state);
|
||||
void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state);
|
||||
void intel_vrr_transcoder_disable(const struct intel_crtc_state *crtc_state);
|
||||
void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state);
|
||||
void intel_vrr_dcb_reset(const struct intel_crtc_state *old_crtc_state,
|
||||
struct intel_crtc *crtc);
|
||||
bool intel_vrr_always_use_vrr_tg(struct intel_display *display);
|
||||
int intel_vrr_safe_window_start(const struct intel_crtc_state *crtc_state);
|
||||
int intel_vrr_vmin_safe_window_end(const struct intel_crtc_state *crtc_state);
|
||||
|
||||
int intel_vrr_dcb_vmin_vblank_start_next(const struct intel_crtc_state *crtc_state);
|
||||
int intel_vrr_dcb_vmax_vblank_start_next(const struct intel_crtc_state *crtc_state);
|
||||
int intel_vrr_dcb_vmin_vblank_start_final(const struct intel_crtc_state *crtc_state);
|
||||
int intel_vrr_dcb_vmax_vblank_start_final(const struct intel_crtc_state *crtc_state);
|
||||
|
||||
#endif /* __INTEL_VRR_H__ */
|
||||
|
||||
@@ -8,6 +8,73 @@
|
||||
|
||||
#include "intel_display_reg_defs.h"
|
||||
|
||||
#define _TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_A 0x604d4
|
||||
#define _TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_B 0x614d4
|
||||
#define TRANS_VRR_DCB_ADJ_FLIPLINE_CFG(trans) _MMIO_TRANS(trans, \
|
||||
_TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_A, \
|
||||
_TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_B)
|
||||
#define VRR_DCB_ADJ_FLIPLINE_CNT_MASK REG_GENMASK(31, 24)
|
||||
#define VRR_DCB_ADJ_FLIPLINE_MASK REG_GENMASK(19, 0)
|
||||
#define VRR_DCB_ADJ_FLIPLINE(flipline) REG_FIELD_PREP(VRR_DCB_ADJ_FLIPLINE_MASK, \
|
||||
(flipline))
|
||||
|
||||
#define _TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_LIVE_A 0x90700
|
||||
#define _TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_LIVE_B 0x98700
|
||||
#define TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_LIVE(trans) _MMIO_TRANS(trans, \
|
||||
_TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_LIVE_A, \
|
||||
_TRANS_VRR_DCB_ADJ_FLIPLINE_CFG_LIVE_B)
|
||||
|
||||
#define _TRANS_VRR_DCB_ADJ_VMAX_CFG_A 0x604d8
|
||||
#define _TRANS_VRR_DCB_ADJ_VMAX_CFG_B 0x614d8
|
||||
#define TRANS_VRR_DCB_ADJ_VMAX_CFG(trans) _MMIO_TRANS(trans, \
|
||||
_TRANS_VRR_DCB_ADJ_VMAX_CFG_A, \
|
||||
_TRANS_VRR_DCB_ADJ_VMAX_CFG_B)
|
||||
#define VRR_DCB_ADJ_VMAX_CNT_MASK REG_GENMASK(31, 24)
|
||||
#define VRR_DCB_ADJ_VMAX_MASK REG_GENMASK(19, 0)
|
||||
#define VRR_DCB_ADJ_VMAX(vmax) REG_FIELD_PREP(VRR_DCB_ADJ_VMAX_MASK, (vmax))
|
||||
|
||||
#define _TRANS_VRR_DCB_ADJ_VMAX_CFG_LIVE_A 0x906f8
|
||||
#define _TRANS_VRR_DCB_ADJ_VMAX_CFG_LIVE_B 0x986f8
|
||||
#define TRANS_VRR_DCB_ADJ_VMAX_CFG_LIVE(trans) _MMIO_TRANS(trans, \
|
||||
_TRANS_VRR_DCB_ADJ_VMAX_CFG_LIVE_A, \
|
||||
_TRANS_VRR_DCB_ADJ_VMAX_CFG_LIVE_B)
|
||||
|
||||
#define _TRANS_VRR_DCB_FLIPLINE_A 0x60418
|
||||
#define _TRANS_VRR_DCB_FLIPLINE_B 0x61418
|
||||
#define TRANS_VRR_DCB_FLIPLINE(trans) _MMIO_TRANS(trans, \
|
||||
_TRANS_VRR_DCB_FLIPLINE_A, \
|
||||
_TRANS_VRR_DCB_FLIPLINE_B)
|
||||
#define VRR_DCB_FLIPLINE_MASK REG_GENMASK(19, 0)
|
||||
#define VRR_DCB_FLIPLINE(flipline) REG_FIELD_PREP(VRR_DCB_FLIPLINE_MASK, \
|
||||
(flipline))
|
||||
|
||||
#define _TRANS_VRR_DCB_FLIPLINE_LIVE_A 0x906fc
|
||||
#define _TRANS_VRR_DCB_FLIPLINE_LIVE_B 0x986fc
|
||||
#define TRANS_VRR_DCB_FLIPLINE_LIVE(trans) _MMIO_TRANS(trans, \
|
||||
_TRANS_VRR_DCB_FLIPLINE_LIVE_A, \
|
||||
_TRANS_VRR_DCB_FLIPLINE_LIVE_B)
|
||||
|
||||
#define _TRANS_VRR_DCB_VMAX_A 0x60414
|
||||
#define _TRANS_VRR_DCB_VMAX_B 0x61414
|
||||
#define TRANS_VRR_DCB_VMAX(trans) _MMIO_TRANS(trans, \
|
||||
_TRANS_VRR_DCB_VMAX_A, \
|
||||
_TRANS_VRR_DCB_VMAX_B)
|
||||
#define VRR_DCB_VMAX_MASK REG_GENMASK(19, 0)
|
||||
#define VRR_DCB_VMAX(vmax) REG_FIELD_PREP(VRR_DCB_VMAX_MASK, (vmax))
|
||||
|
||||
#define _TRANS_VRR_DCB_VMAX_LIVE_A 0x906f4
|
||||
#define _TRANS_VRR_DCB_VMAX_LIVE_B 0x986f4
|
||||
#define TRANS_VRR_DCB_VMAX_LIVE(trans) _MMIO_TRANS(trans, \
|
||||
_TRANS_VRR_DCB_VMAX_LIVE_A, \
|
||||
_TRANS_VRR_DCB_VMAX_LIVE_B)
|
||||
|
||||
#define _TRANS_ADAPTIVE_SYNC_DCB_CTL_A 0x604c0
|
||||
#define _TRANS_ADAPTIVE_SYNC_DCB_CTL_B 0x614c0
|
||||
#define TRANS_ADAPTIVE_SYNC_DCB_CTL(trans) _MMIO_TRANS(trans, \
|
||||
_TRANS_ADAPTIVE_SYNC_DCB_CTL_A, \
|
||||
_TRANS_ADAPTIVE_SYNC_DCB_CTL_B)
|
||||
#define ADAPTIVE_SYNC_COUNTER_EN REG_BIT(31)
|
||||
|
||||
#define _TRANS_VRR_CTL_A 0x60420
|
||||
#define _TRANS_VRR_CTL_B 0x61420
|
||||
#define _TRANS_VRR_CTL_C 0x62420
|
||||
@@ -19,6 +86,7 @@
|
||||
#define VRR_CTL_CMRR_ENABLE REG_BIT(27)
|
||||
#define VRR_CTL_PIPELINE_FULL_MASK REG_GENMASK(10, 3)
|
||||
#define VRR_CTL_PIPELINE_FULL(x) REG_FIELD_PREP(VRR_CTL_PIPELINE_FULL_MASK, (x))
|
||||
#define VRR_CTL_DCB_ADJ_ENABLE REG_BIT(28)
|
||||
#define VRR_CTL_PIPELINE_FULL_OVERRIDE REG_BIT(0)
|
||||
#define XELPD_VRR_CTL_VRR_GUARDBAND_MASK REG_GENMASK(15, 0)
|
||||
#define XELPD_VRR_CTL_VRR_GUARDBAND(x) REG_FIELD_PREP(XELPD_VRR_CTL_VRR_GUARDBAND_MASK, (x))
|
||||
|
||||
Reference in New Issue
Block a user