drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT
authorJim Bride <jim.bride@linux.intel.com>
Wed, 7 Sep 2016 22:47:34 +0000 (15:47 -0700)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Fri, 9 Sep 2016 21:53:18 +0000 (14:53 -0700)
Add the PLL selection code for HSW/BDW/BXT/SKL into a stand-alone function
in order to allow for the implementation of a platform neutral upfront
link training function.

v4:
* Removed dereferencing NULL pointer in  case of failure (Dhinakaran Pandiyan)
v3:
* Add Hooks for all DDI platforms into this standalone function

v2:
* Change the macro to use dev_priv instead of dev (David Weinehall)

Reviewed-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_dpll_mgr.c
drivers/gpu/drm/i915/intel_dpll_mgr.h
drivers/gpu/drm/i915/intel_drv.h

index e4b875e..25e7973 100644 (file)
@@ -2393,6 +2393,45 @@ intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
        return connector;
 }
 
+struct intel_shared_dpll *
+intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
+{
+       struct intel_connector *connector = intel_dp->attached_connector;
+       struct intel_encoder *encoder = connector->encoder;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct intel_shared_dpll *pll = NULL;
+       struct intel_shared_dpll_config tmp_pll_config;
+       enum intel_dpll_id dpll_id;
+
+       if (IS_BROXTON(dev_priv)) {
+               dpll_id =  (enum intel_dpll_id)dig_port->port;
+               /*
+                * Select the required PLL. This works for platforms where
+                * there is no shared DPLL.
+                */
+               pll = &dev_priv->shared_dplls[dpll_id];
+               if (WARN_ON(pll->active_mask)) {
+
+                       DRM_ERROR("Shared DPLL in use. active_mask:%x\n",
+                                 pll->active_mask);
+                       return NULL;
+               }
+               tmp_pll_config = pll->config;
+               if (!bxt_ddi_dp_set_dpll_hw_state(clock,
+                                                 &pll->config.hw_state)) {
+                       DRM_ERROR("Could not setup DPLL\n");
+                       pll->config = tmp_pll_config;
+                       return NULL;
+               }
+       } else if (IS_SKYLAKE(dev_priv)) {
+               pll = skl_find_link_pll(dev_priv, clock);
+       } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
+               pll = hsw_ddi_dp_get_dpll(encoder, clock);
+       }
+       return pll;
+}
+
 void intel_ddi_init(struct drm_device *dev, enum port port)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
index 9a1da98..4b067ac 100644 (file)
 #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)
 {
index aed7408..f438535 100644 (file)
@@ -168,6 +168,8 @@ bool bxt_ddi_dp_set_dpll_hw_state(int clock,
 /* SKL dpll related functions */
 bool skl_ddi_dp_set_dpll_hw_state(int clock,
                                  struct intel_dpll_hw_state *dpll_hw_state);
+struct intel_shared_dpll *skl_find_link_pll(struct drm_i915_private *dev_priv,
+                                           int clock);
 
 
 /* HSW dpll related functions */
index 8c089e3..1bcf8ea 100644 (file)
@@ -1159,7 +1159,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
                         struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
-
+struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
+                                                 int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
                                   unsigned int height,
                                   uint32_t pixel_format,