> -----Original Message-----
> From: Intel-gfx <intel-gfx-boun...@lists.freedesktop.org> On Behalf Of Ville
> Syrjala
> Sent: Monday, June 20, 2022 8:52 PM
> To: intel-gfx@lists.freedesktop.org
> Subject: [Intel-gfx] [PATCH v3 15/17] drm/i915: Allow M/N change during
> fastset on bdw+
> 
> From: Ville Syrjälä <ville.syrj...@linux.intel.com>
> 
> 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.kah...@intel.com>

> Signed-off-by: Ville Syrjälä <ville.syrj...@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_display.c  | 13 +++++--
>  .../drm/i915/display/intel_display_types.h    |  1 +
>  drivers/gpu/drm/i915/display/intel_dp.c       | 37 ++++++++++++++++---
>  3 files changed, 43 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c
> b/drivers/gpu/drm/i915/display/intel_display.c
> index afef6a826ef2..43c00f8b4057 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -5719,7 +5719,8 @@ intel_pipe_config_compare(const struct
> intel_crtc_state *current_config,
>       PIPE_CONF_CHECK_X(lane_lat_optim_mask);
> 
>       if (HAS_DOUBLE_BUFFERED_M_N(dev_priv)) {
> -             PIPE_CONF_CHECK_M_N_ALT(dp_m_n, dp_m2_n2);
> +             if (!fastset || !pipe_config->seamless_m_n)
> +                     PIPE_CONF_CHECK_M_N_ALT(dp_m_n, dp_m2_n2);
>       } else {
>               PIPE_CONF_CHECK_M_N(dp_m_n);
>               PIPE_CONF_CHECK_M_N(dp_m2_n2);
> @@ -5851,8 +5852,10 @@ intel_pipe_config_compare(const struct
> intel_crtc_state *current_config,
>       if (IS_G4X(dev_priv) || DISPLAY_VER(dev_priv) >= 5)
>               PIPE_CONF_CHECK_I(pipe_bpp);
> 
> -     PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_clock);
> -     PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_clock);
> +     if (!fastset || !pipe_config->seamless_m_n) {
> +             PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_clock);
> +             PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_clock);
> +     }
>       PIPE_CONF_CHECK_I(port_clock);
> 
>       PIPE_CONF_CHECK_I(min_voltage_level);
> @@ -6991,6 +6994,10 @@ static void intel_pipe_fastset(const struct
> intel_crtc_state *old_crtc_state,
>       if (DISPLAY_VER(dev_priv) >= 9 ||
>           IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
>               hsw_set_linetime_wm(new_crtc_state);
> +
> +     if (new_crtc_state->seamless_m_n)
> +             intel_cpu_transcoder_set_m1_n1(crtc, new_crtc_state-
> >cpu_transcoder,
> +                                            &new_crtc_state->dp_m_n);
>  }
> 
>  static void commit_pipe_pre_planes(struct intel_atomic_state *state, diff 
> --git
> a/drivers/gpu/drm/i915/display/intel_display_types.h
> b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 8b0949b6dc75..95159d1c8ca8 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1129,6 +1129,7 @@ struct intel_crtc_state {
>       /* m2_n2 for eDP downclock */
>       struct intel_link_m_n dp_m2_n2;
>       bool has_drrs;
> +     bool seamless_m_n;
> 
>       /* PSR is supported but might not be enabled due the lack of enabled
> planes */
>       bool has_psr;
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c
> b/drivers/gpu/drm/i915/display/intel_dp.c
> index cf7e4e105891..90fa8eda6911 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -1311,21 +1311,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); @@ -
> 1625,7 +1649,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", @@ -1913,6 +1937,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);
> --
> 2.35.1

Reply via email to