blob: 18b52b64af955aa8c003bb48f07450b13021fff7 [file] [log] [blame]
// SPDX-License-Identifier: MIT
/*
* Copyright © 2019 Intel Corporation
*/
#include <linux/util_macros.h>
#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.
*/
void intel_snps_phy_wait_for_calibration(struct drm_i915_private *dev_priv)
{
enum phy phy;
for_each_phy_masked(phy, ~0) {
if (!intel_phy_is_snps(dev_priv, phy))
continue;
if (intel_de_wait_for_clear(dev_priv, ICL_PHY_MISC(phy),
DG2_PHY_DP_TX_ACK_MASK, 25))
DRM_ERROR("SNPS PHY %c failed to calibrate after 25ms.\n",
phy);
}
}
void intel_snps_phy_update_psr_power_state(struct drm_i915_private *dev_priv,
enum phy phy, bool enable)
{
u32 val;
if (!intel_phy_is_snps(dev_priv, phy))
return;
val = REG_FIELD_PREP(SNPS_PHY_TX_REQ_LN_DIS_PWR_STATE_PSR,
enable ? 2 : 3);
intel_uncore_rmw(&dev_priv->uncore, SNPS_PHY_TX_REQ(phy),
SNPS_PHY_TX_REQ_LN_DIS_PWR_STATE_PSR, val);
}
static const u32 dg2_ddi_translations[] = {
/* VS 0, pre-emph 0 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 26),
/* VS 0, pre-emph 1 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 33) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 6),
/* VS 0, pre-emph 2 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 38) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 12),
/* VS 0, pre-emph 3 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 43) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 19),
/* VS 1, pre-emph 0 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 39),
/* VS 1, pre-emph 1 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 44) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 8),
/* VS 1, pre-emph 2 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 47) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 15),
/* VS 2, pre-emph 0 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 52),
/* VS 2, pre-emph 1 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 51) |
REG_FIELD_PREP(SNPS_PHY_TX_EQ_POST, 10),
/* VS 3, pre-emph 0 */
REG_FIELD_PREP(SNPS_PHY_TX_EQ_MAIN, 62),
};
void intel_snps_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
u32 level)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
int n_entries, ln;
n_entries = ARRAY_SIZE(dg2_ddi_translations);
if (level >= n_entries)
level = n_entries - 1;
for (ln = 0; ln < 4; ln++)
intel_de_write(dev_priv, SNPS_PHY_TX_EQ(ln, phy),
dg2_ddi_translations[level]);
}
/*
* 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,
};
/*
* 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)) {
return 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)
return dg2_dp_38_4_tables;
else
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];
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().
*/
}
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;
}