Skip to content
Snippets Groups Projects
Commit 55be2f08 authored by Ander Conselvan de Oliveira's avatar Ander Conselvan de Oliveira
Browse files
parent 7abd4b35
No related branches found
No related tags found
No related merge requests found
......@@ -2430,235 +2430,6 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
}
}
static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
POSTING_READ(WRPLL_CTL(pll->id));
udelay(20);
}
static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
I915_WRITE(SPLL_CTL, pll->config.hw_state.spll);
POSTING_READ(SPLL_CTL);
udelay(20);
}
static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
uint32_t val;
val = I915_READ(WRPLL_CTL(pll->id));
I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
POSTING_READ(WRPLL_CTL(pll->id));
}
static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
uint32_t val;
val = I915_READ(SPLL_CTL);
I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
POSTING_READ(SPLL_CTL);
}
static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll,
struct intel_dpll_hw_state *hw_state)
{
uint32_t val;
if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
val = I915_READ(WRPLL_CTL(pll->id));
hw_state->wrpll = val;
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
return val & WRPLL_PLL_ENABLE;
}
static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll,
struct intel_dpll_hw_state *hw_state)
{
uint32_t val;
if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
val = I915_READ(SPLL_CTL);
hw_state->spll = val;
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
return val & SPLL_PLL_ENABLE;
}
static const char * const hsw_ddi_pll_names[] = {
"WRPLL 1",
"WRPLL 2",
"SPLL"
};
static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv)
{
int i;
dev_priv->num_shared_dpll = 3;
for (i = 0; i < 2; i++) {
dev_priv->shared_dplls[i].id = i;
dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
dev_priv->shared_dplls[i].disable = hsw_ddi_wrpll_disable;
dev_priv->shared_dplls[i].enable = hsw_ddi_wrpll_enable;
dev_priv->shared_dplls[i].get_hw_state =
hsw_ddi_wrpll_get_hw_state;
}
/* SPLL is special, but needs to be initialized anyway.. */
dev_priv->shared_dplls[i].id = i;
dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
dev_priv->shared_dplls[i].disable = hsw_ddi_spll_disable;
dev_priv->shared_dplls[i].enable = hsw_ddi_spll_enable;
dev_priv->shared_dplls[i].get_hw_state = hsw_ddi_spll_get_hw_state;
}
static const char * const skl_ddi_pll_names[] = {
"DPLL 1",
"DPLL 2",
"DPLL 3",
};
struct skl_dpll_regs {
i915_reg_t ctl, cfgcr1, cfgcr2;
};
/* this array is indexed by the *shared* pll id */
static const struct skl_dpll_regs skl_dpll_regs[3] = {
{
/* DPLL 1 */
.ctl = LCPLL2_CTL,
.cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
.cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
},
{
/* DPLL 2 */
.ctl = WRPLL_CTL(0),
.cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
.cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
},
{
/* DPLL 3 */
.ctl = WRPLL_CTL(1),
.cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
.cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
},
};
static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
uint32_t val;
unsigned int dpll;
const struct skl_dpll_regs *regs = skl_dpll_regs;
/* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
dpll = pll->id + 1;
val = I915_READ(DPLL_CTRL1);
val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) |
DPLL_CTRL1_LINK_RATE_MASK(dpll));
val |= pll->config.hw_state.ctrl1 << (dpll * 6);
I915_WRITE(DPLL_CTRL1, val);
POSTING_READ(DPLL_CTRL1);
I915_WRITE(regs[pll->id].cfgcr1, pll->config.hw_state.cfgcr1);
I915_WRITE(regs[pll->id].cfgcr2, pll->config.hw_state.cfgcr2);
POSTING_READ(regs[pll->id].cfgcr1);
POSTING_READ(regs[pll->id].cfgcr2);
/* the enable bit is always bit 31 */
I915_WRITE(regs[pll->id].ctl,
I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE);
if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(dpll), 5))
DRM_ERROR("DPLL %d not locked\n", dpll);
}
static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
const struct skl_dpll_regs *regs = skl_dpll_regs;
/* the enable bit is always bit 31 */
I915_WRITE(regs[pll->id].ctl,
I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE);
POSTING_READ(regs[pll->id].ctl);
}
static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll,
struct intel_dpll_hw_state *hw_state)
{
uint32_t val;
unsigned int dpll;
const struct skl_dpll_regs *regs = skl_dpll_regs;
bool ret;
if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
ret = false;
/* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
dpll = pll->id + 1;
val = I915_READ(regs[pll->id].ctl);
if (!(val & LCPLL_PLL_ENABLE))
goto out;
val = I915_READ(DPLL_CTRL1);
hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f;
/* avoid reading back stale values if HDMI mode is not enabled */
if (val & DPLL_CTRL1_HDMI_MODE(dpll)) {
hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
}
ret = true;
out:
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
return ret;
}
static void skl_shared_dplls_init(struct drm_i915_private *dev_priv)
{
int i;
dev_priv->num_shared_dpll = 3;
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
dev_priv->shared_dplls[i].id = i;
dev_priv->shared_dplls[i].name = skl_ddi_pll_names[i];
dev_priv->shared_dplls[i].disable = skl_ddi_pll_disable;
dev_priv->shared_dplls[i].enable = skl_ddi_pll_enable;
dev_priv->shared_dplls[i].get_hw_state =
skl_ddi_pll_get_hw_state;
}
}
static void broxton_phy_init(struct drm_i915_private *dev_priv,
enum dpio_phy phy)
{
......@@ -2783,249 +2554,6 @@ void broxton_ddi_phy_uninit(struct drm_device *dev)
I915_WRITE(BXT_P_CR_GT_DISP_PWRON, 0);
}
static const char * const bxt_ddi_pll_names[] = {
"PORT PLL A",
"PORT PLL B",
"PORT PLL C",
};
static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
uint32_t temp;
enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
temp &= ~PORT_PLL_REF_SEL;
/* Non-SSC reference */
I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
/* Disable 10 bit clock */
temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
/* Write P1 & P2 */
temp = I915_READ(BXT_PORT_PLL_EBB_0(port));
temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK);
temp |= pll->config.hw_state.ebb0;
I915_WRITE(BXT_PORT_PLL_EBB_0(port), temp);
/* Write M2 integer */
temp = I915_READ(BXT_PORT_PLL(port, 0));
temp &= ~PORT_PLL_M2_MASK;
temp |= pll->config.hw_state.pll0;
I915_WRITE(BXT_PORT_PLL(port, 0), temp);
/* Write N */
temp = I915_READ(BXT_PORT_PLL(port, 1));
temp &= ~PORT_PLL_N_MASK;
temp |= pll->config.hw_state.pll1;
I915_WRITE(BXT_PORT_PLL(port, 1), temp);
/* Write M2 fraction */
temp = I915_READ(BXT_PORT_PLL(port, 2));
temp &= ~PORT_PLL_M2_FRAC_MASK;
temp |= pll->config.hw_state.pll2;
I915_WRITE(BXT_PORT_PLL(port, 2), temp);
/* Write M2 fraction enable */
temp = I915_READ(BXT_PORT_PLL(port, 3));
temp &= ~PORT_PLL_M2_FRAC_ENABLE;
temp |= pll->config.hw_state.pll3;
I915_WRITE(BXT_PORT_PLL(port, 3), temp);
/* Write coeff */
temp = I915_READ(BXT_PORT_PLL(port, 6));
temp &= ~PORT_PLL_PROP_COEFF_MASK;
temp &= ~PORT_PLL_INT_COEFF_MASK;
temp &= ~PORT_PLL_GAIN_CTL_MASK;
temp |= pll->config.hw_state.pll6;
I915_WRITE(BXT_PORT_PLL(port, 6), temp);
/* Write calibration val */
temp = I915_READ(BXT_PORT_PLL(port, 8));
temp &= ~PORT_PLL_TARGET_CNT_MASK;
temp |= pll->config.hw_state.pll8;
I915_WRITE(BXT_PORT_PLL(port, 8), temp);
temp = I915_READ(BXT_PORT_PLL(port, 9));
temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK;
temp |= pll->config.hw_state.pll9;
I915_WRITE(BXT_PORT_PLL(port, 9), temp);
temp = I915_READ(BXT_PORT_PLL(port, 10));
temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H;
temp &= ~PORT_PLL_DCO_AMP_MASK;
temp |= pll->config.hw_state.pll10;
I915_WRITE(BXT_PORT_PLL(port, 10), temp);
/* Recalibrate with new settings */
temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
temp |= PORT_PLL_RECALIBRATE;
I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
temp |= pll->config.hw_state.ebb4;
I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
/* Enable PLL */
temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
temp |= PORT_PLL_ENABLE;
I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
POSTING_READ(BXT_PORT_PLL_ENABLE(port));
if (wait_for_atomic_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) &
PORT_PLL_LOCK), 200))
DRM_ERROR("PLL %d not locked\n", port);
/*
* While we write to the group register to program all lanes at once we
* can read only lane registers and we pick lanes 0/1 for that.
*/
temp = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
temp &= ~LANE_STAGGER_MASK;
temp &= ~LANESTAGGER_STRAP_OVRD;
temp |= pll->config.hw_state.pcsdw12;
I915_WRITE(BXT_PORT_PCS_DW12_GRP(port), temp);
}
static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
uint32_t temp;
temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
temp &= ~PORT_PLL_ENABLE;
I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
POSTING_READ(BXT_PORT_PLL_ENABLE(port));
}
static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll,
struct intel_dpll_hw_state *hw_state)
{
enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
uint32_t val;
bool ret;
if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
ret = false;
val = I915_READ(BXT_PORT_PLL_ENABLE(port));
if (!(val & PORT_PLL_ENABLE))
goto out;
hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port));
hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0));
hw_state->pll0 &= PORT_PLL_M2_MASK;
hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1));
hw_state->pll1 &= PORT_PLL_N_MASK;
hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2));
hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK;
hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3));
hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE;
hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6));
hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK |
PORT_PLL_INT_COEFF_MASK |
PORT_PLL_GAIN_CTL_MASK;
hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8));
hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK;
hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9));
hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK;
hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10));
hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H |
PORT_PLL_DCO_AMP_MASK;
/*
* While we write to the group register to program all lanes at once we
* can read only lane registers. We configure all lanes the same way, so
* here just read out lanes 0/1 and output a note if lanes 2/3 differ.
*/
hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
if (I915_READ(BXT_PORT_PCS_DW12_LN23(port)) != hw_state->pcsdw12)
DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
hw_state->pcsdw12,
I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
ret = true;
out:
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
return ret;
}
static void bxt_shared_dplls_init(struct drm_i915_private *dev_priv)
{
int i;
dev_priv->num_shared_dpll = 3;
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
dev_priv->shared_dplls[i].id = i;
dev_priv->shared_dplls[i].name = bxt_ddi_pll_names[i];
dev_priv->shared_dplls[i].disable = bxt_ddi_pll_disable;
dev_priv->shared_dplls[i].enable = bxt_ddi_pll_enable;
dev_priv->shared_dplls[i].get_hw_state =
bxt_ddi_pll_get_hw_state;
}
}
void intel_ddi_pll_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t val = I915_READ(LCPLL_CTL);
if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
skl_shared_dplls_init(dev_priv);
else if (IS_BROXTON(dev))
bxt_shared_dplls_init(dev_priv);
else
hsw_shared_dplls_init(dev_priv);
if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
int cdclk_freq;
cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
dev_priv->skl_boot_cdclk = cdclk_freq;
if (skl_sanitize_cdclk(dev_priv))
DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n");
if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE))
DRM_ERROR("LCPLL1 is disabled\n");
} else if (IS_BROXTON(dev)) {
broxton_init_cdclk(dev);
broxton_ddi_phy_init(dev);
} else {
/*
* The LCPLL register should be turned on by the BIOS. For now
* let's just check its state and print errors in case
* something is wrong. Don't even try to turn it on.
*/
if (val & LCPLL_CD_SOURCE_FCLK)
DRM_ERROR("CDCLK source is not LCPLL\n");
if (val & LCPLL_PLL_DISABLE)
DRM_ERROR("LCPLL is disabled\n");
}
}
void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
......
......@@ -353,6 +353,478 @@ static void ibx_pch_dpll_init(struct drm_device *dev)
}
}
static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
POSTING_READ(WRPLL_CTL(pll->id));
udelay(20);
}
static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
I915_WRITE(SPLL_CTL, pll->config.hw_state.spll);
POSTING_READ(SPLL_CTL);
udelay(20);
}
static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
uint32_t val;
val = I915_READ(WRPLL_CTL(pll->id));
I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
POSTING_READ(WRPLL_CTL(pll->id));
}
static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
uint32_t val;
val = I915_READ(SPLL_CTL);
I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
POSTING_READ(SPLL_CTL);
}
static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll,
struct intel_dpll_hw_state *hw_state)
{
uint32_t val;
if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
val = I915_READ(WRPLL_CTL(pll->id));
hw_state->wrpll = val;
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
return val & WRPLL_PLL_ENABLE;
}
static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll,
struct intel_dpll_hw_state *hw_state)
{
uint32_t val;
if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
val = I915_READ(SPLL_CTL);
hw_state->spll = val;
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
return val & SPLL_PLL_ENABLE;
}
static const char * const hsw_ddi_pll_names[] = {
"WRPLL 1",
"WRPLL 2",
"SPLL"
};
static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv)
{
int i;
dev_priv->num_shared_dpll = 3;
for (i = 0; i < 2; i++) {
dev_priv->shared_dplls[i].id = i;
dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
dev_priv->shared_dplls[i].disable = hsw_ddi_wrpll_disable;
dev_priv->shared_dplls[i].enable = hsw_ddi_wrpll_enable;
dev_priv->shared_dplls[i].get_hw_state =
hsw_ddi_wrpll_get_hw_state;
}
/* SPLL is special, but needs to be initialized anyway.. */
dev_priv->shared_dplls[i].id = i;
dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
dev_priv->shared_dplls[i].disable = hsw_ddi_spll_disable;
dev_priv->shared_dplls[i].enable = hsw_ddi_spll_enable;
dev_priv->shared_dplls[i].get_hw_state = hsw_ddi_spll_get_hw_state;
}
static const char * const skl_ddi_pll_names[] = {
"DPLL 1",
"DPLL 2",
"DPLL 3",
};
struct skl_dpll_regs {
i915_reg_t ctl, cfgcr1, cfgcr2;
};
/* this array is indexed by the *shared* pll id */
static const struct skl_dpll_regs skl_dpll_regs[3] = {
{
/* DPLL 1 */
.ctl = LCPLL2_CTL,
.cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
.cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
},
{
/* DPLL 2 */
.ctl = WRPLL_CTL(0),
.cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
.cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
},
{
/* DPLL 3 */
.ctl = WRPLL_CTL(1),
.cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
.cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
},
};
static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
uint32_t val;
unsigned int dpll;
const struct skl_dpll_regs *regs = skl_dpll_regs;
/* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
dpll = pll->id + 1;
val = I915_READ(DPLL_CTRL1);
val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) |
DPLL_CTRL1_LINK_RATE_MASK(dpll));
val |= pll->config.hw_state.ctrl1 << (dpll * 6);
I915_WRITE(DPLL_CTRL1, val);
POSTING_READ(DPLL_CTRL1);
I915_WRITE(regs[pll->id].cfgcr1, pll->config.hw_state.cfgcr1);
I915_WRITE(regs[pll->id].cfgcr2, pll->config.hw_state.cfgcr2);
POSTING_READ(regs[pll->id].cfgcr1);
POSTING_READ(regs[pll->id].cfgcr2);
/* the enable bit is always bit 31 */
I915_WRITE(regs[pll->id].ctl,
I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE);
if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(dpll), 5))
DRM_ERROR("DPLL %d not locked\n", dpll);
}
static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
const struct skl_dpll_regs *regs = skl_dpll_regs;
/* the enable bit is always bit 31 */
I915_WRITE(regs[pll->id].ctl,
I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE);
POSTING_READ(regs[pll->id].ctl);
}
static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll,
struct intel_dpll_hw_state *hw_state)
{
uint32_t val;
unsigned int dpll;
const struct skl_dpll_regs *regs = skl_dpll_regs;
bool ret;
if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
ret = false;
/* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
dpll = pll->id + 1;
val = I915_READ(regs[pll->id].ctl);
if (!(val & LCPLL_PLL_ENABLE))
goto out;
val = I915_READ(DPLL_CTRL1);
hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f;
/* avoid reading back stale values if HDMI mode is not enabled */
if (val & DPLL_CTRL1_HDMI_MODE(dpll)) {
hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
}
ret = true;
out:
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
return ret;
}
static void skl_shared_dplls_init(struct drm_i915_private *dev_priv)
{
int i;
dev_priv->num_shared_dpll = 3;
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
dev_priv->shared_dplls[i].id = i;
dev_priv->shared_dplls[i].name = skl_ddi_pll_names[i];
dev_priv->shared_dplls[i].disable = skl_ddi_pll_disable;
dev_priv->shared_dplls[i].enable = skl_ddi_pll_enable;
dev_priv->shared_dplls[i].get_hw_state =
skl_ddi_pll_get_hw_state;
}
}
static const char * const bxt_ddi_pll_names[] = {
"PORT PLL A",
"PORT PLL B",
"PORT PLL C",
};
static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
uint32_t temp;
enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
temp &= ~PORT_PLL_REF_SEL;
/* Non-SSC reference */
I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
/* Disable 10 bit clock */
temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
/* Write P1 & P2 */
temp = I915_READ(BXT_PORT_PLL_EBB_0(port));
temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK);
temp |= pll->config.hw_state.ebb0;
I915_WRITE(BXT_PORT_PLL_EBB_0(port), temp);
/* Write M2 integer */
temp = I915_READ(BXT_PORT_PLL(port, 0));
temp &= ~PORT_PLL_M2_MASK;
temp |= pll->config.hw_state.pll0;
I915_WRITE(BXT_PORT_PLL(port, 0), temp);
/* Write N */
temp = I915_READ(BXT_PORT_PLL(port, 1));
temp &= ~PORT_PLL_N_MASK;
temp |= pll->config.hw_state.pll1;
I915_WRITE(BXT_PORT_PLL(port, 1), temp);
/* Write M2 fraction */
temp = I915_READ(BXT_PORT_PLL(port, 2));
temp &= ~PORT_PLL_M2_FRAC_MASK;
temp |= pll->config.hw_state.pll2;
I915_WRITE(BXT_PORT_PLL(port, 2), temp);
/* Write M2 fraction enable */
temp = I915_READ(BXT_PORT_PLL(port, 3));
temp &= ~PORT_PLL_M2_FRAC_ENABLE;
temp |= pll->config.hw_state.pll3;
I915_WRITE(BXT_PORT_PLL(port, 3), temp);
/* Write coeff */
temp = I915_READ(BXT_PORT_PLL(port, 6));
temp &= ~PORT_PLL_PROP_COEFF_MASK;
temp &= ~PORT_PLL_INT_COEFF_MASK;
temp &= ~PORT_PLL_GAIN_CTL_MASK;
temp |= pll->config.hw_state.pll6;
I915_WRITE(BXT_PORT_PLL(port, 6), temp);
/* Write calibration val */
temp = I915_READ(BXT_PORT_PLL(port, 8));
temp &= ~PORT_PLL_TARGET_CNT_MASK;
temp |= pll->config.hw_state.pll8;
I915_WRITE(BXT_PORT_PLL(port, 8), temp);
temp = I915_READ(BXT_PORT_PLL(port, 9));
temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK;
temp |= pll->config.hw_state.pll9;
I915_WRITE(BXT_PORT_PLL(port, 9), temp);
temp = I915_READ(BXT_PORT_PLL(port, 10));
temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H;
temp &= ~PORT_PLL_DCO_AMP_MASK;
temp |= pll->config.hw_state.pll10;
I915_WRITE(BXT_PORT_PLL(port, 10), temp);
/* Recalibrate with new settings */
temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
temp |= PORT_PLL_RECALIBRATE;
I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
temp |= pll->config.hw_state.ebb4;
I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
/* Enable PLL */
temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
temp |= PORT_PLL_ENABLE;
I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
POSTING_READ(BXT_PORT_PLL_ENABLE(port));
if (wait_for_atomic_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) &
PORT_PLL_LOCK), 200))
DRM_ERROR("PLL %d not locked\n", port);
/*
* While we write to the group register to program all lanes at once we
* can read only lane registers and we pick lanes 0/1 for that.
*/
temp = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
temp &= ~LANE_STAGGER_MASK;
temp &= ~LANESTAGGER_STRAP_OVRD;
temp |= pll->config.hw_state.pcsdw12;
I915_WRITE(BXT_PORT_PCS_DW12_GRP(port), temp);
}
static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
uint32_t temp;
temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
temp &= ~PORT_PLL_ENABLE;
I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
POSTING_READ(BXT_PORT_PLL_ENABLE(port));
}
static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll,
struct intel_dpll_hw_state *hw_state)
{
enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
uint32_t val;
bool ret;
if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
ret = false;
val = I915_READ(BXT_PORT_PLL_ENABLE(port));
if (!(val & PORT_PLL_ENABLE))
goto out;
hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port));
hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0));
hw_state->pll0 &= PORT_PLL_M2_MASK;
hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1));
hw_state->pll1 &= PORT_PLL_N_MASK;
hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2));
hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK;
hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3));
hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE;
hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6));
hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK |
PORT_PLL_INT_COEFF_MASK |
PORT_PLL_GAIN_CTL_MASK;
hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8));
hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK;
hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9));
hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK;
hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10));
hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H |
PORT_PLL_DCO_AMP_MASK;
/*
* While we write to the group register to program all lanes at once we
* can read only lane registers. We configure all lanes the same way, so
* here just read out lanes 0/1 and output a note if lanes 2/3 differ.
*/
hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
if (I915_READ(BXT_PORT_PCS_DW12_LN23(port)) != hw_state->pcsdw12)
DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
hw_state->pcsdw12,
I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
ret = true;
out:
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
return ret;
}
static void bxt_shared_dplls_init(struct drm_i915_private *dev_priv)
{
int i;
dev_priv->num_shared_dpll = 3;
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
dev_priv->shared_dplls[i].id = i;
dev_priv->shared_dplls[i].name = bxt_ddi_pll_names[i];
dev_priv->shared_dplls[i].disable = bxt_ddi_pll_disable;
dev_priv->shared_dplls[i].enable = bxt_ddi_pll_enable;
dev_priv->shared_dplls[i].get_hw_state =
bxt_ddi_pll_get_hw_state;
}
}
static void intel_ddi_pll_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t val = I915_READ(LCPLL_CTL);
if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
skl_shared_dplls_init(dev_priv);
else if (IS_BROXTON(dev))
bxt_shared_dplls_init(dev_priv);
else
hsw_shared_dplls_init(dev_priv);
if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
int cdclk_freq;
cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
dev_priv->skl_boot_cdclk = cdclk_freq;
if (skl_sanitize_cdclk(dev_priv))
DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n");
if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE))
DRM_ERROR("LCPLL1 is disabled\n");
} else if (IS_BROXTON(dev)) {
broxton_init_cdclk(dev);
broxton_ddi_phy_init(dev);
} else {
/*
* The LCPLL register should be turned on by the BIOS. For now
* let's just check its state and print errors in case
* something is wrong. Don't even try to turn it on.
*/
if (val & LCPLL_CD_SOURCE_FCLK)
DRM_ERROR("CDCLK source is not LCPLL\n");
if (val & LCPLL_PLL_DISABLE)
DRM_ERROR("LCPLL is disabled\n");
}
}
void intel_shared_dpll_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
......
......@@ -1066,7 +1066,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc);
void intel_ddi_init(struct drm_device *dev, enum port port);
enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder);
bool intel_ddi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe);
void intel_ddi_pll_init(struct drm_device *dev);
void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc);
void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
enum transcoder cpu_transcoder);
......
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