drm/i915/dg2: Add MPLLB programming for HDMI
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
This commit is contained in:
parent
2908100804
commit
865b73ea18
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user