drm/i915/dg2: Add MPLLB programming for HDMI
authorMatt Roper <matthew.d.roper@intel.com>
Fri, 23 Jul 2021 17:42:33 +0000 (10:42 -0700)
committerMatt Roper <matthew.d.roper@intel.com>
Thu, 29 Jul 2021 16:06:01 +0000 (09:06 -0700)
At the moment we don't have a proper algorithm that can be used to
calculate PHY settings for arbitrary HDMI link rates.  The PHY tables
here should support the regular modes of real-world HDMI monitors.

Bspec: 54032
Cc: Matt Atwood <matthew.s.atwood@intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
Reviewed-by: Matt Atwood <matthew.s.atwood@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210723174239.1551352-25-matthew.d.roper@intel.com
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_hdmi.c
drivers/gpu/drm/i915/display/intel_snps_phy.c
drivers/gpu/drm/i915/display/intel_snps_phy.h
drivers/gpu/drm/i915/i915_reg.h

index 061a663..f48bc97 100644 (file)
@@ -51,6 +51,7 @@
 #include "intel_panel.h"
 #include "intel_pps.h"
 #include "intel_psr.h"
+#include "intel_snps_phy.h"
 #include "intel_sprite.h"
 #include "intel_tc.h"
 #include "intel_vdsc.h"
@@ -3754,6 +3755,15 @@ void intel_ddi_get_clock(struct intel_encoder *encoder,
                                                     &crtc_state->dpll_hw_state);
 }
 
+static void dg2_ddi_get_config(struct intel_encoder *encoder,
+                               struct intel_crtc_state *crtc_state)
+{
+       intel_mpllb_readout_hw_state(encoder, &crtc_state->mpllb_state);
+       crtc_state->port_clock = intel_mpllb_calc_port_clock(encoder, &crtc_state->mpllb_state);
+
+       intel_ddi_get_config(encoder, crtc_state);
+}
+
 static void adls_ddi_get_config(struct intel_encoder *encoder,
                                struct intel_crtc_state *crtc_state)
 {
@@ -4616,7 +4626,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
        encoder->cloneable = 0;
        encoder->pipe_mask = ~0;
 
-       if (IS_ALDERLAKE_S(dev_priv)) {
+       if (IS_DG2(dev_priv)) {
+               encoder->get_config = dg2_ddi_get_config;
+       } else if (IS_ALDERLAKE_S(dev_priv)) {
                encoder->enable_clock = adls_ddi_enable_clock;
                encoder->disable_clock = adls_ddi_disable_clock;
                encoder->is_clock_enabled = adls_ddi_is_clock_enabled;
index 82298b0..378c05b 100644 (file)
@@ -9182,6 +9182,52 @@ verify_shared_dpll_state(struct intel_crtc *crtc,
        }
 }
 
+static void
+verify_mpllb_state(struct intel_atomic_state *state,
+                  struct intel_crtc_state *new_crtc_state)
+{
+       struct drm_i915_private *i915 = to_i915(state->base.dev);
+       struct intel_mpllb_state mpllb_hw_state = { 0 };
+       struct intel_mpllb_state *mpllb_sw_state = &new_crtc_state->mpllb_state;
+       struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
+       struct intel_encoder *encoder;
+
+       if (!IS_DG2(i915))
+               return;
+
+       if (!new_crtc_state->hw.active)
+               return;
+
+       encoder = intel_get_crtc_new_encoder(state, new_crtc_state);
+       intel_mpllb_readout_hw_state(encoder, &mpllb_hw_state);
+
+#define MPLLB_CHECK(name) do { \
+       if (mpllb_sw_state->name != mpllb_hw_state.name) { \
+               pipe_config_mismatch(false, crtc, "MPLLB:" __stringify(name), \
+                                    "(expected 0x%08x, found 0x%08x)", \
+                                    mpllb_sw_state->name, \
+                                    mpllb_hw_state.name); \
+       } \
+} while (0)
+
+       MPLLB_CHECK(mpllb_cp);
+       MPLLB_CHECK(mpllb_div);
+       MPLLB_CHECK(mpllb_div2);
+       MPLLB_CHECK(mpllb_fracn1);
+       MPLLB_CHECK(mpllb_fracn2);
+       MPLLB_CHECK(mpllb_sscen);
+       MPLLB_CHECK(mpllb_sscstep);
+
+       /*
+        * ref_control is handled by the hardware/firemware and never
+        * programmed by the software, but the proper values are supplied
+        * in the bspec for verification purposes.
+        */
+       MPLLB_CHECK(ref_control);
+
+#undef MPLLB_CHECK
+}
+
 static void
 intel_modeset_verify_crtc(struct intel_crtc *crtc,
                          struct intel_atomic_state *state,
@@ -9195,6 +9241,7 @@ intel_modeset_verify_crtc(struct intel_crtc *crtc,
        verify_connector_state(state, crtc);
        verify_crtc_state(crtc, old_crtc_state, new_crtc_state);
        verify_shared_dpll_state(crtc, old_crtc_state, new_crtc_state);
+       verify_mpllb_state(state, new_crtc_state);
 }
 
 static void
index 852af2b..b04685b 100644 (file)
@@ -51,6 +51,7 @@
 #include "intel_hdmi.h"
 #include "intel_lspcon.h"
 #include "intel_panel.h"
+#include "intel_snps_phy.h"
 
 static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
 {
@@ -1850,6 +1851,16 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi,
        if (IS_CHERRYVIEW(dev_priv) && clock > 216000 && clock < 240000)
                return MODE_CLOCK_RANGE;
 
+       /*
+        * SNPS PHYs' MPLLB table-based programming can only handle a fixed
+        * set of link rates.
+        *
+        * FIXME: We will hopefully get an algorithmic way of programming
+        * the MPLLB for HDMI in the future.
+        */
+       if (IS_DG2(dev_priv))
+               return intel_snps_phy_check_hdmi_link_rate(clock);
+
        return MODE_OK;
 }
 
index 6d92059..1317b4e 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright © 2019 Intel Corporation
  */
 
+#include <linux/util_macros.h>
+
 #include "intel_de.h"
 #include "intel_display_types.h"
 #include "intel_snps_phy.h"
@@ -375,14 +377,172 @@ static const struct intel_mpllb_state *dg2_edp_tables[] = {
        NULL,
 };
 
-int intel_mpllb_calc_state(struct intel_crtc_state *crtc_state,
-                          struct intel_encoder *encoder)
-{
-       const struct intel_mpllb_state **tables;
-       int i;
+/*
+ * HDMI link rates with 100 MHz reference clock.
+ */
+
+static const struct intel_mpllb_state dg2_hdmi_25_175 = {
+       .clock = 25175,
+       .ref_control =
+               REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
+       .mpllb_cp =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 5) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 15) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
+       .mpllb_div =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 5) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2),
+       .mpllb_div2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 128) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
+       .mpllb_fracn1 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 143),
+       .mpllb_fracn2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 36663) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 71),
+       .mpllb_sscen =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
+};
+
+static const struct intel_mpllb_state dg2_hdmi_27_0 = {
+       .clock = 27000,
+       .ref_control =
+               REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
+       .mpllb_cp =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 5) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 15) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
+       .mpllb_div =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 5) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2),
+       .mpllb_div2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 140) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
+       .mpllb_fracn1 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 5),
+       .mpllb_fracn2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 26214) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 2),
+       .mpllb_sscen =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
+};
+
+static const struct intel_mpllb_state dg2_hdmi_74_25 = {
+       .clock = 74250,
+       .ref_control =
+               REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
+       .mpllb_cp =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 4) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 15) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
+       .mpllb_div =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
+       .mpllb_div2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 86) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
+       .mpllb_fracn1 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 5),
+       .mpllb_fracn2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 26214) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 2),
+       .mpllb_sscen =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
+};
+
+static const struct intel_mpllb_state dg2_hdmi_148_5 = {
+       .clock = 148500,
+       .ref_control =
+               REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
+       .mpllb_cp =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 4) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 15) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
+       .mpllb_div =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 2) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
+       .mpllb_div2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 86) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
+       .mpllb_fracn1 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 5),
+       .mpllb_fracn2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 26214) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 2),
+       .mpllb_sscen =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
+};
+
+static const struct intel_mpllb_state dg2_hdmi_594 = {
+       .clock = 594000,
+       .ref_control =
+               REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
+       .mpllb_cp =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 4) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 15) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
+       .mpllb_div =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
+       .mpllb_div2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 86) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
+       .mpllb_fracn1 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 5),
+       .mpllb_fracn2 =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 26214) |
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 2),
+       .mpllb_sscen =
+               REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
+};
 
+static const struct intel_mpllb_state *dg2_hdmi_tables[] = {
+       &dg2_hdmi_25_175,
+       &dg2_hdmi_27_0,
+       &dg2_hdmi_74_25,
+       &dg2_hdmi_148_5,
+       &dg2_hdmi_594,
+       NULL,
+};
+
+static const struct intel_mpllb_state **
+intel_mpllb_tables_get(struct intel_crtc_state *crtc_state,
+                      struct intel_encoder *encoder)
+{
        if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) {
-               tables = dg2_edp_tables;
+               return dg2_edp_tables;
        } else if (intel_crtc_has_dp_encoder(crtc_state)) {
                /*
                 * FIXME: Initially we're just enabling the "combo" outputs on
@@ -397,15 +557,41 @@ int intel_mpllb_calc_state(struct intel_crtc_state *crtc_state,
                 * that to determine which table to use.
                 */
                if (0)
-                       tables = dg2_dp_38_4_tables;
+                       return dg2_dp_38_4_tables;
                else
-                       tables = dg2_dp_100_tables;
-       } else {
-               /* TODO: Add HDMI support */
-               MISSING_CASE(encoder->type);
-               return -EINVAL;
+                       return dg2_dp_100_tables;
+       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
+               return dg2_hdmi_tables;
        }
 
+       MISSING_CASE(encoder->type);
+       return NULL;
+}
+
+int intel_mpllb_calc_state(struct intel_crtc_state *crtc_state,
+                          struct intel_encoder *encoder)
+{
+       const struct intel_mpllb_state **tables;
+       int i;
+
+       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
+               if (intel_snps_phy_check_hdmi_link_rate(crtc_state->port_clock)
+                   != MODE_OK) {
+                       /*
+                        * FIXME: Can only support fixed HDMI frequencies
+                        * until we have a proper algorithm under a valid
+                        * license.
+                        */
+                       DRM_DEBUG_KMS("Can't support HDMI link rate %d\n",
+                                     crtc_state->port_clock);
+                       return -EINVAL;
+               }
+       }
+
+       tables = intel_mpllb_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->mpllb_state = *tables[i];
@@ -515,3 +701,79 @@ void intel_mpllb_disable(struct intel_encoder *encoder)
         * We handle this step in bxt_set_cdclk().
         */
 }
+
+int intel_mpllb_calc_port_clock(struct intel_encoder *encoder,
+                               const struct intel_mpllb_state *pll_state)
+{
+       unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1;
+       unsigned int multiplier, tx_clk_div, refclk;
+       bool frac_en;
+
+       if (0)
+               refclk = 38400;
+       else
+               refclk = 100000;
+
+       refclk >>= REG_FIELD_GET(SNPS_PHY_MPLLB_REF_CLK_DIV, pll_state->mpllb_div2) - 1;
+
+       frac_en = REG_FIELD_GET(SNPS_PHY_MPLLB_FRACN_EN, pll_state->mpllb_fracn1);
+
+       if (frac_en) {
+               frac_quot = REG_FIELD_GET(SNPS_PHY_MPLLB_FRACN_QUOT, pll_state->mpllb_fracn2);
+               frac_rem = REG_FIELD_GET(SNPS_PHY_MPLLB_FRACN_REM, pll_state->mpllb_fracn2);
+               frac_den = REG_FIELD_GET(SNPS_PHY_MPLLB_FRACN_DEN, pll_state->mpllb_fracn1);
+       }
+
+       multiplier = REG_FIELD_GET(SNPS_PHY_MPLLB_MULTIPLIER, pll_state->mpllb_div2) / 2 + 16;
+
+       tx_clk_div = REG_FIELD_GET(SNPS_PHY_MPLLB_TX_CLK_DIV, pll_state->mpllb_div);
+
+       return 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));
+}
+
+void intel_mpllb_readout_hw_state(struct intel_encoder *encoder,
+                                 struct intel_mpllb_state *pll_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
+
+       pll_state->mpllb_cp = intel_de_read(dev_priv, SNPS_PHY_MPLLB_CP(phy));
+       pll_state->mpllb_div = intel_de_read(dev_priv, SNPS_PHY_MPLLB_DIV(phy));
+       pll_state->mpllb_div2 = intel_de_read(dev_priv, SNPS_PHY_MPLLB_DIV2(phy));
+       pll_state->mpllb_sscen = intel_de_read(dev_priv, SNPS_PHY_MPLLB_SSCEN(phy));
+       pll_state->mpllb_sscstep = intel_de_read(dev_priv, SNPS_PHY_MPLLB_SSCSTEP(phy));
+       pll_state->mpllb_fracn1 = intel_de_read(dev_priv, SNPS_PHY_MPLLB_FRACN1(phy));
+       pll_state->mpllb_fracn2 = intel_de_read(dev_priv, SNPS_PHY_MPLLB_FRACN2(phy));
+
+       /*
+        * REF_CONTROL is under firmware control and never programmed by the
+        * driver; we read it only for sanity checking purposes.  The bspec
+        * only tells us the expected value for one field in this register,
+        * so we'll only read out those specific bits here.
+        */
+       pll_state->ref_control = intel_de_read(dev_priv, SNPS_PHY_REF_CONTROL(phy)) &
+               SNPS_PHY_REF_CONTROL_REF_RANGE;
+
+       /*
+        * MPLLB_DIV is programmed twice, once with the software-computed
+        * state, then again with the MPLLB_FORCE_EN bit added.  Drop that
+        * extra bit during readout so that we return the actual expected
+        * software state.
+        */
+       pll_state->mpllb_div &= ~SNPS_PHY_MPLLB_FORCE_EN;
+}
+
+int intel_snps_phy_check_hdmi_link_rate(int clock)
+{
+       const struct intel_mpllb_state **tables = dg2_hdmi_tables;
+       int i;
+
+       for (i = 0; tables[i]; i++) {
+               if (clock == tables[i]->clock)
+                       return MODE_OK;
+       }
+
+       return MODE_CLOCK_RANGE;
+}
index 205ab46..ca4c2a2 100644 (file)
@@ -8,11 +8,18 @@
 
 struct intel_encoder;
 struct intel_crtc_state;
+struct intel_mpllb_state;
 
 int intel_mpllb_calc_state(struct intel_crtc_state *crtc_state,
                           struct intel_encoder *encoder);
 void intel_mpllb_enable(struct intel_encoder *encoder,
                        const struct intel_crtc_state *crtc_state);
 void intel_mpllb_disable(struct intel_encoder *encoder);
+void intel_mpllb_readout_hw_state(struct intel_encoder *encoder,
+                                 struct intel_mpllb_state *pll_state);
+int intel_mpllb_calc_port_clock(struct intel_encoder *encoder,
+                               const struct intel_mpllb_state *pll_state);
+
+int intel_snps_phy_check_hdmi_link_rate(int clock);
 
 #endif /* __INTEL_SNPS_PHY_H__ */
index bf4a816..f82a7e2 100644 (file)
@@ -2317,12 +2317,15 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 
 #define SNPS_PHY_MPLLB_SSCEN(phy)              _MMIO_SNPS(phy, 0x168014)
 #define   SNPS_PHY_MPLLB_SSC_EN                        REG_BIT(31)
+#define   SNPS_PHY_MPLLB_SSC_UP_SPREAD         REG_BIT(30)
 #define   SNPS_PHY_MPLLB_SSC_PEAK              REG_GENMASK(29, 10)
 
 #define SNPS_PHY_MPLLB_SSCSTEP(phy)            _MMIO_SNPS(phy, 0x168018)
 #define   SNPS_PHY_MPLLB_SSC_STEPSIZE          REG_GENMASK(31, 11)
 
 #define SNPS_PHY_MPLLB_DIV2(phy)               _MMIO_SNPS(phy, 0x16801C)
+#define   SNPS_PHY_MPLLB_HDMI_PIXEL_CLK_DIV    REG_GENMASK(19, 18)
+#define   SNPS_PHY_MPLLB_HDMI_DIV              REG_GENMASK(17, 15)
 #define   SNPS_PHY_MPLLB_REF_CLK_DIV           REG_GENMASK(14, 12)
 #define   SNPS_PHY_MPLLB_MULTIPLIER            REG_GENMASK(11, 0)