drm/i915: Move shared dpll code to a new file
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Tue, 8 Mar 2016 15:46:15 +0000 (17:46 +0200)
committerAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Wed, 9 Mar 2016 09:55:29 +0000 (11:55 +0200)
Create the new file intel_dpll_mgr.c and move the shared dpll code to
it. Follow up patches that reorganize pll handling will move more code
there and tweak the interface.

No functional changes.

Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1457451987-17466-2-git-send-email-ander.conselvan.de.oliveira@intel.com
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dpll_mgr.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_drv.h

index 0851de0..5558a03 100644 (file)
@@ -56,6 +56,7 @@ i915-y += intel_audio.o \
          intel_atomic_plane.o \
          intel_bios.o \
          intel_display.o \
+         intel_dpll_mgr.o \
          intel_fbc.o \
          intel_fifo_underrun.o \
          intel_frontbuffer.o \
index 62d36a7..1d5695d 100644 (file)
@@ -1197,34 +1197,6 @@ static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
 #define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true)
 #define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false)
 
-struct intel_shared_dpll *
-intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
-{
-       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
-
-       if (crtc->config->shared_dpll < 0)
-               return NULL;
-
-       return &dev_priv->shared_dplls[crtc->config->shared_dpll];
-}
-
-/* For ILK+ */
-void assert_shared_dpll(struct drm_i915_private *dev_priv,
-                       struct intel_shared_dpll *pll,
-                       bool state)
-{
-       bool cur_state;
-       struct intel_dpll_hw_state hw_state;
-
-       if (WARN(!pll, "asserting DPLL %s with no DPLL\n", onoff(state)))
-               return;
-
-       cur_state = pll->get_hw_state(dev_priv, pll, &hw_state);
-       I915_STATE_WARN(cur_state != state,
-            "%s assertion failure (expected %s, current %s)\n",
-                       pll->name, onoff(state), onoff(cur_state));
-}
-
 static void assert_fdi_tx(struct drm_i915_private *dev_priv,
                          enum pipe pipe, bool state)
 {
@@ -1461,21 +1433,8 @@ static void assert_vblank_disabled(struct drm_crtc *crtc)
                drm_crtc_vblank_put(crtc);
 }
 
-static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
-{
-       u32 val;
-       bool enabled;
-
-       I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
-
-       val = I915_READ(PCH_DREF_CONTROL);
-       enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
-                           DREF_SUPERSPREAD_SOURCE_MASK));
-       I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
-}
-
-static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
-                                          enum pipe pipe)
+void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
+                                   enum pipe pipe)
 {
        u32 val;
        bool enabled;
@@ -1871,100 +1830,6 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
                     port_name(dport->port), I915_READ(dpll_reg) & port_mask, expected_mask);
 }
 
-static void intel_prepare_shared_dpll(struct intel_crtc *crtc)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
-
-       if (WARN_ON(pll == NULL))
-               return;
-
-       WARN_ON(!pll->config.crtc_mask);
-       if (pll->active == 0) {
-               DRM_DEBUG_DRIVER("setting up %s\n", pll->name);
-               WARN_ON(pll->on);
-               assert_shared_dpll_disabled(dev_priv, pll);
-
-               pll->mode_set(dev_priv, pll);
-       }
-}
-
-/**
- * intel_enable_shared_dpll - enable PCH PLL
- * @dev_priv: i915 private structure
- * @pipe: pipe PLL to enable
- *
- * The PCH PLL needs to be enabled before the PCH transcoder, since it
- * drives the transcoder clock.
- */
-static void intel_enable_shared_dpll(struct intel_crtc *crtc)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
-
-       if (WARN_ON(pll == NULL))
-               return;
-
-       if (WARN_ON(pll->config.crtc_mask == 0))
-               return;
-
-       DRM_DEBUG_KMS("enable %s (active %d, on? %d) for crtc %d\n",
-                     pll->name, pll->active, pll->on,
-                     crtc->base.base.id);
-
-       if (pll->active++) {
-               WARN_ON(!pll->on);
-               assert_shared_dpll_enabled(dev_priv, pll);
-               return;
-       }
-       WARN_ON(pll->on);
-
-       intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
-
-       DRM_DEBUG_KMS("enabling %s\n", pll->name);
-       pll->enable(dev_priv, pll);
-       pll->on = true;
-}
-
-static void intel_disable_shared_dpll(struct intel_crtc *crtc)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
-
-       /* PCH only available on ILK+ */
-       if (INTEL_INFO(dev)->gen < 5)
-               return;
-
-       if (pll == NULL)
-               return;
-
-       if (WARN_ON(!(pll->config.crtc_mask & (1 << drm_crtc_index(&crtc->base)))))
-               return;
-
-       DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n",
-                     pll->name, pll->active, pll->on,
-                     crtc->base.base.id);
-
-       if (WARN_ON(pll->active == 0)) {
-               assert_shared_dpll_disabled(dev_priv, pll);
-               return;
-       }
-
-       assert_shared_dpll_enabled(dev_priv, pll);
-       WARN_ON(!pll->on);
-       if (--pll->active)
-               return;
-
-       DRM_DEBUG_KMS("disabling %s\n", pll->name);
-       pll->disable(dev_priv, pll);
-       pll->on = false;
-
-       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
-}
-
 static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
                                           enum pipe pipe)
 {
@@ -4361,113 +4226,6 @@ static void lpt_pch_enable(struct drm_crtc *crtc)
        lpt_enable_pch_transcoder(dev_priv, cpu_transcoder);
 }
 
-struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
-                                               struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
-       struct intel_shared_dpll *pll;
-       struct intel_shared_dpll_config *shared_dpll;
-       enum intel_dpll_id i;
-       int max = dev_priv->num_shared_dpll;
-
-       shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
-
-       if (HAS_PCH_IBX(dev_priv->dev)) {
-               /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
-               i = (enum intel_dpll_id) crtc->pipe;
-               pll = &dev_priv->shared_dplls[i];
-
-               DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
-                             crtc->base.base.id, pll->name);
-
-               WARN_ON(shared_dpll[i].crtc_mask);
-
-               goto found;
-       }
-
-       if (IS_BROXTON(dev_priv->dev)) {
-               /* PLL is attached to port in bxt */
-               struct intel_encoder *encoder;
-               struct intel_digital_port *intel_dig_port;
-
-               encoder = intel_ddi_get_crtc_new_encoder(crtc_state);
-               if (WARN_ON(!encoder))
-                       return NULL;
-
-               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;
-               pll = &dev_priv->shared_dplls[i];
-               DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
-                       crtc->base.base.id, pll->name);
-               WARN_ON(shared_dpll[i].crtc_mask);
-
-               goto found;
-       } else if (INTEL_INFO(dev_priv)->gen < 9 && HAS_DDI(dev_priv))
-               /* Do not consider SPLL */
-               max = 2;
-
-       for (i = 0; i < max; i++) {
-               pll = &dev_priv->shared_dplls[i];
-
-               /* Only want to check enabled timings first */
-               if (shared_dpll[i].crtc_mask == 0)
-                       continue;
-
-               if (memcmp(&crtc_state->dpll_hw_state,
-                          &shared_dpll[i].hw_state,
-                          sizeof(crtc_state->dpll_hw_state)) == 0) {
-                       DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n",
-                                     crtc->base.base.id, pll->name,
-                                     shared_dpll[i].crtc_mask,
-                                     pll->active);
-                       goto found;
-               }
-       }
-
-       /* Ok no matching timings, maybe there's a free one? */
-       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
-               pll = &dev_priv->shared_dplls[i];
-               if (shared_dpll[i].crtc_mask == 0) {
-                       DRM_DEBUG_KMS("CRTC:%d allocated %s\n",
-                                     crtc->base.base.id, pll->name);
-                       goto found;
-               }
-       }
-
-       return NULL;
-
-found:
-       if (shared_dpll[i].crtc_mask == 0)
-               shared_dpll[i].hw_state =
-                       crtc_state->dpll_hw_state;
-
-       crtc_state->shared_dpll = i;
-       DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
-                        pipe_name(crtc->pipe));
-
-       shared_dpll[i].crtc_mask |= 1 << crtc->pipe;
-
-       return pll;
-}
-
-static void intel_shared_dpll_commit(struct drm_atomic_state *state)
-{
-       struct drm_i915_private *dev_priv = to_i915(state->dev);
-       struct intel_shared_dpll_config *shared_dpll;
-       struct intel_shared_dpll *pll;
-       enum intel_dpll_id i;
-
-       if (!to_intel_atomic_state(state)->dpll_set)
-               return;
-
-       shared_dpll = to_intel_atomic_state(state)->shared_dpll;
-       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
-               pll = &dev_priv->shared_dplls[i];
-               pll->config = shared_dpll[i];
-       }
-}
-
 static void cpt_verify_modeset(struct drm_device *dev, int pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -13887,108 +13645,6 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
        .atomic_destroy_state = intel_crtc_destroy_state,
 };
 
-static bool ibx_pch_dpll_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(PCH_DPLL(pll->id));
-       hw_state->dpll = val;
-       hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
-       hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
-
-       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
-
-       return val & DPLL_VCO_ENABLE;
-}
-
-static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv,
-                                 struct intel_shared_dpll *pll)
-{
-       I915_WRITE(PCH_FP0(pll->id), pll->config.hw_state.fp0);
-       I915_WRITE(PCH_FP1(pll->id), pll->config.hw_state.fp1);
-}
-
-static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
-                               struct intel_shared_dpll *pll)
-{
-       /* PCH refclock must be enabled first */
-       ibx_assert_pch_refclk_enabled(dev_priv);
-
-       I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
-
-       /* Wait for the clocks to stabilize. */
-       POSTING_READ(PCH_DPLL(pll->id));
-       udelay(150);
-
-       /* The pixel multiplier can only be updated once the
-        * DPLL is enabled and the clocks are stable.
-        *
-        * So write it again.
-        */
-       I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
-       POSTING_READ(PCH_DPLL(pll->id));
-       udelay(200);
-}
-
-static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
-                                struct intel_shared_dpll *pll)
-{
-       struct drm_device *dev = dev_priv->dev;
-       struct intel_crtc *crtc;
-
-       /* Make sure no transcoder isn't still depending on us. */
-       for_each_intel_crtc(dev, crtc) {
-               if (intel_crtc_to_shared_dpll(crtc) == pll)
-                       assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
-       }
-
-       I915_WRITE(PCH_DPLL(pll->id), 0);
-       POSTING_READ(PCH_DPLL(pll->id));
-       udelay(200);
-}
-
-static char *ibx_pch_dpll_names[] = {
-       "PCH DPLL A",
-       "PCH DPLL B",
-};
-
-static void ibx_pch_dpll_init(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-
-       dev_priv->num_shared_dpll = 2;
-
-       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
-               dev_priv->shared_dplls[i].id = i;
-               dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i];
-               dev_priv->shared_dplls[i].mode_set = ibx_pch_dpll_mode_set;
-               dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable;
-               dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable;
-               dev_priv->shared_dplls[i].get_hw_state =
-                       ibx_pch_dpll_get_hw_state;
-       }
-}
-
-static void intel_shared_dpll_init(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (HAS_DDI(dev))
-               intel_ddi_pll_init(dev);
-       else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
-               ibx_pch_dpll_init(dev);
-       else
-               dev_priv->num_shared_dpll = 0;
-
-       BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
-}
-
 /**
  * intel_prepare_plane_fb - Prepare fb for usage on plane
  * @plane: drm plane to prepare for
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
new file mode 100644 (file)
index 0000000..d7ebac6
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright © 2006-2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "intel_drv.h"
+
+struct intel_shared_dpll *
+intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+       if (crtc->config->shared_dpll < 0)
+               return NULL;
+
+       return &dev_priv->shared_dplls[crtc->config->shared_dpll];
+}
+
+/* For ILK+ */
+void assert_shared_dpll(struct drm_i915_private *dev_priv,
+                       struct intel_shared_dpll *pll,
+                       bool state)
+{
+       bool cur_state;
+       struct intel_dpll_hw_state hw_state;
+
+       if (WARN(!pll, "asserting DPLL %s with no DPLL\n", onoff(state)))
+               return;
+
+       cur_state = pll->get_hw_state(dev_priv, pll, &hw_state);
+       I915_STATE_WARN(cur_state != state,
+            "%s assertion failure (expected %s, current %s)\n",
+                       pll->name, onoff(state), onoff(cur_state));
+}
+
+void intel_prepare_shared_dpll(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
+
+       if (WARN_ON(pll == NULL))
+               return;
+
+       WARN_ON(!pll->config.crtc_mask);
+       if (pll->active == 0) {
+               DRM_DEBUG_DRIVER("setting up %s\n", pll->name);
+               WARN_ON(pll->on);
+               assert_shared_dpll_disabled(dev_priv, pll);
+
+               pll->mode_set(dev_priv, pll);
+       }
+}
+
+/**
+ * intel_enable_shared_dpll - enable PCH PLL
+ * @dev_priv: i915 private structure
+ * @pipe: pipe PLL to enable
+ *
+ * The PCH PLL needs to be enabled before the PCH transcoder, since it
+ * drives the transcoder clock.
+ */
+void intel_enable_shared_dpll(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
+
+       if (WARN_ON(pll == NULL))
+               return;
+
+       if (WARN_ON(pll->config.crtc_mask == 0))
+               return;
+
+       DRM_DEBUG_KMS("enable %s (active %d, on? %d) for crtc %d\n",
+                     pll->name, pll->active, pll->on,
+                     crtc->base.base.id);
+
+       if (pll->active++) {
+               WARN_ON(!pll->on);
+               assert_shared_dpll_enabled(dev_priv, pll);
+               return;
+       }
+       WARN_ON(pll->on);
+
+       intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
+
+       DRM_DEBUG_KMS("enabling %s\n", pll->name);
+       pll->enable(dev_priv, pll);
+       pll->on = true;
+}
+
+void intel_disable_shared_dpll(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
+
+       /* PCH only available on ILK+ */
+       if (INTEL_INFO(dev)->gen < 5)
+               return;
+
+       if (pll == NULL)
+               return;
+
+       if (WARN_ON(!(pll->config.crtc_mask & (1 << drm_crtc_index(&crtc->base)))))
+               return;
+
+       DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n",
+                     pll->name, pll->active, pll->on,
+                     crtc->base.base.id);
+
+       if (WARN_ON(pll->active == 0)) {
+               assert_shared_dpll_disabled(dev_priv, pll);
+               return;
+       }
+
+       assert_shared_dpll_enabled(dev_priv, pll);
+       WARN_ON(!pll->on);
+       if (--pll->active)
+               return;
+
+       DRM_DEBUG_KMS("disabling %s\n", pll->name);
+       pll->disable(dev_priv, pll);
+       pll->on = false;
+
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+}
+
+struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
+                                               struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+       struct intel_shared_dpll *pll;
+       struct intel_shared_dpll_config *shared_dpll;
+       enum intel_dpll_id i;
+       int max = dev_priv->num_shared_dpll;
+
+       shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
+
+       if (HAS_PCH_IBX(dev_priv->dev)) {
+               /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
+               i = (enum intel_dpll_id) crtc->pipe;
+               pll = &dev_priv->shared_dplls[i];
+
+               DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
+                             crtc->base.base.id, pll->name);
+
+               WARN_ON(shared_dpll[i].crtc_mask);
+
+               goto found;
+       }
+
+       if (IS_BROXTON(dev_priv->dev)) {
+               /* PLL is attached to port in bxt */
+               struct intel_encoder *encoder;
+               struct intel_digital_port *intel_dig_port;
+
+               encoder = intel_ddi_get_crtc_new_encoder(crtc_state);
+               if (WARN_ON(!encoder))
+                       return NULL;
+
+               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;
+               pll = &dev_priv->shared_dplls[i];
+               DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
+                       crtc->base.base.id, pll->name);
+               WARN_ON(shared_dpll[i].crtc_mask);
+
+               goto found;
+       } else if (INTEL_INFO(dev_priv)->gen < 9 && HAS_DDI(dev_priv))
+               /* Do not consider SPLL */
+               max = 2;
+
+       for (i = 0; i < max; i++) {
+               pll = &dev_priv->shared_dplls[i];
+
+               /* Only want to check enabled timings first */
+               if (shared_dpll[i].crtc_mask == 0)
+                       continue;
+
+               if (memcmp(&crtc_state->dpll_hw_state,
+                          &shared_dpll[i].hw_state,
+                          sizeof(crtc_state->dpll_hw_state)) == 0) {
+                       DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n",
+                                     crtc->base.base.id, pll->name,
+                                     shared_dpll[i].crtc_mask,
+                                     pll->active);
+                       goto found;
+               }
+       }
+
+       /* Ok no matching timings, maybe there's a free one? */
+       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+               pll = &dev_priv->shared_dplls[i];
+               if (shared_dpll[i].crtc_mask == 0) {
+                       DRM_DEBUG_KMS("CRTC:%d allocated %s\n",
+                                     crtc->base.base.id, pll->name);
+                       goto found;
+               }
+       }
+
+       return NULL;
+
+found:
+       if (shared_dpll[i].crtc_mask == 0)
+               shared_dpll[i].hw_state =
+                       crtc_state->dpll_hw_state;
+
+       crtc_state->shared_dpll = i;
+       DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
+                        pipe_name(crtc->pipe));
+
+       shared_dpll[i].crtc_mask |= 1 << crtc->pipe;
+
+       return pll;
+}
+
+void intel_shared_dpll_commit(struct drm_atomic_state *state)
+{
+       struct drm_i915_private *dev_priv = to_i915(state->dev);
+       struct intel_shared_dpll_config *shared_dpll;
+       struct intel_shared_dpll *pll;
+       enum intel_dpll_id i;
+
+       if (!to_intel_atomic_state(state)->dpll_set)
+               return;
+
+       shared_dpll = to_intel_atomic_state(state)->shared_dpll;
+       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+               pll = &dev_priv->shared_dplls[i];
+               pll->config = shared_dpll[i];
+       }
+}
+
+static bool ibx_pch_dpll_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(PCH_DPLL(pll->id));
+       hw_state->dpll = val;
+       hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
+       hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
+
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+       return val & DPLL_VCO_ENABLE;
+}
+
+static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv,
+                                 struct intel_shared_dpll *pll)
+{
+       I915_WRITE(PCH_FP0(pll->id), pll->config.hw_state.fp0);
+       I915_WRITE(PCH_FP1(pll->id), pll->config.hw_state.fp1);
+}
+
+static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
+{
+       u32 val;
+       bool enabled;
+
+       I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
+
+       val = I915_READ(PCH_DREF_CONTROL);
+       enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
+                           DREF_SUPERSPREAD_SOURCE_MASK));
+       I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
+}
+
+static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
+                               struct intel_shared_dpll *pll)
+{
+       /* PCH refclock must be enabled first */
+       ibx_assert_pch_refclk_enabled(dev_priv);
+
+       I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
+
+       /* Wait for the clocks to stabilize. */
+       POSTING_READ(PCH_DPLL(pll->id));
+       udelay(150);
+
+       /* The pixel multiplier can only be updated once the
+        * DPLL is enabled and the clocks are stable.
+        *
+        * So write it again.
+        */
+       I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
+       POSTING_READ(PCH_DPLL(pll->id));
+       udelay(200);
+}
+
+static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
+                                struct intel_shared_dpll *pll)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct intel_crtc *crtc;
+
+       /* Make sure no transcoder isn't still depending on us. */
+       for_each_intel_crtc(dev, crtc) {
+               if (intel_crtc_to_shared_dpll(crtc) == pll)
+                       assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
+       }
+
+       I915_WRITE(PCH_DPLL(pll->id), 0);
+       POSTING_READ(PCH_DPLL(pll->id));
+       udelay(200);
+}
+
+static char *ibx_pch_dpll_names[] = {
+       "PCH DPLL A",
+       "PCH DPLL B",
+};
+
+static void ibx_pch_dpll_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+
+       dev_priv->num_shared_dpll = 2;
+
+       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+               dev_priv->shared_dplls[i].id = i;
+               dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i];
+               dev_priv->shared_dplls[i].mode_set = ibx_pch_dpll_mode_set;
+               dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable;
+               dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable;
+               dev_priv->shared_dplls[i].get_hw_state =
+                       ibx_pch_dpll_get_hw_state;
+       }
+}
+
+void intel_shared_dpll_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (HAS_DDI(dev))
+               intel_ddi_pll_init(dev);
+       else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+               ibx_pch_dpll_init(dev);
+       else
+               dev_priv->num_shared_dpll = 0;
+
+       BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
+}
index 7b2d66d..63b36b5 100644 (file)
@@ -1201,6 +1201,9 @@ intel_rotation_90_or_270(unsigned int rotation)
 void intel_create_rotation_property(struct drm_device *dev,
                                        struct intel_plane *plane);
 
+void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
+                                   enum pipe pipe);
+
 /* shared dpll functions */
 struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
 void assert_shared_dpll(struct drm_i915_private *dev_priv,
@@ -1210,6 +1213,11 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
 #define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
 struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
                                                struct intel_crtc_state *state);
+void intel_prepare_shared_dpll(struct intel_crtc *crtc);
+void intel_enable_shared_dpll(struct intel_crtc *crtc);
+void intel_disable_shared_dpll(struct intel_crtc *crtc);
+void intel_shared_dpll_commit(struct drm_atomic_state *state);
+void intel_shared_dpll_init(struct drm_device *dev);
 
 int vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
                     const struct dpll *dpll);