|
@@ -696,21 +696,23 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */,
|
|
|
*n2_out = best.n2;
|
|
|
*p_out = best.p;
|
|
|
*r2_out = best.r2;
|
|
|
-
|
|
|
- DRM_DEBUG_KMS("WRPLL: %dHz refresh rate with p=%d, n2=%d r2=%d\n",
|
|
|
- clock, *p_out, *n2_out, *r2_out);
|
|
|
}
|
|
|
|
|
|
-bool intel_ddi_pll_mode_set(struct drm_crtc *crtc)
|
|
|
+/*
|
|
|
+ * Tries to find a PLL for the CRTC. If it finds, it increases the refcount and
|
|
|
+ * stores it in intel_crtc->ddi_pll_sel, so other mode sets won't be able to
|
|
|
+ * steal the selected PLL. You need to call intel_ddi_pll_enable to actually
|
|
|
+ * enable the PLL.
|
|
|
+ */
|
|
|
+bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
|
|
|
{
|
|
|
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
+ struct drm_crtc *crtc = &intel_crtc->base;
|
|
|
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
|
|
|
struct drm_encoder *encoder = &intel_encoder->base;
|
|
|
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
|
|
|
struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
|
|
|
int type = intel_encoder->type;
|
|
|
enum pipe pipe = intel_crtc->pipe;
|
|
|
- uint32_t reg, val;
|
|
|
int clock = intel_crtc->config.port_clock;
|
|
|
|
|
|
intel_ddi_put_crtc_pll(crtc);
|
|
@@ -734,10 +736,8 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- /* We don't need to turn any PLL on because we'll use LCPLL. */
|
|
|
- return true;
|
|
|
-
|
|
|
} else if (type == INTEL_OUTPUT_HDMI) {
|
|
|
+ uint32_t reg, val;
|
|
|
unsigned p, n2, r2;
|
|
|
|
|
|
intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
|
|
@@ -767,6 +767,9 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n",
|
|
|
+ clock, p, n2, r2);
|
|
|
+
|
|
|
if (reg == WRPLL_CTL1) {
|
|
|
plls->wrpll1_refcount++;
|
|
|
intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1;
|
|
@@ -780,29 +783,98 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc)
|
|
|
DRM_DEBUG_KMS("Using SPLL on pipe %c\n",
|
|
|
pipe_name(pipe));
|
|
|
plls->spll_refcount++;
|
|
|
- reg = SPLL_CTL;
|
|
|
intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL;
|
|
|
} else {
|
|
|
DRM_ERROR("SPLL already in use\n");
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- WARN(I915_READ(reg) & SPLL_PLL_ENABLE,
|
|
|
- "SPLL already enabled\n");
|
|
|
-
|
|
|
- val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
|
|
|
-
|
|
|
} else {
|
|
|
WARN(1, "Invalid DDI encoder type %d\n", type);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- I915_WRITE(reg, val);
|
|
|
- udelay(20);
|
|
|
-
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * To be called after intel_ddi_pll_select(). That one selects the PLL to be
|
|
|
+ * used, this one actually enables the PLL.
|
|
|
+ */
|
|
|
+void intel_ddi_pll_enable(struct intel_crtc *crtc)
|
|
|
+{
|
|
|
+ struct drm_device *dev = crtc->base.dev;
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+ struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
|
|
|
+ int clock = crtc->config.port_clock;
|
|
|
+ uint32_t reg, cur_val, new_val;
|
|
|
+ int refcount;
|
|
|
+ const char *pll_name;
|
|
|
+ uint32_t enable_bit = (1 << 31);
|
|
|
+ unsigned int p, n2, r2;
|
|
|
+
|
|
|
+ BUILD_BUG_ON(enable_bit != SPLL_PLL_ENABLE);
|
|
|
+ BUILD_BUG_ON(enable_bit != WRPLL_PLL_ENABLE);
|
|
|
+
|
|
|
+ switch (crtc->ddi_pll_sel) {
|
|
|
+ case PORT_CLK_SEL_LCPLL_2700:
|
|
|
+ case PORT_CLK_SEL_LCPLL_1350:
|
|
|
+ case PORT_CLK_SEL_LCPLL_810:
|
|
|
+ /*
|
|
|
+ * LCPLL should always be enabled at this point of the mode set
|
|
|
+ * sequence, so nothing to do.
|
|
|
+ */
|
|
|
+ return;
|
|
|
+
|
|
|
+ case PORT_CLK_SEL_SPLL:
|
|
|
+ pll_name = "SPLL";
|
|
|
+ reg = SPLL_CTL;
|
|
|
+ refcount = plls->spll_refcount;
|
|
|
+ new_val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz |
|
|
|
+ SPLL_PLL_SSC;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case PORT_CLK_SEL_WRPLL1:
|
|
|
+ case PORT_CLK_SEL_WRPLL2:
|
|
|
+ if (crtc->ddi_pll_sel == PORT_CLK_SEL_WRPLL1) {
|
|
|
+ pll_name = "WRPLL1";
|
|
|
+ reg = WRPLL_CTL1;
|
|
|
+ refcount = plls->wrpll1_refcount;
|
|
|
+ } else {
|
|
|
+ pll_name = "WRPLL2";
|
|
|
+ reg = WRPLL_CTL2;
|
|
|
+ refcount = plls->wrpll2_refcount;
|
|
|
+ }
|
|
|
+
|
|
|
+ intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
|
|
|
+
|
|
|
+ new_val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 |
|
|
|
+ WRPLL_DIVIDER_REFERENCE(r2) |
|
|
|
+ WRPLL_DIVIDER_FEEDBACK(n2) | WRPLL_DIVIDER_POST(p);
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case PORT_CLK_SEL_NONE:
|
|
|
+ WARN(1, "Bad selected pll: PORT_CLK_SEL_NONE\n");
|
|
|
+ return;
|
|
|
+ default:
|
|
|
+ WARN(1, "Bad selected pll: 0x%08x\n", crtc->ddi_pll_sel);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ cur_val = I915_READ(reg);
|
|
|
+
|
|
|
+ WARN(refcount < 1, "Bad %s refcount: %d\n", pll_name, refcount);
|
|
|
+ if (refcount == 1) {
|
|
|
+ WARN(cur_val & enable_bit, "%s already enabled\n", pll_name);
|
|
|
+ I915_WRITE(reg, new_val);
|
|
|
+ POSTING_READ(reg);
|
|
|
+ udelay(20);
|
|
|
+ } else {
|
|
|
+ WARN((cur_val & enable_bit) == 0, "%s disabled\n", pll_name);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
|