[Intel-gfx] [PATCH 1/9] drm/i915: Move PCH refclok stuff into its own file

David Airlie airlied at redhat.com
Sun Oct 17 23:56:33 UTC 2021


On Fri, Oct 15, 2021 at 5:16 PM Ville Syrjala
<ville.syrjala at linux.intel.com> wrote:
>
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
>
> Move the PCH refclk stuff (including all the LPT/WPT
> iCLKIP/CLKOUT_DP things) to its own file.
>
> We also suck in the mPHY programming from intel_fdi.c
> since we're the only caller.

The title of the patch has a typo refclok->reclock.

Other than that this looks fine,

Reviewed-by: Dave Airlie <airlied at redhat.com>

>
> Cc: Dave Airlie <airlied at redhat.com>
> Cc: Jani Nikula <jani.nikula at intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile                 |   1 +
>  drivers/gpu/drm/i915/display/intel_crt.c      |   1 +
>  drivers/gpu/drm/i915/display/intel_display.c  | 537 +--------------
>  drivers/gpu/drm/i915/display/intel_display.h  |   4 -
>  .../drm/i915/display/intel_display_power.c    |   1 +
>  drivers/gpu/drm/i915/display/intel_dpll_mgr.c |   1 +
>  drivers/gpu/drm/i915/display/intel_fdi.c      |  99 ---
>  drivers/gpu/drm/i915/display/intel_fdi.h      |   1 -
>  .../gpu/drm/i915/display/intel_pch_refclk.c   | 648 ++++++++++++++++++
>  .../gpu/drm/i915/display/intel_pch_refclk.h   |  21 +
>  drivers/gpu/drm/i915/i915_drv.c               |   1 +
>  11 files changed, 675 insertions(+), 640 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/display/intel_pch_refclk.c
>  create mode 100644 drivers/gpu/drm/i915/display/intel_pch_refclk.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 660bb03de6fc..96f3b8f6c50d 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -226,6 +226,7 @@ i915-y += \
>         display/intel_hotplug.o \
>         display/intel_lpe_audio.o \
>         display/intel_overlay.o \
> +       display/intel_pch_refclk.o \
>         display/intel_plane_initial.o \
>         display/intel_psr.o \
>         display/intel_quirks.o \
> diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
> index 1c161eeed82f..bf03bd0ecd43 100644
> --- a/drivers/gpu/drm/i915/display/intel_crt.c
> +++ b/drivers/gpu/drm/i915/display/intel_crt.c
> @@ -45,6 +45,7 @@
>  #include "intel_fifo_underrun.h"
>  #include "intel_gmbus.h"
>  #include "intel_hotplug.h"
> +#include "intel_pch_refclk.h"
>
>  /* Here's the desired hotplug mode */
>  #define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 |               \
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index ff598b6cd953..995050443065 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -96,6 +96,7 @@
>  #include "intel_hotplug.h"
>  #include "intel_overlay.h"
>  #include "intel_panel.h"
> +#include "intel_pch_refclk.h"
>  #include "intel_pcode.h"
>  #include "intel_pipe_crc.h"
>  #include "intel_plane_initial.h"
> @@ -103,7 +104,6 @@
>  #include "intel_pps.h"
>  #include "intel_psr.h"
>  #include "intel_quirks.h"
> -#include "intel_sbi.h"
>  #include "intel_sprite.h"
>  #include "intel_tc.h"
>  #include "intel_vga.h"
> @@ -1388,133 +1388,6 @@ bool intel_has_pending_fb_unpin(struct drm_i915_private *dev_priv)
>         return false;
>  }
>
> -void lpt_disable_iclkip(struct drm_i915_private *dev_priv)
> -{
> -       u32 temp;
> -
> -       intel_de_write(dev_priv, PIXCLK_GATE, PIXCLK_GATE_GATE);
> -
> -       mutex_lock(&dev_priv->sb_lock);
> -
> -       temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
> -       temp |= SBI_SSCCTL_DISABLE;
> -       intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);
> -
> -       mutex_unlock(&dev_priv->sb_lock);
> -}
> -
> -/* Program iCLKIP clock to the desired frequency */
> -static void lpt_program_iclkip(const struct intel_crtc_state *crtc_state)
> -{
> -       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -       int clock = crtc_state->hw.adjusted_mode.crtc_clock;
> -       u32 divsel, phaseinc, auxdiv, phasedir = 0;
> -       u32 temp;
> -
> -       lpt_disable_iclkip(dev_priv);
> -
> -       /* The iCLK virtual clock root frequency is in MHz,
> -        * but the adjusted_mode->crtc_clock in in KHz. To get the
> -        * divisors, it is necessary to divide one by another, so we
> -        * convert the virtual clock precision to KHz here for higher
> -        * precision.
> -        */
> -       for (auxdiv = 0; auxdiv < 2; auxdiv++) {
> -               u32 iclk_virtual_root_freq = 172800 * 1000;
> -               u32 iclk_pi_range = 64;
> -               u32 desired_divisor;
> -
> -               desired_divisor = DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
> -                                                   clock << auxdiv);
> -               divsel = (desired_divisor / iclk_pi_range) - 2;
> -               phaseinc = desired_divisor % iclk_pi_range;
> -
> -               /*
> -                * Near 20MHz is a corner case which is
> -                * out of range for the 7-bit divisor
> -                */
> -               if (divsel <= 0x7f)
> -                       break;
> -       }
> -
> -       /* This should not happen with any sane values */
> -       drm_WARN_ON(&dev_priv->drm, SBI_SSCDIVINTPHASE_DIVSEL(divsel) &
> -                   ~SBI_SSCDIVINTPHASE_DIVSEL_MASK);
> -       drm_WARN_ON(&dev_priv->drm, SBI_SSCDIVINTPHASE_DIR(phasedir) &
> -                   ~SBI_SSCDIVINTPHASE_INCVAL_MASK);
> -
> -       drm_dbg_kms(&dev_priv->drm,
> -                   "iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n",
> -                   clock, auxdiv, divsel, phasedir, phaseinc);
> -
> -       mutex_lock(&dev_priv->sb_lock);
> -
> -       /* Program SSCDIVINTPHASE6 */
> -       temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
> -       temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK;
> -       temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel);
> -       temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK;
> -       temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc);
> -       temp |= SBI_SSCDIVINTPHASE_DIR(phasedir);
> -       temp |= SBI_SSCDIVINTPHASE_PROPAGATE;
> -       intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE6, temp, SBI_ICLK);
> -
> -       /* Program SSCAUXDIV */
> -       temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
> -       temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1);
> -       temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv);
> -       intel_sbi_write(dev_priv, SBI_SSCAUXDIV6, temp, SBI_ICLK);
> -
> -       /* Enable modulator and associated divider */
> -       temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
> -       temp &= ~SBI_SSCCTL_DISABLE;
> -       intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);
> -
> -       mutex_unlock(&dev_priv->sb_lock);
> -
> -       /* Wait for initialization time */
> -       udelay(24);
> -
> -       intel_de_write(dev_priv, PIXCLK_GATE, PIXCLK_GATE_UNGATE);
> -}
> -
> -int lpt_get_iclkip(struct drm_i915_private *dev_priv)
> -{
> -       u32 divsel, phaseinc, auxdiv;
> -       u32 iclk_virtual_root_freq = 172800 * 1000;
> -       u32 iclk_pi_range = 64;
> -       u32 desired_divisor;
> -       u32 temp;
> -
> -       if ((intel_de_read(dev_priv, PIXCLK_GATE) & PIXCLK_GATE_UNGATE) == 0)
> -               return 0;
> -
> -       mutex_lock(&dev_priv->sb_lock);
> -
> -       temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
> -       if (temp & SBI_SSCCTL_DISABLE) {
> -               mutex_unlock(&dev_priv->sb_lock);
> -               return 0;
> -       }
> -
> -       temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
> -       divsel = (temp & SBI_SSCDIVINTPHASE_DIVSEL_MASK) >>
> -               SBI_SSCDIVINTPHASE_DIVSEL_SHIFT;
> -       phaseinc = (temp & SBI_SSCDIVINTPHASE_INCVAL_MASK) >>
> -               SBI_SSCDIVINTPHASE_INCVAL_SHIFT;
> -
> -       temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
> -       auxdiv = (temp & SBI_SSCAUXDIV_FINALDIV2SEL_MASK) >>
> -               SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT;
> -
> -       mutex_unlock(&dev_priv->sb_lock);
> -
> -       desired_divisor = (divsel + 2) * iclk_pi_range + phaseinc;
> -
> -       return DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
> -                                desired_divisor << auxdiv);
> -}
>
>  static void ilk_pch_transcoder_set_timings(const struct intel_crtc_state *crtc_state,
>                                            enum pipe pch_transcoder)
> @@ -4299,414 +4172,6 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
>         return ret;
>  }
>
> -static void ilk_init_pch_refclk(struct drm_i915_private *dev_priv)
> -{
> -       struct intel_encoder *encoder;
> -       int i;
> -       u32 val, final;
> -       bool has_lvds = false;
> -       bool has_cpu_edp = false;
> -       bool has_panel = false;
> -       bool has_ck505 = false;
> -       bool can_ssc = false;
> -       bool using_ssc_source = false;
> -
> -       /* We need to take the global config into account */
> -       for_each_intel_encoder(&dev_priv->drm, encoder) {
> -               switch (encoder->type) {
> -               case INTEL_OUTPUT_LVDS:
> -                       has_panel = true;
> -                       has_lvds = true;
> -                       break;
> -               case INTEL_OUTPUT_EDP:
> -                       has_panel = true;
> -                       if (encoder->port == PORT_A)
> -                               has_cpu_edp = true;
> -                       break;
> -               default:
> -                       break;
> -               }
> -       }
> -
> -       if (HAS_PCH_IBX(dev_priv)) {
> -               has_ck505 = dev_priv->vbt.display_clock_mode;
> -               can_ssc = has_ck505;
> -       } else {
> -               has_ck505 = false;
> -               can_ssc = true;
> -       }
> -
> -       /* Check if any DPLLs are using the SSC source */
> -       for (i = 0; i < dev_priv->dpll.num_shared_dpll; i++) {
> -               u32 temp = intel_de_read(dev_priv, PCH_DPLL(i));
> -
> -               if (!(temp & DPLL_VCO_ENABLE))
> -                       continue;
> -
> -               if ((temp & PLL_REF_INPUT_MASK) ==
> -                   PLLB_REF_INPUT_SPREADSPECTRUMIN) {
> -                       using_ssc_source = true;
> -                       break;
> -               }
> -       }
> -
> -       drm_dbg_kms(&dev_priv->drm,
> -                   "has_panel %d has_lvds %d has_ck505 %d using_ssc_source %d\n",
> -                   has_panel, has_lvds, has_ck505, using_ssc_source);
> -
> -       /* Ironlake: try to setup display ref clock before DPLL
> -        * enabling. This is only under driver's control after
> -        * PCH B stepping, previous chipset stepping should be
> -        * ignoring this setting.
> -        */
> -       val = intel_de_read(dev_priv, PCH_DREF_CONTROL);
> -
> -       /* As we must carefully and slowly disable/enable each source in turn,
> -        * compute the final state we want first and check if we need to
> -        * make any changes at all.
> -        */
> -       final = val;
> -       final &= ~DREF_NONSPREAD_SOURCE_MASK;
> -       if (has_ck505)
> -               final |= DREF_NONSPREAD_CK505_ENABLE;
> -       else
> -               final |= DREF_NONSPREAD_SOURCE_ENABLE;
> -
> -       final &= ~DREF_SSC_SOURCE_MASK;
> -       final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
> -       final &= ~DREF_SSC1_ENABLE;
> -
> -       if (has_panel) {
> -               final |= DREF_SSC_SOURCE_ENABLE;
> -
> -               if (intel_panel_use_ssc(dev_priv) && can_ssc)
> -                       final |= DREF_SSC1_ENABLE;
> -
> -               if (has_cpu_edp) {
> -                       if (intel_panel_use_ssc(dev_priv) && can_ssc)
> -                               final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
> -                       else
> -                               final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
> -               } else
> -                       final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
> -       } else if (using_ssc_source) {
> -               final |= DREF_SSC_SOURCE_ENABLE;
> -               final |= DREF_SSC1_ENABLE;
> -       }
> -
> -       if (final == val)
> -               return;
> -
> -       /* Always enable nonspread source */
> -       val &= ~DREF_NONSPREAD_SOURCE_MASK;
> -
> -       if (has_ck505)
> -               val |= DREF_NONSPREAD_CK505_ENABLE;
> -       else
> -               val |= DREF_NONSPREAD_SOURCE_ENABLE;
> -
> -       if (has_panel) {
> -               val &= ~DREF_SSC_SOURCE_MASK;
> -               val |= DREF_SSC_SOURCE_ENABLE;
> -
> -               /* SSC must be turned on before enabling the CPU output  */
> -               if (intel_panel_use_ssc(dev_priv) && can_ssc) {
> -                       drm_dbg_kms(&dev_priv->drm, "Using SSC on panel\n");
> -                       val |= DREF_SSC1_ENABLE;
> -               } else
> -                       val &= ~DREF_SSC1_ENABLE;
> -
> -               /* Get SSC going before enabling the outputs */
> -               intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
> -               intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
> -               udelay(200);
> -
> -               val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
> -
> -               /* Enable CPU source on CPU attached eDP */
> -               if (has_cpu_edp) {
> -                       if (intel_panel_use_ssc(dev_priv) && can_ssc) {
> -                               drm_dbg_kms(&dev_priv->drm,
> -                                           "Using SSC on eDP\n");
> -                               val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
> -                       } else
> -                               val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
> -               } else
> -                       val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
> -
> -               intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
> -               intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
> -               udelay(200);
> -       } else {
> -               drm_dbg_kms(&dev_priv->drm, "Disabling CPU source output\n");
> -
> -               val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
> -
> -               /* Turn off CPU output */
> -               val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
> -
> -               intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
> -               intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
> -               udelay(200);
> -
> -               if (!using_ssc_source) {
> -                       drm_dbg_kms(&dev_priv->drm, "Disabling SSC source\n");
> -
> -                       /* Turn off the SSC source */
> -                       val &= ~DREF_SSC_SOURCE_MASK;
> -                       val |= DREF_SSC_SOURCE_DISABLE;
> -
> -                       /* Turn off SSC1 */
> -                       val &= ~DREF_SSC1_ENABLE;
> -
> -                       intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
> -                       intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
> -                       udelay(200);
> -               }
> -       }
> -
> -       BUG_ON(val != final);
> -}
> -
> -/* Implements 3 different sequences from BSpec chapter "Display iCLK
> - * Programming" based on the parameters passed:
> - * - Sequence to enable CLKOUT_DP
> - * - Sequence to enable CLKOUT_DP without spread
> - * - Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O
> - */
> -static void lpt_enable_clkout_dp(struct drm_i915_private *dev_priv,
> -                                bool with_spread, bool with_fdi)
> -{
> -       u32 reg, tmp;
> -
> -       if (drm_WARN(&dev_priv->drm, with_fdi && !with_spread,
> -                    "FDI requires downspread\n"))
> -               with_spread = true;
> -       if (drm_WARN(&dev_priv->drm, HAS_PCH_LPT_LP(dev_priv) &&
> -                    with_fdi, "LP PCH doesn't have FDI\n"))
> -               with_fdi = false;
> -
> -       mutex_lock(&dev_priv->sb_lock);
> -
> -       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
> -       tmp &= ~SBI_SSCCTL_DISABLE;
> -       tmp |= SBI_SSCCTL_PATHALT;
> -       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
> -
> -       udelay(24);
> -
> -       if (with_spread) {
> -               tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
> -               tmp &= ~SBI_SSCCTL_PATHALT;
> -               intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
> -
> -               if (with_fdi)
> -                       lpt_fdi_program_mphy(dev_priv);
> -       }
> -
> -       reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;
> -       tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
> -       tmp |= SBI_GEN0_CFG_BUFFENABLE_DISABLE;
> -       intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
> -
> -       mutex_unlock(&dev_priv->sb_lock);
> -}
> -
> -/* Sequence to disable CLKOUT_DP */
> -void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv)
> -{
> -       u32 reg, tmp;
> -
> -       mutex_lock(&dev_priv->sb_lock);
> -
> -       reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;
> -       tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
> -       tmp &= ~SBI_GEN0_CFG_BUFFENABLE_DISABLE;
> -       intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
> -
> -       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
> -       if (!(tmp & SBI_SSCCTL_DISABLE)) {
> -               if (!(tmp & SBI_SSCCTL_PATHALT)) {
> -                       tmp |= SBI_SSCCTL_PATHALT;
> -                       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
> -                       udelay(32);
> -               }
> -               tmp |= SBI_SSCCTL_DISABLE;
> -               intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
> -       }
> -
> -       mutex_unlock(&dev_priv->sb_lock);
> -}
> -
> -#define BEND_IDX(steps) ((50 + (steps)) / 5)
> -
> -static const u16 sscdivintphase[] = {
> -       [BEND_IDX( 50)] = 0x3B23,
> -       [BEND_IDX( 45)] = 0x3B23,
> -       [BEND_IDX( 40)] = 0x3C23,
> -       [BEND_IDX( 35)] = 0x3C23,
> -       [BEND_IDX( 30)] = 0x3D23,
> -       [BEND_IDX( 25)] = 0x3D23,
> -       [BEND_IDX( 20)] = 0x3E23,
> -       [BEND_IDX( 15)] = 0x3E23,
> -       [BEND_IDX( 10)] = 0x3F23,
> -       [BEND_IDX(  5)] = 0x3F23,
> -       [BEND_IDX(  0)] = 0x0025,
> -       [BEND_IDX( -5)] = 0x0025,
> -       [BEND_IDX(-10)] = 0x0125,
> -       [BEND_IDX(-15)] = 0x0125,
> -       [BEND_IDX(-20)] = 0x0225,
> -       [BEND_IDX(-25)] = 0x0225,
> -       [BEND_IDX(-30)] = 0x0325,
> -       [BEND_IDX(-35)] = 0x0325,
> -       [BEND_IDX(-40)] = 0x0425,
> -       [BEND_IDX(-45)] = 0x0425,
> -       [BEND_IDX(-50)] = 0x0525,
> -};
> -
> -/*
> - * Bend CLKOUT_DP
> - * steps -50 to 50 inclusive, in steps of 5
> - * < 0 slow down the clock, > 0 speed up the clock, 0 == no bend (135MHz)
> - * change in clock period = -(steps / 10) * 5.787 ps
> - */
> -static void lpt_bend_clkout_dp(struct drm_i915_private *dev_priv, int steps)
> -{
> -       u32 tmp;
> -       int idx = BEND_IDX(steps);
> -
> -       if (drm_WARN_ON(&dev_priv->drm, steps % 5 != 0))
> -               return;
> -
> -       if (drm_WARN_ON(&dev_priv->drm, idx >= ARRAY_SIZE(sscdivintphase)))
> -               return;
> -
> -       mutex_lock(&dev_priv->sb_lock);
> -
> -       if (steps % 10 != 0)
> -               tmp = 0xAAAAAAAB;
> -       else
> -               tmp = 0x00000000;
> -       intel_sbi_write(dev_priv, SBI_SSCDITHPHASE, tmp, SBI_ICLK);
> -
> -       tmp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE, SBI_ICLK);
> -       tmp &= 0xffff0000;
> -       tmp |= sscdivintphase[idx];
> -       intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE, tmp, SBI_ICLK);
> -
> -       mutex_unlock(&dev_priv->sb_lock);
> -}
> -
> -#undef BEND_IDX
> -
> -static bool spll_uses_pch_ssc(struct drm_i915_private *dev_priv)
> -{
> -       u32 fuse_strap = intel_de_read(dev_priv, FUSE_STRAP);
> -       u32 ctl = intel_de_read(dev_priv, SPLL_CTL);
> -
> -       if ((ctl & SPLL_PLL_ENABLE) == 0)
> -               return false;
> -
> -       if ((ctl & SPLL_REF_MASK) == SPLL_REF_MUXED_SSC &&
> -           (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)
> -               return true;
> -
> -       if (IS_BROADWELL(dev_priv) &&
> -           (ctl & SPLL_REF_MASK) == SPLL_REF_PCH_SSC_BDW)
> -               return true;
> -
> -       return false;
> -}
> -
> -static bool wrpll_uses_pch_ssc(struct drm_i915_private *dev_priv,
> -                              enum intel_dpll_id id)
> -{
> -       u32 fuse_strap = intel_de_read(dev_priv, FUSE_STRAP);
> -       u32 ctl = intel_de_read(dev_priv, WRPLL_CTL(id));
> -
> -       if ((ctl & WRPLL_PLL_ENABLE) == 0)
> -               return false;
> -
> -       if ((ctl & WRPLL_REF_MASK) == WRPLL_REF_PCH_SSC)
> -               return true;
> -
> -       if ((IS_BROADWELL(dev_priv) || IS_HSW_ULT(dev_priv)) &&
> -           (ctl & WRPLL_REF_MASK) == WRPLL_REF_MUXED_SSC_BDW &&
> -           (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)
> -               return true;
> -
> -       return false;
> -}
> -
> -static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv)
> -{
> -       struct intel_encoder *encoder;
> -       bool has_fdi = false;
> -
> -       for_each_intel_encoder(&dev_priv->drm, encoder) {
> -               switch (encoder->type) {
> -               case INTEL_OUTPUT_ANALOG:
> -                       has_fdi = true;
> -                       break;
> -               default:
> -                       break;
> -               }
> -       }
> -
> -       /*
> -        * The BIOS may have decided to use the PCH SSC
> -        * reference so we must not disable it until the
> -        * relevant PLLs have stopped relying on it. We'll
> -        * just leave the PCH SSC reference enabled in case
> -        * any active PLL is using it. It will get disabled
> -        * after runtime suspend if we don't have FDI.
> -        *
> -        * TODO: Move the whole reference clock handling
> -        * to the modeset sequence proper so that we can
> -        * actually enable/disable/reconfigure these things
> -        * safely. To do that we need to introduce a real
> -        * clock hierarchy. That would also allow us to do
> -        * clock bending finally.
> -        */
> -       dev_priv->pch_ssc_use = 0;
> -
> -       if (spll_uses_pch_ssc(dev_priv)) {
> -               drm_dbg_kms(&dev_priv->drm, "SPLL using PCH SSC\n");
> -               dev_priv->pch_ssc_use |= BIT(DPLL_ID_SPLL);
> -       }
> -
> -       if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL1)) {
> -               drm_dbg_kms(&dev_priv->drm, "WRPLL1 using PCH SSC\n");
> -               dev_priv->pch_ssc_use |= BIT(DPLL_ID_WRPLL1);
> -       }
> -
> -       if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL2)) {
> -               drm_dbg_kms(&dev_priv->drm, "WRPLL2 using PCH SSC\n");
> -               dev_priv->pch_ssc_use |= BIT(DPLL_ID_WRPLL2);
> -       }
> -
> -       if (dev_priv->pch_ssc_use)
> -               return;
> -
> -       if (has_fdi) {
> -               lpt_bend_clkout_dp(dev_priv, 0);
> -               lpt_enable_clkout_dp(dev_priv, true, true);
> -       } else {
> -               lpt_disable_clkout_dp(dev_priv);
> -       }
> -}
> -
> -/*
> - * Initialize reference clocks when the driver loads
> - */
> -void intel_init_pch_refclk(struct drm_i915_private *dev_priv)
> -{
> -       if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))
> -               ilk_init_pch_refclk(dev_priv);
> -       else if (HAS_PCH_LPT(dev_priv))
> -               lpt_init_pch_refclk(dev_priv);
> -}
> -
>  static void ilk_set_pipeconf(const struct intel_crtc_state *crtc_state)
>  {
>         struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
> index 0c76bf57f86b..39c18b8807f9 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.h
> +++ b/drivers/gpu/drm/i915/display/intel_display.h
> @@ -521,7 +521,6 @@ void intel_link_compute_m_n(u16 bpp, int nlanes,
>                             int pixel_clock, int link_clock,
>                             struct intel_link_m_n *m_n,
>                             bool constant_n, bool fec_enable);
> -void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv);
>  u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
>                               u32 pixel_format, u64 modifier);
>  enum drm_mode_status
> @@ -544,7 +543,6 @@ int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
>                            const char *name, u32 reg);
>  void lpt_pch_enable(const struct intel_crtc_state *crtc_state);
>  void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv);
> -void lpt_disable_iclkip(struct drm_i915_private *dev_priv);
>  void intel_init_display_hooks(struct drm_i915_private *dev_priv);
>  unsigned int intel_fb_xy_to_linear(int x, int y,
>                                    const struct intel_plane_state *state,
> @@ -583,7 +581,6 @@ intel_framebuffer_create(struct drm_i915_gem_object *obj,
>  void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
>                                     enum pipe pipe);
>
> -int lpt_get_iclkip(struct drm_i915_private *dev_priv);
>  bool intel_fuzzy_clock_check(int clock1, int clock2);
>
>  void intel_display_prepare_reset(struct drm_i915_private *dev_priv);
> @@ -632,7 +629,6 @@ void intel_modeset_driver_remove(struct drm_i915_private *i915);
>  void intel_modeset_driver_remove_noirq(struct drm_i915_private *i915);
>  void intel_modeset_driver_remove_nogem(struct drm_i915_private *i915);
>  void intel_display_resume(struct drm_device *dev);
> -void intel_init_pch_refclk(struct drm_i915_private *dev_priv);
>  int intel_modeset_all_pipes(struct intel_atomic_state *state);
>
>  /* modesetting asserts */
> diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
> index 1672604f9ef7..d88da0d0f05a 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_power.c
> +++ b/drivers/gpu/drm/i915/display/intel_display_power.c
> @@ -15,6 +15,7 @@
>  #include "intel_dpio_phy.h"
>  #include "intel_dpll.h"
>  #include "intel_hotplug.h"
> +#include "intel_pch_refclk.h"
>  #include "intel_pcode.h"
>  #include "intel_pm.h"
>  #include "intel_pps.h"
> diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
> index 0a7e04db04be..ca69b67bbc23 100644
> --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
> +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
> @@ -26,6 +26,7 @@
>  #include "intel_dpio_phy.h"
>  #include "intel_dpll.h"
>  #include "intel_dpll_mgr.h"
> +#include "intel_pch_refclk.h"
>  #include "intel_tc.h"
>
>  /**
> diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c
> index dd2cf0c59921..d1c1600c66cb 100644
> --- a/drivers/gpu/drm/i915/display/intel_fdi.c
> +++ b/drivers/gpu/drm/i915/display/intel_fdi.c
> @@ -8,7 +8,6 @@
>  #include "intel_de.h"
>  #include "intel_display_types.h"
>  #include "intel_fdi.h"
> -#include "intel_sbi.h"
>
>  static void assert_fdi_tx(struct drm_i915_private *dev_priv,
>                           enum pipe pipe, bool state)
> @@ -1006,104 +1005,6 @@ void ilk_fdi_disable(struct intel_crtc *crtc)
>         udelay(100);
>  }
>
> -static void lpt_fdi_reset_mphy(struct drm_i915_private *dev_priv)
> -{
> -       u32 tmp;
> -
> -       tmp = intel_de_read(dev_priv, SOUTH_CHICKEN2);
> -       tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
> -       intel_de_write(dev_priv, SOUTH_CHICKEN2, tmp);
> -
> -       if (wait_for_us(intel_de_read(dev_priv, SOUTH_CHICKEN2) &
> -                       FDI_MPHY_IOSFSB_RESET_STATUS, 100))
> -               drm_err(&dev_priv->drm, "FDI mPHY reset assert timeout\n");
> -
> -       tmp = intel_de_read(dev_priv, SOUTH_CHICKEN2);
> -       tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
> -       intel_de_write(dev_priv, SOUTH_CHICKEN2, tmp);
> -
> -       if (wait_for_us((intel_de_read(dev_priv, SOUTH_CHICKEN2) &
> -                        FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100))
> -               drm_err(&dev_priv->drm, "FDI mPHY reset de-assert timeout\n");
> -}
> -
> -/* WaMPhyProgramming:hsw */
> -void lpt_fdi_program_mphy(struct drm_i915_private *dev_priv)
> -{
> -       u32 tmp;
> -
> -       lpt_fdi_reset_mphy(dev_priv);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY);
> -       tmp &= ~(0xFF << 24);
> -       tmp |= (0x12 << 24);
> -       intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY);
> -       tmp |= (1 << 11);
> -       intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x2108, SBI_MPHY);
> -       tmp |= (1 << 11);
> -       intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY);
> -       tmp |= (1 << 24) | (1 << 21) | (1 << 18);
> -       intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x216C, SBI_MPHY);
> -       tmp |= (1 << 24) | (1 << 21) | (1 << 18);
> -       intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
> -       tmp &= ~(7 << 13);
> -       tmp |= (5 << 13);
> -       intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
> -       tmp &= ~(7 << 13);
> -       tmp |= (5 << 13);
> -       intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY);
> -       tmp &= ~0xFF;
> -       tmp |= 0x1C;
> -       intel_sbi_write(dev_priv, 0x208C, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x218C, SBI_MPHY);
> -       tmp &= ~0xFF;
> -       tmp |= 0x1C;
> -       intel_sbi_write(dev_priv, 0x218C, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x2098, SBI_MPHY);
> -       tmp &= ~(0xFF << 16);
> -       tmp |= (0x1C << 16);
> -       intel_sbi_write(dev_priv, 0x2098, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x2198, SBI_MPHY);
> -       tmp &= ~(0xFF << 16);
> -       tmp |= (0x1C << 16);
> -       intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
> -       tmp |= (1 << 27);
> -       intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
> -       tmp |= (1 << 27);
> -       intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
> -       tmp &= ~(0xF << 28);
> -       tmp |= (4 << 28);
> -       intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
> -
> -       tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
> -       tmp &= ~(0xF << 28);
> -       tmp |= (4 << 28);
> -       intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
> -}
> -
>  static const struct intel_fdi_funcs ilk_funcs = {
>         .fdi_link_train = ilk_fdi_link_train,
>  };
> diff --git a/drivers/gpu/drm/i915/display/intel_fdi.h b/drivers/gpu/drm/i915/display/intel_fdi.h
> index 640d6585c137..5a361730f80a 100644
> --- a/drivers/gpu/drm/i915/display/intel_fdi.h
> +++ b/drivers/gpu/drm/i915/display/intel_fdi.h
> @@ -24,7 +24,6 @@ void intel_fdi_init_hook(struct drm_i915_private *dev_priv);
>  void hsw_fdi_link_train(struct intel_encoder *encoder,
>                         const struct intel_crtc_state *crtc_state);
>  void intel_fdi_pll_freq_update(struct drm_i915_private *i915);
> -void lpt_fdi_program_mphy(struct drm_i915_private *i915);
>
>  void intel_fdi_link_train(struct intel_crtc *crtc,
>                           const struct intel_crtc_state *crtc_state);
> diff --git a/drivers/gpu/drm/i915/display/intel_pch_refclk.c b/drivers/gpu/drm/i915/display/intel_pch_refclk.c
> new file mode 100644
> index 000000000000..b688fd87e3da
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_pch_refclk.c
> @@ -0,0 +1,648 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +
> +#include "intel_de.h"
> +#include "intel_display_types.h"
> +#include "intel_panel.h"
> +#include "intel_pch_refclk.h"
> +#include "intel_sbi.h"
> +
> +static void lpt_fdi_reset_mphy(struct drm_i915_private *dev_priv)
> +{
> +       u32 tmp;
> +
> +       tmp = intel_de_read(dev_priv, SOUTH_CHICKEN2);
> +       tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
> +       intel_de_write(dev_priv, SOUTH_CHICKEN2, tmp);
> +
> +       if (wait_for_us(intel_de_read(dev_priv, SOUTH_CHICKEN2) &
> +                       FDI_MPHY_IOSFSB_RESET_STATUS, 100))
> +               drm_err(&dev_priv->drm, "FDI mPHY reset assert timeout\n");
> +
> +       tmp = intel_de_read(dev_priv, SOUTH_CHICKEN2);
> +       tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
> +       intel_de_write(dev_priv, SOUTH_CHICKEN2, tmp);
> +
> +       if (wait_for_us((intel_de_read(dev_priv, SOUTH_CHICKEN2) &
> +                        FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100))
> +               drm_err(&dev_priv->drm, "FDI mPHY reset de-assert timeout\n");
> +}
> +
> +/* WaMPhyProgramming:hsw */
> +static void lpt_fdi_program_mphy(struct drm_i915_private *dev_priv)
> +{
> +       u32 tmp;
> +
> +       lpt_fdi_reset_mphy(dev_priv);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY);
> +       tmp &= ~(0xFF << 24);
> +       tmp |= (0x12 << 24);
> +       intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY);
> +       tmp |= (1 << 11);
> +       intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x2108, SBI_MPHY);
> +       tmp |= (1 << 11);
> +       intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY);
> +       tmp |= (1 << 24) | (1 << 21) | (1 << 18);
> +       intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x216C, SBI_MPHY);
> +       tmp |= (1 << 24) | (1 << 21) | (1 << 18);
> +       intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
> +       tmp &= ~(7 << 13);
> +       tmp |= (5 << 13);
> +       intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
> +       tmp &= ~(7 << 13);
> +       tmp |= (5 << 13);
> +       intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY);
> +       tmp &= ~0xFF;
> +       tmp |= 0x1C;
> +       intel_sbi_write(dev_priv, 0x208C, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x218C, SBI_MPHY);
> +       tmp &= ~0xFF;
> +       tmp |= 0x1C;
> +       intel_sbi_write(dev_priv, 0x218C, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x2098, SBI_MPHY);
> +       tmp &= ~(0xFF << 16);
> +       tmp |= (0x1C << 16);
> +       intel_sbi_write(dev_priv, 0x2098, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x2198, SBI_MPHY);
> +       tmp &= ~(0xFF << 16);
> +       tmp |= (0x1C << 16);
> +       intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
> +       tmp |= (1 << 27);
> +       intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
> +       tmp |= (1 << 27);
> +       intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
> +       tmp &= ~(0xF << 28);
> +       tmp |= (4 << 28);
> +       intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
> +
> +       tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
> +       tmp &= ~(0xF << 28);
> +       tmp |= (4 << 28);
> +       intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
> +}
> +
> +void lpt_disable_iclkip(struct drm_i915_private *dev_priv)
> +{
> +       u32 temp;
> +
> +       intel_de_write(dev_priv, PIXCLK_GATE, PIXCLK_GATE_GATE);
> +
> +       mutex_lock(&dev_priv->sb_lock);
> +
> +       temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
> +       temp |= SBI_SSCCTL_DISABLE;
> +       intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);
> +
> +       mutex_unlock(&dev_priv->sb_lock);
> +}
> +
> +/* Program iCLKIP clock to the desired frequency */
> +void lpt_program_iclkip(const struct intel_crtc_state *crtc_state)
> +{
> +       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +       int clock = crtc_state->hw.adjusted_mode.crtc_clock;
> +       u32 divsel, phaseinc, auxdiv, phasedir = 0;
> +       u32 temp;
> +
> +       lpt_disable_iclkip(dev_priv);
> +
> +       /* The iCLK virtual clock root frequency is in MHz,
> +        * but the adjusted_mode->crtc_clock in KHz. To get the
> +        * divisors, it is necessary to divide one by another, so we
> +        * convert the virtual clock precision to KHz here for higher
> +        * precision.
> +        */
> +       for (auxdiv = 0; auxdiv < 2; auxdiv++) {
> +               u32 iclk_virtual_root_freq = 172800 * 1000;
> +               u32 iclk_pi_range = 64;
> +               u32 desired_divisor;
> +
> +               desired_divisor = DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
> +                                                   clock << auxdiv);
> +               divsel = (desired_divisor / iclk_pi_range) - 2;
> +               phaseinc = desired_divisor % iclk_pi_range;
> +
> +               /*
> +                * Near 20MHz is a corner case which is
> +                * out of range for the 7-bit divisor
> +                */
> +               if (divsel <= 0x7f)
> +                       break;
> +       }
> +
> +       /* This should not happen with any sane values */
> +       drm_WARN_ON(&dev_priv->drm, SBI_SSCDIVINTPHASE_DIVSEL(divsel) &
> +                   ~SBI_SSCDIVINTPHASE_DIVSEL_MASK);
> +       drm_WARN_ON(&dev_priv->drm, SBI_SSCDIVINTPHASE_DIR(phasedir) &
> +                   ~SBI_SSCDIVINTPHASE_INCVAL_MASK);
> +
> +       drm_dbg_kms(&dev_priv->drm,
> +                   "iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n",
> +                   clock, auxdiv, divsel, phasedir, phaseinc);
> +
> +       mutex_lock(&dev_priv->sb_lock);
> +
> +       /* Program SSCDIVINTPHASE6 */
> +       temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
> +       temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK;
> +       temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel);
> +       temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK;
> +       temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc);
> +       temp |= SBI_SSCDIVINTPHASE_DIR(phasedir);
> +       temp |= SBI_SSCDIVINTPHASE_PROPAGATE;
> +       intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE6, temp, SBI_ICLK);
> +
> +       /* Program SSCAUXDIV */
> +       temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
> +       temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1);
> +       temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv);
> +       intel_sbi_write(dev_priv, SBI_SSCAUXDIV6, temp, SBI_ICLK);
> +
> +       /* Enable modulator and associated divider */
> +       temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
> +       temp &= ~SBI_SSCCTL_DISABLE;
> +       intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);
> +
> +       mutex_unlock(&dev_priv->sb_lock);
> +
> +       /* Wait for initialization time */
> +       udelay(24);
> +
> +       intel_de_write(dev_priv, PIXCLK_GATE, PIXCLK_GATE_UNGATE);
> +}
> +
> +int lpt_get_iclkip(struct drm_i915_private *dev_priv)
> +{
> +       u32 divsel, phaseinc, auxdiv;
> +       u32 iclk_virtual_root_freq = 172800 * 1000;
> +       u32 iclk_pi_range = 64;
> +       u32 desired_divisor;
> +       u32 temp;
> +
> +       if ((intel_de_read(dev_priv, PIXCLK_GATE) & PIXCLK_GATE_UNGATE) == 0)
> +               return 0;
> +
> +       mutex_lock(&dev_priv->sb_lock);
> +
> +       temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
> +       if (temp & SBI_SSCCTL_DISABLE) {
> +               mutex_unlock(&dev_priv->sb_lock);
> +               return 0;
> +       }
> +
> +       temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
> +       divsel = (temp & SBI_SSCDIVINTPHASE_DIVSEL_MASK) >>
> +               SBI_SSCDIVINTPHASE_DIVSEL_SHIFT;
> +       phaseinc = (temp & SBI_SSCDIVINTPHASE_INCVAL_MASK) >>
> +               SBI_SSCDIVINTPHASE_INCVAL_SHIFT;
> +
> +       temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
> +       auxdiv = (temp & SBI_SSCAUXDIV_FINALDIV2SEL_MASK) >>
> +               SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT;
> +
> +       mutex_unlock(&dev_priv->sb_lock);
> +
> +       desired_divisor = (divsel + 2) * iclk_pi_range + phaseinc;
> +
> +       return DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
> +                                desired_divisor << auxdiv);
> +}
> +
> +/* Implements 3 different sequences from BSpec chapter "Display iCLK
> + * Programming" based on the parameters passed:
> + * - Sequence to enable CLKOUT_DP
> + * - Sequence to enable CLKOUT_DP without spread
> + * - Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O
> + */
> +static void lpt_enable_clkout_dp(struct drm_i915_private *dev_priv,
> +                                bool with_spread, bool with_fdi)
> +{
> +       u32 reg, tmp;
> +
> +       if (drm_WARN(&dev_priv->drm, with_fdi && !with_spread,
> +                    "FDI requires downspread\n"))
> +               with_spread = true;
> +       if (drm_WARN(&dev_priv->drm, HAS_PCH_LPT_LP(dev_priv) &&
> +                    with_fdi, "LP PCH doesn't have FDI\n"))
> +               with_fdi = false;
> +
> +       mutex_lock(&dev_priv->sb_lock);
> +
> +       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
> +       tmp &= ~SBI_SSCCTL_DISABLE;
> +       tmp |= SBI_SSCCTL_PATHALT;
> +       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
> +
> +       udelay(24);
> +
> +       if (with_spread) {
> +               tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
> +               tmp &= ~SBI_SSCCTL_PATHALT;
> +               intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
> +
> +               if (with_fdi)
> +                       lpt_fdi_program_mphy(dev_priv);
> +       }
> +
> +       reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;
> +       tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
> +       tmp |= SBI_GEN0_CFG_BUFFENABLE_DISABLE;
> +       intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
> +
> +       mutex_unlock(&dev_priv->sb_lock);
> +}
> +
> +/* Sequence to disable CLKOUT_DP */
> +void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv)
> +{
> +       u32 reg, tmp;
> +
> +       mutex_lock(&dev_priv->sb_lock);
> +
> +       reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;
> +       tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
> +       tmp &= ~SBI_GEN0_CFG_BUFFENABLE_DISABLE;
> +       intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
> +
> +       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
> +       if (!(tmp & SBI_SSCCTL_DISABLE)) {
> +               if (!(tmp & SBI_SSCCTL_PATHALT)) {
> +                       tmp |= SBI_SSCCTL_PATHALT;
> +                       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
> +                       udelay(32);
> +               }
> +               tmp |= SBI_SSCCTL_DISABLE;
> +               intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
> +       }
> +
> +       mutex_unlock(&dev_priv->sb_lock);
> +}
> +
> +#define BEND_IDX(steps) ((50 + (steps)) / 5)
> +
> +static const u16 sscdivintphase[] = {
> +       [BEND_IDX( 50)] = 0x3B23,
> +       [BEND_IDX( 45)] = 0x3B23,
> +       [BEND_IDX( 40)] = 0x3C23,
> +       [BEND_IDX( 35)] = 0x3C23,
> +       [BEND_IDX( 30)] = 0x3D23,
> +       [BEND_IDX( 25)] = 0x3D23,
> +       [BEND_IDX( 20)] = 0x3E23,
> +       [BEND_IDX( 15)] = 0x3E23,
> +       [BEND_IDX( 10)] = 0x3F23,
> +       [BEND_IDX(  5)] = 0x3F23,
> +       [BEND_IDX(  0)] = 0x0025,
> +       [BEND_IDX( -5)] = 0x0025,
> +       [BEND_IDX(-10)] = 0x0125,
> +       [BEND_IDX(-15)] = 0x0125,
> +       [BEND_IDX(-20)] = 0x0225,
> +       [BEND_IDX(-25)] = 0x0225,
> +       [BEND_IDX(-30)] = 0x0325,
> +       [BEND_IDX(-35)] = 0x0325,
> +       [BEND_IDX(-40)] = 0x0425,
> +       [BEND_IDX(-45)] = 0x0425,
> +       [BEND_IDX(-50)] = 0x0525,
> +};
> +
> +/*
> + * Bend CLKOUT_DP
> + * steps -50 to 50 inclusive, in steps of 5
> + * < 0 slow down the clock, > 0 speed up the clock, 0 == no bend (135MHz)
> + * change in clock period = -(steps / 10) * 5.787 ps
> + */
> +static void lpt_bend_clkout_dp(struct drm_i915_private *dev_priv, int steps)
> +{
> +       u32 tmp;
> +       int idx = BEND_IDX(steps);
> +
> +       if (drm_WARN_ON(&dev_priv->drm, steps % 5 != 0))
> +               return;
> +
> +       if (drm_WARN_ON(&dev_priv->drm, idx >= ARRAY_SIZE(sscdivintphase)))
> +               return;
> +
> +       mutex_lock(&dev_priv->sb_lock);
> +
> +       if (steps % 10 != 0)
> +               tmp = 0xAAAAAAAB;
> +       else
> +               tmp = 0x00000000;
> +       intel_sbi_write(dev_priv, SBI_SSCDITHPHASE, tmp, SBI_ICLK);
> +
> +       tmp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE, SBI_ICLK);
> +       tmp &= 0xffff0000;
> +       tmp |= sscdivintphase[idx];
> +       intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE, tmp, SBI_ICLK);
> +
> +       mutex_unlock(&dev_priv->sb_lock);
> +}
> +
> +#undef BEND_IDX
> +
> +static bool spll_uses_pch_ssc(struct drm_i915_private *dev_priv)
> +{
> +       u32 fuse_strap = intel_de_read(dev_priv, FUSE_STRAP);
> +       u32 ctl = intel_de_read(dev_priv, SPLL_CTL);
> +
> +       if ((ctl & SPLL_PLL_ENABLE) == 0)
> +               return false;
> +
> +       if ((ctl & SPLL_REF_MASK) == SPLL_REF_MUXED_SSC &&
> +           (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)
> +               return true;
> +
> +       if (IS_BROADWELL(dev_priv) &&
> +           (ctl & SPLL_REF_MASK) == SPLL_REF_PCH_SSC_BDW)
> +               return true;
> +
> +       return false;
> +}
> +
> +static bool wrpll_uses_pch_ssc(struct drm_i915_private *dev_priv,
> +                              enum intel_dpll_id id)
> +{
> +       u32 fuse_strap = intel_de_read(dev_priv, FUSE_STRAP);
> +       u32 ctl = intel_de_read(dev_priv, WRPLL_CTL(id));
> +
> +       if ((ctl & WRPLL_PLL_ENABLE) == 0)
> +               return false;
> +
> +       if ((ctl & WRPLL_REF_MASK) == WRPLL_REF_PCH_SSC)
> +               return true;
> +
> +       if ((IS_BROADWELL(dev_priv) || IS_HSW_ULT(dev_priv)) &&
> +           (ctl & WRPLL_REF_MASK) == WRPLL_REF_MUXED_SSC_BDW &&
> +           (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)
> +               return true;
> +
> +       return false;
> +}
> +
> +static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv)
> +{
> +       struct intel_encoder *encoder;
> +       bool has_fdi = false;
> +
> +       for_each_intel_encoder(&dev_priv->drm, encoder) {
> +               switch (encoder->type) {
> +               case INTEL_OUTPUT_ANALOG:
> +                       has_fdi = true;
> +                       break;
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       /*
> +        * The BIOS may have decided to use the PCH SSC
> +        * reference so we must not disable it until the
> +        * relevant PLLs have stopped relying on it. We'll
> +        * just leave the PCH SSC reference enabled in case
> +        * any active PLL is using it. It will get disabled
> +        * after runtime suspend if we don't have FDI.
> +        *
> +        * TODO: Move the whole reference clock handling
> +        * to the modeset sequence proper so that we can
> +        * actually enable/disable/reconfigure these things
> +        * safely. To do that we need to introduce a real
> +        * clock hierarchy. That would also allow us to do
> +        * clock bending finally.
> +        */
> +       dev_priv->pch_ssc_use = 0;
> +
> +       if (spll_uses_pch_ssc(dev_priv)) {
> +               drm_dbg_kms(&dev_priv->drm, "SPLL using PCH SSC\n");
> +               dev_priv->pch_ssc_use |= BIT(DPLL_ID_SPLL);
> +       }
> +
> +       if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL1)) {
> +               drm_dbg_kms(&dev_priv->drm, "WRPLL1 using PCH SSC\n");
> +               dev_priv->pch_ssc_use |= BIT(DPLL_ID_WRPLL1);
> +       }
> +
> +       if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL2)) {
> +               drm_dbg_kms(&dev_priv->drm, "WRPLL2 using PCH SSC\n");
> +               dev_priv->pch_ssc_use |= BIT(DPLL_ID_WRPLL2);
> +       }
> +
> +       if (dev_priv->pch_ssc_use)
> +               return;
> +
> +       if (has_fdi) {
> +               lpt_bend_clkout_dp(dev_priv, 0);
> +               lpt_enable_clkout_dp(dev_priv, true, true);
> +       } else {
> +               lpt_disable_clkout_dp(dev_priv);
> +       }
> +}
> +
> +static void ilk_init_pch_refclk(struct drm_i915_private *dev_priv)
> +{
> +       struct intel_encoder *encoder;
> +       int i;
> +       u32 val, final;
> +       bool has_lvds = false;
> +       bool has_cpu_edp = false;
> +       bool has_panel = false;
> +       bool has_ck505 = false;
> +       bool can_ssc = false;
> +       bool using_ssc_source = false;
> +
> +       /* We need to take the global config into account */
> +       for_each_intel_encoder(&dev_priv->drm, encoder) {
> +               switch (encoder->type) {
> +               case INTEL_OUTPUT_LVDS:
> +                       has_panel = true;
> +                       has_lvds = true;
> +                       break;
> +               case INTEL_OUTPUT_EDP:
> +                       has_panel = true;
> +                       if (encoder->port == PORT_A)
> +                               has_cpu_edp = true;
> +                       break;
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       if (HAS_PCH_IBX(dev_priv)) {
> +               has_ck505 = dev_priv->vbt.display_clock_mode;
> +               can_ssc = has_ck505;
> +       } else {
> +               has_ck505 = false;
> +               can_ssc = true;
> +       }
> +
> +       /* Check if any DPLLs are using the SSC source */
> +       for (i = 0; i < dev_priv->dpll.num_shared_dpll; i++) {
> +               u32 temp = intel_de_read(dev_priv, PCH_DPLL(i));
> +
> +               if (!(temp & DPLL_VCO_ENABLE))
> +                       continue;
> +
> +               if ((temp & PLL_REF_INPUT_MASK) ==
> +                   PLLB_REF_INPUT_SPREADSPECTRUMIN) {
> +                       using_ssc_source = true;
> +                       break;
> +               }
> +       }
> +
> +       drm_dbg_kms(&dev_priv->drm,
> +                   "has_panel %d has_lvds %d has_ck505 %d using_ssc_source %d\n",
> +                   has_panel, has_lvds, has_ck505, using_ssc_source);
> +
> +       /* Ironlake: try to setup display ref clock before DPLL
> +        * enabling. This is only under driver's control after
> +        * PCH B stepping, previous chipset stepping should be
> +        * ignoring this setting.
> +        */
> +       val = intel_de_read(dev_priv, PCH_DREF_CONTROL);
> +
> +       /* As we must carefully and slowly disable/enable each source in turn,
> +        * compute the final state we want first and check if we need to
> +        * make any changes at all.
> +        */
> +       final = val;
> +       final &= ~DREF_NONSPREAD_SOURCE_MASK;
> +       if (has_ck505)
> +               final |= DREF_NONSPREAD_CK505_ENABLE;
> +       else
> +               final |= DREF_NONSPREAD_SOURCE_ENABLE;
> +
> +       final &= ~DREF_SSC_SOURCE_MASK;
> +       final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
> +       final &= ~DREF_SSC1_ENABLE;
> +
> +       if (has_panel) {
> +               final |= DREF_SSC_SOURCE_ENABLE;
> +
> +               if (intel_panel_use_ssc(dev_priv) && can_ssc)
> +                       final |= DREF_SSC1_ENABLE;
> +
> +               if (has_cpu_edp) {
> +                       if (intel_panel_use_ssc(dev_priv) && can_ssc)
> +                               final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
> +                       else
> +                               final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
> +               } else {
> +                       final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
> +               }
> +       } else if (using_ssc_source) {
> +               final |= DREF_SSC_SOURCE_ENABLE;
> +               final |= DREF_SSC1_ENABLE;
> +       }
> +
> +       if (final == val)
> +               return;
> +
> +       /* Always enable nonspread source */
> +       val &= ~DREF_NONSPREAD_SOURCE_MASK;
> +
> +       if (has_ck505)
> +               val |= DREF_NONSPREAD_CK505_ENABLE;
> +       else
> +               val |= DREF_NONSPREAD_SOURCE_ENABLE;
> +
> +       if (has_panel) {
> +               val &= ~DREF_SSC_SOURCE_MASK;
> +               val |= DREF_SSC_SOURCE_ENABLE;
> +
> +               /* SSC must be turned on before enabling the CPU output  */
> +               if (intel_panel_use_ssc(dev_priv) && can_ssc) {
> +                       drm_dbg_kms(&dev_priv->drm, "Using SSC on panel\n");
> +                       val |= DREF_SSC1_ENABLE;
> +               } else {
> +                       val &= ~DREF_SSC1_ENABLE;
> +               }
> +
> +               /* Get SSC going before enabling the outputs */
> +               intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
> +               intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
> +               udelay(200);
> +
> +               val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
> +
> +               /* Enable CPU source on CPU attached eDP */
> +               if (has_cpu_edp) {
> +                       if (intel_panel_use_ssc(dev_priv) && can_ssc) {
> +                               drm_dbg_kms(&dev_priv->drm,
> +                                           "Using SSC on eDP\n");
> +                               val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
> +                       } else {
> +                               val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
> +                       }
> +               } else {
> +                       val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
> +               }
> +
> +               intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
> +               intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
> +               udelay(200);
> +       } else {
> +               drm_dbg_kms(&dev_priv->drm, "Disabling CPU source output\n");
> +
> +               val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
> +
> +               /* Turn off CPU output */
> +               val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
> +
> +               intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
> +               intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
> +               udelay(200);
> +
> +               if (!using_ssc_source) {
> +                       drm_dbg_kms(&dev_priv->drm, "Disabling SSC source\n");
> +
> +                       /* Turn off the SSC source */
> +                       val &= ~DREF_SSC_SOURCE_MASK;
> +                       val |= DREF_SSC_SOURCE_DISABLE;
> +
> +                       /* Turn off SSC1 */
> +                       val &= ~DREF_SSC1_ENABLE;
> +
> +                       intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
> +                       intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
> +                       udelay(200);
> +               }
> +       }
> +
> +       BUG_ON(val != final);
> +}
> +
> +/*
> + * Initialize reference clocks when the driver loads
> + */
> +void intel_init_pch_refclk(struct drm_i915_private *dev_priv)
> +{
> +       if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))
> +               ilk_init_pch_refclk(dev_priv);
> +       else if (HAS_PCH_LPT(dev_priv))
> +               lpt_init_pch_refclk(dev_priv);
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_pch_refclk.h b/drivers/gpu/drm/i915/display/intel_pch_refclk.h
> new file mode 100644
> index 000000000000..12ab2c75a800
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_pch_refclk.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +
> +#ifndef _INTEL_PCH_REFCLK_H_
> +#define _INTEL_PCH_REFCLK_H_
> +
> +#include <linux/types.h>
> +
> +struct drm_i915_private;
> +struct intel_crtc_state;
> +
> +void lpt_program_iclkip(const struct intel_crtc_state *crtc_state);
> +void lpt_disable_iclkip(struct drm_i915_private *dev_priv);
> +int lpt_get_iclkip(struct drm_i915_private *dev_priv);
> +
> +void intel_init_pch_refclk(struct drm_i915_private *dev_priv);
> +void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv);
> +
> +#endif
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index b18a250e5d2e..1e5b75ae9932 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -54,6 +54,7 @@
>  #include "display/intel_fbdev.h"
>  #include "display/intel_hotplug.h"
>  #include "display/intel_overlay.h"
> +#include "display/intel_pch_refclk.h"
>  #include "display/intel_pipe_crc.h"
>  #include "display/intel_pps.h"
>  #include "display/intel_sprite.h"
> --
> 2.32.0
>



More information about the Intel-gfx mailing list