diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-01-24 09:57:18 -0800 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-01-24 09:57:18 -0800 |
| commit | 62ed8ceda1699acae01b666497f004bfd3d67a6f (patch) | |
| tree | fe38c83c49dfd568b540666948ef78cb9d082c38 /drivers/gpu/drm/i915/intel_dpll_mgr.c | |
| parent | 1c3415a06b1016a596bfe59e0cfee56c773aa958 (diff) | |
| parent | 7a308bb3016f57e5be11a677d15b821536419d36 (diff) | |
Merge tag 'v4.10-rc5' into for-linus
Sync up with mainline to apply fixup to a commit that came through
power supply tree.
Diffstat (limited to 'drivers/gpu/drm/i915/intel_dpll_mgr.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_dpll_mgr.c | 568 |
1 files changed, 349 insertions, 219 deletions
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 5c1f2d235ffa..58a756f2f224 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -24,6 +24,44 @@ #include "intel_drv.h" struct intel_shared_dpll * +skl_find_link_pll(struct drm_i915_private *dev_priv, int clock) +{ + struct intel_shared_dpll *pll = NULL; + struct intel_dpll_hw_state dpll_hw_state; + enum intel_dpll_id i; + bool found = false; + + if (!skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state)) + return pll; + + for (i = DPLL_ID_SKL_DPLL1; i <= DPLL_ID_SKL_DPLL3; i++) { + pll = &dev_priv->shared_dplls[i]; + + /* Only want to check enabled timings first */ + if (pll->config.crtc_mask == 0) + continue; + + if (memcmp(&dpll_hw_state, &pll->config.hw_state, + sizeof(pll->config.hw_state)) == 0) { + found = true; + break; + } + } + + /* Ok no matching timings, maybe there's a free one? */ + for (i = DPLL_ID_SKL_DPLL1; + ((found == false) && (i <= DPLL_ID_SKL_DPLL3)); i++) { + pll = &dev_priv->shared_dplls[i]; + if (pll->config.crtc_mask == 0) { + pll->config.hw_state = dpll_hw_state; + break; + } + } + + return pll; +} + +struct intel_shared_dpll * intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv, enum intel_dpll_id id) { @@ -150,13 +188,12 @@ out: void intel_disable_shared_dpll(struct intel_crtc *crtc) { - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct intel_shared_dpll *pll = crtc->config->shared_dpll; unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base); /* PCH only available on ILK+ */ - if (INTEL_INFO(dev)->gen < 5) + if (INTEL_GEN(dev_priv) < 5) return; if (pll == NULL) @@ -452,26 +489,6 @@ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv, return val & SPLL_PLL_ENABLE; } -static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll) -{ - switch (pll->id) { - case DPLL_ID_WRPLL1: - return PORT_CLK_SEL_WRPLL1; - case DPLL_ID_WRPLL2: - return PORT_CLK_SEL_WRPLL2; - case DPLL_ID_SPLL: - return PORT_CLK_SEL_SPLL; - case DPLL_ID_LCPLL_810: - return PORT_CLK_SEL_LCPLL_810; - case DPLL_ID_LCPLL_1350: - return PORT_CLK_SEL_LCPLL_1350; - case DPLL_ID_LCPLL_2700: - return PORT_CLK_SEL_LCPLL_2700; - default: - return PORT_CLK_SEL_NONE; - } -} - #define LC_FREQ 2700 #define LC_FREQ_2K U64_C(LC_FREQ * 2000) @@ -687,11 +704,65 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */, *r2_out = best.r2; } +static struct intel_shared_dpll *hsw_ddi_hdmi_get_dpll(int clock, + struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state) +{ + struct intel_shared_dpll *pll; + uint32_t val; + unsigned int p, n2, r2; + + hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); + + val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL | + WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | + WRPLL_DIVIDER_POST(p); + + crtc_state->dpll_hw_state.wrpll = val; + + pll = intel_find_shared_dpll(crtc, crtc_state, + DPLL_ID_WRPLL1, DPLL_ID_WRPLL2); + + if (!pll) + return NULL; + + return pll; +} + +struct intel_shared_dpll *hsw_ddi_dp_get_dpll(struct intel_encoder *encoder, + int clock) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_shared_dpll *pll; + enum intel_dpll_id pll_id; + + switch (clock / 2) { + case 81000: + pll_id = DPLL_ID_LCPLL_810; + break; + case 135000: + pll_id = DPLL_ID_LCPLL_1350; + break; + case 270000: + pll_id = DPLL_ID_LCPLL_2700; + break; + default: + DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock); + return NULL; + } + + pll = intel_get_shared_dpll_by_id(dev_priv, pll_id); + + if (!pll) + return NULL; + + return pll; +} + static struct intel_shared_dpll * hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct intel_shared_dpll *pll; int clock = crtc_state->port_clock; @@ -699,41 +770,12 @@ hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, sizeof(crtc_state->dpll_hw_state)); if (encoder->type == INTEL_OUTPUT_HDMI) { - uint32_t val; - unsigned p, n2, r2; - - hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); - - val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL | - WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | - WRPLL_DIVIDER_POST(p); - - crtc_state->dpll_hw_state.wrpll = val; - - pll = intel_find_shared_dpll(crtc, crtc_state, - DPLL_ID_WRPLL1, DPLL_ID_WRPLL2); + pll = hsw_ddi_hdmi_get_dpll(clock, crtc, crtc_state); } else if (encoder->type == INTEL_OUTPUT_DP || encoder->type == INTEL_OUTPUT_DP_MST || encoder->type == INTEL_OUTPUT_EDP) { - enum intel_dpll_id pll_id; - - switch (clock / 2) { - case 81000: - pll_id = DPLL_ID_LCPLL_810; - break; - case 135000: - pll_id = DPLL_ID_LCPLL_1350; - break; - case 270000: - pll_id = DPLL_ID_LCPLL_2700; - break; - default: - DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock); - return NULL; - } - - pll = intel_get_shared_dpll_by_id(dev_priv, pll_id); + pll = hsw_ddi_dp_get_dpll(encoder, clock); } else if (encoder->type == INTEL_OUTPUT_ANALOG) { if (WARN_ON(crtc_state->port_clock / 2 != 135000)) @@ -751,14 +793,11 @@ hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, if (!pll) return NULL; - crtc_state->ddi_pll_sel = hsw_pll_to_ddi_pll_sel(pll); - intel_reference_shared_dpll(pll, crtc_state); return pll; } - static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = { .enable = hsw_ddi_wrpll_enable, .disable = hsw_ddi_wrpll_disable, @@ -1194,75 +1233,110 @@ skip_remaining_dividers: return true; } -static struct intel_shared_dpll * -skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, - struct intel_encoder *encoder) +static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state, + int clock) { - struct intel_shared_dpll *pll; uint32_t ctrl1, cfgcr1, cfgcr2; - int clock = crtc_state->port_clock; + struct skl_wrpll_params wrpll_params = { 0, }; /* * See comment in intel_dpll_hw_state to understand why we always use 0 * as the DPLL id in this function. */ - ctrl1 = DPLL_CTRL1_OVERRIDE(0); - if (encoder->type == INTEL_OUTPUT_HDMI) { - struct skl_wrpll_params wrpll_params = { 0, }; + ctrl1 |= DPLL_CTRL1_HDMI_MODE(0); - ctrl1 |= DPLL_CTRL1_HDMI_MODE(0); + if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params)) + return false; - if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params)) - return NULL; + cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE | + DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) | + wrpll_params.dco_integer; + + cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) | + DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) | + DPLL_CFGCR2_KDIV(wrpll_params.kdiv) | + DPLL_CFGCR2_PDIV(wrpll_params.pdiv) | + wrpll_params.central_freq; + + memset(&crtc_state->dpll_hw_state, 0, + sizeof(crtc_state->dpll_hw_state)); + + crtc_state->dpll_hw_state.ctrl1 = ctrl1; + crtc_state->dpll_hw_state.cfgcr1 = cfgcr1; + crtc_state->dpll_hw_state.cfgcr2 = cfgcr2; + return true; +} - cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE | - DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) | - wrpll_params.dco_integer; - cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) | - DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) | - DPLL_CFGCR2_KDIV(wrpll_params.kdiv) | - DPLL_CFGCR2_PDIV(wrpll_params.pdiv) | - wrpll_params.central_freq; +bool skl_ddi_dp_set_dpll_hw_state(int clock, + struct intel_dpll_hw_state *dpll_hw_state) +{ + uint32_t ctrl1; + + /* + * See comment in intel_dpll_hw_state to understand why we always use 0 + * as the DPLL id in this function. + */ + ctrl1 = DPLL_CTRL1_OVERRIDE(0); + switch (clock / 2) { + case 81000: + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0); + break; + case 135000: + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0); + break; + case 270000: + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0); + break; + /* eDP 1.4 rates */ + case 162000: + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0); + break; + case 108000: + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0); + break; + case 216000: + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0); + break; + } + + dpll_hw_state->ctrl1 = ctrl1; + return true; +} + +static struct intel_shared_dpll * +skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder) +{ + struct intel_shared_dpll *pll; + int clock = crtc_state->port_clock; + bool bret; + struct intel_dpll_hw_state dpll_hw_state; + + memset(&dpll_hw_state, 0, sizeof(dpll_hw_state)); + + if (encoder->type == INTEL_OUTPUT_HDMI) { + bret = skl_ddi_hdmi_pll_dividers(crtc, crtc_state, clock); + if (!bret) { + DRM_DEBUG_KMS("Could not get HDMI pll dividers.\n"); + return NULL; + } } else if (encoder->type == INTEL_OUTPUT_DP || encoder->type == INTEL_OUTPUT_DP_MST || encoder->type == INTEL_OUTPUT_EDP) { - switch (crtc_state->port_clock / 2) { - case 81000: - ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0); - break; - case 135000: - ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0); - break; - case 270000: - ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0); - break; - /* eDP 1.4 rates */ - case 162000: - ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0); - break; - case 108000: - ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0); - break; - case 216000: - ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0); - break; + bret = skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state); + if (!bret) { + DRM_DEBUG_KMS("Could not set DP dpll HW state.\n"); + return NULL; } - - cfgcr1 = cfgcr2 = 0; + crtc_state->dpll_hw_state = dpll_hw_state; } else { return NULL; } - memset(&crtc_state->dpll_hw_state, 0, - sizeof(crtc_state->dpll_hw_state)); - - crtc_state->dpll_hw_state.ctrl1 = ctrl1; - crtc_state->dpll_hw_state.cfgcr1 = cfgcr1; - crtc_state->dpll_hw_state.cfgcr2 = cfgcr2; - if (encoder->type == INTEL_OUTPUT_EDP) pll = intel_find_shared_dpll(crtc, crtc_state, DPLL_ID_SKL_DPLL0, @@ -1274,8 +1348,6 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, if (!pll) return NULL; - crtc_state->ddi_pll_sel = pll->id; - intel_reference_shared_dpll(pll, crtc_state); return pll; @@ -1298,6 +1370,10 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, { uint32_t temp; enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */ + enum dpio_phy phy; + enum dpio_channel ch; + + bxt_port_to_phy_channel(port, &phy, &ch); /* Non-SSC reference */ temp = I915_READ(BXT_PORT_PLL_ENABLE(port)); @@ -1305,72 +1381,72 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp); /* Disable 10 bit clock */ - temp = I915_READ(BXT_PORT_PLL_EBB_4(port)); + temp = I915_READ(BXT_PORT_PLL_EBB_4(phy, ch)); temp &= ~PORT_PLL_10BIT_CLK_ENABLE; - I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp); + I915_WRITE(BXT_PORT_PLL_EBB_4(phy, ch), temp); /* Write P1 & P2 */ - temp = I915_READ(BXT_PORT_PLL_EBB_0(port)); + temp = I915_READ(BXT_PORT_PLL_EBB_0(phy, ch)); temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK); temp |= pll->config.hw_state.ebb0; - I915_WRITE(BXT_PORT_PLL_EBB_0(port), temp); + I915_WRITE(BXT_PORT_PLL_EBB_0(phy, ch), temp); /* Write M2 integer */ - temp = I915_READ(BXT_PORT_PLL(port, 0)); + temp = I915_READ(BXT_PORT_PLL(phy, ch, 0)); temp &= ~PORT_PLL_M2_MASK; temp |= pll->config.hw_state.pll0; - I915_WRITE(BXT_PORT_PLL(port, 0), temp); + I915_WRITE(BXT_PORT_PLL(phy, ch, 0), temp); /* Write N */ - temp = I915_READ(BXT_PORT_PLL(port, 1)); + temp = I915_READ(BXT_PORT_PLL(phy, ch, 1)); temp &= ~PORT_PLL_N_MASK; temp |= pll->config.hw_state.pll1; - I915_WRITE(BXT_PORT_PLL(port, 1), temp); + I915_WRITE(BXT_PORT_PLL(phy, ch, 1), temp); /* Write M2 fraction */ - temp = I915_READ(BXT_PORT_PLL(port, 2)); + temp = I915_READ(BXT_PORT_PLL(phy, ch, 2)); temp &= ~PORT_PLL_M2_FRAC_MASK; temp |= pll->config.hw_state.pll2; - I915_WRITE(BXT_PORT_PLL(port, 2), temp); + I915_WRITE(BXT_PORT_PLL(phy, ch, 2), temp); /* Write M2 fraction enable */ - temp = I915_READ(BXT_PORT_PLL(port, 3)); + temp = I915_READ(BXT_PORT_PLL(phy, ch, 3)); temp &= ~PORT_PLL_M2_FRAC_ENABLE; temp |= pll->config.hw_state.pll3; - I915_WRITE(BXT_PORT_PLL(port, 3), temp); + I915_WRITE(BXT_PORT_PLL(phy, ch, 3), temp); /* Write coeff */ - temp = I915_READ(BXT_PORT_PLL(port, 6)); + temp = I915_READ(BXT_PORT_PLL(phy, ch, 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); + I915_WRITE(BXT_PORT_PLL(phy, ch, 6), temp); /* Write calibration val */ - temp = I915_READ(BXT_PORT_PLL(port, 8)); + temp = I915_READ(BXT_PORT_PLL(phy, ch, 8)); temp &= ~PORT_PLL_TARGET_CNT_MASK; temp |= pll->config.hw_state.pll8; - I915_WRITE(BXT_PORT_PLL(port, 8), temp); + I915_WRITE(BXT_PORT_PLL(phy, ch, 8), temp); - temp = I915_READ(BXT_PORT_PLL(port, 9)); + temp = I915_READ(BXT_PORT_PLL(phy, ch, 9)); temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK; temp |= pll->config.hw_state.pll9; - I915_WRITE(BXT_PORT_PLL(port, 9), temp); + I915_WRITE(BXT_PORT_PLL(phy, ch, 9), temp); - temp = I915_READ(BXT_PORT_PLL(port, 10)); + temp = I915_READ(BXT_PORT_PLL(phy, ch, 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); + I915_WRITE(BXT_PORT_PLL(phy, ch, 10), temp); /* Recalibrate with new settings */ - temp = I915_READ(BXT_PORT_PLL_EBB_4(port)); + temp = I915_READ(BXT_PORT_PLL_EBB_4(phy, ch)); temp |= PORT_PLL_RECALIBRATE; - I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp); + I915_WRITE(BXT_PORT_PLL_EBB_4(phy, ch), temp); temp &= ~PORT_PLL_10BIT_CLK_ENABLE; temp |= pll->config.hw_state.ebb4; - I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp); + I915_WRITE(BXT_PORT_PLL_EBB_4(phy, ch), temp); /* Enable PLL */ temp = I915_READ(BXT_PORT_PLL_ENABLE(port)); @@ -1386,11 +1462,11 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, * 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 = I915_READ(BXT_PORT_PCS_DW12_LN01(phy, ch)); temp &= ~LANE_STAGGER_MASK; temp &= ~LANESTAGGER_STRAP_OVRD; temp |= pll->config.hw_state.pcsdw12; - I915_WRITE(BXT_PORT_PCS_DW12_GRP(port), temp); + I915_WRITE(BXT_PORT_PCS_DW12_GRP(phy, ch), temp); } static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv, @@ -1412,6 +1488,10 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */ uint32_t val; bool ret; + enum dpio_phy phy; + enum dpio_channel ch; + + bxt_port_to_phy_channel(port, &phy, &ch); if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS)) return false; @@ -1422,36 +1502,36 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, if (!(val & PORT_PLL_ENABLE)) goto out; - hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port)); + hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(phy, ch)); 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 = I915_READ(BXT_PORT_PLL_EBB_4(phy, ch)); hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE; - hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0)); + hw_state->pll0 = I915_READ(BXT_PORT_PLL(phy, ch, 0)); hw_state->pll0 &= PORT_PLL_M2_MASK; - hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1)); + hw_state->pll1 = I915_READ(BXT_PORT_PLL(phy, ch, 1)); hw_state->pll1 &= PORT_PLL_N_MASK; - hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2)); + hw_state->pll2 = I915_READ(BXT_PORT_PLL(phy, ch, 2)); hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK; - hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3)); + hw_state->pll3 = I915_READ(BXT_PORT_PLL(phy, ch, 3)); hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE; - hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6)); + hw_state->pll6 = I915_READ(BXT_PORT_PLL(phy, ch, 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 = I915_READ(BXT_PORT_PLL(phy, ch, 8)); hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK; - hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9)); + hw_state->pll9 = I915_READ(BXT_PORT_PLL(phy, ch, 9)); hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK; - hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10)); + hw_state->pll10 = I915_READ(BXT_PORT_PLL(phy, ch, 10)); hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H | PORT_PLL_DCO_AMP_MASK; @@ -1460,11 +1540,11 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, * 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) + hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(phy, ch)); + if (I915_READ(BXT_PORT_PCS_DW12_LN23(phy, ch)) != 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))); + I915_READ(BXT_PORT_PCS_DW12_LN23(phy, ch))); hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD; ret = true; @@ -1484,6 +1564,8 @@ struct bxt_clk_div { uint32_t m2_frac; bool m2_frac_en; uint32_t n; + + int vco; }; /* pre-calculated values for DP linkrates */ @@ -1497,57 +1579,60 @@ static const struct bxt_clk_div bxt_dp_clk_val[] = { {432000, 3, 1, 32, 1677722, 1, 1} }; -static struct intel_shared_dpll * -bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, - struct intel_encoder *encoder) +static bool +bxt_ddi_hdmi_pll_dividers(struct intel_crtc *intel_crtc, + struct intel_crtc_state *crtc_state, int clock, + struct bxt_clk_div *clk_div) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct intel_shared_dpll *pll; - enum intel_dpll_id i; - struct intel_digital_port *intel_dig_port; - struct bxt_clk_div clk_div = {0}; - int vco = 0; - uint32_t prop_coef, int_coef, gain_ctl, targ_cnt; - uint32_t lanestagger; - int clock = crtc_state->port_clock; + struct dpll best_clock; - if (encoder->type == INTEL_OUTPUT_HDMI) { - struct dpll best_clock; + /* Calculate HDMI div */ + /* + * FIXME: tie the following calculation into + * i9xx_crtc_compute_clock + */ + if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) { + DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n", + clock, pipe_name(intel_crtc->pipe)); + return false; + } - /* Calculate HDMI div */ - /* - * FIXME: tie the following calculation into - * i9xx_crtc_compute_clock - */ - if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) { - DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n", - clock, pipe_name(crtc->pipe)); - return NULL; - } + clk_div->p1 = best_clock.p1; + clk_div->p2 = best_clock.p2; + WARN_ON(best_clock.m1 != 2); + clk_div->n = best_clock.n; + clk_div->m2_int = best_clock.m2 >> 22; + clk_div->m2_frac = best_clock.m2 & ((1 << 22) - 1); + clk_div->m2_frac_en = clk_div->m2_frac != 0; - clk_div.p1 = best_clock.p1; - clk_div.p2 = best_clock.p2; - WARN_ON(best_clock.m1 != 2); - clk_div.n = best_clock.n; - clk_div.m2_int = best_clock.m2 >> 22; - clk_div.m2_frac = best_clock.m2 & ((1 << 22) - 1); - clk_div.m2_frac_en = clk_div.m2_frac != 0; + clk_div->vco = best_clock.vco; - vco = best_clock.vco; - } else if (encoder->type == INTEL_OUTPUT_DP || - encoder->type == INTEL_OUTPUT_EDP) { - int i; + return true; +} - clk_div = bxt_dp_clk_val[0]; - for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) { - if (bxt_dp_clk_val[i].clock == clock) { - clk_div = bxt_dp_clk_val[i]; - break; - } +static void bxt_ddi_dp_pll_dividers(int clock, struct bxt_clk_div *clk_div) +{ + int i; + + *clk_div = bxt_dp_clk_val[0]; + for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) { + if (bxt_dp_clk_val[i].clock == clock) { + *clk_div = bxt_dp_clk_val[i]; + break; } - vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2; } + clk_div->vco = clock * 10 / 2 * clk_div->p1 * clk_div->p2; +} + +static bool bxt_ddi_set_dpll_hw_state(int clock, + struct bxt_clk_div *clk_div, + struct intel_dpll_hw_state *dpll_hw_state) +{ + int vco = clk_div->vco; + uint32_t prop_coef, int_coef, gain_ctl, targ_cnt; + uint32_t lanestagger; + if (vco >= 6200000 && vco <= 6700000) { prop_coef = 4; int_coef = 9; @@ -1566,12 +1651,9 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, targ_cnt = 9; } else { DRM_ERROR("Invalid VCO\n"); - return NULL; + return false; } - memset(&crtc_state->dpll_hw_state, 0, - sizeof(crtc_state->dpll_hw_state)); - if (clock > 270000) lanestagger = 0x18; else if (clock > 135000) @@ -1583,35 +1665,86 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, else lanestagger = 0x02; - crtc_state->dpll_hw_state.ebb0 = - PORT_PLL_P1(clk_div.p1) | PORT_PLL_P2(clk_div.p2); - crtc_state->dpll_hw_state.pll0 = clk_div.m2_int; - crtc_state->dpll_hw_state.pll1 = PORT_PLL_N(clk_div.n); - crtc_state->dpll_hw_state.pll2 = clk_div.m2_frac; + dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2); + dpll_hw_state->pll0 = clk_div->m2_int; + dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n); + dpll_hw_state->pll2 = clk_div->m2_frac; - if (clk_div.m2_frac_en) - crtc_state->dpll_hw_state.pll3 = - PORT_PLL_M2_FRAC_ENABLE; + if (clk_div->m2_frac_en) + dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE; - crtc_state->dpll_hw_state.pll6 = - prop_coef | PORT_PLL_INT_COEFF(int_coef); - crtc_state->dpll_hw_state.pll6 |= - PORT_PLL_GAIN_CTL(gain_ctl); + dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef); + dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl); - crtc_state->dpll_hw_state.pll8 = targ_cnt; + dpll_hw_state->pll8 = targ_cnt; - crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT; + dpll_hw_state->pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT; - crtc_state->dpll_hw_state.pll10 = + dpll_hw_state->pll10 = PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT) | PORT_PLL_DCO_AMP_OVR_EN_H; - crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE; + dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE; + + dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger; + + return true; +} + +bool bxt_ddi_dp_set_dpll_hw_state(int clock, + struct intel_dpll_hw_state *dpll_hw_state) +{ + struct bxt_clk_div clk_div = {0}; + + bxt_ddi_dp_pll_dividers(clock, &clk_div); + + return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state); +} + +static bool +bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc *intel_crtc, + struct intel_crtc_state *crtc_state, int clock, + struct intel_dpll_hw_state *dpll_hw_state) +{ + struct bxt_clk_div clk_div = { }; - crtc_state->dpll_hw_state.pcsdw12 = - LANESTAGGER_STRAP_OVRD | lanestagger; + bxt_ddi_hdmi_pll_dividers(intel_crtc, crtc_state, clock, &clk_div); - intel_dig_port = enc_to_dig_port(&encoder->base); + return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state); +} + +static struct intel_shared_dpll * +bxt_get_dpll(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state, + struct intel_encoder *encoder) +{ + struct intel_dpll_hw_state dpll_hw_state = { }; + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_digital_port *intel_dig_port; + struct intel_shared_dpll *pll; + int i, clock = crtc_state->port_clock; + + if (encoder->type == INTEL_OUTPUT_HDMI && + !bxt_ddi_hdmi_set_dpll_hw_state(crtc, crtc_state, clock, + &dpll_hw_state)) + return NULL; + + if ((encoder->type == INTEL_OUTPUT_DP || + encoder->type == INTEL_OUTPUT_EDP) && + !bxt_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state)) + return NULL; + + memset(&crtc_state->dpll_hw_state, 0, + sizeof(crtc_state->dpll_hw_state)); + + crtc_state->dpll_hw_state = dpll_hw_state; + + if (encoder->type == INTEL_OUTPUT_DP_MST) { + struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); + + intel_dig_port = intel_mst->primary; + } else + intel_dig_port = enc_to_dig_port(&encoder->base); /* 1:1 mapping between ports and PLLs */ i = (enum intel_dpll_id) intel_dig_port->port; @@ -1622,9 +1755,6 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, intel_reference_shared_dpll(pll, crtc_state); - /* shared DPLL id 0 is DPLL A */ - crtc_state->ddi_pll_sel = pll->id; - return pll; } @@ -1728,13 +1858,13 @@ void intel_shared_dpll_init(struct drm_device *dev) const struct dpll_info *dpll_info; int i; - if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) + if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) dpll_mgr = &skl_pll_mgr; - else if (IS_BROXTON(dev)) + else if (IS_BROXTON(dev_priv)) dpll_mgr = &bxt_pll_mgr; - else if (HAS_DDI(dev)) + else if (HAS_DDI(dev_priv)) dpll_mgr = &hsw_pll_mgr; - else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)) dpll_mgr = &pch_pll_mgr; if (!dpll_mgr) { @@ -1760,7 +1890,7 @@ void intel_shared_dpll_init(struct drm_device *dev) BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); /* FIXME: Move this to a more suitable place */ - if (HAS_DDI(dev)) + if (HAS_DDI(dev_priv)) intel_ddi_pll_init(dev); } |
