summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/display/intel_dp.c
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2022-09-07 12:10:55 +0300
committerVille Syrjälä <ville.syrjala@linux.intel.com>2022-09-08 14:21:50 +0300
commite6f29923c0489b6fec1ac000f2c045df43ec081c (patch)
tree39e4f263a4a18e846260bd3539d3db0b3f255e3c /drivers/gpu/drm/i915/display/intel_dp.c
parent74d6f31fa427b87616bc65987a8aff460da1e670 (diff)
downloadlinux-e6f29923c0489b6fec1ac000f2c045df43ec081c.tar.gz
linux-e6f29923c0489b6fec1ac000f2c045df43ec081c.tar.bz2
linux-e6f29923c0489b6fec1ac000f2c045df43ec081c.zip
drm/i915: Allow M/N change during fastset on bdw+
On BDW+ M/N are double buffered and so we can easily reprogram them during a fastset. So for eDP panels that support seamless DRRS we can just change these without a full modeset. For earlier platforms we'd need to play tricks with M1/N1 vs. M2/N2 during the fastset to make sure we do the switch atomically. Not sure the added complexity is worth the hassle, so leave it alone for now. The slight downside is that we have to keep the link running at a link rate capable of supporting the highest refresh rate we want to use. For the moment we just pick the highest mode the panel reports and calculate the link based on that. This might need further refinement (eg. if we run into bandwidth restrictions)... v2: Only use the high link rate if the platform really supports the seamless M/N change uring fastset (ie. bdw+) v3: Rebase due to HAS_DOUBLE_BUFFERED_M_N() Reviewed-by: Mika Kahola <mika.kahola@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20220907091057.11572-16-ville.syrjala@linux.intel.com
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dp.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 5073b612fef1..3b94715779c0 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1297,21 +1297,45 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
}
}
+static bool has_seamless_m_n(struct intel_connector *connector)
+{
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+
+ /*
+ * Seamless M/N reprogramming only implemented
+ * for BDW+ double buffered M/N registers so far.
+ */
+ return HAS_DOUBLE_BUFFERED_M_N(i915) &&
+ intel_panel_drrs_type(connector) == DRRS_TYPE_SEAMLESS;
+}
+
+static int intel_dp_mode_clock(const struct intel_crtc_state *crtc_state,
+ const struct drm_connector_state *conn_state)
+{
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
+
+ /* FIXME a bit of a mess wrt clock vs. crtc_clock */
+ if (has_seamless_m_n(connector))
+ return intel_panel_highest_mode(connector, adjusted_mode)->clock;
+ else
+ return adjusted_mode->crtc_clock;
+}
+
/* Optimize link config in order: max bpp, min clock, min lanes */
static int
intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
struct intel_crtc_state *pipe_config,
+ const struct drm_connector_state *conn_state,
const struct link_config_limits *limits)
{
- struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
- int bpp, i, lane_count;
+ int bpp, i, lane_count, clock = intel_dp_mode_clock(pipe_config, conn_state);
int mode_rate, link_rate, link_avail;
for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
int output_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp);
- mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
- output_bpp);
+ mode_rate = intel_dp_link_required(clock, output_bpp);
for (i = 0; i < intel_dp->num_common_rates; i++) {
link_rate = intel_dp_common_rate(intel_dp, i);
@@ -1622,7 +1646,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
* Optimize for slow and wide for everything, because there are some
* eDP 1.3 and 1.4 panels don't work well with fast and narrow.
*/
- ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, &limits);
+ ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, conn_state, &limits);
if (ret || joiner_needs_dsc || intel_dp->force_dsc_en) {
drm_dbg_kms(&i915->drm, "Try DSC (fallback=%s, joiner=%s, force=%s)\n",
@@ -1910,6 +1934,9 @@ intel_dp_drrs_compute_config(struct intel_connector *connector,
intel_panel_downclock_mode(connector, &pipe_config->hw.adjusted_mode);
int pixel_clock;
+ if (has_seamless_m_n(connector))
+ pipe_config->seamless_m_n = true;
+
if (!can_enable_drrs(connector, pipe_config, downclock_mode)) {
if (intel_cpu_transcoder_has_m2_n2(i915, pipe_config->cpu_transcoder))
intel_zero_m_n(&pipe_config->dp_m2_n2);