On Tue, Jul 13, 2021 at 08:15:32PM -0700, Matt Roper wrote: > 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@xxxxxxxxx> > Signed-off-by: Matt Roper <matthew.d.roper@xxxxxxxxx> > Signed-off-by: Vandita Kulkarni <vandita.kulkarni@xxxxxxxxx> Reviewed-by: Matt Atwood <matthew.s.atwood@xxxxxxxxx> > --- > drivers/gpu/drm/i915/display/intel_ddi.c | 14 +- > drivers/gpu/drm/i915/display/intel_display.c | 47 +++ > drivers/gpu/drm/i915/display/intel_hdmi.c | 11 + > drivers/gpu/drm/i915/display/intel_snps_phy.c | 286 +++++++++++++++++- > drivers/gpu/drm/i915/display/intel_snps_phy.h | 7 + > drivers/gpu/drm/i915/i915_reg.h | 3 + > 6 files changed, 355 insertions(+), 13 deletions(-) > > diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c > index 26a3aa73fcc4..929a95ddb316 100644 > --- a/drivers/gpu/drm/i915/display/intel_ddi.c > +++ b/drivers/gpu/drm/i915/display/intel_ddi.c > @@ -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" > @@ -3745,6 +3746,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) > { > @@ -4606,7 +4616,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; > diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c > index 2357b79d6577..6f532b695b29 100644 > --- a/drivers/gpu/drm/i915/display/intel_display.c > +++ b/drivers/gpu/drm/i915/display/intel_display.c > @@ -9113,6 +9113,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, > @@ -9126,6 +9172,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 > diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c > index 852af2b23540..b04685bb6439 100644 > --- a/drivers/gpu/drm/i915/display/intel_hdmi.c > +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c > @@ -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; > } > > diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c > index 6d9205906595..1317b4e94b50 100644 > --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c > +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c > @@ -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; > +} > diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.h b/drivers/gpu/drm/i915/display/intel_snps_phy.h > index 205ab46f0b67..ca4c2a25182b 100644 > --- a/drivers/gpu/drm/i915/display/intel_snps_phy.h > +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.h > @@ -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__ */ > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index 1422fbce36cb..92408b4e2730 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -2325,12 +2325,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) > > -- > 2.25.4 > _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx