summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-09-08 21:05:59 +1000
committerDave Airlie <airlied@redhat.com>2026-09-08 21:06:06 +1000
commitf5c6fdfa1f4460c5714cd4996c6aa280d25399ca (patch)
tree23a2ecfed79d0786010732f0b6a4d289df27998d
parent483ece619b64a6596bdaf69479ea0ecbbd197a00 (diff)
parent0d63d6fc993b1fb97e314f435bdefbf0ccd947bd (diff)
downloadlinux-next-f5c6fdfa1f4460c5714cd4996c6aa280d25399ca.tar.gz
linux-next-f5c6fdfa1f4460c5714cd4996c6aa280d25399ca.zip
Merge tag 'drm-intel-next-2026-09-03' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-next
Xe related: - Some clean-ups around drm/xe/display (Jani) Display in general: - Regular clean-ups (Jani) - Enable CMRR (Content Match Refresh Rate) in fixed-RR VRR path (Mitul) - Switch DG2 Multi-protocol PLL (MPLLB) to the DPLL framework (Mika) - DP-HDMI PCON DSC fixes (Ankit) - Remove duplicated call introduced by a bad cherry-pick (Chaitanya) - Limit invalid joiner combinations harder (Jani) - Fix value being written to DDI_CLK_VALFREQ (Suraj) - Harden some bit-shifting operations (Luca) - Clear SEL_FETCH_PLANE_CTL on plane disable (Nemesa) - Update CURSOR_BUF/WM masks (Suraj) - CDCLK related fixes and refactor specially around PCODE interaction (Ville) - Reduce clock_gating interface between core and display (Luca) - Gate UHBR SST SDP splitting on sink capability (Mitul) - Enable joiner cursor fast updates (Nemesa) - Cear the Panel Replay error status register (Jake) - Add HDMI TMDS audio bandwidth check (Chaitanya) - Reset use_flipq when duplicating crtc state (Mika) Beyond display: - Guard against NULL driver_data (Deepanshu) - Rename GEN6_PCODE_DATA to match spec (Michal) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patch.msgid.link/apmWNIUJ5lmsvNzc@intel.com
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio.c153
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio_regs.h16
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.c326
-rw-r--r--drivers/gpu/drm/i915/display/intel_cmtg.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_crtc_state_dump.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_cursor.c292
-rw-r--r--drivers/gpu/drm/i915/display/intel_cursor_regs.h8
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c34
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c76
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_clock_gating.c67
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_clock_gating.h16
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_debugfs.c21
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power_well.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_regs.h18
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h19
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_wa.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_wa.h9
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c96
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll.c22
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.c221
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.h22
-rw-r--r--drivers/gpu/drm/i915/display/intel_frontbuffer.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.c53
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.h11
-rw-r--r--drivers/gpu/drm/i915/display/intel_hti.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_modeset_verify.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_parent.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_parent.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c18
-rw-r--r--drivers/gpu/drm/i915/display/intel_snps_phy.c60
-rw-r--r--drivers/gpu/drm/i915/display/intel_snps_phy.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_tdf.h25
-rw-r--r--drivers/gpu/drm/i915/display/intel_vrr.c393
-rw-r--r--drivers/gpu/drm/i915/display/intel_vrr.h2
-rw-r--r--drivers/gpu/drm/i915/gvt/handlers.c2
-rw-r--r--drivers/gpu/drm/i915/i915_dpt.c1
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h2
-rw-r--r--drivers/gpu/drm/i915/intel_clock_gating.c30
-rw-r--r--drivers/gpu/drm/i915/intel_gvt_mmio_table.c2
-rw-r--r--drivers/gpu/drm/i915/intel_pcode.c14
-rw-r--r--drivers/gpu/drm/i915/intel_pcode.h2
-rw-r--r--drivers/gpu/drm/xe/Makefile3
-rw-r--r--drivers/gpu/drm/xe/display/xe_display.c22
-rw-r--r--drivers/gpu/drm/xe/display/xe_display_rpm.c2
-rw-r--r--drivers/gpu/drm/xe/display/xe_display_wa.c13
-rw-r--r--drivers/gpu/drm/xe/display/xe_display_wa.h9
-rw-r--r--drivers/gpu/drm/xe/display/xe_tdf.c15
-rw-r--r--include/drm/intel/display_parent_interface.h15
51 files changed, 1540 insertions, 615 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
index 9d0d47c79dd1..b66c2d4ba2b3 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -276,6 +276,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
crtc_state->dsb_color = NULL;
crtc_state->dsb_commit = NULL;
crtc_state->use_dsb = false;
+ crtc_state->use_flipq = false;
return &crtc_state->uapi;
}
diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c
index eae76e961105..32f8c5e55319 100644
--- a/drivers/gpu/drm/i915/display/intel_audio.c
+++ b/drivers/gpu/drm/i915/display/intel_audio.c
@@ -697,6 +697,156 @@ static void ibx_audio_codec_enable(struct intel_encoder *encoder,
mutex_unlock(&display->audio.mutex);
}
+#define HDMI_TMDS_AUDIO_PACKETS_LINE_MAX 18
+
+static bool hdmi_audio_rate_supported(const struct intel_crtc_state *crtc_state,
+ int available_tmds,
+ int audio_rate, int channels)
+{
+ const struct drm_display_mode *mode = &crtc_state->hw.adjusted_mode;
+ int pixel_clk_max_hz;
+ int audio_pkt_factor;
+ u64 audio_pkt_rate_x4_x1000;
+ int audio_packets_line;
+ int hblank_overhead;
+ int hblank_audio_min;
+
+ /*
+ * Part 2: Calculate TMDS clock cycles required for Audio Bandwidth
+ *
+ * Step 1: pixelclk_max = nominal_pixel_rate * (1 + 0.5%)
+ * crtc_clock (kHz) * 1000 * 1.005 = crtc_clock * 1005 (Hz)
+ */
+ pixel_clk_max_hz = mode->crtc_clock * 1005;
+
+ /*
+ * Steps 3-4: Audio Packet Rate.
+ * R_AP = (audio_rate * AP + 2 * acrrate_max) * (1 + 1000 / 1e6)
+ * = (audio_rate * AP + 2*1500) * 1.001
+ *
+ * AP = 0.25 (2ch) or 1.0 (3-8ch); acrrate_max = 1500 Hz (max ACR
+ * packet transmission rate per HDMI spec)
+ *
+ * Scale by 4*1000 to stay integer:
+ * x4: eliminates AP=0.25 -> audio_pkt_factor=1(2ch) or 4(3-8ch),
+ * scaled acrrate_max: 2 * 1500 * 4 = 12000
+ * x1000: eliminates 1.001 -> *1000*1.001 = *1001
+ *
+ * R_AP * 4 * 1000 = (audio_rate * audio_pkt_factor + 12000) * 1001
+ */
+ audio_pkt_factor = (channels <= 2) ? 1 : 4;
+ audio_pkt_rate_x4_x1000 = (u64)(audio_rate * audio_pkt_factor + 12000) * 1001;
+
+ /*
+ * Steps 2+5-6: Audio packets per line.
+ * AudioPackets_Line = CEIL[R_AP * htotal / f_pixelclk_max]
+ *
+ * With audio_pkt_rate_x4_x1000 = R_AP * 4 * 1000:
+ * = CEIL[audio_pkt_rate_x4_x1000 * htotal / (4 * 1000 * pixel_clk_max_hz)]
+ */
+ audio_packets_line = DIV64_U64_ROUND_UP(audio_pkt_rate_x4_x1000 * mode->htotal,
+ (u64)4 * 1000 * pixel_clk_max_hz);
+
+ /*
+ * Steps 7-9: Hblank overhead.
+ * Standard: 2*dip_guardband + 2*control_period + video_guardband
+ * = 2*2 + 2*12 + 2 = 30
+ * HDCP 1.x: rekey_period + dip_guardband + control_period + video_guardband
+ * = 58 + 2 + 12 + 2 = 74
+ *
+ * Always use HDCP 1.x worst case (74) since HDCP can be toggled
+ * via fastset without compute_config.
+ */
+ hblank_overhead = 74;
+
+ /*
+ * Step 10: Required TMDS cycles for Audio.
+ * 32 TMDS clock cycles per audio packet.
+ * Hblank_audio_min = 32 * AudioPackets_Line + Hblank_overhead
+ */
+ hblank_audio_min = 32 * audio_packets_line + hblank_overhead;
+
+ /*
+ * Part 3: audio supported if Hblank_audio_min <= TB_blank and
+ * audio packets per line <= Maximum allowed packets per line
+ */
+ return hblank_audio_min <= available_tmds &&
+ audio_packets_line <= HDMI_TMDS_AUDIO_PACKETS_LINE_MAX;
+}
+
+static void intel_audio_hdmi_eld_compute_config(struct intel_crtc_state *crtc_state)
+{
+ static const int sad_freqs[] = {
+ 32000, 44100, 48000, 88200, 96000, 176400, 192000
+ };
+ const struct drm_display_mode *mode = &crtc_state->hw.adjusted_mode;
+ int hblank = mode->htotal - mode->hdisplay;
+ int bpc = crtc_state->pipe_bpp / 3;
+ int ycbcr_420_divider = (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) ? 2 : 1;
+ int available_tmds;
+ u8 *eld = crtc_state->eld;
+ int mnl = drm_eld_mnl(eld);
+ int sad_count = drm_eld_sad_count(eld);
+ int src, dst = 0;
+
+ /*
+ * Part 1: Calculate available TMDS clock cycles (TB_blank).
+ *
+ * TB_blank = CEILING[hblank * K_CD / K_420]
+ *
+ * K_CD = 1 for YCbCr4:2:2, bpc / 8 otherwise.
+ * K_420 = 2 for YCbCr4:2:0, 1 otherwise.
+ * Rearranged: CEILING[hblank * bpc / (8 * K_420)]
+ *
+ * TODO: As and when support for YCbCr4:2:2 is added, set bpc = 8
+ * to achieve K_CD = 1
+ */
+ available_tmds = DIV_ROUND_UP(hblank * bpc, 8 * ycbcr_420_divider);
+
+ /*
+ * Walk all SADs once, keeping the ones with at least one supported
+ * rate and compacting them down to a contiguous [0, dst) range.
+ */
+ for (src = 0; src < sad_count; src++) {
+ struct cea_sad sad;
+ u8 new_freq_mask = 0;
+ int channels;
+ int bit;
+
+ drm_eld_sad_get(eld, src, &sad);
+ channels = sad.channels + 1;
+
+ for (bit = 0; bit < 7; bit++) {
+ if (!(sad.freq & BIT(bit)))
+ continue;
+ if (hdmi_audio_rate_supported(crtc_state, available_tmds,
+ sad_freqs[bit], channels))
+ new_freq_mask |= BIT(bit);
+ }
+
+ if (!new_freq_mask)
+ continue;
+
+ sad.freq = new_freq_mask;
+ drm_eld_sad_set(eld, dst, &sad);
+ dst++;
+ }
+
+ /* Clear the now-unused tail */
+ if (dst != sad_count)
+ memset(&eld[DRM_ELD_CEA_SAD(mnl, dst)], 0, (sad_count - dst) * 3);
+
+ sad_count = dst;
+
+ /* Update SAD count in ELD header */
+ eld[DRM_ELD_SAD_COUNT_CONN_TYPE] &= ~DRM_ELD_SAD_COUNT_MASK;
+ eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= sad_count << DRM_ELD_SAD_COUNT_SHIFT;
+
+ /* Recalculate baseline ELD length (in dwords) */
+ eld[DRM_ELD_BASELINE_ELD_LEN] =
+ DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4);
+}
+
static
bool intel_audio_needs_cpu_transcoder_id(const struct intel_crtc_state *crtc_state)
{
@@ -725,6 +875,9 @@ bool intel_audio_compute_config(struct intel_encoder *encoder,
BUILD_BUG_ON(sizeof(crtc_state->eld) != sizeof(connector->eld));
memcpy(crtc_state->eld, connector->eld, sizeof(crtc_state->eld));
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+ intel_audio_hdmi_eld_compute_config(crtc_state);
+
crtc_state->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
mutex_unlock(&connector->eld_mutex);
diff --git a/drivers/gpu/drm/i915/display/intel_audio_regs.h b/drivers/gpu/drm/i915/display/intel_audio_regs.h
index 4c31844d21df..f3d2a99c03d0 100644
--- a/drivers/gpu/drm/i915/display/intel_audio_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_audio_regs.h
@@ -109,12 +109,20 @@
#define _HSW_AUD_EDID_DATA_B 0x65150
#define HSW_AUD_EDID_DATA(trans) _MMIO_TRANS(trans, _HSW_AUD_EDID_DATA_A, _HSW_AUD_EDID_DATA_B)
+/*
+ * HSW_AUD_PIN_ELD_CP_VLD has a 4-bit field per transcoder for
+ * TRANSCODER_A..TRANSCODER_D only (bits 0..15). Any other transcoder
+ * value (TRANSCODER_EDP, TRANSCODER_DSI_*, INVALID_TRANSCODER) is not
+ * valid here. Mask the index to the low 2 bits so the shift is
+ * always well-defined.
+ */
#define HSW_AUD_PIPE_CONV_CFG _MMIO(0x6507c)
#define HSW_AUD_PIN_ELD_CP_VLD _MMIO(0x650c0)
-#define AUDIO_INACTIVE(trans) ((1 << 3) << ((trans) * 4))
-#define AUDIO_OUTPUT_ENABLE(trans) ((1 << 2) << ((trans) * 4))
-#define AUDIO_CP_READY(trans) ((1 << 1) << ((trans) * 4))
-#define AUDIO_ELD_VALID(trans) ((1 << 0) << ((trans) * 4))
+#define __AUDIO_TRANS_SHIFT(trans) (((trans) & 0x3) * 4)
+#define AUDIO_INACTIVE(trans) REG_BIT(__AUDIO_TRANS_SHIFT(trans) + 3)
+#define AUDIO_OUTPUT_ENABLE(trans) REG_BIT(__AUDIO_TRANS_SHIFT(trans) + 2)
+#define AUDIO_CP_READY(trans) REG_BIT(__AUDIO_TRANS_SHIFT(trans) + 1)
+#define AUDIO_ELD_VALID(trans) REG_BIT(__AUDIO_TRANS_SHIFT(trans))
#define _AUD_TCA_DP_2DOT0_CTRL 0x650bc
#define _AUD_TCB_DP_2DOT0_CTRL 0x651bc
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index a1a5720996b7..92e6fca861f6 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -163,6 +163,9 @@ struct intel_cdclk_funcs {
void (*set_cdclk)(struct intel_display *display,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe);
+ int (*pre_notify)(struct intel_display *display);
+ int (*post_notify)(struct intel_display *display,
+ const struct intel_cdclk_config *cdclk_config);
int (*modeset_calc_cdclk)(struct intel_atomic_state *state);
u8 (*calc_voltage_level)(int cdclk);
};
@@ -173,11 +176,45 @@ void intel_cdclk_get_cdclk(struct intel_display *display,
display->cdclk.funcs->get_cdclk(display, cdclk_config);
}
+static int intel_cdclk_pre_notify(struct intel_display *display)
+{
+ int ret;
+
+ if (!display->cdclk.funcs->pre_notify)
+ return 0;
+
+ ret = display->cdclk.funcs->pre_notify(display);
+ if (ret)
+ drm_err(display->drm,
+ "Failed to inform system about start of CDCLK change (%d)\n", ret);
+
+ return ret;
+}
+
+static void intel_cdclk_post_notify(struct intel_display *display,
+ const struct intel_cdclk_config *cdclk_config)
+{
+ int ret;
+
+ if (!display->cdclk.funcs->post_notify)
+ return;
+
+ ret = display->cdclk.funcs->post_notify(display, cdclk_config);
+ if (ret)
+ drm_err(display->drm,
+ "Failed to inform system about end of CDCLK change (%d)\n", ret);
+}
+
static void intel_cdclk_set_cdclk(struct intel_display *display,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe)
{
+ if (intel_cdclk_pre_notify(display))
+ return;
+
display->cdclk.funcs->set_cdclk(display, cdclk_config, pipe);
+
+ intel_cdclk_post_notify(display, cdclk_config);
}
static int intel_cdclk_modeset_calc_cdclk(struct intel_atomic_state *state)
@@ -872,6 +909,19 @@ static u32 bdw_cdclk_freq_sel(int cdclk)
}
}
+static int bdw_cdclk_pcode_pre_notify(struct intel_display *display)
+{
+ return intel_parent_pcode_write(display, BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ,
+ 0x0);
+}
+
+static int bdw_cdclk_pcode_post_notify(struct intel_display *display,
+ const struct intel_cdclk_config *cdclk_config)
+{
+ return intel_parent_pcode_write(display, HSW_PCODE_DE_WRITE_FREQ_REQ,
+ cdclk_config->voltage_level);
+}
+
static void bdw_set_cdclk(struct intel_display *display,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe)
@@ -888,13 +938,6 @@ static void bdw_set_cdclk(struct intel_display *display,
"trying to change cdclk frequency with cdclk not enabled\n"))
return;
- ret = intel_parent_pcode_write(display, BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ, 0x0);
- if (ret) {
- drm_err(display->drm,
- "failed to inform pcode about cdclk change\n");
- return;
- }
-
intel_de_rmw(display, LCPLL_CTL,
0, LCPLL_CD_SOURCE_FCLK);
@@ -918,9 +961,6 @@ static void bdw_set_cdclk(struct intel_display *display,
if (ret)
drm_err(display->drm, "Switching back to LCPLL failed\n");
- intel_parent_pcode_write(display, HSW_PCODE_DE_WRITE_FREQ_REQ,
- cdclk_config->voltage_level);
-
intel_de_write(display, CDCLK_FREQ,
DIV_ROUND_CLOSEST(cdclk, 1000) - 1);
@@ -1155,6 +1195,21 @@ static u32 skl_cdclk_freq_sel(struct intel_display *display,
}
}
+static int skl_cdclk_pcode_pre_notify(struct intel_display *display)
+{
+ return intel_parent_pcode_request(display, SKL_PCODE_CDCLK_CONTROL,
+ SKL_CDCLK_PREPARE_FOR_CHANGE,
+ SKL_CDCLK_READY_FOR_CHANGE,
+ SKL_CDCLK_READY_FOR_CHANGE, 3);
+}
+
+static int skl_cdclk_pcode_post_notify(struct intel_display *display,
+ const struct intel_cdclk_config *cdclk_config)
+{
+ return intel_parent_pcode_write(display, SKL_PCODE_CDCLK_CONTROL,
+ cdclk_config->voltage_level);
+}
+
static void skl_set_cdclk(struct intel_display *display,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe)
@@ -1162,7 +1217,6 @@ static void skl_set_cdclk(struct intel_display *display,
int cdclk = cdclk_config->cdclk;
int vco = cdclk_config->vco;
u32 freq_select, cdclk_ctl;
- int ret;
/*
* Based on WA#1183 CDCLK rates 308 and 617MHz CDCLK rates are
@@ -1175,16 +1229,6 @@ static void skl_set_cdclk(struct intel_display *display,
drm_WARN_ON_ONCE(display->drm,
display->platform.skylake && vco == 8640000);
- ret = intel_parent_pcode_request(display, SKL_PCODE_CDCLK_CONTROL,
- SKL_CDCLK_PREPARE_FOR_CHANGE,
- SKL_CDCLK_READY_FOR_CHANGE,
- SKL_CDCLK_READY_FOR_CHANGE, 3);
- if (ret) {
- drm_err(display->drm,
- "Failed to inform PCU about cdclk change (%d)\n", ret);
- return;
- }
-
freq_select = skl_cdclk_freq_sel(display, cdclk, vco);
if (display->cdclk.hw.vco != 0 &&
@@ -1220,10 +1264,6 @@ static void skl_set_cdclk(struct intel_display *display,
intel_de_write(display, CDCLK_CTL, cdclk_ctl);
intel_de_posting_read(display, CDCLK_CTL);
- /* inform PCU of the change */
- intel_parent_pcode_write(display, SKL_PCODE_CDCLK_CONTROL,
- cdclk_config->voltage_level);
-
intel_update_cdclk(display);
}
@@ -1314,7 +1354,7 @@ static void skl_cdclk_init_hw(struct intel_display *display)
cdclk_config.cdclk = skl_calc_cdclk(0, cdclk_config.vco);
cdclk_config.voltage_level = skl_calc_voltage_level(cdclk_config.cdclk);
- skl_set_cdclk(display, &cdclk_config, INVALID_PIPE);
+ intel_cdclk_set_cdclk(display, &cdclk_config, INVALID_PIPE);
}
static void skl_cdclk_uninit_hw(struct intel_display *display)
@@ -1325,7 +1365,7 @@ static void skl_cdclk_uninit_hw(struct intel_display *display)
cdclk_config.vco = 0;
cdclk_config.voltage_level = skl_calc_voltage_level(cdclk_config.cdclk);
- skl_set_cdclk(display, &cdclk_config, INVALID_PIPE);
+ intel_cdclk_set_cdclk(display, &cdclk_config, INVALID_PIPE);
}
struct intel_cdclk_vals {
@@ -2177,6 +2217,11 @@ static bool pll_enable_wa_needed(struct intel_display *display)
display->cdclk.hw.vco > 0;
}
+static bool has_cd2x_pipe_select(struct intel_display *display)
+{
+ return IS_DISPLAY_VER(display, 10, 20) || display->platform.broxton;
+}
+
static u32 bxt_cdclk_ctl(struct intel_display *display,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe)
@@ -2190,7 +2235,7 @@ static u32 bxt_cdclk_ctl(struct intel_display *display,
val = bxt_cdclk_cd2x_div_sel(display, cdclk, vco, waveform);
- if (DISPLAY_VER(display) < 30)
+ if (has_cd2x_pipe_select(display))
val |= bxt_cdclk_cd2x_pipe(display, pipe);
/*
@@ -2220,6 +2265,29 @@ static u32 bxt_cdclk_ctl(struct intel_display *display,
return val;
}
+static int bxt_cdclk_pcode_pre_notify(struct intel_display *display)
+{
+ /*
+ * BSpec requires us to wait up to 150usec, but that leads to
+ * timeouts; the 2ms used here is based on experiment.
+ */
+ return intel_parent_pcode_write_timeout(display, HSW_PCODE_DE_WRITE_FREQ_REQ,
+ 0x80000000, 2);
+}
+
+static int bxt_cdclk_pcode_post_notify(struct intel_display *display,
+ const struct intel_cdclk_config *cdclk_config)
+{
+ /*
+ * The timeout isn't specified, the 2ms used here is based on
+ * experiment.
+ * FIXME: Waiting for the request completion could be delayed
+ * until the next PCODE request based on BSpec.
+ */
+ return intel_parent_pcode_write_timeout(display, HSW_PCODE_DE_WRITE_FREQ_REQ,
+ cdclk_config->voltage_level, 2);
+}
+
static void _bxt_set_cdclk(struct intel_display *display,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe)
@@ -2259,36 +2327,6 @@ static void bxt_set_cdclk(struct intel_display *display,
{
struct intel_cdclk_config mid_cdclk_config;
int cdclk = cdclk_config->cdclk;
- int ret = 0;
-
- /*
- * Inform power controller of upcoming frequency change.
- * Display versions 14 and beyond do not follow the PUnit
- * mailbox communication, skip
- * this step.
- */
- if (DISPLAY_VER(display) >= 14 || display->platform.dg2)
- ; /* NOOP */
- else if (DISPLAY_VER(display) >= 11)
- ret = intel_parent_pcode_request(display, SKL_PCODE_CDCLK_CONTROL,
- SKL_CDCLK_PREPARE_FOR_CHANGE,
- SKL_CDCLK_READY_FOR_CHANGE,
- SKL_CDCLK_READY_FOR_CHANGE, 3);
- else
- /*
- * BSpec requires us to wait up to 150usec, but that leads to
- * timeouts; the 2ms used here is based on experiment.
- */
- ret = intel_parent_pcode_write_timeout(display,
- HSW_PCODE_DE_WRITE_FREQ_REQ,
- 0x80000000, 2);
-
- if (ret) {
- drm_err(display->drm,
- "Failed to inform PCU about cdclk change (err %d, freq %d)\n",
- ret, cdclk);
- return;
- }
if (DISPLAY_VER(display) >= 20 && cdclk < display->cdclk.hw.cdclk)
xe2lpd_mdclk_cdclk_ratio_program(display, cdclk_config);
@@ -2304,40 +2342,13 @@ static void bxt_set_cdclk(struct intel_display *display,
if (DISPLAY_VER(display) >= 20 && cdclk > display->cdclk.hw.cdclk)
xe2lpd_mdclk_cdclk_ratio_program(display, cdclk_config);
- if (DISPLAY_VER(display) >= 14)
- /*
- * NOOP - No Pcode communication needed for
- * Display versions 14 and beyond
- */;
- else if (DISPLAY_VER(display) >= 11 && !display->platform.dg2)
- ret = intel_parent_pcode_write(display, SKL_PCODE_CDCLK_CONTROL,
- cdclk_config->voltage_level);
- if (DISPLAY_VER(display) < 11) {
- /*
- * The timeout isn't specified, the 2ms used here is based on
- * experiment.
- * FIXME: Waiting for the request completion could be delayed
- * until the next PCODE request based on BSpec.
- */
- ret = intel_parent_pcode_write_timeout(display,
- HSW_PCODE_DE_WRITE_FREQ_REQ,
- cdclk_config->voltage_level, 2);
- }
- if (ret) {
- drm_err(display->drm,
- "PCode CDCLK freq set failed, (err %d, freq %d)\n",
- ret, cdclk);
- return;
- }
-
intel_update_cdclk(display);
- if (DISPLAY_VER(display) >= 11)
- /*
- * Can't read out the voltage level :(
- * Let's just assume everything is as expected.
- */
- display->cdclk.hw.voltage_level = cdclk_config->voltage_level;
+ /*
+ * Can't read out the voltage level :(
+ * Let's just assume everything is as expected.
+ */
+ display->cdclk.hw.voltage_level = cdclk_config->voltage_level;
}
static void bxt_sanitize_cdclk(struct intel_display *display)
@@ -2381,7 +2392,7 @@ static void bxt_sanitize_cdclk(struct intel_display *display)
* dividers both syncing to an active pipe, or asynchronously
* (PIPE_NONE).
*/
- if (DISPLAY_VER(display) < 30) {
+ if (has_cd2x_pipe_select(display)) {
cdctl &= ~bxt_cdclk_cd2x_pipe_mask(display);
cdctl |= bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
}
@@ -2437,7 +2448,7 @@ static void bxt_cdclk_init_hw(struct intel_display *display)
cdclk_config.voltage_level =
intel_cdclk_calc_voltage_level(display, cdclk_config.cdclk);
- bxt_set_cdclk(display, &cdclk_config, INVALID_PIPE);
+ intel_cdclk_set_cdclk(display, &cdclk_config, INVALID_PIPE);
}
static void bxt_cdclk_uninit_hw(struct intel_display *display)
@@ -2449,7 +2460,7 @@ static void bxt_cdclk_uninit_hw(struct intel_display *display)
cdclk_config.voltage_level =
intel_cdclk_calc_voltage_level(display, cdclk_config.cdclk);
- bxt_set_cdclk(display, &cdclk_config, INVALID_PIPE);
+ intel_cdclk_set_cdclk(display, &cdclk_config, INVALID_PIPE);
}
/**
@@ -2579,8 +2590,7 @@ static bool intel_cdclk_can_cd2x_update(struct intel_display *display,
const struct intel_cdclk_config *a,
const struct intel_cdclk_config *b)
{
- /* Older hw doesn't have the capability */
- if (DISPLAY_VER(display) < 10 && !display->platform.broxton)
+ if (!has_cd2x_pipe_select(display))
return false;
/*
@@ -2623,19 +2633,15 @@ void intel_cdclk_dump_config(struct intel_display *display,
cdclk_config->voltage_level);
}
-static void intel_pcode_notify(struct intel_display *display,
- u8 voltage_level,
- u8 active_pipe_count,
- u16 cdclk,
- bool cdclk_update_valid,
- bool pipe_count_update_valid)
+static int dg2_cdclk_pcode_notify(struct intel_display *display,
+ u8 voltage_level,
+ u8 active_pipe_count,
+ u16 cdclk,
+ bool cdclk_update_valid,
+ bool pipe_count_update_valid)
{
- int ret;
u32 update_mask = 0;
- if (!display->platform.dg2)
- return;
-
update_mask = DISPLAY_TO_PCODE_UPDATE_MASK(cdclk, active_pipe_count, voltage_level);
if (cdclk_update_valid)
@@ -2644,15 +2650,10 @@ static void intel_pcode_notify(struct intel_display *display,
if (pipe_count_update_valid)
update_mask |= DISPLAY_TO_PCODE_PIPE_COUNT_VALID;
- ret = intel_parent_pcode_request(display, SKL_PCODE_CDCLK_CONTROL,
- SKL_CDCLK_PREPARE_FOR_CHANGE |
- update_mask,
- SKL_CDCLK_READY_FOR_CHANGE,
- SKL_CDCLK_READY_FOR_CHANGE, 3);
- if (ret)
- drm_err(display->drm,
- "Failed to inform PCU about display config (err %d)\n",
- ret);
+ return intel_parent_pcode_request(display, SKL_PCODE_CDCLK_CONTROL,
+ update_mask,
+ SKL_CDCLK_READY_FOR_CHANGE,
+ SKL_CDCLK_READY_FOR_CHANGE, 3);
}
static void intel_set_cdclk(struct intel_display *display,
@@ -2721,15 +2722,17 @@ static int dg2_power_well_count(struct intel_display *display,
return display->platform.dg2 ? hweight8(cdclk_state->active_pipes) : 0;
}
-static void intel_cdclk_pcode_pre_notify(struct intel_atomic_state *state)
+static void dg2_cdclk_pcode_pre_notify(struct intel_atomic_state *state)
{
struct intel_display *display = to_intel_display(state);
const struct intel_cdclk_state *old_cdclk_state =
intel_atomic_get_old_cdclk_state(state);
const struct intel_cdclk_state *new_cdclk_state =
intel_atomic_get_new_cdclk_state(state);
- unsigned int cdclk = 0; u8 voltage_level, num_active_pipes = 0;
+ u8 voltage_level, num_active_pipes = 0;
bool change_cdclk, update_pipe_count;
+ unsigned int cdclk_mhz = 0;
+ int ret;
if (!intel_cdclk_changed(&old_cdclk_state->actual,
&new_cdclk_state->actual) &&
@@ -2750,8 +2753,12 @@ static void intel_cdclk_pcode_pre_notify(struct intel_atomic_state *state)
* if CDCLK is decreasing or not changing, set bits 25:16 to current CDCLK,
* which basically means we choose the maximum of old and new CDCLK, if we know both
*/
- if (change_cdclk)
- cdclk = max(new_cdclk_state->actual.cdclk, old_cdclk_state->actual.cdclk);
+ if (change_cdclk) {
+ unsigned int cdclk = max(new_cdclk_state->actual.cdclk,
+ old_cdclk_state->actual.cdclk);
+
+ cdclk_mhz = DIV_ROUND_UP(cdclk, 1000);
+ }
/*
* According to "Sequence For Pipe Count Change",
@@ -2762,19 +2769,24 @@ static void intel_cdclk_pcode_pre_notify(struct intel_atomic_state *state)
if (update_pipe_count)
num_active_pipes = dg2_power_well_count(display, new_cdclk_state);
- intel_pcode_notify(display, voltage_level, num_active_pipes, cdclk,
- change_cdclk, update_pipe_count);
+ ret = dg2_cdclk_pcode_notify(display, voltage_level, num_active_pipes, cdclk_mhz,
+ change_cdclk, update_pipe_count);
+ if (ret)
+ drm_err(display->drm,
+ "Failed to inform PCODE about start of CDCLK change (%d)\n", ret);
}
-static void intel_cdclk_pcode_post_notify(struct intel_atomic_state *state)
+static void dg2_cdclk_pcode_post_notify(struct intel_atomic_state *state)
{
struct intel_display *display = to_intel_display(state);
const struct intel_cdclk_state *new_cdclk_state =
intel_atomic_get_new_cdclk_state(state);
const struct intel_cdclk_state *old_cdclk_state =
intel_atomic_get_old_cdclk_state(state);
- unsigned int cdclk = 0; u8 voltage_level, num_active_pipes = 0;
+ u8 voltage_level, num_active_pipes = 0;
bool update_cdclk, update_pipe_count;
+ unsigned int cdclk_mhz = 0;
+ int ret;
/* According to "Sequence After Frequency Change", set voltage to used level */
voltage_level = new_cdclk_state->actual.voltage_level;
@@ -2787,8 +2799,11 @@ static void intel_cdclk_pcode_post_notify(struct intel_atomic_state *state)
* According to "Sequence After Frequency Change",
* set bits 25:16 to current CDCLK
*/
- if (update_cdclk)
- cdclk = new_cdclk_state->actual.cdclk;
+ if (update_cdclk) {
+ unsigned int cdclk = new_cdclk_state->actual.cdclk;
+
+ cdclk_mhz = DIV_ROUND_UP(cdclk, 1000);
+ }
/*
* According to "Sequence For Pipe Count Change",
@@ -2799,8 +2814,11 @@ static void intel_cdclk_pcode_post_notify(struct intel_atomic_state *state)
if (update_pipe_count)
num_active_pipes = dg2_power_well_count(display, new_cdclk_state);
- intel_pcode_notify(display, voltage_level, num_active_pipes, cdclk,
- update_cdclk, update_pipe_count);
+ ret = dg2_cdclk_pcode_notify(display, voltage_level, num_active_pipes, cdclk_mhz,
+ update_cdclk, update_pipe_count);
+ if (ret)
+ drm_err(display->drm,
+ "Failed to inform PCODE about end of CDCLK change (%d)\n", ret);
}
bool intel_cdclk_is_decreasing_later(struct intel_atomic_state *state)
@@ -2836,12 +2854,11 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)
return;
if (!intel_cdclk_changed(&old_cdclk_state->actual,
- &new_cdclk_state->actual))
+ &new_cdclk_state->actual) &&
+ dg2_power_well_count(display, old_cdclk_state) ==
+ dg2_power_well_count(display, new_cdclk_state))
return;
- if (display->platform.dg2)
- intel_cdclk_pcode_pre_notify(state);
-
if (new_cdclk_state->disable_pipes) {
cdclk_config = new_cdclk_state->actual;
pipe = INVALID_PIPE;
@@ -2866,6 +2883,9 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)
drm_WARN_ON(display->drm, !new_cdclk_state->base.changed);
+ if (display->platform.dg2)
+ dg2_cdclk_pcode_pre_notify(state);
+
intel_set_cdclk(display, &cdclk_config, pipe,
"Pre changing CDCLK to");
}
@@ -2891,12 +2911,11 @@ intel_set_cdclk_post_plane_update(struct intel_atomic_state *state)
return;
if (!intel_cdclk_changed(&old_cdclk_state->actual,
- &new_cdclk_state->actual))
+ &new_cdclk_state->actual) &&
+ dg2_power_well_count(display, old_cdclk_state) ==
+ dg2_power_well_count(display, new_cdclk_state))
return;
- if (display->platform.dg2)
- intel_cdclk_pcode_post_notify(state);
-
if (!new_cdclk_state->disable_pipes &&
new_cdclk_state->actual.cdclk < old_cdclk_state->actual.cdclk)
pipe = new_cdclk_state->pipe;
@@ -2907,6 +2926,9 @@ intel_set_cdclk_post_plane_update(struct intel_atomic_state *state)
intel_set_cdclk(display, &new_cdclk_state->actual, pipe,
"Post changing CDCLK to");
+
+ if (display->platform.dg2)
+ dg2_cdclk_pcode_post_notify(state);
}
/* pixels per CDCLK */
@@ -3942,9 +3964,25 @@ static const struct intel_cdclk_funcs xe3lpd_cdclk_funcs = {
.calc_voltage_level = xe3lpd_calc_voltage_level,
};
+static const struct intel_cdclk_funcs mtl_cdclk_funcs = {
+ .get_cdclk = bxt_get_cdclk,
+ .set_cdclk = bxt_set_cdclk,
+ .modeset_calc_cdclk = bxt_modeset_calc_cdclk,
+ .calc_voltage_level = rplu_calc_voltage_level,
+};
+
+static const struct intel_cdclk_funcs dg2_cdclk_funcs = {
+ .get_cdclk = bxt_get_cdclk,
+ .set_cdclk = bxt_set_cdclk,
+ .modeset_calc_cdclk = bxt_modeset_calc_cdclk,
+ .calc_voltage_level = tgl_calc_voltage_level,
+};
+
static const struct intel_cdclk_funcs rplu_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk,
+ .pre_notify = skl_cdclk_pcode_pre_notify,
+ .post_notify = skl_cdclk_pcode_post_notify,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = rplu_calc_voltage_level,
};
@@ -3952,6 +3990,8 @@ static const struct intel_cdclk_funcs rplu_cdclk_funcs = {
static const struct intel_cdclk_funcs tgl_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk,
+ .pre_notify = skl_cdclk_pcode_pre_notify,
+ .post_notify = skl_cdclk_pcode_post_notify,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = tgl_calc_voltage_level,
};
@@ -3959,6 +3999,8 @@ static const struct intel_cdclk_funcs tgl_cdclk_funcs = {
static const struct intel_cdclk_funcs ehl_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk,
+ .pre_notify = skl_cdclk_pcode_pre_notify,
+ .post_notify = skl_cdclk_pcode_post_notify,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = ehl_calc_voltage_level,
};
@@ -3966,6 +4008,8 @@ static const struct intel_cdclk_funcs ehl_cdclk_funcs = {
static const struct intel_cdclk_funcs icl_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk,
+ .pre_notify = skl_cdclk_pcode_pre_notify,
+ .post_notify = skl_cdclk_pcode_post_notify,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = icl_calc_voltage_level,
};
@@ -3973,6 +4017,8 @@ static const struct intel_cdclk_funcs icl_cdclk_funcs = {
static const struct intel_cdclk_funcs bxt_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk,
+ .pre_notify = bxt_cdclk_pcode_pre_notify,
+ .post_notify = bxt_cdclk_pcode_post_notify,
.modeset_calc_cdclk = bxt_modeset_calc_cdclk,
.calc_voltage_level = bxt_calc_voltage_level,
};
@@ -3980,12 +4026,16 @@ static const struct intel_cdclk_funcs bxt_cdclk_funcs = {
static const struct intel_cdclk_funcs skl_cdclk_funcs = {
.get_cdclk = skl_get_cdclk,
.set_cdclk = skl_set_cdclk,
+ .pre_notify = skl_cdclk_pcode_pre_notify,
+ .post_notify = skl_cdclk_pcode_post_notify,
.modeset_calc_cdclk = skl_modeset_calc_cdclk,
};
static const struct intel_cdclk_funcs bdw_cdclk_funcs = {
.get_cdclk = bdw_get_cdclk,
.set_cdclk = bdw_set_cdclk,
+ .pre_notify = bdw_cdclk_pcode_pre_notify,
+ .post_notify = bdw_cdclk_pcode_post_notify,
.modeset_calc_cdclk = bdw_modeset_calc_cdclk,
};
@@ -4091,16 +4141,16 @@ void intel_init_cdclk_hooks(struct intel_display *display)
display->cdclk.funcs = &xe3lpd_cdclk_funcs;
display->cdclk.table = xe3lpd_cdclk_table;
} else if (DISPLAY_VER(display) >= 20) {
- display->cdclk.funcs = &rplu_cdclk_funcs;
+ display->cdclk.funcs = &mtl_cdclk_funcs;
display->cdclk.table = xe2lpd_cdclk_table;
} else if (DISPLAY_VERx100(display) >= 1401) {
- display->cdclk.funcs = &rplu_cdclk_funcs;
+ display->cdclk.funcs = &mtl_cdclk_funcs;
display->cdclk.table = xe2hpd_cdclk_table;
} else if (DISPLAY_VER(display) >= 14) {
- display->cdclk.funcs = &rplu_cdclk_funcs;
+ display->cdclk.funcs = &mtl_cdclk_funcs;
display->cdclk.table = mtl_cdclk_table;
} else if (display->platform.dg2) {
- display->cdclk.funcs = &tgl_cdclk_funcs;
+ display->cdclk.funcs = &dg2_cdclk_funcs;
display->cdclk.table = dg2_cdclk_table;
} else if (display->platform.alderlake_p) {
/* Wa_22011320316:adl-p[a0] */
diff --git a/drivers/gpu/drm/i915/display/intel_cmtg.c b/drivers/gpu/drm/i915/display/intel_cmtg.c
index c8e0f90af910..3c0f5b2fb2e7 100644
--- a/drivers/gpu/drm/i915/display/intel_cmtg.c
+++ b/drivers/gpu/drm/i915/display/intel_cmtg.c
@@ -326,7 +326,7 @@ void intel_cmtg_set_vrr_ctl(const struct intel_crtc_state *crtc_state)
XELPD_VRR_CTL_VRR_GUARDBAND(crtc_state->vrr.guardband);
/* TODO: The code below may need to be revisited once CMRR is enabled */
- if (crtc_state->cmrr.enable)
+ if (crtc_state->vrr.cmrr.enable)
vrr_ctl |= VRR_CTL_CMRR_ENABLE;
intel_de_write(display, TRANS_VRR_CTL(display, cmtg_transcoder), vrr_ctl);
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 4493483f10a9..ad4f362e0c09 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
@@ -311,6 +311,9 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config,
pipe_config->vrr.dc_balance.max_increase,
pipe_config->vrr.dc_balance.max_decrease,
pipe_config->vrr.dc_balance.vblank_target);
+ drm_printf(&p, "cmrr: %s, cmrr_m: %llu, cmrr_n: %llu\n",
+ str_yes_no(pipe_config->vrr.cmrr.enable),
+ pipe_config->vrr.cmrr.cmrr_m, pipe_config->vrr.cmrr.cmrr_n);
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_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
index 86bb96ac449b..cce041e1da51 100644
--- a/drivers/gpu/drm/i915/display/intel_cursor.c
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -13,6 +13,7 @@
#include <drm/drm_vblank.h>
#include "intel_atomic.h"
+#include "intel_crtc.h"
#include "intel_cursor.h"
#include "intel_cursor_regs.h"
#include "intel_de.h"
@@ -801,6 +802,88 @@ void intel_cursor_unpin_work(struct kthread_work *base)
intel_plane_destroy_state(&plane->base, &plane_state->uapi);
}
+static int intel_cursor_lock_joined_planes(struct intel_display *display,
+ const struct intel_crtc_state *crtc_state,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct intel_crtc *pipe_crtc;
+ int ret;
+
+ for_each_intel_crtc_in_pipe_mask(display, pipe_crtc,
+ intel_crtc_joined_pipe_mask(crtc_state)) {
+ struct intel_plane *pipe_plane =
+ intel_crtc_get_plane(pipe_crtc, PLANE_CURSOR);
+
+ ret = drm_modeset_lock(&pipe_crtc->base.mutex, ctx);
+ if (ret)
+ return ret;
+
+ ret = drm_modeset_lock(&pipe_plane->base.mutex, ctx);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static bool
+intel_cursor_joiner_commits_idle(struct intel_display *display,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *pipe_crtc;
+
+ for_each_intel_crtc_in_pipe_mask(display, pipe_crtc,
+ intel_crtc_joined_pipe_mask(crtc_state)) {
+ struct intel_plane *pipe_plane =
+ intel_crtc_get_plane(pipe_crtc, PLANE_CURSOR);
+ struct intel_plane_state *pipe_plane_state =
+ to_intel_plane_state(pipe_plane->base.state);
+
+ if (pipe_plane_state->uapi.commit &&
+ !try_wait_for_completion(&pipe_plane_state->uapi.commit->hw_done))
+ return false;
+ }
+
+ return true;
+}
+
+static void
+intel_cursor_fastpath_update_plane_state(struct intel_plane_state *plane_state,
+ const struct intel_plane_state *from_plane_state,
+ struct drm_framebuffer *fb,
+ struct intel_crtc *hw_crtc,
+ int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ u32 src_x, u32 src_y,
+ u32 src_w, u32 src_h)
+{
+ /*
+ * Only the primary owns its uapi state; a secondary mirrors it, so
+ * its uapi.crtc/fb stay NULL and hw.crtc comes from hw_crtc.
+ */
+ if (plane_state == from_plane_state) {
+ drm_atomic_set_fb_for_plane(&plane_state->uapi, fb);
+
+ plane_state->uapi.src_x = src_x;
+ plane_state->uapi.src_y = src_y;
+ plane_state->uapi.src_w = src_w;
+ plane_state->uapi.src_h = src_h;
+ plane_state->uapi.crtc_x = crtc_x;
+ plane_state->uapi.crtc_y = crtc_y;
+ plane_state->uapi.crtc_w = crtc_w;
+ plane_state->uapi.crtc_h = crtc_h;
+ }
+
+ intel_plane_copy_uapi_to_hw_state(NULL, plane_state, from_plane_state, hw_crtc);
+}
+
+struct intel_cursor_joiner_state {
+ struct intel_plane *plane;
+ struct intel_crtc *crtc;
+ struct intel_crtc_state *crtc_state;
+ struct intel_plane_state *old_plane_state;
+ struct intel_plane_state *new_plane_state;
+};
+
static int
intel_legacy_cursor_update(struct drm_plane *_plane,
struct drm_crtc *_crtc,
@@ -816,11 +899,13 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
struct intel_display *display = to_intel_display(plane);
struct intel_plane_state *old_plane_state =
to_intel_plane_state(plane->base.state);
- struct intel_plane_state *new_plane_state;
struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
- struct intel_crtc_state *new_crtc_state;
struct intel_vblank_evade_ctx evade;
+ struct intel_cursor_joiner_state joined_pipe_state[I915_MAX_PIPES] = {};
+ struct intel_crtc *pipe_crtc;
+ int num_pipes = 0;
+ u32 start_vbl_count, end_vbl_count;
int ret;
/*
@@ -829,22 +914,10 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
* PSR2 selective fetch also requires the slow path as
* PSR2 plane and transcoder registers can only be updated during
* vblank.
- *
- * FIXME joiner fastpath would be good
*/
if (!crtc_state->hw.active ||
intel_crtc_needs_modeset(crtc_state) ||
- intel_crtc_needs_fastset(crtc_state) ||
- crtc_state->joiner_pipes)
- goto slow;
-
- /*
- * Don't do an async update if there is an outstanding commit modifying
- * the plane. This prevents our async update's changes from getting
- * overridden by a previous synchronous update's state.
- */
- if (old_plane_state->uapi.commit &&
- !try_wait_for_completion(&old_plane_state->uapi.commit->hw_done))
+ intel_crtc_needs_fastset(crtc_state))
goto slow;
/*
@@ -860,46 +933,89 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
!old_plane_state->uapi.fb != !fb)
goto slow;
- new_plane_state = to_intel_plane_state(intel_plane_duplicate_state(&plane->base));
- if (!new_plane_state)
- return -ENOMEM;
-
- new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(&crtc->base));
- if (!new_crtc_state) {
- ret = -ENOMEM;
- goto out_free;
- }
+ ret = intel_cursor_lock_joined_planes(display, crtc_state, ctx);
+ if (ret == -EDEADLK)
+ return ret;
+ if (ret)
+ goto slow;
- drm_atomic_set_fb_for_plane(&new_plane_state->uapi, fb);
+ /*
+ * Don't do an async update if there is an outstanding commit modifying
+ * any of the joined cursor planes. This prevents our async update's
+ * changes from getting overridden by a previous synchronous update's
+ * state.
+ */
+ if (!intel_cursor_joiner_commits_idle(display, crtc_state))
+ goto slow;
- new_plane_state->uapi.src_x = src_x;
- new_plane_state->uapi.src_y = src_y;
- new_plane_state->uapi.src_w = src_w;
- new_plane_state->uapi.src_h = src_h;
- new_plane_state->uapi.crtc_x = crtc_x;
- new_plane_state->uapi.crtc_y = crtc_y;
- new_plane_state->uapi.crtc_w = crtc_w;
- new_plane_state->uapi.crtc_h = crtc_h;
+ /*
+ * Iterate over all joined pipes (primary and secondary) uniformly.
+ * The joined pipe mask includes both the primary pipe and all
+ * secondary joiner pipes, allowing us to handle them all the same way.
+ */
+ for_each_intel_crtc_in_pipe_mask(display, pipe_crtc,
+ intel_crtc_joined_pipe_mask(crtc_state)) {
+ struct intel_cursor_joiner_state *j = &joined_pipe_state[num_pipes];
+
+ j->plane = intel_crtc_get_plane(pipe_crtc, PLANE_CURSOR);
+ j->crtc = pipe_crtc;
+ j->crtc_state = to_intel_crtc_state(pipe_crtc->base.state);
+ j->old_plane_state = to_intel_plane_state(j->plane->base.state);
+ j->new_plane_state =
+ to_intel_plane_state(intel_plane_duplicate_state(&j->plane->base));
+
+ if (!j->new_plane_state) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
- intel_plane_copy_uapi_to_hw_state(NULL, new_plane_state, new_plane_state, crtc);
+ intel_cursor_fastpath_update_plane_state(j->new_plane_state,
+ joined_pipe_state[0].new_plane_state,
+ fb, pipe_crtc,
+ crtc_x, crtc_y,
+ crtc_w, crtc_h,
+ src_x, src_y,
+ src_w, src_h);
+
+ ret = j->plane->check_plane(j->crtc_state, j->new_plane_state);
+ if (ret) {
+ intel_plane_destroy_state(&j->plane->base,
+ &j->new_plane_state->uapi);
+ goto out_free;
+ }
- ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
- old_plane_state, new_plane_state);
- if (ret)
- goto out_free;
+ ret = intel_plane_pin_fb(j->new_plane_state, j->old_plane_state);
+ if (ret) {
+ intel_plane_destroy_state(&j->plane->base,
+ &j->new_plane_state->uapi);
+ goto out_free;
+ }
- ret = intel_plane_pin_fb(new_plane_state, old_plane_state);
- if (ret)
- goto out_free;
+ num_pipes++;
+ }
- intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb),
+ intel_frontbuffer_flush(to_intel_frontbuffer(joined_pipe_state[0].new_plane_state->hw.fb),
ORIGIN_CURSOR_UPDATE);
- intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb),
- to_intel_frontbuffer(new_plane_state->hw.fb),
- plane->frontbuffer_bit);
- /* Swap plane state */
- plane->base.state = &new_plane_state->uapi;
+ for (int i = 0; i < num_pipes; i++) {
+ struct intel_frontbuffer *old_front =
+ to_intel_frontbuffer(joined_pipe_state[i].old_plane_state->hw.fb);
+ struct intel_frontbuffer *new_front =
+ to_intel_frontbuffer(joined_pipe_state[i].new_plane_state->hw.fb);
+
+ intel_frontbuffer_track(old_front, new_front,
+ joined_pipe_state[i].plane->frontbuffer_bit);
+ }
+
+ for (int i = 0; i < num_pipes; i++) {
+ joined_pipe_state[i].plane->base.state =
+ &joined_pipe_state[i].new_plane_state->uapi;
+
+ if (joined_pipe_state[i].new_plane_state->uapi.visible)
+ joined_pipe_state[i].crtc_state->active_planes |= BIT(PLANE_CURSOR);
+ else
+ joined_pipe_state[i].crtc_state->active_planes &= ~BIT(PLANE_CURSOR);
+ }
/*
* We cannot swap crtc_state as it may be in use by an atomic commit or
@@ -911,7 +1027,6 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
* planes atomically. If the cursor was part of the atomic update then
* we would have taken the slowpath.
*/
- crtc_state->active_planes = new_crtc_state->active_planes;
intel_vblank_evade_init(crtc_state, crtc_state, &evade);
@@ -933,37 +1048,74 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
local_irq_disable();
}
- if (new_plane_state->uapi.visible) {
- intel_plane_update_noarm(NULL, plane, crtc_state, new_plane_state);
- intel_plane_update_arm(NULL, plane, crtc_state, new_plane_state);
- } else {
- intel_plane_disable_arm(NULL, plane, crtc_state);
+ /*
+ * Joiner pipes are vblank-synchronized, so sampling only the primary
+ * pipe is sufficient to detect a straddle across all joined pipes.
+ * The vblank evasion above also operates on the primary pipe only.
+ */
+ start_vbl_count = intel_crtc_get_vblank_counter(joined_pipe_state[0].crtc);
+
+ for (int i = 0; i < num_pipes; i++) {
+ if (joined_pipe_state[i].new_plane_state->uapi.visible) {
+ intel_plane_update_noarm(NULL, joined_pipe_state[i].plane,
+ joined_pipe_state[i].crtc_state,
+ joined_pipe_state[i].new_plane_state);
+ intel_plane_update_arm(NULL, joined_pipe_state[i].plane,
+ joined_pipe_state[i].crtc_state,
+ joined_pipe_state[i].new_plane_state);
+ } else {
+ intel_plane_disable_arm(NULL, joined_pipe_state[i].plane,
+ joined_pipe_state[i].crtc_state);
+ }
}
- local_irq_enable();
+ end_vbl_count = intel_crtc_get_vblank_counter(joined_pipe_state[0].crtc);
- intel_psr_unlock(crtc_state);
+ local_irq_enable();
- if (old_plane_state->ggtt_vma != new_plane_state->ggtt_vma) {
- drm_vblank_work_init(&old_plane_state->unpin_work, &crtc->base,
- intel_cursor_unpin_work);
+ if (start_vbl_count != end_vbl_count)
+ drm_err(display->drm,
+ "Atomic update failure on pipe %c (start=%u end=%u)\n",
+ pipe_name(joined_pipe_state[0].crtc->pipe),
+ start_vbl_count, end_vbl_count);
- drm_vblank_work_schedule(&old_plane_state->unpin_work,
- drm_crtc_accurate_vblank_count(&crtc->base) + 1,
- false);
+ intel_psr_unlock(crtc_state);
- old_plane_state = NULL;
- } else {
- intel_plane_unpin_fb(old_plane_state);
+ /*
+ * Schedule or immediately unpin old framebuffers.
+ * Protect against concurrent access.
+ */
+ for (int i = 0; i < num_pipes; i++) {
+ struct intel_plane_state *old = joined_pipe_state[i].old_plane_state;
+
+ if (old->ggtt_vma != joined_pipe_state[i].new_plane_state->ggtt_vma) {
+ drm_vblank_work_init(&old->unpin_work, &crtc->base,
+ intel_cursor_unpin_work);
+ drm_vblank_work_schedule(&old->unpin_work,
+ drm_crtc_accurate_vblank_count(&crtc->base) + 1,
+ false);
+ joined_pipe_state[i].old_plane_state = NULL;
+ } else {
+ intel_plane_unpin_fb(old);
+ }
}
out_free:
- if (new_crtc_state)
- intel_crtc_destroy_state(&crtc->base, &new_crtc_state->uapi);
- if (ret)
- intel_plane_destroy_state(&plane->base, &new_plane_state->uapi);
- else if (old_plane_state)
- intel_plane_destroy_state(&plane->base, &old_plane_state->uapi);
+ if (ret) {
+ for (int i = 0; i < num_pipes; i++) {
+ intel_plane_unpin_fb(joined_pipe_state[i].new_plane_state);
+ intel_plane_destroy_state(&joined_pipe_state[i].plane->base,
+ &joined_pipe_state[i].new_plane_state->uapi);
+ }
+ } else {
+ for (int i = 0; i < num_pipes; i++) {
+ if (!joined_pipe_state[i].old_plane_state)
+ continue;
+
+ intel_plane_destroy_state(&joined_pipe_state[i].plane->base,
+ &joined_pipe_state[i].old_plane_state->uapi);
+ }
+ }
return ret;
slow:
diff --git a/drivers/gpu/drm/i915/display/intel_cursor_regs.h b/drivers/gpu/drm/i915/display/intel_cursor_regs.h
index aaa66331063e..da2f9630ae2d 100644
--- a/drivers/gpu/drm/i915/display/intel_cursor_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_cursor_regs.h
@@ -81,7 +81,7 @@
#define CUR_WM_EN REG_BIT(31)
#define CUR_WM_IGNORE_LINES REG_BIT(30)
#define CUR_WM_LINES_MASK REG_GENMASK(26, 14)
-#define CUR_WM_BLOCKS_MASK REG_GENMASK(11, 0)
+#define CUR_WM_BLOCKS_MASK REG_GENMASK(12, 0)
#define _CUR_WM_SAGV_A 0x70158
#define _CUR_WM_SAGV_B 0x71158
@@ -98,10 +98,10 @@
#define _CUR_BUF_CFG_A 0x7017c
#define _CUR_BUF_CFG_B 0x7117c
#define CUR_BUF_CFG(pipe) _MMIO_PIPE((pipe), _CUR_BUF_CFG_A, _CUR_BUF_CFG_B)
-/* skl+: 10 bits, icl+ 11 bits, adlp+ 12 bits */
-#define CUR_BUF_END_MASK REG_GENMASK(27, 16)
+/* skl+: 10 bits, icl+ 11 bits, adlp+ 12 bits, xe3plpd+ 13 bits */
+#define CUR_BUF_END_MASK REG_GENMASK(28, 16)
#define CUR_BUF_END(end) REG_FIELD_PREP(CUR_BUF_END_MASK, (end))
-#define CUR_BUF_START_MASK REG_GENMASK(11, 0)
+#define CUR_BUF_START_MASK REG_GENMASK(12, 0)
#define CUR_BUF_START(start) REG_FIELD_PREP(CUR_BUF_START_MASK, (start))
/* tgl+ */
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 02a53c9848e1..9b3b526e5e55 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4325,11 +4325,33 @@ static void mtl_ddi_tc_phy_get_config(struct intel_encoder *encoder,
mtl_port_to_pll_id(display, encoder->port));
}
+static struct intel_dpll *dg2_ddi_get_pll(struct intel_encoder *encoder)
+{
+ struct intel_display *display = to_intel_display(encoder);
+
+ return intel_get_dpll_by_id(display, dg2_port_to_pll_id(encoder->port));
+}
+
static void dg2_ddi_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state)
+ struct intel_crtc_state *crtc_state)
{
- intel_mpllb_readout_hw_state(encoder, &crtc_state->dpll_hw_state.mpllb);
- crtc_state->port_clock = intel_mpllb_calc_port_clock(encoder, &crtc_state->dpll_hw_state.mpllb);
+ struct icl_port_dpll *port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
+ struct intel_dpll *pll = dg2_ddi_get_pll(encoder);
+
+ if (pll)
+ intel_ddi_get_clock(encoder, crtc_state, pll);
+
+ /*
+ * Keep the hw readout robust against unexpected NULL PLL lookups,
+ * so modeset verify always has intel_dpll populated for DG2.
+ */
+ if (!crtc_state->intel_dpll) {
+ port_dpll->pll = pll;
+ intel_mpllb_readout_hw_state(encoder, &port_dpll->hw_state.mpllb);
+ icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT);
+ crtc_state->port_clock = intel_mpllb_calc_port_clock(encoder,
+ &port_dpll->hw_state.mpllb);
+ }
intel_ddi_get_config(encoder, crtc_state);
}
@@ -4657,8 +4679,8 @@ static int intel_ddi_compute_config_late(struct intel_atomic_state *state,
if (crtc_state->master_transcoder == crtc_state->cpu_transcoder) {
crtc_state->master_transcoder = INVALID_TRANSCODER;
- crtc_state->sync_mode_slaves_mask =
- port_sync_transcoders & ~BIT(crtc_state->cpu_transcoder);
+ crtc_state->sync_mode_slaves_mask = port_sync_transcoders &
+ ~REG_BIT(crtc_state->cpu_transcoder);
}
return 0;
@@ -5343,8 +5365,6 @@ void intel_ddi_init(struct intel_display *display,
else
encoder->get_config = mtl_ddi_non_tc_phy_get_config;
} else if (display->platform.dg2) {
- encoder->enable_clock = intel_mpllb_enable;
- encoder->disable_clock = intel_mpllb_disable;
encoder->get_config = dg2_ddi_get_config;
} else if (display->platform.alderlake_s) {
encoder->enable_clock = adls_ddi_enable_clock;
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 9dfd095f325f..fc30a455bed3 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -60,7 +60,6 @@
#include "intel_bo.h"
#include "intel_bw.h"
#include "intel_cdclk.h"
-#include "intel_clock_gating.h"
#include "intel_cmtg.h"
#include "intel_color.h"
#include "intel_crt.h"
@@ -107,6 +106,7 @@
#include "intel_modeset_verify.h"
#include "intel_overlay.h"
#include "intel_panel.h"
+#include "intel_parent.h"
#include "intel_pch_display.h"
#include "intel_pch_refclk.h"
#include "intel_pfit.h"
@@ -119,7 +119,6 @@
#include "intel_sdvo.h"
#include "intel_snps_phy.h"
#include "intel_tc.h"
-#include "intel_tdf.h"
#include "intel_tv.h"
#include "intel_vblank.h"
#include "intel_vdsc.h"
@@ -193,6 +192,53 @@ is_trans_port_sync_mode(const struct intel_crtc_state *crtc_state)
is_trans_port_sync_slave(crtc_state);
}
+/*
+ * Return a bitmask of all the start indices of consecutive bitfields of size
+ * width in mask.
+ */
+static unsigned long find_consecutive_bits(unsigned long mask, int width)
+{
+ unsigned long bit, out_mask = 0;
+
+ if (!width)
+ return 0;
+
+ for_each_set_bit(bit, &mask, BITS_PER_TYPE(mask)) {
+ /* For each set bit, see if the following bits are set also */
+ unsigned long bitfield = GENMASK(bit + width - 1, bit);
+
+ if ((mask & bitfield) == bitfield)
+ out_mask |= BIT(bit);
+ }
+
+ return out_mask;
+}
+
+/*
+ * Return a bitmask of all valid joiner primary pipes for joining
+ * num_joined_pipes pipes. For completeness, return all valid pipes for
+ * num_joined_pipes == 1.
+ *
+ * Return 0 if the platform doesn't support joining for the requested number of
+ * pipes, or there are not enough consecutive pipes available.
+ */
+u8 intel_joiner_valid_primary_pipe_mask(struct intel_display *display, int num_joined_pipes)
+{
+ if (num_joined_pipes == 1) {
+ return DISPLAY_RUNTIME_INFO(display)->pipe_mask;
+ } else if (num_joined_pipes == 2) {
+ if (!HAS_UNCOMPRESSED_JOINER(display) && !HAS_BIGJOINER(display))
+ return 0;
+ } else if (num_joined_pipes == 4) {
+ if (!HAS_ULTRAJOINER(display))
+ return 0;
+ } else {
+ return 0;
+ }
+
+ return find_consecutive_bits(DISPLAY_RUNTIME_INFO(display)->pipe_mask, num_joined_pipes);
+}
+
static enum pipe joiner_primary_pipe(const struct intel_crtc_state *crtc_state)
{
return ffs(crtc_state->joiner_pipes) - 1;
@@ -950,8 +996,8 @@ static bool vrr_params_changed(const struct intel_crtc_state *old_crtc_state,
static bool cmrr_params_changed(const struct intel_crtc_state *old_crtc_state,
const struct intel_crtc_state *new_crtc_state)
{
- return old_crtc_state->cmrr.cmrr_m != new_crtc_state->cmrr.cmrr_m ||
- old_crtc_state->cmrr.cmrr_n != new_crtc_state->cmrr.cmrr_n;
+ return old_crtc_state->vrr.cmrr.cmrr_m != new_crtc_state->vrr.cmrr.cmrr_m ||
+ old_crtc_state->vrr.cmrr.cmrr_n != new_crtc_state->vrr.cmrr.cmrr_n;
}
static bool intel_crtc_vrr_enabling(struct intel_atomic_state *state,
@@ -1817,9 +1863,7 @@ static void hsw_crtc_disable(struct intel_atomic_state *state,
/* Prefer intel_encoder_is_combo() */
bool intel_phy_is_combo(struct intel_display *display, enum phy phy)
{
- if (phy == PHY_NONE)
- return false;
- else if (display->platform.alderlake_s)
+ if (display->platform.alderlake_s)
return phy <= PHY_E;
else if (display->platform.dg1 || display->platform.rocketlake)
return phy <= PHY_D;
@@ -1873,7 +1917,7 @@ bool intel_phy_is_snps(struct intel_display *display, enum phy phy)
* For DG2, and for DG2 only, all four "combo" ports and the TC1 port
* (PHY E) use Synopsis PHYs. See intel_phy_is_tc().
*/
- return display->platform.dg2 && phy > PHY_NONE && phy <= PHY_E;
+ return display->platform.dg2 && phy <= PHY_E;
}
/* Prefer intel_encoder_to_phy() */
@@ -1891,6 +1935,10 @@ enum phy intel_port_to_phy(struct intel_display *display, enum port port)
port == PORT_D)
return PHY_A;
+ if (drm_WARN(display->drm, port < 0,
+ "PHY is invalid if port < 0 (%d), assuming PHY_A\n", port))
+ return PHY_A;
+
return PHY_A + port - PORT_A;
}
@@ -5536,9 +5584,9 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_I(vrr.flipline);
PIPE_CONF_CHECK_I(vrr.vsync_start);
PIPE_CONF_CHECK_I(vrr.vsync_end);
- PIPE_CONF_CHECK_LLI(cmrr.cmrr_m);
- PIPE_CONF_CHECK_LLI(cmrr.cmrr_n);
- PIPE_CONF_CHECK_BOOL(cmrr.enable);
+ PIPE_CONF_CHECK_LLI(vrr.cmrr.cmrr_m);
+ PIPE_CONF_CHECK_LLI(vrr.cmrr.cmrr_n);
+ PIPE_CONF_CHECK_BOOL(vrr.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);
@@ -7506,7 +7554,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
intel_atomic_commit_fence_wait(state);
- intel_td_flush(display);
+ intel_parent_transient_data_flush(display);
intel_atomic_prepare_plane_clear_colors(state);
@@ -8113,9 +8161,9 @@ static int max_dotclock(struct intel_display *display)
{
int max_dotclock = display->cdclk.max_dotclk_freq;
- if (HAS_ULTRAJOINER(display))
+ if (intel_joiner_valid_primary_pipe_mask(display, 4))
max_dotclock *= 4;
- else if (HAS_UNCOMPRESSED_JOINER(display) || HAS_BIGJOINER(display))
+ else if (intel_joiner_valid_primary_pipe_mask(display, 2))
max_dotclock *= 2;
return max_dotclock;
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index 57ea4f2edf2a..eecafff167d3 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -136,8 +136,6 @@ enum tc_port {
};
enum phy {
- PHY_NONE = -1,
-
PHY_A = 0,
PHY_B,
PHY_C,
@@ -373,6 +371,7 @@ intel_cpu_transcoder_mode_valid(struct intel_display *display,
enum phy intel_port_to_phy(struct intel_display *display, enum port port);
bool is_trans_port_sync_mode(const struct intel_crtc_state *state);
bool is_trans_port_sync_master(const struct intel_crtc_state *state);
+u8 intel_joiner_valid_primary_pipe_mask(struct intel_display *display, int num_joined_pipes);
u8 intel_crtc_joined_pipe_mask(const struct intel_crtc_state *crtc_state);
bool intel_crtc_is_joiner_secondary(const struct intel_crtc_state *crtc_state);
bool intel_crtc_is_joiner_primary(const struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_display_clock_gating.c b/drivers/gpu/drm/i915/display/intel_display_clock_gating.c
index d036c7e5863d..ef1ee72494df 100644
--- a/drivers/gpu/drm/i915/display/intel_display_clock_gating.c
+++ b/drivers/gpu/drm/i915/display/intel_display_clock_gating.c
@@ -27,7 +27,7 @@ static void intel_display_gen9_init_clock_gating(struct intel_display *display)
intel_de_rmw(display, DISP_ARB_CTL, 0, DISP_FBC_MEMORY_WAKE);
}
-void intel_display_skl_init_clock_gating(struct intel_display *display)
+static void intel_display_skl_init_clock_gating(struct intel_display *display)
{
/*
* WaCompressedResourceDisplayNewHashMode:skl,kbl
@@ -47,7 +47,7 @@ void intel_display_skl_init_clock_gating(struct intel_display *display)
intel_de_rmw(display, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS);
}
-void intel_display_kbl_init_clock_gating(struct intel_display *display)
+static void intel_display_kbl_init_clock_gating(struct intel_display *display)
{
/*
* WaCompressedResourceDisplayNewHashMode:skl,kbl
@@ -67,7 +67,7 @@ void intel_display_kbl_init_clock_gating(struct intel_display *display)
intel_de_rmw(display, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS);
}
-void intel_display_cfl_init_clock_gating(struct intel_display *display)
+static void intel_display_cfl_init_clock_gating(struct intel_display *display)
{
/*
* WaCompressedResourceDisplayNewHashMode:skl,kbl (and cfl, cml)
@@ -93,7 +93,7 @@ void intel_display_cfl_init_clock_gating(struct intel_display *display)
intel_de_rmw(display, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS);
}
-void intel_display_bxt_init_clock_gating(struct intel_display *display)
+static void intel_display_bxt_init_clock_gating(struct intel_display *display)
{
intel_display_gen9_init_clock_gating(display);
@@ -120,7 +120,7 @@ void intel_display_bxt_init_clock_gating(struct intel_display *display)
intel_de_rmw(display, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS);
}
-void intel_display_glk_init_clock_gating(struct intel_display *display)
+static void intel_display_glk_init_clock_gating(struct intel_display *display)
{
intel_display_gen9_init_clock_gating(display);
@@ -134,13 +134,13 @@ void intel_display_glk_init_clock_gating(struct intel_display *display)
PWM1_GATING_DIS | PWM2_GATING_DIS);
}
-void intel_display_bdw_clock_gating_disable_fbcq(struct intel_display *display)
+static void intel_display_bdw_clock_gating_disable_fbcq(struct intel_display *display)
{
/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
intel_de_rmw(display, CHICKEN_PIPESL_1(PIPE_A), 0, HSW_FBCQ_DIS);
}
-void intel_display_bdw_clock_gating_vblank_in_srd(struct intel_display *display)
+static void intel_display_bdw_clock_gating_vblank_in_srd(struct intel_display *display)
{
enum pipe pipe;
@@ -154,14 +154,21 @@ void intel_display_bdw_clock_gating_vblank_in_srd(struct intel_display *display)
}
}
-void intel_display_bdw_clock_gating_kvm_notif(struct intel_display *display)
+static void intel_display_bdw_clock_gating_kvm_notif(struct intel_display *display)
{
/* WaKVMNotificationOnConfigChange:bdw */
intel_de_rmw(display, CHICKEN_PAR2_1, 0,
KVM_CONFIG_CHANGE_NOTIFICATION_SELECT);
}
-void intel_display_hsw_init_clock_gating(struct intel_display *display)
+static void intel_display_bdw_init_clock_gating(struct intel_display *display)
+{
+ intel_display_bdw_clock_gating_disable_fbcq(display);
+ intel_display_bdw_clock_gating_vblank_in_srd(display);
+ intel_display_bdw_clock_gating_kvm_notif(display);
+}
+
+static void intel_display_hsw_init_clock_gating(struct intel_display *display)
{
enum pipe pipe;
@@ -178,7 +185,7 @@ void intel_display_hsw_init_clock_gating(struct intel_display *display)
}
}
-void intel_display_disable_trickle_feed(struct intel_display *display)
+static void intel_display_disable_trickle_feed(struct intel_display *display)
{
enum pipe pipe;
@@ -191,7 +198,7 @@ void intel_display_disable_trickle_feed(struct intel_display *display)
}
}
-void intel_display_ilk_init_clock_gating(struct intel_display *display)
+static void intel_display_ilk_init_clock_gating(struct intel_display *display)
{
u32 dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE;
@@ -223,7 +230,7 @@ void intel_display_ilk_init_clock_gating(struct intel_display *display)
intel_display_disable_trickle_feed(display);
}
-void intel_display_gen6_init_clock_gating(struct intel_display *display)
+static void intel_display_gen6_init_clock_gating(struct intel_display *display)
{
u32 dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE;
@@ -244,13 +251,15 @@ void intel_display_gen6_init_clock_gating(struct intel_display *display)
intel_display_disable_trickle_feed(display);
}
-void intel_display_ivb_init_clock_gating(struct intel_display *display)
+static void intel_display_ivb_init_clock_gating(struct intel_display *display)
{
intel_de_write(display, ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE);
intel_de_rmw(display, ILK_DISPLAY_CHICKEN1, 0, ILK_FBCQ_DIS);
+
+ intel_display_disable_trickle_feed(display);
}
-void intel_display_g4x_init_clock_gating(struct intel_display *display)
+static void intel_display_g4x_init_clock_gating(struct intel_display *display)
{
u32 dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
OVRUNIT_CLOCK_GATE_DISABLE |
@@ -264,7 +273,35 @@ void intel_display_g4x_init_clock_gating(struct intel_display *display)
intel_display_disable_trickle_feed(display);
}
-void intel_display_i965gm_init_clock_gating(struct intel_display *display)
+static void intel_display_i965gm_init_clock_gating(struct intel_display *display)
{
intel_de_write(display, DSPCLK_GATE_D, 0);
}
+
+void intel_display_init_clock_gating(struct intel_display *display)
+{
+ if (display->platform.skylake)
+ intel_display_skl_init_clock_gating(display);
+ else if (display->platform.kabylake)
+ intel_display_kbl_init_clock_gating(display);
+ else if (display->platform.coffeelake || display->platform.cometlake)
+ intel_display_cfl_init_clock_gating(display);
+ else if (display->platform.broxton)
+ intel_display_bxt_init_clock_gating(display);
+ else if (display->platform.geminilake)
+ intel_display_glk_init_clock_gating(display);
+ else if (display->platform.broadwell)
+ intel_display_bdw_init_clock_gating(display);
+ else if (display->platform.haswell)
+ intel_display_hsw_init_clock_gating(display);
+ else if (display->platform.ivybridge)
+ intel_display_ivb_init_clock_gating(display);
+ else if (display->platform.sandybridge)
+ intel_display_gen6_init_clock_gating(display);
+ else if (display->platform.ironlake)
+ intel_display_ilk_init_clock_gating(display);
+ else if (display->platform.g4x)
+ intel_display_g4x_init_clock_gating(display);
+ else if (display->platform.i965gm)
+ intel_display_i965gm_init_clock_gating(display);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_display_clock_gating.h b/drivers/gpu/drm/i915/display/intel_display_clock_gating.h
index b6dd34ca92dd..dbfa5892cffe 100644
--- a/drivers/gpu/drm/i915/display/intel_display_clock_gating.h
+++ b/drivers/gpu/drm/i915/display/intel_display_clock_gating.h
@@ -8,20 +8,6 @@
struct intel_display;
-void intel_display_skl_init_clock_gating(struct intel_display *display);
-void intel_display_kbl_init_clock_gating(struct intel_display *display);
-void intel_display_cfl_init_clock_gating(struct intel_display *display);
-void intel_display_bxt_init_clock_gating(struct intel_display *display);
-void intel_display_glk_init_clock_gating(struct intel_display *display);
-void intel_display_bdw_clock_gating_disable_fbcq(struct intel_display *display);
-void intel_display_bdw_clock_gating_vblank_in_srd(struct intel_display *display);
-void intel_display_bdw_clock_gating_kvm_notif(struct intel_display *display);
-void intel_display_hsw_init_clock_gating(struct intel_display *display);
-void intel_display_disable_trickle_feed(struct intel_display *display);
-void intel_display_ilk_init_clock_gating(struct intel_display *display);
-void intel_display_gen6_init_clock_gating(struct intel_display *display);
-void intel_display_ivb_init_clock_gating(struct intel_display *display);
-void intel_display_g4x_init_clock_gating(struct intel_display *display);
-void intel_display_i965gm_init_clock_gating(struct intel_display *display);
+void intel_display_init_clock_gating(struct intel_display *display);
#endif /* __INTEL_DISPLAY_CLOCK_GATING_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 3f02868ef105..3e302f23f247 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -49,6 +49,7 @@
#include "intel_psr.h"
#include "intel_psr_regs.h"
#include "intel_vdsc.h"
+#include "intel_vrr.h"
#include "intel_wm.h"
#include "intel_tc.h"
@@ -1284,22 +1285,11 @@ static ssize_t i915_joiner_write(struct file *file,
if (ret < 0)
return ret;
- switch (force_joined_pipes) {
- case 0:
- case 1:
- case 2:
- connector->force_joined_pipes = force_joined_pipes;
- break;
- case 4:
- if (HAS_ULTRAJOINER(display)) {
- connector->force_joined_pipes = force_joined_pipes;
- break;
- }
-
- fallthrough;
- default:
+ if (force_joined_pipes &&
+ !intel_joiner_valid_primary_pipe_mask(display, force_joined_pipes))
return -EINVAL;
- }
+
+ connector->force_joined_pipes = force_joined_pipes;
*offp += len;
@@ -1395,6 +1385,7 @@ void intel_crtc_debugfs_add(struct intel_crtc *crtc)
intel_drrs_crtc_debugfs_add(crtc);
intel_fbc_crtc_debugfs_add(crtc);
hsw_ips_crtc_debugfs_add(crtc);
+ intel_vrr_crtc_debugfs_add(crtc);
debugfs_create_file("i915_current_bpc", 0444, root, crtc,
&i915_current_bpc_fops);
diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c
index 02cb4d800e23..233465a8306e 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power_well.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c
@@ -325,7 +325,11 @@ static enum phy icl_aux_pw_to_phy(struct intel_display *display,
{
struct intel_encoder *encoder = icl_aux_pw_to_encoder(display, power_well);
- return encoder ? intel_encoder_to_phy(encoder) : PHY_NONE;
+ if (drm_WARN(display->drm, !encoder,
+ "PHY is invalid if encoder is NULL, assuming PHY_A\n"))
+ return PHY_A;
+
+ return intel_encoder_to_phy(encoder);
}
static bool icl_aux_pw_is_tc_phy(struct intel_display *display,
diff --git a/drivers/gpu/drm/i915/display/intel_display_regs.h b/drivers/gpu/drm/i915/display/intel_display_regs.h
index 0f5018482497..8251ec15190b 100644
--- a/drivers/gpu/drm/i915/display/intel_display_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_display_regs.h
@@ -2788,7 +2788,7 @@ enum skl_power_gate {
#define BXT_CDCLK_CD2X_PIPE_MASK REG_GENMASK(21, 20) /* bxt/glk */
#define BXT_CDCLK_CD2X_PIPE(pipe) REG_FIELD_PREP(BXT_CDCLK_CD2X_PIPE_MASK, (pipe))
#define BXT_CDCLK_CD2X_PIPE_NONE REG_FIELD_PREP(BXT_CDCLK_CD2X_PIPE_MASK, 3)
-#define ICL_CDCLK_CD2X_PIPE_MASK REG_GENMASK(21, 19) /* icl+ */
+#define ICL_CDCLK_CD2X_PIPE_MASK REG_GENMASK(21, 19) /* icl-lnl */
#define ICL_CDCLK_CD2X_PIPE(pipe) REG_FIELD_PREP(ICL_CDCLK_CD2X_PIPE_MASK, (pipe) << 1)
#define ICL_CDCLK_CD2X_PIPE_NONE REG_FIELD_PREP(ICL_CDCLK_CD2X_PIPE_MASK, 7)
#define CDCLK_DIVMUX_CD_OVERRIDE REG_BIT(19) /* pre-icl */
@@ -2874,9 +2874,19 @@ enum skl_power_gate {
#define ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port) (1 << ((tc_port) < TC_PORT_4 ? \
(tc_port) + 12 : \
(tc_port) - TC_PORT_4 + 21))
-#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) ((phy) * 2)
-#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) (3 << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
-#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) ((pll) << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
+
+/*
+ * ICL_DPCLKA_CFGCR0 has a 2-bit DDI_CLK_SEL field per combo PHY, for
+ * PHY_A..PHY_D only. Any other phy value (PHY_NONE, TypeC/SNPS PHYs)
+ * is not valid here.
+ */
+#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) _PICK(phy & 0x3, 0, 2, 4, 6)
+#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) \
+ REG_GENMASK(ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) + 1, \
+ ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
+#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) \
+ ((pll) << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
+
#define RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) _PICK(phy, 0, 2, 4, 27)
#define RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) \
(3 << RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index b7cc361fd955..5f0fe18c0614 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1408,13 +1408,13 @@ struct intel_crtc_state {
u16 max_increase, max_decrease;
u16 vblank_target;
} dc_balance;
- } vrr;
- /* Content Match Refresh Rate state */
- struct {
- bool enable;
- u64 cmrr_n, cmrr_m;
- } cmrr;
+ /* Content Match Refresh Rate state */
+ struct {
+ bool enable;
+ u64 cmrr_n, cmrr_m;
+ } cmrr;
+ } vrr;
/* Stream Splitter for eDP MSO */
struct {
@@ -1553,6 +1553,11 @@ struct intel_crtc {
u64 flip_count;
} dc_balance;
+ struct {
+ u32 numerator;
+ u32 denominator;
+ } force_cmrr;
+
int scanline_offset;
struct {
@@ -1946,6 +1951,8 @@ struct intel_dp {
bool colorimetry_support;
+ bool sst_split_sdp_support;
+
struct {
enum transcoder transcoder;
struct mutex lock;
diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.c b/drivers/gpu/drm/i915/display/intel_display_wa.c
index 3662e0f17c69..888676693f5e 100644
--- a/drivers/gpu/drm/i915/display/intel_display_wa.c
+++ b/drivers/gpu/drm/i915/display/intel_display_wa.c
@@ -4,6 +4,7 @@
*/
#include <drm/drm_print.h>
+#include <drm/intel/display_parent_interface.h>
#include <drm/intel/step.h>
#include "intel_de.h"
@@ -131,7 +132,8 @@ bool __intel_display_wa(struct intel_display *display, enum intel_display_wa wa,
case INTEL_DISPLAY_WA_16011863758:
return DISPLAY_VER(display) >= 11;
case INTEL_DISPLAY_WA_16023588340:
- return intel_display_needs_wa_16023588340(display);
+ /* This is a GT workaround. */
+ return display->parent->wa && display->parent->wa->wa_16023588340(display->drm);
case INTEL_DISPLAY_WA_16025573575:
return intel_display_needs_wa_16025573575(display);
case INTEL_DISPLAY_WA_16025596647:
diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.h b/drivers/gpu/drm/i915/display/intel_display_wa.h
index 338b32e4162d..425a300840aa 100644
--- a/drivers/gpu/drm/i915/display/intel_display_wa.h
+++ b/drivers/gpu/drm/i915/display/intel_display_wa.h
@@ -12,15 +12,6 @@ struct intel_display;
void intel_display_wa_apply(struct intel_display *display);
-#ifdef I915
-static inline bool intel_display_needs_wa_16023588340(struct intel_display *display)
-{
- return false;
-}
-#else
-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
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 113d767e62e9..0cd5e6b5034c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1274,17 +1274,7 @@ bool intel_dp_can_join(struct intel_dp *intel_dp,
if (num_joined_pipes > 1 && !intel_dp_has_joiner(intel_dp))
return false;
- switch (num_joined_pipes) {
- case 1:
- return true;
- case 2:
- return HAS_BIGJOINER(display) ||
- HAS_UNCOMPRESSED_JOINER(display);
- case 4:
- return HAS_ULTRAJOINER(display);
- default:
- return false;
- }
+ return intel_joiner_valid_primary_pipe_mask(display, num_joined_pipes);
}
bool intel_dp_dotclk_valid(struct intel_display *display,
@@ -2920,6 +2910,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
struct drm_connector_state *conn_state,
bool respect_downstream_limits)
{
+ struct intel_display *display = to_intel_display(encoder);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct intel_connector *connector =
to_intel_connector(conn_state->connector);
@@ -2934,6 +2925,10 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
return -EINVAL;
for_each_joiner_candidate(connector, adjusted_mode, num_joined_pipes) {
+ /* If the pipe can't be a joiner primary, skip early. */
+ if (!(intel_joiner_valid_primary_pipe_mask(display, num_joined_pipes) & BIT(crtc->pipe)))
+ continue;
+
/*
* NOTE:
* The crtc_state->joiner_pipes should have been set at the end
@@ -3125,6 +3120,7 @@ static void intel_dp_compute_as_sdp(struct intel_dp *intel_dp,
struct drm_dp_as_sdp *as_sdp = &crtc_state->infoframes.as_sdp;
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
/*
* #FIXME: SDP/infoframe updates aren’t truly atomic, and with the new
@@ -3142,10 +3138,14 @@ static void intel_dp_compute_as_sdp(struct intel_dp *intel_dp,
as_sdp->revision = 0x2;
as_sdp->vtotal = intel_vrr_vmin_vtotal(crtc_state);
- if (crtc_state->cmrr.enable) {
+ if (crtc_state->vrr.cmrr.enable) {
as_sdp->mode = DP_AS_SDP_FAVT_TRR_REACHED;
as_sdp->target_rr = drm_mode_vrefresh(adjusted_mode);
- as_sdp->target_rr_divider = true;
+
+ if (crtc->force_cmrr.denominator == 1001)
+ as_sdp->target_rr_divider = true;
+ else
+ as_sdp->target_rr_divider = false;
} else if (crtc_state->vrr.enable) {
as_sdp->mode = DP_AS_SDP_AVT_DYNAMIC_VTOTAL;
} else {
@@ -3409,12 +3409,22 @@ intel_dp_audio_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state)
{
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
pipe_config->has_audio =
intel_dp_has_audio(encoder, conn_state) &&
intel_audio_compute_config(encoder, pipe_config, conn_state);
pipe_config->sdp_split_enable = pipe_config->has_audio &&
intel_dp_is_uhbr(pipe_config);
+
+ /*
+ * SDP splitting for UHBR audio requires explicit sink capability in
+ * SST mode, whereas in MST mode it is inherently supported.
+ */
+ if (pipe_config->sdp_split_enable &&
+ !intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST))
+ pipe_config->sdp_split_enable = intel_dp->sst_split_sdp_support;
}
void
@@ -4129,14 +4139,9 @@ static int intel_dp_pcon_set_frl_mask(int max_frl)
static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp)
{
struct intel_connector *connector = intel_dp->attached_connector;
- const struct drm_display_info *info = &connector->base.display_info;
- int max_frl_rate;
- int max_lanes, rate_per_lane;
- int max_dsc_lanes, dsc_rate_per_lane;
-
- max_lanes = info->hdmi.max_lanes;
- rate_per_lane = info->hdmi.max_frl_rate_per_lane;
- max_frl_rate = max_lanes * rate_per_lane;
+ struct drm_connector *drm_connector = &connector->base;
+ int max_frl_rate = intel_hdmi_sink_max_frl_rate(drm_connector);
+ int dsc_max_frl_rate = intel_hdmi_sink_dsc_max_frl_rate(drm_connector);
/*
* The sink's DSC max FRL rate only applies to compressed video
@@ -4145,12 +4150,8 @@ static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp)
* the regular max FRL rate is the limit.
*/
if (drm_dp_pcon_enc_is_dsc_1_2(intel_dp->pcon_dsc_dpcd) &&
- info->hdmi.dsc_cap.v_1p2) {
- max_dsc_lanes = info->hdmi.dsc_cap.max_lanes;
- dsc_rate_per_lane = info->hdmi.dsc_cap.max_frl_rate_per_lane;
- if (max_dsc_lanes && dsc_rate_per_lane)
- max_frl_rate = min(max_frl_rate, max_dsc_lanes * dsc_rate_per_lane);
- }
+ dsc_max_frl_rate)
+ return min(max_frl_rate, dsc_max_frl_rate);
return max_frl_rate;
}
@@ -4316,7 +4317,9 @@ intel_dp_pcon_dsc_enc_slices(struct intel_dp *intel_dp,
int pcon_max_slices = drm_dp_pcon_dsc_max_slices(intel_dp->pcon_dsc_dpcd);
int pcon_max_slice_width = drm_dp_pcon_dsc_max_slice_width(intel_dp->pcon_dsc_dpcd);
- return intel_hdmi_dsc_get_num_slices(crtc_state, pcon_max_slices,
+ return intel_hdmi_dsc_get_num_slices(&crtc_state->hw.adjusted_mode,
+ crtc_state->output_format,
+ pcon_max_slices,
pcon_max_slice_width,
hdmi_max_slices, hdmi_throughput);
}
@@ -4333,9 +4336,10 @@ intel_dp_pcon_dsc_enc_bpp(struct intel_dp *intel_dp,
int pcon_fractional_bpp = drm_dp_pcon_dsc_bpp_incr(intel_dp->pcon_dsc_dpcd);
int hdmi_max_chunk_bytes =
info->hdmi.dsc_cap.total_chunk_kbytes * 1024;
+ int bpc = crtc_state->pipe_bpp / 3;
return intel_hdmi_dsc_get_bpp(pcon_fractional_bpp, slice_width,
- num_slices, output_format, hdmi_all_bpp,
+ num_slices, output_format, bpc, hdmi_all_bpp,
hdmi_max_chunk_bytes);
}
@@ -4462,16 +4466,25 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
str_enable_disable(tmp));
}
-static bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
+static u8 intel_dp_read_dprx_feature_enum(struct intel_dp *intel_dp)
{
u8 dprx = 0;
- if (drm_dp_dpcd_readb(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
- &dprx) != 1)
- return false;
+ drm_dp_dpcd_read_data(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
+ &dprx, sizeof(dprx));
+ return dprx;
+}
+
+static bool intel_dp_get_colorimetry_status(u8 dprx)
+{
return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED;
}
+static bool intel_dp_get_sst_split_sdp_status(u8 dprx)
+{
+ return dprx & DP_SST_SPLIT_SDP_CAP;
+}
+
static int intel_dp_read_dsc_dpcd(struct drm_dp_aux *aux,
u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
{
@@ -4771,6 +4784,7 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector
{
struct intel_display *display = to_intel_display(intel_dp);
int ret;
+ u8 dprx;
/* this function is meant to be called only once */
drm_WARN_ON(display->drm, intel_dp->dpcd[DP_DPCD_REV] != 0);
@@ -4782,8 +4796,13 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector
drm_dp_is_branch(intel_dp->dpcd));
intel_init_dpcd_quirks(intel_dp, &intel_dp->desc.ident);
+ dprx = intel_dp_read_dprx_feature_enum(intel_dp);
+
intel_dp->colorimetry_support =
- intel_dp_get_colorimetry_status(intel_dp);
+ intel_dp_get_colorimetry_status(dprx);
+
+ intel_dp->sst_split_sdp_support =
+ intel_dp_get_sst_split_sdp_status(dprx);
/*
* Read the eDP display control registers.
@@ -4874,13 +4893,20 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
* the OUI/ID since we know it won't change.
*/
if (!intel_dp_is_edp(intel_dp)) {
+ u8 dprx;
+
drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
drm_dp_is_branch(intel_dp->dpcd));
intel_init_dpcd_quirks(intel_dp, &intel_dp->desc.ident);
+ dprx = intel_dp_read_dprx_feature_enum(intel_dp);
+
intel_dp->colorimetry_support =
- intel_dp_get_colorimetry_status(intel_dp);
+ intel_dp_get_colorimetry_status(dprx);
+
+ intel_dp->sst_split_sdp_support =
+ intel_dp_get_sst_split_sdp_status(dprx);
intel_dp_update_sink_caps(intel_dp);
}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 57daed0b0b36..6a869d0f6ffc 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -766,6 +766,10 @@ static int mst_stream_compute_config(struct intel_atomic_state *state,
return ret;
for_each_joiner_candidate(connector, adjusted_mode, num_joined_pipes) {
+ /* If the pipe can't be a joiner primary, skip early. */
+ if (!(intel_joiner_valid_primary_pipe_mask(display, num_joined_pipes) & BIT(crtc->pipe)))
+ continue;
+
if (num_joined_pipes > 1)
pipe_config->joiner_pipes = GENMASK(crtc->pipe + num_joined_pipes - 1,
crtc->pipe);
diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c
index f40807a5566b..20fd091cb9db 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll.c
@@ -22,7 +22,6 @@
#include "intel_lvds_regs.h"
#include "intel_panel.h"
#include "intel_pps.h"
-#include "intel_snps_phy.h"
#include "vlv_dpio_phy_regs.h"
#include "vlv_sideband.h"
@@ -1194,24 +1193,6 @@ static int hsw_crtc_get_dpll(struct intel_atomic_state *state,
return intel_dpll_reserve(state, crtc, encoder);
}
-static int dg2_crtc_compute_clock(struct intel_atomic_state *state,
- struct intel_crtc *crtc)
-{
- struct intel_crtc_state *crtc_state =
- intel_atomic_get_new_crtc_state(state, crtc);
- struct intel_encoder *encoder =
- intel_get_crtc_new_encoder(state, crtc_state);
- int ret;
-
- ret = intel_mpllb_calc_state(crtc_state, encoder);
- if (ret)
- return ret;
-
- crtc_state->hw.adjusted_mode.crtc_clock = intel_crtc_dotclock(crtc_state);
-
- return 0;
-}
-
static int ilk_fb_cb_factor(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
@@ -1682,7 +1663,8 @@ static const struct intel_dpll_global_funcs mtl_dpll_funcs = {
};
static const struct intel_dpll_global_funcs dg2_dpll_funcs = {
- .crtc_compute_clock = dg2_crtc_compute_clock,
+ .crtc_compute_clock = hsw_crtc_compute_clock,
+ .crtc_get_dpll = hsw_crtc_get_dpll,
};
static const struct intel_dpll_global_funcs hsw_dpll_funcs = {
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index 0f933101b7dd..bfd6f0a19725 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -42,6 +42,7 @@
#include "intel_lt_phy.h"
#include "intel_mg_phy_regs.h"
#include "intel_pch_refclk.h"
+#include "intel_snps_phy.h"
#include "intel_tc.h"
/**
@@ -4735,6 +4736,214 @@ static const struct intel_dpll_mgr xe3plpd_pll_mgr = {
.compare_hw_state = xe3plpd_compare_hw_state,
};
+enum intel_dpll_id dg2_port_to_pll_id(enum port port)
+{
+ switch (port) {
+ case PORT_A:
+ return DPLL_ID_DG2_DPLL_A;
+ case PORT_B:
+ return DPLL_ID_DG2_DPLL_B;
+ case PORT_C:
+ return DPLL_ID_DG2_DPLL_C;
+ case PORT_D_XELPD:
+ return DPLL_ID_DG2_DPLL_D;
+ case PORT_TC1:
+ return DPLL_ID_DG2_DPLL_E;
+ default:
+ MISSING_CASE(port);
+ return DPLL_ID_DG2_DPLL_A;
+ }
+}
+
+static struct intel_encoder *dg2_get_intel_encoder(struct intel_display *display,
+ const struct intel_dpll *pll)
+{
+ struct intel_encoder *encoder;
+
+ for_each_intel_encoder(display->drm, encoder) {
+ if (dg2_port_to_pll_id(encoder->port) == pll->info->id &&
+ intel_encoder_is_dig_port(encoder))
+ return encoder;
+ }
+
+ return NULL;
+}
+
+static void dg2_mpllb_enable(struct intel_display *display,
+ struct intel_dpll *pll,
+ const struct intel_dpll_hw_state *dpll_hw_state)
+{
+ struct intel_encoder *encoder = dg2_get_intel_encoder(display, pll);
+
+ if (drm_WARN_ON(display->drm, !encoder))
+ return;
+
+ intel_mpllb_enable_phy(encoder, &dpll_hw_state->mpllb);
+}
+
+static void dg2_mpllb_disable(struct intel_display *display,
+ struct intel_dpll *pll)
+{
+ struct intel_encoder *encoder = dg2_get_intel_encoder(display, pll);
+
+ if (drm_WARN_ON(display->drm, !encoder))
+ return;
+
+ intel_mpllb_disable(encoder);
+}
+
+static bool dg2_mpllb_get_hw_state(struct intel_display *display,
+ struct intel_dpll *pll,
+ struct intel_dpll_hw_state *dpll_hw_state)
+{
+ struct intel_encoder *encoder = dg2_get_intel_encoder(display, pll);
+ enum phy phy;
+ i915_reg_t enable_reg;
+ struct ref_tracker *wakeref;
+ bool ret = false;
+ u32 val;
+
+ if (!encoder)
+ return false;
+
+ wakeref = intel_display_power_get_if_enabled(display,
+ POWER_DOMAIN_DISPLAY_CORE);
+ if (!wakeref)
+ return false;
+
+ phy = intel_encoder_to_phy(encoder);
+ enable_reg = (phy <= PHY_D ? DG2_PLL_ENABLE(phy) : MG_PLL_ENABLE(0));
+
+ val = intel_de_read(display, enable_reg);
+ if (!(val & PLL_ENABLE))
+ goto out;
+
+ intel_mpllb_readout_hw_state(encoder, &dpll_hw_state->mpllb);
+ ret = true;
+
+out:
+ intel_display_power_put(display, POWER_DOMAIN_DISPLAY_CORE, wakeref);
+ return ret;
+}
+
+static int dg2_mpllb_get_freq(struct intel_display *display,
+ const struct intel_dpll *pll,
+ const struct intel_dpll_hw_state *dpll_hw_state)
+{
+ struct intel_encoder *encoder = dg2_get_intel_encoder(display, pll);
+
+ if (drm_WARN_ON(display->drm, !encoder))
+ return 0;
+
+ return intel_mpllb_calc_port_clock(encoder, &dpll_hw_state->mpllb);
+}
+
+static const struct intel_dpll_funcs mpllb_pll_funcs = {
+ .enable = dg2_mpllb_enable,
+ .disable = dg2_mpllb_disable,
+ .get_hw_state = dg2_mpllb_get_hw_state,
+ .get_freq = dg2_mpllb_get_freq,
+};
+
+static const struct dpll_info dg2_plls[] = {
+ { .name = "MPLLB A", .funcs = &mpllb_pll_funcs, .id = DPLL_ID_DG2_DPLL_A, },
+ { .name = "MPLLB B", .funcs = &mpllb_pll_funcs, .id = DPLL_ID_DG2_DPLL_B, },
+ { .name = "MPLLB C", .funcs = &mpllb_pll_funcs, .id = DPLL_ID_DG2_DPLL_C, },
+ { .name = "MPLLB D", .funcs = &mpllb_pll_funcs, .id = DPLL_ID_DG2_DPLL_D, },
+ { .name = "MPLLB E", .funcs = &mpllb_pll_funcs, .id = DPLL_ID_DG2_DPLL_E, },
+ {}
+};
+
+static int dg2_compute_dplls(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_encoder *encoder)
+{
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+ struct icl_port_dpll *port_dpll =
+ &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
+ int ret;
+
+ ret = intel_mpllb_calc_state(crtc_state, encoder);
+ if (ret)
+ return ret;
+
+ port_dpll->hw_state = crtc_state->dpll_hw_state;
+
+ /* this is mainly for the fastset check */
+ icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT);
+
+ crtc_state->port_clock = intel_mpllb_calc_port_clock(encoder,
+ &port_dpll->hw_state.mpllb);
+
+ return 0;
+}
+
+static int dg2_get_dplls(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ struct intel_encoder *encoder)
+{
+ struct intel_crtc_state *crtc_state =
+ intel_atomic_get_new_crtc_state(state, crtc);
+ struct icl_port_dpll *port_dpll =
+ &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
+ enum intel_dpll_id dpll_id = dg2_port_to_pll_id(encoder->port);
+
+ port_dpll->pll = intel_find_dpll(state, crtc,
+ &port_dpll->hw_state,
+ BIT(dpll_id));
+ if (!port_dpll->pll)
+ return -EINVAL;
+
+ intel_reference_dpll(state, crtc,
+ port_dpll->pll, &port_dpll->hw_state);
+
+ icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT);
+
+ return 0;
+}
+
+static void dg2_dump_hw_state(struct drm_printer *p,
+ const struct intel_dpll_hw_state *dpll_hw_state)
+{
+ const struct intel_mpllb_state *hw_state = &dpll_hw_state->mpllb;
+
+ drm_printf(p, "dpll_hw_state: mpllb_cp: 0x%x, mpllb_div: 0x%x, "
+ "mpllb_div2: 0x%x, mpllb_fracn1: 0x%x, "
+ "mpllb_fracn2: 0x%x, mpllb_sscen: 0x%x, "
+ "mpllb_sscstep: 0x%x, ref_control: 0x%x\n",
+ hw_state->mpllb_cp, hw_state->mpllb_div,
+ hw_state->mpllb_div2, hw_state->mpllb_fracn1,
+ hw_state->mpllb_fracn2, hw_state->mpllb_sscen,
+ hw_state->mpllb_sscstep, hw_state->ref_control);
+}
+
+static bool dg2_compare_hw_state(const struct intel_dpll_hw_state *_a,
+ const struct intel_dpll_hw_state *_b)
+{
+ const struct intel_mpllb_state *a = &_a->mpllb;
+ const struct intel_mpllb_state *b = &_b->mpllb;
+
+ return a->mpllb_cp == b->mpllb_cp &&
+ a->mpllb_div == b->mpllb_div &&
+ a->mpllb_div2 == b->mpllb_div2 &&
+ a->mpllb_fracn1 == b->mpllb_fracn1 &&
+ a->mpllb_fracn2 == b->mpllb_fracn2 &&
+ a->mpllb_sscen == b->mpllb_sscen &&
+ a->mpllb_sscstep == b->mpllb_sscstep;
+}
+
+static const struct intel_dpll_mgr dg2_pll_mgr = {
+ .dpll_info = dg2_plls,
+ .compute_dplls = dg2_compute_dplls,
+ .get_dplls = dg2_get_dplls,
+ .put_dplls = icl_put_dplls,
+ .update_active_dpll = icl_update_active_dpll,
+ .update_ref_clks = icl_update_dpll_ref_clks,
+ .dump_hw_state = dg2_dump_hw_state,
+ .compare_hw_state = dg2_compare_hw_state,
+};
+
/**
* intel_dpll_init - Initialize DPLLs
* @display: intel_display device
@@ -4750,8 +4959,7 @@ void intel_dpll_init(struct intel_display *display)
mutex_init(&display->dpll.lock);
if (display->platform.dg2)
- /* No shared DPLLs on DG2; port PLLs are part of the PHY */
- dpll_mgr = NULL;
+ dpll_mgr = &dg2_pll_mgr;
else if (DISPLAY_VER(display) >= 35)
dpll_mgr = &xe3plpd_pll_mgr;
else if (DISPLAY_VER(display) >= 14)
@@ -5120,8 +5328,13 @@ verify_single_dpll_state(struct intel_display *display,
if (pll->on) {
const struct intel_dpll_mgr *dpll_mgr = display->dpll.mgr;
-
- if (HAS_LT_PHY(display))
+ /*
+ * Avoid direct struct comparison here. Some hw state fields, such
+ * as DG2 MPLLB ref_control or LT PHY config[1], are written by
+ * firmware and may differ from the software state without indicating
+ * a real mismatch.
+ */
+ if (HAS_LT_PHY(display) || display->platform.dg2)
pll_mismatch = !dpll_mgr->compare_hw_state(&pll->state.hw_state,
&dpll_hw_state);
else
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
index d408ccf6f902..f4b84733a58c 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
@@ -169,9 +169,31 @@ enum intel_dpll_id {
* @DPLL_ID_DG1_DPLL3: DG1 combo PHY DPLL3
*/
DPLL_ID_DG1_DPLL3 = 3,
+
+ /**
+ * @DPLL_ID_DG2_DPLL_A: DG2 port PLL for PHY A (PORT_A)
+ */
+ DPLL_ID_DG2_DPLL_A = 0,
+ /**
+ * @DPLL_ID_DG2_DPLL_B: DG2 port PLL for PHY B (PORT_B)
+ */
+ DPLL_ID_DG2_DPLL_B = 1,
+ /**
+ * @DPLL_ID_DG2_DPLL_C: DG2 port PLL for PHY C (PORT_C)
+ */
+ DPLL_ID_DG2_DPLL_C = 2,
+ /**
+ * @DPLL_ID_DG2_DPLL_D: DG2 port PLL for PHY D (PORT_D_XELPD)
+ */
+ DPLL_ID_DG2_DPLL_D = 3,
+ /**
+ * @DPLL_ID_DG2_DPLL_E: DG2 port PLL for PHY F (PORT_TC1)
+ */
+ DPLL_ID_DG2_DPLL_E = 4,
};
#define I915_NUM_PLLS 9
+enum intel_dpll_id dg2_port_to_pll_id(enum port port);
enum icl_port_dpll_id {
ICL_PORT_DPLL_DEFAULT,
diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c
index 705742e117ca..70aae6ffa3fe 100644
--- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c
+++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c
@@ -66,7 +66,6 @@
#include "intel_frontbuffer.h"
#include "intel_parent.h"
#include "intel_psr.h"
-#include "intel_tdf.h"
/**
* frontbuffer_flush - flush frontbuffer
@@ -95,7 +94,7 @@ static void frontbuffer_flush(struct intel_display *display,
trace_intel_frontbuffer_flush(display, frontbuffer_bits, origin);
might_sleep();
- intel_td_flush(display);
+ intel_parent_transient_data_flush(display);
intel_drrs_flush(display, frontbuffer_bits);
intel_psr_flush(display, frontbuffer_bits, origin);
intel_fbc_flush(display, frontbuffer_bits, origin);
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 8a019d3574df..b6fa1a1558b8 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2399,10 +2399,6 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
if (!intel_link_bw_compute_pipe_bpp(pipe_config))
return -EINVAL;
- pipe_config->has_audio =
- intel_hdmi_has_audio(encoder, pipe_config, conn_state) &&
- intel_audio_compute_config(encoder, pipe_config, conn_state);
-
/*
* Try to respect downstream TMDS clock limits first, if
* that fails assume the user might know something we don't.
@@ -2417,6 +2413,10 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
return ret;
}
+ pipe_config->has_audio =
+ intel_hdmi_has_audio(encoder, pipe_config, conn_state) &&
+ intel_audio_compute_config(encoder, pipe_config, conn_state);
+
ret = intel_pfit_compute_config(pipe_config, conn_state);
if (ret)
return ret;
@@ -3216,7 +3216,8 @@ int intel_hdmi_dsc_get_slice_height(int vactive)
* intel_hdmi_dsc_get_num_slices - get no. of dsc slices based on dsc encoder
* and dsc decoder capabilities
*
- * @crtc_state: intel crtc_state
+ * @mode: drm_display_mode for which num of slices are needed
+ * @output_format : pipe output format
* @src_max_slices: maximum slices supported by the DSC encoder
* @src_max_slice_width: maximum slice width supported by DSC encoder
* @hdmi_max_slices: maximum slices supported by sink DSC decoder
@@ -3226,7 +3227,8 @@ int intel_hdmi_dsc_get_slice_height(int vactive)
* and decoder.
*/
int
-intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state,
+intel_hdmi_dsc_get_num_slices(const struct drm_display_mode *mode,
+ enum intel_output_format output_format,
int src_max_slices, int src_max_slice_width,
int hdmi_max_slices, int hdmi_throughput)
{
@@ -3248,7 +3250,7 @@ intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state,
int max_throughput; /* max clock freq. in khz per slice */
int max_slice_width;
int slice_width;
- int pixel_clock = crtc_state->hw.adjusted_mode.crtc_clock;
+ int pixel_clock = mode->crtc_clock;
if (!hdmi_throughput)
return 0;
@@ -3259,8 +3261,8 @@ intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state,
* for 4:4:4 is 1.0. Multiplying these factors by 10 and later
* dividing adjusted clock value by 10.
*/
- if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 ||
- crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB)
+ if (output_format == INTEL_OUTPUT_FORMAT_YCBCR444 ||
+ output_format == INTEL_OUTPUT_FORMAT_RGB)
kslice_adjust = 10;
else
kslice_adjust = 5;
@@ -3315,7 +3317,7 @@ intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state,
else
return 0;
- slice_width = DIV_ROUND_UP(crtc_state->hw.adjusted_mode.hdisplay, target_slices);
+ slice_width = DIV_ROUND_UP(mode->hdisplay, target_slices);
if (slice_width >= max_slice_width)
min_slices = target_slices + 1;
} while (slice_width >= max_slice_width);
@@ -3331,6 +3333,7 @@ intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state,
* @slice_width: dsc slice width supported by the source and sink
* @num_slices: num of slices supported by the source and sink
* @output_format: video output format
+ * @bpc: bits per color
* @hdmi_all_bpp: sink supports decoding of 1/16th bpp setting
* @hdmi_max_chunk_bytes: max bytes in a line of chunks supported by sink
*
@@ -3338,8 +3341,8 @@ intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state,
*/
int
intel_hdmi_dsc_get_bpp(int src_fractional_bpp, int slice_width, int num_slices,
- int output_format, bool hdmi_all_bpp,
- int hdmi_max_chunk_bytes)
+ enum intel_output_format output_format, int bpc,
+ bool hdmi_all_bpp, int hdmi_max_chunk_bytes)
{
int max_dsc_bpp, min_dsc_bpp;
int target_bytes;
@@ -3356,18 +3359,17 @@ intel_hdmi_dsc_get_bpp(int src_fractional_bpp, int slice_width, int num_slices,
* for each bpp we check if no of bytes can be supported by HDMI sink
*/
- /* Assuming: bpc as 8*/
if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
min_dsc_bpp = 6;
- max_dsc_bpp = 3 * 4; /* 3*bpc/2 */
+ max_dsc_bpp = 3 * bpc / 2;
} else if (output_format == INTEL_OUTPUT_FORMAT_YCBCR444 ||
output_format == INTEL_OUTPUT_FORMAT_RGB) {
min_dsc_bpp = 8;
- max_dsc_bpp = 3 * 8; /* 3*bpc */
+ max_dsc_bpp = 3 * bpc;
} else {
/* Assuming 4:2:2 encoding */
min_dsc_bpp = 7;
- max_dsc_bpp = 2 * 8; /* 2*bpc */
+ max_dsc_bpp = 2 * bpc;
}
/*
@@ -3420,3 +3422,22 @@ intel_hdmi_dsc_get_bpp(int src_fractional_bpp, int slice_width, int num_slices,
return 0;
}
+
+int intel_hdmi_sink_max_frl_rate(struct drm_connector *connector)
+{
+ int max_lanes = connector->display_info.hdmi.max_lanes;
+ int rate_per_lane = connector->display_info.hdmi.max_frl_rate_per_lane;
+
+ return max_lanes * rate_per_lane;
+}
+
+int intel_hdmi_sink_dsc_max_frl_rate(struct drm_connector *connector)
+{
+ int max_lanes = connector->display_info.hdmi.dsc_cap.max_lanes;
+ int rate_per_lane = connector->display_info.hdmi.dsc_cap.max_frl_rate_per_lane;
+
+ if (!max_lanes || !rate_per_lane)
+ return 0;
+
+ return max_lanes * rate_per_lane;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
index 0fa3661568e8..c95ed37bcc0c 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
@@ -13,6 +13,7 @@ enum intel_output_format;
enum port;
struct drm_connector;
struct drm_connector_state;
+struct drm_display_mode;
struct drm_encoder;
struct intel_connector;
struct intel_crtc_state;
@@ -54,9 +55,10 @@ bool intel_hdmi_bpc_possible(const struct intel_crtc_state *crtc_state,
int bpc, bool has_hdmi_sink);
int intel_hdmi_tmds_clock(int clock, int bpc, enum intel_output_format sink_format);
int intel_hdmi_dsc_get_bpp(int src_fractional_bpp, int slice_width,
- int num_slices, int output_format, bool hdmi_all_bpp,
- int hdmi_max_chunk_bytes);
-int intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state,
+ int num_slices, enum intel_output_format output_format,
+ int bpc, bool hdmi_all_bpp, int hdmi_max_chunk_bytes);
+int intel_hdmi_dsc_get_num_slices(const struct drm_display_mode *mode,
+ enum intel_output_format output_format,
int src_max_slices, int src_max_slice_width,
int hdmi_max_slices, int hdmi_throughput);
int intel_hdmi_dsc_get_slice_height(int vactive);
@@ -73,4 +75,7 @@ void hsw_read_infoframe(struct intel_encoder *encoder,
void intel_hdmi_poll_for_scrambling_enable(const struct intel_crtc_state *crtc_state,
struct drm_connector *_connector);
+int intel_hdmi_sink_max_frl_rate(struct drm_connector *connector);
+int intel_hdmi_sink_dsc_max_frl_rate(struct drm_connector *connector);
+
#endif /* __INTEL_HDMI_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_hti.c b/drivers/gpu/drm/i915/display/intel_hti.c
index dc454420c134..56602240ceff 100644
--- a/drivers/gpu/drm/i915/display/intel_hti.c
+++ b/drivers/gpu/drm/i915/display/intel_hti.c
@@ -23,9 +23,6 @@ void intel_hti_init(struct intel_display *display)
bool intel_hti_uses_phy(struct intel_display *display, enum phy phy)
{
- if (drm_WARN_ON(display->drm, phy == PHY_NONE))
- return false;
-
return display->hti.state & HDPORT_ENABLED &&
display->hti.state & HDPORT_DDI_USED(phy);
}
diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c
index 2ec17c2bfe0f..f0761d8a7437 100644
--- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c
+++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c
@@ -245,7 +245,6 @@ void intel_modeset_verify_crtc(struct intel_atomic_state *state,
verify_connector_state(state, crtc);
verify_crtc_state(state, crtc);
intel_dpll_state_verify(state, crtc);
- intel_mpllb_state_verify(state, crtc);
}
void intel_modeset_verify_disabled(struct intel_atomic_state *state)
diff --git a/drivers/gpu/drm/i915/display/intel_parent.c b/drivers/gpu/drm/i915/display/intel_parent.c
index a5e41ea66921..99cebb17763a 100644
--- a/drivers/gpu/drm/i915/display/intel_parent.c
+++ b/drivers/gpu/drm/i915/display/intel_parent.c
@@ -281,9 +281,9 @@ void intel_parent_pc8_unblock(struct intel_display *display)
}
/* pcode */
-int intel_parent_pcode_read(struct intel_display *display, u32 mbox, u32 *val, u32 *val1)
+int intel_parent_pcode_read(struct intel_display *display, u32 mbox, u32 *val0, u32 *val1)
{
- return display->parent->pcode->read(display->drm, mbox, val, val1);
+ return display->parent->pcode->read(display->drm, mbox, val0, val1);
}
int intel_parent_pcode_write_timeout(struct intel_display *display, u32 mbox, u32 val, int timeout_ms)
@@ -451,6 +451,12 @@ bool intel_parent_has_fenced_regions(struct intel_display *display)
return display->parent->has_fenced_regions && display->parent->has_fenced_regions(display->drm);
}
+void intel_parent_transient_data_flush(struct intel_display *display)
+{
+ if (display->parent->transient_data_flush)
+ display->parent->transient_data_flush(display->drm);
+}
+
bool intel_parent_vgpu_active(struct intel_display *display)
{
return display->parent->vgpu_active && display->parent->vgpu_active(display->drm);
diff --git a/drivers/gpu/drm/i915/display/intel_parent.h b/drivers/gpu/drm/i915/display/intel_parent.h
index 595d4148b8eb..cc4a58f63166 100644
--- a/drivers/gpu/drm/i915/display/intel_parent.h
+++ b/drivers/gpu/drm/i915/display/intel_parent.h
@@ -115,7 +115,7 @@ void intel_parent_pc8_block(struct intel_display *display);
void intel_parent_pc8_unblock(struct intel_display *display);
/* pcode */
-int intel_parent_pcode_read(struct intel_display *display, u32 mbox, u32 *val, u32 *val1);
+int intel_parent_pcode_read(struct intel_display *display, u32 mbox, u32 *val0, u32 *val1);
int intel_parent_pcode_write_timeout(struct intel_display *display, u32 mbox, u32 val, int timeout_ms);
int intel_parent_pcode_write(struct intel_display *display, u32 mbox, u32 val);
int intel_parent_pcode_request(struct intel_display *display, u32 mbox, u32 request,
@@ -155,6 +155,7 @@ int intel_parent_vlv_iosf_write(struct intel_display *display, enum vlv_iosf_sb_
/* generic */
bool intel_parent_has_auxccs(struct intel_display *display);
bool intel_parent_has_fenced_regions(struct intel_display *display);
+void intel_parent_transient_data_flush(struct intel_display *display);
bool intel_parent_vgpu_active(struct intel_display *display);
void intel_parent_fence_priority_display(struct intel_display *display, struct dma_fence *fence);
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 40e3d7095996..f490beb66629 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -1491,6 +1491,12 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay;
int psr_max_h = 0, psr_max_v = 0, max_bpp = 0;
+ if (crtc_state->vrr.cmrr.enable) {
+ drm_dbg_kms(display->drm,
+ "PSR2 cannot be enabled when CMRR is enabled\n");
+ return false;
+ }
+
if (!connector->dp.psr_caps.su_support || display->params.enable_psr == 1)
return false;
@@ -3840,6 +3846,7 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp)
struct intel_display *display = to_intel_display(intel_dp);
struct intel_psr *psr = &intel_dp->psr;
u8 status, error_status;
+ bool panel_replay_enabled;
const u8 errors = DP_PSR_RFB_STORAGE_ERROR |
DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR |
DP_PSR_LINK_CRC_ERROR;
@@ -3860,6 +3867,12 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp)
goto exit;
}
+ /*
+ * Save this before intel_psr_disable_locked() clears it; the error
+ * status is acknowledged to a different DPCD address depending on it.
+ */
+ panel_replay_enabled = psr->panel_replay_enabled;
+
if ((!psr->panel_replay_enabled && status == DP_PSR_SINK_INTERNAL_ERROR) ||
(error_status & errors)) {
intel_psr_disable_locked(intel_dp);
@@ -3885,7 +3898,10 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp)
"PSR_ERROR_STATUS unhandled errors %x\n",
error_status & ~errors);
/* clear status register */
- drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_ERROR_STATUS, error_status);
+ drm_dp_dpcd_writeb(&intel_dp->aux,
+ panel_replay_enabled ?
+ DP_PANEL_REPLAY_ERROR_STATUS : DP_PSR_ERROR_STATUS,
+ error_status);
if (!psr->panel_replay_enabled) {
psr_alpm_check(intel_dp);
diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c
index bf9df566630f..ce94ac689064 100644
--- a/drivers/gpu/drm/i915/display/intel_snps_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c
@@ -1816,11 +1816,10 @@ int intel_mpllb_calc_state(struct intel_crtc_state *crtc_state,
return -EINVAL;
}
-void intel_mpllb_enable(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state)
+void intel_mpllb_enable_phy(struct intel_encoder *encoder,
+ const struct intel_mpllb_state *pll_state)
{
struct intel_display *display = to_intel_display(encoder);
- const struct intel_mpllb_state *pll_state = &crtc_state->dpll_hw_state.mpllb;
enum phy phy = intel_encoder_to_phy(encoder);
intel_reg_t enable_reg = (phy <= PHY_D ?
DG2_PLL_ENABLE(phy) : MG_PLL_ENABLE(0));
@@ -1875,6 +1874,12 @@ void intel_mpllb_enable(struct intel_encoder *encoder,
*/
}
+void intel_mpllb_enable(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ intel_mpllb_enable_phy(encoder, &crtc_state->dpll_hw_state.mpllb);
+}
+
void intel_mpllb_disable(struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(encoder);
@@ -1977,52 +1982,3 @@ void intel_mpllb_readout_hw_state(struct intel_encoder *encoder,
*/
pll_state->mpllb_div &= ~SNPS_PHY_MPLLB_FORCE_EN;
}
-
-void intel_mpllb_state_verify(struct intel_atomic_state *state,
- struct intel_crtc *crtc)
-{
- struct intel_display *display = to_intel_display(state);
- const struct intel_crtc_state *new_crtc_state =
- intel_atomic_get_new_crtc_state(state, crtc);
- struct intel_mpllb_state mpllb_hw_state = {};
- const struct intel_mpllb_state *mpllb_sw_state = &new_crtc_state->dpll_hw_state.mpllb;
- struct intel_encoder *encoder;
-
- if (!display->platform.dg2)
- return;
-
- if (!new_crtc_state->hw.active)
- return;
-
- /* intel_get_crtc_new_encoder() only works for modeset/fastset commits */
- if (!intel_crtc_needs_modeset(new_crtc_state) &&
- !intel_crtc_needs_fastset(new_crtc_state))
- return;
-
- encoder = intel_get_crtc_new_encoder(state, new_crtc_state);
- intel_mpllb_readout_hw_state(encoder, &mpllb_hw_state);
-
-#define MPLLB_CHECK(__name) \
- INTEL_DISPLAY_STATE_WARN(display, mpllb_sw_state->__name != mpllb_hw_state.__name, \
- "[CRTC:%d:%s] mismatch in MPLLB: %s (expected 0x%08x, found 0x%08x)", \
- crtc->base.base.id, crtc->base.name, \
- __stringify(__name), \
- mpllb_sw_state->__name, mpllb_hw_state.__name)
-
- MPLLB_CHECK(mpllb_cp);
- MPLLB_CHECK(mpllb_div);
- MPLLB_CHECK(mpllb_div2);
- MPLLB_CHECK(mpllb_fracn1);
- MPLLB_CHECK(mpllb_fracn2);
- MPLLB_CHECK(mpllb_sscen);
- MPLLB_CHECK(mpllb_sscstep);
-
- /*
- * ref_control is handled by the hardware/firemware and never
- * programmed by the software, but the proper values are supplied
- * in the bspec for verification purposes.
- */
- MPLLB_CHECK(ref_control);
-
-#undef MPLLB_CHECK
-}
diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.h b/drivers/gpu/drm/i915/display/intel_snps_phy.h
index 7f96da22d028..2c7a5f2040f1 100644
--- a/drivers/gpu/drm/i915/display/intel_snps_phy.h
+++ b/drivers/gpu/drm/i915/display/intel_snps_phy.h
@@ -22,6 +22,8 @@ void intel_snps_phy_update_psr_power_state(struct intel_encoder *encoder,
int intel_mpllb_calc_state(struct intel_crtc_state *crtc_state,
struct intel_encoder *encoder);
+void intel_mpllb_enable_phy(struct intel_encoder *encoder,
+ const struct intel_mpllb_state *pll_state);
void intel_mpllb_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
void intel_mpllb_disable(struct intel_encoder *encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_tdf.h b/drivers/gpu/drm/i915/display/intel_tdf.h
deleted file mode 100644
index 0862c2bfd9cd..000000000000
--- a/drivers/gpu/drm/i915/display/intel_tdf.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2024 Intel Corporation
- */
-
-#ifndef __INTEL_TDF_H__
-#define __INTEL_TDF_H__
-
-/*
- * TDF (Transient-Data-Flush) is needed for Xe2+ where special L3:XD caching can
- * be enabled through various PAT index modes. Idea is to use this caching mode
- * when for example rendering onto the display surface, with the promise that
- * KMD will ensure transient cache entries are always flushed by the time we do
- * the display flip, since display engine is never coherent with CPU/GPU caches.
- */
-
-struct intel_display;
-
-#ifdef I915
-static inline void intel_td_flush(struct intel_display *display) {}
-#else
-void intel_td_flush(struct intel_display *display);
-#endif
-
-#endif
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
index 51e4f3309b8b..e36db1174440 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -4,10 +4,16 @@
*
*/
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+
+#include <drm/drm_atomic.h>
#include <drm/drm_print.h>
#include <drm/intel/step.h>
#include "intel_alpm.h"
+#include "intel_atomic.h"
#include "intel_cmtg.h"
#include "intel_crtc.h"
#include "intel_de.h"
@@ -23,9 +29,6 @@
#include "skl_prefill.h"
#include "skl_watermark.h"
-#define FIXED_POINT_PRECISION 100
-#define CMRR_PRECISION_TOLERANCE 10
-
/*
* Tunable parameters for DC Balance correction.
* These are captured based on experimentations.
@@ -187,69 +190,87 @@ int intel_vrr_vmax_vblank_start(const struct intel_crtc_state *crtc_state)
return intel_vrr_vmax_vtotal(crtc_state) - crtc_state->vrr.guardband;
}
-static bool
-is_cmrr_frac_required(struct intel_crtc_state *crtc_state)
+static bool intel_vrr_cmrr_possible(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
- int calculated_refresh_k, actual_refresh_k, pixel_clock_per_line;
- struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
-
- /* Avoid CMRR for now till we have VRR with fixed timings working */
- if (!HAS_CMRR(display) || true)
- return false;
-
- actual_refresh_k =
- drm_mode_vrefresh(adjusted_mode) * FIXED_POINT_PRECISION;
- pixel_clock_per_line =
- adjusted_mode->crtc_clock * 1000 / adjusted_mode->crtc_htotal;
- calculated_refresh_k =
- pixel_clock_per_line * FIXED_POINT_PRECISION / adjusted_mode->crtc_vtotal;
-
- if ((actual_refresh_k - calculated_refresh_k) < CMRR_PRECISION_TOLERANCE)
- return false;
- return true;
+ return HAS_CMRR(display) && intel_vrr_always_use_vrr_tg(display);
}
-static unsigned int
-cmrr_get_vtotal(struct intel_crtc_state *crtc_state, bool video_mode_required)
+static void
+intel_vrr_cmrr_compute_config(struct intel_crtc_state *crtc_state)
{
- int multiplier_m = 1, multiplier_n = 1, vtotal, desired_refresh_rate;
- u64 adjusted_pixel_rate;
+ struct intel_display *display = to_intel_display(crtc_state);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
+ u64 dividend;
+ u32 mode_rate_mhz;
+ u32 requested_rate_mhz = crtc->force_cmrr.numerator;
+ bool video_mode = crtc->force_cmrr.denominator != 1000;
+ int rr_multiplier = video_mode ? 1000 : 1;
+ int rr_divider = video_mode ? 1001 : 1;
+
+ if (!intel_vrr_cmrr_possible(crtc_state))
+ return;
- desired_refresh_rate = drm_mode_vrefresh(adjusted_mode);
+ /* No CMRR ratio configured through debugfs */
+ if (!requested_rate_mhz)
+ return;
- if (video_mode_required) {
- multiplier_m = 1001;
- multiplier_n = 1000;
+ /* Requested rate must match the mode's nominal (integer) refresh rate */
+ if (DIV_ROUND_CLOSEST(requested_rate_mhz, 1000) !=
+ drm_mode_vrefresh(adjusted_mode)) {
+ drm_dbg_kms(display->drm,
+ "[CRTC:%d:%s] CMRR requested %u.%03u Hz doesn't match mode %d Hz\n",
+ crtc->base.base.id, crtc->base.name,
+ requested_rate_mhz / 1000, requested_rate_mhz % 1000,
+ drm_mode_vrefresh(adjusted_mode));
+ return;
}
- crtc_state->cmrr.cmrr_n = mul_u32_u32(desired_refresh_rate * adjusted_mode->crtc_htotal,
- multiplier_n);
- vtotal = DIV_ROUND_UP_ULL(mul_u32_u32(adjusted_mode->crtc_clock * 1000, multiplier_n),
- crtc_state->cmrr.cmrr_n);
- adjusted_pixel_rate = mul_u32_u32(adjusted_mode->crtc_clock * 1000, multiplier_m);
- crtc_state->cmrr.cmrr_m = do_div(adjusted_pixel_rate, crtc_state->cmrr.cmrr_n);
+ /* Actual rate produced by the current timings, in milli-Hz */
+ mode_rate_mhz =
+ DIV_ROUND_CLOSEST_ULL((u64)adjusted_mode->crtc_clock * 1000 * 1000,
+ adjusted_mode->crtc_vtotal *
+ adjusted_mode->crtc_htotal);
- return vtotal;
-}
+ /*
+ * 1:1 request already satisfied by the mode -> CMRR not needed.
+ */
+ if (!video_mode && DIV_ROUND_CLOSEST(mode_rate_mhz, 10) ==
+ DIV_ROUND_CLOSEST(requested_rate_mhz, 10)) {
+ drm_dbg_kms(display->drm,
+ "[CRTC:%d:%s] %u.%03u Hz can be driven without CMRR\n",
+ crtc->base.base.id, crtc->base.name,
+ requested_rate_mhz / 1000, requested_rate_mhz % 1000);
+ return;
+ }
-static
-void intel_vrr_compute_cmrr_timings(struct intel_crtc_state *crtc_state)
-{
/*
- * TODO: Compute precise target refresh rate to determine
- * if video_mode_required should be true. Currently set to
- * false due to uncertainty about the precise target
- * refresh Rate.
+ * Let pixel_clock_hz = adjusted_mode->crtc_clock * 1000.
+ *
+ * cmrr_n = (requested_rate_mhz x htotal x rr_multiplier) / 1000
+ * cmrr_m = (pixel_clock_hz x rr_divider) % cmrr_n
+ *
+ * where requested_rate_mhz is the requested refresh rate in milli-Hz
+ * and rr_multiplier/rr_divider = 1000/1001 when the video timing
+ * is required, else 1/1. The integer vtotal term is tracked in SW
+ * (it is the programmed mode vtotal) while the fractional part
+ * represented by cmrr_m/cmrr_n is tracked in HW.
+ *
+ * TODO: Using the actual desired rate for cmrr_n in video
+ * mode produces more aggressive vtotal dithering than
+ * expected; revisit once the Bspec algorithm is clarified.
*/
- crtc_state->vrr.vmax = cmrr_get_vtotal(crtc_state, false);
- crtc_state->vrr.vmin = crtc_state->vrr.vmax;
- crtc_state->vrr.flipline = crtc_state->vrr.vmin;
+ crtc_state->vrr.cmrr.cmrr_n =
+ div64_u64((u64)requested_rate_mhz *
+ adjusted_mode->crtc_htotal * rr_multiplier, 1000);
+ dividend = (u64)adjusted_mode->crtc_clock * rr_divider * 1000;
+ adjusted_mode->crtc_vtotal = div64_u64_rem(dividend,
+ crtc_state->vrr.cmrr.cmrr_n,
+ &crtc_state->vrr.cmrr.cmrr_m);
- crtc_state->cmrr.enable = true;
- crtc_state->mode_flags |= I915_MODE_FLAG_VRR;
+ crtc_state->vrr.cmrr.enable = true;
}
static
@@ -325,6 +346,36 @@ int intel_vrr_fixed_rr_hw_flipline(const struct intel_crtc_state *crtc_state)
return intel_vrr_fixed_rr_hw_vtotal(crtc_state);
}
+static void
+intel_vrr_set_cmrr_timings(const struct intel_crtc_state *crtc_state,
+ enum transcoder transcoder)
+{
+ struct intel_display *display = to_intel_display(crtc_state);
+
+ if (!intel_vrr_cmrr_possible(crtc_state))
+ return;
+
+ intel_de_write(display, TRANS_CMRR_M_HI(display, transcoder),
+ upper_32_bits(crtc_state->vrr.cmrr.cmrr_m));
+ intel_de_write(display, TRANS_CMRR_M_LO(display, transcoder),
+ lower_32_bits(crtc_state->vrr.cmrr.cmrr_m));
+ intel_de_write(display, TRANS_CMRR_N_LO(display, transcoder),
+ lower_32_bits(crtc_state->vrr.cmrr.cmrr_n));
+ intel_de_write(display, TRANS_CMRR_N_HI(display, transcoder),
+ upper_32_bits(crtc_state->vrr.cmrr.cmrr_n));
+
+ /*
+ * On always-VRR-TG platforms the fastset path does not rewrite the
+ * whole TRANS_VRR_CTL, so RMW only the CMRR enable bit here. On a
+ * modeset the authoritative writes (intel_vrr_tg_enable(),
+ * intel_cmtg_set_vrr_ctl()) carry the same bit, so this stays
+ * consistent.
+ */
+ intel_de_rmw(display, TRANS_VRR_CTL(display, transcoder),
+ VRR_CTL_CMRR_ENABLE,
+ crtc_state->vrr.cmrr.enable ? VRR_CTL_CMRR_ENABLE : 0);
+}
+
void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state,
enum transcoder transcoder)
{
@@ -333,6 +384,8 @@ void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state,
if (!intel_vrr_possible(crtc_state))
return;
+ intel_vrr_set_cmrr_timings(crtc_state, transcoder);
+
intel_de_write(display, TRANS_VRR_VMIN(display, transcoder),
intel_vrr_fixed_rr_hw_vmin(crtc_state) - 1);
intel_de_write(display, TRANS_VRR_VMAX(display, transcoder),
@@ -425,8 +478,6 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state,
struct intel_display *display = to_intel_display(crtc_state);
struct intel_connector *connector =
to_intel_connector(conn_state->connector);
- struct intel_dp *intel_dp = intel_attached_dp(connector);
- bool is_edp = intel_dp_is_edp(intel_dp);
struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
int vmin, vmax;
@@ -460,12 +511,17 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state,
vmax = vmin;
}
- if (crtc_state->uapi.vrr_enabled && vmin < vmax)
+ if (crtc_state->uapi.vrr_enabled && vmin < vmax) {
intel_vrr_compute_vrr_timings(crtc_state, vmin, vmax);
- else if (is_cmrr_frac_required(crtc_state) && is_edp)
- intel_vrr_compute_cmrr_timings(crtc_state);
- else
+ } else {
+ /*
+ * CMRR is a fixed average Vtotal mode and is only computed on
+ * the fixed refresh rate path. It is generic across transcoders
+ * and gated on platform support and a valid debugfs ratio.
+ */
+ intel_vrr_cmrr_compute_config(crtc_state);
intel_vrr_compute_fixed_rr_timings(crtc_state);
+ }
if (HAS_AS_SDP(display)) {
crtc_state->vrr.vsync_start =
@@ -641,17 +697,6 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state)
return;
}
- if (crtc_state->cmrr.enable) {
- intel_de_write(display, TRANS_CMRR_M_HI(display, cpu_transcoder),
- upper_32_bits(crtc_state->cmrr.cmrr_m));
- intel_de_write(display, TRANS_CMRR_M_LO(display, cpu_transcoder),
- lower_32_bits(crtc_state->cmrr.cmrr_m));
- intel_de_write(display, TRANS_CMRR_N_HI(display, cpu_transcoder),
- upper_32_bits(crtc_state->cmrr.cmrr_n));
- intel_de_write(display, TRANS_CMRR_N_LO(display, cpu_transcoder),
- lower_32_bits(crtc_state->cmrr.cmrr_n));
- }
-
intel_vrr_set_fixed_rr_timings(crtc_state, cpu_transcoder);
intel_cmtg_set_vrr_timings(crtc_state);
@@ -917,8 +962,7 @@ intel_vrr_disable_dc_balancing(const struct intel_crtc_state *old_crtc_state)
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)
+static void intel_vrr_tg_enable(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
@@ -930,11 +974,12 @@ static void intel_vrr_tg_enable(const struct intel_crtc_state *crtc_state,
vrr_ctl = VRR_CTL_VRR_ENABLE | trans_vrr_ctl(crtc_state);
/*
- * FIXME this might be broken as bspec seems to imply that
- * even VRR_CTL_CMRR_ENABLE is armed by TRANS_CMRR_N_HI
- * when enabling CMRR (but not when disabling CMRR?).
+ * This full TRANS_VRR_CTL write is the authoritative one, so it must
+ * carry VRR_CTL_CMRR_ENABLE when CMRR is in use. Writing TRANS_CMRR_N_HI
+ * arms the bit in hardware, but this later write would otherwise clear
+ * it again.
*/
- if (cmrr_enable)
+ if (crtc_state->vrr.cmrr.enable)
vrr_ctl |= VRR_CTL_CMRR_ENABLE;
intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), vrr_ctl);
@@ -970,7 +1015,7 @@ void intel_vrr_enable(const struct intel_crtc_state *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);
+ intel_vrr_tg_enable(crtc_state);
}
void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state)
@@ -997,7 +1042,7 @@ void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state)
return;
if (intel_vrr_always_use_vrr_tg(display))
- intel_vrr_tg_enable(crtc_state, false);
+ intel_vrr_tg_enable(crtc_state);
}
void intel_vrr_transcoder_disable(const struct intel_crtc_state *old_crtc_state)
@@ -1066,13 +1111,13 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state)
trans_vrr_ctl = intel_de_read(display,
TRANS_VRR_CTL(display, cpu_transcoder));
- if (HAS_CMRR(display))
- crtc_state->cmrr.enable = (trans_vrr_ctl & VRR_CTL_CMRR_ENABLE);
+ if (intel_vrr_cmrr_possible(crtc_state))
+ crtc_state->vrr.cmrr.enable = (trans_vrr_ctl & VRR_CTL_CMRR_ENABLE);
- if (crtc_state->cmrr.enable) {
- crtc_state->cmrr.cmrr_n =
+ if (crtc_state->vrr.cmrr.enable) {
+ crtc_state->vrr.cmrr.cmrr_n =
intel_de_read64_2x32(display, TRANS_CMRR_N_LO(display, cpu_transcoder));
- crtc_state->cmrr.cmrr_m =
+ crtc_state->vrr.cmrr.cmrr_m =
intel_de_read64_2x32(display, TRANS_CMRR_M_LO(display, cpu_transcoder));
}
@@ -1132,11 +1177,6 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state)
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.
- * Need to keep this in mind while re-enabling CMRR.
- */
if (crtc_state->vrr.enable)
crtc_state->mode_flags |= I915_MODE_FLAG_VRR;
@@ -1231,3 +1271,186 @@ int intel_vrr_dcb_vmax_vblank_start_final(const struct intel_crtc_state *crtc_st
return intel_vrr_vblank_start(crtc_state, VRR_DCB_VMAX(tmp) + 1);
}
+
+static
+int intel_vrr_cmrr_parse_ratio(char *str, u32 *numerator, u32 *denominator)
+{
+ char *sep;
+ int ret;
+
+ /*
+ * Parse a "numerator/denominator" CMRR ratio string. The numerator
+ * is the requested refresh rate in milli-Hz (refresh rate in Hz * 1000)
+ * and the denominator selects the timing: 1000 for a 1:1 ratio
+ * (no video timing) or 1001 for the 1000/1001 video timing.
+ */
+
+ sep = strchr(str, '/');
+ if (!sep)
+ return -EINVAL;
+
+ *sep = '\0';
+
+ ret = kstrtou32(strim(str), 10, numerator);
+ if (ret)
+ return ret;
+
+ ret = kstrtou32(strim(sep + 1), 10, denominator);
+ if (ret)
+ return ret;
+ /*
+ * "0/0" clears any previously configured CMRR override.
+ * A zero numerator already means "CMRR not requested" in
+ * intel_vrr_cmrr_compute_config(), so just let it through.
+ */
+ if (*numerator == 0 && *denominator == 0)
+ return 0;
+
+ if (*numerator == 0)
+ return -EINVAL;
+
+ if (*denominator != 1000 && *denominator != 1001)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int intel_vrr_debugfs_target_rr_show(struct seq_file *m, void *data)
+{
+ struct intel_crtc *crtc = m->private;
+
+ seq_printf(m, "%u/%u\n", crtc->force_cmrr.numerator, crtc->force_cmrr.denominator);
+
+ return 0;
+}
+
+static int intel_vrr_debugfs_target_rr_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, intel_vrr_debugfs_target_rr_show, inode->i_private);
+}
+
+/*
+ * Force an internal commit on @crtc so that a CMRR ratio programmed
+ * via debugfs gets recomputed and latched into hardware.
+ *
+ * CMRR only alters the (average) vtotal. Depending on whether the
+ * computed vblank value (with LRR disabled) changes, this commit may or
+ * may not be downgraded to a fastset.
+ */
+static int intel_vrr_cmrr_commit_force(struct intel_crtc *crtc)
+{
+ struct intel_display *display = to_intel_display(crtc);
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_commit *state;
+ struct intel_crtc_state *crtc_state;
+ int ret = 0;
+
+ state = drm_atomic_commit_alloc(display->drm);
+ if (!state)
+ return -ENOMEM;
+
+ drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
+
+ state->acquire_ctx = &ctx;
+ to_intel_atomic_state(state)->internal = true;
+
+retry:
+ crtc_state = intel_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ ret = PTR_ERR(crtc_state);
+ goto out;
+ }
+
+ if (!crtc_state->hw.active)
+ goto out;
+
+ /* Mark mode as changed to trigger a pipe recompute + update() */
+ crtc_state->uapi.mode_changed = true;
+
+ ret = drm_atomic_commit(state);
+out:
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+ drm_atomic_commit_put(state);
+
+ return ret;
+}
+
+static ssize_t intel_vrr_debugfs_target_rr_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ struct seq_file *m = file->private_data;
+ struct intel_crtc *crtc = m->private;
+ u32 numerator, denominator;
+ u32 old_numerator, old_denominator;
+ char kbuf[32];
+ int ret;
+
+ if (len >= sizeof(kbuf))
+ return -EINVAL;
+
+ if (copy_from_user(kbuf, ubuf, len))
+ return -EFAULT;
+
+ kbuf[len] = '\0';
+
+ ret = intel_vrr_cmrr_parse_ratio(kbuf, &numerator, &denominator);
+ if (ret)
+ return ret;
+
+ if (crtc->force_cmrr.numerator == numerator &&
+ crtc->force_cmrr.denominator == denominator)
+ return len;
+
+ old_numerator = crtc->force_cmrr.numerator;
+ old_denominator = crtc->force_cmrr.denominator;
+
+ crtc->force_cmrr.numerator = numerator;
+ crtc->force_cmrr.denominator = denominator;
+
+ /*
+ * The debugfs value is a side channel that is not tracked by the atomic
+ * state, so kick an internal commit to recompute and latch the
+ * new CMRR parameters.
+ */
+ ret = intel_vrr_cmrr_commit_force(crtc);
+ if (ret) {
+ /*
+ * Restore the last known good ratio so that force_cmrr does not
+ * hold on to bad values, which would make all subsequent commits
+ * fail.
+ */
+ crtc->force_cmrr.numerator = old_numerator;
+ crtc->force_cmrr.denominator = old_denominator;
+ return ret;
+ }
+
+ return len;
+}
+
+static const struct file_operations intel_vrr_debugfs_target_rr_fops = {
+ .owner = THIS_MODULE,
+ .open = intel_vrr_debugfs_target_rr_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = intel_vrr_debugfs_target_rr_write,
+};
+
+void intel_vrr_crtc_debugfs_add(struct intel_crtc *crtc)
+{
+ struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
+
+ if (!intel_vrr_cmrr_possible(crtc_state))
+ return;
+
+ debugfs_create_file("intel_vrr_target_refresh_rate", 0600, crtc->base.debugfs_entry,
+ crtc, &intel_vrr_debugfs_target_rr_fops);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h b/drivers/gpu/drm/i915/display/intel_vrr.h
index 55e9c429f579..19c7990be1b2 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.h
+++ b/drivers/gpu/drm/i915/display/intel_vrr.h
@@ -56,4 +56,6 @@ int intel_vrr_dcb_vmax_vblank_start_next(const struct intel_crtc_state *crtc_sta
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);
+void intel_vrr_crtc_debugfs_add(struct intel_crtc *crtc);
+
#endif /* __INTEL_VRR_H__ */
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index 9f61867e2478..22dd0179863e 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -1706,7 +1706,7 @@ static int mailbox_write(struct intel_vgpu *vgpu, unsigned int offset,
{
u32 value = *(u32 *)p_data;
u32 cmd = value & 0xff;
- u32 *data0 = &vgpu_vreg_t(vgpu, GEN6_PCODE_DATA);
+ u32 *data0 = &vgpu_vreg_t(vgpu, GEN6_PCODE_DATA0);
switch (cmd) {
case GEN9_PCODE_READ_MEM_LATENCY:
diff --git a/drivers/gpu/drm/i915/i915_dpt.c b/drivers/gpu/drm/i915/i915_dpt.c
index fcd7cced771d..e01dc4de1788 100644
--- a/drivers/gpu/drm/i915/i915_dpt.c
+++ b/drivers/gpu/drm/i915/i915_dpt.c
@@ -6,7 +6,6 @@
#include <drm/drm_print.h>
#include <drm/intel/display_parent_interface.h>
-#include "display/intel_display_core.h"
#include "gem/i915_gem_domain.h"
#include "gem/i915_gem_internal.h"
#include "gem/i915_gem_lmem.h"
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 64e906380131..d873072b7a92 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -697,7 +697,7 @@
#define EDRAM_WAYS_IDX(cap) (((cap) >> 5) & 0x7)
#define EDRAM_SETS_IDX(cap) (((cap) >> 8) & 0x3)
-#define GEN6_PCODE_DATA _MMIO(0x138128)
+#define GEN6_PCODE_DATA0 _MMIO(0x138128)
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16
#define GEN6_PCODE_DATA1 _MMIO(0x13812C)
diff --git a/drivers/gpu/drm/i915/intel_clock_gating.c b/drivers/gpu/drm/i915/intel_clock_gating.c
index 86bdeb20f427..c5c4441f3a61 100644
--- a/drivers/gpu/drm/i915/intel_clock_gating.c
+++ b/drivers/gpu/drm/i915/intel_clock_gating.c
@@ -57,12 +57,12 @@ static void bxt_init_clock_gating(struct drm_i915_private *i915)
*/
intel_uncore_rmw(&i915->uncore, GEN8_UCGCTL6, 0, GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ);
- intel_display_bxt_init_clock_gating(i915->display);
+ intel_display_init_clock_gating(i915->display);
}
static void glk_init_clock_gating(struct drm_i915_private *i915)
{
- intel_display_glk_init_clock_gating(i915->display);
+ intel_display_init_clock_gating(i915->display);
}
static void ilk_init_clock_gating(struct drm_i915_private *i915)
@@ -73,7 +73,7 @@ static void ilk_init_clock_gating(struct drm_i915_private *i915)
intel_uncore_write(&i915->uncore, PCH_3DCGDIS1,
VFMUNIT_CLOCK_GATE_DISABLE);
- intel_display_ilk_init_clock_gating(i915->display);
+ intel_display_init_clock_gating(i915->display);
intel_pch_init_clock_gating(i915->display);
}
@@ -90,7 +90,7 @@ static void gen6_check_mch_setup(struct drm_i915_private *i915)
static void gen6_init_clock_gating(struct drm_i915_private *i915)
{
- intel_display_gen6_init_clock_gating(i915->display);
+ intel_display_init_clock_gating(i915->display);
intel_uncore_write(&i915->uncore, GEN6_UCGCTL1,
intel_uncore_read(&i915->uncore, GEN6_UCGCTL1) |
@@ -170,7 +170,7 @@ static void cfl_init_clock_gating(struct drm_i915_private *i915)
/* WAC6entrylatency:cfl */
intel_uncore_rmw(&i915->uncore, FBC_LLC_READ_CTRL, 0, FBC_LLC_FULLY_OPEN);
- intel_display_cfl_init_clock_gating(i915->display);
+ intel_display_init_clock_gating(i915->display);
}
static void kbl_init_clock_gating(struct drm_i915_private *i915)
@@ -188,7 +188,7 @@ static void kbl_init_clock_gating(struct drm_i915_private *i915)
intel_uncore_rmw(&i915->uncore, GEN6_UCGCTL1,
0, GEN6_GAMUNIT_CLOCK_GATE_DISABLE);
- intel_display_kbl_init_clock_gating(i915->display);
+ intel_display_init_clock_gating(i915->display);
}
static void skl_init_clock_gating(struct drm_i915_private *i915)
@@ -200,18 +200,16 @@ static void skl_init_clock_gating(struct drm_i915_private *i915)
/* WAC6entrylatency:skl */
intel_uncore_rmw(&i915->uncore, FBC_LLC_READ_CTRL, 0, FBC_LLC_FULLY_OPEN);
- intel_display_skl_init_clock_gating(i915->display);
+ intel_display_init_clock_gating(i915->display);
}
static void bdw_init_clock_gating(struct drm_i915_private *i915)
{
- intel_display_bdw_clock_gating_disable_fbcq(i915->display);
+ intel_display_init_clock_gating(i915->display);
/* WaSwitchSolVfFArbitrationPriority:bdw */
intel_uncore_rmw(&i915->uncore, GAM_ECOCHK, 0, HSW_ECOCHK_ARB_PRIO_SOL);
- intel_display_bdw_clock_gating_vblank_in_srd(i915->display);
-
/* WaVSRefCountFullforceMissDisable:bdw */
/* WaDSRefCountFullforceMissDisable:bdw */
intel_uncore_rmw(&i915->uncore, GEN7_FF_THREAD_MODE,
@@ -226,8 +224,6 @@ static void bdw_init_clock_gating(struct drm_i915_private *i915)
/* WaProgramL3SqcReg1Default:bdw */
gen8_set_l3sqc_credits(i915, 30, 2);
- intel_display_bdw_clock_gating_kvm_notif(i915->display);
-
intel_pch_init_clock_gating(i915->display);
/* WaDisableDopClockGating:bdw
@@ -240,7 +236,7 @@ static void bdw_init_clock_gating(struct drm_i915_private *i915)
static void hsw_init_clock_gating(struct drm_i915_private *i915)
{
- intel_display_hsw_init_clock_gating(i915->display);
+ intel_display_init_clock_gating(i915->display);
/* This is required by WaCatErrorRejectionIssue:hsw */
intel_uncore_rmw(&i915->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
@@ -256,7 +252,7 @@ static void ivb_init_clock_gating(struct drm_i915_private *i915)
{
struct intel_display *display = i915->display;
- intel_display_ivb_init_clock_gating(display);
+ intel_display_init_clock_gating(display);
/* WaDisableBackToBackFlipFix:ivb */
intel_uncore_write(&i915->uncore, IVB_CHICKEN3,
@@ -285,8 +281,6 @@ static void ivb_init_clock_gating(struct drm_i915_private *i915)
intel_uncore_rmw(&i915->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
0, GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
- intel_display_disable_trickle_feed(display);
-
intel_uncore_rmw(&i915->uncore, GEN6_MBCUNIT_SNPCR, GEN6_MBC_SNPCR_MASK,
GEN6_MBC_SNPCR_MED);
@@ -362,7 +356,7 @@ static void g4x_init_clock_gating(struct drm_i915_private *i915)
GS_UNIT_CLOCK_GATE_DISABLE |
CL_UNIT_CLOCK_GATE_DISABLE);
intel_uncore_write(&i915->uncore, RAMCLK_GATE_D, 0);
- intel_display_g4x_init_clock_gating(i915->display);
+ intel_display_init_clock_gating(i915->display);
}
static void i965gm_init_clock_gating(struct drm_i915_private *i915)
@@ -371,7 +365,7 @@ static void i965gm_init_clock_gating(struct drm_i915_private *i915)
intel_uncore_write(uncore, RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
intel_uncore_write(uncore, RENCLK_GATE_D2, 0);
- intel_display_i965gm_init_clock_gating(i915->display);
+ intel_display_init_clock_gating(i915->display);
intel_uncore_write(uncore, RAMCLK_GATE_D, 0);
intel_uncore_write16(uncore, DEUC, 0);
intel_uncore_write(uncore,
diff --git a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c
index de118fae0a49..25b72b20e709 100644
--- a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c
+++ b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c
@@ -611,7 +611,7 @@ static int iterate_generic_mmio(struct intel_gvt_mmio_table_iter *iter)
MMIO_D(GEN6_UCGCTL1);
MMIO_D(GEN6_UCGCTL2);
MMIO_F(_MMIO(0x4f000), 0x90);
- MMIO_D(GEN6_PCODE_DATA);
+ MMIO_D(GEN6_PCODE_DATA0);
MMIO_D(_MMIO(0x13812c));
MMIO_D(GEN7_ERR_INT);
MMIO_D(HSW_EDRAM_CAP);
diff --git a/drivers/gpu/drm/i915/intel_pcode.c b/drivers/gpu/drm/i915/intel_pcode.c
index c07d48fc1b35..1c9d1f413757 100644
--- a/drivers/gpu/drm/i915/intel_pcode.c
+++ b/drivers/gpu/drm/i915/intel_pcode.c
@@ -58,7 +58,7 @@ static int gen7_check_mailbox_status(u32 mbox)
}
static int __snb_pcode_rw(struct intel_uncore *uncore, u32 mbox,
- u32 *val, u32 *val1,
+ u32 *val0, u32 *val1,
int fast_timeout_us, int slow_timeout_ms,
bool is_read)
{
@@ -73,7 +73,7 @@ static int __snb_pcode_rw(struct intel_uncore *uncore, u32 mbox,
if (intel_uncore_read_fw(uncore, GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY)
return -EAGAIN;
- intel_uncore_write_fw(uncore, GEN6_PCODE_DATA, *val);
+ intel_uncore_write_fw(uncore, GEN6_PCODE_DATA0, *val0);
intel_uncore_write_fw(uncore, GEN6_PCODE_DATA1, val1 ? *val1 : 0);
intel_uncore_write_fw(uncore,
GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox);
@@ -87,7 +87,7 @@ static int __snb_pcode_rw(struct intel_uncore *uncore, u32 mbox,
return -ETIMEDOUT;
if (is_read)
- *val = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA);
+ *val0 = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA0);
if (is_read && val1)
*val1 = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA1);
@@ -97,12 +97,12 @@ static int __snb_pcode_rw(struct intel_uncore *uncore, u32 mbox,
return gen6_check_mailbox_status(mbox);
}
-int snb_pcode_read(struct intel_uncore *uncore, u32 mbox, u32 *val, u32 *val1)
+int snb_pcode_read(struct intel_uncore *uncore, u32 mbox, u32 *val0, u32 *val1)
{
int err;
mutex_lock(&uncore->i915->sb_lock);
- err = __snb_pcode_rw(uncore, mbox, val, val1, 500, 20, true);
+ err = __snb_pcode_rw(uncore, mbox, val0, val1, 500, 20, true);
mutex_unlock(&uncore->i915->sb_lock);
if (err) {
@@ -278,11 +278,11 @@ int snb_pcode_write_p(struct intel_uncore *uncore, u32 mbcmd, u32 p1, u32 p2, u3
return err;
}
-static int intel_pcode_read(struct drm_device *drm, u32 mbox, u32 *val, u32 *val1)
+static int intel_pcode_read(struct drm_device *drm, u32 mbox, u32 *val0, u32 *val1)
{
struct drm_i915_private *i915 = to_i915(drm);
- return snb_pcode_read(&i915->uncore, mbox, val, val1);
+ return snb_pcode_read(&i915->uncore, mbox, val0, val1);
}
static int intel_pcode_write_timeout(struct drm_device *drm, u32 mbox, u32 val, int timeout_ms)
diff --git a/drivers/gpu/drm/i915/intel_pcode.h b/drivers/gpu/drm/i915/intel_pcode.h
index 19795ea8172e..deecc64bc1b3 100644
--- a/drivers/gpu/drm/i915/intel_pcode.h
+++ b/drivers/gpu/drm/i915/intel_pcode.h
@@ -11,7 +11,7 @@
struct drm_device;
struct intel_uncore;
-int snb_pcode_read(struct intel_uncore *uncore, u32 mbox, u32 *val, u32 *val1);
+int snb_pcode_read(struct intel_uncore *uncore, u32 mbox, u32 *val0, u32 *val1);
int snb_pcode_write_timeout(struct intel_uncore *uncore, u32 mbox, u32 val, int timeout_ms);
#define snb_pcode_write(uncore, mbox, val) \
snb_pcode_write_timeout((uncore), (mbox), (val), 1)
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index adc2de37e768..67b8b5477639 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -231,8 +231,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
display/xe_hdcp_gsc.o \
display/xe_initial_plane.o \
display/xe_panic.o \
- display/xe_stolen.o \
- display/xe_tdf.o
+ display/xe_stolen.o
# Display code shared with i915
xe-$(CONFIG_DRM_XE_DISPLAY) += \
diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c
index 8da4c457a4a0..7b25c0814674 100644
--- a/drivers/gpu/drm/xe/display/xe_display.c
+++ b/drivers/gpu/drm/xe/display/xe_display.c
@@ -18,7 +18,6 @@
#include <uapi/drm/xe_drm.h>
#include "intel_acpi.h"
-#include "intel_audio.h"
#include "intel_display.h"
#include "intel_display_core.h"
#include "intel_display_device.h"
@@ -29,7 +28,6 @@
#include "intel_dmc_wl.h"
#include "intel_dp.h"
#include "intel_fbdev.h"
-#include "intel_hdcp.h"
#include "intel_hotplug.h"
#include "intel_opregion.h"
#include "skl_watermark.h"
@@ -37,6 +35,7 @@
#include "xe_display_bo.h"
#include "xe_display_pcode.h"
#include "xe_display_rpm.h"
+#include "xe_display_wa.h"
#include "xe_dsb_buffer.h"
#include "xe_fb_pin.h"
#include "xe_frontbuffer.h"
@@ -129,9 +128,6 @@ static void xe_display_fini(void *arg)
struct xe_device *xe = arg;
struct intel_display *display = xe->display;
- intel_hpd_poll_fini(display);
- intel_hdcp_component_fini(display);
- intel_audio_deinit(display);
intel_display_driver_remove(display);
}
@@ -446,6 +442,20 @@ static bool has_auxccs(struct drm_device *drm)
return xe->info.platform == XE_ALDERLAKE_P;
}
+/*
+ * TDF (Transient-Data-Flush) is needed for Xe2+ where special L3:XD caching can
+ * be enabled through various PAT index modes. Idea is to use this caching mode
+ * when for example rendering onto the display surface, with the promise that
+ * KMD will ensure transient cache entries are always flushed by the time we do
+ * the display flip, since display engine is never coherent with CPU/GPU caches.
+ */
+static void transient_data_flush(struct drm_device *drm)
+{
+ struct xe_device *xe = to_xe_device(drm);
+
+ xe_device_td_flush(xe);
+}
+
static const struct intel_display_parent_interface parent = {
.bo = &xe_display_bo_interface,
.dsb = &xe_display_dsb_interface,
@@ -458,7 +468,9 @@ static const struct intel_display_parent_interface parent = {
.pcode = &xe_display_pcode_interface,
.rpm = &xe_display_rpm_interface,
.stolen = &xe_display_stolen_interface,
+ .wa = &xe_display_wa_interface,
.has_auxccs = has_auxccs,
+ .transient_data_flush = transient_data_flush,
};
/**
diff --git a/drivers/gpu/drm/xe/display/xe_display_rpm.c b/drivers/gpu/drm/xe/display/xe_display_rpm.c
index b3db40035499..548b503aa024 100644
--- a/drivers/gpu/drm/xe/display/xe_display_rpm.c
+++ b/drivers/gpu/drm/xe/display/xe_display_rpm.c
@@ -3,8 +3,6 @@
#include <drm/intel/display_parent_interface.h>
-#include "intel_display_core.h"
-#include "intel_display_rpm.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_pm.h"
diff --git a/drivers/gpu/drm/xe/display/xe_display_wa.c b/drivers/gpu/drm/xe/display/xe_display_wa.c
index 2aa1b8c03411..46e41e8a3304 100644
--- a/drivers/gpu/drm/xe/display/xe_display_wa.c
+++ b/drivers/gpu/drm/xe/display/xe_display_wa.c
@@ -3,17 +3,22 @@
* Copyright © 2024 Intel Corporation
*/
-#include "intel_display_core.h"
-#include "intel_display_wa.h"
+#include <drm/intel/display_parent_interface.h>
+
#include "xe_device.h"
+#include "xe_display_wa.h"
#include "xe_wa.h"
#include <generated/xe_wa_oob.h>
-bool intel_display_needs_wa_16023588340(struct intel_display *display)
+static bool intel_display_needs_wa_16023588340(struct drm_device *drm)
{
- struct xe_device *xe = to_xe_device(display->drm);
+ struct xe_device *xe = to_xe_device(drm);
struct xe_gt *wa_gt = xe_root_mmio_gt(xe);
return wa_gt && XE_GT_WA(wa_gt, 16023588340);
}
+
+const struct intel_display_wa_interface xe_display_wa_interface = {
+ .wa_16023588340 = intel_display_needs_wa_16023588340,
+};
diff --git a/drivers/gpu/drm/xe/display/xe_display_wa.h b/drivers/gpu/drm/xe/display/xe_display_wa.h
new file mode 100644
index 000000000000..0262b463916d
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/xe_display_wa.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2026 Intel Corporation */
+
+#ifndef __XE_DISPLAY_WA_H__
+#define __XE_DISPLAY_WA_H__
+
+extern const struct intel_display_wa_interface xe_display_wa_interface;
+
+#endif
diff --git a/drivers/gpu/drm/xe/display/xe_tdf.c b/drivers/gpu/drm/xe/display/xe_tdf.c
deleted file mode 100644
index 78bda4c47874..000000000000
--- a/drivers/gpu/drm/xe/display/xe_tdf.c
+++ /dev/null
@@ -1,15 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2024 Intel Corporation
- */
-
-#include "intel_display_core.h"
-#include "intel_tdf.h"
-#include "xe_device.h"
-
-void intel_td_flush(struct intel_display *display)
-{
- struct xe_device *xe = to_xe_device(display->drm);
-
- xe_device_td_flush(xe);
-}
diff --git a/include/drm/intel/display_parent_interface.h b/include/drm/intel/display_parent_interface.h
index de395df9ca30..5e44c022d1ae 100644
--- a/include/drm/intel/display_parent_interface.h
+++ b/include/drm/intel/display_parent_interface.h
@@ -179,7 +179,7 @@ struct intel_display_pc8_interface {
};
struct intel_display_pcode_interface {
- int (*read)(struct drm_device *drm, u32 mbox, u32 *val, u32 *val1);
+ int (*read)(struct drm_device *drm, u32 mbox, u32 *val0, u32 *val1);
int (*write)(struct drm_device *drm, u32 mbox, u32 val, int timeout_ms);
int (*request)(struct drm_device *drm, u32 mbox, u32 request,
u32 reply_mask, u32 reply, int timeout_base_ms);
@@ -230,6 +230,10 @@ struct intel_display_vlv_iosf_interface {
int (*write)(struct drm_device *drm, enum vlv_iosf_sb_unit unit, u32 addr, u32 val);
};
+struct intel_display_wa_interface {
+ bool (*wa_16023588340)(struct drm_device *drm);
+};
+
/**
* struct intel_display_parent_interface - services parent driver provides to display
*
@@ -291,6 +295,12 @@ struct intel_display_parent_interface {
/** @vlv_iosf: VLV IOSF sideband. Optional. */
const struct intel_display_vlv_iosf_interface *vlv_iosf;
+ /**
+ * @wa: Display workarounds query. Use only for workarounds that require
+ * information only available to the parent driver. Optional.
+ */
+ const struct intel_display_wa_interface *wa;
+
/* Generic independent functions */
struct {
/** @fence_priority_display: Set display priority. Optional. */
@@ -302,6 +312,9 @@ struct intel_display_parent_interface {
/** @has_fenced_regions: Support legacy fencing? Optional. */
bool (*has_fenced_regions)(struct drm_device *drm);
+ /** @transient_data_flush: Transient data flush. Optional. */
+ void (*transient_data_flush)(struct drm_device *drm);
+
/** @vgpu_active: Is vGPU active? Optional. */
bool (*vgpu_active)(struct drm_device *drm);
};