diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-01-16 12:57:20 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-01-16 12:57:29 +1000 |
| commit | 9d10cd526111a989eb353c3a4df9d4c79695ea8d (patch) | |
| tree | 2e6c5370871c747752d1e09602deaa1374a28f27 | |
| parent | 37b812b7fdc2f1c7cb9e22c888776be7347097b0 (diff) | |
| parent | d30f75d2dba913754dbacb982b19b783a30253ea (diff) | |
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
95 files changed, 2008 insertions, 1434 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 5f7b2bbe448c..241b1d2e2603 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -78,6 +78,7 @@ i915-$(CONFIG_PERF_EVENTS) += \ i915-y += \ i915_display_pc8.o \ i915_hdcp_gsc.o \ + i915_initial_plane.o \ i915_panic.o # "Graphics Technology" (aka we talk to the gpu) @@ -288,6 +289,7 @@ i915-y += \ display/intel_hotplug.o \ display/intel_hotplug_irq.o \ display/intel_hti.o \ + display/intel_initial_plane.o \ display/intel_link_bw.o \ display/intel_load_detect.o \ display/intel_lpe_audio.o \ @@ -300,7 +302,6 @@ i915-y += \ display/intel_pch_display.o \ display/intel_pch_refclk.o \ display/intel_plane.o \ - display/intel_plane_initial.o \ display/intel_pmdemand.o \ display/intel_psr.o \ display/intel_quirks.o \ @@ -381,6 +382,9 @@ i915-y += \ i915-$(CONFIG_DRM_I915_DP_TUNNEL) += \ display/intel_dp_tunnel.o +i915-$(CONFIG_DRM_I915_GVT) += \ + display/intel_gvt_api.o + i915-y += \ i915_perf.o diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c index 167277cd8877..39dfceb438ae 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.c +++ b/drivers/gpu/drm/i915/display/i9xx_wm.c @@ -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; diff --git a/drivers/gpu/drm/i915/display/intel_alpm.h b/drivers/gpu/drm/i915/display/intel_alpm.h index 53599b464dea..c6a4ec5b9561 100644 --- a/drivers/gpu/drm/i915/display/intel_alpm.h +++ b/drivers/gpu/drm/i915/display/intel_alpm.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: MIT - * +/* SPDX-License-Identifier: MIT */ +/* * Copyright © 2024 Intel Corporation */ diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index d27835ed49c2..4ee3f5172f4e 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -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); diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 0aa59d624095..9bfbfbf34dc0 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -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; } diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index c128bc4215c4..682bf1be350d 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -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" diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index c2a6217c2262..234843b8f83a 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -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)); diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 2c87c58812da..7288065d2461 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -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; diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 9f10113e2d18..ae98ac23ea22 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +/* SPDX-License-Identifier: MIT */ /* * Copyright © 2023 Intel Corporation */ diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h index 8df5cd5ce418..658890f73515 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: MIT - * +/* SPDX-License-Identifier: MIT */ +/* * Copyright © 2023 Intel Corporation */ diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d5947cc9b94c..81b3a6692ca2 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -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 diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index 50b2e9ae2c18..6c74d6b0cc48 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -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; diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index e1d29aea0ddc..268b1de45b81 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -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" diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index b01bc5700c52..b95ecf728daa 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +/* SPDX-License-Identifier: MIT */ /* * Copyright © 2023 Intel Corporation */ diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 47042a4c3a30..d27397f43863 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -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; diff --git a/drivers/gpu/drm/i915/display/intel_display_reg_defs.h b/drivers/gpu/drm/i915/display/intel_display_reg_defs.h index b83ad06f2ea7..175334b41bba 100644 --- a/drivers/gpu/drm/i915/display/intel_display_reg_defs.h +++ b/drivers/gpu/drm/i915/display/intel_display_reg_defs.h @@ -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__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index eb2e3f1e83c9..6b92f333e18b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.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 { diff --git a/drivers/gpu/drm/i915/display/intel_display_utils.h b/drivers/gpu/drm/i915/display/intel_display_utils.h index 2a18f160320c..affa3179f52c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_utils.h +++ b/drivers/gpu/drm/i915/display/intel_display_utils.h @@ -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)) diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.c b/drivers/gpu/drm/i915/display/intel_display_wa.c index a00af39f7538..581d943b9bdc 100644 --- a/drivers/gpu/drm/i915/display/intel_display_wa.c +++ b/drivers/gpu/drm/i915/display/intel_display_wa.c @@ -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; diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.h b/drivers/gpu/drm/i915/display/intel_display_wa.h index a68c0bb7e516..40f989f19df1 100644 --- a/drivers/gpu/drm/i915/display/intel_display_wa.h +++ b/drivers/gpu/drm/i915/display/intel_display_wa.h @@ -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); diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 2fb6fec6dc99..1182bc9a2e6d 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -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); +} diff --git a/drivers/gpu/drm/i915/display/intel_dmc.h b/drivers/gpu/drm/i915/display/intel_dmc.h index 40e9dcb033cc..3d8a9a593319 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.h +++ b/drivers/gpu/drm/i915/display/intel_dmc.h @@ -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, diff --git a/drivers/gpu/drm/i915/display/intel_dmc_regs.h b/drivers/gpu/drm/i915/display/intel_dmc_regs.h index c5aa49921cb9..38e342b45af0 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dmc_regs.h @@ -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__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2dadbf7e8922..7e022c47e8ac 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -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; + + for (i = ARRAY_SIZE(valid_dsc_bpp) - 1; i >= 0; i--) { + int vesa_bpp_x16 = fxp_q4_from_int(valid_dsc_bpp[i]); - bits_per_pixel = 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; + + 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, + 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; +} + +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); } +} - return false; +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; - - 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; + int ret; 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; - - /* 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); + else + pipe_bpp = limits->pipe.max_bpp; - 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; - - 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; + limits->link.min_bpp_x16 = + compute_min_compressed_bpp_x16(connector, crtc_state->output_format); - 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); diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 30eebb8cad6d..25bfbfd291b0 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -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, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 0db6ed2d9664..24f8e60df9ac 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -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) { diff --git a/drivers/gpu/drm/i915/display/intel_dram.c b/drivers/gpu/drm/i915/display/intel_dram.c index 019a722a38bf..170de304fe96 100644 --- a/drivers/gpu/drm/i915/display/intel_dram.c +++ b/drivers/gpu/drm/i915/display/intel_dram.c @@ -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: diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index ec2a3fb171ab..91060e2a5762 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -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); diff --git a/drivers/gpu/drm/i915/display/intel_dsb.h b/drivers/gpu/drm/i915/display/intel_dsb.h index 2f31f2c1d0c5..386a5a942572 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.h +++ b/drivers/gpu/drm/i915/display/intel_dsb.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: MIT - * +/* SPDX-License-Identifier: MIT */ +/* * Copyright © 2019 Intel Corporation */ diff --git a/drivers/gpu/drm/i915/display/intel_dsb_buffer.h b/drivers/gpu/drm/i915/display/intel_dsb_buffer.h index d746c872e0c7..f4577d1f25cd 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb_buffer.h +++ b/drivers/gpu/drm/i915/display/intel_dsb_buffer.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: MIT - * +/* SPDX-License-Identifier: MIT */ +/* * Copyright © 2023 Intel Corporation */ diff --git a/drivers/gpu/drm/i915/display/intel_gvt_api.c b/drivers/gpu/drm/i915/display/intel_gvt_api.c new file mode 100644 index 000000000000..a69e249395ae --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_gvt_api.c @@ -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"); diff --git a/drivers/gpu/drm/i915/display/intel_gvt_api.h b/drivers/gpu/drm/i915/display/intel_gvt_api.h new file mode 100644 index 000000000000..ce3b744142a5 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_gvt_api.h @@ -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__ */ diff --git a/drivers/gpu/drm/i915/display/intel_initial_plane.c b/drivers/gpu/drm/i915/display/intel_initial_plane.c new file mode 100644 index 000000000000..ee545c033da6 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_initial_plane.c @@ -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); + } +} diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.h b/drivers/gpu/drm/i915/display/intel_initial_plane.h index 5c315acda210..5f9a347be8f0 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.h +++ b/drivers/gpu/drm/i915/display/intel_initial_plane.h @@ -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 diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c index 939c8975fd4c..6cdae03ee172 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.c +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c @@ -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; - - if (memcmp(&a->data, &b->data, sizeof(a->data)) != 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; - 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, diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.h b/drivers/gpu/drm/i915/display/intel_lt_phy.h index 7659c92b6c3c..bf41858f1bc3 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.h +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: MIT - * +/* SPDX-License-Identifier: MIT */ +/* * Copyright © 2025 Intel Corporation */ diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy_regs.h b/drivers/gpu/drm/i915/display/intel_lt_phy_regs.h index 98ccc069a69b..37e46fb9abde 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_lt_phy_regs.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: MIT - * +/* SPDX-License-Identifier: MIT */ +/* * Copyright © 2025 Intel Corporation */ diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c deleted file mode 100644 index ff1afd3a8f20..000000000000 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ /dev/null @@ -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); - } -} diff --git a/drivers/gpu/drm/i915/display/intel_rom.c b/drivers/gpu/drm/i915/display/intel_rom.c index 2f17dc856e7f..c8f615315310 100644 --- a/drivers/gpu/drm/i915/display/intel_rom.c +++ b/drivers/gpu/drm/i915/display/intel_rom.c @@ -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; diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c index 671f357c6563..1b7cfe226ff8 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c @@ -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 { diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index ad5fe841e4b3..5493082f30a7 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -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); } diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index b92c42fde937..db74744ddb31 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -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); } diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h b/drivers/gpu/drm/i915/display/intel_vrr.h index bc9044621635..bedcc8c4bff2 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.h +++ b/drivers/gpu/drm/i915/display/intel_vrr.h @@ -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__ */ diff --git a/drivers/gpu/drm/i915/display/intel_vrr_regs.h b/drivers/gpu/drm/i915/display/intel_vrr_regs.h index ba9b9215dc11..427ada0d3973 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr_regs.h +++ b/drivers/gpu/drm/i915/display/intel_vrr_regs.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)) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c index c4854c5b4e0f..c1deea20c28a 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c @@ -113,7 +113,7 @@ bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, if (clflush) { i915_sw_fence_await_reservation(&clflush->base.chain, obj->base.resv, true, - i915_fence_timeout(i915), + i915_fence_timeout(), I915_FENCE_GFP); dma_resv_add_fence(obj->base.resv, &clflush->base.dma, DMA_RESV_USAGE_KERNEL); diff --git a/drivers/gpu/drm/i915/gvt/aperture_gm.c b/drivers/gpu/drm/i915/gvt/aperture_gm.c index 8cc6e712b0f7..253b41789be9 100644 --- a/drivers/gpu/drm/i915/gvt/aperture_gm.c +++ b/drivers/gpu/drm/i915/gvt/aperture_gm.c @@ -36,10 +36,11 @@ #include <drm/drm_print.h> -#include "i915_drv.h" -#include "i915_reg.h" #include "gt/intel_ggtt_fencing.h" + #include "gvt.h" +#include "i915_drv.h" +#include "i915_reg.h" static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm) { diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c index 295a7b5e1d7c..1937e04d3791 100644 --- a/drivers/gpu/drm/i915/gvt/cfg_space.c +++ b/drivers/gpu/drm/i915/gvt/cfg_space.c @@ -33,8 +33,8 @@ #include <drm/drm_print.h> -#include "i915_drv.h" #include "gvt.h" +#include "i915_drv.h" #include "intel_pci_config.h" enum { diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index df04e4ead8ea..bf7c3d3f5f8a 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -38,27 +38,29 @@ #include <drm/drm_print.h> -#include "i915_drv.h" -#include "i915_reg.h" +#include "display/i9xx_plane_regs.h" #include "display/intel_display_regs.h" +#include "display/intel_sprite_regs.h" + +#include "gem/i915_gem_context.h" +#include "gem/i915_gem_pm.h" + +#include "gt/intel_context.h" #include "gt/intel_engine_regs.h" #include "gt/intel_gpu_commands.h" #include "gt/intel_gt_regs.h" +#include "gt/intel_gt_requests.h" #include "gt/intel_lrc.h" #include "gt/intel_ring.h" -#include "gt/intel_gt_requests.h" #include "gt/shmem_utils.h" + +#include "display_helpers.h" #include "gvt.h" +#include "i915_drv.h" #include "i915_pvinfo.h" +#include "i915_reg.h" #include "trace.h" -#include "display/i9xx_plane_regs.h" -#include "display/intel_display_core.h" -#include "display/intel_sprite_regs.h" -#include "gem/i915_gem_context.h" -#include "gem/i915_gem_pm.h" -#include "gt/intel_context.h" - #define INVALID_OP (~0U) #define OP_LEN_MI 9 diff --git a/drivers/gpu/drm/i915/gvt/debugfs.c b/drivers/gpu/drm/i915/gvt/debugfs.c index 415422b5943c..ae3fd2c3cd23 100644 --- a/drivers/gpu/drm/i915/gvt/debugfs.c +++ b/drivers/gpu/drm/i915/gvt/debugfs.c @@ -20,10 +20,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + #include <linux/debugfs.h> #include <linux/list_sort.h> -#include "i915_drv.h" + #include "gvt.h" +#include "i915_drv.h" struct mmio_diff_param { struct intel_vgpu *vgpu; diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index 06517d1f07a2..21341842c0a9 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -35,20 +35,21 @@ #include <drm/display/drm_dp.h> #include <drm/drm_print.h> -#include "i915_drv.h" -#include "i915_reg.h" -#include "display/intel_display_regs.h" -#include "gvt.h" - #include "display/bxt_dpio_phy_regs.h" #include "display/i9xx_plane_regs.h" #include "display/intel_crt_regs.h" #include "display/intel_cursor_regs.h" #include "display/intel_display.h" -#include "display/intel_display_core.h" +#include "display/intel_display_regs.h" #include "display/intel_dpio_phy.h" +#include "display/intel_dpll_mgr.h" #include "display/intel_sprite_regs.h" +#include "display_helpers.h" +#include "gvt.h" +#include "i915_drv.h" +#include "i915_reg.h" + static int get_edp_pipe(struct intel_vgpu *vgpu) { u32 data = vgpu_vreg(vgpu, _TRANS_DDI_FUNC_CTL_EDP); @@ -187,7 +188,7 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu) { struct drm_i915_private *dev_priv = vgpu->gvt->gt->i915; struct intel_display *display = dev_priv->display; - int pipe; + enum pipe pipe; if (IS_BROXTON(dev_priv)) { enum transcoder trans; @@ -199,7 +200,7 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu) GEN8_DE_PORT_HOTPLUG(HPD_PORT_B) | GEN8_DE_PORT_HOTPLUG(HPD_PORT_C)); - for_each_pipe(display, pipe) { + gvt_for_each_pipe(display, pipe) { vgpu_vreg_t(vgpu, TRANSCONF(display, pipe)) &= ~(TRANSCONF_ENABLE | TRANSCONF_STATE_ENABLE); vgpu_vreg_t(vgpu, DSPCNTR(display, pipe)) &= ~DISP_ENABLE; @@ -515,7 +516,7 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu) vgpu_vreg_t(vgpu, PCH_ADPA) &= ~ADPA_CRT_HOTPLUG_MONITOR_MASK; /* Disable Primary/Sprite/Cursor plane */ - for_each_pipe(display, pipe) { + gvt_for_each_pipe(display, pipe) { vgpu_vreg_t(vgpu, DSPCNTR(display, pipe)) &= ~DISP_ENABLE; vgpu_vreg_t(vgpu, SPRCTL(pipe)) &= ~SPRITE_ENABLE; vgpu_vreg_t(vgpu, CURCNTR(display, pipe)) &= ~MCURSOR_MODE_MASK; @@ -668,10 +669,10 @@ void intel_vgpu_emulate_vblank(struct intel_vgpu *vgpu) { struct drm_i915_private *i915 = vgpu->gvt->gt->i915; struct intel_display *display = i915->display; - int pipe; + enum pipe pipe; mutex_lock(&vgpu->vgpu_lock); - for_each_pipe(display, pipe) + gvt_for_each_pipe(display, pipe) emulate_vblank_on_pipe(vgpu, pipe); mutex_unlock(&vgpu->vgpu_lock); } diff --git a/drivers/gpu/drm/i915/gvt/display.h b/drivers/gpu/drm/i915/gvt/display.h index bc7f05f9a271..41a3b053663a 100644 --- a/drivers/gpu/drm/i915/gvt/display.h +++ b/drivers/gpu/drm/i915/gvt/display.h @@ -35,8 +35,8 @@ #ifndef _GVT_DISPLAY_H_ #define _GVT_DISPLAY_H_ -#include <linux/types.h> #include <linux/hrtimer.h> +#include <linux/types.h> struct intel_gvt; struct intel_vgpu; diff --git a/drivers/gpu/drm/i915/gvt/display_helpers.h b/drivers/gpu/drm/i915/gvt/display_helpers.h new file mode 100644 index 000000000000..0418397c09c4 --- /dev/null +++ b/drivers/gpu/drm/i915/gvt/display_helpers.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright © 2025 Intel Corporation + */ + +#ifndef __DISPLAY_HELPERS_H__ +#define __DISPLAY_HELPERS_H__ + +#include "display/intel_gvt_api.h" + +#define DISPLAY_MMIO_BASE(display) \ + intel_display_device_mmio_base((display)) + +/* + * #FIXME: + * TRANSCONF() uses pipe-based addressing via _MMIO_PIPE2(). + * Some GVT call sites pass enum transcoder instead of enum pipe. + * Cast the argument to enum pipe for now since TRANSCODER_A..D map + * 1:1 to PIPE_A..D. + * TRANSCODER_EDP is an exception, the cast preserves the existing + * behaviour but this needs to be handled later either by using the + * correct pipe or by switching TRANSCONF() to use _MMIO_TRANS2(). + */ +#define INTEL_DISPLAY_DEVICE_PIPE_OFFSET(display, idx) \ + intel_display_device_pipe_offset((display), (enum pipe)(idx)) + +#define INTEL_DISPLAY_DEVICE_TRANS_OFFSET(display, trans) \ + intel_display_device_trans_offset((display), (trans)) + +#define INTEL_DISPLAY_DEVICE_CURSOR_OFFSET(display, pipe) \ + intel_display_device_cursor_offset((display), (pipe)) + +#define gvt_for_each_pipe(display, __p) \ + for ((__p) = PIPE_A; (__p) < I915_MAX_PIPES; (__p)++) \ + for_each_if(intel_display_device_pipe_valid((display), (__p))) + +#endif /* __DISPLAY_HELPERS_H__ */ diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.c b/drivers/gpu/drm/i915/gvt/dmabuf.c index 92506c80322d..8e76869b352c 100644 --- a/drivers/gpu/drm/i915/gvt/dmabuf.c +++ b/drivers/gpu/drm/i915/gvt/dmabuf.c @@ -35,12 +35,12 @@ #include <drm/drm_plane.h> #include <drm/drm_print.h> +#include "display/skl_universal_plane_regs.h" + #include "gem/i915_gem_dmabuf.h" -#include "i915_drv.h" #include "gvt.h" - -#include "display/skl_universal_plane_regs.h" +#include "i915_drv.h" #define GEN8_DECODE_PTE(pte) (pte & GENMASK_ULL(63, 12)) diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.h b/drivers/gpu/drm/i915/gvt/dmabuf.h index 3dcdb6570eda..aa7523386d94 100644 --- a/drivers/gpu/drm/i915/gvt/dmabuf.h +++ b/drivers/gpu/drm/i915/gvt/dmabuf.h @@ -30,7 +30,12 @@ #ifndef _GVT_DMABUF_H_ #define _GVT_DMABUF_H_ -#include <linux/vfio.h> + +#include <linux/kref.h> +#include <linux/types.h> + +struct intel_vgpu; +struct intel_vgpu_dmabuf_obj; struct intel_vgpu_fb_info { __u64 start; diff --git a/drivers/gpu/drm/i915/gvt/edid.c b/drivers/gpu/drm/i915/gvt/edid.c index 30e414381af3..021afff1cd5d 100644 --- a/drivers/gpu/drm/i915/gvt/edid.c +++ b/drivers/gpu/drm/i915/gvt/edid.c @@ -38,6 +38,7 @@ #include "display/intel_dp_aux_regs.h" #include "display/intel_gmbus.h" #include "display/intel_gmbus_regs.h" + #include "gvt.h" #include "i915_drv.h" #include "i915_reg.h" diff --git a/drivers/gpu/drm/i915/gvt/execlist.c b/drivers/gpu/drm/i915/gvt/execlist.c index 274c6ef42400..29147a9f162e 100644 --- a/drivers/gpu/drm/i915/gvt/execlist.c +++ b/drivers/gpu/drm/i915/gvt/execlist.c @@ -32,8 +32,8 @@ * */ -#include "i915_drv.h" #include "gvt.h" +#include "i915_drv.h" #define _EL_OFFSET_STATUS 0x234 #define _EL_OFFSET_STATUS_BUF 0x370 diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c index a8079cfa8e1d..d7abf38df532 100644 --- a/drivers/gpu/drm/i915/gvt/fb_decoder.c +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c @@ -35,18 +35,18 @@ #include <uapi/drm/drm_fourcc.h> -#include "gvt.h" -#include "i915_drv.h" -#include "i915_pvinfo.h" -#include "i915_reg.h" -#include "display/intel_display_regs.h" - #include "display/i9xx_plane_regs.h" #include "display/intel_cursor_regs.h" -#include "display/intel_display_core.h" +#include "display/intel_display_regs.h" #include "display/intel_sprite_regs.h" #include "display/skl_universal_plane_regs.h" +#include "display_helpers.h" +#include "gvt.h" +#include "i915_drv.h" +#include "i915_pvinfo.h" +#include "i915_reg.h" + #define PRIMARY_FORMAT_NUM 16 struct pixel_format { int drm_format; /* Pixel format in DRM definition */ diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.h b/drivers/gpu/drm/i915/gvt/fb_decoder.h index 436d43c0087b..bc1e9d149e25 100644 --- a/drivers/gpu/drm/i915/gvt/fb_decoder.h +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.h @@ -38,8 +38,6 @@ #include <linux/types.h> -#include "display/intel_display_limits.h" - struct intel_vgpu; #define _PLANE_CTL_FORMAT_SHIFT 24 diff --git a/drivers/gpu/drm/i915/gvt/firmware.c b/drivers/gpu/drm/i915/gvt/firmware.c index 221a3ae81baf..e452298991be 100644 --- a/drivers/gpu/drm/i915/gvt/firmware.c +++ b/drivers/gpu/drm/i915/gvt/firmware.c @@ -28,12 +28,12 @@ * */ -#include <linux/firmware.h> #include <linux/crc32.h> +#include <linux/firmware.h> #include <linux/vmalloc.h> -#include "i915_drv.h" #include "gvt.h" +#include "i915_drv.h" #include "i915_pvinfo.h" #define FIRMWARE_VERSION (0x0) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 076d9139edc6..49028e7ef1e0 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -33,16 +33,17 @@ * */ +#include <linux/vmalloc.h> + #include <drm/drm_print.h> -#include "i915_drv.h" +#include "gt/intel_gt_regs.h" + #include "gvt.h" +#include "i915_drv.h" #include "i915_pvinfo.h" #include "trace.h" -#include "gt/intel_gt_regs.h" -#include <linux/vmalloc.h> - #if defined(VERBOSE_DEBUG) #define gvt_vdbg_mm(fmt, args...) gvt_dbg_mm(fmt, ##args) #else diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index 1d10c16e6465..7fd2356f463c 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -34,29 +34,29 @@ #define _GVT_H_ #include <uapi/linux/pci_regs.h> -#include <linux/vfio.h> #include <linux/mdev.h> - +#include <linux/vfio.h> #include <asm/kvm_page_track.h> +#include "display/intel_display_limits.h" + #include "gt/intel_gt.h" -#include "intel_gvt.h" +#include "cmd_parser.h" #include "debug.h" -#include "mmio.h" -#include "reg.h" -#include "interrupt.h" -#include "gtt.h" #include "display.h" +#include "dmabuf.h" #include "edid.h" #include "execlist.h" -#include "scheduler.h" -#include "sched_policy.h" -#include "mmio_context.h" -#include "cmd_parser.h" #include "fb_decoder.h" -#include "dmabuf.h" +#include "gtt.h" +#include "intel_gvt.h" +#include "interrupt.h" +#include "mmio.h" +#include "mmio_context.h" #include "page_track.h" +#include "reg.h" +#include "scheduler.h" #define GVT_MAX_VGPU 8 diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 36ea12ade849..bd20f287720f 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -36,20 +36,16 @@ */ +#include <linux/vmalloc.h> + #include <drm/display/drm_dp.h> #include <drm/drm_print.h> -#include "i915_drv.h" -#include "i915_reg.h" -#include "display/intel_display_regs.h" -#include "gvt.h" -#include "i915_pvinfo.h" -#include "intel_mchbar_regs.h" #include "display/bxt_dpio_phy_regs.h" #include "display/i9xx_plane_regs.h" #include "display/intel_crt_regs.h" #include "display/intel_cursor_regs.h" -#include "display/intel_display_core.h" +#include "display/intel_display_regs.h" #include "display/intel_display_types.h" #include "display/intel_dmc_regs.h" #include "display/intel_dp_aux_regs.h" @@ -64,8 +60,17 @@ #include "display/skl_universal_plane_regs.h" #include "display/skl_watermark_regs.h" #include "display/vlv_dsi_pll_regs.h" + +#include "gt/intel_engine_regs.h" #include "gt/intel_gt_regs.h" -#include <linux/vmalloc.h> + +#include "display_helpers.h" +#include "gvt.h" +#include "i915_drv.h" +#include "i915_pvinfo.h" +#include "i915_reg.h" +#include "intel_mchbar_regs.h" +#include "sched_policy.h" /* XXX FIXME i915 has changed PP_XXX definition */ #define PCH_PP_STATUS _MMIO(0xc7200) diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c index 3e66269bc4ee..91d22b1c62e2 100644 --- a/drivers/gpu/drm/i915/gvt/interrupt.c +++ b/drivers/gpu/drm/i915/gvt/interrupt.c @@ -33,10 +33,11 @@ #include <drm/drm_print.h> -#include "i915_drv.h" -#include "i915_reg.h" #include "display/intel_display_regs.h" + #include "gvt.h" +#include "i915_drv.h" +#include "i915_reg.h" #include "trace.h" struct intel_gvt_irq_info { diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 3abc9206f1a8..009aa2df7958 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -33,26 +33,26 @@ * Zhi Wang <zhi.a.wang@intel.com> */ +#include <linux/debugfs.h> +#include <linux/eventfd.h> #include <linux/init.h> -#include <linux/mm.h> #include <linux/kthread.h> -#include <linux/sched/mm.h> -#include <linux/types.h> #include <linux/list.h> -#include <linux/rbtree.h> -#include <linux/spinlock.h> -#include <linux/eventfd.h> #include <linux/mdev.h> -#include <linux/debugfs.h> - +#include <linux/mm.h> #include <linux/nospec.h> +#include <linux/rbtree.h> +#include <linux/sched/mm.h> +#include <linux/spinlock.h> +#include <linux/types.h> #include <drm/drm_edid.h> #include <drm/drm_print.h> +#include "gvt.h" #include "i915_drv.h" #include "intel_gvt.h" -#include "gvt.h" +#include "sched_policy.h" MODULE_IMPORT_NS("DMA_BUF"); MODULE_IMPORT_NS("I915_GVT"); diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c index 214eb7effa31..9e98db2d4f67 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.c +++ b/drivers/gpu/drm/i915/gvt/mmio.c @@ -37,15 +37,16 @@ #include <drm/drm_print.h> -#include "i915_drv.h" -#include "i915_reg.h" -#include "display/intel_display_regs.h" -#include "gvt.h" - #include "display/bxt_dpio_phy_regs.h" +#include "display/intel_display_regs.h" #include "display/intel_dpio_phy.h" + #include "gt/intel_gt_regs.h" +#include "gvt.h" +#include "i915_drv.h" +#include "i915_reg.h" + /** * intel_vgpu_gpa_to_mmio_offset - translate a GPA to MMIO offset * @vgpu: a vGPU diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.h b/drivers/gpu/drm/i915/gvt/mmio_context.h index a821edf574dd..c0e3695e3bbe 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.h +++ b/drivers/gpu/drm/i915/gvt/mmio_context.h @@ -38,8 +38,6 @@ #include <linux/types.h> -#include "gt/intel_engine_regs.h" - struct i915_request; struct intel_context; struct intel_engine_cs; @@ -57,7 +55,4 @@ bool is_inhibit_context(struct intel_context *ce); int intel_vgpu_restore_inhibit_context(struct intel_vgpu *vgpu, struct i915_request *req); -#define IS_RESTORE_INHIBIT(a) \ - IS_MASKED_BITS_ENABLED(a, CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT) - #endif diff --git a/drivers/gpu/drm/i915/gvt/opregion.c b/drivers/gpu/drm/i915/gvt/opregion.c index dbad4d853d3a..d6e76ba31d60 100644 --- a/drivers/gpu/drm/i915/gvt/opregion.c +++ b/drivers/gpu/drm/i915/gvt/opregion.c @@ -22,8 +22,9 @@ */ #include <linux/acpi.h> -#include "i915_drv.h" + #include "gvt.h" +#include "i915_drv.h" /* * Note: Only for GVT-g virtual VBT generation, other usage must diff --git a/drivers/gpu/drm/i915/gvt/page_track.c b/drivers/gpu/drm/i915/gvt/page_track.c index 20c3cd807488..b22ef801963e 100644 --- a/drivers/gpu/drm/i915/gvt/page_track.c +++ b/drivers/gpu/drm/i915/gvt/page_track.c @@ -20,8 +20,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "i915_drv.h" + #include "gvt.h" +#include "i915_drv.h" /** * intel_vgpu_find_page_track - find page track rcord of guest page diff --git a/drivers/gpu/drm/i915/gvt/sched_policy.c b/drivers/gpu/drm/i915/gvt/sched_policy.c index 6c2d68e88266..9736a15a896f 100644 --- a/drivers/gpu/drm/i915/gvt/sched_policy.c +++ b/drivers/gpu/drm/i915/gvt/sched_policy.c @@ -31,8 +31,9 @@ * */ -#include "i915_drv.h" #include "gvt.h" +#include "i915_drv.h" +#include "sched_policy.h" static bool vgpu_has_pending_workload(struct intel_vgpu *vgpu) { diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index 63ad1fed525a..15fdd514ca83 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -38,20 +38,26 @@ #include <drm/drm_print.h> #include "gem/i915_gem_pm.h" + #include "gt/intel_context.h" +#include "gt/intel_engine_regs.h" #include "gt/intel_execlists_submission.h" #include "gt/intel_gt_regs.h" #include "gt/intel_lrc.h" #include "gt/intel_ring.h" +#include "gvt.h" #include "i915_drv.h" #include "i915_gem_gtt.h" #include "i915_perf_oa_regs.h" -#include "gvt.h" +#include "sched_policy.h" #define RING_CTX_OFF(x) \ offsetof(struct execlist_ring_context, x) +#define IS_RESTORE_INHIBIT(a) \ + IS_MASKED_BITS_ENABLED(a, CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT) + static void set_context_pdp_root_pointer( struct execlist_ring_context *ring_context, u32 pdp[8]) diff --git a/drivers/gpu/drm/i915/gvt/trace.h b/drivers/gpu/drm/i915/gvt/trace.h index 63874d385c6f..8cd0601e478f 100644 --- a/drivers/gpu/drm/i915/gvt/trace.h +++ b/drivers/gpu/drm/i915/gvt/trace.h @@ -31,9 +31,9 @@ #if !defined(_GVT_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) #define _GVT_TRACE_H_ -#include <linux/types.h> #include <linux/stringify.h> #include <linux/tracepoint.h> +#include <linux/types.h> #include <asm/tsc.h> #undef TRACE_SYSTEM diff --git a/drivers/gpu/drm/i915/gvt/trace_points.c b/drivers/gpu/drm/i915/gvt/trace_points.c index fe552e877e09..79b75356d622 100644 --- a/drivers/gpu/drm/i915/gvt/trace_points.c +++ b/drivers/gpu/drm/i915/gvt/trace_points.c @@ -30,5 +30,7 @@ #ifndef __CHECKER__ #define CREATE_TRACE_POINTS + #include "trace.h" + #endif diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index c49e4bf95a30..96d0bd1fa337 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -31,12 +31,14 @@ * */ +#include <linux/vmalloc.h> + #include <drm/drm_print.h> -#include "i915_drv.h" #include "gvt.h" +#include "i915_drv.h" #include "i915_pvinfo.h" -#include <linux/vmalloc.h> +#include "sched_policy.h" void populate_pvinfo_page(struct intel_vgpu *vgpu) { diff --git a/drivers/gpu/drm/i915/i915_config.c b/drivers/gpu/drm/i915/i915_config.c index 3cb615ffa96d..9e13b1be407c 100644 --- a/drivers/gpu/drm/i915/i915_config.c +++ b/drivers/gpu/drm/i915/i915_config.c @@ -8,8 +8,7 @@ #include "i915_config.h" #include "i915_jiffies.h" -unsigned long -i915_fence_context_timeout(const struct drm_i915_private *i915, u64 context) +unsigned long i915_fence_context_timeout(u64 context) { if (CONFIG_DRM_I915_FENCE_TIMEOUT && context) return msecs_to_jiffies_timeout(CONFIG_DRM_I915_FENCE_TIMEOUT); diff --git a/drivers/gpu/drm/i915/i915_config.h b/drivers/gpu/drm/i915/i915_config.h index 10e18b036489..f386328d9e95 100644 --- a/drivers/gpu/drm/i915/i915_config.h +++ b/drivers/gpu/drm/i915/i915_config.h @@ -9,15 +9,11 @@ #include <linux/types.h> #include <linux/limits.h> -struct drm_i915_private; +unsigned long i915_fence_context_timeout(u64 context); -unsigned long i915_fence_context_timeout(const struct drm_i915_private *i915, - u64 context); - -static inline unsigned long -i915_fence_timeout(const struct drm_i915_private *i915) +static inline unsigned long i915_fence_timeout(void) { - return i915_fence_context_timeout(i915, U64_MAX); + return i915_fence_context_timeout(U64_MAX); } #endif /* __I915_CONFIG_H__ */ diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index e025273e9ab1..f0105c5b49a7 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -99,6 +99,7 @@ #include "i915_gmch.h" #include "i915_hdcp_gsc.h" #include "i915_hwmon.h" +#include "i915_initial_plane.h" #include "i915_ioc32.h" #include "i915_ioctl.h" #include "i915_irq.h" @@ -764,6 +765,7 @@ static bool vgpu_active(struct drm_device *drm) static const struct intel_display_parent_interface parent = { .hdcp = &i915_display_hdcp_interface, + .initial_plane = &i915_display_initial_plane_interface, .irq = &i915_display_irq_interface, .panic = &i915_display_panic_interface, .pc8 = &i915_display_pc8_interface, diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 7582ef34bf3f..303d8d9b7775 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -686,7 +686,7 @@ static void err_print_guc_ctb(struct drm_i915_error_state_buf *m, } /* This list includes registers that are useful in debugging GuC hangs. */ -const struct { +static const struct { u32 start; u32 count; } guc_hw_reg_state[] = { diff --git a/drivers/gpu/drm/i915/i915_initial_plane.c b/drivers/gpu/drm/i915/i915_initial_plane.c new file mode 100644 index 000000000000..7fb52d81f7b6 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_initial_plane.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include <drm/drm_print.h> +#include <drm/intel/display_parent_interface.h> + +#include "display/intel_crtc.h" +#include "display/intel_display_types.h" +#include "display/intel_fb.h" +#include "gem/i915_gem_lmem.h" +#include "gem/i915_gem_region.h" + +#include "i915_drv.h" +#include "i915_initial_plane.h" + +static void i915_initial_plane_vblank_wait(struct drm_crtc *crtc) +{ + intel_crtc_wait_for_next_vblank(to_intel_crtc(crtc)); +} + +static enum intel_memory_type +initial_plane_memory_type(struct drm_i915_private *i915) +{ + if (IS_DGFX(i915)) + 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 drm_i915_private *i915, + struct intel_initial_plane_config *plane_config) +{ + 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(i915); + mem = intel_memory_region_by_type(i915, mem_type); + if (!mem) { + drm_dbg_kms(&i915->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(&i915->drm, "Initial plane FB PTE not present\n"); + return false; + } + + if (intel_memory_type_is_local(mem->type) != is_local) { + drm_err(&i915->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(&i915->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(&i915->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 drm_i915_private *i915, + struct intel_initial_plane_config *plane_config) +{ + 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(i915, 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(&i915->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(&i915->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(&i915->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 struct drm_gem_object * +i915_alloc_initial_plane_obj(struct drm_device *drm, + struct intel_initial_plane_config *plane_config) +{ + struct drm_i915_private *i915 = to_i915(drm); + struct drm_mode_fb_cmd2 mode_cmd = {}; + struct drm_framebuffer *fb = &plane_config->fb->base; + struct i915_vma *vma; + + vma = initial_plane_vma(i915, plane_config); + if (!vma) + return NULL; + + 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(&i915->drm, "intel fb init failed\n"); + goto err_vma; + } + + plane_config->vma = vma; + return intel_bo_to_drm_bo(vma->obj); + +err_vma: + i915_vma_put(vma); + return NULL; +} + +static int +i915_initial_plane_setup(struct drm_plane_state *_plane_state, + struct intel_initial_plane_config *plane_config, + struct drm_framebuffer *fb, + struct i915_vma *vma) +{ + struct intel_plane_state *plane_state = to_intel_plane_state(_plane_state); + struct drm_i915_private *dev_priv = to_i915(_plane_state->plane->dev); + + __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); + + if (fb->modifier != DRM_FORMAT_MOD_LINEAR) + dev_priv->preserve_bios_swizzle = true; + + return 0; +} + +static void i915_plane_config_fini(struct intel_initial_plane_config *plane_config) +{ + if (plane_config->vma) + i915_vma_put(plane_config->vma); +} + +const struct intel_display_initial_plane_interface i915_display_initial_plane_interface = { + .vblank_wait = i915_initial_plane_vblank_wait, + .alloc_obj = i915_alloc_initial_plane_obj, + .setup = i915_initial_plane_setup, + .config_fini = i915_plane_config_fini, +}; diff --git a/drivers/gpu/drm/i915/i915_initial_plane.h b/drivers/gpu/drm/i915/i915_initial_plane.h new file mode 100644 index 000000000000..99ba462659a6 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_initial_plane.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __I915_INITIAL_PLANE_H__ +#define __I915_INITIAL_PLANE_H__ + +extern const struct intel_display_initial_plane_interface i915_display_initial_plane_interface; + +#endif diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 4399941236cb..d2c7b1090df0 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1351,8 +1351,7 @@ __i915_request_await_external(struct i915_request *rq, struct dma_fence *fence) { mark_external(rq); return i915_sw_fence_await_dma_fence(&rq->submit, fence, - i915_fence_context_timeout(rq->i915, - fence->context), + i915_fence_context_timeout(fence->context), I915_FENCE_GFP); } diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index 9e5b7fcadbe2..ecc20e0528f4 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -38,22 +38,18 @@ struct drm_i915_private; -#ifndef MISSING_CASE #define MISSING_CASE(x) WARN(1, "Missing case (%s == %ld)\n", \ __stringify(x), (long)(x)) -#endif #define i915_probe_error(i915, fmt, ...) ({ \ drm_err(&(i915)->drm, fmt, ##__VA_ARGS__); \ }) -#ifndef fetch_and_zero #define fetch_and_zero(ptr) ({ \ typeof(*ptr) __T = *(ptr); \ *(ptr) = (typeof(*ptr))0; \ __T; \ }) -#endif /* * check_user_mbz: Check that a user value exists and is zero diff --git a/drivers/gpu/drm/i915/intel_gvt.c b/drivers/gpu/drm/i915/intel_gvt.c index 5f615ec0e580..6b43713899b8 100644 --- a/drivers/gpu/drm/i915/intel_gvt.c +++ b/drivers/gpu/drm/i915/intel_gvt.c @@ -21,16 +21,19 @@ * SOFTWARE. */ +#include <linux/vmalloc.h> + #include <drm/drm_print.h> -#include "i915_drv.h" -#include "i915_vgpu.h" -#include "intel_gvt.h" #include "gem/i915_gem_dmabuf.h" + #include "gt/intel_context.h" #include "gt/intel_ring.h" #include "gt/shmem_utils.h" -#include <linux/vmalloc.h> + +#include "i915_drv.h" +#include "i915_vgpu.h" +#include "intel_gvt.h" /** * DOC: Intel GVT-g host support diff --git a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c index ca57a3dd3148..478d00f89a4b 100644 --- a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c +++ b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c @@ -12,6 +12,7 @@ #include "display/intel_crt_regs.h" #include "display/intel_cursor_regs.h" #include "display/intel_display_core.h" +#include "display/intel_display_regs.h" #include "display/intel_display_types.h" #include "display/intel_dmc_regs.h" #include "display/intel_dp_aux_regs.h" @@ -27,14 +28,15 @@ #include "display/skl_universal_plane_regs.h" #include "display/skl_watermark_regs.h" #include "display/vlv_dsi_pll_regs.h" + #include "gt/intel_engine_regs.h" #include "gt/intel_gt_regs.h" + #include "gvt/reg.h" #include "i915_drv.h" #include "i915_pvinfo.h" #include "i915_reg.h" -#include "display/intel_display_regs.h" #include "intel_gvt.h" #include "intel_mchbar_regs.h" diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 8dcc85cb8d42..2b20c79d7ec9 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -200,8 +200,7 @@ endif # i915 Display compat #defines and #includes subdir-ccflags-$(CONFIG_DRM_XE_DISPLAY) += \ -I$(src)/compat-i915-headers \ - -I$(srctree)/drivers/gpu/drm/i915/display/ \ - -Ddrm_i915_private=xe_device + -I$(srctree)/drivers/gpu/drm/i915/display/ # Rule to build display code shared with i915 $(obj)/i915-display/%.o: $(srctree)/drivers/gpu/drm/i915/display/%.c FORCE @@ -219,8 +218,8 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ display/xe_dsb_buffer.o \ display/xe_fb_pin.o \ display/xe_hdcp_gsc.o \ + display/xe_initial_plane.o \ display/xe_panic.o \ - display/xe_plane_initial.o \ display/xe_stolen.o \ display/xe_tdf.o @@ -296,6 +295,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/intel_hotplug.o \ i915-display/intel_hotplug_irq.o \ i915-display/intel_hti.o \ + i915-display/intel_initial_plane.o \ i915-display/intel_link_bw.o \ i915-display/intel_lspcon.o \ i915-display/intel_lt_phy.o \ diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_config.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_config.h index e835bea08d1b..d4522203e2dd 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/i915_config.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/i915_config.h @@ -8,10 +8,7 @@ #include <linux/sched.h> -struct drm_i915_private; - -static inline unsigned long -i915_fence_timeout(const struct drm_i915_private *i915) +static inline unsigned long i915_fence_timeout(void) { return MAX_SCHEDULE_TIMEOUT; } diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h deleted file mode 100644 index 04d1925f9a19..000000000000 --- a/drivers/gpu/drm/xe/compat-i915-headers/i915_drv.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2023 Intel Corporation - */ -#ifndef _XE_I915_DRV_H_ -#define _XE_I915_DRV_H_ - -/* - * "Adaptation header" to allow i915 display to also build for xe driver. - * TODO: refactor i915 and xe so this can cease to exist - */ - -#include <drm/drm_drv.h> - -#include "xe_device_types.h" - -static inline struct drm_i915_private *to_i915(const struct drm_device *dev) -{ - return container_of(dev, struct drm_i915_private, drm); -} - -#endif diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_utils.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_utils.h deleted file mode 100644 index 3639721f0bf8..000000000000 --- a/drivers/gpu/drm/xe/compat-i915-headers/i915_utils.h +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2023 Intel Corporation - */ - -/* for a couple of users under i915/display */ -#define i915_inject_probe_failure(unused) ((unused) && 0) diff --git a/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h b/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h index d93ddacdf743..c05d4c4292d3 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h @@ -10,8 +10,6 @@ #include "xe_device_types.h" #include "xe_mmio.h" -#define FORCEWAKE_ALL XE_FORCEWAKE_ALL - static inline struct intel_uncore *to_intel_uncore(struct drm_device *drm) { return &to_xe_device(drm)->uncore; @@ -154,9 +152,10 @@ static inline void intel_uncore_write_notrace(struct intel_uncore *uncore, xe_mmio_write32(__compat_uncore_to_mmio(uncore), reg, val); } -#define intel_uncore_forcewake_get(x, y) do { } while (0) -#define intel_uncore_forcewake_put(x, y) do { } while (0) - -#define intel_uncore_arm_unclaimed_mmio_detection(x) do { } while (0) +static inline bool +intel_uncore_arm_unclaimed_mmio_detection(struct intel_uncore *uncore) +{ + return false; +} #endif /* __INTEL_UNCORE_H__ */ diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index eda65a05f601..f8a831b5dc7d 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -37,6 +37,7 @@ #include "skl_watermark.h" #include "xe_display_rpm.h" #include "xe_hdcp_gsc.h" +#include "xe_initial_plane.h" #include "xe_module.h" #include "xe_panic.h" #include "xe_stolen.h" @@ -538,6 +539,7 @@ static const struct intel_display_irq_interface xe_display_irq_interface = { static const struct intel_display_parent_interface parent = { .hdcp = &xe_display_hdcp_interface, + .initial_plane = &xe_display_initial_plane_interface, .irq = &xe_display_irq_interface, .panic = &xe_display_panic_interface, .rpm = &xe_display_rpm_interface, diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c index 6a935a75f2a4..a22a9182dadb 100644 --- a/drivers/gpu/drm/xe/display/xe_fb_pin.c +++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c @@ -373,7 +373,7 @@ intel_fb_pin_to_ggtt(const struct drm_framebuffer *fb, { *out_flags = 0; - return __xe_pin_fb_vma(to_intel_framebuffer(fb), view, phys_alignment); + return __xe_pin_fb_vma(to_intel_framebuffer(fb), view, alignment); } void intel_fb_unpin_vma(struct i915_vma *vma, unsigned long flags) diff --git a/drivers/gpu/drm/xe/display/xe_initial_plane.c b/drivers/gpu/drm/xe/display/xe_initial_plane.c new file mode 100644 index 000000000000..4cfeafcc158d --- /dev/null +++ b/drivers/gpu/drm/xe/display/xe_initial_plane.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +/* for ioread64 */ +#include <linux/io-64-nonatomic-lo-hi.h> + +#include <drm/intel/display_parent_interface.h> + +#include "regs/xe_gtt_defs.h" +#include "xe_ggtt.h" +#include "xe_mmio.h" + +#include "i915_vma.h" +#include "intel_crtc.h" +#include "intel_display_regs.h" +#include "intel_display_types.h" +#include "intel_fb.h" +#include "intel_fb_pin.h" +#include "xe_bo.h" +#include "xe_vram_types.h" +#include "xe_wa.h" + +#include <generated/xe_device_wa_oob.h> + +/* Early xe has no irq */ +static void xe_initial_plane_vblank_wait(struct drm_crtc *_crtc) +{ + struct intel_crtc *crtc = to_intel_crtc(_crtc); + struct xe_device *xe = to_xe_device(crtc->base.dev); + struct xe_reg pipe_frmtmstmp = XE_REG(i915_mmio_reg_offset(PIPE_FRMTMSTMP(crtc->pipe))); + u32 timestamp; + int ret; + + timestamp = xe_mmio_read32(xe_root_tile_mmio(xe), pipe_frmtmstmp); + + ret = xe_mmio_wait32_not(xe_root_tile_mmio(xe), pipe_frmtmstmp, ~0U, timestamp, 40000U, ×tamp, false); + if (ret < 0) + drm_warn(&xe->drm, "waiting for early vblank failed with %i\n", ret); +} + +static struct xe_bo * +initial_plane_bo(struct xe_device *xe, + struct intel_initial_plane_config *plane_config) +{ + struct xe_tile *tile0 = xe_device_get_root_tile(xe); + struct xe_bo *bo; + resource_size_t phys_base; + u32 base, size, flags; + u64 page_size = xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K; + + if (plane_config->size == 0) + return NULL; + + flags = XE_BO_FLAG_SCANOUT | XE_BO_FLAG_GGTT; + + base = round_down(plane_config->base, page_size); + if (IS_DGFX(xe)) { + u64 pte = xe_ggtt_read_pte(tile0->mem.ggtt, base); + + if (!(pte & XE_GGTT_PTE_DM)) { + drm_err(&xe->drm, + "Initial plane programming missing DM bit\n"); + return NULL; + } + + phys_base = pte & ~(page_size - 1); + flags |= XE_BO_FLAG_VRAM0; + + /* + * We don't currently expect this to ever be placed in the + * stolen portion. + */ + if (phys_base >= xe_vram_region_usable_size(tile0->mem.vram)) { + drm_err(&xe->drm, + "Initial plane programming using invalid range, phys_base=%pa\n", + &phys_base); + return NULL; + } + + drm_dbg(&xe->drm, + "Using phys_base=%pa, based on initial plane programming\n", + &phys_base); + } else { + struct ttm_resource_manager *stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN); + + if (!stolen) + return NULL; + phys_base = base; + flags |= XE_BO_FLAG_STOLEN; + + if (XE_DEVICE_WA(xe, 22019338487_display)) + return NULL; + + /* + * 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) && + plane_config->size * 2 >> PAGE_SHIFT >= stolen->size) + return NULL; + } + + size = round_up(plane_config->base + plane_config->size, + page_size); + size -= base; + + bo = xe_bo_create_pin_map_at_novm(xe, tile0, size, phys_base, + ttm_bo_type_kernel, flags, 0, false); + if (IS_ERR(bo)) { + drm_dbg(&xe->drm, + "Failed to create bo phys_base=%pa size %u with flags %x: %li\n", + &phys_base, size, flags, PTR_ERR(bo)); + return NULL; + } + + return bo; +} + +static struct drm_gem_object * +xe_alloc_initial_plane_obj(struct drm_device *drm, + struct intel_initial_plane_config *plane_config) +{ + struct xe_device *xe = to_xe_device(drm); + struct drm_mode_fb_cmd2 mode_cmd = { 0 }; + struct drm_framebuffer *fb = &plane_config->fb->base; + struct xe_bo *bo; + + 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; + + bo = initial_plane_bo(xe, plane_config); + if (!bo) + return NULL; + + if (intel_framebuffer_init(to_intel_framebuffer(fb), + &bo->ttm.base, fb->format, &mode_cmd)) { + drm_dbg_kms(&xe->drm, "intel fb init failed\n"); + goto err_bo; + } + /* Reference handed over to fb */ + xe_bo_put(bo); + + return &bo->ttm.base; + +err_bo: + xe_bo_unpin_map_no_vm(bo); + return NULL; +} + +static int +xe_initial_plane_setup(struct drm_plane_state *_plane_state, + struct intel_initial_plane_config *plane_config, + struct drm_framebuffer *fb, + struct i915_vma *_unused) +{ + struct intel_plane_state *plane_state = to_intel_plane_state(_plane_state); + struct i915_vma *vma; + + vma = intel_fb_pin_to_ggtt(fb, &plane_state->view.gtt, + 0, 0, 0, false, &plane_state->flags); + if (IS_ERR(vma)) + return PTR_ERR(vma); + + plane_state->ggtt_vma = vma; + + plane_state->surf = i915_ggtt_offset(plane_state->ggtt_vma); + + plane_config->vma = vma; + + return 0; +} + +static void xe_plane_config_fini(struct intel_initial_plane_config *plane_config) +{ +} + +const struct intel_display_initial_plane_interface xe_display_initial_plane_interface = { + .vblank_wait = xe_initial_plane_vblank_wait, + .alloc_obj = xe_alloc_initial_plane_obj, + .setup = xe_initial_plane_setup, + .config_fini = xe_plane_config_fini, +}; diff --git a/drivers/gpu/drm/xe/display/xe_initial_plane.h b/drivers/gpu/drm/xe/display/xe_initial_plane.h new file mode 100644 index 000000000000..399d15f14441 --- /dev/null +++ b/drivers/gpu/drm/xe/display/xe_initial_plane.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __XE_INITIAL_PLANE_H__ +#define __XE_INITIAL_PLANE_H__ + +extern const struct intel_display_initial_plane_interface xe_display_initial_plane_interface; + +#endif diff --git a/drivers/gpu/drm/xe/display/xe_plane_initial.c b/drivers/gpu/drm/xe/display/xe_plane_initial.c deleted file mode 100644 index 01c105a93bb9..000000000000 --- a/drivers/gpu/drm/xe/display/xe_plane_initial.c +++ /dev/null @@ -1,321 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright © 2021 Intel Corporation - */ - -/* for ioread64 */ -#include <linux/io-64-nonatomic-lo-hi.h> - -#include "regs/xe_gtt_defs.h" -#include "xe_ggtt.h" -#include "xe_mmio.h" - -#include "i915_vma.h" -#include "intel_crtc.h" -#include "intel_display.h" -#include "intel_display_core.h" -#include "intel_display_regs.h" -#include "intel_display_types.h" -#include "intel_fb.h" -#include "intel_fb_pin.h" -#include "intel_frontbuffer.h" -#include "intel_plane.h" -#include "intel_plane_initial.h" -#include "xe_bo.h" -#include "xe_vram_types.h" -#include "xe_wa.h" - -#include <generated/xe_device_wa_oob.h> - -void intel_plane_initial_vblank_wait(struct intel_crtc *crtc) -{ - /* Early xe has no irq */ - struct xe_device *xe = to_xe_device(crtc->base.dev); - struct xe_reg pipe_frmtmstmp = XE_REG(i915_mmio_reg_offset(PIPE_FRMTMSTMP(crtc->pipe))); - u32 timestamp; - int ret; - - timestamp = xe_mmio_read32(xe_root_tile_mmio(xe), pipe_frmtmstmp); - - ret = xe_mmio_wait32_not(xe_root_tile_mmio(xe), pipe_frmtmstmp, ~0U, timestamp, 40000U, ×tamp, false); - if (ret < 0) - drm_warn(&xe->drm, "waiting for early vblank failed with %i\n", ret); -} - -static bool -intel_reuse_initial_plane_obj(struct intel_crtc *this, - const struct intel_initial_plane_config plane_configs[], - struct drm_framebuffer **fb) -{ - struct xe_device *xe = to_xe_device(this->base.dev); - struct intel_crtc *crtc; - - for_each_intel_crtc(&xe->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; - return true; - } - } - - return false; -} - -static struct xe_bo * -initial_plane_bo(struct xe_device *xe, - struct intel_initial_plane_config *plane_config) -{ - struct xe_tile *tile0 = xe_device_get_root_tile(xe); - struct xe_bo *bo; - resource_size_t phys_base; - u32 base, size, flags; - u64 page_size = xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K; - - if (plane_config->size == 0) - return NULL; - - flags = XE_BO_FLAG_SCANOUT | XE_BO_FLAG_GGTT; - - base = round_down(plane_config->base, page_size); - if (IS_DGFX(xe)) { - u64 pte = xe_ggtt_read_pte(tile0->mem.ggtt, base); - - if (!(pte & XE_GGTT_PTE_DM)) { - drm_err(&xe->drm, - "Initial plane programming missing DM bit\n"); - return NULL; - } - - phys_base = pte & ~(page_size - 1); - flags |= XE_BO_FLAG_VRAM0; - - /* - * We don't currently expect this to ever be placed in the - * stolen portion. - */ - if (phys_base >= xe_vram_region_usable_size(tile0->mem.vram)) { - drm_err(&xe->drm, - "Initial plane programming using invalid range, phys_base=%pa\n", - &phys_base); - return NULL; - } - - drm_dbg(&xe->drm, - "Using phys_base=%pa, based on initial plane programming\n", - &phys_base); - } else { - struct ttm_resource_manager *stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN); - - if (!stolen) - return NULL; - phys_base = base; - flags |= XE_BO_FLAG_STOLEN; - - if (XE_DEVICE_WA(xe, 22019338487_display)) - return NULL; - - /* - * 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) && - plane_config->size * 2 >> PAGE_SHIFT >= stolen->size) - return NULL; - } - - size = round_up(plane_config->base + plane_config->size, - page_size); - size -= base; - - bo = xe_bo_create_pin_map_at_novm(xe, tile0, size, phys_base, - ttm_bo_type_kernel, flags, 0, false); - if (IS_ERR(bo)) { - drm_dbg(&xe->drm, - "Failed to create bo phys_base=%pa size %u with flags %x: %li\n", - &phys_base, size, flags, PTR_ERR(bo)); - return NULL; - } - - return bo; -} - -static bool -intel_alloc_initial_plane_obj(struct intel_crtc *crtc, - struct intel_initial_plane_config *plane_config) -{ - struct xe_device *xe = to_xe_device(crtc->base.dev); - struct drm_mode_fb_cmd2 mode_cmd = { 0 }; - struct drm_framebuffer *fb = &plane_config->fb->base; - struct xe_bo *bo; - - 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_kms(&xe->drm, - "Unsupported modifier for initial FB: 0x%llx\n", - fb->modifier); - 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; - - bo = initial_plane_bo(xe, plane_config); - if (!bo) - return false; - - if (intel_framebuffer_init(to_intel_framebuffer(fb), - &bo->ttm.base, fb->format, &mode_cmd)) { - drm_dbg_kms(&xe->drm, "intel fb init failed\n"); - goto err_bo; - } - /* Reference handed over to fb */ - xe_bo_put(bo); - - return true; - -err_bo: - xe_bo_unpin_map_no_vm(bo); - return false; -} - -static void -intel_find_initial_plane_obj(struct intel_crtc *crtc, - struct intel_initial_plane_config plane_configs[]) -{ - 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; - else if (!intel_reuse_initial_plane_obj(crtc, plane_configs, &fb)) - goto nofb; - - plane_state->uapi.rotation = plane_config->rotation; - intel_fb_fill_view(to_intel_framebuffer(fb), - plane_state->uapi.rotation, &plane_state->view); - - vma = intel_fb_pin_to_ggtt(fb, &plane_state->view.gtt, - 0, 0, 0, false, &plane_state->flags); - if (IS_ERR(vma)) - goto nofb; - - plane_state->ggtt_vma = vma; - - 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; - - 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); - - plane_config->vma = vma; - 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_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); - } -} - -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); - } -} diff --git a/include/drm/intel/display_parent_interface.h b/include/drm/intel/display_parent_interface.h index 10c50b42844e..ce946859a3a9 100644 --- a/include/drm/intel/display_parent_interface.h +++ b/include/drm/intel/display_parent_interface.h @@ -7,9 +7,15 @@ #include <linux/types.h> struct dma_fence; +struct drm_crtc; struct drm_device; +struct drm_framebuffer; +struct drm_gem_object; +struct drm_plane_state; struct drm_scanout_buffer; +struct i915_vma; struct intel_hdcp_gsc_context; +struct intel_initial_plane_config; struct intel_panic; struct intel_stolen_node; struct ref_tracker; @@ -25,6 +31,14 @@ struct intel_display_hdcp_interface { void (*gsc_context_free)(struct intel_hdcp_gsc_context *gsc_context); }; +struct intel_display_initial_plane_interface { + void (*vblank_wait)(struct drm_crtc *crtc); + struct drm_gem_object *(*alloc_obj)(struct drm_device *drm, struct intel_initial_plane_config *plane_config); + int (*setup)(struct drm_plane_state *plane_state, struct intel_initial_plane_config *plane_config, + struct drm_framebuffer *fb, struct i915_vma *vma); + void (*config_fini)(struct intel_initial_plane_config *plane_configs); +}; + struct intel_display_irq_interface { bool (*enabled)(struct drm_device *drm); void (*synchronize)(struct drm_device *drm); @@ -95,6 +109,9 @@ struct intel_display_parent_interface { /** @hdcp: HDCP GSC interface */ const struct intel_display_hdcp_interface *hdcp; + /** @initial_plane: Initial plane interface */ + const struct intel_display_initial_plane_interface *initial_plane; + /** @irq: IRQ interface */ const struct intel_display_irq_interface *irq; diff --git a/include/drm/intel/intel_lb_mei_interface.h b/include/drm/intel/intel_lb_mei_interface.h index d65be2cba2ab..0850738a30fc 100644 --- a/include/drm/intel/intel_lb_mei_interface.h +++ b/include/drm/intel/intel_lb_mei_interface.h @@ -53,7 +53,8 @@ enum intel_lb_status { */ struct intel_lb_component_ops { /** - * push_payload - Sends a payload to the authentication firmware + * @push_payload: Sends a payload to the authentication firmware + * * @dev: Device struct corresponding to the mei device * @type: Payload type (see &enum intel_lb_type) * @flags: Payload flags bitmap (e.g. %INTEL_LB_FLAGS_IS_PERSISTENT) |
