From 889ff8dd4679ae7b608f79ebbbd511a3b8b315c1 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:18 +0200 Subject: drm/i915/dsc: Track the detaild DSC slice configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a way to track the detailed DSC pipes-per-line, streams-per-pipe, slices-per-stream configuration instead of the current streams-per-pipe and slices-per-line value. This way describes the slice configuration in a clearer way, for instance providing a 2 pipes-per-line x 2 streams-per-pipe x 2 slices-per-stream = 8 slices-per-line view, instead of the current, coarser 2 streams-per-pipe, 8 slices-per-line view, the former better reflecting that each DSC stream engine has 2 slices. This also let's optimizing the configuration in a simpler/clearer way, for instance using 1 stream x 2 slices, or 1 stream x 4 slices instead of the current 2 stream x 1 slice, or 2 streams x 2 slices configuration (so that 1 DSC stream engine can be powered off in each pipe). Follow-up changes will convert the current slices-per-line computation logic to compute instead the above detailed slice configuration. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-2-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display_types.h | 5 +++++ drivers/gpu/drm/i915/display/intel_vdsc.c | 5 +++++ drivers/gpu/drm/i915/display/intel_vdsc.h | 2 ++ 3 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 113e43bc1f6d..7d1654f60094 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1333,6 +1333,11 @@ struct intel_crtc_state { bool compression_enabled_on_link; bool compression_enable; int num_streams; + struct intel_dsc_slice_config { + int pipes_per_line; + int streams_per_pipe; + int slices_per_stream; + } slice_config; /* Compressed Bpp in U6.4 format (first 4 bits for fractional part) */ u16 compressed_bpp_x16; u8 slice_count; diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 5493082f30a7..f8e4b2aa6c17 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -35,6 +35,11 @@ bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state) return true; } +int intel_dsc_line_slice_count(const struct intel_dsc_slice_config *config) +{ + return config->pipes_per_line * config->streams_per_pipe * config->slices_per_stream; +} + static bool is_pipe_dsc(struct intel_crtc *crtc, enum transcoder cpu_transcoder) { struct intel_display *display = to_intel_display(crtc); diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.h b/drivers/gpu/drm/i915/display/intel_vdsc.h index 99f64ac54b27..e61116d5297c 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.h +++ b/drivers/gpu/drm/i915/display/intel_vdsc.h @@ -13,9 +13,11 @@ struct drm_printer; enum transcoder; struct intel_crtc; struct intel_crtc_state; +struct intel_dsc_slice_config; struct intel_encoder; bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state); +int intel_dsc_line_slice_count(const struct intel_dsc_slice_config *config); void intel_uncompressed_joiner_enable(const struct intel_crtc_state *crtc_state); void intel_dsc_enable(const struct intel_crtc_state *crtc_state); void intel_dsc_disable(const struct intel_crtc_state *crtc_state); -- cgit v1.2.3 From 2b8f5b5cb29786f03cd1805aad42da41ad7c51a4 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:19 +0200 Subject: drm/i915/dsc: Track the DSC stream count in the DSC slice config state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the tracking for the DSC stream count from intel_crtc_state::dsc.num_streams to intel_crtc_state::dsc.slice_config.streams_per_pipe. While at it add a TODO comment to read out the full DSC configuration from HW including the pipes-per-line and slices-per-stream values. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-3-imre.deak@intel.com --- drivers/gpu/drm/i915/display/icl_dsi.c | 4 ++-- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_display_types.h | 1 - drivers/gpu/drm/i915/display/intel_dp.c | 6 +++--- drivers/gpu/drm/i915/display/intel_vdsc.c | 11 ++++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index dac781f54661..5b64e8d6e838 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1626,9 +1626,9 @@ static int gen11_dsi_dsc_compute_config(struct intel_encoder *encoder, /* FIXME: split only when necessary */ if (crtc_state->dsc.slice_count > 1) - crtc_state->dsc.num_streams = 2; + crtc_state->dsc.slice_config.streams_per_pipe = 2; else - crtc_state->dsc.num_streams = 1; + crtc_state->dsc.slice_config.streams_per_pipe = 1; /* FIXME: initialize from VBT */ vdsc_cfg->rc_model_size = DSC_RC_MODEL_SIZE_CONST; diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 81b3a6692ca2..7491e00e3858 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5459,7 +5459,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(dsc.config.nsl_bpg_offset); PIPE_CONF_CHECK_BOOL(dsc.compression_enable); - PIPE_CONF_CHECK_I(dsc.num_streams); + PIPE_CONF_CHECK_I(dsc.slice_config.streams_per_pipe); PIPE_CONF_CHECK_I(dsc.compressed_bpp_x16); PIPE_CONF_CHECK_BOOL(splitter.enable); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 7d1654f60094..f223cabb185a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1332,7 +1332,6 @@ struct intel_crtc_state { /* Only used for state computation, not read out from the HW. */ bool compression_enabled_on_link; bool compression_enable; - int num_streams; struct intel_dsc_slice_config { int pipes_per_line; int streams_per_pipe; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7e022c47e8ac..396c25d15af5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2418,11 +2418,11 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, */ if (pipe_config->joiner_pipes && num_joined_pipes == 4 && pipe_config->dsc.slice_count == 12) - pipe_config->dsc.num_streams = 3; + pipe_config->dsc.slice_config.streams_per_pipe = 3; else if (pipe_config->joiner_pipes || pipe_config->dsc.slice_count > 1) - pipe_config->dsc.num_streams = 2; + pipe_config->dsc.slice_config.streams_per_pipe = 2; else - pipe_config->dsc.num_streams = 1; + pipe_config->dsc.slice_config.streams_per_pipe = 1; ret = intel_dp_dsc_compute_params(connector, pipe_config); if (ret < 0) { diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index f8e4b2aa6c17..4a3d505338cb 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -421,7 +421,7 @@ intel_dsc_power_domain(struct intel_crtc *crtc, enum transcoder cpu_transcoder) static int intel_dsc_get_vdsc_per_pipe(const struct intel_crtc_state *crtc_state) { - return crtc_state->dsc.num_streams; + return crtc_state->dsc.slice_config.streams_per_pipe; } int intel_dsc_get_num_vdsc_instances(const struct intel_crtc_state *crtc_state) @@ -1023,12 +1023,13 @@ void intel_dsc_get_config(struct intel_crtc_state *crtc_state) if (!crtc_state->dsc.compression_enable) goto out; + /* TODO: Read out slice_config.pipes_per_line/slices_per_stream as well */ if (dss_ctl1 & JOINER_ENABLE && dss_ctl2 & (VDSC2_ENABLE | SMALL_JOINER_CONFIG_3_ENGINES)) - crtc_state->dsc.num_streams = 3; + crtc_state->dsc.slice_config.streams_per_pipe = 3; else if (dss_ctl1 & JOINER_ENABLE && dss_ctl2 & VDSC1_ENABLE) - crtc_state->dsc.num_streams = 2; + crtc_state->dsc.slice_config.streams_per_pipe = 2; else - crtc_state->dsc.num_streams = 1; + crtc_state->dsc.slice_config.streams_per_pipe = 1; intel_dsc_get_pps_config(crtc_state); out: @@ -1042,7 +1043,7 @@ static void intel_vdsc_dump_state(struct drm_printer *p, int indent, "dsc-dss: compressed-bpp:" FXP_Q4_FMT ", slice-count: %d, num_streams: %d\n", FXP_Q4_ARGS(crtc_state->dsc.compressed_bpp_x16), crtc_state->dsc.slice_count, - crtc_state->dsc.num_streams); + crtc_state->dsc.slice_config.streams_per_pipe); } void intel_vdsc_state_dump(struct drm_printer *p, int indent, -- cgit v1.2.3 From 611cadd5c02b04ac461a5dddf3070ce4c1094829 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:20 +0200 Subject: drm/i915/dsi: Move initialization of DSI DSC streams-per-pipe to fill_dsc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the initialization of the DSI DSC streams-per-pipe value to fill_dsc() next to where the corresponding (per-line) slice_count value is initialized. This allows converting the initialization to use the detailed slice configuration state in follow-up changes. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-4-imre.deak@intel.com --- drivers/gpu/drm/i915/display/icl_dsi.c | 6 ------ drivers/gpu/drm/i915/display/intel_bios.c | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 5b64e8d6e838..c8e0333706c1 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1624,12 +1624,6 @@ static int gen11_dsi_dsc_compute_config(struct intel_encoder *encoder, if (crtc_state->pipe_bpp < 8 * 3) return -EINVAL; - /* FIXME: split only when necessary */ - if (crtc_state->dsc.slice_count > 1) - crtc_state->dsc.slice_config.streams_per_pipe = 2; - else - crtc_state->dsc.slice_config.streams_per_pipe = 1; - /* FIXME: initialize from VBT */ vdsc_cfg->rc_model_size = DSC_RC_MODEL_SIZE_CONST; diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index ae0b922d5bc3..9b4428472831 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -3575,10 +3575,14 @@ static void fill_dsc(struct intel_crtc_state *crtc_state, * throughput etc. into account. * * Also, per spec DSI supports 1, 2, 3 or 4 horizontal slices. + * + * FIXME: split only when necessary */ if (dsc->slices_per_line & BIT(2)) { + crtc_state->dsc.slice_config.streams_per_pipe = 2; crtc_state->dsc.slice_count = 4; } else if (dsc->slices_per_line & BIT(1)) { + crtc_state->dsc.slice_config.streams_per_pipe = 2; crtc_state->dsc.slice_count = 2; } else { /* FIXME */ @@ -3586,6 +3590,7 @@ static void fill_dsc(struct intel_crtc_state *crtc_state, drm_dbg_kms(display->drm, "VBT: Unsupported DSC slice count for DSI\n"); + crtc_state->dsc.slice_config.streams_per_pipe = 1; crtc_state->dsc.slice_count = 1; } -- cgit v1.2.3 From 57152a502ed2a4d8f0470321c9d482a76daa3cb9 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:21 +0200 Subject: drm/i915/dsi: Track the detailed DSC slice configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tracking for the DSI DSC pipes-per-line and slices-per-stream value in the slice config state and compute the current slices-per-line value using this slice config state. The slices-per-line value used atm will be removed by a follow-up change after converting all the places using it to use the detailed slice config instead. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-5-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 9b4428472831..8fcfdb2e1c74 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -41,6 +41,7 @@ #include "intel_display_utils.h" #include "intel_gmbus.h" #include "intel_rom.h" +#include "intel_vdsc.h" #define _INTEL_BIOS_PRIVATE #include "intel_vbt_defs.h" @@ -3578,12 +3579,14 @@ static void fill_dsc(struct intel_crtc_state *crtc_state, * * FIXME: split only when necessary */ + crtc_state->dsc.slice_config.pipes_per_line = 1; + if (dsc->slices_per_line & BIT(2)) { crtc_state->dsc.slice_config.streams_per_pipe = 2; - crtc_state->dsc.slice_count = 4; + crtc_state->dsc.slice_config.slices_per_stream = 2; } else if (dsc->slices_per_line & BIT(1)) { crtc_state->dsc.slice_config.streams_per_pipe = 2; - crtc_state->dsc.slice_count = 2; + crtc_state->dsc.slice_config.slices_per_stream = 1; } else { /* FIXME */ if (!(dsc->slices_per_line & BIT(0))) @@ -3591,9 +3594,11 @@ static void fill_dsc(struct intel_crtc_state *crtc_state, "VBT: Unsupported DSC slice count for DSI\n"); crtc_state->dsc.slice_config.streams_per_pipe = 1; - crtc_state->dsc.slice_count = 1; + crtc_state->dsc.slice_config.slices_per_stream = 1; } + crtc_state->dsc.slice_count = intel_dsc_line_slice_count(&crtc_state->dsc.slice_config); + if (crtc_state->hw.adjusted_mode.crtc_hdisplay % crtc_state->dsc.slice_count != 0) drm_dbg_kms(display->drm, -- cgit v1.2.3 From fd1e610ca21861f582e57e26e5e5628d01c6c36d Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:22 +0200 Subject: drm/i915/dp: Track the detailed DSC slice configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tracking for the DP DSC pipes-per-line and slices-per-stream value in the slice config state and compute the current slices-per-line (slice_count) value using this slice config. The slices-per-line value used atm will be removed by a follow-up change after converting all the places using it to use the slice config instead. For now the slices-per-stream value is calculated based on the slices-per-line value (slice_count) calculated by the drm_dp_dsc_sink_max_slice_count() / intel_dp_dsc_get_slice_count() functions. In a follow-up change these functions will be converted to calculate the slices-per-stream value directly, along with the detailed slice configuration. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-6-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 396c25d15af5..3b62d16403f2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2357,6 +2357,7 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, &pipe_config->hw.adjusted_mode; int num_joined_pipes = intel_crtc_num_joined_pipes(pipe_config); bool is_mst = intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST); + int slices_per_line; int ret; /* @@ -2384,30 +2385,26 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, /* Calculate Slice count */ if (intel_dp_is_edp(intel_dp)) { - pipe_config->dsc.slice_count = + slices_per_line = drm_dp_dsc_sink_max_slice_count(connector->dp.dsc_dpcd, true); - if (!pipe_config->dsc.slice_count) { + if (!slices_per_line) { drm_dbg_kms(display->drm, "Unsupported Slice Count %d\n", - pipe_config->dsc.slice_count); + slices_per_line); return -EINVAL; } } else { - u8 dsc_dp_slice_count; - - dsc_dp_slice_count = + slices_per_line = intel_dp_dsc_get_slice_count(connector, adjusted_mode->crtc_clock, adjusted_mode->crtc_hdisplay, num_joined_pipes); - if (!dsc_dp_slice_count) { + if (!slices_per_line) { drm_dbg_kms(display->drm, "Compressed Slice Count not supported\n"); return -EINVAL; } - - pipe_config->dsc.slice_count = dsc_dp_slice_count; } /* * VDSC engine operates at 1 Pixel per clock, so if peak pixel rate @@ -2416,14 +2413,27 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, * In case of Ultrajoiner along with 12 slices we need to use 3 * VDSC instances. */ + pipe_config->dsc.slice_config.pipes_per_line = num_joined_pipes; + if (pipe_config->joiner_pipes && num_joined_pipes == 4 && - pipe_config->dsc.slice_count == 12) + slices_per_line == 12) pipe_config->dsc.slice_config.streams_per_pipe = 3; - else if (pipe_config->joiner_pipes || pipe_config->dsc.slice_count > 1) + else if (pipe_config->joiner_pipes || slices_per_line > 1) pipe_config->dsc.slice_config.streams_per_pipe = 2; else pipe_config->dsc.slice_config.streams_per_pipe = 1; + pipe_config->dsc.slice_config.slices_per_stream = + slices_per_line / + pipe_config->dsc.slice_config.pipes_per_line / + pipe_config->dsc.slice_config.streams_per_pipe; + + pipe_config->dsc.slice_count = + intel_dsc_line_slice_count(&pipe_config->dsc.slice_config); + + drm_WARN_ON(display->drm, + pipe_config->dsc.slice_count != slices_per_line); + ret = intel_dp_dsc_compute_params(connector, pipe_config); if (ret < 0) { drm_dbg_kms(display->drm, -- cgit v1.2.3 From e941eb107847f7a910e309799cdde49493b857cf Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:23 +0200 Subject: drm/i915/dsc: Switch to using intel_dsc_line_slice_count() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By now all the places are updated to track the DSC slice configuration in intel_crtc_state::dsc.slice_config, so calculate the slices-per-line value using that config, instead of using intel_crtc_state::dsc.slice_count caching the same value and remove the cached slice_count. v2: Rebase on latest drm-tip, converting another user of dsc.slice_count in intel_vdsc_min_cdclk(). Cc: Ankit Nautiyal Reviewed-by: Jouni Högander # v1 Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-7-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 6 ++---- drivers/gpu/drm/i915/display/intel_display_types.h | 1 - drivers/gpu/drm/i915/display/intel_dp.c | 11 +++++------ drivers/gpu/drm/i915/display/intel_vdsc.c | 9 +++++---- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 8fcfdb2e1c74..a007fcf6e1a8 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -3597,14 +3597,12 @@ static void fill_dsc(struct intel_crtc_state *crtc_state, crtc_state->dsc.slice_config.slices_per_stream = 1; } - crtc_state->dsc.slice_count = intel_dsc_line_slice_count(&crtc_state->dsc.slice_config); - if (crtc_state->hw.adjusted_mode.crtc_hdisplay % - crtc_state->dsc.slice_count != 0) + intel_dsc_line_slice_count(&crtc_state->dsc.slice_config) != 0) drm_dbg_kms(display->drm, "VBT: DSC hdisplay %d not divisible by slice count %d\n", crtc_state->hw.adjusted_mode.crtc_hdisplay, - crtc_state->dsc.slice_count); + intel_dsc_line_slice_count(&crtc_state->dsc.slice_config)); /* * The VBT rc_buffer_block_size and rc_buffer_size definitions diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index f223cabb185a..c7a8e475cb22 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1339,7 +1339,6 @@ struct intel_crtc_state { } slice_config; /* Compressed Bpp in U6.4 format (first 4 bits for fractional part) */ u16 compressed_bpp_x16; - u8 slice_count; struct drm_dsc_config config; } dsc; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 3b62d16403f2..3a12156cd6e5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2032,12 +2032,14 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp, } else { unsigned long bw_overhead_flags = pipe_config->fec_enable ? DRM_DP_BW_OVERHEAD_FEC : 0; + int line_slice_count = + intel_dsc_line_slice_count(&pipe_config->dsc.slice_config); if (!is_bw_sufficient_for_dsc_config(intel_dp, link_rate, lane_count, adjusted_mode->crtc_clock, adjusted_mode->hdisplay, - pipe_config->dsc.slice_count, + line_slice_count, dsc_bpp_x16, bw_overhead_flags)) continue; @@ -2428,11 +2430,8 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->dsc.slice_config.pipes_per_line / pipe_config->dsc.slice_config.streams_per_pipe; - pipe_config->dsc.slice_count = - intel_dsc_line_slice_count(&pipe_config->dsc.slice_config); - drm_WARN_ON(display->drm, - pipe_config->dsc.slice_count != slices_per_line); + intel_dsc_line_slice_count(&pipe_config->dsc.slice_config) != slices_per_line); ret = intel_dp_dsc_compute_params(connector, pipe_config); if (ret < 0) { @@ -2450,7 +2449,7 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, "Compressed Bpp = " FXP_Q4_FMT " Slice Count = %d\n", pipe_config->pipe_bpp, FXP_Q4_ARGS(pipe_config->dsc.compressed_bpp_x16), - pipe_config->dsc.slice_count); + intel_dsc_line_slice_count(&pipe_config->dsc.slice_config)); return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 4a3d505338cb..d213947103b5 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -283,8 +283,9 @@ int intel_dsc_compute_params(struct intel_crtc_state *pipe_config) int ret; vdsc_cfg->pic_width = pipe_config->hw.adjusted_mode.crtc_hdisplay; - vdsc_cfg->slice_width = DIV_ROUND_UP(vdsc_cfg->pic_width, - pipe_config->dsc.slice_count); + vdsc_cfg->slice_width = + DIV_ROUND_UP(vdsc_cfg->pic_width, + intel_dsc_line_slice_count(&pipe_config->dsc.slice_config)); err = intel_dsc_slice_dimensions_valid(pipe_config, vdsc_cfg); @@ -1042,7 +1043,7 @@ static void intel_vdsc_dump_state(struct drm_printer *p, int indent, drm_printf_indent(p, indent, "dsc-dss: compressed-bpp:" FXP_Q4_FMT ", slice-count: %d, num_streams: %d\n", FXP_Q4_ARGS(crtc_state->dsc.compressed_bpp_x16), - crtc_state->dsc.slice_count, + intel_dsc_line_slice_count(&crtc_state->dsc.slice_config), crtc_state->dsc.slice_config.streams_per_pipe); } @@ -1078,7 +1079,7 @@ int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state) struct intel_display *display = to_intel_display(crtc_state); int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state); int htotal = crtc_state->hw.adjusted_mode.crtc_htotal; - int dsc_slices = crtc_state->dsc.slice_count; + int dsc_slices = intel_dsc_line_slice_count(&crtc_state->dsc.slice_config); int pixel_rate; int min_cdclk; -- cgit v1.2.3 From 15f908bce5d90fcfbc0599e426530cc10e9dfef3 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:24 +0200 Subject: drm/i915/dp: Factor out intel_dp_dsc_min_slice_count() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Factor out intel_dp_dsc_min_slice_count() for making intel_dp_dsc_get_slice_count() more readable and also to prepare for a follow-up change unifying the eDP and DP slice count/config computation. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-8-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 3a12156cd6e5..4455d0a2e59c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -959,14 +959,11 @@ u32 get_max_compressed_bpp_with_joiner(struct intel_display *display, return max_bpp; } -u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, - int mode_clock, int mode_hdisplay, - int num_joined_pipes) +static int intel_dp_dsc_min_slice_count(const struct intel_connector *connector, + int mode_clock, int mode_hdisplay) { struct intel_display *display = to_intel_display(connector); - u32 sink_slice_count_mask = - drm_dp_dsc_sink_slice_count_mask(connector->dp.dsc_dpcd, false); - u8 min_slice_count, i; + u8 min_slice_count; int max_slice_width; int tp_rgb_yuv444; int tp_yuv422_420; @@ -1025,6 +1022,20 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, DIV_ROUND_UP(mode_hdisplay, max_slice_width)); + return min_slice_count; +} + +u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, + int mode_clock, int mode_hdisplay, + int num_joined_pipes) +{ + struct intel_display *display = to_intel_display(connector); + int min_slice_count = + intel_dp_dsc_min_slice_count(connector, mode_clock, mode_hdisplay); + u32 sink_slice_count_mask = + drm_dp_dsc_sink_slice_count_mask(connector->dp.dsc_dpcd, false); + int i; + /* Find the closest match to the valid slice count values */ for (i = 0; i < ARRAY_SIZE(valid_dsc_slicecount); i++) { u8 test_slice_count = valid_dsc_slicecount[i] * num_joined_pipes; -- cgit v1.2.3 From 856428d1ce352b926d2eb026490503ec39424ac8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:25 +0200 Subject: drm/i915/dp: Use int for DSC slice count variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no reason to use the more specific u8 type for slice count variables, use the more generic int type instead. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-9-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 4455d0a2e59c..bd35a2ba3042 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -963,7 +963,7 @@ static int intel_dp_dsc_min_slice_count(const struct intel_connector *connector, int mode_clock, int mode_hdisplay) { struct intel_display *display = to_intel_display(connector); - u8 min_slice_count; + int min_slice_count; int max_slice_width; int tp_rgb_yuv444; int tp_yuv422_420; @@ -1008,7 +1008,7 @@ static int intel_dp_dsc_min_slice_count(const struct intel_connector *connector, * slice and VDSC engine, whenever we approach close enough to max CDCLK */ if (mode_clock >= ((display->cdclk.max_cdclk_freq * 85) / 100)) - min_slice_count = max_t(u8, min_slice_count, 2); + min_slice_count = max(min_slice_count, 2); max_slice_width = drm_dp_dsc_sink_max_slice_width(connector->dp.dsc_dpcd); if (max_slice_width < DP_DSC_MIN_SLICE_WIDTH_VALUE) { @@ -1018,9 +1018,8 @@ static int intel_dp_dsc_min_slice_count(const struct intel_connector *connector, return 0; } /* Also take into account max slice width */ - min_slice_count = max_t(u8, min_slice_count, - DIV_ROUND_UP(mode_hdisplay, - max_slice_width)); + min_slice_count = max(min_slice_count, + DIV_ROUND_UP(mode_hdisplay, max_slice_width)); return min_slice_count; } @@ -1038,7 +1037,7 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, /* Find the closest match to the valid slice count values */ for (i = 0; i < ARRAY_SIZE(valid_dsc_slicecount); i++) { - u8 test_slice_count = valid_dsc_slicecount[i] * num_joined_pipes; + int test_slice_count = valid_dsc_slicecount[i] * num_joined_pipes; /* * 3 DSC Slices per pipe need 3 DSC engines, which is supported only -- cgit v1.2.3 From 0e6d7b6e502158d6a12725471d57450dcc0b3326 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:26 +0200 Subject: drm/i915/dp: Rename test_slice_count to slices_per_line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename test_slice_count to slices_per_line for clarity. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-10-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index bd35a2ba3042..57abc13a02d2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1037,7 +1037,7 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, /* Find the closest match to the valid slice count values */ for (i = 0; i < ARRAY_SIZE(valid_dsc_slicecount); i++) { - int test_slice_count = valid_dsc_slicecount[i] * num_joined_pipes; + int slices_per_line = valid_dsc_slicecount[i] * num_joined_pipes; /* * 3 DSC Slices per pipe need 3 DSC engines, which is supported only @@ -1047,7 +1047,7 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, (!HAS_DSC_3ENGINES(display) || num_joined_pipes != 4)) continue; - if (!(drm_dp_dsc_slice_count_to_mask(test_slice_count) & + if (!(drm_dp_dsc_slice_count_to_mask(slices_per_line) & sink_slice_count_mask)) continue; @@ -1059,11 +1059,11 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, if (num_joined_pipes > 1 && valid_dsc_slicecount[i] < 2) continue; - if (mode_hdisplay % test_slice_count) + if (mode_hdisplay % slices_per_line) continue; - if (min_slice_count <= test_slice_count) - return test_slice_count; + if (min_slice_count <= slices_per_line) + return slices_per_line; } /* Print slice count 1,2,4,..24 if bit#0,1,3,..23 is set in the mask. */ -- cgit v1.2.3 From da833bb4baf58a8c817818a064bc354429a8c091 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:27 +0200 Subject: drm/i915/dp: Simplify the DSC slice config loop's slices-per-pipe iteration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the slice config loop in intel_dp_dsc_get_slice_count(), using the loop iterator as the slices-per-pipe value directly, instead of looking up the same value from an array. While at it move the code comment about the slice configuration closer to where the configuration is determined and clarify it a bit. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-11-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 57abc13a02d2..eff4ea998a94 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -107,20 +107,6 @@ /* Constants for DP DSC configurations */ static const u8 valid_dsc_bpp[] = {6, 8, 10, 12, 15}; -/* - * With Single pipe configuration, HW is capable of supporting maximum of: - * 2 slices per line for ICL, BMG - * 4 slices per line for other platforms. - * For now consider a max of 2 slices per line, which works for all platforms. - * With this we can have max of 4 DSC Slices per pipe. - * - * For higher resolutions where 12 slice support is required with - * ultrajoiner, only then each pipe can support 3 slices. - * - * #TODO Split this better to use 4 slices/dsc engine where supported. - */ -static const u8 valid_dsc_slicecount[] = {1, 2, 3, 4}; - /** * intel_dp_is_edp - is the given port attached to an eDP panel (either CPU or PCH) * @intel_dp: DP struct @@ -1033,17 +1019,24 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, intel_dp_dsc_min_slice_count(connector, mode_clock, mode_hdisplay); u32 sink_slice_count_mask = drm_dp_dsc_sink_slice_count_mask(connector->dp.dsc_dpcd, false); - int i; + int slices_per_pipe; - /* Find the closest match to the valid slice count values */ - for (i = 0; i < ARRAY_SIZE(valid_dsc_slicecount); i++) { - int slices_per_line = valid_dsc_slicecount[i] * num_joined_pipes; + /* + * Find the closest match to the valid slice count values + * + * Max HW DSC-per-pipe x slice-per-DSC (= slice-per-pipe) capability: + * ICL: 2x2 + * BMG: 2x2, or for ultrajoined 4 pipes: 3x1 + * TGL+: 2x4 (TODO: Add support for this) + */ + for (slices_per_pipe = 1; slices_per_pipe <= 4; slices_per_pipe++) { + int slices_per_line = slices_per_pipe * num_joined_pipes; /* * 3 DSC Slices per pipe need 3 DSC engines, which is supported only * with Ultrajoiner only for some platforms. */ - if (valid_dsc_slicecount[i] == 3 && + if (slices_per_pipe == 3 && (!HAS_DSC_3ENGINES(display) || num_joined_pipes != 4)) continue; @@ -1056,7 +1049,7 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, * So there should be at least 2 dsc slices per pipe, * whenever bigjoiner is enabled. */ - if (num_joined_pipes > 1 && valid_dsc_slicecount[i] < 2) + if (num_joined_pipes > 1 && slices_per_pipe < 2) continue; if (mode_hdisplay % slices_per_line) -- cgit v1.2.3 From 91f0a9497414443b708e84e60b3813ff119f2444 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:28 +0200 Subject: drm/i915/dsc: Add intel_dsc_get_slice_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add intel_dsc_get_slice_config() and move the logic to select a given slice configuration to that function from the configuration loop in intel_dp_dsc_get_slice_count(). The same functionality can be used by other outputs like DSI as well, done as a follow-up. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-12-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 22 +++++---------- drivers/gpu/drm/i915/display/intel_vdsc.c | 47 +++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_vdsc.h | 4 +++ 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index eff4ea998a94..1d6009b99497 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1030,28 +1030,20 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, * TGL+: 2x4 (TODO: Add support for this) */ for (slices_per_pipe = 1; slices_per_pipe <= 4; slices_per_pipe++) { - int slices_per_line = slices_per_pipe * num_joined_pipes; + struct intel_dsc_slice_config config; + int slices_per_line; - /* - * 3 DSC Slices per pipe need 3 DSC engines, which is supported only - * with Ultrajoiner only for some platforms. - */ - if (slices_per_pipe == 3 && - (!HAS_DSC_3ENGINES(display) || num_joined_pipes != 4)) + if (!intel_dsc_get_slice_config(display, + num_joined_pipes, slices_per_pipe, + &config)) continue; + slices_per_line = intel_dsc_line_slice_count(&config); + if (!(drm_dp_dsc_slice_count_to_mask(slices_per_line) & sink_slice_count_mask)) continue; - /* - * Bigjoiner needs small joiner to be enabled. - * So there should be at least 2 dsc slices per pipe, - * whenever bigjoiner is enabled. - */ - if (num_joined_pipes > 1 && slices_per_pipe < 2) - continue; - if (mode_hdisplay % slices_per_line) continue; diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index d213947103b5..642a89270d8e 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -40,6 +40,53 @@ int intel_dsc_line_slice_count(const struct intel_dsc_slice_config *config) return config->pipes_per_line * config->streams_per_pipe * config->slices_per_stream; } +bool intel_dsc_get_slice_config(struct intel_display *display, + int pipes_per_line, int slices_per_pipe, + struct intel_dsc_slice_config *config) +{ + int streams_per_pipe; + + /* TODO: Add support for 8 slices per pipe on TGL+. */ + switch (slices_per_pipe) { + case 3: + /* + * 3 DSC Slices per pipe need 3 DSC engines, which is supported only + * with Ultrajoiner only for some platforms. + */ + if (!HAS_DSC_3ENGINES(display) || pipes_per_line != 4) + return false; + + streams_per_pipe = 3; + break; + case 4: + /* TODO: Consider using 1 DSC engine stream x 4 slices instead. */ + case 2: + /* TODO: Consider using 1 DSC engine stream x 2 slices instead. */ + streams_per_pipe = 2; + break; + case 1: + /* + * Bigjoiner needs small joiner to be enabled. + * So there should be at least 2 dsc slices per pipe, + * whenever bigjoiner is enabled. + */ + if (pipes_per_line > 1) + return false; + + streams_per_pipe = 1; + break; + default: + MISSING_CASE(slices_per_pipe); + return false; + } + + config->pipes_per_line = pipes_per_line; + config->streams_per_pipe = streams_per_pipe; + config->slices_per_stream = slices_per_pipe / streams_per_pipe; + + return true; +} + static bool is_pipe_dsc(struct intel_crtc *crtc, enum transcoder cpu_transcoder) { struct intel_display *display = to_intel_display(crtc); diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.h b/drivers/gpu/drm/i915/display/intel_vdsc.h index e61116d5297c..aeb17670307b 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.h +++ b/drivers/gpu/drm/i915/display/intel_vdsc.h @@ -13,11 +13,15 @@ struct drm_printer; enum transcoder; struct intel_crtc; struct intel_crtc_state; +struct intel_display; struct intel_dsc_slice_config; struct intel_encoder; bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state); int intel_dsc_line_slice_count(const struct intel_dsc_slice_config *config); +bool intel_dsc_get_slice_config(struct intel_display *display, + int num_joined_pipes, int slice_per_pipe, + struct intel_dsc_slice_config *config); void intel_uncompressed_joiner_enable(const struct intel_crtc_state *crtc_state); void intel_dsc_enable(const struct intel_crtc_state *crtc_state); void intel_dsc_disable(const struct intel_crtc_state *crtc_state); -- cgit v1.2.3 From ba9f0bbecdc462ebf361f65f62842a1e85c8baa8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:29 +0200 Subject: drm/i915/dsi: Use intel_dsc_get_slice_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use intel_dsc_get_slice_config() for DSI to compute the slice configuration based on the slices-per-line sink capability, instead of open-coding the same. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-13-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index a007fcf6e1a8..2afc99a39429 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -3545,12 +3545,13 @@ bool intel_bios_is_dsi_present(struct intel_display *display, return false; } -static void fill_dsc(struct intel_crtc_state *crtc_state, +static bool fill_dsc(struct intel_crtc_state *crtc_state, struct dsc_compression_parameters_entry *dsc, int dsc_max_bpc) { struct intel_display *display = to_intel_display(crtc_state); struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; + int slices_per_line; int bpc = 8; vdsc_cfg->dsc_version_major = dsc->version_major; @@ -3579,24 +3580,24 @@ static void fill_dsc(struct intel_crtc_state *crtc_state, * * FIXME: split only when necessary */ - crtc_state->dsc.slice_config.pipes_per_line = 1; - if (dsc->slices_per_line & BIT(2)) { - crtc_state->dsc.slice_config.streams_per_pipe = 2; - crtc_state->dsc.slice_config.slices_per_stream = 2; + slices_per_line = 4; } else if (dsc->slices_per_line & BIT(1)) { - crtc_state->dsc.slice_config.streams_per_pipe = 2; - crtc_state->dsc.slice_config.slices_per_stream = 1; + slices_per_line = 2; } else { /* FIXME */ if (!(dsc->slices_per_line & BIT(0))) drm_dbg_kms(display->drm, "VBT: Unsupported DSC slice count for DSI\n"); - crtc_state->dsc.slice_config.streams_per_pipe = 1; - crtc_state->dsc.slice_config.slices_per_stream = 1; + slices_per_line = 1; } + if (drm_WARN_ON(display->drm, + !intel_dsc_get_slice_config(display, 1, slices_per_line, + &crtc_state->dsc.slice_config))) + return false; + if (crtc_state->hw.adjusted_mode.crtc_hdisplay % intel_dsc_line_slice_count(&crtc_state->dsc.slice_config) != 0) drm_dbg_kms(display->drm, @@ -3617,6 +3618,8 @@ static void fill_dsc(struct intel_crtc_state *crtc_state, vdsc_cfg->block_pred_enable = dsc->block_prediction_enable; vdsc_cfg->slice_height = dsc->slice_height; + + return true; } /* FIXME: initially DSI specific */ @@ -3637,9 +3640,7 @@ bool intel_bios_get_dsc_params(struct intel_encoder *encoder, if (!devdata->dsc) return false; - fill_dsc(crtc_state, devdata->dsc, dsc_max_bpc); - - return true; + return fill_dsc(crtc_state, devdata->dsc, dsc_max_bpc); } } -- cgit v1.2.3 From 088d06bb17b024866401a20484017cd172ead3d8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:30 +0200 Subject: drm/i915/dp: Unify DP and eDP slice count computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify the DP and eDP slices-per-line computation. Atm eDP simply returns the maximum slices-per-line value supported by the sink, but using the same helper function for both cases still makes sense, since a follow-up change will compute the detailed slice config for both cases. Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-14-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 50 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 1d6009b99497..2c50e380fb39 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -949,11 +949,20 @@ static int intel_dp_dsc_min_slice_count(const struct intel_connector *connector, int mode_clock, int mode_hdisplay) { struct intel_display *display = to_intel_display(connector); + bool is_edp = + connector->base.connector_type == DRM_MODE_CONNECTOR_eDP; int min_slice_count; int max_slice_width; int tp_rgb_yuv444; int tp_yuv422_420; + /* + * TODO: allow using less than the maximum number of slices + * supported by the eDP sink, to allow using fewer DSC engines. + */ + if (is_edp) + return drm_dp_dsc_sink_max_slice_count(connector->dp.dsc_dpcd, true); + /* * TODO: Use the throughput value specific to the actual RGB/YUV * format of the output. @@ -1017,8 +1026,10 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, struct intel_display *display = to_intel_display(connector); int min_slice_count = intel_dp_dsc_min_slice_count(connector, mode_clock, mode_hdisplay); + bool is_edp = + connector->base.connector_type == DRM_MODE_CONNECTOR_eDP; u32 sink_slice_count_mask = - drm_dp_dsc_sink_slice_count_mask(connector->dp.dsc_dpcd, false); + drm_dp_dsc_sink_slice_count_mask(connector->dp.dsc_dpcd, is_edp); int slices_per_pipe; /* @@ -1471,9 +1482,13 @@ intel_dp_mode_valid(struct drm_connector *_connector, if (intel_dp_is_edp(intel_dp)) { dsc_max_compressed_bpp = drm_edp_dsc_sink_output_bpp(connector->dp.dsc_dpcd) >> 4; + dsc_slice_count = - drm_dp_dsc_sink_max_slice_count(connector->dp.dsc_dpcd, - true); + intel_dp_dsc_get_slice_count(connector, + target_clock, + mode->hdisplay, + num_joined_pipes); + dsc = dsc_max_compressed_bpp && dsc_slice_count; } else if (drm_dp_sink_supports_fec(connector->dp.fec_capability)) { unsigned long bw_overhead_flags = 0; @@ -2381,28 +2396,13 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, } /* Calculate Slice count */ - if (intel_dp_is_edp(intel_dp)) { - slices_per_line = - drm_dp_dsc_sink_max_slice_count(connector->dp.dsc_dpcd, - true); - if (!slices_per_line) { - drm_dbg_kms(display->drm, - "Unsupported Slice Count %d\n", - slices_per_line); - return -EINVAL; - } - } else { - slices_per_line = - intel_dp_dsc_get_slice_count(connector, - adjusted_mode->crtc_clock, - adjusted_mode->crtc_hdisplay, - num_joined_pipes); - if (!slices_per_line) { - drm_dbg_kms(display->drm, - "Compressed Slice Count not supported\n"); - return -EINVAL; - } - } + slices_per_line = intel_dp_dsc_get_slice_count(connector, + adjusted_mode->crtc_clock, + adjusted_mode->crtc_hdisplay, + num_joined_pipes); + if (!slices_per_line) + return -EINVAL; + /* * VDSC engine operates at 1 Pixel per clock, so if peak pixel rate * is greater than the maximum Cdclock and if slice count is even -- cgit v1.2.3 From 54cf7900c6eff4832a349806bef85e0e123aa626 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:31 +0200 Subject: drm/i915/dp: Add intel_dp_dsc_get_slice_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add intel_dp_dsc_get_slice_config() to compute the detailed slice configuration and determine the slices-per-line value (returned by intel_dp_dsc_get_slice_count()) using this function. v2: Fix incorrectly returning false from intel_dp_dsc_min_slice_count() due to rebase fail. (Jouni) Cc: Jouni Högander Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-15-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2c50e380fb39..0ea9c4e3b7d3 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1019,9 +1019,11 @@ static int intel_dp_dsc_min_slice_count(const struct intel_connector *connector, return min_slice_count; } -u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, - int mode_clock, int mode_hdisplay, - int num_joined_pipes) +static bool +intel_dp_dsc_get_slice_config(const struct intel_connector *connector, + int mode_clock, int mode_hdisplay, + int num_joined_pipes, + struct intel_dsc_slice_config *config_ret) { struct intel_display *display = to_intel_display(connector); int min_slice_count = @@ -1058,8 +1060,11 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, if (mode_hdisplay % slices_per_line) continue; - if (min_slice_count <= slices_per_line) - return slices_per_line; + if (min_slice_count <= slices_per_line) { + *config_ret = config; + + return true; + } } /* Print slice count 1,2,4,..24 if bit#0,1,3,..23 is set in the mask. */ @@ -1070,7 +1075,21 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, min_slice_count, (int)BITS_PER_TYPE(sink_slice_count_mask), &sink_slice_count_mask); - return 0; + return false; +} + +u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, + int mode_clock, int mode_hdisplay, + int num_joined_pipes) +{ + struct intel_dsc_slice_config config; + + if (!intel_dp_dsc_get_slice_config(connector, + mode_clock, mode_hdisplay, + num_joined_pipes, &config)) + return 0; + + return intel_dsc_line_slice_count(&config); } static bool source_can_output(struct intel_dp *intel_dp, -- cgit v1.2.3 From 4d636e0fc26b90be9c56961d8a631f26dcedf4a4 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Jan 2026 18:22:32 +0200 Subject: drm/i915/dp: Use intel_dp_dsc_get_slice_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify things by computing the detailed slice configuration using intel_dp_dsc_get_slice_config(), instead of open-coding the same. While at it add a TODO comment to intel_dp_dsc_compute_config() to explore if it's worth increasing the number of VDSC stream engines used, in order to reduce the minimum CDCLK required. v2: Add a TODO comment to intel_dp_dsc_compute_config() to explore if it's worth increasing the number of slices in order to use a lower CDCLK. (Jouni) Reviewed-by: Jouni Högander Signed-off-by: Imre Deak Link: https://patch.msgid.link/20260114162232.92731-16-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 41 ++++++++------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 0ea9c4e3b7d3..053443eea9d5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1041,6 +1041,12 @@ intel_dp_dsc_get_slice_config(const struct intel_connector *connector, * ICL: 2x2 * BMG: 2x2, or for ultrajoined 4 pipes: 3x1 * TGL+: 2x4 (TODO: Add support for this) + * + * TODO: Explore if it's worth increasing the number of slices (from 1 + * to 2 or 3), so that multiple VDSC engines can be used, thus + * reducing the minimum CDCLK requirement, which in turn is determined + * by the 1 pixel per clock VDSC engine throughput in + * intel_vdsc_min_cdclk(). */ for (slices_per_pipe = 1; slices_per_pipe <= 4; slices_per_pipe++) { struct intel_dsc_slice_config config; @@ -2388,7 +2394,6 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, &pipe_config->hw.adjusted_mode; int num_joined_pipes = intel_crtc_num_joined_pipes(pipe_config); bool is_mst = intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST); - int slices_per_line; int ret; /* @@ -2414,39 +2419,11 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, } } - /* Calculate Slice count */ - slices_per_line = intel_dp_dsc_get_slice_count(connector, - adjusted_mode->crtc_clock, - adjusted_mode->crtc_hdisplay, - num_joined_pipes); - if (!slices_per_line) + if (!intel_dp_dsc_get_slice_config(connector, adjusted_mode->crtc_clock, + adjusted_mode->crtc_hdisplay, num_joined_pipes, + &pipe_config->dsc.slice_config)) return -EINVAL; - /* - * VDSC engine operates at 1 Pixel per clock, so if peak pixel rate - * is greater than the maximum Cdclock and if slice count is even - * then we need to use 2 VDSC instances. - * In case of Ultrajoiner along with 12 slices we need to use 3 - * VDSC instances. - */ - pipe_config->dsc.slice_config.pipes_per_line = num_joined_pipes; - - if (pipe_config->joiner_pipes && num_joined_pipes == 4 && - slices_per_line == 12) - pipe_config->dsc.slice_config.streams_per_pipe = 3; - else if (pipe_config->joiner_pipes || slices_per_line > 1) - pipe_config->dsc.slice_config.streams_per_pipe = 2; - else - pipe_config->dsc.slice_config.streams_per_pipe = 1; - - pipe_config->dsc.slice_config.slices_per_stream = - slices_per_line / - pipe_config->dsc.slice_config.pipes_per_line / - pipe_config->dsc.slice_config.streams_per_pipe; - - drm_WARN_ON(display->drm, - intel_dsc_line_slice_count(&pipe_config->dsc.slice_config) != slices_per_line); - ret = intel_dp_dsc_compute_params(connector, pipe_config); if (ret < 0) { drm_dbg_kms(display->drm, -- cgit v1.2.3 From c5a52cd04e24f0ae53fda26f74ab027b8c548e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20H=C3=B6gander?= Date: Thu, 15 Jan 2026 09:00:39 +0200 Subject: drm/i915/psr: Don't enable Panel Replay on sink if globally disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With some panels informing support for Panel Replay we are observing problems if having Panel Replay enable bit set on sink when forced to use PSR instead of Panel Replay. Avoid these problems by not setting Panel Replay enable bit in sink when Panel Replay is globally disabled during link training. I.e. disabled by module parameter. The enable bit is still set when disabling Panel Replay via debugfs interface. Added note comment about this. Fixes: 68f3a505b367 ("drm/i915/psr: Enable Panel Replay on sink always when it's supported") Cc: Mika Kahola Cc: Jani Nikula Cc: Rodrigo Vivi Cc: # v6.15+ Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://patch.msgid.link/20260115070039.368965-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 91f4ac86c7ad..62208ffc5101 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -842,7 +842,12 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp, void intel_psr_panel_replay_enable_sink(struct intel_dp *intel_dp) { - if (CAN_PANEL_REPLAY(intel_dp)) + /* + * NOTE: We might want to trigger mode set when + * disabling/enabling Panel Replay via debugfs interface to + * ensure this bit is cleared/set accordingly. + */ + if (CAN_PANEL_REPLAY(intel_dp) && panel_replay_global_enabled(intel_dp)) drm_dp_dpcd_writeb(&intel_dp->aux, PANEL_REPLAY_CONFIG, DP_PANEL_REPLAY_ENABLE); } -- cgit v1.2.3 From 1b85a9b04681423013bf6caeffde73aa6f29ab65 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Thu, 8 Jan 2026 18:11:40 +0530 Subject: drm/i915/vbt: Add edp pipe joiner enable/disable bits Add VBT support to enable/disable eDP Pipe Joiner feature. The OEMs can choose to enable/disable the feature from VBT. ARL - VBTs default this field to disabled. PTL+ - VBTs default this field to enabled. Bspec:20142 Signed-off-by: Ankit Nautiyal Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260108124141.1407760-2-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 4 ++++ drivers/gpu/drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_vbt_defs.h | 1 + 3 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 2afc99a39429..eb745a6cbc5e 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1547,6 +1547,10 @@ parse_edp(struct intel_display *display, if (display->vbt.version >= 251) panel->vbt.edp.dsc_disable = panel_bool(edp->edp_dsc_disable, panel_type); + + if (display->vbt.version >= 261) + panel->vbt.edp.pipe_joiner_enable = + panel_bool(edp->pipe_joiner_enable, panel_type); } static void diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index c7a8e475cb22..08692e06d8e9 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -350,6 +350,7 @@ struct intel_vbt_panel_data { bool low_vswing; bool hobl; bool dsc_disable; + bool pipe_joiner_enable; } edp; struct { diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h index 57fda5824c9c..0dc13d080e8a 100644 --- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h @@ -1109,6 +1109,7 @@ struct bdb_edp { u16 edp_dsc_disable; /* 251+ */ u16 t6_delay_support; /* 260+ */ u16 link_idle_time[16]; /* 260+ */ + u16 pipe_joiner_enable; /* 261+ */ } __packed; /* -- cgit v1.2.3 From 650471948e495204f1f89731c71bcf48b3f81b08 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Thu, 8 Jan 2026 18:11:41 +0530 Subject: drm/i915/dp: Avoid joiner for eDP if not enabled in VBT For eDP, enable the Pipe Joiner feature only if VBT explicitly allows it. If VBT disables the feature, skip joiner for eDP, even if the hardware supports it. Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14616 Signed-off-by: Ankit Nautiyal Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260108124141.1407760-3-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 053443eea9d5..79fd3b8d8b25 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -494,11 +494,16 @@ bool intel_dp_has_joiner(struct intel_dp *intel_dp) struct intel_display *display = to_intel_display(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &intel_dig_port->base; + struct intel_connector *connector = intel_dp->attached_connector; /* eDP MSO is not compatible with joiner */ if (intel_dp->mso_link_count) return false; + if (intel_dp_is_edp(intel_dp) && + !connector->panel.vbt.edp.pipe_joiner_enable) + return false; + return DISPLAY_VER(display) >= 12 || (DISPLAY_VER(display) == 11 && encoder->port != PORT_A); -- cgit v1.2.3 From 33fd0375f1c31e20db08535aa9ac36df8156af8a Mon Sep 17 00:00:00 2001 From: Nemesa Garg Date: Thu, 15 Jan 2026 17:09:48 +0530 Subject: drm/i915/casf: Disable CASF with joiner Disable CASF with joiner as it is not supported in hardware. v2: Replace dmesg_WARN with drm_dbg_kms. [Jani] v3: Modify commit message. [Suraj] Signed-off-by: Nemesa Garg Reviewed-by: Suraj Kandpal Signed-off-by: Suraj Kandpal Link: https://patch.msgid.link/20260115113948.641822-1-nemesa.garg@intel.com --- drivers/gpu/drm/i915/display/intel_casf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_casf.c b/drivers/gpu/drm/i915/display/intel_casf.c index 95339b496f24..0fe4398a1a4e 100644 --- a/drivers/gpu/drm/i915/display/intel_casf.c +++ b/drivers/gpu/drm/i915/display/intel_casf.c @@ -116,6 +116,12 @@ int intel_casf_compute_config(struct intel_crtc_state *crtc_state) return 0; } + /* CASF with joiner not supported in hardware */ + if (crtc_state->joiner_pipes) { + drm_dbg_kms(display->drm, "CASF not supported with joiner\n"); + return -EINVAL; + } + crtc_state->hw.casf_params.casf_enable = true; /* -- cgit v1.2.3 From bc5ecacbdc4d315f656988fefb48ecffecdd3c76 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:42 +0000 Subject: drm/i915/cx0: Move C10 port clock calculation Prepare removal of .clock member from pll state structures by moving intel_c10pll_calc_port_clock() function. No functional changes. Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-2-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 54 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 7288065d2461..5cd756321373 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2103,6 +2103,33 @@ static bool cx0pll_state_is_dp(const struct intel_cx0pll_state *pll_state) return c20pll_state_is_dp(&pll_state->c20); } +static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c10pll_state *pll_state) +{ + unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1; + unsigned int multiplier, tx_clk_div, hdmi_div, refclk = 38400; + int tmpclk = 0; + + if (pll_state->pll[0] & C10_PLL0_FRACEN) { + frac_quot = pll_state->pll[12] << 8 | pll_state->pll[11]; + frac_rem = pll_state->pll[14] << 8 | pll_state->pll[13]; + frac_den = pll_state->pll[10] << 8 | pll_state->pll[9]; + } + + multiplier = (REG_FIELD_GET8(C10_PLL3_MULTIPLIERH_MASK, pll_state->pll[3]) << 8 | + pll_state->pll[2]) / 2 + 16; + + tx_clk_div = REG_FIELD_GET8(C10_PLL15_TXCLKDIV_MASK, pll_state->pll[15]); + hdmi_div = REG_FIELD_GET8(C10_PLL15_HDMIDIV_MASK, pll_state->pll[15]); + + tmpclk = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, (multiplier << 16) + frac_quot) + + DIV_ROUND_CLOSEST(refclk * frac_rem, frac_den), + 10 << (tx_clk_div + 16)); + tmpclk *= (hdmi_div ? 2 : 1); + + return tmpclk; +} + /* * TODO: Convert the following to align with intel_c20pll_find_table() and * intel_c20pll_calc_state_from_table(). @@ -2166,33 +2193,6 @@ static int intel_c10pll_calc_state(const struct intel_crtc_state *crtc_state, return 0; } -static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c10pll_state *pll_state) -{ - unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1; - unsigned int multiplier, tx_clk_div, hdmi_div, refclk = 38400; - int tmpclk = 0; - - if (pll_state->pll[0] & C10_PLL0_FRACEN) { - frac_quot = pll_state->pll[12] << 8 | pll_state->pll[11]; - frac_rem = pll_state->pll[14] << 8 | pll_state->pll[13]; - frac_den = pll_state->pll[10] << 8 | pll_state->pll[9]; - } - - multiplier = (REG_FIELD_GET8(C10_PLL3_MULTIPLIERH_MASK, pll_state->pll[3]) << 8 | - pll_state->pll[2]) / 2 + 16; - - tx_clk_div = REG_FIELD_GET8(C10_PLL15_TXCLKDIV_MASK, pll_state->pll[15]); - hdmi_div = REG_FIELD_GET8(C10_PLL15_HDMIDIV_MASK, pll_state->pll[15]); - - tmpclk = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, (multiplier << 16) + frac_quot) + - DIV_ROUND_CLOSEST(refclk * frac_rem, frac_den), - 10 << (tx_clk_div + 16)); - tmpclk *= (hdmi_div ? 2 : 1); - - return tmpclk; -} - static int readout_enabled_lane_count(struct intel_encoder *encoder) { struct intel_display *display = to_intel_display(encoder); -- cgit v1.2.3 From c26ed2ec4d10d1fee7ef8f9987663765ee737487 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:43 +0000 Subject: drm/i915/cx0: Move C20 port clock calculation Prepare removal of .clock member from the pll state structure by moving intel_c20pll_calc_port_clock() function. No functional change. Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-3-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 100 +++++++++++++-------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 5cd756321373..ac5e304ba306 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2130,6 +2130,56 @@ static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, return tmpclk; } +static bool intel_c20phy_use_mpllb(const struct intel_c20pll_state *state) +{ + return state->tx[0] & C20_PHY_USE_MPLLB; +} + +static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c20pll_state *pll_state) +{ + unsigned int frac, frac_en, frac_quot, frac_rem, frac_den; + unsigned int multiplier, refclk = 38400; + unsigned int tx_clk_div; + unsigned int ref_clk_mpllb_div; + unsigned int fb_clk_div4_en; + unsigned int ref, vco; + unsigned int tx_rate_mult; + unsigned int tx_rate = REG_FIELD_GET(C20_PHY_TX_RATE, pll_state->tx[0]); + + if (intel_c20phy_use_mpllb(pll_state)) { + tx_rate_mult = 1; + frac_en = REG_FIELD_GET(C20_MPLLB_FRACEN, pll_state->mpllb[6]); + frac_quot = pll_state->mpllb[8]; + frac_rem = pll_state->mpllb[9]; + frac_den = pll_state->mpllb[7]; + multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mpllb[0]); + tx_clk_div = REG_FIELD_GET(C20_MPLLB_TX_CLK_DIV_MASK, pll_state->mpllb[0]); + ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mpllb[6]); + fb_clk_div4_en = 0; + } else { + tx_rate_mult = 2; + frac_en = REG_FIELD_GET(C20_MPLLA_FRACEN, pll_state->mplla[6]); + frac_quot = pll_state->mplla[8]; + frac_rem = pll_state->mplla[9]; + frac_den = pll_state->mplla[7]; + multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mplla[0]); + tx_clk_div = REG_FIELD_GET(C20_MPLLA_TX_CLK_DIV_MASK, pll_state->mplla[1]); + ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mplla[6]); + fb_clk_div4_en = REG_FIELD_GET(C20_FB_CLK_DIV4_EN, pll_state->mplla[0]); + } + + if (frac_en) + frac = frac_quot + DIV_ROUND_CLOSEST(frac_rem, frac_den); + else + frac = 0; + + ref = DIV_ROUND_CLOSEST(refclk * (1 << (1 + fb_clk_div4_en)), 1 << ref_clk_mpllb_div); + vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(ref, (multiplier << (17 - 2)) + frac) >> 17, 10); + + return vco << tx_rate_mult >> tx_clk_div >> tx_rate; +} + /* * TODO: Convert the following to align with intel_c20pll_find_table() and * intel_c20pll_calc_state_from_table(). @@ -2705,56 +2755,6 @@ int intel_cx0pll_calc_state(const struct intel_crtc_state *crtc_state, return intel_c20pll_calc_state(crtc_state, encoder, hw_state); } -static bool intel_c20phy_use_mpllb(const struct intel_c20pll_state *state) -{ - return state->tx[0] & C20_PHY_USE_MPLLB; -} - -static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c20pll_state *pll_state) -{ - unsigned int frac, frac_en, frac_quot, frac_rem, frac_den; - unsigned int multiplier, refclk = 38400; - unsigned int tx_clk_div; - unsigned int ref_clk_mpllb_div; - unsigned int fb_clk_div4_en; - unsigned int ref, vco; - unsigned int tx_rate_mult; - unsigned int tx_rate = REG_FIELD_GET(C20_PHY_TX_RATE, pll_state->tx[0]); - - if (intel_c20phy_use_mpllb(pll_state)) { - tx_rate_mult = 1; - frac_en = REG_FIELD_GET(C20_MPLLB_FRACEN, pll_state->mpllb[6]); - frac_quot = pll_state->mpllb[8]; - frac_rem = pll_state->mpllb[9]; - frac_den = pll_state->mpllb[7]; - multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mpllb[0]); - tx_clk_div = REG_FIELD_GET(C20_MPLLB_TX_CLK_DIV_MASK, pll_state->mpllb[0]); - ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mpllb[6]); - fb_clk_div4_en = 0; - } else { - tx_rate_mult = 2; - frac_en = REG_FIELD_GET(C20_MPLLA_FRACEN, pll_state->mplla[6]); - frac_quot = pll_state->mplla[8]; - frac_rem = pll_state->mplla[9]; - frac_den = pll_state->mplla[7]; - multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mplla[0]); - tx_clk_div = REG_FIELD_GET(C20_MPLLA_TX_CLK_DIV_MASK, pll_state->mplla[1]); - ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mplla[6]); - fb_clk_div4_en = REG_FIELD_GET(C20_FB_CLK_DIV4_EN, pll_state->mplla[0]); - } - - if (frac_en) - frac = frac_quot + DIV_ROUND_CLOSEST(frac_rem, frac_den); - else - frac = 0; - - ref = DIV_ROUND_CLOSEST(refclk * (1 << (1 + fb_clk_div4_en)), 1 << ref_clk_mpllb_div); - vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(ref, (multiplier << (17 - 2)) + frac) >> 17, 10); - - return vco << tx_rate_mult >> tx_clk_div >> tx_rate; -} - static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, struct intel_cx0pll_state *cx0pll_state) { -- cgit v1.2.3 From 2db8d9c26760f1c64137c4ebca76b61fc0e14548 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:44 +0000 Subject: drm/i915/cx0: Drop Cx0 crtc_state from HDMI TMDS pll divider calculation Drop crtc_state from HDMI TMDS calculation and replace with the parameters that are only required. Follow-up changes will call these functions without a crtc_state available. v2: Keep required crtc_state param for intel_c20_pll_tables_get() and other functions calling this one. Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-4-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index ac5e304ba306..6447d7c80ffc 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2414,9 +2414,8 @@ static bool is_arrowlake_s_by_host_bridge(void) return pdev && IS_ARROWLAKE_S_BY_HOST_BRIDGE_ID(host_bridge_pci_dev_id); } -static u16 intel_c20_hdmi_tmds_tx_cgf_1(const struct intel_crtc_state *crtc_state) +static u16 intel_c20_hdmi_tmds_tx_cgf_1(struct intel_display *display) { - struct intel_display *display = to_intel_display(crtc_state); u16 tx_misc; u16 tx_dcc_cal_dac_ctrl_range = 8; u16 tx_term_ctrl = 2; @@ -2438,7 +2437,8 @@ static u16 intel_c20_hdmi_tmds_tx_cgf_1(const struct intel_crtc_state *crtc_stat C20_PHY_TX_DCC_BYPASS | C20_PHY_TX_TERM_CTL(tx_term_ctrl)); } -static int intel_c20_compute_hdmi_tmds_pll(const struct intel_crtc_state *crtc_state, +static int intel_c20_compute_hdmi_tmds_pll(struct intel_display *display, + int port_clock, struct intel_c20pll_state *pll_state) { u64 datarate; @@ -2452,10 +2452,10 @@ static int intel_c20_compute_hdmi_tmds_pll(const struct intel_crtc_state *crtc_s u8 mpllb_ana_freq_vco; u8 mpll_div_multiplier; - if (crtc_state->port_clock < 25175 || crtc_state->port_clock > 600000) + if (port_clock < 25175 || port_clock > 600000) return -EINVAL; - datarate = ((u64)crtc_state->port_clock * 1000) * 10; + datarate = ((u64)port_clock * 1000) * 10; mpll_tx_clk_div = ilog2(div64_u64((u64)CLOCK_9999MHZ, (u64)datarate)); vco_freq_shift = ilog2(div64_u64((u64)CLOCK_4999MHZ * (u64)256, (u64)datarate)); vco_freq = (datarate << vco_freq_shift) >> 8; @@ -2477,9 +2477,9 @@ static int intel_c20_compute_hdmi_tmds_pll(const struct intel_crtc_state *crtc_s else mpllb_ana_freq_vco = MPLLB_ANA_FREQ_VCO_0; - pll_state->clock = crtc_state->port_clock; + pll_state->clock = port_clock; pll_state->tx[0] = 0xbe88; - pll_state->tx[1] = intel_c20_hdmi_tmds_tx_cgf_1(crtc_state); + pll_state->tx[1] = intel_c20_hdmi_tmds_tx_cgf_1(display); pll_state->tx[2] = 0x0000; pll_state->cmn[0] = 0x0500; pll_state->cmn[1] = 0x0005; @@ -2731,7 +2731,8 @@ static int intel_c20pll_calc_state(const struct intel_crtc_state *crtc_state, /* TODO: Update SSC state for HDMI as well */ if (!is_dp && err) - err = intel_c20_compute_hdmi_tmds_pll(crtc_state, &hw_state->cx0pll.c20); + err = intel_c20_compute_hdmi_tmds_pll(display, crtc_state->port_clock, + &hw_state->cx0pll.c20); if (err) return err; -- cgit v1.2.3 From a35ab9c32f19a9435d3526fb6b025343c1dc7400 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:45 +0000 Subject: drm/i915/lt_phy: Drop LT PHY crtc_state for port calculation Drop crtc_state from intel_lt_phy_calc_port_clock() function call and replace it with pll state instead. Follow-up changes will call these functions without a crtc_state available. Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-5-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 4 +++- drivers/gpu/drm/i915/display/intel_dpll.c | 3 ++- drivers/gpu/drm/i915/display/intel_lt_phy.c | 18 +++++++----------- drivers/gpu/drm/i915/display/intel_lt_phy.h | 4 ++-- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index cb91d07cdaa6..d8739e2bb004 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4247,13 +4247,15 @@ void intel_ddi_get_clock(struct intel_encoder *encoder, static void xe3plpd_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state) { + struct intel_display *display = to_intel_display(encoder); + intel_lt_phy_pll_readout_hw_state(encoder, crtc_state, &crtc_state->dpll_hw_state.ltpll); if (crtc_state->dpll_hw_state.ltpll.tbt_mode) crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder); else crtc_state->port_clock = - intel_lt_phy_calc_port_clock(encoder, crtc_state); + intel_lt_phy_calc_port_clock(display, &crtc_state->dpll_hw_state.ltpll); intel_ddi_get_config(encoder, crtc_state); } diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index a4f372c9e6fc..1b5b18fa0a36 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -1219,6 +1219,7 @@ static int xe3plpd_crtc_compute_clock(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); struct intel_encoder *encoder = intel_get_crtc_new_encoder(state, crtc_state); + struct intel_display *display = to_intel_display(encoder); int ret; ret = intel_lt_phy_pll_calc_state(crtc_state, encoder); @@ -1227,7 +1228,7 @@ static int xe3plpd_crtc_compute_clock(struct intel_atomic_state *state, /* TODO: Do the readback via intel_compute_shared_dplls() */ crtc_state->port_clock = - intel_lt_phy_calc_port_clock(encoder, crtc_state); + intel_lt_phy_calc_port_clock(display, &crtc_state->dpll_hw_state.ltpll); crtc_state->hw.adjusted_mode.crtc_clock = intel_crtc_dotclock(crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c index 6cdae03ee172..48f644f417d2 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.c +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c @@ -1680,7 +1680,8 @@ intel_lt_phy_calculate_hdmi_state(struct intel_lt_phy_pll_state *lt_state, } static int -intel_lt_phy_calc_hdmi_port_clock(const struct intel_crtc_state *crtc_state) +intel_lt_phy_calc_hdmi_port_clock(struct intel_display *display, + const struct intel_lt_phy_pll_state *lt_state) { #define REGVAL(i) ( \ (lt_state->data[i][3]) | \ @@ -1689,9 +1690,6 @@ intel_lt_phy_calc_hdmi_port_clock(const struct intel_crtc_state *crtc_state) (lt_state->data[i][0] << 24) \ ) - struct intel_display *display = to_intel_display(crtc_state); - const struct intel_lt_phy_pll_state *lt_state = - &crtc_state->dpll_hw_state.ltpll; int clk = 0; u32 d8, pll_reg_5, pll_reg_3, pll_reg_57, m2div_frac, m2div_int; u64 temp0, temp1; @@ -1749,13 +1747,10 @@ intel_lt_phy_calc_hdmi_port_clock(const struct intel_crtc_state *crtc_state) } int -intel_lt_phy_calc_port_clock(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +intel_lt_phy_calc_port_clock(struct intel_display *display, + const struct intel_lt_phy_pll_state *lt_state) { - struct intel_display *display = to_intel_display(encoder); int clk; - const struct intel_lt_phy_pll_state *lt_state = - &crtc_state->dpll_hw_state.ltpll; u8 mode, rate; mode = REG_FIELD_GET8(LT_PHY_VDR_MODE_ENCODING_MASK, @@ -1771,7 +1766,7 @@ intel_lt_phy_calc_port_clock(struct intel_encoder *encoder, lt_state->config[0]); clk = intel_lt_phy_get_dp_clock(rate); } else if (mode == MODE_HDMI_20) { - clk = intel_lt_phy_calc_hdmi_port_clock(crtc_state); + clk = intel_lt_phy_calc_hdmi_port_clock(display, lt_state); } else { drm_WARN_ON(display->drm, "Unsupported LT PHY Mode!\n"); clk = xe3plpd_lt_hdmi_252.clock; @@ -2230,6 +2225,7 @@ void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, struct intel_lt_phy_pll_state *pll_state) { + struct intel_display *display = to_intel_display(encoder); u8 owned_lane_mask; u8 lane; struct ref_tracker *wakeref; @@ -2255,7 +2251,7 @@ void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, } pll_state->clock = - intel_lt_phy_calc_port_clock(encoder, crtc_state); + intel_lt_phy_calc_port_clock(display, &crtc_state->dpll_hw_state.ltpll); intel_lt_phy_transaction_end(encoder, wakeref); } diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.h b/drivers/gpu/drm/i915/display/intel_lt_phy.h index bf41858f1bc3..22b12d2d5bb1 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.h +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.h @@ -21,8 +21,8 @@ void intel_lt_phy_pll_disable(struct intel_encoder *encoder); int intel_lt_phy_pll_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder); -int intel_lt_phy_calc_port_clock(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state); +int intel_lt_phy_calc_port_clock(struct intel_display *display, + const struct intel_lt_phy_pll_state *lt_state); void intel_lt_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_lt_phy_dump_hw_state(struct intel_display *display, -- cgit v1.2.3 From 81152791701fdfa1bb9adff846a6eef888021227 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:46 +0000 Subject: drm/i915/cx0: Drop encoder from port clock calculation For C10 and C20 we have unused encoder parameter passed to port clock calculation function. Remove the encoder from being passed to the port clock calculation function. Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-6-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 6447d7c80ffc..77378e057908 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -2103,8 +2103,7 @@ static bool cx0pll_state_is_dp(const struct intel_cx0pll_state *pll_state) return c20pll_state_is_dp(&pll_state->c20); } -static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c10pll_state *pll_state) +static int intel_c10pll_calc_port_clock(const struct intel_c10pll_state *pll_state) { unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1; unsigned int multiplier, tx_clk_div, hdmi_div, refclk = 38400; @@ -2135,8 +2134,7 @@ static bool intel_c20phy_use_mpllb(const struct intel_c20pll_state *state) return state->tx[0] & C20_PHY_USE_MPLLB; } -static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c20pll_state *pll_state) +static int intel_c20pll_calc_port_clock(const struct intel_c20pll_state *pll_state) { unsigned int frac, frac_en, frac_quot, frac_rem, frac_den; unsigned int multiplier, refclk = 38400; @@ -2325,7 +2323,7 @@ static void intel_c10pll_readout_hw_state(struct intel_encoder *encoder, intel_cx0_phy_transaction_end(encoder, wakeref); - pll_state->clock = intel_c10pll_calc_port_clock(encoder, pll_state); + pll_state->clock = intel_c10pll_calc_port_clock(pll_state); cx0pll_state->ssc_enabled = readout_ssc_state(encoder, true); @@ -2824,7 +2822,7 @@ static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, } } - pll_state->clock = intel_c20pll_calc_port_clock(encoder, pll_state); + pll_state->clock = intel_c20pll_calc_port_clock(pll_state); intel_cx0_phy_transaction_end(encoder, wakeref); @@ -3731,9 +3729,9 @@ int intel_cx0pll_calc_port_clock(struct intel_encoder *encoder, const struct intel_cx0pll_state *pll_state) { if (intel_encoder_is_c10phy(encoder)) - return intel_c10pll_calc_port_clock(encoder, &pll_state->c10); + return intel_c10pll_calc_port_clock(&pll_state->c10); - return intel_c20pll_calc_port_clock(encoder, &pll_state->c20); + return intel_c20pll_calc_port_clock(&pll_state->c20); } /* -- cgit v1.2.3 From 52801b2eb532e8516e2366c4f67ef7cd022ef4ba Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:47 +0000 Subject: drm/i915/cx0: Create macro around PLL tables Create macro for storing PLL dividers with table name and clock rate. v2: Preserve the terminating {} in each PLL table. Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-7-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 301 +++++++++++++++------------ 1 file changed, 167 insertions(+), 134 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 77378e057908..8e780480f6c0 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -780,25 +780,58 @@ static const struct intel_c10pll_state mtl_c10_dp_hbr3 = { .pll[19] = 0x23, }; -static const struct intel_c10pll_state * const mtl_c10_dp_tables[] = { - &mtl_c10_dp_rbr, - &mtl_c10_dp_hbr1, - &mtl_c10_dp_hbr2, - &mtl_c10_dp_hbr3, - NULL, -}; - -static const struct intel_c10pll_state * const mtl_c10_edp_tables[] = { - &mtl_c10_dp_rbr, - &mtl_c10_edp_r216, - &mtl_c10_edp_r243, - &mtl_c10_dp_hbr1, - &mtl_c10_edp_r324, - &mtl_c10_edp_r432, - &mtl_c10_dp_hbr2, - &mtl_c10_edp_r675, - &mtl_c10_dp_hbr3, - NULL, +struct intel_cx0pll_params { + const char *name; + bool is_c10; + bool is_hdmi; + int clock_rate; + union { + const struct intel_c10pll_state *c10; + const struct intel_c20pll_state *c20; + }; +}; + +#define __C10PLL_PARAMS(__is_hdmi, __clock_rate, __state) { \ + .name = __stringify(__state), \ + .is_c10 = true, \ + .is_hdmi = __is_hdmi, \ + .clock_rate = __clock_rate, \ + .c10 = &__state, \ +} + +#define __C20PLL_PARAMS(__is_hdmi, __clock_rate, __state) { \ + .name = __stringify(__state), \ + .is_c10 = false, \ + .is_hdmi = __is_hdmi, \ + .clock_rate = __clock_rate, \ + .c20 = &__state, \ +} + +#define C10PLL_HDMI_PARAMS(__clock_rate, __state) __C10PLL_PARAMS(true, __clock_rate, __state) +#define C10PLL_DP_PARAMS(__clock_rate, __state) __C10PLL_PARAMS(false, __clock_rate, __state) + +#define C20PLL_HDMI_PARAMS(__clock_rate, __state) __C20PLL_PARAMS(true, __clock_rate, __state) +#define C20PLL_DP_PARAMS(__clock_rate, __state) __C20PLL_PARAMS(false, __clock_rate, __state) + +static const struct intel_cx0pll_params mtl_c10_dp_tables[] = { + C10PLL_DP_PARAMS(162000, mtl_c10_dp_rbr), + C10PLL_DP_PARAMS(270000, mtl_c10_dp_hbr1), + C10PLL_DP_PARAMS(540000, mtl_c10_dp_hbr2), + C10PLL_DP_PARAMS(810000, mtl_c10_dp_hbr3), + {} +}; + +static const struct intel_cx0pll_params mtl_c10_edp_tables[] = { + C10PLL_DP_PARAMS(162000, mtl_c10_dp_rbr), + C10PLL_DP_PARAMS(216000, mtl_c10_edp_r216), + C10PLL_DP_PARAMS(243000, mtl_c10_edp_r243), + C10PLL_DP_PARAMS(270000, mtl_c10_dp_hbr1), + C10PLL_DP_PARAMS(324000, mtl_c10_edp_r324), + C10PLL_DP_PARAMS(432000, mtl_c10_edp_r432), + C10PLL_DP_PARAMS(540000, mtl_c10_dp_hbr2), + C10PLL_DP_PARAMS(675000, mtl_c10_edp_r675), + C10PLL_DP_PARAMS(810000, mtl_c10_dp_hbr3), + {} }; /* C20 basic DP 1.4 tables */ @@ -976,15 +1009,15 @@ static const struct intel_c20pll_state mtl_c20_dp_uhbr20 = { }, }; -static const struct intel_c20pll_state * const mtl_c20_dp_tables[] = { - &mtl_c20_dp_rbr, - &mtl_c20_dp_hbr1, - &mtl_c20_dp_hbr2, - &mtl_c20_dp_hbr3, - &mtl_c20_dp_uhbr10, - &mtl_c20_dp_uhbr13_5, - &mtl_c20_dp_uhbr20, - NULL, +static const struct intel_cx0pll_params mtl_c20_dp_tables[] = { + C20PLL_DP_PARAMS(162000, mtl_c20_dp_rbr), + C20PLL_DP_PARAMS(270000, mtl_c20_dp_hbr1), + C20PLL_DP_PARAMS(540000, mtl_c20_dp_hbr2), + C20PLL_DP_PARAMS(810000, mtl_c20_dp_hbr3), + C20PLL_DP_PARAMS(1000000, mtl_c20_dp_uhbr10), + C20PLL_DP_PARAMS(1350000, mtl_c20_dp_uhbr13_5), + C20PLL_DP_PARAMS(2000000, mtl_c20_dp_uhbr20), + {} }; /* @@ -1116,17 +1149,17 @@ static const struct intel_c20pll_state xe2hpd_c20_edp_r675 = { }, }; -static const struct intel_c20pll_state * const xe2hpd_c20_edp_tables[] = { - &mtl_c20_dp_rbr, - &xe2hpd_c20_edp_r216, - &xe2hpd_c20_edp_r243, - &mtl_c20_dp_hbr1, - &xe2hpd_c20_edp_r324, - &xe2hpd_c20_edp_r432, - &mtl_c20_dp_hbr2, - &xe2hpd_c20_edp_r675, - &mtl_c20_dp_hbr3, - NULL, +static const struct intel_cx0pll_params xe2hpd_c20_edp_tables[] = { + C20PLL_DP_PARAMS(162000, mtl_c20_dp_rbr), + C20PLL_DP_PARAMS(216000, xe2hpd_c20_edp_r216), + C20PLL_DP_PARAMS(243000, xe2hpd_c20_edp_r243), + C20PLL_DP_PARAMS(270000, mtl_c20_dp_hbr1), + C20PLL_DP_PARAMS(324000, xe2hpd_c20_edp_r324), + C20PLL_DP_PARAMS(432000, xe2hpd_c20_edp_r432), + C20PLL_DP_PARAMS(540000, mtl_c20_dp_hbr2), + C20PLL_DP_PARAMS(675000, xe2hpd_c20_edp_r675), + C20PLL_DP_PARAMS(810000, mtl_c20_dp_hbr3), + {} }; static const struct intel_c20pll_state xe2hpd_c20_dp_uhbr13_5 = { @@ -1154,30 +1187,30 @@ static const struct intel_c20pll_state xe2hpd_c20_dp_uhbr13_5 = { }, }; -static const struct intel_c20pll_state * const xe2hpd_c20_dp_tables[] = { - &mtl_c20_dp_rbr, - &mtl_c20_dp_hbr1, - &mtl_c20_dp_hbr2, - &mtl_c20_dp_hbr3, - &mtl_c20_dp_uhbr10, - &xe2hpd_c20_dp_uhbr13_5, - NULL, +static const struct intel_cx0pll_params xe2hpd_c20_dp_tables[] = { + C20PLL_DP_PARAMS(162000, mtl_c20_dp_rbr), + C20PLL_DP_PARAMS(270000, mtl_c20_dp_hbr1), + C20PLL_DP_PARAMS(540000, mtl_c20_dp_hbr2), + C20PLL_DP_PARAMS(810000, mtl_c20_dp_hbr3), + C20PLL_DP_PARAMS(1000000, mtl_c20_dp_uhbr10), + C20PLL_DP_PARAMS(1350000, xe2hpd_c20_dp_uhbr13_5), + {} }; -static const struct intel_c20pll_state * const xe3lpd_c20_dp_edp_tables[] = { - &mtl_c20_dp_rbr, - &xe2hpd_c20_edp_r216, - &xe2hpd_c20_edp_r243, - &mtl_c20_dp_hbr1, - &xe2hpd_c20_edp_r324, - &xe2hpd_c20_edp_r432, - &mtl_c20_dp_hbr2, - &xe2hpd_c20_edp_r675, - &mtl_c20_dp_hbr3, - &mtl_c20_dp_uhbr10, - &xe2hpd_c20_dp_uhbr13_5, - &mtl_c20_dp_uhbr20, - NULL, +static const struct intel_cx0pll_params xe3lpd_c20_dp_edp_tables[] = { + C20PLL_DP_PARAMS(162000, mtl_c20_dp_rbr), + C20PLL_DP_PARAMS(216000, xe2hpd_c20_edp_r216), + C20PLL_DP_PARAMS(243000, xe2hpd_c20_edp_r243), + C20PLL_DP_PARAMS(270000, mtl_c20_dp_hbr1), + C20PLL_DP_PARAMS(324000, xe2hpd_c20_edp_r324), + C20PLL_DP_PARAMS(432000, xe2hpd_c20_edp_r432), + C20PLL_DP_PARAMS(540000, mtl_c20_dp_hbr2), + C20PLL_DP_PARAMS(675000, xe2hpd_c20_edp_r675), + C20PLL_DP_PARAMS(810000, mtl_c20_dp_hbr3), + C20PLL_DP_PARAMS(1000000, mtl_c20_dp_uhbr10), + C20PLL_DP_PARAMS(1350000, xe2hpd_c20_dp_uhbr13_5), + C20PLL_DP_PARAMS(2000000, mtl_c20_dp_uhbr20), + {} }; /* @@ -1715,53 +1748,53 @@ static const struct intel_c10pll_state mtl_c10_hdmi_593407 = { .pll[15] = 0x08, .pll[16] = 0x08, .pll[17] = 0x8F, .pll[18] = 0x84, .pll[19] = 0x23, }; -static const struct intel_c10pll_state * const mtl_c10_hdmi_tables[] = { - &mtl_c10_hdmi_25_2, /* Consolidated Table */ - &mtl_c10_hdmi_27_0, /* Consolidated Table */ - &mtl_c10_hdmi_27027, - &mtl_c10_hdmi_28320, - &mtl_c10_hdmi_30240, - &mtl_c10_hdmi_31500, - &mtl_c10_hdmi_36000, - &mtl_c10_hdmi_40000, - &mtl_c10_hdmi_49500, - &mtl_c10_hdmi_50000, - &mtl_c10_hdmi_57284, - &mtl_c10_hdmi_58000, - &mtl_c10_hdmi_65000, - &mtl_c10_hdmi_71000, - &mtl_c10_hdmi_74176, - &mtl_c10_hdmi_74_25, /* Consolidated Table */ - &mtl_c10_hdmi_75000, - &mtl_c10_hdmi_78750, - &mtl_c10_hdmi_85500, - &mtl_c10_hdmi_88750, - &mtl_c10_hdmi_106500, - &mtl_c10_hdmi_108000, - &mtl_c10_hdmi_115500, - &mtl_c10_hdmi_119000, - &mtl_c10_hdmi_135000, - &mtl_c10_hdmi_138500, - &mtl_c10_hdmi_147160, - &mtl_c10_hdmi_148352, - &mtl_c10_hdmi_148_5, /* Consolidated Table */ - &mtl_c10_hdmi_154000, - &mtl_c10_hdmi_162000, - &mtl_c10_hdmi_167000, - &mtl_c10_hdmi_197802, - &mtl_c10_hdmi_198000, - &mtl_c10_hdmi_209800, - &mtl_c10_hdmi_241500, - &mtl_c10_hdmi_262750, - &mtl_c10_hdmi_268500, - &mtl_c10_hdmi_296703, - &mtl_c10_hdmi_297000, - &mtl_c10_hdmi_319750, - &mtl_c10_hdmi_497750, - &mtl_c10_hdmi_592000, - &mtl_c10_hdmi_593407, - &mtl_c10_hdmi_594, /* Consolidated Table */ - NULL, +static const struct intel_cx0pll_params mtl_c10_hdmi_tables[] = { + C10PLL_HDMI_PARAMS(25200, mtl_c10_hdmi_25_2), /* Consolidated Table */ + C10PLL_HDMI_PARAMS(27000, mtl_c10_hdmi_27_0), /* Consolidated Table */ + C10PLL_HDMI_PARAMS(27027, mtl_c10_hdmi_27027), + C10PLL_HDMI_PARAMS(28320, mtl_c10_hdmi_28320), + C10PLL_HDMI_PARAMS(30240, mtl_c10_hdmi_30240), + C10PLL_HDMI_PARAMS(31500, mtl_c10_hdmi_31500), + C10PLL_HDMI_PARAMS(36000, mtl_c10_hdmi_36000), + C10PLL_HDMI_PARAMS(40000, mtl_c10_hdmi_40000), + C10PLL_HDMI_PARAMS(49500, mtl_c10_hdmi_49500), + C10PLL_HDMI_PARAMS(50000, mtl_c10_hdmi_50000), + C10PLL_HDMI_PARAMS(57284, mtl_c10_hdmi_57284), + C10PLL_HDMI_PARAMS(58000, mtl_c10_hdmi_58000), + C10PLL_HDMI_PARAMS(65000, mtl_c10_hdmi_65000), + C10PLL_HDMI_PARAMS(71000, mtl_c10_hdmi_71000), + C10PLL_HDMI_PARAMS(74176, mtl_c10_hdmi_74176), + C10PLL_HDMI_PARAMS(74250, mtl_c10_hdmi_74_25), /* Consolidated Table */ + C10PLL_HDMI_PARAMS(75000, mtl_c10_hdmi_75000), + C10PLL_HDMI_PARAMS(78750, mtl_c10_hdmi_78750), + C10PLL_HDMI_PARAMS(85500, mtl_c10_hdmi_85500), + C10PLL_HDMI_PARAMS(88750, mtl_c10_hdmi_88750), + C10PLL_HDMI_PARAMS(106500, mtl_c10_hdmi_106500), + C10PLL_HDMI_PARAMS(108000, mtl_c10_hdmi_108000), + C10PLL_HDMI_PARAMS(115500, mtl_c10_hdmi_115500), + C10PLL_HDMI_PARAMS(119000, mtl_c10_hdmi_119000), + C10PLL_HDMI_PARAMS(135000, mtl_c10_hdmi_135000), + C10PLL_HDMI_PARAMS(138500, mtl_c10_hdmi_138500), + C10PLL_HDMI_PARAMS(147160, mtl_c10_hdmi_147160), + C10PLL_HDMI_PARAMS(148352, mtl_c10_hdmi_148352), + C10PLL_HDMI_PARAMS(148500, mtl_c10_hdmi_148_5), /* Consolidated Table */ + C10PLL_HDMI_PARAMS(154000, mtl_c10_hdmi_154000), + C10PLL_HDMI_PARAMS(162000, mtl_c10_hdmi_162000), + C10PLL_HDMI_PARAMS(167000, mtl_c10_hdmi_167000), + C10PLL_HDMI_PARAMS(197802, mtl_c10_hdmi_197802), + C10PLL_HDMI_PARAMS(198000, mtl_c10_hdmi_198000), + C10PLL_HDMI_PARAMS(209800, mtl_c10_hdmi_209800), + C10PLL_HDMI_PARAMS(241500, mtl_c10_hdmi_241500), + C10PLL_HDMI_PARAMS(262750, mtl_c10_hdmi_262750), + C10PLL_HDMI_PARAMS(268500, mtl_c10_hdmi_268500), + C10PLL_HDMI_PARAMS(296703, mtl_c10_hdmi_296703), + C10PLL_HDMI_PARAMS(297000, mtl_c10_hdmi_297000), + C10PLL_HDMI_PARAMS(319750, mtl_c10_hdmi_319750), + C10PLL_HDMI_PARAMS(497750, mtl_c10_hdmi_497750), + C10PLL_HDMI_PARAMS(592000, mtl_c10_hdmi_592000), + C10PLL_HDMI_PARAMS(593407, mtl_c10_hdmi_593407), + C10PLL_HDMI_PARAMS(594000, mtl_c10_hdmi_594), /* Consolidated Table */ + {} }; static const struct intel_c20pll_state mtl_c20_hdmi_25_175 = { @@ -2014,21 +2047,21 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1200 = { }, }; -static const struct intel_c20pll_state * const mtl_c20_hdmi_tables[] = { - &mtl_c20_hdmi_25_175, - &mtl_c20_hdmi_27_0, - &mtl_c20_hdmi_74_25, - &mtl_c20_hdmi_148_5, - &mtl_c20_hdmi_594, - &mtl_c20_hdmi_300, - &mtl_c20_hdmi_600, - &mtl_c20_hdmi_800, - &mtl_c20_hdmi_1000, - &mtl_c20_hdmi_1200, - NULL, +static const struct intel_cx0pll_params mtl_c20_hdmi_tables[] = { + C20PLL_HDMI_PARAMS(25175, mtl_c20_hdmi_25_175), + C20PLL_HDMI_PARAMS(27000, mtl_c20_hdmi_27_0), + C20PLL_HDMI_PARAMS(74250, mtl_c20_hdmi_74_25), + C20PLL_HDMI_PARAMS(148500, mtl_c20_hdmi_148_5), + C20PLL_HDMI_PARAMS(594000, mtl_c20_hdmi_594), + C20PLL_HDMI_PARAMS(300000, mtl_c20_hdmi_300), + C20PLL_HDMI_PARAMS(600000, mtl_c20_hdmi_600), + C20PLL_HDMI_PARAMS(800000, mtl_c20_hdmi_800), + C20PLL_HDMI_PARAMS(1000000, mtl_c20_hdmi_1000), + C20PLL_HDMI_PARAMS(1200000, mtl_c20_hdmi_1200), + {} }; -static const struct intel_c10pll_state * const * +static const struct intel_cx0pll_params * intel_c10pll_tables_get(const struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { @@ -2183,16 +2216,16 @@ static int intel_c20pll_calc_port_clock(const struct intel_c20pll_state *pll_sta * intel_c20pll_calc_state_from_table(). */ static int intel_c10pll_calc_state_from_table(struct intel_encoder *encoder, - const struct intel_c10pll_state * const *tables, + const struct intel_cx0pll_params *tables, bool is_dp, int port_clock, int lane_count, struct intel_cx0pll_state *pll_state) { struct intel_display *display = to_intel_display(encoder); int i; - for (i = 0; tables[i]; i++) { - if (port_clock == tables[i]->clock) { - pll_state->c10 = *tables[i]; + for (i = 0; tables[i].name; i++) { + if (port_clock == tables[i].clock_rate) { + pll_state->c10 = *tables[i].c10; intel_cx0pll_update_ssc(encoder, pll_state, is_dp); intel_c10pll_update_pll(encoder, pll_state); @@ -2214,7 +2247,7 @@ static int intel_c10pll_calc_state(const struct intel_crtc_state *crtc_state, { struct intel_display *display = to_intel_display(encoder); bool is_dp = intel_crtc_has_dp_encoder(crtc_state); - const struct intel_c10pll_state * const *tables; + const struct intel_cx0pll_params *tables; int err; tables = intel_c10pll_tables_get(crtc_state, encoder); @@ -2505,7 +2538,7 @@ static int intel_c20_compute_hdmi_tmds_pll(struct intel_display *display, return 0; } -static const struct intel_c20pll_state * const * +static const struct intel_cx0pll_params * intel_c20_pll_tables_get(const struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { @@ -2673,20 +2706,20 @@ static void intel_c20_program_vdr_params(struct intel_encoder *encoder, MB_WRITE_COMMITTED); } -static const struct intel_c20pll_state * +static const struct intel_cx0pll_params * intel_c20_pll_find_table(const struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { - const struct intel_c20pll_state * const *tables; + const struct intel_cx0pll_params *tables; int i; tables = intel_c20_pll_tables_get(crtc_state, encoder); if (!tables) return NULL; - for (i = 0; tables[i]; i++) - if (crtc_state->port_clock == tables[i]->clock) - return tables[i]; + for (i = 0; tables[i].name; i++) + if (crtc_state->port_clock == tables[i].clock_rate) + return &tables[i]; return NULL; } @@ -2695,13 +2728,13 @@ static int intel_c20pll_calc_state_from_table(const struct intel_crtc_state *crt struct intel_encoder *encoder, struct intel_cx0pll_state *pll_state) { - const struct intel_c20pll_state *table; + const struct intel_cx0pll_params *table; table = intel_c20_pll_find_table(crtc_state, encoder); if (!table) return -EINVAL; - pll_state->c20 = *table; + pll_state->c20 = *table->c20; intel_cx0pll_update_ssc(encoder, pll_state, intel_crtc_has_dp_encoder(crtc_state)); -- cgit v1.2.3 From cf0635d40af0029ed5f600f366a395df3c58a19b Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:48 +0000 Subject: drm/i915/lt_phy: Create macro for LT PHY PLL state Create a macro for PLL state for LT PHY similar as for cx0 case. v2: - Move addition of LT_PHY_PLL_DP/HDMI_PARAMS() to this patch. - Fix end of table checking while looking up a table. Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-8-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_lt_phy.c | 83 +++++++++++++++++------------ 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c index 48f644f417d2..a86ae6139ff0 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.c +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c @@ -437,15 +437,32 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_uhbr20 = { }, }; -static const struct intel_lt_phy_pll_state * const xe3plpd_lt_dp_tables[] = { - &xe3plpd_lt_dp_rbr, - &xe3plpd_lt_dp_hbr1, - &xe3plpd_lt_dp_hbr2, - &xe3plpd_lt_dp_hbr3, - &xe3plpd_lt_dp_uhbr10, - &xe3plpd_lt_dp_uhbr13_5, - &xe3plpd_lt_dp_uhbr20, - NULL, +struct intel_lt_phy_pll_params { + const char *name; + bool is_hdmi; + int clock_rate; + const struct intel_lt_phy_pll_state *state; +}; + +#define __LT_PHY_PLL_PARAMS(__is_hdmi, __clock_rate, __state) { \ + .name = __stringify(__state), \ + .is_hdmi = __is_hdmi, \ + .clock_rate = __clock_rate, \ + .state = &__state, \ +} + +#define LT_PHY_PLL_HDMI_PARAMS(__clock_rate, __state) __LT_PHY_PLL_PARAMS(true, __clock_rate, __state) +#define LT_PHY_PLL_DP_PARAMS(__clock_rate, __state) __LT_PHY_PLL_PARAMS(false, __clock_rate, __state) + +static const struct intel_lt_phy_pll_params xe3plpd_lt_dp_tables[] = { + LT_PHY_PLL_DP_PARAMS(162000, xe3plpd_lt_dp_rbr), + LT_PHY_PLL_DP_PARAMS(270000, xe3plpd_lt_dp_hbr1), + LT_PHY_PLL_DP_PARAMS(540000, xe3plpd_lt_dp_hbr2), + LT_PHY_PLL_DP_PARAMS(810000, xe3plpd_lt_dp_hbr3), + LT_PHY_PLL_DP_PARAMS(1000000, xe3plpd_lt_dp_uhbr10), + LT_PHY_PLL_DP_PARAMS(1350000, xe3plpd_lt_dp_uhbr13_5), + LT_PHY_PLL_DP_PARAMS(2000000, xe3plpd_lt_dp_uhbr20), + {} }; static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_2_16 = { @@ -718,17 +735,17 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_6_75 = { }, }; -static const struct intel_lt_phy_pll_state * const xe3plpd_lt_edp_tables[] = { - &xe3plpd_lt_dp_rbr, - &xe3plpd_lt_edp_2_16, - &xe3plpd_lt_edp_2_43, - &xe3plpd_lt_dp_hbr1, - &xe3plpd_lt_edp_3_24, - &xe3plpd_lt_edp_4_32, - &xe3plpd_lt_dp_hbr2, - &xe3plpd_lt_edp_6_75, - &xe3plpd_lt_dp_hbr3, - NULL, +static const struct intel_lt_phy_pll_params xe3plpd_lt_edp_tables[] = { + LT_PHY_PLL_DP_PARAMS(162000, xe3plpd_lt_dp_rbr), + LT_PHY_PLL_DP_PARAMS(216000, xe3plpd_lt_edp_2_16), + LT_PHY_PLL_DP_PARAMS(243000, xe3plpd_lt_edp_2_43), + LT_PHY_PLL_DP_PARAMS(270000, xe3plpd_lt_dp_hbr1), + LT_PHY_PLL_DP_PARAMS(324000, xe3plpd_lt_edp_3_24), + LT_PHY_PLL_DP_PARAMS(432000, xe3plpd_lt_edp_4_32), + LT_PHY_PLL_DP_PARAMS(540000, xe3plpd_lt_dp_hbr2), + LT_PHY_PLL_DP_PARAMS(675000, xe3plpd_lt_edp_6_75), + LT_PHY_PLL_DP_PARAMS(810000, xe3plpd_lt_dp_hbr3), + {} }; static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_252 = { @@ -1001,13 +1018,13 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_5p94 = { }, }; -static const struct intel_lt_phy_pll_state * const xe3plpd_lt_hdmi_tables[] = { - &xe3plpd_lt_hdmi_252, - &xe3plpd_lt_hdmi_272, - &xe3plpd_lt_hdmi_742p5, - &xe3plpd_lt_hdmi_1p485, - &xe3plpd_lt_hdmi_5p94, - NULL, +static const struct intel_lt_phy_pll_params xe3plpd_lt_hdmi_tables[] = { + LT_PHY_PLL_HDMI_PARAMS(25200, xe3plpd_lt_hdmi_252), + LT_PHY_PLL_HDMI_PARAMS(27200, xe3plpd_lt_hdmi_272), + LT_PHY_PLL_HDMI_PARAMS(74250, xe3plpd_lt_hdmi_742p5), + LT_PHY_PLL_HDMI_PARAMS(148500, xe3plpd_lt_hdmi_1p485), + LT_PHY_PLL_HDMI_PARAMS(594000, xe3plpd_lt_hdmi_5p94), + {} }; static u8 intel_lt_phy_get_owned_lane_mask(struct intel_encoder *encoder) @@ -1346,7 +1363,7 @@ static void intel_lt_phy_transaction_end(struct intel_encoder *encoder, struct r intel_display_power_put(display, POWER_DOMAIN_DC_OFF, wakeref); } -static const struct intel_lt_phy_pll_state * const * +static const struct intel_lt_phy_pll_params * intel_lt_phy_pll_tables_get(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { @@ -1735,7 +1752,7 @@ intel_lt_phy_calc_hdmi_port_clock(struct intel_display *display, if (d8 == 0) { drm_WARN_ON(display->drm, "Invalid port clock using lowest HDMI portclock\n"); - return xe3plpd_lt_hdmi_252.clock; + return xe3plpd_lt_hdmi_tables[0].clock_rate; } m2div_int = (pll_reg_3 & REG_GENMASK(14, 5)) >> 5; temp0 = ((u64)m2div_frac * REF_CLK_KHZ) >> 32; @@ -1779,16 +1796,16 @@ int intel_lt_phy_pll_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { - const struct intel_lt_phy_pll_state * const *tables; + const struct intel_lt_phy_pll_params *tables; int i; tables = intel_lt_phy_pll_tables_get(crtc_state, encoder); if (!tables) return -EINVAL; - for (i = 0; tables[i]; i++) { - if (crtc_state->port_clock == tables[i]->clock) { - crtc_state->dpll_hw_state.ltpll = *tables[i]; + for (i = 0; tables[i].name; i++) { + if (crtc_state->port_clock == tables[i].clock_rate) { + crtc_state->dpll_hw_state.ltpll = *tables[i].state; if (intel_crtc_has_dp_encoder(crtc_state)) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) crtc_state->dpll_hw_state.ltpll.config[2] = 1; -- cgit v1.2.3 From 920fa5d920c362a2e57ffec7bb39b5c25bc59610 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:49 +0000 Subject: drm/i915/display: Add helper function for fuzzy clock check The hard coded clock rate stored in the PLL state will be removed by a follow-up change. The clock is calculated instead of using clock from the PLL divider values. Since this calculated clock may vary due to fixed point rounding issues, a +-1 kHz variation is allowed with the request clock rate against the calculated clock rate. v2: - Use the stricter +-1 kHz allowed difference. - Derive the clock from PLL dividers in intel_cx0pll_enable(). - Move corresponding fuzzy check for LT PHY PLLs to this patch. v3: Reword commit message (Suraj) Move clock check to intel_dpll and rename it (Suraj) Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-9-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 22 ++++++++++++++++++---- drivers/gpu/drm/i915/display/intel_dpll.c | 5 +++++ drivers/gpu/drm/i915/display/intel_dpll.h | 1 + drivers/gpu/drm/i915/display/intel_lt_phy.c | 7 ++++++- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 8e780480f6c0..26d3d41d41a7 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -18,6 +18,7 @@ #include "intel_display_types.h" #include "intel_display_utils.h" #include "intel_dp.h" +#include "intel_dpll.h" #include "intel_hdmi.h" #include "intel_lt_phy.h" #include "intel_panel.h" @@ -2224,7 +2225,10 @@ static int intel_c10pll_calc_state_from_table(struct intel_encoder *encoder, int i; for (i = 0; tables[i].name; i++) { - if (port_clock == tables[i].clock_rate) { + int clock = intel_c10pll_calc_port_clock(tables[i].c10); + + drm_WARN_ON(display->drm, !intel_dpll_clock_matches(clock, tables[i].clock_rate)); + if (intel_dpll_clock_matches(port_clock, clock)) { pll_state->c10 = *tables[i].c10; intel_cx0pll_update_ssc(encoder, pll_state, is_dp); intel_c10pll_update_pll(encoder, pll_state); @@ -2710,6 +2714,7 @@ static const struct intel_cx0pll_params * intel_c20_pll_find_table(const struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { + struct intel_display *display = to_intel_display(crtc_state); const struct intel_cx0pll_params *tables; int i; @@ -2717,9 +2722,13 @@ intel_c20_pll_find_table(const struct intel_crtc_state *crtc_state, if (!tables) return NULL; - for (i = 0; tables[i].name; i++) - if (crtc_state->port_clock == tables[i].clock_rate) + for (i = 0; tables[i].name; i++) { + int clock = intel_c20pll_calc_port_clock(tables[i].c20); + + drm_WARN_ON(display->drm, !intel_dpll_clock_matches(clock, tables[i].clock_rate)); + if (intel_dpll_clock_matches(crtc_state->port_clock, clock)) return &tables[i]; + } return NULL; } @@ -3255,7 +3264,6 @@ static u32 intel_cx0_get_pclk_pll_ack(u8 lane_mask) static void intel_cx0pll_enable(struct intel_encoder *encoder, const struct intel_cx0pll_state *pll_state) { - int port_clock = pll_state->use_c10 ? pll_state->c10.clock : pll_state->c20.clock; struct intel_display *display = to_intel_display(encoder); enum phy phy = intel_encoder_to_phy(encoder); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); @@ -3263,6 +3271,12 @@ static void intel_cx0pll_enable(struct intel_encoder *encoder, u8 maxpclk_lane = lane_reversal ? INTEL_CX0_LANE1 : INTEL_CX0_LANE0; struct ref_tracker *wakeref = intel_cx0_phy_transaction_begin(encoder); + int port_clock; + + if (pll_state->use_c10) + port_clock = intel_c10pll_calc_port_clock(&pll_state->c10); + else + port_clock = intel_c20pll_calc_port_clock(&pll_state->c20); /* * Lane reversal is never used in DP-alt mode, in that case the diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 1b5b18fa0a36..8433e3ff0319 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -2334,3 +2334,8 @@ void assert_pll_disabled(struct intel_display *display, enum pipe pipe) { assert_pll(display, pipe, false); } + +bool intel_dpll_clock_matches(int clock1, int clock2) +{ + return abs(clock1 - clock2) <= 1; +} diff --git a/drivers/gpu/drm/i915/display/intel_dpll.h b/drivers/gpu/drm/i915/display/intel_dpll.h index 3444a2dd3166..8cd0d17e974e 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.h +++ b/drivers/gpu/drm/i915/display/intel_dpll.h @@ -48,5 +48,6 @@ void chv_crtc_clock_get(struct intel_crtc_state *crtc_state); void assert_pll_enabled(struct intel_display *display, enum pipe pipe); void assert_pll_disabled(struct intel_display *display, enum pipe pipe); +bool intel_dpll_clock_matches(int clock1, int clock2); #endif diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c index a86ae6139ff0..2790caba5457 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.c +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c @@ -14,6 +14,7 @@ #include "intel_display.h" #include "intel_display_types.h" #include "intel_display_utils.h" +#include "intel_dpll.h" #include "intel_dpll_mgr.h" #include "intel_hdmi.h" #include "intel_lt_phy.h" @@ -1796,6 +1797,7 @@ int intel_lt_phy_pll_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { + struct intel_display *display = to_intel_display(crtc_state); const struct intel_lt_phy_pll_params *tables; int i; @@ -1804,7 +1806,10 @@ intel_lt_phy_pll_calc_state(struct intel_crtc_state *crtc_state, return -EINVAL; for (i = 0; tables[i].name; i++) { - if (crtc_state->port_clock == tables[i].clock_rate) { + int clock = intel_lt_phy_calc_port_clock(display, tables[i].state); + + drm_WARN_ON(display->drm, !intel_dpll_clock_matches(clock, tables[i].clock_rate)); + if (intel_dpll_clock_matches(crtc_state->port_clock, clock)) { crtc_state->dpll_hw_state.ltpll = *tables[i].state; if (intel_crtc_has_dp_encoder(crtc_state)) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) -- cgit v1.2.3 From 6af62d12317f369f96b0f272e9e074372d09e89d Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:50 +0000 Subject: drm/i915/cx0: Fix HDMI FRL clock rates HDMI FRL clock rates are incorrectly defined. Fix these rates. Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-10-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 26d3d41d41a7..eda0e176b8be 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -1924,7 +1924,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_594 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_300 = { - .clock = 3000000, + .clock = 300000, .tx = { 0xbe98, /* tx cfg0 */ 0x8800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1949,7 +1949,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_300 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_600 = { - .clock = 6000000, + .clock = 600000, .tx = { 0xbe98, /* tx cfg0 */ 0x8800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1974,7 +1974,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_600 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_800 = { - .clock = 8000000, + .clock = 800000, .tx = { 0xbe98, /* tx cfg0 */ 0x8800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1999,7 +1999,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_800 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { - .clock = 10000000, + .clock = 1000000, .tx = { 0xbe98, /* tx cfg0 */ 0x8800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -2024,7 +2024,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_1200 = { - .clock = 12000000, + .clock = 1200000, .tx = { 0xbe98, /* tx cfg0 */ 0x8800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ -- cgit v1.2.3 From 50ad932880feaf6a526e0cfc314a4caf83310cd3 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:51 +0000 Subject: drm/i915/cx0: Add a fuzzy check for DP/HDMI clock rates during programming Since the clock rate is derived from the PLL divider values it can have a +-1kHz difference wrt. the reference rates in the comparison Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-11-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 8 +++++++- drivers/gpu/drm/i915/display/intel_hdmi.c | 19 +++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index eda0e176b8be..3b56d25c8db8 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -3012,6 +3012,12 @@ static void intel_c20_pll_program(struct intel_display *display, MB_WRITE_COMMITTED); } +static bool is_mplla_clock_rate(int clock) +{ + return intel_dpll_clock_matches(clock, 1000000) || + intel_dpll_clock_matches(clock, 2000000); +} + static void intel_program_port_clock_ctl(struct intel_encoder *encoder, const struct intel_cx0pll_state *pll_state, int port_clock, @@ -3037,7 +3043,7 @@ static void intel_program_port_clock_ctl(struct intel_encoder *encoder, /* TODO: HDMI FRL */ /* DP2.0 10G and 20G rates enable MPLLA*/ - if (port_clock == 1000000 || port_clock == 2000000) + if (is_mplla_clock_rate(port_clock)) val |= pll_state->ssc_enabled ? XELPDP_SSC_ENABLE_PLLA : 0; else val |= pll_state->ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0; diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 055e68810d0d..05e898d10a2b 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -56,6 +56,7 @@ #include "intel_display_types.h" #include "intel_display_utils.h" #include "intel_dp.h" +#include "intel_dpll.h" #include "intel_gmbus.h" #include "intel_hdcp.h" #include "intel_hdcp_regs.h" @@ -70,16 +71,14 @@ bool intel_hdmi_is_frl(u32 clock) { - switch (clock) { - case 300000: /* 3 Gbps */ - case 600000: /* 6 Gbps */ - case 800000: /* 8 Gbps */ - case 1000000: /* 10 Gbps */ - case 1200000: /* 12 Gbps */ - return true; - default: - return false; - } + u32 rates[] = { 300000, 600000, 800000, 1000000, 1200000 }; + int i; + + for (i = 0; i < ARRAY_SIZE(rates); i++) + if (intel_dpll_clock_matches(clock, rates[i])) + return true; + + return false; } static void -- cgit v1.2.3 From 58213c1d781cb4f5a4f6cadedf296dc6fc43b3a6 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:52 +0000 Subject: drm/i915/cx0: Verify C10/C20 pll dividers Add verification for pll table dividers. The port clock is computed based on pll tables and, for hdmi case, the algorithmic model is applied to calculate pll dividers. If port clock differs more than +-1 kHz from expected value an drm_warn() is thrown and pll divider differences are printed out for debugging purposes. v2: - Move clock derivation from dividers in intel_cx0pll_enable() earlier in the patchset. - Keep intel_cx0_pll_power_save_wa() in intel_dpll_sanitize_state() - Use tables[i].name != NULL as a terminating condition. - Drop duplicate intel_cx0pll_clock_matches() declaration in header. - Use state vs. params term consistently in intel_c10pll_verify_clock() and intel_c20pll_verify_clock(). Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-12-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 121 ++++++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_cx0_phy.h | 1 + drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 9 +- 3 files changed, 130 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 3b56d25c8db8..ce4b7582b737 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -3838,3 +3838,124 @@ void intel_cx0_pll_power_save_wa(struct intel_display *display) intel_cx0pll_disable(encoder); } } + +static void intel_c10pll_verify_clock(struct intel_display *display, + int precomputed_clock, + const char *pll_state_name, + const struct intel_c10pll_state *pll_state, + bool is_precomputed_state) +{ + struct drm_printer p; + int clock; + + clock = intel_c10pll_calc_port_clock(pll_state); + + if (intel_dpll_clock_matches(clock, precomputed_clock)) + return; + + drm_warn(display->drm, + "PLL state %s (%s): clock difference too high: computed %d, pre-computed %d\n", + pll_state_name, + is_precomputed_state ? "precomputed" : "computed", + clock, precomputed_clock); + + if (!drm_debug_enabled(DRM_UT_KMS)) + return; + + p = drm_dbg_printer(display->drm, DRM_UT_KMS, NULL); + + drm_printf(&p, "PLL state %s (%s):\n", + pll_state_name, + is_precomputed_state ? "precomputed" : "computed"); + intel_c10pll_dump_hw_state(&p, pll_state); +} + +static void intel_c10pll_verify_params(struct intel_display *display, + const struct intel_cx0pll_params *pll_params) +{ + struct intel_c10pll_state pll_state; + + intel_c10pll_verify_clock(display, pll_params->clock_rate, pll_params->name, pll_params->c10, true); + + if (!pll_params->is_hdmi) + return; + + intel_snps_hdmi_pll_compute_c10pll(&pll_state, pll_params->clock_rate); + + intel_c10pll_verify_clock(display, pll_params->clock_rate, pll_params->name, &pll_state, false); +} + +static void intel_c20pll_verify_clock(struct intel_display *display, + int precomputed_clock, + const char *pll_state_name, + const struct intel_c20pll_state *pll_state, + bool is_precomputed_state) +{ + struct drm_printer p; + int clock; + + clock = intel_c20pll_calc_port_clock(pll_state); + + if (intel_dpll_clock_matches(clock, precomputed_clock)) + return; + + drm_warn(display->drm, + "PLL state %s (%s): clock difference too high: computed %d, pre-computed %d\n", + pll_state_name, + is_precomputed_state ? "precomputed" : "computed", + clock, precomputed_clock); + + if (!drm_debug_enabled(DRM_UT_KMS)) + return; + + p = drm_dbg_printer(display->drm, DRM_UT_KMS, NULL); + + drm_printf(&p, "PLL state %s (%s):\n", + pll_state_name, + is_precomputed_state ? "precomputed" : "computed"); + intel_c20pll_dump_hw_state(&p, pll_state); +} + +static void intel_c20pll_verify_params(struct intel_display *display, + const struct intel_cx0pll_params *pll_params) +{ + struct intel_c20pll_state pll_state; + + intel_c20pll_verify_clock(display, pll_params->clock_rate, pll_params->name, pll_params->c20, true); + + if (!pll_params->is_hdmi) + return; + + if (intel_c20_compute_hdmi_tmds_pll(display, pll_params->clock_rate, &pll_state) != 0) + return; + + intel_c20pll_verify_clock(display, pll_params->clock_rate, pll_params->name, &pll_state, false); +} + +static void intel_cx0pll_verify_tables(struct intel_display *display, + const struct intel_cx0pll_params *tables) +{ + int i; + + for (i = 0; tables[i].name; i++) { + if (tables[i].is_c10) + intel_c10pll_verify_params(display, &tables[i]); + else + intel_c20pll_verify_params(display, &tables[i]); + } +} + +void intel_cx0pll_verify_plls(struct intel_display *display) +{ + /* C10 */ + intel_cx0pll_verify_tables(display, mtl_c10_edp_tables); + intel_cx0pll_verify_tables(display, mtl_c10_dp_tables); + intel_cx0pll_verify_tables(display, mtl_c10_hdmi_tables); + + /* C20 */ + intel_cx0pll_verify_tables(display, xe2hpd_c20_edp_tables); + intel_cx0pll_verify_tables(display, mtl_c20_dp_tables); + intel_cx0pll_verify_tables(display, xe2hpd_c20_dp_tables); + intel_cx0pll_verify_tables(display, xe3lpd_c20_dp_edp_tables); + intel_cx0pll_verify_tables(display, mtl_c20_hdmi_tables); +} diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index ae98ac23ea22..347fdbc0af73 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -77,6 +77,7 @@ bool intel_mtl_tbt_pll_readout_hw_state(struct intel_display *display, struct intel_dpll_hw_state *hw_state); int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder); +void intel_cx0pll_verify_plls(struct intel_display *display); void intel_cx0_pll_power_save_wa(struct intel_display *display); void intel_lnl_mac_transmit_lfps(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 9aa84a430f09..7127bc2a0898 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -4613,7 +4613,7 @@ void intel_dpll_init(struct intel_display *display) dpll_mgr = &pch_pll_mgr; if (!dpll_mgr) - return; + goto out_verify; dpll_info = dpll_mgr->dpll_info; @@ -4632,6 +4632,13 @@ void intel_dpll_init(struct intel_display *display) display->dpll.mgr = dpll_mgr; display->dpll.num_dpll = i; + +out_verify: + /* + * TODO: Convert these to a KUnit test or dependent on a kconfig + * debug option. + */ + intel_cx0pll_verify_plls(display); } /** -- cgit v1.2.3 From 10d187b3560a45e6cf829a9c52ee54c6dfb42f3a Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:53 +0000 Subject: drm/i915/lt_phy: Add verification for lt phy pll dividers Add verification for lt phy pll dividers during boot. The port clock is calculated from pll dividers and compared against the requested port clock value. If there are a difference exceeding +-1 kHz an drm_warn() is thrown out to indicate possible pll divider mismatch. v2: - Move the LT_PHY_PLL_PARAMS -> LT_PHY_PLL_DP/HDMI_PARAMS change earlier. - Use tables[i].name != NULL as a terminating condition. - Use state vs. params term consistently in intel_c10pll_verify_clock() and intel_c20pll_verify_clock(). Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-13-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 2 + drivers/gpu/drm/i915/display/intel_lt_phy.c | 63 +++++++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_lt_phy.h | 1 + 3 files changed, 66 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 7127bc2a0898..f35a9252f4e1 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -38,6 +38,7 @@ #include "intel_dpll.h" #include "intel_dpll_mgr.h" #include "intel_hti.h" +#include "intel_lt_phy.h" #include "intel_mg_phy_regs.h" #include "intel_pch_refclk.h" #include "intel_step.h" @@ -4639,6 +4640,7 @@ out_verify: * debug option. */ intel_cx0pll_verify_plls(display); + intel_lt_phy_verify_plls(display); } /** diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c index 2790caba5457..dbe2b2dc9887 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.c +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c @@ -2337,3 +2337,66 @@ void intel_xe3plpd_pll_disable(struct intel_encoder *encoder) intel_lt_phy_pll_disable(encoder); } + +static void intel_lt_phy_pll_verify_clock(struct intel_display *display, + int precomputed_clock, + const char *pll_state_name, + const struct intel_lt_phy_pll_state *pll_state, + bool is_precomputed_state) +{ + struct drm_printer p; + int clock; + + clock = intel_lt_phy_calc_port_clock(display, pll_state); + + if (intel_dpll_clock_matches(clock, precomputed_clock)) + return; + + drm_warn(display->drm, + "PLL state %s (%s): clock difference too high: computed %d, pre-computed %d\n", + pll_state_name, + is_precomputed_state ? "precomputed" : "computed", + clock, precomputed_clock); + + if (!drm_debug_enabled(DRM_UT_KMS)) + return; + + p = drm_dbg_printer(display->drm, DRM_UT_KMS, NULL); + + drm_printf(&p, "PLL state %s (%s):\n", + pll_state_name, + is_precomputed_state ? "precomputed" : "computed"); + intel_lt_phy_dump_hw_state(display, pll_state); +} + +static void intel_lt_phy_pll_verify_params(struct intel_display *display, + const struct intel_lt_phy_pll_params *pll_params) +{ + struct intel_lt_phy_pll_state pll_state; + + intel_lt_phy_pll_verify_clock(display, pll_params->clock_rate, pll_params->name, pll_params->state, true); + + if (!pll_params->is_hdmi) + return; + + if (intel_lt_phy_calculate_hdmi_state(&pll_state, pll_params->clock_rate) != 0) + return; + + intel_lt_phy_pll_verify_clock(display, pll_params->clock_rate, pll_params->name, &pll_state, false); +} + +static void intel_lt_phy_pll_verify_tables(struct intel_display *display, + const struct intel_lt_phy_pll_params *tables) +{ + int i; + + for (i = 0; tables[i].name; i++) + intel_lt_phy_pll_verify_params(display, &tables[i]); +} + +void intel_lt_phy_verify_plls(struct intel_display *display) +{ + intel_lt_phy_pll_verify_tables(display, xe3plpd_lt_dp_tables); + intel_lt_phy_pll_verify_tables(display, xe3plpd_lt_edp_tables); + intel_lt_phy_pll_verify_tables(display, xe3plpd_lt_hdmi_tables); +} diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.h b/drivers/gpu/drm/i915/display/intel_lt_phy.h index 22b12d2d5bb1..db905668f86d 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.h +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.h @@ -41,5 +41,6 @@ intel_lt_phy_calculate_hdmi_state(struct intel_lt_phy_pll_state *lt_state, void intel_xe3plpd_pll_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_xe3plpd_pll_disable(struct intel_encoder *encoder); +void intel_lt_phy_verify_plls(struct intel_display *display); #endif /* __INTEL_LT_PHY_H__ */ -- cgit v1.2.3 From 4fa244583e77fba2388f05a44f400f44f79da396 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:54 +0000 Subject: drm/i915/cx0: Drop C20 25.175 MHz rate Drop C20 25.175 MHz PLL table as with these PLL dividers the port clock will be incorrectly calculated to 25.2 MHz. For 25.175 MHz rate the PLl dividers are calculated algorithmically making PLL table for this rate redundant. Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-14-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index ce4b7582b737..a0af7d3e87b6 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -1798,31 +1798,6 @@ static const struct intel_cx0pll_params mtl_c10_hdmi_tables[] = { {} }; -static const struct intel_c20pll_state mtl_c20_hdmi_25_175 = { - .clock = 25175, - .tx = { 0xbe88, /* tx cfg0 */ - 0x9800, /* tx cfg1 */ - 0x0000, /* tx cfg2 */ - }, - .cmn = { 0x0500, /* cmn cfg0*/ - 0x0005, /* cmn cfg1 */ - 0x0000, /* cmn cfg2 */ - 0x0000, /* cmn cfg3 */ - }, - .mpllb = { 0xa0d2, /* mpllb cfg0 */ - 0x7d80, /* mpllb cfg1 */ - 0x0906, /* mpllb cfg2 */ - 0xbe40, /* mpllb cfg3 */ - 0x0000, /* mpllb cfg4 */ - 0x0000, /* mpllb cfg5 */ - 0x0200, /* mpllb cfg6 */ - 0x0001, /* mpllb cfg7 */ - 0x0000, /* mpllb cfg8 */ - 0x0000, /* mpllb cfg9 */ - 0x0001, /* mpllb cfg10 */ - }, -}; - static const struct intel_c20pll_state mtl_c20_hdmi_27_0 = { .clock = 27000, .tx = { 0xbe88, /* tx cfg0 */ @@ -2049,7 +2024,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1200 = { }; static const struct intel_cx0pll_params mtl_c20_hdmi_tables[] = { - C20PLL_HDMI_PARAMS(25175, mtl_c20_hdmi_25_175), C20PLL_HDMI_PARAMS(27000, mtl_c20_hdmi_27_0), C20PLL_HDMI_PARAMS(74250, mtl_c20_hdmi_74_25), C20PLL_HDMI_PARAMS(148500, mtl_c20_hdmi_148_5), -- cgit v1.2.3 From 1b85f96de24fd91274e46614c9d9d2a274dafe46 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:55 +0000 Subject: drm/i915/lt_phy: Drop 27.2 MHz rate Drop 27.2 MHz PLL table as with these PLL dividers the port clock will be incorrectly calculated to 27.0 MHz. For 27.2 MHz rate the PLl dividers are calculated algorithmically making PLL table for this rate redundant. Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-15-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_lt_phy.c | 55 ----------------------------- 1 file changed, 55 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c index dbe2b2dc9887..a3326057449a 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.c +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c @@ -803,60 +803,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_252 = { }, }; -static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_272 = { - .clock = 27200, - .config = { - 0x84, - 0x2d, - 0x0, - }, - .addr_msb = { - 0x87, - 0x87, - 0x87, - 0x87, - 0x88, - 0x88, - 0x88, - 0x88, - 0x88, - 0x88, - 0x88, - 0x88, - 0x88, - }, - .addr_lsb = { - 0x10, - 0x0c, - 0x14, - 0xe4, - 0x0c, - 0x10, - 0x14, - 0x18, - 0x48, - 0x40, - 0x4c, - 0x24, - 0x44, - }, - .data = { - { 0x0, 0x4c, 0x2, 0x0 }, - { 0x0b, 0x15, 0x26, 0xa0 }, - { 0x60, 0x0, 0x0, 0x0 }, - { 0x8, 0x4, 0x96, 0x28 }, - { 0xfa, 0x0c, 0x84, 0x11 }, - { 0x80, 0x0f, 0xd9, 0x53 }, - { 0x86, 0x0, 0x0, 0x0 }, - { 0x1, 0xa0, 0x1, 0x0 }, - { 0x4b, 0x0, 0x0, 0x0 }, - { 0x28, 0x0, 0x0, 0x0 }, - { 0x0, 0x14, 0x2a, 0x14 }, - { 0x0, 0x0, 0x0, 0x0 }, - { 0x0, 0x0, 0x0, 0x0 }, - }, -}; - static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_742p5 = { .clock = 74250, .config = { @@ -1021,7 +967,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_5p94 = { static const struct intel_lt_phy_pll_params xe3plpd_lt_hdmi_tables[] = { LT_PHY_PLL_HDMI_PARAMS(25200, xe3plpd_lt_hdmi_252), - LT_PHY_PLL_HDMI_PARAMS(27200, xe3plpd_lt_hdmi_272), LT_PHY_PLL_HDMI_PARAMS(74250, xe3plpd_lt_hdmi_742p5), LT_PHY_PLL_HDMI_PARAMS(148500, xe3plpd_lt_hdmi_1p485), LT_PHY_PLL_HDMI_PARAMS(594000, xe3plpd_lt_hdmi_5p94), -- cgit v1.2.3 From 301929e3628bd8afc8919123e63763cefd14ce89 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 19 Jan 2026 09:37:56 +0000 Subject: drm/i915/display: Remove .clock member from eDP/DP/HDMI pll tables PLL state structure has a member .clock. This is not needed as the port clock is possible to calculate from the pll dividers. Remove the encoder from being passed to the port clock calculation function. v2: Keep the pll_state->clock assignment in intel_snps_hdmi_pll_compute_mpllb(). Signed-off-by: Mika Kahola Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260119093757.2850233-16-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 86 +--------------------- drivers/gpu/drm/i915/display/intel_dpll_mgr.h | 3 - drivers/gpu/drm/i915/display/intel_lt_phy.c | 21 +----- drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c | 2 - 4 files changed, 3 insertions(+), 109 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index a0af7d3e87b6..4f56a370102d 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -548,7 +548,6 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, */ static const struct intel_c10pll_state mtl_c10_dp_rbr = { - .clock = 162000, .tx = 0x10, .cmn = 0x21, .pll[0] = 0xB4, @@ -574,7 +573,6 @@ static const struct intel_c10pll_state mtl_c10_dp_rbr = { }; static const struct intel_c10pll_state mtl_c10_edp_r216 = { - .clock = 216000, .tx = 0x10, .cmn = 0x21, .pll[0] = 0x4, @@ -600,7 +598,6 @@ static const struct intel_c10pll_state mtl_c10_edp_r216 = { }; static const struct intel_c10pll_state mtl_c10_edp_r243 = { - .clock = 243000, .tx = 0x10, .cmn = 0x21, .pll[0] = 0x34, @@ -626,7 +623,6 @@ static const struct intel_c10pll_state mtl_c10_edp_r243 = { }; static const struct intel_c10pll_state mtl_c10_dp_hbr1 = { - .clock = 270000, .tx = 0x10, .cmn = 0x21, .pll[0] = 0xF4, @@ -652,7 +648,6 @@ static const struct intel_c10pll_state mtl_c10_dp_hbr1 = { }; static const struct intel_c10pll_state mtl_c10_edp_r324 = { - .clock = 324000, .tx = 0x10, .cmn = 0x21, .pll[0] = 0xB4, @@ -678,7 +673,6 @@ static const struct intel_c10pll_state mtl_c10_edp_r324 = { }; static const struct intel_c10pll_state mtl_c10_edp_r432 = { - .clock = 432000, .tx = 0x10, .cmn = 0x21, .pll[0] = 0x4, @@ -704,7 +698,6 @@ static const struct intel_c10pll_state mtl_c10_edp_r432 = { }; static const struct intel_c10pll_state mtl_c10_dp_hbr2 = { - .clock = 540000, .tx = 0x10, .cmn = 0x21, .pll[0] = 0xF4, @@ -730,7 +723,6 @@ static const struct intel_c10pll_state mtl_c10_dp_hbr2 = { }; static const struct intel_c10pll_state mtl_c10_edp_r675 = { - .clock = 675000, .tx = 0x10, .cmn = 0x21, .pll[0] = 0xB4, @@ -756,7 +748,6 @@ static const struct intel_c10pll_state mtl_c10_edp_r675 = { }; static const struct intel_c10pll_state mtl_c10_dp_hbr3 = { - .clock = 810000, .tx = 0x10, .cmn = 0x21, .pll[0] = 0x34, @@ -837,7 +828,6 @@ static const struct intel_cx0pll_params mtl_c10_edp_tables[] = { /* C20 basic DP 1.4 tables */ static const struct intel_c20pll_state mtl_c20_dp_rbr = { - .clock = 162000, .tx = { 0xbe88, /* tx cfg0 */ 0x5800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -862,7 +852,6 @@ static const struct intel_c20pll_state mtl_c20_dp_rbr = { }; static const struct intel_c20pll_state mtl_c20_dp_hbr1 = { - .clock = 270000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -887,7 +876,6 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr1 = { }; static const struct intel_c20pll_state mtl_c20_dp_hbr2 = { - .clock = 540000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -912,7 +900,6 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr2 = { }; static const struct intel_c20pll_state mtl_c20_dp_hbr3 = { - .clock = 810000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -938,7 +925,6 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr3 = { /* C20 basic DP 2.0 tables */ static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = { - .clock = 1000000, /* 10 Gbps */ .tx = { 0xbe21, /* tx cfg0 */ 0xe800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -962,7 +948,6 @@ static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = { }; static const struct intel_c20pll_state mtl_c20_dp_uhbr13_5 = { - .clock = 1350000, /* 13.5 Gbps */ .tx = { 0xbea0, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -987,7 +972,6 @@ static const struct intel_c20pll_state mtl_c20_dp_uhbr13_5 = { }; static const struct intel_c20pll_state mtl_c20_dp_uhbr20 = { - .clock = 2000000, /* 20 Gbps */ .tx = { 0xbe20, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1026,7 +1010,6 @@ static const struct intel_cx0pll_params mtl_c20_dp_tables[] = { */ static const struct intel_c20pll_state xe2hpd_c20_edp_r216 = { - .clock = 216000, .tx = { 0xbe88, 0x4800, 0x0000, @@ -1051,7 +1034,6 @@ static const struct intel_c20pll_state xe2hpd_c20_edp_r216 = { }; static const struct intel_c20pll_state xe2hpd_c20_edp_r243 = { - .clock = 243000, .tx = { 0xbe88, 0x4800, 0x0000, @@ -1076,7 +1058,6 @@ static const struct intel_c20pll_state xe2hpd_c20_edp_r243 = { }; static const struct intel_c20pll_state xe2hpd_c20_edp_r324 = { - .clock = 324000, .tx = { 0xbe88, 0x4800, 0x0000, @@ -1101,7 +1082,6 @@ static const struct intel_c20pll_state xe2hpd_c20_edp_r324 = { }; static const struct intel_c20pll_state xe2hpd_c20_edp_r432 = { - .clock = 432000, .tx = { 0xbe88, 0x4800, 0x0000, @@ -1126,7 +1106,6 @@ static const struct intel_c20pll_state xe2hpd_c20_edp_r432 = { }; static const struct intel_c20pll_state xe2hpd_c20_edp_r675 = { - .clock = 675000, .tx = { 0xbe88, 0x4800, 0x0000, @@ -1164,7 +1143,6 @@ static const struct intel_cx0pll_params xe2hpd_c20_edp_tables[] = { }; static const struct intel_c20pll_state xe2hpd_c20_dp_uhbr13_5 = { - .clock = 1350000, /* 13.5 Gbps */ .tx = { 0xbea0, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1219,7 +1197,6 @@ static const struct intel_cx0pll_params xe3lpd_c20_dp_edp_tables[] = { */ static const struct intel_c10pll_state mtl_c10_hdmi_25_2 = { - .clock = 25200, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x4, @@ -1245,7 +1222,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_25_2 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_27_0 = { - .clock = 27000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, @@ -1271,7 +1247,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_27_0 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_74_25 = { - .clock = 74250, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, @@ -1297,7 +1272,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_74_25 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_148_5 = { - .clock = 148500, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, @@ -1323,7 +1297,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_148_5 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_594 = { - .clock = 594000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, @@ -1350,7 +1323,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_594 = { /* Precomputed C10 HDMI PLL tables */ static const struct intel_c10pll_state mtl_c10_hdmi_27027 = { - .clock = 27027, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, .pll[1] = 0x00, .pll[2] = 0xC0, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1360,7 +1332,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_27027 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_28320 = { - .clock = 28320, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x04, .pll[1] = 0x00, .pll[2] = 0xCC, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1370,7 +1341,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_28320 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_30240 = { - .clock = 30240, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x04, .pll[1] = 0x00, .pll[2] = 0xDC, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1380,7 +1350,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_30240 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_31500 = { - .clock = 31500, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x62, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1390,7 +1359,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_31500 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_36000 = { - .clock = 36000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xC4, .pll[1] = 0x00, .pll[2] = 0x76, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1400,7 +1368,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_36000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_40000 = { - .clock = 40000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xB4, .pll[1] = 0x00, .pll[2] = 0x86, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1410,7 +1377,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_40000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_49500 = { - .clock = 49500, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x74, .pll[1] = 0x00, .pll[2] = 0xAE, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1420,7 +1386,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_49500 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_50000 = { - .clock = 50000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x74, .pll[1] = 0x00, .pll[2] = 0xB0, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1430,7 +1395,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_50000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_57284 = { - .clock = 57284, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, .pll[1] = 0x00, .pll[2] = 0xCE, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1440,7 +1404,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_57284 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_58000 = { - .clock = 58000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, .pll[1] = 0x00, .pll[2] = 0xD0, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1450,7 +1413,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_58000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_65000 = { - .clock = 65000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x66, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1460,7 +1422,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_65000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_71000 = { - .clock = 71000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x72, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1470,7 +1431,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_71000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_74176 = { - .clock = 74176, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x7A, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1480,7 +1440,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_74176 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_75000 = { - .clock = 75000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x7C, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1490,7 +1449,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_75000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_78750 = { - .clock = 78750, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xB4, .pll[1] = 0x00, .pll[2] = 0x84, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1500,7 +1458,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_78750 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_85500 = { - .clock = 85500, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xB4, .pll[1] = 0x00, .pll[2] = 0x92, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1510,7 +1467,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_85500 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_88750 = { - .clock = 88750, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x74, .pll[1] = 0x00, .pll[2] = 0x98, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1520,7 +1476,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_88750 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_106500 = { - .clock = 106500, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, .pll[1] = 0x00, .pll[2] = 0xBC, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1530,7 +1485,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_106500 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_108000 = { - .clock = 108000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, .pll[1] = 0x00, .pll[2] = 0xC0, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1540,7 +1494,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_108000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_115500 = { - .clock = 115500, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, .pll[1] = 0x00, .pll[2] = 0xD0, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1550,7 +1503,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_115500 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_119000 = { - .clock = 119000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, .pll[1] = 0x00, .pll[2] = 0xD6, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1560,7 +1512,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_119000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_135000 = { - .clock = 135000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x6C, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1570,7 +1521,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_135000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_138500 = { - .clock = 138500, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x70, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1580,7 +1530,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_138500 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_147160 = { - .clock = 147160, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x78, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1590,7 +1539,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_147160 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_148352 = { - .clock = 148352, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x7A, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1600,7 +1548,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_148352 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_154000 = { - .clock = 154000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xB4, .pll[1] = 0x00, .pll[2] = 0x80, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1610,7 +1557,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_154000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_162000 = { - .clock = 162000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xB4, .pll[1] = 0x00, .pll[2] = 0x88, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1620,7 +1566,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_162000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_167000 = { - .clock = 167000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xB4, .pll[1] = 0x00, .pll[2] = 0x8C, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1630,7 +1575,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_167000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_197802 = { - .clock = 197802, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x74, .pll[1] = 0x00, .pll[2] = 0xAE, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1640,7 +1584,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_197802 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_198000 = { - .clock = 198000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x74, .pll[1] = 0x00, .pll[2] = 0xAE, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1650,7 +1593,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_198000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_209800 = { - .clock = 209800, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, .pll[1] = 0x00, .pll[2] = 0xBA, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1660,7 +1602,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_209800 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_241500 = { - .clock = 241500, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, .pll[1] = 0x00, .pll[2] = 0xDA, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1670,7 +1611,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_241500 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_262750 = { - .clock = 262750, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x68, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1680,7 +1620,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_262750 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_268500 = { - .clock = 268500, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x6A, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1690,7 +1629,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_268500 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_296703 = { - .clock = 296703, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x7A, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1700,7 +1638,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_296703 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_297000 = { - .clock = 297000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x7A, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1710,7 +1647,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_297000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_319750 = { - .clock = 319750, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xB4, .pll[1] = 0x00, .pll[2] = 0x86, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1720,7 +1656,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_319750 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_497750 = { - .clock = 497750, .tx = 0x10, .cmn = 0x1, .pll[0] = 0x34, .pll[1] = 0x00, .pll[2] = 0xE2, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1730,7 +1665,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_497750 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_592000 = { - .clock = 592000, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x7A, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1740,7 +1674,6 @@ static const struct intel_c10pll_state mtl_c10_hdmi_592000 = { }; static const struct intel_c10pll_state mtl_c10_hdmi_593407 = { - .clock = 593407, .tx = 0x10, .cmn = 0x1, .pll[0] = 0xF4, .pll[1] = 0x00, .pll[2] = 0x7A, .pll[3] = 0x00, .pll[4] = 0x00, @@ -1799,7 +1732,6 @@ static const struct intel_cx0pll_params mtl_c10_hdmi_tables[] = { }; static const struct intel_c20pll_state mtl_c20_hdmi_27_0 = { - .clock = 27000, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1824,7 +1756,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_27_0 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_74_25 = { - .clock = 74250, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1849,7 +1780,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_74_25 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_148_5 = { - .clock = 148500, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1874,7 +1804,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_148_5 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_594 = { - .clock = 594000, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1899,7 +1828,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_594 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_300 = { - .clock = 300000, .tx = { 0xbe98, /* tx cfg0 */ 0x8800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1924,7 +1852,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_300 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_600 = { - .clock = 600000, .tx = { 0xbe98, /* tx cfg0 */ 0x8800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1949,7 +1876,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_600 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_800 = { - .clock = 800000, .tx = { 0xbe98, /* tx cfg0 */ 0x8800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1974,7 +1900,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_800 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { - .clock = 1000000, .tx = { 0xbe98, /* tx cfg0 */ 0x8800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1999,7 +1924,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_1200 = { - .clock = 1200000, .tx = { 0xbe98, /* tx cfg0 */ 0x8800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -2334,8 +2258,6 @@ static void intel_c10pll_readout_hw_state(struct intel_encoder *encoder, intel_cx0_phy_transaction_end(encoder, wakeref); - pll_state->clock = intel_c10pll_calc_port_clock(pll_state); - cx0pll_state->ssc_enabled = readout_ssc_state(encoder, true); if (cx0pll_state->ssc_enabled != intel_c10pll_ssc_enabled(pll_state)) @@ -2380,8 +2302,7 @@ static void intel_c10pll_dump_hw_state(struct drm_printer *p, unsigned int multiplier, tx_clk_div; fracen = hw_state->pll[0] & C10_PLL0_FRACEN; - drm_printf(p, "c10pll_hw_state: clock: %d, fracen: %s, ", - hw_state->clock, str_yes_no(fracen)); + drm_printf(p, "c10pll_hw_state: fracen: %s, ", str_yes_no(fracen)); if (fracen) { frac_quot = hw_state->pll[12] << 8 | hw_state->pll[11]; @@ -2486,7 +2407,6 @@ static int intel_c20_compute_hdmi_tmds_pll(struct intel_display *display, else mpllb_ana_freq_vco = MPLLB_ANA_FREQ_VCO_0; - pll_state->clock = port_clock; pll_state->tx[0] = 0xbe88; pll_state->tx[1] = intel_c20_hdmi_tmds_tx_cgf_1(display); pll_state->tx[2] = 0x0000; @@ -2838,8 +2758,6 @@ static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, } } - pll_state->clock = intel_c20pll_calc_port_clock(pll_state); - intel_cx0_phy_transaction_end(encoder, wakeref); cx0pll_state->ssc_enabled = readout_ssc_state(encoder, intel_c20phy_use_mpllb(pll_state)); @@ -2850,7 +2768,7 @@ static void intel_c20pll_dump_hw_state(struct drm_printer *p, { int i; - drm_printf(p, "c20pll_hw_state: clock: %d\n", hw_state->clock); + drm_printf(p, "c20pll_hw_state:\n"); drm_printf(p, "tx[0] = 0x%.4x, tx[1] = 0x%.4x, tx[2] = 0x%.4x\n", hw_state->tx[0], hw_state->tx[1], hw_state->tx[2]); diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index 5b71c860515f..4cc14ce5eebe 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -241,14 +241,12 @@ struct intel_mpllb_state { }; struct intel_c10pll_state { - u32 clock; /* in KHz */ u8 tx; u8 cmn; u8 pll[20]; }; struct intel_c20pll_state { - u32 clock; /* in kHz */ u16 tx[3]; u16 cmn[4]; union { @@ -274,7 +272,6 @@ struct intel_cx0pll_state { }; struct intel_lt_phy_pll_state { - u32 clock; /* in kHz */ u8 addr_msb[13]; u8 addr_lsb[13]; u8 data[13][4]; diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c index a3326057449a..b4b281ef258b 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.c +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c @@ -61,7 +61,6 @@ struct lt_phy_params { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_rbr = { - .clock = 162000, .config = { 0x83, 0x2d, @@ -115,7 +114,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_rbr = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_hbr1 = { - .clock = 270000, .config = { 0x8b, 0x2d, @@ -169,7 +167,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_hbr1 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_hbr2 = { - .clock = 540000, .config = { 0x93, 0x2d, @@ -223,7 +220,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_hbr2 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_hbr3 = { - .clock = 810000, .config = { 0x9b, 0x2d, @@ -277,7 +273,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_hbr3 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_uhbr10 = { - .clock = 1000000, .config = { 0x43, 0x2d, @@ -331,7 +326,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_uhbr10 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_uhbr13_5 = { - .clock = 1350000, .config = { 0xcb, 0x2d, @@ -385,7 +379,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_uhbr13_5 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_uhbr20 = { - .clock = 2000000, .config = { 0x53, 0x2d, @@ -467,7 +460,6 @@ static const struct intel_lt_phy_pll_params xe3plpd_lt_dp_tables[] = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_2_16 = { - .clock = 216000, .config = { 0xa3, 0x2d, @@ -521,7 +513,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_2_16 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_2_43 = { - .clock = 243000, .config = { 0xab, 0x2d, @@ -575,7 +566,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_2_43 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_3_24 = { - .clock = 324000, .config = { 0xb3, 0x2d, @@ -629,7 +619,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_3_24 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_4_32 = { - .clock = 432000, .config = { 0xbb, 0x2d, @@ -683,7 +672,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_4_32 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_edp_6_75 = { - .clock = 675000, .config = { 0xdb, 0x2d, @@ -750,7 +738,6 @@ static const struct intel_lt_phy_pll_params xe3plpd_lt_edp_tables[] = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_252 = { - .clock = 25200, .config = { 0x84, 0x2d, @@ -804,7 +791,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_252 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_742p5 = { - .clock = 74250, .config = { 0x84, 0x2d, @@ -858,7 +844,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_742p5 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_1p485 = { - .clock = 148500, .config = { 0x84, 0x2d, @@ -912,7 +897,6 @@ static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_1p485 = { }; static const struct intel_lt_phy_pll_state xe3plpd_lt_hdmi_5p94 = { - .clock = 594000, .config = { 0x84, 0x2d, @@ -1732,7 +1716,7 @@ intel_lt_phy_calc_port_clock(struct intel_display *display, clk = intel_lt_phy_calc_hdmi_port_clock(display, lt_state); } else { drm_WARN_ON(display->drm, "Unsupported LT PHY Mode!\n"); - clk = xe3plpd_lt_hdmi_252.clock; + clk = 25200; } return clk; @@ -2192,7 +2176,6 @@ void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, struct intel_lt_phy_pll_state *pll_state) { - struct intel_display *display = to_intel_display(encoder); u8 owned_lane_mask; u8 lane; struct ref_tracker *wakeref; @@ -2217,8 +2200,6 @@ void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, LT_PHY_VDR_X_DATAY(i, j)); } - pll_state->clock = - intel_lt_phy_calc_port_clock(display, &crtc_state->dpll_hw_state.ltpll); intel_lt_phy_transaction_end(encoder, wakeref); } diff --git a/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c b/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c index a201edceee10..7fe6b4a18213 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c +++ b/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c @@ -332,8 +332,6 @@ void intel_snps_hdmi_pll_compute_c10pll(struct intel_c10pll_state *pll_state, u6 c10_curve_1, c10_curve_2, prescaler_divider, &pll_params); - pll_state->clock = pixel_clock; - pll_state->tx = 0x10; pll_state->cmn = 0x1; pll_state->pll[0] = REG_FIELD_PREP(C10_PLL0_DIV5CLK_EN, pll_params.mpll_div5_en) | -- cgit v1.2.3 From 6695dc279820a50cb20ecd8b5250e05234dac780 Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Wed, 7 Jan 2026 16:29:36 +0000 Subject: drm/i915/display: Prevent u64 underflow in intel_fbc_stolen_end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Static analysis reveals a potential integer underflow in intel_fbc_stolen_end. This can apparently occur if intel_parent_stolen_area_size returns zero (or, theoretically, any value less than 2^23), as 2^23 is subtracted from the return value and stored in a u64. While this doesn't appear to cause any issues due to the use of the min() function to clamp the return values from the intel_fbc_stolen_end function, it would be best practice to avoid undeflowing values like this on principle. So, rework the function to prevent the underflow from occurring. Note that the underflow at present would result in the value of intel_fbc_cfb_base_max being returned at the end of intel_fbc_stolen_end, so just return that if the value of intel_parent_stolen_area_size is too small. While we're here, fix the other comments here and modify the execution path for readability. v2: (Jani) - Fix the comments in intel_fbc_stolen_end - Use check_sub_overflow - Remove macro that mirrors SZ_8M, as it is now only referenced once - Misc. formatting fixes Fixes: a9da512b3ed7 ("drm/i915: avoid the last 8mb of stolen on BDW/SKL") Signed-off-by: Jonathan Cavitt Cc: Paulo Zanoni Cc: Ville Syrjälä Cc: Daniel Vetter Reviewed-by: Jani Nikula Link: https://patch.msgid.link/20260107162935.8123-2-jonathan.cavitt@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/i915/display/intel_fbc.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index fef2f35ff1e9..1f3f5237a1c2 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -809,19 +809,32 @@ static u64 intel_fbc_cfb_base_max(struct intel_display *display) static u64 intel_fbc_stolen_end(struct intel_display *display) { - u64 end; + u64 end = intel_fbc_cfb_base_max(display); - /* The FBC hardware for BDW/SKL doesn't have access to the stolen + /* + * The FBC hardware for BDW/SKL doesn't have access to the stolen * reserved range size, so it always assumes the maximum (8mb) is used. * If we enable FBC using a CFB on that memory range we'll get FIFO - * underruns, even if that range is not reserved by the BIOS. */ + * underruns, even if that range is not reserved by the BIOS. + */ if (display->platform.broadwell || - (DISPLAY_VER(display) == 9 && !display->platform.broxton)) - end = intel_parent_stolen_area_size(display) - 8 * 1024 * 1024; - else - end = U64_MAX; + (DISPLAY_VER(display) == 9 && !display->platform.broxton)) { + u64 stolen_area_size = intel_parent_stolen_area_size(display); + + /* + * If stolen_area_size is less than SZ_8M, use + * intel_fbc_cfb_base_max instead. This should not happen, + * so warn if it does. + */ + if (drm_WARN_ON(display->drm, + check_sub_overflow(stolen_area_size, + SZ_8M, &stolen_area_size))) + return end; + + return min(end, stolen_area_size); + } - return min(end, intel_fbc_cfb_base_max(display)); + return end; } static int intel_fbc_min_limit(const struct intel_plane_state *plane_state) -- cgit v1.2.3 From 37d5f4da49821cd542561d5cfffea35d32f5bef6 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 14 Jan 2026 08:24:56 +0530 Subject: drm/i915/gvt_mmio_table: Use the gvt versions of the display macros Include gvt/display_helpers.h so that the display register macros in intel_gvt_mmio_table.c expand through the exported display functions. This lets us keep the existing macro calls while avoiding direct access to display internals, helping the display modularization work. Signed-off-by: Ankit Nautiyal Reviewed-by: Jani Nikula Link: https://patch.msgid.link/20260114025456.1639171-1-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/intel_gvt_mmio_table.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c index 478d00f89a4b..052596ac83a0 100644 --- a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c +++ b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c @@ -11,12 +11,12 @@ #include "display/intel_color_regs.h" #include "display/intel_crt_regs.h" #include "display/intel_cursor_regs.h" -#include "display/intel_display_core.h" #include "display/intel_display_regs.h" #include "display/intel_display_types.h" #include "display/intel_dmc_regs.h" #include "display/intel_dp_aux_regs.h" #include "display/intel_dpio_phy.h" +#include "display/intel_fbc.h" #include "display/intel_fbc_regs.h" #include "display/intel_fdi_regs.h" #include "display/intel_lvds_regs.h" @@ -32,6 +32,7 @@ #include "gt/intel_engine_regs.h" #include "gt/intel_gt_regs.h" +#include "gvt/display_helpers.h" #include "gvt/reg.h" #include "i915_drv.h" -- cgit v1.2.3 From 70ea362b84449b7061cefd63a532f648d2919916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:19 +0200 Subject: drm/i915/vga: Register vgaarb client later MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we register to vgaarb way too early. Thus it is possible that the entire VGA decode logic gets nuked via GMCH_CTRL before intel_vga_disable() has even disabled the VGA plane. This could even cause a system hang because we'll be unable to turn off the VGA plane gracefully. Move the vgaarb registration into intel_display_driver_register(). I suppose we could do it a bit earlier (after intel_vga_disable()), but not convinced there's any point. Also the error handling here is pointless since the registration can't fail (unless the device isn't a VGA class in which case all VGA decode logic should aleady be disabled by the BIOS via GMCH_CTRL). But let's toss in a WARN to catch any future breakage of vga_client_register(). Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display_driver.c | 18 +++++++----------- drivers/gpu/drm/i915/display/intel_vga.c | 7 ++----- drivers/gpu/drm/i915/display/intel_vga.h | 2 +- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 268b1de45b81..967da2b41316 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -208,16 +208,12 @@ int intel_display_driver_probe_noirq(struct intel_display *display) intel_bios_init(display); - ret = intel_vga_register(display); - if (ret) - goto cleanup_bios; - intel_psr_dc5_dc6_wa_init(display); /* FIXME: completely on the wrong abstraction layer */ ret = intel_power_domains_init(display); if (ret < 0) - goto cleanup_vga; + goto cleanup_bios; intel_pmdemand_init_early(display); @@ -229,7 +225,7 @@ int intel_display_driver_probe_noirq(struct intel_display *display) display->hotplug.dp_wq = alloc_ordered_workqueue("intel-dp", 0); if (!display->hotplug.dp_wq) { ret = -ENOMEM; - goto cleanup_vga_client_pw_domain_dmc; + goto cleanup_pw_domain_dmc; } display->wq.modeset = alloc_ordered_workqueue("i915_modeset", 0); @@ -301,11 +297,9 @@ cleanup_wq_modeset: destroy_workqueue(display->wq.modeset); cleanup_wq_dp: destroy_workqueue(display->hotplug.dp_wq); -cleanup_vga_client_pw_domain_dmc: +cleanup_pw_domain_dmc: intel_dmc_fini(display); intel_power_domains_driver_remove(display); -cleanup_vga: - intel_vga_unregister(display); cleanup_bios: intel_bios_driver_remove(display); @@ -554,6 +548,8 @@ void intel_display_driver_register(struct intel_display *display) if (!HAS_DISPLAY(display)) return; + intel_vga_register(display); + /* Must be done after probing outputs */ intel_opregion_register(display); intel_acpi_video_register(display); @@ -646,8 +642,6 @@ void intel_display_driver_remove_nogem(struct intel_display *display) intel_power_domains_driver_remove(display); - intel_vga_unregister(display); - intel_bios_driver_remove(display); } @@ -675,6 +669,8 @@ void intel_display_driver_unregister(struct intel_display *display) acpi_video_unregister(); intel_opregion_unregister(display); + + intel_vga_unregister(display); } /* diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index c45c4bbc3f95..f13734cfd904 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -135,7 +135,7 @@ static unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_ return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; } -int intel_vga_register(struct intel_display *display) +void intel_vga_register(struct intel_display *display) { struct pci_dev *pdev = to_pci_dev(display->drm->dev); @@ -150,10 +150,7 @@ int intel_vga_register(struct intel_display *display) * vga_client_register() fails with -ENODEV. */ ret = vga_client_register(pdev, intel_gmch_vga_set_decode); - if (ret && ret != -ENODEV) - return ret; - - return 0; + drm_WARN_ON(display->drm, ret && ret != -ENODEV); } void intel_vga_unregister(struct intel_display *display) diff --git a/drivers/gpu/drm/i915/display/intel_vga.h b/drivers/gpu/drm/i915/display/intel_vga.h index 16d699f3b641..80084265c6cd 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.h +++ b/drivers/gpu/drm/i915/display/intel_vga.h @@ -10,7 +10,7 @@ struct intel_display; void intel_vga_reset_io_mem(struct intel_display *display); void intel_vga_disable(struct intel_display *display); -int intel_vga_register(struct intel_display *display); +void intel_vga_register(struct intel_display *display); void intel_vga_unregister(struct intel_display *display); #endif /* __INTEL_VGA_H__ */ -- cgit v1.2.3 From 4d71ff25f3a027ed3acbb186d2208113d0e1ec82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:20 +0200 Subject: drm/i915/vga: Get rid of intel_vga_reset_io_mem() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the MSR VGA register access from the power well hook, and just do it once in intel_vga_disable(). Turns out that the hardware has two levels of MDA vs. CGA decode logic: GPU level and display engine level. When we write the MSR register MDA/CGA mode selection bit both decode logics are updated accordingly, so that whichever register accessed the GPU claims will also be claimed by the display engine on the RMbus. If the two get out of sync the GPU will claim the register accesses but the display engine will not, leading to RMbus NoClaim errors. The way to get the two decode logics out of sync is by resetting the power well housing the VGA stuff, while we are in CGA mode. At that point only the display engine level decode logic will be updated with the new MSR register reset value (which selects MDA mode), and the GPU level decode logic will retain its previous state (GGA mode). To avoid the mismatch we just have to switch to MDA mode with an explicit MSR register write. Currently this is being done in a somewhat dodgy manner whenever the power well gets enabled. But doing if from the power well hook is not actually necessary since the GPU level decode logic will retain its state even when the power well is disabled. Ie. doing it just the one time is sufficient, and that can be done when we're anyway writing other VGA registers while disabling the VGA plane. See commit f9dcb0dfee98 ("drm/i915: touch VGA MSR after we enable the power well") for the original details. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-3-ville.syrjala@linux.intel.com Acked-by: Jani Nikula --- .../drm/i915/display/intel_display_power_well.c | 3 -- drivers/gpu/drm/i915/display/intel_vga.c | 40 +++++++++++----------- 2 files changed, 20 insertions(+), 23 deletions(-) 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 db185a859133..52b20118ace6 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -204,9 +204,6 @@ int intel_power_well_refcount(struct i915_power_well *power_well) static void hsw_power_well_post_enable(struct intel_display *display, u8 irq_pipe_mask, bool has_vga) { - if (has_vga) - intel_vga_reset_io_mem(display); - if (irq_pipe_mask) gen8_irq_power_well_post_enable(display, irq_pipe_mask); } diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index f13734cfd904..39c68aec647b 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -47,8 +47,8 @@ void intel_vga_disable(struct intel_display *display) struct pci_dev *pdev = to_pci_dev(display->drm->dev); i915_reg_t vga_reg = intel_vga_cntrl_reg(display); enum pipe pipe; + u8 msr, sr1; u32 tmp; - u8 sr1; tmp = intel_de_read(display, vga_reg); if (tmp & VGA_DISP_DISABLE) @@ -66,35 +66,35 @@ void intel_vga_disable(struct intel_display *display) /* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */ vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO); + outb(0x01, VGA_SEQ_I); sr1 = inb(VGA_SEQ_D); outb(sr1 | VGA_SR01_SCREEN_OFF, VGA_SEQ_D); + + msr = inb(VGA_MIS_R); + /* + * VGA_MIS_COLOR controls both GPU level and display engine level + * MDA vs. CGA decode logic. But when the register gets reset + * (reset value has VGA_MIS_COLOR=0) by the power well, only the + * display engine level decode logic gets notified. + * + * Switch to MDA mode to make sure the GPU level decode logic will + * be in sync with the display engine level decode logic after the + * power well has been reset. Otherwise the GPU will claim CGA + * register accesses but the display engine will not, causing + * RMbus NoClaim errors. + */ + msr &= ~VGA_MIS_COLOR; + outb(msr, VGA_MIS_W); + vga_put(pdev, VGA_RSRC_LEGACY_IO); + udelay(300); intel_de_write(display, vga_reg, VGA_DISP_DISABLE); intel_de_posting_read(display, vga_reg); } -void intel_vga_reset_io_mem(struct intel_display *display) -{ - struct pci_dev *pdev = to_pci_dev(display->drm->dev); - - /* - * After we re-enable the power well, if we touch VGA register 0x3d5 - * we'll get unclaimed register interrupts. This stops after we write - * anything to the VGA MSR register. The vgacon module uses this - * register all the time, so if we unbind our driver and, as a - * consequence, bind vgacon, we'll get stuck in an infinite loop at - * console_unlock(). So make here we touch the VGA MSR register, making - * sure vgacon can keep working normally without triggering interrupts - * and error messages. - */ - vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO); - outb(inb(VGA_MIS_R), VGA_MIS_W); - vga_put(pdev, VGA_RSRC_LEGACY_IO); -} - static int intel_gmch_vga_set_state(struct intel_display *display, bool enable_decode) { struct pci_dev *pdev = to_pci_dev(display->drm->dev); -- cgit v1.2.3 From 284c6d8043a82549ec4f3e0300ea14c53713d974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:21 +0200 Subject: drm/i915/power: Remove i915_power_well_desc::has_vga MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We no longer have any need for the has_vga flag in the display power well descriptor. Get rid of it. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display_power_map.c | 13 ------------- drivers/gpu/drm/i915/display/intel_display_power_well.c | 5 ++--- drivers/gpu/drm/i915/display/intel_display_power_well.h | 2 -- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power_map.c b/drivers/gpu/drm/i915/display/intel_display_power_map.c index 9b49952994ce..638d971a3a6c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_map.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_map.c @@ -112,7 +112,6 @@ static const struct i915_power_well_desc hsw_power_wells_main[] = { .id = HSW_DISP_PW_GLOBAL), ), .ops = &hsw_power_well_ops, - .has_vga = true, }, }; @@ -146,7 +145,6 @@ static const struct i915_power_well_desc bdw_power_wells_main[] = { .id = HSW_DISP_PW_GLOBAL), ), .ops = &hsw_power_well_ops, - .has_vga = true, .irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), }, }; @@ -390,7 +388,6 @@ static const struct i915_power_well_desc skl_power_wells_main[] = { .id = SKL_DISP_PW_2), ), .ops = &hsw_power_well_ops, - .has_vga = true, .irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .has_fuses = true, }, { @@ -469,7 +466,6 @@ static const struct i915_power_well_desc bxt_power_wells_main[] = { .id = SKL_DISP_PW_2), ), .ops = &hsw_power_well_ops, - .has_vga = true, .irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .has_fuses = true, }, { @@ -572,7 +568,6 @@ static const struct i915_power_well_desc glk_power_wells_main[] = { .id = SKL_DISP_PW_2), ), .ops = &hsw_power_well_ops, - .has_vga = true, .irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .has_fuses = true, }, { @@ -748,7 +743,6 @@ static const struct i915_power_well_desc icl_power_wells_main[] = { .id = ICL_DISP_PW_3), ), .ops = &hsw_power_well_ops, - .has_vga = true, .irq_pipe_mask = BIT(PIPE_B), .has_fuses = true, }, { @@ -914,7 +908,6 @@ static const struct i915_power_well_desc tgl_power_wells_main[] = { .id = ICL_DISP_PW_3), ), .ops = &hsw_power_well_ops, - .has_vga = true, .irq_pipe_mask = BIT(PIPE_B), .has_fuses = true, }, { @@ -1071,7 +1064,6 @@ static const struct i915_power_well_desc rkl_power_wells_main[] = { ), .ops = &hsw_power_well_ops, .irq_pipe_mask = BIT(PIPE_B), - .has_vga = true, .has_fuses = true, }, { .instances = &I915_PW_INSTANCES( @@ -1166,7 +1158,6 @@ static const struct i915_power_well_desc dg1_power_wells_main[] = { ), .ops = &hsw_power_well_ops, .irq_pipe_mask = BIT(PIPE_B), - .has_vga = true, .has_fuses = true, }, { .instances = &I915_PW_INSTANCES( @@ -1325,7 +1316,6 @@ static const struct i915_power_well_desc xelpd_power_wells_main[] = { .id = SKL_DISP_PW_2), ), .ops = &hsw_power_well_ops, - .has_vga = true, .has_fuses = true, }, { .instances = &I915_PW_INSTANCES( @@ -1482,7 +1472,6 @@ static const struct i915_power_well_desc xelpdp_power_wells_main[] = { .id = SKL_DISP_PW_2), ), .ops = &hsw_power_well_ops, - .has_vga = true, .has_fuses = true, }, { .instances = &I915_PW_INSTANCES( @@ -1649,7 +1638,6 @@ static const struct i915_power_well_desc xe3lpd_power_wells_main[] = { .id = SKL_DISP_PW_2), ), .ops = &hsw_power_well_ops, - .has_vga = true, .has_fuses = true, }, { .instances = &I915_PW_INSTANCES( @@ -1722,7 +1710,6 @@ static const struct i915_power_well_desc wcl_power_wells_main[] = { .id = SKL_DISP_PW_2), ), .ops = &hsw_power_well_ops, - .has_vga = true, .has_fuses = true, }, { .instances = &I915_PW_INSTANCES( 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 52b20118ace6..68f293c3ac01 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -202,7 +202,7 @@ int intel_power_well_refcount(struct i915_power_well *power_well) * requesting it to be enabled. */ static void hsw_power_well_post_enable(struct intel_display *display, - u8 irq_pipe_mask, bool has_vga) + u8 irq_pipe_mask) { if (irq_pipe_mask) gen8_irq_power_well_post_enable(display, irq_pipe_mask); @@ -415,8 +415,7 @@ static void hsw_power_well_enable(struct intel_display *display, } hsw_power_well_post_enable(display, - power_well->desc->irq_pipe_mask, - power_well->desc->has_vga); + power_well->desc->irq_pipe_mask); } static void hsw_power_well_disable(struct intel_display *display, diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.h b/drivers/gpu/drm/i915/display/intel_display_power_well.h index ec8e508d0593..8f5524da2d06 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.h +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.h @@ -103,8 +103,6 @@ struct i915_power_well_desc { * the well enabled. */ u16 fixed_enable_delay:1; - /* The pw is backing the VGA functionality */ - u16 has_vga:1; u16 has_fuses:1; /* * The pw is for an ICL+ TypeC PHY port in -- cgit v1.2.3 From d4470842e415e8e1b170bfac98c65077babdffcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:22 +0200 Subject: drm/i915/vga: Extract intel_gmch_ctrl_reg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the GMCH_CTLR register offset determination into a helper rather than using a local varaible. I'll be needing this in another function soon. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_vga.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index 39c68aec647b..84fd5475d336 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -18,6 +18,11 @@ #include "intel_vga.h" #include "intel_vga_regs.h" +static unsigned int intel_gmch_ctrl_reg(struct intel_display *display) +{ + return DISPLAY_VER(display) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL; +} + static i915_reg_t intel_vga_cntrl_reg(struct intel_display *display) { if (display->platform.valleyview || display->platform.cherryview) @@ -98,10 +103,10 @@ void intel_vga_disable(struct intel_display *display) static int intel_gmch_vga_set_state(struct intel_display *display, bool enable_decode) { struct pci_dev *pdev = to_pci_dev(display->drm->dev); - unsigned int reg = DISPLAY_VER(display) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL; u16 gmch_ctrl; - if (pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0), reg, &gmch_ctrl)) { + if (pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0), + intel_gmch_ctrl_reg(display), &gmch_ctrl)) { drm_err(display->drm, "failed to read control word\n"); return -EIO; } @@ -114,7 +119,8 @@ static int intel_gmch_vga_set_state(struct intel_display *display, bool enable_d else gmch_ctrl |= INTEL_GMCH_VGA_DISABLE; - if (pci_bus_write_config_word(pdev->bus, PCI_DEVFN(0, 0), reg, gmch_ctrl)) { + if (pci_bus_write_config_word(pdev->bus, PCI_DEVFN(0, 0), + intel_gmch_ctrl_reg(display), gmch_ctrl)) { drm_err(display->drm, "failed to write control word\n"); return -EIO; } -- cgit v1.2.3 From 46ccf3fb55d5260e6e3535fec7bcb85f3e9ba667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:23 +0200 Subject: drm/i915/vga: Don't touch VGA registers if VGA decode is fully disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some systems the BIOS will disable the VGA decode logic in the iGPU (via GMCH_CTRL) when an external GPU is used as the primary VGA device. In that case the iGPU will never claim any VGA register accesses, and any access we do will in fact end up on the external GPU. Don't go poking around in the other GPUs' registers. Note that (at least on the g4x board where I tested this) the BIOS forgets to set the VGACNTR VGA_DISP_DISABLE bit, and the reset value for said bit is 0. That apparently prevents the pipes from running, so we must still remember to set the bit, despite the VGA plane was never actually enabled. On more modern platforms (hsw+ maybe?) the reset value for VGACNTR was changed to have VGA_DISP_DISABLE already set. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-6-ville.syrjala@linux.intel.com Acked-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_vga.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index 84fd5475d336..744812260ae3 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -23,6 +23,18 @@ static unsigned int intel_gmch_ctrl_reg(struct intel_display *display) return DISPLAY_VER(display) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL; } +static bool intel_vga_decode_is_enabled(struct intel_display *display) +{ + struct pci_dev *pdev = to_pci_dev(display->drm->dev); + u16 gmch_ctrl = 0; + + if (pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0), + intel_gmch_ctrl_reg(display), &gmch_ctrl)) + return false; + + return !(gmch_ctrl & INTEL_GMCH_VGA_DISABLE); +} + static i915_reg_t intel_vga_cntrl_reg(struct intel_display *display) { if (display->platform.valleyview || display->platform.cherryview) @@ -55,6 +67,17 @@ void intel_vga_disable(struct intel_display *display) u8 msr, sr1; u32 tmp; + if (!intel_vga_decode_is_enabled(display)) { + drm_dbg_kms(display->drm, "VGA decode is disabled\n"); + + /* + * On older hardware VGA_DISP_DISABLE defaults to 0, but + * it *must* be set or else the pipe will be completely + * stuck (at least on g4x). + */ + goto reset_vgacntr; + } + tmp = intel_de_read(display, vga_reg); if (tmp & VGA_DISP_DISABLE) return; @@ -96,6 +119,7 @@ void intel_vga_disable(struct intel_display *display) udelay(300); +reset_vgacntr: intel_de_write(display, vga_reg, VGA_DISP_DISABLE); intel_de_posting_read(display, vga_reg); } -- cgit v1.2.3 From f1640f9d7fa44b19f06aa0e9b2e99bdd8e62863a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:24 +0200 Subject: drm/i915/vga: Clean up VGA registers even if VGA plane is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns out at least some systems (eg. HSW Lenovo ThinkCentre E73) configure the VGA registers even when booting in UEFI mode. So in order to avoid any issues with the MSR register we should clean up the VGA registers anyway. For now this mostly avoids the potential for unclaimed register accesses due to the power well vs. MDA/CGA selection. But this will become more important soon as we'll start to rely on the MSR register to control VGA memory decode as well. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-7-ville.syrjala@linux.intel.com Acked-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_vga.c | 36 ++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index 744812260ae3..6a19fb242248 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -63,7 +63,6 @@ void intel_vga_disable(struct intel_display *display) { struct pci_dev *pdev = to_pci_dev(display->drm->dev); i915_reg_t vga_reg = intel_vga_cntrl_reg(display); - enum pipe pipe; u8 msr, sr1; u32 tmp; @@ -79,18 +78,33 @@ void intel_vga_disable(struct intel_display *display) } tmp = intel_de_read(display, vga_reg); - if (tmp & VGA_DISP_DISABLE) - return; - if (display->platform.cherryview) - pipe = REG_FIELD_GET(VGA_PIPE_SEL_MASK_CHV, tmp); - else if (has_vga_pipe_sel(display)) - pipe = REG_FIELD_GET(VGA_PIPE_SEL_MASK, tmp); - else - pipe = PIPE_A; + if ((tmp & VGA_DISP_DISABLE) == 0) { + enum pipe pipe; + + if (display->platform.cherryview) + pipe = REG_FIELD_GET(VGA_PIPE_SEL_MASK_CHV, tmp); + else if (has_vga_pipe_sel(display)) + pipe = REG_FIELD_GET(VGA_PIPE_SEL_MASK, tmp); + else + pipe = PIPE_A; + + drm_dbg_kms(display->drm, "Disabling VGA plane on pipe %c\n", + pipe_name(pipe)); + } else { + drm_dbg_kms(display->drm, "VGA plane is disabled\n"); - drm_dbg_kms(display->drm, "Disabling VGA plane on pipe %c\n", - pipe_name(pipe)); + /* + * Unfortunately at least some BIOSes (eg. HSW Lenovo + * ThinkCentre E73) set up the VGA registers even when + * in UEFI mode with the VGA plane disabled. So we need to + * always clean up the mess for iGPUs. For discrete GPUs we + * don't really care about the state of the VGA registers + * since all VGA accesses can be blocked via the bridge. + */ + if (display->platform.dgfx) + goto reset_vgacntr; + } /* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */ vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO); -- cgit v1.2.3 From cc6ed470caa201b25e9e7e1ca21144e17914644c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:25 +0200 Subject: drm/i915/vga: Avoid VGA arbiter during intel_vga_disable() for iGPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid using the VGA arbiter during intel_vga_get() for iGPUs because that will clobber the VGA routing for whatever external GPU is the current VGA device. That will cause all reads from VGA memory to come back as 0xff/white, and thus we get a white rectangle on screen when the external GPU switches from vgacon to fbcon. The iGPU has the highest VGA decode priority so it will steal all VGA register accesses whenever its IO decoding is enabled. We'll only keep the IO decode enabled for a short time so hopefully we don't end up eating too many unrelated VGA register accesses. For discrete GPUs we need all the bridges to have their VGA forwarding bits correctly configured so we can't really avoid the VGA arbiter there. Although we only do this stuff on dGPUs when the VGA plane was actaully enabled, so the dGPU should be the current VGA device and thus have VGA routed to it already anyway. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-8-ville.syrjala@linux.intel.com Acked-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_vga.c | 54 +++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index 6a19fb242248..a2a1c33d053e 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -58,11 +58,58 @@ static bool has_vga_pipe_sel(struct intel_display *display) return DISPLAY_VER(display) < 7; } +static bool intel_pci_set_io_decode(struct pci_dev *pdev, bool enable) +{ + u16 old = 0, cmd; + + pci_read_config_word(pdev, PCI_COMMAND, &old); + cmd = old & ~PCI_COMMAND_IO; + if (enable) + cmd |= PCI_COMMAND_IO; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + return old & PCI_COMMAND_IO; +} + +static bool intel_vga_get(struct intel_display *display) +{ + struct pci_dev *pdev = to_pci_dev(display->drm->dev); + + /* WaEnableVGAAccessThroughIOPort:ctg+ */ + + /* + * Bypass the VGA arbiter on the iGPU and just enable + * IO decode by hand. This avoids clobbering the VGA + * routing for an external GPU when it's the current + * VGA device, and thus prevents the all 0xff/white + * readout from VGA memory when taking over from vgacon. + * + * The iGPU has the highest VGA decode priority so it will + * grab any VGA IO access when IO decode is enabled, regardless + * of how any other VGA routing bits are configured. + */ + if (display->platform.dgfx) + vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO); + + return intel_pci_set_io_decode(pdev, true); +} + +static void intel_vga_put(struct intel_display *display, bool io_decode) +{ + struct pci_dev *pdev = to_pci_dev(display->drm->dev); + + /* see intel_vga_get() */ + intel_pci_set_io_decode(pdev, io_decode); + + if (display->platform.dgfx) + vga_put(pdev, VGA_RSRC_LEGACY_IO); +} + /* Disable the VGA plane that we never use */ void intel_vga_disable(struct intel_display *display) { - struct pci_dev *pdev = to_pci_dev(display->drm->dev); i915_reg_t vga_reg = intel_vga_cntrl_reg(display); + bool io_decode; u8 msr, sr1; u32 tmp; @@ -106,8 +153,7 @@ void intel_vga_disable(struct intel_display *display) goto reset_vgacntr; } - /* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */ - vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO); + io_decode = intel_vga_get(display); outb(0x01, VGA_SEQ_I); sr1 = inb(VGA_SEQ_D); @@ -129,7 +175,7 @@ void intel_vga_disable(struct intel_display *display) msr &= ~VGA_MIS_COLOR; outb(msr, VGA_MIS_W); - vga_put(pdev, VGA_RSRC_LEGACY_IO); + intel_vga_put(display, io_decode); udelay(300); -- cgit v1.2.3 From 01f827140bcbde9f6b4ce68bc7657f9bb9739a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:26 +0200 Subject: drm/i915/vga: Stop trying to use GMCH_CTRL for VGA decode control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_gmch_vga_set_state() is a complete lie on ILK+ because the GMCH_CTRL register is locked and can't actually be written. But we still need to remove the iGPU from the VGA arbitration on iGPU+dGPU systems, or else Xorg performance will tank due to the constant VGA arbiter accesses. For VGA memory decode we can't turn off the PCI_COMMAND memory deocde as that would disable even normal MMIO. Instead we can disable just the VGA memory decode via the VGA MSR register. And we can do that just once when disabling the VGA plane. That way we don't have to touch VGA registers anywhere else. We can also inform the arbiter that we're no longer decoding VGA memory. This will stop the arbiter from disabling all memory decode for the iGPU via PCI_COMMAND (and thus breaking everything) whenever some other GPU wants to own the VGA memory accesses. For IO we can disable all IO decode via the PCI_COMMAND register, except around the few VGA register accesses that we need to do in intel_vga_disable(). Unfortunately we can't disable IO decode permanently as it makes some laptops (eg. Dell Latitude E5400) hang during reboot/shutdown. One option would be to re-enable IO decode from the poweroff hooks, but that won't help the sysrq emergency reboot/shutdown since it won't call said hooks. So let's try to keep IO decode in its original setting unless we really need to disable it to exclude the GPU from VGA arbitration. I suppose we could keep frobbing GMCH_CTRL on pre-ILK, but it seems better to not do it since it has other side effects such as changing the class code of the PCI device. For discrete GPUs we'll rely on the bridge control instead. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-9-ville.syrjala@linux.intel.com Acked-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_vga.c | 91 ++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index a2a1c33d053e..f2f7d396c556 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -71,6 +71,19 @@ static bool intel_pci_set_io_decode(struct pci_dev *pdev, bool enable) return old & PCI_COMMAND_IO; } +static bool intel_pci_bridge_set_vga(struct pci_dev *pdev, bool enable) +{ + u16 old = 0, ctl; + + pci_read_config_word(pdev->bus->self, PCI_BRIDGE_CONTROL, &old); + ctl = old & ~PCI_BRIDGE_CTL_VGA; + if (enable) + ctl |= PCI_BRIDGE_CTL_VGA; + pci_write_config_word(pdev->bus->self, PCI_BRIDGE_CONTROL, ctl); + + return old & PCI_BRIDGE_CTL_VGA; +} + static bool intel_vga_get(struct intel_display *display) { struct pci_dev *pdev = to_pci_dev(display->drm->dev); @@ -108,6 +121,7 @@ static void intel_vga_put(struct intel_display *display, bool io_decode) /* Disable the VGA plane that we never use */ void intel_vga_disable(struct intel_display *display) { + struct pci_dev *pdev = to_pci_dev(display->drm->dev); i915_reg_t vga_reg = intel_vga_cntrl_reg(display); bool io_decode; u8 msr, sr1; @@ -160,6 +174,12 @@ void intel_vga_disable(struct intel_display *display) outb(sr1 | VGA_SR01_SCREEN_OFF, VGA_SEQ_D); msr = inb(VGA_MIS_R); + /* + * Always disable VGA memory decode for iGPU so that + * intel_vga_set_decode() doesn't need to access VGA registers. + * VGA_MIS_ENB_MEM_ACCESS=0 is also the reset value. + */ + msr &= ~VGA_MIS_ENB_MEM_ACCESS; /* * VGA_MIS_COLOR controls both GPU level and display engine level * MDA vs. CGA decode logic. But when the register gets reset @@ -177,6 +197,14 @@ void intel_vga_disable(struct intel_display *display) intel_vga_put(display, io_decode); + /* + * Inform the arbiter about VGA memory decode being disabled so + * that it doesn't disable all memory decode for the iGPU when + * targeting another GPU. + */ + if (!display->platform.dgfx) + vga_set_legacy_decoding(pdev, VGA_RSRC_LEGACY_IO); + udelay(300); reset_vgacntr: @@ -184,45 +212,38 @@ reset_vgacntr: intel_de_posting_read(display, vga_reg); } -static int intel_gmch_vga_set_state(struct intel_display *display, bool enable_decode) +static unsigned int intel_vga_set_decode(struct pci_dev *pdev, bool enable_decode) { - struct pci_dev *pdev = to_pci_dev(display->drm->dev); - u16 gmch_ctrl; - - if (pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0), - intel_gmch_ctrl_reg(display), &gmch_ctrl)) { - drm_err(display->drm, "failed to read control word\n"); - return -EIO; - } - - if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !enable_decode) - return 0; + struct intel_display *display = to_intel_display(pdev); + unsigned int decodes = VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; - if (enable_decode) - gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE; - else - gmch_ctrl |= INTEL_GMCH_VGA_DISABLE; + drm_dbg_kms(display->drm, "%s VGA decode due to VGA arbitration\n", + str_enable_disable(enable_decode)); - if (pci_bus_write_config_word(pdev->bus, PCI_DEVFN(0, 0), - intel_gmch_ctrl_reg(display), gmch_ctrl)) { - drm_err(display->drm, "failed to write control word\n"); - return -EIO; + /* + * Can't use GMCH_CTRL INTEL_GMCH_VGA_DISABLE to disable VGA + * decode on ILK+ since the register is locked. Instead + * intel_disable_vga() will disable VGA memory decode for the + * iGPU, and here we just need to take care of the IO decode. + * For discrete GPUs we rely on the bridge VGA control. + * + * We can't disable IO decode already in intel_vga_disable() + * because at least some laptops (eg. CTG Dell Latitude E5400) + * will hang during reboot/shutfown with IO decode disabled. + */ + if (display->platform.dgfx) { + if (!enable_decode) + intel_pci_bridge_set_vga(pdev, false); + else + decodes |= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; + } else { + if (!enable_decode) + intel_pci_set_io_decode(pdev, false); + else + decodes |= VGA_RSRC_LEGACY_IO; } - return 0; -} - -static unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_decode) -{ - struct intel_display *display = to_intel_display(pdev); - - intel_gmch_vga_set_state(display, enable_decode); - - if (enable_decode) - return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; - else - return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; + return decodes; } void intel_vga_register(struct intel_display *display) @@ -239,7 +260,7 @@ void intel_vga_register(struct intel_display *display) * then we do not take part in VGA arbitration and the * vga_client_register() fails with -ENODEV. */ - ret = vga_client_register(pdev, intel_gmch_vga_set_decode); + ret = vga_client_register(pdev, intel_vga_set_decode); drm_WARN_ON(display->drm, ret && ret != -ENODEV); } -- cgit v1.2.3 From 7e47a14b02fe288029448f8ba80852fe2b0b2d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:27 +0200 Subject: drm/i915/vga: Assert that VGA register accesses are going to the right GPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want our VGA register accesses to land on the correct GPU. Check that the VGA routing is appropriately configured. For the iGPU this just means the IO decode enable on the GPU, but for dGPUs we also need the entire chain of bridges to forward the VGA accesses. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-10-ville.syrjala@linux.intel.com Acked-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_vga.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index f2f7d396c556..e51451966f72 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -58,6 +58,28 @@ static bool has_vga_pipe_sel(struct intel_display *display) return DISPLAY_VER(display) < 7; } +static bool intel_pci_has_vga_io_decode(struct pci_dev *pdev) +{ + u16 cmd = 0; + + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if ((cmd & PCI_COMMAND_IO) == 0) + return false; + + pdev = pdev->bus->self; + while (pdev) { + u16 ctl = 0; + + pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &ctl); + if ((ctl & PCI_BRIDGE_CTL_VGA) == 0) + return false; + + pdev = pdev->bus->self; + } + + return true; +} + static bool intel_pci_set_io_decode(struct pci_dev *pdev, bool enable) { u16 old = 0, cmd; @@ -169,6 +191,8 @@ void intel_vga_disable(struct intel_display *display) io_decode = intel_vga_get(display); + drm_WARN_ON(display->drm, !intel_pci_has_vga_io_decode(pdev)); + outb(0x01, VGA_SEQ_I); sr1 = inb(VGA_SEQ_D); outb(sr1 | VGA_SR01_SCREEN_OFF, VGA_SEQ_D); -- cgit v1.2.3 From d2bfe35f840d9fdfe76efcd4ffab185abad44046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:28 +0200 Subject: drm/i915/de: Simplify intel_de_read8() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_de_read8() is only needed for VGA register MMIO access by the CRT code on gen2/3. Remove the redundant wakelock stuff, and add a platform check to make sure this won't get used on any platform where MMIO VGA register accesses don't work. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-11-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_de.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_de.h b/drivers/gpu/drm/i915/display/intel_de.h index a7ce3b875e06..5c1b37d30045 100644 --- a/drivers/gpu/drm/i915/display/intel_de.h +++ b/drivers/gpu/drm/i915/display/intel_de.h @@ -6,6 +6,8 @@ #ifndef __INTEL_DE_H__ #define __INTEL_DE_H__ +#include + #include "intel_display_core.h" #include "intel_dmc_wl.h" #include "intel_dsb.h" @@ -34,15 +36,10 @@ intel_de_read(struct intel_display *display, i915_reg_t reg) static inline u8 intel_de_read8(struct intel_display *display, i915_reg_t reg) { - u8 val; - - intel_dmc_wl_get(display, reg); - - val = intel_uncore_read8(__to_uncore(display), reg); + /* this is only used on VGA registers (possible on pre-g4x) */ + drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 5 || display->platform.g4x); - intel_dmc_wl_put(display, reg); - - return val; + return intel_uncore_read8(__to_uncore(display), reg); } static inline u64 -- cgit v1.2.3 From 005a496d0f5b2c5818e320d58edc0a47f7bdb923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:29 +0200 Subject: drm/i915/de: Add intel_de_write8() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a write counterpart to intel_de_read8(). Will be used for MMIO access to VGA registers on pre-g4x. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-12-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_de.h | 8 ++++++++ drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h | 8 ++++++++ drivers/gpu/drm/xe/xe_mmio.c | 9 +++++++++ drivers/gpu/drm/xe/xe_mmio.h | 1 + 4 files changed, 26 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_de.h b/drivers/gpu/drm/i915/display/intel_de.h index 5c1b37d30045..f30f3f8ebee1 100644 --- a/drivers/gpu/drm/i915/display/intel_de.h +++ b/drivers/gpu/drm/i915/display/intel_de.h @@ -42,6 +42,14 @@ intel_de_read8(struct intel_display *display, i915_reg_t reg) return intel_uncore_read8(__to_uncore(display), reg); } +static inline void +intel_de_write8(struct intel_display *display, i915_reg_t reg, u8 val) +{ + drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 5 || display->platform.g4x); + + intel_uncore_write8(__to_uncore(display), reg, val); +} + static inline u64 intel_de_read64_2x32(struct intel_display *display, i915_reg_t lower_reg, i915_reg_t upper_reg) diff --git a/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h b/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h index c05d4c4292d3..c5e198ace7bc 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h @@ -38,6 +38,14 @@ static inline u8 intel_uncore_read8(struct intel_uncore *uncore, return xe_mmio_read8(__compat_uncore_to_mmio(uncore), reg); } +static inline void intel_uncore_write8(struct intel_uncore *uncore, + i915_reg_t i915_reg, u8 val) +{ + struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg)); + + xe_mmio_write8(__compat_uncore_to_mmio(uncore), reg, val); +} + static inline u16 intel_uncore_read16(struct intel_uncore *uncore, i915_reg_t i915_reg) { diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 350dca1f0925..6bdaedc1da73 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -158,6 +158,15 @@ u8 xe_mmio_read8(struct xe_mmio *mmio, struct xe_reg reg) return val; } +void xe_mmio_write8(struct xe_mmio *mmio, struct xe_reg reg, u8 val) +{ + u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); + + trace_xe_reg_rw(mmio, true, addr, val, sizeof(val)); + + writeb(val, mmio->regs + addr); +} + u16 xe_mmio_read16(struct xe_mmio *mmio, struct xe_reg reg) { u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); diff --git a/drivers/gpu/drm/xe/xe_mmio.h b/drivers/gpu/drm/xe/xe_mmio.h index 15362789ab99..cd355a43af3d 100644 --- a/drivers/gpu/drm/xe/xe_mmio.h +++ b/drivers/gpu/drm/xe/xe_mmio.h @@ -17,6 +17,7 @@ int xe_mmio_probe_tiles(struct xe_device *xe); void xe_mmio_init(struct xe_mmio *mmio, struct xe_tile *tile, void __iomem *ptr, u32 size); u8 xe_mmio_read8(struct xe_mmio *mmio, struct xe_reg reg); +void xe_mmio_write8(struct xe_mmio *mmio, struct xe_reg reg, u8 val); u16 xe_mmio_read16(struct xe_mmio *mmio, struct xe_reg reg); void xe_mmio_write32(struct xe_mmio *mmio, struct xe_reg reg, u32 val); u32 xe_mmio_read32(struct xe_mmio *mmio, struct xe_reg reg); -- cgit v1.2.3 From 3acd8cbbd738eb8c85fc5ec3c7d9fbee26db6d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 8 Dec 2025 20:26:30 +0200 Subject: drm/i915/vga: Introduce intel_vga_{read,write}() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VGA register are rather special since they either get accessed via the global IO addresses, or possibly through MMIO on pre-g4x platforms. Wrap all VGA register accesses in intel_vga_{read,write}() to make it obvious where they get accessed. Signed-off-by: Ville Syrjälä Link: https://patch.msgid.link/20251208182637.334-13-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_crt.c | 6 ++++-- drivers/gpu/drm/i915/display/intel_crt_regs.h | 2 -- drivers/gpu/drm/i915/display/intel_vga.c | 27 ++++++++++++++++++++++----- drivers/gpu/drm/i915/display/intel_vga.h | 3 +++ 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 5f9a03877ea9..dedc26f6a2b2 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -33,6 +33,7 @@ #include #include #include +#include