Commit 865b73ea authored by Matt Roper's avatar Matt Roper

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: default avatarMatt Roper <matthew.d.roper@intel.com>
Signed-off-by: default avatarVandita Kulkarni <vandita.kulkarni@intel.com>
Reviewed-by: default avatarMatt Atwood <matthew.s.atwood@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210723174239.1551352-25-matthew.d.roper@intel.com
parent 29081008
......@@ -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;
}
......
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment