drm/i915/dg2: Add MPLLB programming for SNPS PHY
DG2's SNPS PHYs incorporate a dedicated port PLL called MPLLB which takes the place of the shared DPLLs we've used on past platforms. Let's add the MPLLB programming sequences; they'll be plugged into the rest of the code in future patches. Bspec: 54032 Bspec: 53881 Cc: Lucas De Marchi <lucas.demarchi@intel.com> Signed-off-by: Matt Roper <matthew.d.roper@intel.com> Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Nidhi Gupta <nidhi1.gupta@intel.com> Reviewed-by: Matt Atwood <matthew.s.atwood@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210723174239.1551352-24-matthew.d.roper@intel.com
This commit is contained in:
parent
65ad82b2a3
commit
2908100804
@ -265,6 +265,7 @@ i915-y += \
|
||||
display/intel_pps.o \
|
||||
display/intel_qp_tables.o \
|
||||
display/intel_sdvo.o \
|
||||
display/intel_snps_phy.o \
|
||||
display/intel_tv.o \
|
||||
display/intel_vdsc.o \
|
||||
display/intel_vrr.o \
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "display/intel_hdmi.h"
|
||||
#include "display/intel_lvds.h"
|
||||
#include "display/intel_sdvo.h"
|
||||
#include "display/intel_snps_phy.h"
|
||||
#include "display/intel_tv.h"
|
||||
#include "display/intel_vdsc.h"
|
||||
#include "display/intel_vrr.h"
|
||||
|
@ -888,6 +888,18 @@ enum intel_output_format {
|
||||
INTEL_OUTPUT_FORMAT_YCBCR444,
|
||||
};
|
||||
|
||||
struct intel_mpllb_state {
|
||||
u32 clock; /* in KHz */
|
||||
u32 ref_control;
|
||||
u32 mpllb_cp;
|
||||
u32 mpllb_div;
|
||||
u32 mpllb_div2;
|
||||
u32 mpllb_fracn1;
|
||||
u32 mpllb_fracn2;
|
||||
u32 mpllb_sscen;
|
||||
u32 mpllb_sscstep;
|
||||
};
|
||||
|
||||
struct intel_crtc_state {
|
||||
/*
|
||||
* uapi (drm) state. This is the software state shown to userspace.
|
||||
@ -1022,7 +1034,10 @@ struct intel_crtc_state {
|
||||
struct intel_shared_dpll *shared_dpll;
|
||||
|
||||
/* Actual register state of the dpll, for shared dpll cross-checking. */
|
||||
struct intel_dpll_hw_state dpll_hw_state;
|
||||
union {
|
||||
struct intel_dpll_hw_state dpll_hw_state;
|
||||
struct intel_mpllb_state mpllb_state;
|
||||
};
|
||||
|
||||
/*
|
||||
* ICL reserved DPLLs for the CRTC/port. The active PLL is selected by
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "intel_lvds.h"
|
||||
#include "intel_panel.h"
|
||||
#include "intel_sideband.h"
|
||||
#include "display/intel_snps_phy.h"
|
||||
|
||||
struct intel_limit {
|
||||
struct {
|
||||
@ -923,12 +924,13 @@ static int hsw_crtc_compute_clock(struct intel_crtc *crtc,
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||
struct intel_atomic_state *state =
|
||||
to_intel_atomic_state(crtc_state->uapi.state);
|
||||
struct intel_encoder *encoder =
|
||||
intel_get_crtc_new_encoder(state, crtc_state);
|
||||
|
||||
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) ||
|
||||
DISPLAY_VER(dev_priv) >= 11) {
|
||||
struct intel_encoder *encoder =
|
||||
intel_get_crtc_new_encoder(state, crtc_state);
|
||||
|
||||
if (IS_DG2(dev_priv)) {
|
||||
return intel_mpllb_calc_state(crtc_state, encoder);
|
||||
} else if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) ||
|
||||
DISPLAY_VER(dev_priv) >= 11) {
|
||||
if (!intel_reserve_shared_dplls(state, crtc, encoder)) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
"failed to find PLL for pipe %c\n",
|
||||
|
517
drivers/gpu/drm/i915/display/intel_snps_phy.c
Normal file
517
drivers/gpu/drm/i915/display/intel_snps_phy.c
Normal file
@ -0,0 +1,517 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright © 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "intel_de.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_snps_phy.h"
|
||||
|
||||
/**
|
||||
* DOC: Synopsis PHY support
|
||||
*
|
||||
* Synopsis PHYs are primarily programmed by looking up magic register values
|
||||
* in tables rather than calculating the necessary values at runtime.
|
||||
*
|
||||
* Of special note is that the SNPS PHYs include a dedicated port PLL, known as
|
||||
* an "MPLLB." The MPLLB replaces the shared DPLL functionality used on other
|
||||
* platforms and must be programming directly during the modeset sequence
|
||||
* since it is not handled by the shared DPLL framework as on other platforms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Basic DP link rates with 100 MHz reference clock.
|
||||
*/
|
||||
|
||||
static const struct intel_mpllb_state dg2_dp_rbr_100 = {
|
||||
.clock = 162000,
|
||||
.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, 20) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.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, 2),
|
||||
.mpllb_div2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 2) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 226),
|
||||
.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, 39321) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 3),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state dg2_dp_hbr1_100 = {
|
||||
.clock = 270000,
|
||||
.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, 20) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.mpllb_div =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 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, 2) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 184),
|
||||
.mpllb_fracn1 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state dg2_dp_hbr2_100 = {
|
||||
.clock = 540000,
|
||||
.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, 20) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.mpllb_div =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_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, 2) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 184),
|
||||
.mpllb_fracn1 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state dg2_dp_hbr3_100 = {
|
||||
.clock = 810000,
|
||||
.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, 19) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.mpllb_div =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2),
|
||||
.mpllb_div2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 2) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 292),
|
||||
.mpllb_fracn1 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 1),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state *dg2_dp_100_tables[] = {
|
||||
&dg2_dp_rbr_100,
|
||||
&dg2_dp_hbr1_100,
|
||||
&dg2_dp_hbr2_100,
|
||||
&dg2_dp_hbr3_100,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* Basic DP link rates with 38.4 MHz reference clock.
|
||||
*/
|
||||
|
||||
static const struct intel_mpllb_state dg2_dp_rbr_38_4 = {
|
||||
.clock = 162000,
|
||||
.ref_control =
|
||||
REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 1),
|
||||
.mpllb_cp =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 5) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 25) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.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, 2),
|
||||
.mpllb_div2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 304),
|
||||
.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, 1),
|
||||
.mpllb_fracn2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 49152),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state dg2_dp_hbr1_38_4 = {
|
||||
.clock = 270000,
|
||||
.ref_control =
|
||||
REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 1),
|
||||
.mpllb_cp =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 5) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 25) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.mpllb_div =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 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, 248),
|
||||
.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, 1),
|
||||
.mpllb_fracn2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 40960),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state dg2_dp_hbr2_38_4 = {
|
||||
.clock = 540000,
|
||||
.ref_control =
|
||||
REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 1),
|
||||
.mpllb_cp =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 5) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 25) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.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, 248),
|
||||
.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, 1),
|
||||
.mpllb_fracn2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 40960),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state dg2_dp_hbr3_38_4 = {
|
||||
.clock = 810000,
|
||||
.ref_control =
|
||||
REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 1),
|
||||
.mpllb_cp =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 26) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.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),
|
||||
.mpllb_div2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 388),
|
||||
.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, 1),
|
||||
.mpllb_fracn2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 61440),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state *dg2_dp_38_4_tables[] = {
|
||||
&dg2_dp_rbr_38_4,
|
||||
&dg2_dp_hbr1_38_4,
|
||||
&dg2_dp_hbr2_38_4,
|
||||
&dg2_dp_hbr3_38_4,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* eDP link rates with 100 MHz reference clock.
|
||||
*/
|
||||
|
||||
static const struct intel_mpllb_state dg2_edp_r216 = {
|
||||
.clock = 216000,
|
||||
.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, 19) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.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),
|
||||
.mpllb_div2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 2) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 312),
|
||||
.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, 52428) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 4),
|
||||
.mpllb_sscen =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 50961),
|
||||
.mpllb_sscstep =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 65752),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state dg2_edp_r243 = {
|
||||
.clock = 243000,
|
||||
.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, 20) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.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),
|
||||
.mpllb_div2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 2) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 356),
|
||||
.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_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 57331),
|
||||
.mpllb_sscstep =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 73971),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state dg2_edp_r324 = {
|
||||
.clock = 324000,
|
||||
.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, 20) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.mpllb_div =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 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, 2),
|
||||
.mpllb_div2 =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 2) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 226),
|
||||
.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, 39321) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 3),
|
||||
.mpllb_sscen =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 38221),
|
||||
.mpllb_sscstep =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 49314),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state dg2_edp_r432 = {
|
||||
.clock = 432000,
|
||||
.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, 19) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 65) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 127),
|
||||
.mpllb_div =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 1) |
|
||||
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, 2) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 312),
|
||||
.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, 52428) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 4),
|
||||
.mpllb_sscen =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_EN, 1) |
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_PEAK, 50961),
|
||||
.mpllb_sscstep =
|
||||
REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_STEPSIZE, 65752),
|
||||
};
|
||||
|
||||
static const struct intel_mpllb_state *dg2_edp_tables[] = {
|
||||
&dg2_dp_rbr_100,
|
||||
&dg2_edp_r216,
|
||||
&dg2_edp_r243,
|
||||
&dg2_dp_hbr1_100,
|
||||
&dg2_edp_r324,
|
||||
&dg2_edp_r432,
|
||||
&dg2_dp_hbr2_100,
|
||||
&dg2_dp_hbr3_100,
|
||||
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_EDP)) {
|
||||
tables = dg2_edp_tables;
|
||||
} else if (intel_crtc_has_dp_encoder(crtc_state)) {
|
||||
/*
|
||||
* FIXME: Initially we're just enabling the "combo" outputs on
|
||||
* port A-D. The MPLLB for those ports takes an input from the
|
||||
* "Display Filter PLL" which always has an output frequency
|
||||
* of 100 MHz, hence the use of the _100 tables below.
|
||||
*
|
||||
* Once we enable port TC1 it will either use the same 100 MHz
|
||||
* "Display Filter PLL" (when strapped to support a native
|
||||
* display connection) or different 38.4 MHz "Filter PLL" when
|
||||
* strapped to support a USB connection, so we'll need to check
|
||||
* that to determine which table to use.
|
||||
*/
|
||||
if (0)
|
||||
tables = dg2_dp_38_4_tables;
|
||||
else
|
||||
tables = dg2_dp_100_tables;
|
||||
} else {
|
||||
/* TODO: Add HDMI support */
|
||||
MISSING_CASE(encoder->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; tables[i]; i++) {
|
||||
if (crtc_state->port_clock <= tables[i]->clock) {
|
||||
crtc_state->mpllb_state = *tables[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void intel_mpllb_enable(struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
const struct intel_mpllb_state *pll_state = &crtc_state->mpllb_state;
|
||||
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
|
||||
i915_reg_t enable_reg = (phy <= PHY_D ?
|
||||
DG2_PLL_ENABLE(phy) : MG_PLL_ENABLE(0));
|
||||
|
||||
/*
|
||||
* 3. Software programs the following PLL registers for the desired
|
||||
* frequency.
|
||||
*/
|
||||
intel_de_write(dev_priv, SNPS_PHY_MPLLB_CP(phy), pll_state->mpllb_cp);
|
||||
intel_de_write(dev_priv, SNPS_PHY_MPLLB_DIV(phy), pll_state->mpllb_div);
|
||||
intel_de_write(dev_priv, SNPS_PHY_MPLLB_DIV2(phy), pll_state->mpllb_div2);
|
||||
intel_de_write(dev_priv, SNPS_PHY_MPLLB_SSCEN(phy), pll_state->mpllb_sscen);
|
||||
intel_de_write(dev_priv, SNPS_PHY_MPLLB_SSCSTEP(phy), pll_state->mpllb_sscstep);
|
||||
intel_de_write(dev_priv, SNPS_PHY_MPLLB_FRACN1(phy), pll_state->mpllb_fracn1);
|
||||
intel_de_write(dev_priv, SNPS_PHY_MPLLB_FRACN2(phy), pll_state->mpllb_fracn2);
|
||||
|
||||
/*
|
||||
* 4. If the frequency will result in a change to the voltage
|
||||
* requirement, follow the Display Voltage Frequency Switching -
|
||||
* Sequence Before Frequency Change.
|
||||
*
|
||||
* We handle this step in bxt_set_cdclk().
|
||||
*/
|
||||
|
||||
/* 5. Software sets DPLL_ENABLE [PLL Enable] to "1". */
|
||||
intel_uncore_rmw(&dev_priv->uncore, enable_reg, 0, PLL_ENABLE);
|
||||
|
||||
/*
|
||||
* 9. Software sets SNPS_PHY_MPLLB_DIV dp_mpllb_force_en to "1". This
|
||||
* will keep the PLL running during the DDI lane programming and any
|
||||
* typeC DP cable disconnect. Do not set the force before enabling the
|
||||
* PLL because that will start the PLL before it has sampled the
|
||||
* divider values.
|
||||
*/
|
||||
intel_de_write(dev_priv, SNPS_PHY_MPLLB_DIV(phy),
|
||||
pll_state->mpllb_div | SNPS_PHY_MPLLB_FORCE_EN);
|
||||
|
||||
/*
|
||||
* 10. Software polls on register DPLL_ENABLE [PLL Lock] to confirm PLL
|
||||
* is locked at new settings. This register bit is sampling PHY
|
||||
* dp_mpllb_state interface signal.
|
||||
*/
|
||||
if (intel_de_wait_for_set(dev_priv, enable_reg, PLL_LOCK, 5))
|
||||
DRM_ERROR("Port %c PLL not locked\n", phy_name(phy));
|
||||
|
||||
/*
|
||||
* 11. If the frequency will result in a change to the voltage
|
||||
* requirement, follow the Display Voltage Frequency Switching -
|
||||
* Sequence After Frequency Change.
|
||||
*
|
||||
* We handle this step in bxt_set_cdclk().
|
||||
*/
|
||||
}
|
||||
|
||||
void intel_mpllb_disable(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
|
||||
i915_reg_t enable_reg = (phy <= PHY_D ?
|
||||
DG2_PLL_ENABLE(phy) : MG_PLL_ENABLE(0));
|
||||
|
||||
/*
|
||||
* 1. If the frequency will result in a change to the voltage
|
||||
* requirement, follow the Display Voltage Frequency Switching -
|
||||
* Sequence Before Frequency Change.
|
||||
*
|
||||
* We handle this step in bxt_set_cdclk().
|
||||
*/
|
||||
|
||||
/* 2. Software programs DPLL_ENABLE [PLL Enable] to "0" */
|
||||
intel_uncore_rmw(&dev_priv->uncore, enable_reg, PLL_ENABLE, 0);
|
||||
|
||||
/*
|
||||
* 4. Software programs SNPS_PHY_MPLLB_DIV dp_mpllb_force_en to "0".
|
||||
* This will allow the PLL to stop running.
|
||||
*/
|
||||
intel_uncore_rmw(&dev_priv->uncore, SNPS_PHY_MPLLB_DIV(phy),
|
||||
SNPS_PHY_MPLLB_FORCE_EN, 0);
|
||||
|
||||
/*
|
||||
* 5. Software polls DPLL_ENABLE [PLL Lock] for PHY acknowledgment
|
||||
* (dp_txX_ack) that the new transmitter setting request is completed.
|
||||
*/
|
||||
if (intel_de_wait_for_clear(dev_priv, enable_reg, PLL_LOCK, 5))
|
||||
DRM_ERROR("Port %c PLL not locked\n", phy_name(phy));
|
||||
|
||||
/*
|
||||
* 6. If the frequency will result in a change to the voltage
|
||||
* requirement, follow the Display Voltage Frequency Switching -
|
||||
* Sequence After Frequency Change.
|
||||
*
|
||||
* We handle this step in bxt_set_cdclk().
|
||||
*/
|
||||
}
|
18
drivers/gpu/drm/i915/display/intel_snps_phy.h
Normal file
18
drivers/gpu/drm/i915/display/intel_snps_phy.h
Normal file
@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __INTEL_SNPS_PHY_H__
|
||||
#define __INTEL_SNPS_PHY_H__
|
||||
|
||||
struct intel_encoder;
|
||||
struct intel_crtc_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);
|
||||
|
||||
#endif /* __INTEL_SNPS_PHY_H__ */
|
@ -2278,6 +2278,57 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
|
||||
#define MG_DP_MODE_CFG_DP_X2_MODE (1 << 7)
|
||||
#define MG_DP_MODE_CFG_DP_X1_MODE (1 << 6)
|
||||
|
||||
/*
|
||||
* DG2 SNPS PHY registers (TC1 = PHY_E)
|
||||
*/
|
||||
#define _SNPS_PHY_A_BASE 0x168000
|
||||
#define _SNPS_PHY_B_BASE 0x169000
|
||||
#define _SNPS_PHY(phy) _PHY(phy, \
|
||||
_SNPS_PHY_A_BASE, \
|
||||
_SNPS_PHY_B_BASE)
|
||||
#define _SNPS2(phy, reg) (_SNPS_PHY(phy) - \
|
||||
_SNPS_PHY_A_BASE + (reg))
|
||||
#define _MMIO_SNPS(phy, reg) _MMIO(_SNPS2(phy, reg))
|
||||
#define _MMIO_SNPS_LN(ln, phy, reg) _MMIO(_SNPS2(phy, \
|
||||
(reg) + (ln) * 0x10))
|
||||
|
||||
#define SNPS_PHY_MPLLB_CP(phy) _MMIO_SNPS(phy, 0x168000)
|
||||
#define SNPS_PHY_MPLLB_CP_INT REG_GENMASK(31, 25)
|
||||
#define SNPS_PHY_MPLLB_CP_INT_GS REG_GENMASK(23, 17)
|
||||
#define SNPS_PHY_MPLLB_CP_PROP REG_GENMASK(15, 9)
|
||||
#define SNPS_PHY_MPLLB_CP_PROP_GS REG_GENMASK(7, 1)
|
||||
|
||||
#define SNPS_PHY_MPLLB_DIV(phy) _MMIO_SNPS(phy, 0x168004)
|
||||
#define SNPS_PHY_MPLLB_FORCE_EN REG_BIT(31)
|
||||
#define SNPS_PHY_MPLLB_DIV5_CLK_EN REG_BIT(29)
|
||||
#define SNPS_PHY_MPLLB_V2I REG_GENMASK(27, 26)
|
||||
#define SNPS_PHY_MPLLB_FREQ_VCO REG_GENMASK(25, 24)
|
||||
#define SNPS_PHY_MPLLB_PMIX_EN REG_BIT(10)
|
||||
#define SNPS_PHY_MPLLB_TX_CLK_DIV REG_GENMASK(7, 5)
|
||||
|
||||
#define SNPS_PHY_MPLLB_FRACN1(phy) _MMIO_SNPS(phy, 0x168008)
|
||||
#define SNPS_PHY_MPLLB_FRACN_EN REG_BIT(31)
|
||||
#define SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN REG_BIT(30)
|
||||
#define SNPS_PHY_MPLLB_FRACN_DEN REG_GENMASK(15, 0)
|
||||
|
||||
#define SNPS_PHY_MPLLB_FRACN2(phy) _MMIO_SNPS(phy, 0x16800C)
|
||||
#define SNPS_PHY_MPLLB_FRACN_REM REG_GENMASK(31, 16)
|
||||
#define SNPS_PHY_MPLLB_FRACN_QUOT REG_GENMASK(15, 0)
|
||||
|
||||
#define SNPS_PHY_MPLLB_SSCEN(phy) _MMIO_SNPS(phy, 0x168014)
|
||||
#define SNPS_PHY_MPLLB_SSC_EN REG_BIT(31)
|
||||
#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_REF_CLK_DIV REG_GENMASK(14, 12)
|
||||
#define SNPS_PHY_MPLLB_MULTIPLIER REG_GENMASK(11, 0)
|
||||
|
||||
#define SNPS_PHY_REF_CONTROL(phy) _MMIO_SNPS(phy, 0x168188)
|
||||
#define SNPS_PHY_REF_CONTROL_REF_RANGE REG_GENMASK(31, 27)
|
||||
|
||||
/* The spec defines this only for BXT PHY0, but lets assume that this
|
||||
* would exist for PHY1 too if it had a second channel.
|
||||
*/
|
||||
@ -10581,6 +10632,11 @@ enum skl_power_gate {
|
||||
#define CNL_DPLL_ENABLE(pll) _MMIO_PLL3(pll, DPLL0_ENABLE, DPLL1_ENABLE, \
|
||||
_ADLS_DPLL2_ENABLE, _ADLS_DPLL3_ENABLE)
|
||||
|
||||
#define _DG2_PLL3_ENABLE 0x4601C
|
||||
|
||||
#define DG2_PLL_ENABLE(pll) _MMIO_PLL3(pll, DPLL0_ENABLE, DPLL1_ENABLE, \
|
||||
_ADLS_DPLL2_ENABLE, _DG2_PLL3_ENABLE)
|
||||
|
||||
#define TBT_PLL_ENABLE _MMIO(0x46020)
|
||||
|
||||
#define _MG_PLL1_ENABLE 0x46030
|
||||
|
Loading…
Reference in New Issue
Block a user