xref: /dflybsd-src/sys/dev/drm/i915/intel_dpll_mgr.c (revision a85cb24f18e3804e75ab8bcda7692564d0563317)
18621f407SFrançois Tigeot /*
28621f407SFrançois Tigeot  * Copyright © 2006-2016 Intel Corporation
38621f407SFrançois Tigeot  *
48621f407SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
58621f407SFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
68621f407SFrançois Tigeot  * to deal in the Software without restriction, including without limitation
78621f407SFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88621f407SFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
98621f407SFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
108621f407SFrançois Tigeot  *
118621f407SFrançois Tigeot  * The above copyright notice and this permission notice (including the next
128621f407SFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
138621f407SFrançois Tigeot  * Software.
148621f407SFrançois Tigeot  *
158621f407SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168621f407SFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178621f407SFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188621f407SFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
198621f407SFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
208621f407SFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
218621f407SFrançois Tigeot  * DEALINGS IN THE SOFTWARE.
228621f407SFrançois Tigeot  */
238621f407SFrançois Tigeot 
248621f407SFrançois Tigeot #include "intel_drv.h"
258621f407SFrançois Tigeot #include <asm/int-ll64.h>
268621f407SFrançois Tigeot 
27*a85cb24fSFrançois Tigeot /**
28*a85cb24fSFrançois Tigeot  * DOC: Display PLLs
29*a85cb24fSFrançois Tigeot  *
30*a85cb24fSFrançois Tigeot  * Display PLLs used for driving outputs vary by platform. While some have
31*a85cb24fSFrançois Tigeot  * per-pipe or per-encoder dedicated PLLs, others allow the use of any PLL
32*a85cb24fSFrançois Tigeot  * from a pool. In the latter scenario, it is possible that multiple pipes
33*a85cb24fSFrançois Tigeot  * share a PLL if their configurations match.
34*a85cb24fSFrançois Tigeot  *
35*a85cb24fSFrançois Tigeot  * This file provides an abstraction over display PLLs. The function
36*a85cb24fSFrançois Tigeot  * intel_shared_dpll_init() initializes the PLLs for the given platform.  The
37*a85cb24fSFrançois Tigeot  * users of a PLL are tracked and that tracking is integrated with the atomic
38*a85cb24fSFrançois Tigeot  * modest interface. During an atomic operation, a PLL can be requested for a
39*a85cb24fSFrançois Tigeot  * given CRTC and encoder configuration by calling intel_get_shared_dpll() and
40*a85cb24fSFrançois Tigeot  * a previously used PLL can be released with intel_release_shared_dpll().
41*a85cb24fSFrançois Tigeot  * Changes to the users are first staged in the atomic state, and then made
42*a85cb24fSFrançois Tigeot  * effective by calling intel_shared_dpll_swap_state() during the atomic
43*a85cb24fSFrançois Tigeot  * commit phase.
44*a85cb24fSFrançois Tigeot  */
45*a85cb24fSFrançois Tigeot 
46*a85cb24fSFrançois Tigeot static void
47*a85cb24fSFrançois Tigeot intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv,
48*a85cb24fSFrançois Tigeot 				  struct intel_shared_dpll_state *shared_dpll)
491e12ee3bSFrançois Tigeot {
501e12ee3bSFrançois Tigeot 	enum intel_dpll_id i;
511e12ee3bSFrançois Tigeot 
52*a85cb24fSFrançois Tigeot 	/* Copy shared dpll state */
53*a85cb24fSFrançois Tigeot 	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
54*a85cb24fSFrançois Tigeot 		struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
551e12ee3bSFrançois Tigeot 
56*a85cb24fSFrançois Tigeot 		shared_dpll[i] = pll->state;
571e12ee3bSFrançois Tigeot 	}
581e12ee3bSFrançois Tigeot }
591e12ee3bSFrançois Tigeot 
60*a85cb24fSFrançois Tigeot static struct intel_shared_dpll_state *
61*a85cb24fSFrançois Tigeot intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s)
62*a85cb24fSFrançois Tigeot {
63*a85cb24fSFrançois Tigeot 	struct intel_atomic_state *state = to_intel_atomic_state(s);
64*a85cb24fSFrançois Tigeot 
65*a85cb24fSFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&s->dev->mode_config.connection_mutex));
66*a85cb24fSFrançois Tigeot 
67*a85cb24fSFrançois Tigeot 	if (!state->dpll_set) {
68*a85cb24fSFrançois Tigeot 		state->dpll_set = true;
69*a85cb24fSFrançois Tigeot 
70*a85cb24fSFrançois Tigeot 		intel_atomic_duplicate_dpll_state(to_i915(s->dev),
71*a85cb24fSFrançois Tigeot 						  state->shared_dpll);
721e12ee3bSFrançois Tigeot 	}
731e12ee3bSFrançois Tigeot 
74*a85cb24fSFrançois Tigeot 	return state->shared_dpll;
751e12ee3bSFrançois Tigeot }
761e12ee3bSFrançois Tigeot 
77*a85cb24fSFrançois Tigeot /**
78*a85cb24fSFrançois Tigeot  * intel_get_shared_dpll_by_id - get a DPLL given its id
79*a85cb24fSFrançois Tigeot  * @dev_priv: i915 device instance
80*a85cb24fSFrançois Tigeot  * @id: pll id
81*a85cb24fSFrançois Tigeot  *
82*a85cb24fSFrançois Tigeot  * Returns:
83*a85cb24fSFrançois Tigeot  * A pointer to the DPLL with @id
84*a85cb24fSFrançois Tigeot  */
851e12ee3bSFrançois Tigeot struct intel_shared_dpll *
868621f407SFrançois Tigeot intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
878621f407SFrançois Tigeot 			    enum intel_dpll_id id)
888621f407SFrançois Tigeot {
898621f407SFrançois Tigeot 	return &dev_priv->shared_dplls[id];
908621f407SFrançois Tigeot }
918621f407SFrançois Tigeot 
92*a85cb24fSFrançois Tigeot /**
93*a85cb24fSFrançois Tigeot  * intel_get_shared_dpll_id - get the id of a DPLL
94*a85cb24fSFrançois Tigeot  * @dev_priv: i915 device instance
95*a85cb24fSFrançois Tigeot  * @pll: the DPLL
96*a85cb24fSFrançois Tigeot  *
97*a85cb24fSFrançois Tigeot  * Returns:
98*a85cb24fSFrançois Tigeot  * The id of @pll
99*a85cb24fSFrançois Tigeot  */
1008621f407SFrançois Tigeot enum intel_dpll_id
1018621f407SFrançois Tigeot intel_get_shared_dpll_id(struct drm_i915_private *dev_priv,
1028621f407SFrançois Tigeot 			 struct intel_shared_dpll *pll)
1038621f407SFrançois Tigeot {
1048621f407SFrançois Tigeot 	if (WARN_ON(pll < dev_priv->shared_dplls||
1058621f407SFrançois Tigeot 		    pll > &dev_priv->shared_dplls[dev_priv->num_shared_dpll]))
1068621f407SFrançois Tigeot 		return -1;
1078621f407SFrançois Tigeot 
1088621f407SFrançois Tigeot 	return (enum intel_dpll_id) (pll - dev_priv->shared_dplls);
1098621f407SFrançois Tigeot }
1108621f407SFrançois Tigeot 
1118621f407SFrançois Tigeot /* For ILK+ */
1128621f407SFrançois Tigeot void assert_shared_dpll(struct drm_i915_private *dev_priv,
1138621f407SFrançois Tigeot 			struct intel_shared_dpll *pll,
1148621f407SFrançois Tigeot 			bool state)
1158621f407SFrançois Tigeot {
1168621f407SFrançois Tigeot 	bool cur_state;
1178621f407SFrançois Tigeot 	struct intel_dpll_hw_state hw_state;
1188621f407SFrançois Tigeot 
1198621f407SFrançois Tigeot 	if (WARN(!pll, "asserting DPLL %s with no DPLL\n", onoff(state)))
1208621f407SFrançois Tigeot 		return;
1218621f407SFrançois Tigeot 
1228621f407SFrançois Tigeot 	cur_state = pll->funcs.get_hw_state(dev_priv, pll, &hw_state);
1238621f407SFrançois Tigeot 	I915_STATE_WARN(cur_state != state,
1248621f407SFrançois Tigeot 	     "%s assertion failure (expected %s, current %s)\n",
1258621f407SFrançois Tigeot 			pll->name, onoff(state), onoff(cur_state));
1268621f407SFrançois Tigeot }
1278621f407SFrançois Tigeot 
128*a85cb24fSFrançois Tigeot /**
129*a85cb24fSFrançois Tigeot  * intel_prepare_shared_dpll - call a dpll's prepare hook
130*a85cb24fSFrançois Tigeot  * @crtc: CRTC which has a shared dpll
131*a85cb24fSFrançois Tigeot  *
132*a85cb24fSFrançois Tigeot  * This calls the PLL's prepare hook if it has one and if the PLL is not
133*a85cb24fSFrançois Tigeot  * already enabled. The prepare hook is platform specific.
134*a85cb24fSFrançois Tigeot  */
1358621f407SFrançois Tigeot void intel_prepare_shared_dpll(struct intel_crtc *crtc)
1368621f407SFrançois Tigeot {
1378621f407SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
138303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1398621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
1408621f407SFrançois Tigeot 
1418621f407SFrançois Tigeot 	if (WARN_ON(pll == NULL))
1428621f407SFrançois Tigeot 		return;
1438621f407SFrançois Tigeot 
1448621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
145*a85cb24fSFrançois Tigeot 	WARN_ON(!pll->state.crtc_mask);
1468621f407SFrançois Tigeot 	if (!pll->active_mask) {
1478621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("setting up %s\n", pll->name);
1488621f407SFrançois Tigeot 		WARN_ON(pll->on);
1498621f407SFrançois Tigeot 		assert_shared_dpll_disabled(dev_priv, pll);
1508621f407SFrançois Tigeot 
151*a85cb24fSFrançois Tigeot 		pll->funcs.prepare(dev_priv, pll);
1528621f407SFrançois Tigeot 	}
1538621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
1548621f407SFrançois Tigeot }
1558621f407SFrançois Tigeot 
1568621f407SFrançois Tigeot /**
157*a85cb24fSFrançois Tigeot  * intel_enable_shared_dpll - enable a CRTC's shared DPLL
158*a85cb24fSFrançois Tigeot  * @crtc: CRTC which has a shared DPLL
1598621f407SFrançois Tigeot  *
160*a85cb24fSFrançois Tigeot  * Enable the shared DPLL used by @crtc.
1618621f407SFrançois Tigeot  */
1628621f407SFrançois Tigeot void intel_enable_shared_dpll(struct intel_crtc *crtc)
1638621f407SFrançois Tigeot {
1648621f407SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
165303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1668621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
1678621f407SFrançois Tigeot 	unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base);
1688621f407SFrançois Tigeot 	unsigned old_mask;
1698621f407SFrançois Tigeot 
1708621f407SFrançois Tigeot 	if (WARN_ON(pll == NULL))
1718621f407SFrançois Tigeot 		return;
1728621f407SFrançois Tigeot 
1738621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
1748621f407SFrançois Tigeot 	old_mask = pll->active_mask;
1758621f407SFrançois Tigeot 
176*a85cb24fSFrançois Tigeot 	if (WARN_ON(!(pll->state.crtc_mask & crtc_mask)) ||
1778621f407SFrançois Tigeot 	    WARN_ON(pll->active_mask & crtc_mask))
1788621f407SFrançois Tigeot 		goto out;
1798621f407SFrançois Tigeot 
1808621f407SFrançois Tigeot 	pll->active_mask |= crtc_mask;
1818621f407SFrançois Tigeot 
1828621f407SFrançois Tigeot 	DRM_DEBUG_KMS("enable %s (active %x, on? %d) for crtc %d\n",
1838621f407SFrançois Tigeot 		      pll->name, pll->active_mask, pll->on,
1848621f407SFrançois Tigeot 		      crtc->base.base.id);
1858621f407SFrançois Tigeot 
1868621f407SFrançois Tigeot 	if (old_mask) {
1878621f407SFrançois Tigeot 		WARN_ON(!pll->on);
1888621f407SFrançois Tigeot 		assert_shared_dpll_enabled(dev_priv, pll);
1898621f407SFrançois Tigeot 		goto out;
1908621f407SFrançois Tigeot 	}
1918621f407SFrançois Tigeot 	WARN_ON(pll->on);
1928621f407SFrançois Tigeot 
1938621f407SFrançois Tigeot 	DRM_DEBUG_KMS("enabling %s\n", pll->name);
1948621f407SFrançois Tigeot 	pll->funcs.enable(dev_priv, pll);
1958621f407SFrançois Tigeot 	pll->on = true;
1968621f407SFrançois Tigeot 
1978621f407SFrançois Tigeot out:
1988621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
1998621f407SFrançois Tigeot }
2008621f407SFrançois Tigeot 
201*a85cb24fSFrançois Tigeot /**
202*a85cb24fSFrançois Tigeot  * intel_disable_shared_dpll - disable a CRTC's shared DPLL
203*a85cb24fSFrançois Tigeot  * @crtc: CRTC which has a shared DPLL
204*a85cb24fSFrançois Tigeot  *
205*a85cb24fSFrançois Tigeot  * Disable the shared DPLL used by @crtc.
206*a85cb24fSFrançois Tigeot  */
2078621f407SFrançois Tigeot void intel_disable_shared_dpll(struct intel_crtc *crtc)
2088621f407SFrançois Tigeot {
2094be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
2108621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
2118621f407SFrançois Tigeot 	unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base);
2128621f407SFrançois Tigeot 
2138621f407SFrançois Tigeot 	/* PCH only available on ILK+ */
2144be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 5)
2158621f407SFrançois Tigeot 		return;
2168621f407SFrançois Tigeot 
2178621f407SFrançois Tigeot 	if (pll == NULL)
2188621f407SFrançois Tigeot 		return;
2198621f407SFrançois Tigeot 
2208621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
2218621f407SFrançois Tigeot 	if (WARN_ON(!(pll->active_mask & crtc_mask)))
2228621f407SFrançois Tigeot 		goto out;
2238621f407SFrançois Tigeot 
2248621f407SFrançois Tigeot 	DRM_DEBUG_KMS("disable %s (active %x, on? %d) for crtc %d\n",
2258621f407SFrançois Tigeot 		      pll->name, pll->active_mask, pll->on,
2268621f407SFrançois Tigeot 		      crtc->base.base.id);
2278621f407SFrançois Tigeot 
2288621f407SFrançois Tigeot 	assert_shared_dpll_enabled(dev_priv, pll);
2298621f407SFrançois Tigeot 	WARN_ON(!pll->on);
2308621f407SFrançois Tigeot 
2318621f407SFrançois Tigeot 	pll->active_mask &= ~crtc_mask;
2328621f407SFrançois Tigeot 	if (pll->active_mask)
2338621f407SFrançois Tigeot 		goto out;
2348621f407SFrançois Tigeot 
2358621f407SFrançois Tigeot 	DRM_DEBUG_KMS("disabling %s\n", pll->name);
2368621f407SFrançois Tigeot 	pll->funcs.disable(dev_priv, pll);
2378621f407SFrançois Tigeot 	pll->on = false;
2388621f407SFrançois Tigeot 
2398621f407SFrançois Tigeot out:
2408621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
2418621f407SFrançois Tigeot }
2428621f407SFrançois Tigeot 
2438621f407SFrançois Tigeot static struct intel_shared_dpll *
2448621f407SFrançois Tigeot intel_find_shared_dpll(struct intel_crtc *crtc,
2458621f407SFrançois Tigeot 		       struct intel_crtc_state *crtc_state,
2468621f407SFrançois Tigeot 		       enum intel_dpll_id range_min,
2478621f407SFrançois Tigeot 		       enum intel_dpll_id range_max)
2488621f407SFrançois Tigeot {
249303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
2508621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
251*a85cb24fSFrançois Tigeot 	struct intel_shared_dpll_state *shared_dpll;
2528621f407SFrançois Tigeot 	enum intel_dpll_id i;
2538621f407SFrançois Tigeot 
2548621f407SFrançois Tigeot 	shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
2558621f407SFrançois Tigeot 
2568621f407SFrançois Tigeot 	for (i = range_min; i <= range_max; i++) {
2578621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
2588621f407SFrançois Tigeot 
2598621f407SFrançois Tigeot 		/* Only want to check enabled timings first */
2608621f407SFrançois Tigeot 		if (shared_dpll[i].crtc_mask == 0)
2618621f407SFrançois Tigeot 			continue;
2628621f407SFrançois Tigeot 
2638621f407SFrançois Tigeot 		if (memcmp(&crtc_state->dpll_hw_state,
2648621f407SFrançois Tigeot 			   &shared_dpll[i].hw_state,
2658621f407SFrançois Tigeot 			   sizeof(crtc_state->dpll_hw_state)) == 0) {
2661487f786SFrançois Tigeot 			DRM_DEBUG_KMS("[CRTC:%d:%s] sharing existing %s (crtc mask 0x%08x, active %x)\n",
2671487f786SFrançois Tigeot 				      crtc->base.base.id, crtc->base.name, pll->name,
2688621f407SFrançois Tigeot 				      shared_dpll[i].crtc_mask,
2698621f407SFrançois Tigeot 				      pll->active_mask);
2708621f407SFrançois Tigeot 			return pll;
2718621f407SFrançois Tigeot 		}
2728621f407SFrançois Tigeot 	}
2738621f407SFrançois Tigeot 
2748621f407SFrançois Tigeot 	/* Ok no matching timings, maybe there's a free one? */
2758621f407SFrançois Tigeot 	for (i = range_min; i <= range_max; i++) {
2768621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
2778621f407SFrançois Tigeot 		if (shared_dpll[i].crtc_mask == 0) {
2781487f786SFrançois Tigeot 			DRM_DEBUG_KMS("[CRTC:%d:%s] allocated %s\n",
2791487f786SFrançois Tigeot 				      crtc->base.base.id, crtc->base.name, pll->name);
2808621f407SFrançois Tigeot 			return pll;
2818621f407SFrançois Tigeot 		}
2828621f407SFrançois Tigeot 	}
2838621f407SFrançois Tigeot 
2848621f407SFrançois Tigeot 	return NULL;
2858621f407SFrançois Tigeot }
2868621f407SFrançois Tigeot 
2878621f407SFrançois Tigeot static void
2888621f407SFrançois Tigeot intel_reference_shared_dpll(struct intel_shared_dpll *pll,
2898621f407SFrançois Tigeot 			    struct intel_crtc_state *crtc_state)
2908621f407SFrançois Tigeot {
291*a85cb24fSFrançois Tigeot 	struct intel_shared_dpll_state *shared_dpll;
2928621f407SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
2938621f407SFrançois Tigeot 	enum intel_dpll_id i = pll->id;
2948621f407SFrançois Tigeot 
2958621f407SFrançois Tigeot 	shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
2968621f407SFrançois Tigeot 
2978621f407SFrançois Tigeot 	if (shared_dpll[i].crtc_mask == 0)
2988621f407SFrançois Tigeot 		shared_dpll[i].hw_state =
2998621f407SFrançois Tigeot 			crtc_state->dpll_hw_state;
3008621f407SFrançois Tigeot 
3018621f407SFrançois Tigeot 	crtc_state->shared_dpll = pll;
3028621f407SFrançois Tigeot 	DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
3038621f407SFrançois Tigeot 			 pipe_name(crtc->pipe));
3048621f407SFrançois Tigeot 
305*a85cb24fSFrançois Tigeot 	shared_dpll[pll->id].crtc_mask |= 1 << crtc->pipe;
3068621f407SFrançois Tigeot }
3078621f407SFrançois Tigeot 
308*a85cb24fSFrançois Tigeot /**
309*a85cb24fSFrançois Tigeot  * intel_shared_dpll_swap_state - make atomic DPLL configuration effective
310*a85cb24fSFrançois Tigeot  * @state: atomic state
311*a85cb24fSFrançois Tigeot  *
312*a85cb24fSFrançois Tigeot  * This is the dpll version of drm_atomic_helper_swap_state() since the
313*a85cb24fSFrançois Tigeot  * helper does not handle driver-specific global state.
314*a85cb24fSFrançois Tigeot  *
315*a85cb24fSFrançois Tigeot  * For consistency with atomic helpers this function does a complete swap,
316*a85cb24fSFrançois Tigeot  * i.e. it also puts the current state into @state, even though there is no
317*a85cb24fSFrançois Tigeot  * need for that at this moment.
318*a85cb24fSFrançois Tigeot  */
319*a85cb24fSFrançois Tigeot void intel_shared_dpll_swap_state(struct drm_atomic_state *state)
3208621f407SFrançois Tigeot {
3218621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(state->dev);
322*a85cb24fSFrançois Tigeot 	struct intel_shared_dpll_state *shared_dpll;
3238621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
3248621f407SFrançois Tigeot 	enum intel_dpll_id i;
3258621f407SFrançois Tigeot 
3268621f407SFrançois Tigeot 	if (!to_intel_atomic_state(state)->dpll_set)
3278621f407SFrançois Tigeot 		return;
3288621f407SFrançois Tigeot 
3298621f407SFrançois Tigeot 	shared_dpll = to_intel_atomic_state(state)->shared_dpll;
3308621f407SFrançois Tigeot 	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
331*a85cb24fSFrançois Tigeot 		struct intel_shared_dpll_state tmp;
332*a85cb24fSFrançois Tigeot 
3338621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
334*a85cb24fSFrançois Tigeot 
335*a85cb24fSFrançois Tigeot 		tmp = pll->state;
336*a85cb24fSFrançois Tigeot 		pll->state = shared_dpll[i];
337*a85cb24fSFrançois Tigeot 		shared_dpll[i] = tmp;
3388621f407SFrançois Tigeot 	}
3398621f407SFrançois Tigeot }
3408621f407SFrançois Tigeot 
3418621f407SFrançois Tigeot static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
3428621f407SFrançois Tigeot 				      struct intel_shared_dpll *pll,
3438621f407SFrançois Tigeot 				      struct intel_dpll_hw_state *hw_state)
3448621f407SFrançois Tigeot {
3458621f407SFrançois Tigeot 	uint32_t val;
3468621f407SFrançois Tigeot 
3478621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
3488621f407SFrançois Tigeot 		return false;
3498621f407SFrançois Tigeot 
3508621f407SFrançois Tigeot 	val = I915_READ(PCH_DPLL(pll->id));
3518621f407SFrançois Tigeot 	hw_state->dpll = val;
3528621f407SFrançois Tigeot 	hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
3538621f407SFrançois Tigeot 	hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
3548621f407SFrançois Tigeot 
3558621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
3568621f407SFrançois Tigeot 
3578621f407SFrançois Tigeot 	return val & DPLL_VCO_ENABLE;
3588621f407SFrançois Tigeot }
3598621f407SFrançois Tigeot 
360*a85cb24fSFrançois Tigeot static void ibx_pch_dpll_prepare(struct drm_i915_private *dev_priv,
3618621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
3628621f407SFrançois Tigeot {
363*a85cb24fSFrançois Tigeot 	I915_WRITE(PCH_FP0(pll->id), pll->state.hw_state.fp0);
364*a85cb24fSFrançois Tigeot 	I915_WRITE(PCH_FP1(pll->id), pll->state.hw_state.fp1);
3658621f407SFrançois Tigeot }
3668621f407SFrançois Tigeot 
3678621f407SFrançois Tigeot static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
3688621f407SFrançois Tigeot {
3698621f407SFrançois Tigeot 	u32 val;
3708621f407SFrançois Tigeot 	bool enabled;
3718621f407SFrançois Tigeot 
3728621f407SFrançois Tigeot 	I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)));
3738621f407SFrançois Tigeot 
3748621f407SFrançois Tigeot 	val = I915_READ(PCH_DREF_CONTROL);
3758621f407SFrançois Tigeot 	enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
3768621f407SFrançois Tigeot 			    DREF_SUPERSPREAD_SOURCE_MASK));
3778621f407SFrançois Tigeot 	I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
3788621f407SFrançois Tigeot }
3798621f407SFrançois Tigeot 
3808621f407SFrançois Tigeot static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
3818621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
3828621f407SFrançois Tigeot {
3838621f407SFrançois Tigeot 	/* PCH refclock must be enabled first */
3848621f407SFrançois Tigeot 	ibx_assert_pch_refclk_enabled(dev_priv);
3858621f407SFrançois Tigeot 
386*a85cb24fSFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), pll->state.hw_state.dpll);
3878621f407SFrançois Tigeot 
3888621f407SFrançois Tigeot 	/* Wait for the clocks to stabilize. */
3898621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
3908621f407SFrançois Tigeot 	udelay(150);
3918621f407SFrançois Tigeot 
3928621f407SFrançois Tigeot 	/* The pixel multiplier can only be updated once the
3938621f407SFrançois Tigeot 	 * DPLL is enabled and the clocks are stable.
3948621f407SFrançois Tigeot 	 *
3958621f407SFrançois Tigeot 	 * So write it again.
3968621f407SFrançois Tigeot 	 */
397*a85cb24fSFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), pll->state.hw_state.dpll);
3988621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
3998621f407SFrançois Tigeot 	udelay(200);
4008621f407SFrançois Tigeot }
4018621f407SFrançois Tigeot 
4028621f407SFrançois Tigeot static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
4038621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
4048621f407SFrançois Tigeot {
405303bf270SFrançois Tigeot 	struct drm_device *dev = &dev_priv->drm;
4068621f407SFrançois Tigeot 	struct intel_crtc *crtc;
4078621f407SFrançois Tigeot 
4088621f407SFrançois Tigeot 	/* Make sure no transcoder isn't still depending on us. */
4098621f407SFrançois Tigeot 	for_each_intel_crtc(dev, crtc) {
4108621f407SFrançois Tigeot 		if (crtc->config->shared_dpll == pll)
4118621f407SFrançois Tigeot 			assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
4128621f407SFrançois Tigeot 	}
4138621f407SFrançois Tigeot 
4148621f407SFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), 0);
4158621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
4168621f407SFrançois Tigeot 	udelay(200);
4178621f407SFrançois Tigeot }
4188621f407SFrançois Tigeot 
4198621f407SFrançois Tigeot static struct intel_shared_dpll *
4208621f407SFrançois Tigeot ibx_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
4218621f407SFrançois Tigeot 	     struct intel_encoder *encoder)
4228621f407SFrançois Tigeot {
4238621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
4248621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
4258621f407SFrançois Tigeot 	enum intel_dpll_id i;
4268621f407SFrançois Tigeot 
4278621f407SFrançois Tigeot 	if (HAS_PCH_IBX(dev_priv)) {
4288621f407SFrançois Tigeot 		/* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
4298621f407SFrançois Tigeot 		i = (enum intel_dpll_id) crtc->pipe;
4308621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
4318621f407SFrançois Tigeot 
4321487f786SFrançois Tigeot 		DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n",
4331487f786SFrançois Tigeot 			      crtc->base.base.id, crtc->base.name, pll->name);
4348621f407SFrançois Tigeot 	} else {
4358621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
4368621f407SFrançois Tigeot 					     DPLL_ID_PCH_PLL_A,
4378621f407SFrançois Tigeot 					     DPLL_ID_PCH_PLL_B);
4388621f407SFrançois Tigeot 	}
4398621f407SFrançois Tigeot 
4408621f407SFrançois Tigeot 	if (!pll)
4418621f407SFrançois Tigeot 		return NULL;
4428621f407SFrançois Tigeot 
4438621f407SFrançois Tigeot 	/* reference the pll */
4448621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
4458621f407SFrançois Tigeot 
4468621f407SFrançois Tigeot 	return pll;
4478621f407SFrançois Tigeot }
4488621f407SFrançois Tigeot 
449*a85cb24fSFrançois Tigeot static void ibx_dump_hw_state(struct drm_i915_private *dev_priv,
450*a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
451*a85cb24fSFrançois Tigeot {
452*a85cb24fSFrançois Tigeot 	DRM_DEBUG_KMS("dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
453*a85cb24fSFrançois Tigeot 		      "fp0: 0x%x, fp1: 0x%x\n",
454*a85cb24fSFrançois Tigeot 		      hw_state->dpll,
455*a85cb24fSFrançois Tigeot 		      hw_state->dpll_md,
456*a85cb24fSFrançois Tigeot 		      hw_state->fp0,
457*a85cb24fSFrançois Tigeot 		      hw_state->fp1);
458*a85cb24fSFrançois Tigeot }
459*a85cb24fSFrançois Tigeot 
4608621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
461*a85cb24fSFrançois Tigeot 	.prepare = ibx_pch_dpll_prepare,
4628621f407SFrançois Tigeot 	.enable = ibx_pch_dpll_enable,
4638621f407SFrançois Tigeot 	.disable = ibx_pch_dpll_disable,
4648621f407SFrançois Tigeot 	.get_hw_state = ibx_pch_dpll_get_hw_state,
4658621f407SFrançois Tigeot };
4668621f407SFrançois Tigeot 
4678621f407SFrançois Tigeot static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
4688621f407SFrançois Tigeot 			       struct intel_shared_dpll *pll)
4698621f407SFrançois Tigeot {
470*a85cb24fSFrançois Tigeot 	I915_WRITE(WRPLL_CTL(pll->id), pll->state.hw_state.wrpll);
4718621f407SFrançois Tigeot 	POSTING_READ(WRPLL_CTL(pll->id));
4728621f407SFrançois Tigeot 	udelay(20);
4738621f407SFrançois Tigeot }
4748621f407SFrançois Tigeot 
4758621f407SFrançois Tigeot static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
4768621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
4778621f407SFrançois Tigeot {
478*a85cb24fSFrançois Tigeot 	I915_WRITE(SPLL_CTL, pll->state.hw_state.spll);
4798621f407SFrançois Tigeot 	POSTING_READ(SPLL_CTL);
4808621f407SFrançois Tigeot 	udelay(20);
4818621f407SFrançois Tigeot }
4828621f407SFrançois Tigeot 
4838621f407SFrançois Tigeot static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
4848621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
4858621f407SFrançois Tigeot {
4868621f407SFrançois Tigeot 	uint32_t val;
4878621f407SFrançois Tigeot 
4888621f407SFrançois Tigeot 	val = I915_READ(WRPLL_CTL(pll->id));
4898621f407SFrançois Tigeot 	I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
4908621f407SFrançois Tigeot 	POSTING_READ(WRPLL_CTL(pll->id));
4918621f407SFrançois Tigeot }
4928621f407SFrançois Tigeot 
4938621f407SFrançois Tigeot static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
4948621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
4958621f407SFrançois Tigeot {
4968621f407SFrançois Tigeot 	uint32_t val;
4978621f407SFrançois Tigeot 
4988621f407SFrançois Tigeot 	val = I915_READ(SPLL_CTL);
4998621f407SFrançois Tigeot 	I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
5008621f407SFrançois Tigeot 	POSTING_READ(SPLL_CTL);
5018621f407SFrançois Tigeot }
5028621f407SFrançois Tigeot 
5038621f407SFrançois Tigeot static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
5048621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
5058621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
5068621f407SFrançois Tigeot {
5078621f407SFrançois Tigeot 	uint32_t val;
5088621f407SFrançois Tigeot 
5098621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
5108621f407SFrançois Tigeot 		return false;
5118621f407SFrançois Tigeot 
5128621f407SFrançois Tigeot 	val = I915_READ(WRPLL_CTL(pll->id));
5138621f407SFrançois Tigeot 	hw_state->wrpll = val;
5148621f407SFrançois Tigeot 
5158621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
5168621f407SFrançois Tigeot 
5178621f407SFrançois Tigeot 	return val & WRPLL_PLL_ENABLE;
5188621f407SFrançois Tigeot }
5198621f407SFrançois Tigeot 
5208621f407SFrançois Tigeot static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
5218621f407SFrançois Tigeot 				      struct intel_shared_dpll *pll,
5228621f407SFrançois Tigeot 				      struct intel_dpll_hw_state *hw_state)
5238621f407SFrançois Tigeot {
5248621f407SFrançois Tigeot 	uint32_t val;
5258621f407SFrançois Tigeot 
5268621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
5278621f407SFrançois Tigeot 		return false;
5288621f407SFrançois Tigeot 
5298621f407SFrançois Tigeot 	val = I915_READ(SPLL_CTL);
5308621f407SFrançois Tigeot 	hw_state->spll = val;
5318621f407SFrançois Tigeot 
5328621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
5338621f407SFrançois Tigeot 
5348621f407SFrançois Tigeot 	return val & SPLL_PLL_ENABLE;
5358621f407SFrançois Tigeot }
5368621f407SFrançois Tigeot 
5378621f407SFrançois Tigeot #define LC_FREQ 2700
5388621f407SFrançois Tigeot #define LC_FREQ_2K U64_C(LC_FREQ * 2000)
5398621f407SFrançois Tigeot 
5408621f407SFrançois Tigeot #define P_MIN 2
5418621f407SFrançois Tigeot #define P_MAX 64
5428621f407SFrançois Tigeot #define P_INC 2
5438621f407SFrançois Tigeot 
5448621f407SFrançois Tigeot /* Constraints for PLL good behavior */
5458621f407SFrançois Tigeot #define REF_MIN 48
5468621f407SFrançois Tigeot #define REF_MAX 400
5478621f407SFrançois Tigeot #define VCO_MIN 2400
5488621f407SFrançois Tigeot #define VCO_MAX 4800
5498621f407SFrançois Tigeot 
5508621f407SFrançois Tigeot struct hsw_wrpll_rnp {
5518621f407SFrançois Tigeot 	unsigned p, n2, r2;
5528621f407SFrançois Tigeot };
5538621f407SFrançois Tigeot 
5548621f407SFrançois Tigeot static unsigned hsw_wrpll_get_budget_for_freq(int clock)
5558621f407SFrançois Tigeot {
5568621f407SFrançois Tigeot 	unsigned budget;
5578621f407SFrançois Tigeot 
5588621f407SFrançois Tigeot 	switch (clock) {
5598621f407SFrançois Tigeot 	case 25175000:
5608621f407SFrançois Tigeot 	case 25200000:
5618621f407SFrançois Tigeot 	case 27000000:
5628621f407SFrançois Tigeot 	case 27027000:
5638621f407SFrançois Tigeot 	case 37762500:
5648621f407SFrançois Tigeot 	case 37800000:
5658621f407SFrançois Tigeot 	case 40500000:
5668621f407SFrançois Tigeot 	case 40541000:
5678621f407SFrançois Tigeot 	case 54000000:
5688621f407SFrançois Tigeot 	case 54054000:
5698621f407SFrançois Tigeot 	case 59341000:
5708621f407SFrançois Tigeot 	case 59400000:
5718621f407SFrançois Tigeot 	case 72000000:
5728621f407SFrançois Tigeot 	case 74176000:
5738621f407SFrançois Tigeot 	case 74250000:
5748621f407SFrançois Tigeot 	case 81000000:
5758621f407SFrançois Tigeot 	case 81081000:
5768621f407SFrançois Tigeot 	case 89012000:
5778621f407SFrançois Tigeot 	case 89100000:
5788621f407SFrançois Tigeot 	case 108000000:
5798621f407SFrançois Tigeot 	case 108108000:
5808621f407SFrançois Tigeot 	case 111264000:
5818621f407SFrançois Tigeot 	case 111375000:
5828621f407SFrançois Tigeot 	case 148352000:
5838621f407SFrançois Tigeot 	case 148500000:
5848621f407SFrançois Tigeot 	case 162000000:
5858621f407SFrançois Tigeot 	case 162162000:
5868621f407SFrançois Tigeot 	case 222525000:
5878621f407SFrançois Tigeot 	case 222750000:
5888621f407SFrançois Tigeot 	case 296703000:
5898621f407SFrançois Tigeot 	case 297000000:
5908621f407SFrançois Tigeot 		budget = 0;
5918621f407SFrançois Tigeot 		break;
5928621f407SFrançois Tigeot 	case 233500000:
5938621f407SFrançois Tigeot 	case 245250000:
5948621f407SFrançois Tigeot 	case 247750000:
5958621f407SFrançois Tigeot 	case 253250000:
5968621f407SFrançois Tigeot 	case 298000000:
5978621f407SFrançois Tigeot 		budget = 1500;
5988621f407SFrançois Tigeot 		break;
5998621f407SFrançois Tigeot 	case 169128000:
6008621f407SFrançois Tigeot 	case 169500000:
6018621f407SFrançois Tigeot 	case 179500000:
6028621f407SFrançois Tigeot 	case 202000000:
6038621f407SFrançois Tigeot 		budget = 2000;
6048621f407SFrançois Tigeot 		break;
6058621f407SFrançois Tigeot 	case 256250000:
6068621f407SFrançois Tigeot 	case 262500000:
6078621f407SFrançois Tigeot 	case 270000000:
6088621f407SFrançois Tigeot 	case 272500000:
6098621f407SFrançois Tigeot 	case 273750000:
6108621f407SFrançois Tigeot 	case 280750000:
6118621f407SFrançois Tigeot 	case 281250000:
6128621f407SFrançois Tigeot 	case 286000000:
6138621f407SFrançois Tigeot 	case 291750000:
6148621f407SFrançois Tigeot 		budget = 4000;
6158621f407SFrançois Tigeot 		break;
6168621f407SFrançois Tigeot 	case 267250000:
6178621f407SFrançois Tigeot 	case 268500000:
6188621f407SFrançois Tigeot 		budget = 5000;
6198621f407SFrançois Tigeot 		break;
6208621f407SFrançois Tigeot 	default:
6218621f407SFrançois Tigeot 		budget = 1000;
6228621f407SFrançois Tigeot 		break;
6238621f407SFrançois Tigeot 	}
6248621f407SFrançois Tigeot 
6258621f407SFrançois Tigeot 	return budget;
6268621f407SFrançois Tigeot }
6278621f407SFrançois Tigeot 
6288621f407SFrançois Tigeot static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget,
6298621f407SFrançois Tigeot 				 unsigned r2, unsigned n2, unsigned p,
6308621f407SFrançois Tigeot 				 struct hsw_wrpll_rnp *best)
6318621f407SFrançois Tigeot {
6328621f407SFrançois Tigeot 	uint64_t a, b, c, d, diff, diff_best;
6338621f407SFrançois Tigeot 
6348621f407SFrançois Tigeot 	/* No best (r,n,p) yet */
6358621f407SFrançois Tigeot 	if (best->p == 0) {
6368621f407SFrançois Tigeot 		best->p = p;
6378621f407SFrançois Tigeot 		best->n2 = n2;
6388621f407SFrançois Tigeot 		best->r2 = r2;
6398621f407SFrançois Tigeot 		return;
6408621f407SFrançois Tigeot 	}
6418621f407SFrançois Tigeot 
6428621f407SFrançois Tigeot 	/*
6438621f407SFrançois Tigeot 	 * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
6448621f407SFrançois Tigeot 	 * freq2k.
6458621f407SFrançois Tigeot 	 *
6468621f407SFrançois Tigeot 	 * delta = 1e6 *
6478621f407SFrançois Tigeot 	 *	   abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
6488621f407SFrançois Tigeot 	 *	   freq2k;
6498621f407SFrançois Tigeot 	 *
6508621f407SFrançois Tigeot 	 * and we would like delta <= budget.
6518621f407SFrançois Tigeot 	 *
6528621f407SFrançois Tigeot 	 * If the discrepancy is above the PPM-based budget, always prefer to
6538621f407SFrançois Tigeot 	 * improve upon the previous solution.  However, if you're within the
6548621f407SFrançois Tigeot 	 * budget, try to maximize Ref * VCO, that is N / (P * R^2).
6558621f407SFrançois Tigeot 	 */
6568621f407SFrançois Tigeot 	a = freq2k * budget * p * r2;
6578621f407SFrançois Tigeot 	b = freq2k * budget * best->p * best->r2;
6588621f407SFrançois Tigeot 	diff = abs_diff((u64)freq2k * p * r2, LC_FREQ_2K * n2);
6598621f407SFrançois Tigeot 	diff_best = abs_diff((u64)freq2k * best->p * best->r2,
6608621f407SFrançois Tigeot 			     LC_FREQ_2K * best->n2);
6618621f407SFrançois Tigeot 	c = 1000000 * diff;
6628621f407SFrançois Tigeot 	d = 1000000 * diff_best;
6638621f407SFrançois Tigeot 
6648621f407SFrançois Tigeot 	if (a < c && b < d) {
6658621f407SFrançois Tigeot 		/* If both are above the budget, pick the closer */
6668621f407SFrançois Tigeot 		if (best->p * best->r2 * diff < p * r2 * diff_best) {
6678621f407SFrançois Tigeot 			best->p = p;
6688621f407SFrançois Tigeot 			best->n2 = n2;
6698621f407SFrançois Tigeot 			best->r2 = r2;
6708621f407SFrançois Tigeot 		}
6718621f407SFrançois Tigeot 	} else if (a >= c && b < d) {
6728621f407SFrançois Tigeot 		/* If A is below the threshold but B is above it?  Update. */
6738621f407SFrançois Tigeot 		best->p = p;
6748621f407SFrançois Tigeot 		best->n2 = n2;
6758621f407SFrançois Tigeot 		best->r2 = r2;
6768621f407SFrançois Tigeot 	} else if (a >= c && b >= d) {
6778621f407SFrançois Tigeot 		/* Both are below the limit, so pick the higher n2/(r2*r2) */
6788621f407SFrançois Tigeot 		if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) {
6798621f407SFrançois Tigeot 			best->p = p;
6808621f407SFrançois Tigeot 			best->n2 = n2;
6818621f407SFrançois Tigeot 			best->r2 = r2;
6828621f407SFrançois Tigeot 		}
6838621f407SFrançois Tigeot 	}
6848621f407SFrançois Tigeot 	/* Otherwise a < c && b >= d, do nothing */
6858621f407SFrançois Tigeot }
6868621f407SFrançois Tigeot 
6878621f407SFrançois Tigeot static void
6888621f407SFrançois Tigeot hsw_ddi_calculate_wrpll(int clock /* in Hz */,
6898621f407SFrançois Tigeot 			unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
6908621f407SFrançois Tigeot {
6918621f407SFrançois Tigeot 	uint64_t freq2k;
6928621f407SFrançois Tigeot 	unsigned p, n2, r2;
6938621f407SFrançois Tigeot 	struct hsw_wrpll_rnp best = { 0, 0, 0 };
6948621f407SFrançois Tigeot 	unsigned budget;
6958621f407SFrançois Tigeot 
6968621f407SFrançois Tigeot 	freq2k = clock / 100;
6978621f407SFrançois Tigeot 
6988621f407SFrançois Tigeot 	budget = hsw_wrpll_get_budget_for_freq(clock);
6998621f407SFrançois Tigeot 
7008621f407SFrançois Tigeot 	/* Special case handling for 540 pixel clock: bypass WR PLL entirely
7018621f407SFrançois Tigeot 	 * and directly pass the LC PLL to it. */
7028621f407SFrançois Tigeot 	if (freq2k == 5400000) {
7038621f407SFrançois Tigeot 		*n2_out = 2;
7048621f407SFrançois Tigeot 		*p_out = 1;
7058621f407SFrançois Tigeot 		*r2_out = 2;
7068621f407SFrançois Tigeot 		return;
7078621f407SFrançois Tigeot 	}
7088621f407SFrançois Tigeot 
7098621f407SFrançois Tigeot 	/*
7108621f407SFrançois Tigeot 	 * Ref = LC_FREQ / R, where Ref is the actual reference input seen by
7118621f407SFrançois Tigeot 	 * the WR PLL.
7128621f407SFrançois Tigeot 	 *
7138621f407SFrançois Tigeot 	 * We want R so that REF_MIN <= Ref <= REF_MAX.
7148621f407SFrançois Tigeot 	 * Injecting R2 = 2 * R gives:
7158621f407SFrançois Tigeot 	 *   REF_MAX * r2 > LC_FREQ * 2 and
7168621f407SFrançois Tigeot 	 *   REF_MIN * r2 < LC_FREQ * 2
7178621f407SFrançois Tigeot 	 *
7188621f407SFrançois Tigeot 	 * Which means the desired boundaries for r2 are:
7198621f407SFrançois Tigeot 	 *  LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
7208621f407SFrançois Tigeot 	 *
7218621f407SFrançois Tigeot 	 */
7228621f407SFrançois Tigeot 	for (r2 = LC_FREQ * 2 / REF_MAX + 1;
7238621f407SFrançois Tigeot 	     r2 <= LC_FREQ * 2 / REF_MIN;
7248621f407SFrançois Tigeot 	     r2++) {
7258621f407SFrançois Tigeot 
7268621f407SFrançois Tigeot 		/*
7278621f407SFrançois Tigeot 		 * VCO = N * Ref, that is: VCO = N * LC_FREQ / R
7288621f407SFrançois Tigeot 		 *
7298621f407SFrançois Tigeot 		 * Once again we want VCO_MIN <= VCO <= VCO_MAX.
7308621f407SFrançois Tigeot 		 * Injecting R2 = 2 * R and N2 = 2 * N, we get:
7318621f407SFrançois Tigeot 		 *   VCO_MAX * r2 > n2 * LC_FREQ and
7328621f407SFrançois Tigeot 		 *   VCO_MIN * r2 < n2 * LC_FREQ)
7338621f407SFrançois Tigeot 		 *
7348621f407SFrançois Tigeot 		 * Which means the desired boundaries for n2 are:
7358621f407SFrançois Tigeot 		 * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
7368621f407SFrançois Tigeot 		 */
7378621f407SFrançois Tigeot 		for (n2 = VCO_MIN * r2 / LC_FREQ + 1;
7388621f407SFrançois Tigeot 		     n2 <= VCO_MAX * r2 / LC_FREQ;
7398621f407SFrançois Tigeot 		     n2++) {
7408621f407SFrançois Tigeot 
7418621f407SFrançois Tigeot 			for (p = P_MIN; p <= P_MAX; p += P_INC)
7428621f407SFrançois Tigeot 				hsw_wrpll_update_rnp(freq2k, budget,
7438621f407SFrançois Tigeot 						     r2, n2, p, &best);
7448621f407SFrançois Tigeot 		}
7458621f407SFrançois Tigeot 	}
7468621f407SFrançois Tigeot 
7478621f407SFrançois Tigeot 	*n2_out = best.n2;
7488621f407SFrançois Tigeot 	*p_out = best.p;
7498621f407SFrançois Tigeot 	*r2_out = best.r2;
7508621f407SFrançois Tigeot }
7518621f407SFrançois Tigeot 
7521e12ee3bSFrançois Tigeot static struct intel_shared_dpll *hsw_ddi_hdmi_get_dpll(int clock,
7531e12ee3bSFrançois Tigeot 						       struct intel_crtc *crtc,
7541e12ee3bSFrançois Tigeot 						       struct intel_crtc_state *crtc_state)
7558621f407SFrançois Tigeot {
7568621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
7578621f407SFrançois Tigeot 	uint32_t val;
7581e12ee3bSFrançois Tigeot 	unsigned int p, n2, r2;
7598621f407SFrançois Tigeot 
7608621f407SFrançois Tigeot 	hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
7618621f407SFrançois Tigeot 
7628621f407SFrançois Tigeot 	val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
7638621f407SFrançois Tigeot 	      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
7648621f407SFrançois Tigeot 	      WRPLL_DIVIDER_POST(p);
7658621f407SFrançois Tigeot 
7668621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.wrpll = val;
7678621f407SFrançois Tigeot 
7688621f407SFrançois Tigeot 	pll = intel_find_shared_dpll(crtc, crtc_state,
7698621f407SFrançois Tigeot 				     DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
7708621f407SFrançois Tigeot 
7711e12ee3bSFrançois Tigeot 	if (!pll)
7721e12ee3bSFrançois Tigeot 		return NULL;
7731e12ee3bSFrançois Tigeot 
7741e12ee3bSFrançois Tigeot 	return pll;
7751e12ee3bSFrançois Tigeot }
7761e12ee3bSFrançois Tigeot 
777*a85cb24fSFrançois Tigeot static struct intel_shared_dpll *
778*a85cb24fSFrançois Tigeot hsw_ddi_dp_get_dpll(struct intel_encoder *encoder, int clock)
7791e12ee3bSFrançois Tigeot {
7801e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
7811e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
7828621f407SFrançois Tigeot 	enum intel_dpll_id pll_id;
7838621f407SFrançois Tigeot 
7848621f407SFrançois Tigeot 	switch (clock / 2) {
7858621f407SFrançois Tigeot 	case 81000:
7868621f407SFrançois Tigeot 		pll_id = DPLL_ID_LCPLL_810;
7878621f407SFrançois Tigeot 		break;
7888621f407SFrançois Tigeot 	case 135000:
7898621f407SFrançois Tigeot 		pll_id = DPLL_ID_LCPLL_1350;
7908621f407SFrançois Tigeot 		break;
7918621f407SFrançois Tigeot 	case 270000:
7928621f407SFrançois Tigeot 		pll_id = DPLL_ID_LCPLL_2700;
7938621f407SFrançois Tigeot 		break;
7948621f407SFrançois Tigeot 	default:
7958621f407SFrançois Tigeot 		DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
7968621f407SFrançois Tigeot 		return NULL;
7978621f407SFrançois Tigeot 	}
7988621f407SFrançois Tigeot 
7998621f407SFrançois Tigeot 	pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
8008621f407SFrançois Tigeot 
8011e12ee3bSFrançois Tigeot 	if (!pll)
8021e12ee3bSFrançois Tigeot 		return NULL;
8031e12ee3bSFrançois Tigeot 
8041e12ee3bSFrançois Tigeot 	return pll;
8051e12ee3bSFrançois Tigeot }
8061e12ee3bSFrançois Tigeot 
8071e12ee3bSFrançois Tigeot static struct intel_shared_dpll *
8081e12ee3bSFrançois Tigeot hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
8091e12ee3bSFrançois Tigeot 	     struct intel_encoder *encoder)
8101e12ee3bSFrançois Tigeot {
8111e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
8121e12ee3bSFrançois Tigeot 	int clock = crtc_state->port_clock;
8131e12ee3bSFrançois Tigeot 
8141e12ee3bSFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
8151e12ee3bSFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
8161e12ee3bSFrançois Tigeot 
8171e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI) {
8181e12ee3bSFrançois Tigeot 		pll = hsw_ddi_hdmi_get_dpll(clock, crtc, crtc_state);
8191e12ee3bSFrançois Tigeot 
8201e12ee3bSFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_DP ||
8211e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_DP_MST ||
8221e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_EDP) {
8231e12ee3bSFrançois Tigeot 		pll = hsw_ddi_dp_get_dpll(encoder, clock);
8241e12ee3bSFrançois Tigeot 
8258621f407SFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_ANALOG) {
8268621f407SFrançois Tigeot 		if (WARN_ON(crtc_state->port_clock / 2 != 135000))
8278621f407SFrançois Tigeot 			return NULL;
8288621f407SFrançois Tigeot 
8298621f407SFrançois Tigeot 		crtc_state->dpll_hw_state.spll =
8308621f407SFrançois Tigeot 			SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
8318621f407SFrançois Tigeot 
8328621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
8338621f407SFrançois Tigeot 					     DPLL_ID_SPLL, DPLL_ID_SPLL);
8348621f407SFrançois Tigeot 	} else {
8358621f407SFrançois Tigeot 		return NULL;
8368621f407SFrançois Tigeot 	}
8378621f407SFrançois Tigeot 
8388621f407SFrançois Tigeot 	if (!pll)
8398621f407SFrançois Tigeot 		return NULL;
8408621f407SFrançois Tigeot 
8418621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
8428621f407SFrançois Tigeot 
8438621f407SFrançois Tigeot 	return pll;
8448621f407SFrançois Tigeot }
8458621f407SFrançois Tigeot 
846*a85cb24fSFrançois Tigeot static void hsw_dump_hw_state(struct drm_i915_private *dev_priv,
847*a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
848*a85cb24fSFrançois Tigeot {
849*a85cb24fSFrançois Tigeot 	DRM_DEBUG_KMS("dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
850*a85cb24fSFrançois Tigeot 		      hw_state->wrpll, hw_state->spll);
851*a85cb24fSFrançois Tigeot }
852*a85cb24fSFrançois Tigeot 
8538621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
8548621f407SFrançois Tigeot 	.enable = hsw_ddi_wrpll_enable,
8558621f407SFrançois Tigeot 	.disable = hsw_ddi_wrpll_disable,
8568621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_wrpll_get_hw_state,
8578621f407SFrançois Tigeot };
8588621f407SFrançois Tigeot 
8598621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_spll_funcs = {
8608621f407SFrançois Tigeot 	.enable = hsw_ddi_spll_enable,
8618621f407SFrançois Tigeot 	.disable = hsw_ddi_spll_disable,
8628621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_spll_get_hw_state,
8638621f407SFrançois Tigeot };
8648621f407SFrançois Tigeot 
8658621f407SFrançois Tigeot static void hsw_ddi_lcpll_enable(struct drm_i915_private *dev_priv,
8668621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
8678621f407SFrançois Tigeot {
8688621f407SFrançois Tigeot }
8698621f407SFrançois Tigeot 
8708621f407SFrançois Tigeot static void hsw_ddi_lcpll_disable(struct drm_i915_private *dev_priv,
8718621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
8728621f407SFrançois Tigeot {
8738621f407SFrançois Tigeot }
8748621f407SFrançois Tigeot 
8758621f407SFrançois Tigeot static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,
8768621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
8778621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
8788621f407SFrançois Tigeot {
8798621f407SFrançois Tigeot 	return true;
8808621f407SFrançois Tigeot }
8818621f407SFrançois Tigeot 
8828621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = {
8838621f407SFrançois Tigeot 	.enable = hsw_ddi_lcpll_enable,
8848621f407SFrançois Tigeot 	.disable = hsw_ddi_lcpll_disable,
8858621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_lcpll_get_hw_state,
8868621f407SFrançois Tigeot };
8878621f407SFrançois Tigeot 
8888621f407SFrançois Tigeot struct skl_dpll_regs {
8898621f407SFrançois Tigeot 	i915_reg_t ctl, cfgcr1, cfgcr2;
8908621f407SFrançois Tigeot };
8918621f407SFrançois Tigeot 
8928621f407SFrançois Tigeot /* this array is indexed by the *shared* pll id */
8938621f407SFrançois Tigeot static const struct skl_dpll_regs skl_dpll_regs[4] = {
8948621f407SFrançois Tigeot 	{
8958621f407SFrançois Tigeot 		/* DPLL 0 */
8968621f407SFrançois Tigeot 		.ctl = LCPLL1_CTL,
8978621f407SFrançois Tigeot 		/* DPLL 0 doesn't support HDMI mode */
8988621f407SFrançois Tigeot 	},
8998621f407SFrançois Tigeot 	{
9008621f407SFrançois Tigeot 		/* DPLL 1 */
9018621f407SFrançois Tigeot 		.ctl = LCPLL2_CTL,
9028621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
9038621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
9048621f407SFrançois Tigeot 	},
9058621f407SFrançois Tigeot 	{
9068621f407SFrançois Tigeot 		/* DPLL 2 */
9078621f407SFrançois Tigeot 		.ctl = WRPLL_CTL(0),
9088621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
9098621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
9108621f407SFrançois Tigeot 	},
9118621f407SFrançois Tigeot 	{
9128621f407SFrançois Tigeot 		/* DPLL 3 */
9138621f407SFrançois Tigeot 		.ctl = WRPLL_CTL(1),
9148621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
9158621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
9168621f407SFrançois Tigeot 	},
9178621f407SFrançois Tigeot };
9188621f407SFrançois Tigeot 
9198621f407SFrançois Tigeot static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *dev_priv,
9208621f407SFrançois Tigeot 				    struct intel_shared_dpll *pll)
9218621f407SFrançois Tigeot {
9228621f407SFrançois Tigeot 	uint32_t val;
9238621f407SFrançois Tigeot 
9248621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
9258621f407SFrançois Tigeot 
9268621f407SFrançois Tigeot 	val &= ~(DPLL_CTRL1_HDMI_MODE(pll->id) | DPLL_CTRL1_SSC(pll->id) |
9278621f407SFrançois Tigeot 		 DPLL_CTRL1_LINK_RATE_MASK(pll->id));
928*a85cb24fSFrançois Tigeot 	val |= pll->state.hw_state.ctrl1 << (pll->id * 6);
9298621f407SFrançois Tigeot 
9308621f407SFrançois Tigeot 	I915_WRITE(DPLL_CTRL1, val);
9318621f407SFrançois Tigeot 	POSTING_READ(DPLL_CTRL1);
9328621f407SFrançois Tigeot }
9338621f407SFrançois Tigeot 
9348621f407SFrançois Tigeot static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
9358621f407SFrançois Tigeot 			       struct intel_shared_dpll *pll)
9368621f407SFrançois Tigeot {
9378621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
9388621f407SFrançois Tigeot 
9398621f407SFrançois Tigeot 	skl_ddi_pll_write_ctrl1(dev_priv, pll);
9408621f407SFrançois Tigeot 
941*a85cb24fSFrançois Tigeot 	I915_WRITE(regs[pll->id].cfgcr1, pll->state.hw_state.cfgcr1);
942*a85cb24fSFrançois Tigeot 	I915_WRITE(regs[pll->id].cfgcr2, pll->state.hw_state.cfgcr2);
9438621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].cfgcr1);
9448621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].cfgcr2);
9458621f407SFrançois Tigeot 
9468621f407SFrançois Tigeot 	/* the enable bit is always bit 31 */
9478621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].ctl,
9488621f407SFrançois Tigeot 		   I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE);
9498621f407SFrançois Tigeot 
9501487f786SFrançois Tigeot 	if (intel_wait_for_register(dev_priv,
9511487f786SFrançois Tigeot 				    DPLL_STATUS,
9521487f786SFrançois Tigeot 				    DPLL_LOCK(pll->id),
9531487f786SFrançois Tigeot 				    DPLL_LOCK(pll->id),
9541487f786SFrançois Tigeot 				    5))
9558621f407SFrançois Tigeot 		DRM_ERROR("DPLL %d not locked\n", pll->id);
9568621f407SFrançois Tigeot }
9578621f407SFrançois Tigeot 
9588621f407SFrançois Tigeot static void skl_ddi_dpll0_enable(struct drm_i915_private *dev_priv,
9598621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
9608621f407SFrançois Tigeot {
9618621f407SFrançois Tigeot 	skl_ddi_pll_write_ctrl1(dev_priv, pll);
9628621f407SFrançois Tigeot }
9638621f407SFrançois Tigeot 
9648621f407SFrançois Tigeot static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
9658621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
9668621f407SFrançois Tigeot {
9678621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
9688621f407SFrançois Tigeot 
9698621f407SFrançois Tigeot 	/* the enable bit is always bit 31 */
9708621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].ctl,
9718621f407SFrançois Tigeot 		   I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE);
9728621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].ctl);
9738621f407SFrançois Tigeot }
9748621f407SFrançois Tigeot 
9758621f407SFrançois Tigeot static void skl_ddi_dpll0_disable(struct drm_i915_private *dev_priv,
9768621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
9778621f407SFrançois Tigeot {
9788621f407SFrançois Tigeot }
9798621f407SFrançois Tigeot 
9808621f407SFrançois Tigeot static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
9818621f407SFrançois Tigeot 				     struct intel_shared_dpll *pll,
9828621f407SFrançois Tigeot 				     struct intel_dpll_hw_state *hw_state)
9838621f407SFrançois Tigeot {
9848621f407SFrançois Tigeot 	uint32_t val;
9858621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
9868621f407SFrançois Tigeot 	bool ret;
9878621f407SFrançois Tigeot 
9888621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
9898621f407SFrançois Tigeot 		return false;
9908621f407SFrançois Tigeot 
9918621f407SFrançois Tigeot 	ret = false;
9928621f407SFrançois Tigeot 
9938621f407SFrançois Tigeot 	val = I915_READ(regs[pll->id].ctl);
9948621f407SFrançois Tigeot 	if (!(val & LCPLL_PLL_ENABLE))
9958621f407SFrançois Tigeot 		goto out;
9968621f407SFrançois Tigeot 
9978621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
9988621f407SFrançois Tigeot 	hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
9998621f407SFrançois Tigeot 
10008621f407SFrançois Tigeot 	/* avoid reading back stale values if HDMI mode is not enabled */
10018621f407SFrançois Tigeot 	if (val & DPLL_CTRL1_HDMI_MODE(pll->id)) {
10028621f407SFrançois Tigeot 		hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
10038621f407SFrançois Tigeot 		hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
10048621f407SFrançois Tigeot 	}
10058621f407SFrançois Tigeot 	ret = true;
10068621f407SFrançois Tigeot 
10078621f407SFrançois Tigeot out:
10088621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
10098621f407SFrançois Tigeot 
10108621f407SFrançois Tigeot 	return ret;
10118621f407SFrançois Tigeot }
10128621f407SFrançois Tigeot 
10138621f407SFrançois Tigeot static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
10148621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
10158621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
10168621f407SFrançois Tigeot {
10178621f407SFrançois Tigeot 	uint32_t val;
10188621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
10198621f407SFrançois Tigeot 	bool ret;
10208621f407SFrançois Tigeot 
10218621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
10228621f407SFrançois Tigeot 		return false;
10238621f407SFrançois Tigeot 
10248621f407SFrançois Tigeot 	ret = false;
10258621f407SFrançois Tigeot 
10268621f407SFrançois Tigeot 	/* DPLL0 is always enabled since it drives CDCLK */
10278621f407SFrançois Tigeot 	val = I915_READ(regs[pll->id].ctl);
10288621f407SFrançois Tigeot 	if (WARN_ON(!(val & LCPLL_PLL_ENABLE)))
10298621f407SFrançois Tigeot 		goto out;
10308621f407SFrançois Tigeot 
10318621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
10328621f407SFrançois Tigeot 	hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
10338621f407SFrançois Tigeot 
10348621f407SFrançois Tigeot 	ret = true;
10358621f407SFrançois Tigeot 
10368621f407SFrançois Tigeot out:
10378621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
10388621f407SFrançois Tigeot 
10398621f407SFrançois Tigeot 	return ret;
10408621f407SFrançois Tigeot }
10418621f407SFrançois Tigeot 
10428621f407SFrançois Tigeot struct skl_wrpll_context {
10438621f407SFrançois Tigeot 	uint64_t min_deviation;		/* current minimal deviation */
10448621f407SFrançois Tigeot 	uint64_t central_freq;		/* chosen central freq */
10458621f407SFrançois Tigeot 	uint64_t dco_freq;		/* chosen dco freq */
10468621f407SFrançois Tigeot 	unsigned int p;			/* chosen divider */
10478621f407SFrançois Tigeot };
10488621f407SFrançois Tigeot 
10498621f407SFrançois Tigeot static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
10508621f407SFrançois Tigeot {
10518621f407SFrançois Tigeot 	memset(ctx, 0, sizeof(*ctx));
10528621f407SFrançois Tigeot 
10538621f407SFrançois Tigeot 	ctx->min_deviation = U64_MAX;
10548621f407SFrançois Tigeot }
10558621f407SFrançois Tigeot 
10568621f407SFrançois Tigeot /* DCO freq must be within +1%/-6%  of the DCO central freq */
10578621f407SFrançois Tigeot #define SKL_DCO_MAX_PDEVIATION	100
10588621f407SFrançois Tigeot #define SKL_DCO_MAX_NDEVIATION	600
10598621f407SFrançois Tigeot 
10608621f407SFrançois Tigeot static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
10618621f407SFrançois Tigeot 				  uint64_t central_freq,
10628621f407SFrançois Tigeot 				  uint64_t dco_freq,
10638621f407SFrançois Tigeot 				  unsigned int divider)
10648621f407SFrançois Tigeot {
10658621f407SFrançois Tigeot 	uint64_t deviation;
10668621f407SFrançois Tigeot 
10678621f407SFrançois Tigeot 	deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
10688621f407SFrançois Tigeot 			      central_freq);
10698621f407SFrançois Tigeot 
10708621f407SFrançois Tigeot 	/* positive deviation */
10718621f407SFrançois Tigeot 	if (dco_freq >= central_freq) {
10728621f407SFrançois Tigeot 		if (deviation < SKL_DCO_MAX_PDEVIATION &&
10738621f407SFrançois Tigeot 		    deviation < ctx->min_deviation) {
10748621f407SFrançois Tigeot 			ctx->min_deviation = deviation;
10758621f407SFrançois Tigeot 			ctx->central_freq = central_freq;
10768621f407SFrançois Tigeot 			ctx->dco_freq = dco_freq;
10778621f407SFrançois Tigeot 			ctx->p = divider;
10788621f407SFrançois Tigeot 		}
10798621f407SFrançois Tigeot 	/* negative deviation */
10808621f407SFrançois Tigeot 	} else if (deviation < SKL_DCO_MAX_NDEVIATION &&
10818621f407SFrançois Tigeot 		   deviation < ctx->min_deviation) {
10828621f407SFrançois Tigeot 		ctx->min_deviation = deviation;
10838621f407SFrançois Tigeot 		ctx->central_freq = central_freq;
10848621f407SFrançois Tigeot 		ctx->dco_freq = dco_freq;
10858621f407SFrançois Tigeot 		ctx->p = divider;
10868621f407SFrançois Tigeot 	}
10878621f407SFrançois Tigeot }
10888621f407SFrançois Tigeot 
10898621f407SFrançois Tigeot static void skl_wrpll_get_multipliers(unsigned int p,
10908621f407SFrançois Tigeot 				      unsigned int *p0 /* out */,
10918621f407SFrançois Tigeot 				      unsigned int *p1 /* out */,
10928621f407SFrançois Tigeot 				      unsigned int *p2 /* out */)
10938621f407SFrançois Tigeot {
10948621f407SFrançois Tigeot 	/* even dividers */
10958621f407SFrançois Tigeot 	if (p % 2 == 0) {
10968621f407SFrançois Tigeot 		unsigned int half = p / 2;
10978621f407SFrançois Tigeot 
10988621f407SFrançois Tigeot 		if (half == 1 || half == 2 || half == 3 || half == 5) {
10998621f407SFrançois Tigeot 			*p0 = 2;
11008621f407SFrançois Tigeot 			*p1 = 1;
11018621f407SFrançois Tigeot 			*p2 = half;
11028621f407SFrançois Tigeot 		} else if (half % 2 == 0) {
11038621f407SFrançois Tigeot 			*p0 = 2;
11048621f407SFrançois Tigeot 			*p1 = half / 2;
11058621f407SFrançois Tigeot 			*p2 = 2;
11068621f407SFrançois Tigeot 		} else if (half % 3 == 0) {
11078621f407SFrançois Tigeot 			*p0 = 3;
11088621f407SFrançois Tigeot 			*p1 = half / 3;
11098621f407SFrançois Tigeot 			*p2 = 2;
11108621f407SFrançois Tigeot 		} else if (half % 7 == 0) {
11118621f407SFrançois Tigeot 			*p0 = 7;
11128621f407SFrançois Tigeot 			*p1 = half / 7;
11138621f407SFrançois Tigeot 			*p2 = 2;
11148621f407SFrançois Tigeot 		}
11158621f407SFrançois Tigeot 	} else if (p == 3 || p == 9) {  /* 3, 5, 7, 9, 15, 21, 35 */
11168621f407SFrançois Tigeot 		*p0 = 3;
11178621f407SFrançois Tigeot 		*p1 = 1;
11188621f407SFrançois Tigeot 		*p2 = p / 3;
11198621f407SFrançois Tigeot 	} else if (p == 5 || p == 7) {
11208621f407SFrançois Tigeot 		*p0 = p;
11218621f407SFrançois Tigeot 		*p1 = 1;
11228621f407SFrançois Tigeot 		*p2 = 1;
11238621f407SFrançois Tigeot 	} else if (p == 15) {
11248621f407SFrançois Tigeot 		*p0 = 3;
11258621f407SFrançois Tigeot 		*p1 = 1;
11268621f407SFrançois Tigeot 		*p2 = 5;
11278621f407SFrançois Tigeot 	} else if (p == 21) {
11288621f407SFrançois Tigeot 		*p0 = 7;
11298621f407SFrançois Tigeot 		*p1 = 1;
11308621f407SFrançois Tigeot 		*p2 = 3;
11318621f407SFrançois Tigeot 	} else if (p == 35) {
11328621f407SFrançois Tigeot 		*p0 = 7;
11338621f407SFrançois Tigeot 		*p1 = 1;
11348621f407SFrançois Tigeot 		*p2 = 5;
11358621f407SFrançois Tigeot 	}
11368621f407SFrançois Tigeot }
11378621f407SFrançois Tigeot 
11388621f407SFrançois Tigeot struct skl_wrpll_params {
11398621f407SFrançois Tigeot 	uint32_t        dco_fraction;
11408621f407SFrançois Tigeot 	uint32_t        dco_integer;
11418621f407SFrançois Tigeot 	uint32_t        qdiv_ratio;
11428621f407SFrançois Tigeot 	uint32_t        qdiv_mode;
11438621f407SFrançois Tigeot 	uint32_t        kdiv;
11448621f407SFrançois Tigeot 	uint32_t        pdiv;
11458621f407SFrançois Tigeot 	uint32_t        central_freq;
11468621f407SFrançois Tigeot };
11478621f407SFrançois Tigeot 
11488621f407SFrançois Tigeot static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
11498621f407SFrançois Tigeot 				      uint64_t afe_clock,
11508621f407SFrançois Tigeot 				      uint64_t central_freq,
11518621f407SFrançois Tigeot 				      uint32_t p0, uint32_t p1, uint32_t p2)
11528621f407SFrançois Tigeot {
11538621f407SFrançois Tigeot 	uint64_t dco_freq;
11548621f407SFrançois Tigeot 
11558621f407SFrançois Tigeot 	switch (central_freq) {
11568621f407SFrançois Tigeot 	case 9600000000ULL:
11578621f407SFrançois Tigeot 		params->central_freq = 0;
11588621f407SFrançois Tigeot 		break;
11598621f407SFrançois Tigeot 	case 9000000000ULL:
11608621f407SFrançois Tigeot 		params->central_freq = 1;
11618621f407SFrançois Tigeot 		break;
11628621f407SFrançois Tigeot 	case 8400000000ULL:
11638621f407SFrançois Tigeot 		params->central_freq = 3;
11648621f407SFrançois Tigeot 	}
11658621f407SFrançois Tigeot 
11668621f407SFrançois Tigeot 	switch (p0) {
11678621f407SFrançois Tigeot 	case 1:
11688621f407SFrançois Tigeot 		params->pdiv = 0;
11698621f407SFrançois Tigeot 		break;
11708621f407SFrançois Tigeot 	case 2:
11718621f407SFrançois Tigeot 		params->pdiv = 1;
11728621f407SFrançois Tigeot 		break;
11738621f407SFrançois Tigeot 	case 3:
11748621f407SFrançois Tigeot 		params->pdiv = 2;
11758621f407SFrançois Tigeot 		break;
11768621f407SFrançois Tigeot 	case 7:
11778621f407SFrançois Tigeot 		params->pdiv = 4;
11788621f407SFrançois Tigeot 		break;
11798621f407SFrançois Tigeot 	default:
11808621f407SFrançois Tigeot 		WARN(1, "Incorrect PDiv\n");
11818621f407SFrançois Tigeot 	}
11828621f407SFrançois Tigeot 
11838621f407SFrançois Tigeot 	switch (p2) {
11848621f407SFrançois Tigeot 	case 5:
11858621f407SFrançois Tigeot 		params->kdiv = 0;
11868621f407SFrançois Tigeot 		break;
11878621f407SFrançois Tigeot 	case 2:
11888621f407SFrançois Tigeot 		params->kdiv = 1;
11898621f407SFrançois Tigeot 		break;
11908621f407SFrançois Tigeot 	case 3:
11918621f407SFrançois Tigeot 		params->kdiv = 2;
11928621f407SFrançois Tigeot 		break;
11938621f407SFrançois Tigeot 	case 1:
11948621f407SFrançois Tigeot 		params->kdiv = 3;
11958621f407SFrançois Tigeot 		break;
11968621f407SFrançois Tigeot 	default:
11978621f407SFrançois Tigeot 		WARN(1, "Incorrect KDiv\n");
11988621f407SFrançois Tigeot 	}
11998621f407SFrançois Tigeot 
12008621f407SFrançois Tigeot 	params->qdiv_ratio = p1;
12018621f407SFrançois Tigeot 	params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
12028621f407SFrançois Tigeot 
12038621f407SFrançois Tigeot 	dco_freq = p0 * p1 * p2 * afe_clock;
12048621f407SFrançois Tigeot 
12058621f407SFrançois Tigeot 	/*
12068621f407SFrançois Tigeot 	 * Intermediate values are in Hz.
12078621f407SFrançois Tigeot 	 * Divide by MHz to match bsepc
12088621f407SFrançois Tigeot 	 */
12098621f407SFrançois Tigeot 	params->dco_integer = div_u64(dco_freq, 24 * MHz(1));
12108621f407SFrançois Tigeot 	params->dco_fraction =
12118621f407SFrançois Tigeot 		div_u64((div_u64(dco_freq, 24) -
12128621f407SFrançois Tigeot 			 params->dco_integer * MHz(1)) * 0x8000, MHz(1));
12138621f407SFrançois Tigeot }
12148621f407SFrançois Tigeot 
12158621f407SFrançois Tigeot static bool
12168621f407SFrançois Tigeot skl_ddi_calculate_wrpll(int clock /* in Hz */,
12178621f407SFrançois Tigeot 			struct skl_wrpll_params *wrpll_params)
12188621f407SFrançois Tigeot {
12198621f407SFrançois Tigeot 	uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
12208621f407SFrançois Tigeot 	uint64_t dco_central_freq[3] = {8400000000ULL,
12218621f407SFrançois Tigeot 					9000000000ULL,
12228621f407SFrançois Tigeot 					9600000000ULL};
12238621f407SFrançois Tigeot 	static const int even_dividers[] = {  4,  6,  8, 10, 12, 14, 16, 18, 20,
12248621f407SFrançois Tigeot 					     24, 28, 30, 32, 36, 40, 42, 44,
12258621f407SFrançois Tigeot 					     48, 52, 54, 56, 60, 64, 66, 68,
12268621f407SFrançois Tigeot 					     70, 72, 76, 78, 80, 84, 88, 90,
12278621f407SFrançois Tigeot 					     92, 96, 98 };
12288621f407SFrançois Tigeot 	static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
12298621f407SFrançois Tigeot 	static const struct {
12308621f407SFrançois Tigeot 		const int *list;
12318621f407SFrançois Tigeot 		int n_dividers;
12328621f407SFrançois Tigeot 	} dividers[] = {
12338621f407SFrançois Tigeot 		{ even_dividers, ARRAY_SIZE(even_dividers) },
12348621f407SFrançois Tigeot 		{ odd_dividers, ARRAY_SIZE(odd_dividers) },
12358621f407SFrançois Tigeot 	};
12368621f407SFrançois Tigeot 	struct skl_wrpll_context ctx;
12378621f407SFrançois Tigeot 	unsigned int dco, d, i;
12388621f407SFrançois Tigeot 	unsigned int p0, p1, p2;
12398621f407SFrançois Tigeot 
12408621f407SFrançois Tigeot 	skl_wrpll_context_init(&ctx);
12418621f407SFrançois Tigeot 
12428621f407SFrançois Tigeot 	for (d = 0; d < ARRAY_SIZE(dividers); d++) {
12438621f407SFrançois Tigeot 		for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
12448621f407SFrançois Tigeot 			for (i = 0; i < dividers[d].n_dividers; i++) {
12458621f407SFrançois Tigeot 				unsigned int p = dividers[d].list[i];
12468621f407SFrançois Tigeot 				uint64_t dco_freq = p * afe_clock;
12478621f407SFrançois Tigeot 
12488621f407SFrançois Tigeot 				skl_wrpll_try_divider(&ctx,
12498621f407SFrançois Tigeot 						      dco_central_freq[dco],
12508621f407SFrançois Tigeot 						      dco_freq,
12518621f407SFrançois Tigeot 						      p);
12528621f407SFrançois Tigeot 				/*
12538621f407SFrançois Tigeot 				 * Skip the remaining dividers if we're sure to
12548621f407SFrançois Tigeot 				 * have found the definitive divider, we can't
12558621f407SFrançois Tigeot 				 * improve a 0 deviation.
12568621f407SFrançois Tigeot 				 */
12578621f407SFrançois Tigeot 				if (ctx.min_deviation == 0)
12588621f407SFrançois Tigeot 					goto skip_remaining_dividers;
12598621f407SFrançois Tigeot 			}
12608621f407SFrançois Tigeot 		}
12618621f407SFrançois Tigeot 
12628621f407SFrançois Tigeot skip_remaining_dividers:
12638621f407SFrançois Tigeot 		/*
12648621f407SFrançois Tigeot 		 * If a solution is found with an even divider, prefer
12658621f407SFrançois Tigeot 		 * this one.
12668621f407SFrançois Tigeot 		 */
12678621f407SFrançois Tigeot 		if (d == 0 && ctx.p)
12688621f407SFrançois Tigeot 			break;
12698621f407SFrançois Tigeot 	}
12708621f407SFrançois Tigeot 
12718621f407SFrançois Tigeot 	if (!ctx.p) {
12728621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
12738621f407SFrançois Tigeot 		return false;
12748621f407SFrançois Tigeot 	}
12758621f407SFrançois Tigeot 
12768621f407SFrançois Tigeot 	/*
12778621f407SFrançois Tigeot 	 * gcc incorrectly analyses that these can be used without being
12788621f407SFrançois Tigeot 	 * initialized. To be fair, it's hard to guess.
12798621f407SFrançois Tigeot 	 */
12808621f407SFrançois Tigeot 	p0 = p1 = p2 = 0;
12818621f407SFrançois Tigeot 	skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
12828621f407SFrançois Tigeot 	skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq,
12838621f407SFrançois Tigeot 				  p0, p1, p2);
12848621f407SFrançois Tigeot 
12858621f407SFrançois Tigeot 	return true;
12868621f407SFrançois Tigeot }
12878621f407SFrançois Tigeot 
12881e12ee3bSFrançois Tigeot static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc *crtc,
12891e12ee3bSFrançois Tigeot 				      struct intel_crtc_state *crtc_state,
12901e12ee3bSFrançois Tigeot 				      int clock)
12918621f407SFrançois Tigeot {
12928621f407SFrançois Tigeot 	uint32_t ctrl1, cfgcr1, cfgcr2;
12931e12ee3bSFrançois Tigeot 	struct skl_wrpll_params wrpll_params = { 0, };
12948621f407SFrançois Tigeot 
12958621f407SFrançois Tigeot 	/*
12968621f407SFrançois Tigeot 	 * See comment in intel_dpll_hw_state to understand why we always use 0
12978621f407SFrançois Tigeot 	 * as the DPLL id in this function.
12988621f407SFrançois Tigeot 	 */
12998621f407SFrançois Tigeot 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
13008621f407SFrançois Tigeot 
13018621f407SFrançois Tigeot 	ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
13028621f407SFrançois Tigeot 
13038621f407SFrançois Tigeot 	if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
13041e12ee3bSFrançois Tigeot 		return false;
13058621f407SFrançois Tigeot 
13068621f407SFrançois Tigeot 	cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
13078621f407SFrançois Tigeot 		DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
13088621f407SFrançois Tigeot 		wrpll_params.dco_integer;
13098621f407SFrançois Tigeot 
13108621f407SFrançois Tigeot 	cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
13118621f407SFrançois Tigeot 		DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
13128621f407SFrançois Tigeot 		DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
13138621f407SFrançois Tigeot 		DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
13148621f407SFrançois Tigeot 		wrpll_params.central_freq;
13151e12ee3bSFrançois Tigeot 
13161e12ee3bSFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
13171e12ee3bSFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
13181e12ee3bSFrançois Tigeot 
13191e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state.ctrl1 = ctrl1;
13201e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
13211e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
13221e12ee3bSFrançois Tigeot 	return true;
13231e12ee3bSFrançois Tigeot }
13241e12ee3bSFrançois Tigeot 
13251e12ee3bSFrançois Tigeot 
1326*a85cb24fSFrançois Tigeot static bool
1327*a85cb24fSFrançois Tigeot skl_ddi_dp_set_dpll_hw_state(int clock,
13281e12ee3bSFrançois Tigeot 			     struct intel_dpll_hw_state *dpll_hw_state)
13291e12ee3bSFrançois Tigeot {
13301e12ee3bSFrançois Tigeot 	uint32_t ctrl1;
13311e12ee3bSFrançois Tigeot 
13321e12ee3bSFrançois Tigeot 	/*
13331e12ee3bSFrançois Tigeot 	 * See comment in intel_dpll_hw_state to understand why we always use 0
13341e12ee3bSFrançois Tigeot 	 * as the DPLL id in this function.
13351e12ee3bSFrançois Tigeot 	 */
13361e12ee3bSFrançois Tigeot 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
13371e12ee3bSFrançois Tigeot 	switch (clock / 2) {
13388621f407SFrançois Tigeot 	case 81000:
13398621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
13408621f407SFrançois Tigeot 		break;
13418621f407SFrançois Tigeot 	case 135000:
13428621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
13438621f407SFrançois Tigeot 		break;
13448621f407SFrançois Tigeot 	case 270000:
13458621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
13468621f407SFrançois Tigeot 		break;
13478621f407SFrançois Tigeot 		/* eDP 1.4 rates */
13488621f407SFrançois Tigeot 	case 162000:
13498621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
13508621f407SFrançois Tigeot 		break;
13518621f407SFrançois Tigeot 	case 108000:
13528621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
13538621f407SFrançois Tigeot 		break;
13548621f407SFrançois Tigeot 	case 216000:
13558621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
13568621f407SFrançois Tigeot 		break;
13578621f407SFrançois Tigeot 	}
13588621f407SFrançois Tigeot 
13591e12ee3bSFrançois Tigeot 	dpll_hw_state->ctrl1 = ctrl1;
13601e12ee3bSFrançois Tigeot 	return true;
13611e12ee3bSFrançois Tigeot }
13621e12ee3bSFrançois Tigeot 
13631e12ee3bSFrançois Tigeot static struct intel_shared_dpll *
13641e12ee3bSFrançois Tigeot skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
13651e12ee3bSFrançois Tigeot 	     struct intel_encoder *encoder)
13661e12ee3bSFrançois Tigeot {
13671e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
13681e12ee3bSFrançois Tigeot 	int clock = crtc_state->port_clock;
13691e12ee3bSFrançois Tigeot 	bool bret;
13701e12ee3bSFrançois Tigeot 	struct intel_dpll_hw_state dpll_hw_state;
13711e12ee3bSFrançois Tigeot 
13721e12ee3bSFrançois Tigeot 	memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
13731e12ee3bSFrançois Tigeot 
13741e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI) {
13751e12ee3bSFrançois Tigeot 		bret = skl_ddi_hdmi_pll_dividers(crtc, crtc_state, clock);
13761e12ee3bSFrançois Tigeot 		if (!bret) {
13771e12ee3bSFrançois Tigeot 			DRM_DEBUG_KMS("Could not get HDMI pll dividers.\n");
13781e12ee3bSFrançois Tigeot 			return NULL;
13791e12ee3bSFrançois Tigeot 		}
13801e12ee3bSFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_DP ||
13811e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_DP_MST ||
13821e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_EDP) {
13831e12ee3bSFrançois Tigeot 		bret = skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state);
13841e12ee3bSFrançois Tigeot 		if (!bret) {
13851e12ee3bSFrançois Tigeot 			DRM_DEBUG_KMS("Could not set DP dpll HW state.\n");
13861e12ee3bSFrançois Tigeot 			return NULL;
13871e12ee3bSFrançois Tigeot 		}
13881e12ee3bSFrançois Tigeot 		crtc_state->dpll_hw_state = dpll_hw_state;
13898621f407SFrançois Tigeot 	} else {
13908621f407SFrançois Tigeot 		return NULL;
13918621f407SFrançois Tigeot 	}
13928621f407SFrançois Tigeot 
13938621f407SFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_EDP)
13948621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
13958621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL0,
13968621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL0);
13978621f407SFrançois Tigeot 	else
13988621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
13998621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL1,
14008621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL3);
14018621f407SFrançois Tigeot 	if (!pll)
14028621f407SFrançois Tigeot 		return NULL;
14038621f407SFrançois Tigeot 
14048621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
14058621f407SFrançois Tigeot 
14068621f407SFrançois Tigeot 	return pll;
14078621f407SFrançois Tigeot }
14088621f407SFrançois Tigeot 
1409*a85cb24fSFrançois Tigeot static void skl_dump_hw_state(struct drm_i915_private *dev_priv,
1410*a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
1411*a85cb24fSFrançois Tigeot {
1412*a85cb24fSFrançois Tigeot 	DRM_DEBUG_KMS("dpll_hw_state: "
1413*a85cb24fSFrançois Tigeot 		      "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n",
1414*a85cb24fSFrançois Tigeot 		      hw_state->ctrl1,
1415*a85cb24fSFrançois Tigeot 		      hw_state->cfgcr1,
1416*a85cb24fSFrançois Tigeot 		      hw_state->cfgcr2);
1417*a85cb24fSFrançois Tigeot }
1418*a85cb24fSFrançois Tigeot 
14198621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs skl_ddi_pll_funcs = {
14208621f407SFrançois Tigeot 	.enable = skl_ddi_pll_enable,
14218621f407SFrançois Tigeot 	.disable = skl_ddi_pll_disable,
14228621f407SFrançois Tigeot 	.get_hw_state = skl_ddi_pll_get_hw_state,
14238621f407SFrançois Tigeot };
14248621f407SFrançois Tigeot 
14258621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = {
14268621f407SFrançois Tigeot 	.enable = skl_ddi_dpll0_enable,
14278621f407SFrançois Tigeot 	.disable = skl_ddi_dpll0_disable,
14288621f407SFrançois Tigeot 	.get_hw_state = skl_ddi_dpll0_get_hw_state,
14298621f407SFrançois Tigeot };
14308621f407SFrançois Tigeot 
14318621f407SFrançois Tigeot static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
14328621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
14338621f407SFrançois Tigeot {
14348621f407SFrançois Tigeot 	uint32_t temp;
14358621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
14364be47400SFrançois Tigeot 	enum dpio_phy phy;
14374be47400SFrançois Tigeot 	enum dpio_channel ch;
14384be47400SFrançois Tigeot 
1439*a85cb24fSFrançois Tigeot 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
14408621f407SFrançois Tigeot 
14418621f407SFrançois Tigeot 	/* Non-SSC reference */
14428621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
14438621f407SFrançois Tigeot 	temp |= PORT_PLL_REF_SEL;
14448621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
14458621f407SFrançois Tigeot 
1446*a85cb24fSFrançois Tigeot 	if (IS_GEMINILAKE(dev_priv)) {
1447*a85cb24fSFrançois Tigeot 		temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
1448*a85cb24fSFrançois Tigeot 		temp |= PORT_PLL_POWER_ENABLE;
1449*a85cb24fSFrançois Tigeot 		I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
1450*a85cb24fSFrançois Tigeot 
1451*a85cb24fSFrançois Tigeot 		if (wait_for_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) &
1452*a85cb24fSFrançois Tigeot 				 PORT_PLL_POWER_STATE), 200))
1453*a85cb24fSFrançois Tigeot 			DRM_ERROR("Power state not set for PLL:%d\n", port);
1454*a85cb24fSFrançois Tigeot 	}
1455*a85cb24fSFrançois Tigeot 
14568621f407SFrançois Tigeot 	/* Disable 10 bit clock */
14574be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_4(phy, ch));
14588621f407SFrançois Tigeot 	temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
14594be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(phy, ch), temp);
14608621f407SFrançois Tigeot 
14618621f407SFrançois Tigeot 	/* Write P1 & P2 */
14624be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_0(phy, ch));
14638621f407SFrançois Tigeot 	temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK);
1464*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.ebb0;
14654be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_0(phy, ch), temp);
14668621f407SFrançois Tigeot 
14678621f407SFrançois Tigeot 	/* Write M2 integer */
14684be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 0));
14698621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_MASK;
1470*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll0;
14714be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 0), temp);
14728621f407SFrançois Tigeot 
14738621f407SFrançois Tigeot 	/* Write N */
14744be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 1));
14758621f407SFrançois Tigeot 	temp &= ~PORT_PLL_N_MASK;
1476*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll1;
14774be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 1), temp);
14788621f407SFrançois Tigeot 
14798621f407SFrançois Tigeot 	/* Write M2 fraction */
14804be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 2));
14818621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_FRAC_MASK;
1482*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll2;
14834be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 2), temp);
14848621f407SFrançois Tigeot 
14858621f407SFrançois Tigeot 	/* Write M2 fraction enable */
14864be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 3));
14878621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_FRAC_ENABLE;
1488*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll3;
14894be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 3), temp);
14908621f407SFrançois Tigeot 
14918621f407SFrançois Tigeot 	/* Write coeff */
14924be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 6));
14938621f407SFrançois Tigeot 	temp &= ~PORT_PLL_PROP_COEFF_MASK;
14948621f407SFrançois Tigeot 	temp &= ~PORT_PLL_INT_COEFF_MASK;
14958621f407SFrançois Tigeot 	temp &= ~PORT_PLL_GAIN_CTL_MASK;
1496*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll6;
14974be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 6), temp);
14988621f407SFrançois Tigeot 
14998621f407SFrançois Tigeot 	/* Write calibration val */
15004be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 8));
15018621f407SFrançois Tigeot 	temp &= ~PORT_PLL_TARGET_CNT_MASK;
1502*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll8;
15034be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 8), temp);
15048621f407SFrançois Tigeot 
15054be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 9));
15068621f407SFrançois Tigeot 	temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK;
1507*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll9;
15084be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 9), temp);
15098621f407SFrançois Tigeot 
15104be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 10));
15118621f407SFrançois Tigeot 	temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H;
15128621f407SFrançois Tigeot 	temp &= ~PORT_PLL_DCO_AMP_MASK;
1513*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll10;
15144be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 10), temp);
15158621f407SFrançois Tigeot 
15168621f407SFrançois Tigeot 	/* Recalibrate with new settings */
15174be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_4(phy, ch));
15188621f407SFrançois Tigeot 	temp |= PORT_PLL_RECALIBRATE;
15194be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(phy, ch), temp);
15208621f407SFrançois Tigeot 	temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
1521*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.ebb4;
15224be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(phy, ch), temp);
15238621f407SFrançois Tigeot 
15248621f407SFrançois Tigeot 	/* Enable PLL */
15258621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
15268621f407SFrançois Tigeot 	temp |= PORT_PLL_ENABLE;
15278621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
15288621f407SFrançois Tigeot 	POSTING_READ(BXT_PORT_PLL_ENABLE(port));
15298621f407SFrançois Tigeot 
15308621f407SFrançois Tigeot 	if (wait_for_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_LOCK),
15318621f407SFrançois Tigeot 			200))
15328621f407SFrançois Tigeot 		DRM_ERROR("PLL %d not locked\n", port);
15338621f407SFrançois Tigeot 
1534*a85cb24fSFrançois Tigeot 	if (IS_GEMINILAKE(dev_priv)) {
1535*a85cb24fSFrançois Tigeot 		temp = I915_READ(BXT_PORT_TX_DW5_LN0(phy, ch));
1536*a85cb24fSFrançois Tigeot 		temp |= DCC_DELAY_RANGE_2;
1537*a85cb24fSFrançois Tigeot 		I915_WRITE(BXT_PORT_TX_DW5_GRP(phy, ch), temp);
1538*a85cb24fSFrançois Tigeot 	}
1539*a85cb24fSFrançois Tigeot 
15408621f407SFrançois Tigeot 	/*
15418621f407SFrançois Tigeot 	 * While we write to the group register to program all lanes at once we
15428621f407SFrançois Tigeot 	 * can read only lane registers and we pick lanes 0/1 for that.
15438621f407SFrançois Tigeot 	 */
15444be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PCS_DW12_LN01(phy, ch));
15458621f407SFrançois Tigeot 	temp &= ~LANE_STAGGER_MASK;
15468621f407SFrançois Tigeot 	temp &= ~LANESTAGGER_STRAP_OVRD;
1547*a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pcsdw12;
15484be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PCS_DW12_GRP(phy, ch), temp);
15498621f407SFrançois Tigeot }
15508621f407SFrançois Tigeot 
15518621f407SFrançois Tigeot static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
15528621f407SFrançois Tigeot 					struct intel_shared_dpll *pll)
15538621f407SFrançois Tigeot {
15548621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
15558621f407SFrançois Tigeot 	uint32_t temp;
15568621f407SFrançois Tigeot 
15578621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
15588621f407SFrançois Tigeot 	temp &= ~PORT_PLL_ENABLE;
15598621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
15608621f407SFrançois Tigeot 	POSTING_READ(BXT_PORT_PLL_ENABLE(port));
1561*a85cb24fSFrançois Tigeot 
1562*a85cb24fSFrançois Tigeot 	if (IS_GEMINILAKE(dev_priv)) {
1563*a85cb24fSFrançois Tigeot 		temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
1564*a85cb24fSFrançois Tigeot 		temp &= ~PORT_PLL_POWER_ENABLE;
1565*a85cb24fSFrançois Tigeot 		I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
1566*a85cb24fSFrançois Tigeot 
1567*a85cb24fSFrançois Tigeot 		if (wait_for_us(!(I915_READ(BXT_PORT_PLL_ENABLE(port)) &
1568*a85cb24fSFrançois Tigeot 				PORT_PLL_POWER_STATE), 200))
1569*a85cb24fSFrançois Tigeot 			DRM_ERROR("Power state not reset for PLL:%d\n", port);
1570*a85cb24fSFrançois Tigeot 	}
15718621f407SFrançois Tigeot }
15728621f407SFrançois Tigeot 
15738621f407SFrançois Tigeot static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
15748621f407SFrançois Tigeot 					struct intel_shared_dpll *pll,
15758621f407SFrançois Tigeot 					struct intel_dpll_hw_state *hw_state)
15768621f407SFrançois Tigeot {
15778621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
15788621f407SFrançois Tigeot 	uint32_t val;
15798621f407SFrançois Tigeot 	bool ret;
15804be47400SFrançois Tigeot 	enum dpio_phy phy;
15814be47400SFrançois Tigeot 	enum dpio_channel ch;
15824be47400SFrançois Tigeot 
1583*a85cb24fSFrançois Tigeot 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
15848621f407SFrançois Tigeot 
15858621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
15868621f407SFrançois Tigeot 		return false;
15878621f407SFrançois Tigeot 
15888621f407SFrançois Tigeot 	ret = false;
15898621f407SFrançois Tigeot 
15908621f407SFrançois Tigeot 	val = I915_READ(BXT_PORT_PLL_ENABLE(port));
15918621f407SFrançois Tigeot 	if (!(val & PORT_PLL_ENABLE))
15928621f407SFrançois Tigeot 		goto out;
15938621f407SFrançois Tigeot 
15944be47400SFrançois Tigeot 	hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(phy, ch));
15958621f407SFrançois Tigeot 	hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
15968621f407SFrançois Tigeot 
15974be47400SFrançois Tigeot 	hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(phy, ch));
15988621f407SFrançois Tigeot 	hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
15998621f407SFrançois Tigeot 
16004be47400SFrançois Tigeot 	hw_state->pll0 = I915_READ(BXT_PORT_PLL(phy, ch, 0));
16018621f407SFrançois Tigeot 	hw_state->pll0 &= PORT_PLL_M2_MASK;
16028621f407SFrançois Tigeot 
16034be47400SFrançois Tigeot 	hw_state->pll1 = I915_READ(BXT_PORT_PLL(phy, ch, 1));
16048621f407SFrançois Tigeot 	hw_state->pll1 &= PORT_PLL_N_MASK;
16058621f407SFrançois Tigeot 
16064be47400SFrançois Tigeot 	hw_state->pll2 = I915_READ(BXT_PORT_PLL(phy, ch, 2));
16078621f407SFrançois Tigeot 	hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK;
16088621f407SFrançois Tigeot 
16094be47400SFrançois Tigeot 	hw_state->pll3 = I915_READ(BXT_PORT_PLL(phy, ch, 3));
16108621f407SFrançois Tigeot 	hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE;
16118621f407SFrançois Tigeot 
16124be47400SFrançois Tigeot 	hw_state->pll6 = I915_READ(BXT_PORT_PLL(phy, ch, 6));
16138621f407SFrançois Tigeot 	hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK |
16148621f407SFrançois Tigeot 			  PORT_PLL_INT_COEFF_MASK |
16158621f407SFrançois Tigeot 			  PORT_PLL_GAIN_CTL_MASK;
16168621f407SFrançois Tigeot 
16174be47400SFrançois Tigeot 	hw_state->pll8 = I915_READ(BXT_PORT_PLL(phy, ch, 8));
16188621f407SFrançois Tigeot 	hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK;
16198621f407SFrançois Tigeot 
16204be47400SFrançois Tigeot 	hw_state->pll9 = I915_READ(BXT_PORT_PLL(phy, ch, 9));
16218621f407SFrançois Tigeot 	hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK;
16228621f407SFrançois Tigeot 
16234be47400SFrançois Tigeot 	hw_state->pll10 = I915_READ(BXT_PORT_PLL(phy, ch, 10));
16248621f407SFrançois Tigeot 	hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H |
16258621f407SFrançois Tigeot 			   PORT_PLL_DCO_AMP_MASK;
16268621f407SFrançois Tigeot 
16278621f407SFrançois Tigeot 	/*
16288621f407SFrançois Tigeot 	 * While we write to the group register to program all lanes at once we
16298621f407SFrançois Tigeot 	 * can read only lane registers. We configure all lanes the same way, so
16308621f407SFrançois Tigeot 	 * here just read out lanes 0/1 and output a note if lanes 2/3 differ.
16318621f407SFrançois Tigeot 	 */
16324be47400SFrançois Tigeot 	hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(phy, ch));
16334be47400SFrançois Tigeot 	if (I915_READ(BXT_PORT_PCS_DW12_LN23(phy, ch)) != hw_state->pcsdw12)
16348621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
16358621f407SFrançois Tigeot 				 hw_state->pcsdw12,
16364be47400SFrançois Tigeot 				 I915_READ(BXT_PORT_PCS_DW12_LN23(phy, ch)));
16378621f407SFrançois Tigeot 	hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
16388621f407SFrançois Tigeot 
16398621f407SFrançois Tigeot 	ret = true;
16408621f407SFrançois Tigeot 
16418621f407SFrançois Tigeot out:
16428621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
16438621f407SFrançois Tigeot 
16448621f407SFrançois Tigeot 	return ret;
16458621f407SFrançois Tigeot }
16468621f407SFrançois Tigeot 
16478621f407SFrançois Tigeot /* bxt clock parameters */
16488621f407SFrançois Tigeot struct bxt_clk_div {
16498621f407SFrançois Tigeot 	int clock;
16508621f407SFrançois Tigeot 	uint32_t p1;
16518621f407SFrançois Tigeot 	uint32_t p2;
16528621f407SFrançois Tigeot 	uint32_t m2_int;
16538621f407SFrançois Tigeot 	uint32_t m2_frac;
16548621f407SFrançois Tigeot 	bool m2_frac_en;
16558621f407SFrançois Tigeot 	uint32_t n;
16561e12ee3bSFrançois Tigeot 
16571e12ee3bSFrançois Tigeot 	int vco;
16588621f407SFrançois Tigeot };
16598621f407SFrançois Tigeot 
16608621f407SFrançois Tigeot /* pre-calculated values for DP linkrates */
16618621f407SFrançois Tigeot static const struct bxt_clk_div bxt_dp_clk_val[] = {
16628621f407SFrançois Tigeot 	{162000, 4, 2, 32, 1677722, 1, 1},
16638621f407SFrançois Tigeot 	{270000, 4, 1, 27,       0, 0, 1},
16648621f407SFrançois Tigeot 	{540000, 2, 1, 27,       0, 0, 1},
16658621f407SFrançois Tigeot 	{216000, 3, 2, 32, 1677722, 1, 1},
16668621f407SFrançois Tigeot 	{243000, 4, 1, 24, 1258291, 1, 1},
16678621f407SFrançois Tigeot 	{324000, 4, 1, 32, 1677722, 1, 1},
16688621f407SFrançois Tigeot 	{432000, 3, 1, 32, 1677722, 1, 1}
16698621f407SFrançois Tigeot };
16708621f407SFrançois Tigeot 
16711e12ee3bSFrançois Tigeot static bool
16721e12ee3bSFrançois Tigeot bxt_ddi_hdmi_pll_dividers(struct intel_crtc *intel_crtc,
16731e12ee3bSFrançois Tigeot 			  struct intel_crtc_state *crtc_state, int clock,
16741e12ee3bSFrançois Tigeot 			  struct bxt_clk_div *clk_div)
16758621f407SFrançois Tigeot {
16761487f786SFrançois Tigeot 	struct dpll best_clock;
16778621f407SFrançois Tigeot 
16788621f407SFrançois Tigeot 	/* Calculate HDMI div */
16798621f407SFrançois Tigeot 	/*
16808621f407SFrançois Tigeot 	 * FIXME: tie the following calculation into
16818621f407SFrançois Tigeot 	 * i9xx_crtc_compute_clock
16828621f407SFrançois Tigeot 	 */
16838621f407SFrançois Tigeot 	if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
16848621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
16851e12ee3bSFrançois Tigeot 				 clock, pipe_name(intel_crtc->pipe));
16861e12ee3bSFrançois Tigeot 		return false;
16878621f407SFrançois Tigeot 	}
16888621f407SFrançois Tigeot 
16891e12ee3bSFrançois Tigeot 	clk_div->p1 = best_clock.p1;
16901e12ee3bSFrançois Tigeot 	clk_div->p2 = best_clock.p2;
16918621f407SFrançois Tigeot 	WARN_ON(best_clock.m1 != 2);
16921e12ee3bSFrançois Tigeot 	clk_div->n = best_clock.n;
16931e12ee3bSFrançois Tigeot 	clk_div->m2_int = best_clock.m2 >> 22;
16941e12ee3bSFrançois Tigeot 	clk_div->m2_frac = best_clock.m2 & ((1 << 22) - 1);
16951e12ee3bSFrançois Tigeot 	clk_div->m2_frac_en = clk_div->m2_frac != 0;
16968621f407SFrançois Tigeot 
16971e12ee3bSFrançois Tigeot 	clk_div->vco = best_clock.vco;
16981e12ee3bSFrançois Tigeot 
16991e12ee3bSFrançois Tigeot 	return true;
17001e12ee3bSFrançois Tigeot }
17011e12ee3bSFrançois Tigeot 
17021e12ee3bSFrançois Tigeot static void bxt_ddi_dp_pll_dividers(int clock, struct bxt_clk_div *clk_div)
17031e12ee3bSFrançois Tigeot {
17048621f407SFrançois Tigeot 	int i;
17058621f407SFrançois Tigeot 
17061e12ee3bSFrançois Tigeot 	*clk_div = bxt_dp_clk_val[0];
17078621f407SFrançois Tigeot 	for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
17088621f407SFrançois Tigeot 		if (bxt_dp_clk_val[i].clock == clock) {
17091e12ee3bSFrançois Tigeot 			*clk_div = bxt_dp_clk_val[i];
17108621f407SFrançois Tigeot 			break;
17118621f407SFrançois Tigeot 		}
17128621f407SFrançois Tigeot 	}
17131e12ee3bSFrançois Tigeot 
17141e12ee3bSFrançois Tigeot 	clk_div->vco = clock * 10 / 2 * clk_div->p1 * clk_div->p2;
17158621f407SFrançois Tigeot }
17168621f407SFrançois Tigeot 
17171e12ee3bSFrançois Tigeot static bool bxt_ddi_set_dpll_hw_state(int clock,
17181e12ee3bSFrançois Tigeot 			  struct bxt_clk_div *clk_div,
17191e12ee3bSFrançois Tigeot 			  struct intel_dpll_hw_state *dpll_hw_state)
17201e12ee3bSFrançois Tigeot {
17211e12ee3bSFrançois Tigeot 	int vco = clk_div->vco;
17221e12ee3bSFrançois Tigeot 	uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
17231e12ee3bSFrançois Tigeot 	uint32_t lanestagger;
17241e12ee3bSFrançois Tigeot 
17258621f407SFrançois Tigeot 	if (vco >= 6200000 && vco <= 6700000) {
17268621f407SFrançois Tigeot 		prop_coef = 4;
17278621f407SFrançois Tigeot 		int_coef = 9;
17288621f407SFrançois Tigeot 		gain_ctl = 3;
17298621f407SFrançois Tigeot 		targ_cnt = 8;
17308621f407SFrançois Tigeot 	} else if ((vco > 5400000 && vco < 6200000) ||
17318621f407SFrançois Tigeot 			(vco >= 4800000 && vco < 5400000)) {
17328621f407SFrançois Tigeot 		prop_coef = 5;
17338621f407SFrançois Tigeot 		int_coef = 11;
17348621f407SFrançois Tigeot 		gain_ctl = 3;
17358621f407SFrançois Tigeot 		targ_cnt = 9;
17368621f407SFrançois Tigeot 	} else if (vco == 5400000) {
17378621f407SFrançois Tigeot 		prop_coef = 3;
17388621f407SFrançois Tigeot 		int_coef = 8;
17398621f407SFrançois Tigeot 		gain_ctl = 1;
17408621f407SFrançois Tigeot 		targ_cnt = 9;
17418621f407SFrançois Tigeot 	} else {
17428621f407SFrançois Tigeot 		DRM_ERROR("Invalid VCO\n");
17431e12ee3bSFrançois Tigeot 		return false;
17448621f407SFrançois Tigeot 	}
17458621f407SFrançois Tigeot 
17468621f407SFrançois Tigeot 	if (clock > 270000)
17478621f407SFrançois Tigeot 		lanestagger = 0x18;
17488621f407SFrançois Tigeot 	else if (clock > 135000)
17498621f407SFrançois Tigeot 		lanestagger = 0x0d;
17508621f407SFrançois Tigeot 	else if (clock > 67000)
17518621f407SFrançois Tigeot 		lanestagger = 0x07;
17528621f407SFrançois Tigeot 	else if (clock > 33000)
17538621f407SFrançois Tigeot 		lanestagger = 0x04;
17548621f407SFrançois Tigeot 	else
17558621f407SFrançois Tigeot 		lanestagger = 0x02;
17568621f407SFrançois Tigeot 
17571e12ee3bSFrançois Tigeot 	dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2);
17581e12ee3bSFrançois Tigeot 	dpll_hw_state->pll0 = clk_div->m2_int;
17591e12ee3bSFrançois Tigeot 	dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n);
17601e12ee3bSFrançois Tigeot 	dpll_hw_state->pll2 = clk_div->m2_frac;
17618621f407SFrançois Tigeot 
17621e12ee3bSFrançois Tigeot 	if (clk_div->m2_frac_en)
17631e12ee3bSFrançois Tigeot 		dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE;
17648621f407SFrançois Tigeot 
17651e12ee3bSFrançois Tigeot 	dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef);
17661e12ee3bSFrançois Tigeot 	dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl);
17678621f407SFrançois Tigeot 
17681e12ee3bSFrançois Tigeot 	dpll_hw_state->pll8 = targ_cnt;
17698621f407SFrançois Tigeot 
17701e12ee3bSFrançois Tigeot 	dpll_hw_state->pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
17718621f407SFrançois Tigeot 
17721e12ee3bSFrançois Tigeot 	dpll_hw_state->pll10 =
17738621f407SFrançois Tigeot 		PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
17748621f407SFrançois Tigeot 		| PORT_PLL_DCO_AMP_OVR_EN_H;
17758621f407SFrançois Tigeot 
17761e12ee3bSFrançois Tigeot 	dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
17778621f407SFrançois Tigeot 
17781e12ee3bSFrançois Tigeot 	dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger;
17798621f407SFrançois Tigeot 
17801e12ee3bSFrançois Tigeot 	return true;
17811e12ee3bSFrançois Tigeot }
17821e12ee3bSFrançois Tigeot 
1783*a85cb24fSFrançois Tigeot static bool
1784*a85cb24fSFrançois Tigeot bxt_ddi_dp_set_dpll_hw_state(int clock,
17851e12ee3bSFrançois Tigeot 			     struct intel_dpll_hw_state *dpll_hw_state)
17861e12ee3bSFrançois Tigeot {
17871e12ee3bSFrançois Tigeot 	struct bxt_clk_div clk_div = {0};
17881e12ee3bSFrançois Tigeot 
17891e12ee3bSFrançois Tigeot 	bxt_ddi_dp_pll_dividers(clock, &clk_div);
17901e12ee3bSFrançois Tigeot 
17911e12ee3bSFrançois Tigeot 	return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state);
17921e12ee3bSFrançois Tigeot }
17931e12ee3bSFrançois Tigeot 
17941e12ee3bSFrançois Tigeot static bool
17951e12ee3bSFrançois Tigeot bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc *intel_crtc,
17961e12ee3bSFrançois Tigeot 			       struct intel_crtc_state *crtc_state, int clock,
17971e12ee3bSFrançois Tigeot 			       struct intel_dpll_hw_state *dpll_hw_state)
17981e12ee3bSFrançois Tigeot {
17991e12ee3bSFrançois Tigeot 	struct bxt_clk_div clk_div = { };
18001e12ee3bSFrançois Tigeot 
18011e12ee3bSFrançois Tigeot 	bxt_ddi_hdmi_pll_dividers(intel_crtc, crtc_state, clock, &clk_div);
18021e12ee3bSFrançois Tigeot 
18031e12ee3bSFrançois Tigeot 	return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state);
18041e12ee3bSFrançois Tigeot }
18051e12ee3bSFrançois Tigeot 
18061e12ee3bSFrançois Tigeot static struct intel_shared_dpll *
18071e12ee3bSFrançois Tigeot bxt_get_dpll(struct intel_crtc *crtc,
18081e12ee3bSFrançois Tigeot 		struct intel_crtc_state *crtc_state,
18091e12ee3bSFrançois Tigeot 		struct intel_encoder *encoder)
18101e12ee3bSFrançois Tigeot {
18111e12ee3bSFrançois Tigeot 	struct intel_dpll_hw_state dpll_hw_state = { };
18121e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
18131e12ee3bSFrançois Tigeot 	struct intel_digital_port *intel_dig_port;
18141e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
18151e12ee3bSFrançois Tigeot 	int i, clock = crtc_state->port_clock;
18161e12ee3bSFrançois Tigeot 
18171e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI &&
18181e12ee3bSFrançois Tigeot 	    !bxt_ddi_hdmi_set_dpll_hw_state(crtc, crtc_state, clock,
18191e12ee3bSFrançois Tigeot 					    &dpll_hw_state))
18201e12ee3bSFrançois Tigeot 		return NULL;
18211e12ee3bSFrançois Tigeot 
18221e12ee3bSFrançois Tigeot 	if ((encoder->type == INTEL_OUTPUT_DP ||
18234be47400SFrançois Tigeot 	     encoder->type == INTEL_OUTPUT_EDP ||
18244be47400SFrançois Tigeot 	     encoder->type == INTEL_OUTPUT_DP_MST) &&
18251e12ee3bSFrançois Tigeot 	    !bxt_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
18261e12ee3bSFrançois Tigeot 		return NULL;
18271e12ee3bSFrançois Tigeot 
18281e12ee3bSFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
18291e12ee3bSFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
18301e12ee3bSFrançois Tigeot 
18311e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state = dpll_hw_state;
18321e12ee3bSFrançois Tigeot 
18331e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_DP_MST) {
18341e12ee3bSFrançois Tigeot 		struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
18351e12ee3bSFrançois Tigeot 
18361e12ee3bSFrançois Tigeot 		intel_dig_port = intel_mst->primary;
18371e12ee3bSFrançois Tigeot 	} else
18388621f407SFrançois Tigeot 		intel_dig_port = enc_to_dig_port(&encoder->base);
18398621f407SFrançois Tigeot 
18408621f407SFrançois Tigeot 	/* 1:1 mapping between ports and PLLs */
18418621f407SFrançois Tigeot 	i = (enum intel_dpll_id) intel_dig_port->port;
18428621f407SFrançois Tigeot 	pll = intel_get_shared_dpll_by_id(dev_priv, i);
18438621f407SFrançois Tigeot 
18441487f786SFrançois Tigeot 	DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n",
18451487f786SFrançois Tigeot 		      crtc->base.base.id, crtc->base.name, pll->name);
18468621f407SFrançois Tigeot 
18478621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
18488621f407SFrançois Tigeot 
18498621f407SFrançois Tigeot 	return pll;
18508621f407SFrançois Tigeot }
18518621f407SFrançois Tigeot 
1852*a85cb24fSFrançois Tigeot static void bxt_dump_hw_state(struct drm_i915_private *dev_priv,
1853*a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
1854*a85cb24fSFrançois Tigeot {
1855*a85cb24fSFrançois Tigeot 	DRM_DEBUG_KMS("dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x,"
1856*a85cb24fSFrançois Tigeot 		      "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, "
1857*a85cb24fSFrançois Tigeot 		      "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pll10: 0x%x, pcsdw12: 0x%x\n",
1858*a85cb24fSFrançois Tigeot 		      hw_state->ebb0,
1859*a85cb24fSFrançois Tigeot 		      hw_state->ebb4,
1860*a85cb24fSFrançois Tigeot 		      hw_state->pll0,
1861*a85cb24fSFrançois Tigeot 		      hw_state->pll1,
1862*a85cb24fSFrançois Tigeot 		      hw_state->pll2,
1863*a85cb24fSFrançois Tigeot 		      hw_state->pll3,
1864*a85cb24fSFrançois Tigeot 		      hw_state->pll6,
1865*a85cb24fSFrançois Tigeot 		      hw_state->pll8,
1866*a85cb24fSFrançois Tigeot 		      hw_state->pll9,
1867*a85cb24fSFrançois Tigeot 		      hw_state->pll10,
1868*a85cb24fSFrançois Tigeot 		      hw_state->pcsdw12);
1869*a85cb24fSFrançois Tigeot }
1870*a85cb24fSFrançois Tigeot 
18718621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = {
18728621f407SFrançois Tigeot 	.enable = bxt_ddi_pll_enable,
18738621f407SFrançois Tigeot 	.disable = bxt_ddi_pll_disable,
18748621f407SFrançois Tigeot 	.get_hw_state = bxt_ddi_pll_get_hw_state,
18758621f407SFrançois Tigeot };
18768621f407SFrançois Tigeot 
18778621f407SFrançois Tigeot static void intel_ddi_pll_init(struct drm_device *dev)
18788621f407SFrançois Tigeot {
1879303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
18801487f786SFrançois Tigeot 
18811487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 9) {
18828621f407SFrançois Tigeot 		uint32_t val = I915_READ(LCPLL_CTL);
18838621f407SFrançois Tigeot 
18848621f407SFrançois Tigeot 		/*
18858621f407SFrançois Tigeot 		 * The LCPLL register should be turned on by the BIOS. For now
18868621f407SFrançois Tigeot 		 * let's just check its state and print errors in case
18878621f407SFrançois Tigeot 		 * something is wrong.  Don't even try to turn it on.
18888621f407SFrançois Tigeot 		 */
18898621f407SFrançois Tigeot 
18908621f407SFrançois Tigeot 		if (val & LCPLL_CD_SOURCE_FCLK)
18918621f407SFrançois Tigeot 			DRM_ERROR("CDCLK source is not LCPLL\n");
18928621f407SFrançois Tigeot 
18938621f407SFrançois Tigeot 		if (val & LCPLL_PLL_DISABLE)
18948621f407SFrançois Tigeot 			DRM_ERROR("LCPLL is disabled\n");
18958621f407SFrançois Tigeot 	}
18968621f407SFrançois Tigeot }
18978621f407SFrançois Tigeot 
18988621f407SFrançois Tigeot struct dpll_info {
18998621f407SFrançois Tigeot 	const char *name;
19008621f407SFrançois Tigeot 	const int id;
19018621f407SFrançois Tigeot 	const struct intel_shared_dpll_funcs *funcs;
19028621f407SFrançois Tigeot 	uint32_t flags;
19038621f407SFrançois Tigeot };
19048621f407SFrançois Tigeot 
19058621f407SFrançois Tigeot struct intel_dpll_mgr {
19068621f407SFrançois Tigeot 	const struct dpll_info *dpll_info;
19078621f407SFrançois Tigeot 
19088621f407SFrançois Tigeot 	struct intel_shared_dpll *(*get_dpll)(struct intel_crtc *crtc,
19098621f407SFrançois Tigeot 					      struct intel_crtc_state *crtc_state,
19108621f407SFrançois Tigeot 					      struct intel_encoder *encoder);
1911*a85cb24fSFrançois Tigeot 
1912*a85cb24fSFrançois Tigeot 	void (*dump_hw_state)(struct drm_i915_private *dev_priv,
1913*a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state);
19148621f407SFrançois Tigeot };
19158621f407SFrançois Tigeot 
19168621f407SFrançois Tigeot static const struct dpll_info pch_plls[] = {
19178621f407SFrançois Tigeot 	{ "PCH DPLL A", DPLL_ID_PCH_PLL_A, &ibx_pch_dpll_funcs, 0 },
19188621f407SFrançois Tigeot 	{ "PCH DPLL B", DPLL_ID_PCH_PLL_B, &ibx_pch_dpll_funcs, 0 },
19198621f407SFrançois Tigeot 	{ NULL, -1, NULL, 0 },
19208621f407SFrançois Tigeot };
19218621f407SFrançois Tigeot 
19228621f407SFrançois Tigeot static const struct intel_dpll_mgr pch_pll_mgr = {
19238621f407SFrançois Tigeot 	.dpll_info = pch_plls,
19248621f407SFrançois Tigeot 	.get_dpll = ibx_get_dpll,
1925*a85cb24fSFrançois Tigeot 	.dump_hw_state = ibx_dump_hw_state,
19268621f407SFrançois Tigeot };
19278621f407SFrançois Tigeot 
19288621f407SFrançois Tigeot static const struct dpll_info hsw_plls[] = {
19298621f407SFrançois Tigeot 	{ "WRPLL 1",    DPLL_ID_WRPLL1,     &hsw_ddi_wrpll_funcs, 0 },
19308621f407SFrançois Tigeot 	{ "WRPLL 2",    DPLL_ID_WRPLL2,     &hsw_ddi_wrpll_funcs, 0 },
19318621f407SFrançois Tigeot 	{ "SPLL",       DPLL_ID_SPLL,       &hsw_ddi_spll_funcs,  0 },
19328621f407SFrançois Tigeot 	{ "LCPLL 810",  DPLL_ID_LCPLL_810,  &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
19338621f407SFrançois Tigeot 	{ "LCPLL 1350", DPLL_ID_LCPLL_1350, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
19348621f407SFrançois Tigeot 	{ "LCPLL 2700", DPLL_ID_LCPLL_2700, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
19358621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
19368621f407SFrançois Tigeot };
19378621f407SFrançois Tigeot 
19388621f407SFrançois Tigeot static const struct intel_dpll_mgr hsw_pll_mgr = {
19398621f407SFrançois Tigeot 	.dpll_info = hsw_plls,
19408621f407SFrançois Tigeot 	.get_dpll = hsw_get_dpll,
1941*a85cb24fSFrançois Tigeot 	.dump_hw_state = hsw_dump_hw_state,
19428621f407SFrançois Tigeot };
19438621f407SFrançois Tigeot 
19448621f407SFrançois Tigeot static const struct dpll_info skl_plls[] = {
19458621f407SFrançois Tigeot 	{ "DPLL 0", DPLL_ID_SKL_DPLL0, &skl_ddi_dpll0_funcs, INTEL_DPLL_ALWAYS_ON },
19468621f407SFrançois Tigeot 	{ "DPLL 1", DPLL_ID_SKL_DPLL1, &skl_ddi_pll_funcs,   0 },
19478621f407SFrançois Tigeot 	{ "DPLL 2", DPLL_ID_SKL_DPLL2, &skl_ddi_pll_funcs,   0 },
19488621f407SFrançois Tigeot 	{ "DPLL 3", DPLL_ID_SKL_DPLL3, &skl_ddi_pll_funcs,   0 },
19498621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
19508621f407SFrançois Tigeot };
19518621f407SFrançois Tigeot 
19528621f407SFrançois Tigeot static const struct intel_dpll_mgr skl_pll_mgr = {
19538621f407SFrançois Tigeot 	.dpll_info = skl_plls,
19548621f407SFrançois Tigeot 	.get_dpll = skl_get_dpll,
1955*a85cb24fSFrançois Tigeot 	.dump_hw_state = skl_dump_hw_state,
19568621f407SFrançois Tigeot };
19578621f407SFrançois Tigeot 
19588621f407SFrançois Tigeot static const struct dpll_info bxt_plls[] = {
19598621f407SFrançois Tigeot 	{ "PORT PLL A", DPLL_ID_SKL_DPLL0, &bxt_ddi_pll_funcs, 0 },
19608621f407SFrançois Tigeot 	{ "PORT PLL B", DPLL_ID_SKL_DPLL1, &bxt_ddi_pll_funcs, 0 },
19618621f407SFrançois Tigeot 	{ "PORT PLL C", DPLL_ID_SKL_DPLL2, &bxt_ddi_pll_funcs, 0 },
19628621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
19638621f407SFrançois Tigeot };
19648621f407SFrançois Tigeot 
19658621f407SFrançois Tigeot static const struct intel_dpll_mgr bxt_pll_mgr = {
19668621f407SFrançois Tigeot 	.dpll_info = bxt_plls,
19678621f407SFrançois Tigeot 	.get_dpll = bxt_get_dpll,
1968*a85cb24fSFrançois Tigeot 	.dump_hw_state = bxt_dump_hw_state,
19698621f407SFrançois Tigeot };
19708621f407SFrançois Tigeot 
1971*a85cb24fSFrançois Tigeot /**
1972*a85cb24fSFrançois Tigeot  * intel_shared_dpll_init - Initialize shared DPLLs
1973*a85cb24fSFrançois Tigeot  * @dev: drm device
1974*a85cb24fSFrançois Tigeot  *
1975*a85cb24fSFrançois Tigeot  * Initialize shared DPLLs for @dev.
1976*a85cb24fSFrançois Tigeot  */
19778621f407SFrançois Tigeot void intel_shared_dpll_init(struct drm_device *dev)
19788621f407SFrançois Tigeot {
1979303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
19808621f407SFrançois Tigeot 	const struct intel_dpll_mgr *dpll_mgr = NULL;
19818621f407SFrançois Tigeot 	const struct dpll_info *dpll_info;
19828621f407SFrançois Tigeot 	int i;
19838621f407SFrançois Tigeot 
1984*a85cb24fSFrançois Tigeot 	if (IS_GEN9_BC(dev_priv))
19858621f407SFrançois Tigeot 		dpll_mgr = &skl_pll_mgr;
1986*a85cb24fSFrançois Tigeot 	else if (IS_GEN9_LP(dev_priv))
19878621f407SFrançois Tigeot 		dpll_mgr = &bxt_pll_mgr;
19881e12ee3bSFrançois Tigeot 	else if (HAS_DDI(dev_priv))
19898621f407SFrançois Tigeot 		dpll_mgr = &hsw_pll_mgr;
19901e12ee3bSFrançois Tigeot 	else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))
19918621f407SFrançois Tigeot 		dpll_mgr = &pch_pll_mgr;
19928621f407SFrançois Tigeot 
19938621f407SFrançois Tigeot 	if (!dpll_mgr) {
19948621f407SFrançois Tigeot 		dev_priv->num_shared_dpll = 0;
19958621f407SFrançois Tigeot 		return;
19968621f407SFrançois Tigeot 	}
19978621f407SFrançois Tigeot 
19988621f407SFrançois Tigeot 	dpll_info = dpll_mgr->dpll_info;
19998621f407SFrançois Tigeot 
20008621f407SFrançois Tigeot 	for (i = 0; dpll_info[i].id >= 0; i++) {
20018621f407SFrançois Tigeot 		WARN_ON(i != dpll_info[i].id);
20028621f407SFrançois Tigeot 
20038621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].id = dpll_info[i].id;
20048621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].name = dpll_info[i].name;
20058621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].funcs = *dpll_info[i].funcs;
20068621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].flags = dpll_info[i].flags;
20078621f407SFrançois Tigeot 	}
20088621f407SFrançois Tigeot 
20098621f407SFrançois Tigeot 	dev_priv->dpll_mgr = dpll_mgr;
20108621f407SFrançois Tigeot 	dev_priv->num_shared_dpll = i;
20118621f407SFrançois Tigeot 	lockinit(&dev_priv->dpll_lock, "dpll_lock", 0, LK_CANRECURSE);
20128621f407SFrançois Tigeot 
20138621f407SFrançois Tigeot 	BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
20148621f407SFrançois Tigeot 
20158621f407SFrançois Tigeot 	/* FIXME: Move this to a more suitable place */
20161e12ee3bSFrançois Tigeot 	if (HAS_DDI(dev_priv))
20178621f407SFrançois Tigeot 		intel_ddi_pll_init(dev);
20188621f407SFrançois Tigeot }
20198621f407SFrançois Tigeot 
2020*a85cb24fSFrançois Tigeot /**
2021*a85cb24fSFrançois Tigeot  * intel_get_shared_dpll - get a shared DPLL for CRTC and encoder combination
2022*a85cb24fSFrançois Tigeot  * @crtc: CRTC
2023*a85cb24fSFrançois Tigeot  * @crtc_state: atomic state for @crtc
2024*a85cb24fSFrançois Tigeot  * @encoder: encoder
2025*a85cb24fSFrançois Tigeot  *
2026*a85cb24fSFrançois Tigeot  * Find an appropriate DPLL for the given CRTC and encoder combination. A
2027*a85cb24fSFrançois Tigeot  * reference from the @crtc to the returned pll is registered in the atomic
2028*a85cb24fSFrançois Tigeot  * state. That configuration is made effective by calling
2029*a85cb24fSFrançois Tigeot  * intel_shared_dpll_swap_state(). The reference should be released by calling
2030*a85cb24fSFrançois Tigeot  * intel_release_shared_dpll().
2031*a85cb24fSFrançois Tigeot  *
2032*a85cb24fSFrançois Tigeot  * Returns:
2033*a85cb24fSFrançois Tigeot  * A shared DPLL to be used by @crtc and @encoder with the given @crtc_state.
2034*a85cb24fSFrançois Tigeot  */
20358621f407SFrançois Tigeot struct intel_shared_dpll *
20368621f407SFrançois Tigeot intel_get_shared_dpll(struct intel_crtc *crtc,
20378621f407SFrançois Tigeot 		      struct intel_crtc_state *crtc_state,
20388621f407SFrançois Tigeot 		      struct intel_encoder *encoder)
20398621f407SFrançois Tigeot {
20408621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
20418621f407SFrançois Tigeot 	const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll_mgr;
20428621f407SFrançois Tigeot 
20438621f407SFrançois Tigeot 	if (WARN_ON(!dpll_mgr))
20448621f407SFrançois Tigeot 		return NULL;
20458621f407SFrançois Tigeot 
20468621f407SFrançois Tigeot 	return dpll_mgr->get_dpll(crtc, crtc_state, encoder);
20478621f407SFrançois Tigeot }
2048*a85cb24fSFrançois Tigeot 
2049*a85cb24fSFrançois Tigeot /**
2050*a85cb24fSFrançois Tigeot  * intel_release_shared_dpll - end use of DPLL by CRTC in atomic state
2051*a85cb24fSFrançois Tigeot  * @dpll: dpll in use by @crtc
2052*a85cb24fSFrançois Tigeot  * @crtc: crtc
2053*a85cb24fSFrançois Tigeot  * @state: atomic state
2054*a85cb24fSFrançois Tigeot  *
2055*a85cb24fSFrançois Tigeot  * This function releases the reference from @crtc to @dpll from the
2056*a85cb24fSFrançois Tigeot  * atomic @state. The new configuration is made effective by calling
2057*a85cb24fSFrançois Tigeot  * intel_shared_dpll_swap_state().
2058*a85cb24fSFrançois Tigeot  */
2059*a85cb24fSFrançois Tigeot void intel_release_shared_dpll(struct intel_shared_dpll *dpll,
2060*a85cb24fSFrançois Tigeot 			       struct intel_crtc *crtc,
2061*a85cb24fSFrançois Tigeot 			       struct drm_atomic_state *state)
2062*a85cb24fSFrançois Tigeot {
2063*a85cb24fSFrançois Tigeot 	struct intel_shared_dpll_state *shared_dpll_state;
2064*a85cb24fSFrançois Tigeot 
2065*a85cb24fSFrançois Tigeot 	shared_dpll_state = intel_atomic_get_shared_dpll_state(state);
2066*a85cb24fSFrançois Tigeot 	shared_dpll_state[dpll->id].crtc_mask &= ~(1 << crtc->pipe);
2067*a85cb24fSFrançois Tigeot }
2068*a85cb24fSFrançois Tigeot 
2069*a85cb24fSFrançois Tigeot /**
2070*a85cb24fSFrançois Tigeot  * intel_shared_dpll_dump_hw_state - write hw_state to dmesg
2071*a85cb24fSFrançois Tigeot  * @dev_priv: i915 drm device
2072*a85cb24fSFrançois Tigeot  * @hw_state: hw state to be written to the log
2073*a85cb24fSFrançois Tigeot  *
2074*a85cb24fSFrançois Tigeot  * Write the relevant values in @hw_state to dmesg using DRM_DEBUG_KMS.
2075*a85cb24fSFrançois Tigeot  */
2076*a85cb24fSFrançois Tigeot void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv,
2077*a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
2078*a85cb24fSFrançois Tigeot {
2079*a85cb24fSFrançois Tigeot 	if (dev_priv->dpll_mgr) {
2080*a85cb24fSFrançois Tigeot 		dev_priv->dpll_mgr->dump_hw_state(dev_priv, hw_state);
2081*a85cb24fSFrançois Tigeot 	} else {
2082*a85cb24fSFrançois Tigeot 		/* fallback for platforms that don't use the shared dpll
2083*a85cb24fSFrançois Tigeot 		 * infrastructure
2084*a85cb24fSFrançois Tigeot 		 */
2085*a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
2086*a85cb24fSFrançois Tigeot 			      "fp0: 0x%x, fp1: 0x%x\n",
2087*a85cb24fSFrançois Tigeot 			      hw_state->dpll,
2088*a85cb24fSFrançois Tigeot 			      hw_state->dpll_md,
2089*a85cb24fSFrançois Tigeot 			      hw_state->fp0,
2090*a85cb24fSFrançois Tigeot 			      hw_state->fp1);
2091*a85cb24fSFrançois Tigeot 	}
2092*a85cb24fSFrançois Tigeot }
2093