xref: /dflybsd-src/sys/dev/drm/i915/intel_dpll_mgr.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
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 
26a85cb24fSFrançois Tigeot /**
27a85cb24fSFrançois Tigeot  * DOC: Display PLLs
28a85cb24fSFrançois Tigeot  *
29a85cb24fSFrançois Tigeot  * Display PLLs used for driving outputs vary by platform. While some have
30a85cb24fSFrançois Tigeot  * per-pipe or per-encoder dedicated PLLs, others allow the use of any PLL
31a85cb24fSFrançois Tigeot  * from a pool. In the latter scenario, it is possible that multiple pipes
32a85cb24fSFrançois Tigeot  * share a PLL if their configurations match.
33a85cb24fSFrançois Tigeot  *
34a85cb24fSFrançois Tigeot  * This file provides an abstraction over display PLLs. The function
35a85cb24fSFrançois Tigeot  * intel_shared_dpll_init() initializes the PLLs for the given platform.  The
36a85cb24fSFrançois Tigeot  * users of a PLL are tracked and that tracking is integrated with the atomic
37a85cb24fSFrançois Tigeot  * modest interface. During an atomic operation, a PLL can be requested for a
38a85cb24fSFrançois Tigeot  * given CRTC and encoder configuration by calling intel_get_shared_dpll() and
39a85cb24fSFrançois Tigeot  * a previously used PLL can be released with intel_release_shared_dpll().
40a85cb24fSFrançois Tigeot  * Changes to the users are first staged in the atomic state, and then made
41a85cb24fSFrançois Tigeot  * effective by calling intel_shared_dpll_swap_state() during the atomic
42a85cb24fSFrançois Tigeot  * commit phase.
43a85cb24fSFrançois Tigeot  */
44a85cb24fSFrançois Tigeot 
45a85cb24fSFrançois Tigeot static void
intel_atomic_duplicate_dpll_state(struct drm_i915_private * dev_priv,struct intel_shared_dpll_state * shared_dpll)46a85cb24fSFrançois Tigeot intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv,
47a85cb24fSFrançois Tigeot 				  struct intel_shared_dpll_state *shared_dpll)
481e12ee3bSFrançois Tigeot {
491e12ee3bSFrançois Tigeot 	enum intel_dpll_id i;
501e12ee3bSFrançois Tigeot 
51a85cb24fSFrançois Tigeot 	/* Copy shared dpll state */
52a85cb24fSFrançois Tigeot 	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
53a85cb24fSFrançois Tigeot 		struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
541e12ee3bSFrançois Tigeot 
55a85cb24fSFrançois Tigeot 		shared_dpll[i] = pll->state;
561e12ee3bSFrançois Tigeot 	}
571e12ee3bSFrançois Tigeot }
581e12ee3bSFrançois Tigeot 
59a85cb24fSFrançois Tigeot static struct intel_shared_dpll_state *
intel_atomic_get_shared_dpll_state(struct drm_atomic_state * s)60a85cb24fSFrançois Tigeot intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s)
61a85cb24fSFrançois Tigeot {
62a85cb24fSFrançois Tigeot 	struct intel_atomic_state *state = to_intel_atomic_state(s);
63a85cb24fSFrançois Tigeot 
64a85cb24fSFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&s->dev->mode_config.connection_mutex));
65a85cb24fSFrançois Tigeot 
66a85cb24fSFrançois Tigeot 	if (!state->dpll_set) {
67a85cb24fSFrançois Tigeot 		state->dpll_set = true;
68a85cb24fSFrançois Tigeot 
69a85cb24fSFrançois Tigeot 		intel_atomic_duplicate_dpll_state(to_i915(s->dev),
70a85cb24fSFrançois Tigeot 						  state->shared_dpll);
711e12ee3bSFrançois Tigeot 	}
721e12ee3bSFrançois Tigeot 
73a85cb24fSFrançois Tigeot 	return state->shared_dpll;
741e12ee3bSFrançois Tigeot }
751e12ee3bSFrançois Tigeot 
76a85cb24fSFrançois Tigeot /**
77a85cb24fSFrançois Tigeot  * intel_get_shared_dpll_by_id - get a DPLL given its id
78a85cb24fSFrançois Tigeot  * @dev_priv: i915 device instance
79a85cb24fSFrançois Tigeot  * @id: pll id
80a85cb24fSFrançois Tigeot  *
81a85cb24fSFrançois Tigeot  * Returns:
82a85cb24fSFrançois Tigeot  * A pointer to the DPLL with @id
83a85cb24fSFrançois Tigeot  */
841e12ee3bSFrançois Tigeot struct intel_shared_dpll *
intel_get_shared_dpll_by_id(struct drm_i915_private * dev_priv,enum intel_dpll_id id)858621f407SFrançois Tigeot intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
868621f407SFrançois Tigeot 			    enum intel_dpll_id id)
878621f407SFrançois Tigeot {
888621f407SFrançois Tigeot 	return &dev_priv->shared_dplls[id];
898621f407SFrançois Tigeot }
908621f407SFrançois Tigeot 
91a85cb24fSFrançois Tigeot /**
92a85cb24fSFrançois Tigeot  * intel_get_shared_dpll_id - get the id of a DPLL
93a85cb24fSFrançois Tigeot  * @dev_priv: i915 device instance
94a85cb24fSFrançois Tigeot  * @pll: the DPLL
95a85cb24fSFrançois Tigeot  *
96a85cb24fSFrançois Tigeot  * Returns:
97a85cb24fSFrançois Tigeot  * The id of @pll
98a85cb24fSFrançois Tigeot  */
998621f407SFrançois Tigeot enum intel_dpll_id
intel_get_shared_dpll_id(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)1008621f407SFrançois Tigeot intel_get_shared_dpll_id(struct drm_i915_private *dev_priv,
1018621f407SFrançois Tigeot 			 struct intel_shared_dpll *pll)
1028621f407SFrançois Tigeot {
1038621f407SFrançois Tigeot 	if (WARN_ON(pll < dev_priv->shared_dplls||
1048621f407SFrançois Tigeot 		    pll > &dev_priv->shared_dplls[dev_priv->num_shared_dpll]))
1058621f407SFrançois Tigeot 		return -1;
1068621f407SFrançois Tigeot 
1078621f407SFrançois Tigeot 	return (enum intel_dpll_id) (pll - dev_priv->shared_dplls);
1088621f407SFrançois Tigeot }
1098621f407SFrançois Tigeot 
1108621f407SFrançois Tigeot /* For ILK+ */
assert_shared_dpll(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll,bool state)1118621f407SFrançois Tigeot void assert_shared_dpll(struct drm_i915_private *dev_priv,
1128621f407SFrançois Tigeot 			struct intel_shared_dpll *pll,
1138621f407SFrançois Tigeot 			bool state)
1148621f407SFrançois Tigeot {
1158621f407SFrançois Tigeot 	bool cur_state;
1168621f407SFrançois Tigeot 	struct intel_dpll_hw_state hw_state;
1178621f407SFrançois Tigeot 
1188621f407SFrançois Tigeot 	if (WARN(!pll, "asserting DPLL %s with no DPLL\n", onoff(state)))
1198621f407SFrançois Tigeot 		return;
1208621f407SFrançois Tigeot 
1218621f407SFrançois Tigeot 	cur_state = pll->funcs.get_hw_state(dev_priv, pll, &hw_state);
1228621f407SFrançois Tigeot 	I915_STATE_WARN(cur_state != state,
1238621f407SFrançois Tigeot 	     "%s assertion failure (expected %s, current %s)\n",
1248621f407SFrançois Tigeot 			pll->name, onoff(state), onoff(cur_state));
1258621f407SFrançois Tigeot }
1268621f407SFrançois Tigeot 
127a85cb24fSFrançois Tigeot /**
128a85cb24fSFrançois Tigeot  * intel_prepare_shared_dpll - call a dpll's prepare hook
129a85cb24fSFrançois Tigeot  * @crtc: CRTC which has a shared dpll
130a85cb24fSFrançois Tigeot  *
131a85cb24fSFrançois Tigeot  * This calls the PLL's prepare hook if it has one and if the PLL is not
132a85cb24fSFrançois Tigeot  * already enabled. The prepare hook is platform specific.
133a85cb24fSFrançois Tigeot  */
intel_prepare_shared_dpll(struct intel_crtc * crtc)1348621f407SFrançois Tigeot void intel_prepare_shared_dpll(struct intel_crtc *crtc)
1358621f407SFrançois Tigeot {
1368621f407SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
137303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1388621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
1398621f407SFrançois Tigeot 
1408621f407SFrançois Tigeot 	if (WARN_ON(pll == NULL))
1418621f407SFrançois Tigeot 		return;
1428621f407SFrançois Tigeot 
1438621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
144a85cb24fSFrançois Tigeot 	WARN_ON(!pll->state.crtc_mask);
1458621f407SFrançois Tigeot 	if (!pll->active_mask) {
1468621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("setting up %s\n", pll->name);
1478621f407SFrançois Tigeot 		WARN_ON(pll->on);
1488621f407SFrançois Tigeot 		assert_shared_dpll_disabled(dev_priv, pll);
1498621f407SFrançois Tigeot 
150a85cb24fSFrançois Tigeot 		pll->funcs.prepare(dev_priv, pll);
1518621f407SFrançois Tigeot 	}
1528621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
1538621f407SFrançois Tigeot }
1548621f407SFrançois Tigeot 
1558621f407SFrançois Tigeot /**
156a85cb24fSFrançois Tigeot  * intel_enable_shared_dpll - enable a CRTC's shared DPLL
157a85cb24fSFrançois Tigeot  * @crtc: CRTC which has a shared DPLL
1588621f407SFrançois Tigeot  *
159a85cb24fSFrançois Tigeot  * Enable the shared DPLL used by @crtc.
1608621f407SFrançois Tigeot  */
intel_enable_shared_dpll(struct intel_crtc * crtc)1618621f407SFrançois Tigeot void intel_enable_shared_dpll(struct intel_crtc *crtc)
1628621f407SFrançois Tigeot {
1638621f407SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
164303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1658621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
1668621f407SFrançois Tigeot 	unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base);
1678621f407SFrançois Tigeot 	unsigned old_mask;
1688621f407SFrançois Tigeot 
1698621f407SFrançois Tigeot 	if (WARN_ON(pll == NULL))
1708621f407SFrançois Tigeot 		return;
1718621f407SFrançois Tigeot 
1728621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
1738621f407SFrançois Tigeot 	old_mask = pll->active_mask;
1748621f407SFrançois Tigeot 
175a85cb24fSFrançois Tigeot 	if (WARN_ON(!(pll->state.crtc_mask & crtc_mask)) ||
1768621f407SFrançois Tigeot 	    WARN_ON(pll->active_mask & crtc_mask))
1778621f407SFrançois Tigeot 		goto out;
1788621f407SFrançois Tigeot 
1798621f407SFrançois Tigeot 	pll->active_mask |= crtc_mask;
1808621f407SFrançois Tigeot 
1818621f407SFrançois Tigeot 	DRM_DEBUG_KMS("enable %s (active %x, on? %d) for crtc %d\n",
1828621f407SFrançois Tigeot 		      pll->name, pll->active_mask, pll->on,
1838621f407SFrançois Tigeot 		      crtc->base.base.id);
1848621f407SFrançois Tigeot 
1858621f407SFrançois Tigeot 	if (old_mask) {
1868621f407SFrançois Tigeot 		WARN_ON(!pll->on);
1878621f407SFrançois Tigeot 		assert_shared_dpll_enabled(dev_priv, pll);
1888621f407SFrançois Tigeot 		goto out;
1898621f407SFrançois Tigeot 	}
1908621f407SFrançois Tigeot 	WARN_ON(pll->on);
1918621f407SFrançois Tigeot 
1928621f407SFrançois Tigeot 	DRM_DEBUG_KMS("enabling %s\n", pll->name);
1938621f407SFrançois Tigeot 	pll->funcs.enable(dev_priv, pll);
1948621f407SFrançois Tigeot 	pll->on = true;
1958621f407SFrançois Tigeot 
1968621f407SFrançois Tigeot out:
1978621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
1988621f407SFrançois Tigeot }
1998621f407SFrançois Tigeot 
200a85cb24fSFrançois Tigeot /**
201a85cb24fSFrançois Tigeot  * intel_disable_shared_dpll - disable a CRTC's shared DPLL
202a85cb24fSFrançois Tigeot  * @crtc: CRTC which has a shared DPLL
203a85cb24fSFrançois Tigeot  *
204a85cb24fSFrançois Tigeot  * Disable the shared DPLL used by @crtc.
205a85cb24fSFrançois Tigeot  */
intel_disable_shared_dpll(struct intel_crtc * crtc)2068621f407SFrançois Tigeot void intel_disable_shared_dpll(struct intel_crtc *crtc)
2078621f407SFrançois Tigeot {
2084be47400SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
2098621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
2108621f407SFrançois Tigeot 	unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base);
2118621f407SFrançois Tigeot 
2128621f407SFrançois Tigeot 	/* PCH only available on ILK+ */
2134be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 5)
2148621f407SFrançois Tigeot 		return;
2158621f407SFrançois Tigeot 
2168621f407SFrançois Tigeot 	if (pll == NULL)
2178621f407SFrançois Tigeot 		return;
2188621f407SFrançois Tigeot 
2198621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
2208621f407SFrançois Tigeot 	if (WARN_ON(!(pll->active_mask & crtc_mask)))
2218621f407SFrançois Tigeot 		goto out;
2228621f407SFrançois Tigeot 
2238621f407SFrançois Tigeot 	DRM_DEBUG_KMS("disable %s (active %x, on? %d) for crtc %d\n",
2248621f407SFrançois Tigeot 		      pll->name, pll->active_mask, pll->on,
2258621f407SFrançois Tigeot 		      crtc->base.base.id);
2268621f407SFrançois Tigeot 
2278621f407SFrançois Tigeot 	assert_shared_dpll_enabled(dev_priv, pll);
2288621f407SFrançois Tigeot 	WARN_ON(!pll->on);
2298621f407SFrançois Tigeot 
2308621f407SFrançois Tigeot 	pll->active_mask &= ~crtc_mask;
2318621f407SFrançois Tigeot 	if (pll->active_mask)
2328621f407SFrançois Tigeot 		goto out;
2338621f407SFrançois Tigeot 
2348621f407SFrançois Tigeot 	DRM_DEBUG_KMS("disabling %s\n", pll->name);
2358621f407SFrançois Tigeot 	pll->funcs.disable(dev_priv, pll);
2368621f407SFrançois Tigeot 	pll->on = false;
2378621f407SFrançois Tigeot 
2388621f407SFrançois Tigeot out:
2398621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
2408621f407SFrançois Tigeot }
2418621f407SFrançois Tigeot 
2428621f407SFrançois Tigeot static struct intel_shared_dpll *
intel_find_shared_dpll(struct intel_crtc * crtc,struct intel_crtc_state * crtc_state,enum intel_dpll_id range_min,enum intel_dpll_id range_max)2438621f407SFrançois Tigeot intel_find_shared_dpll(struct intel_crtc *crtc,
2448621f407SFrançois Tigeot 		       struct intel_crtc_state *crtc_state,
2458621f407SFrançois Tigeot 		       enum intel_dpll_id range_min,
2468621f407SFrançois Tigeot 		       enum intel_dpll_id range_max)
2478621f407SFrançois Tigeot {
248303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
2498621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
250a85cb24fSFrançois Tigeot 	struct intel_shared_dpll_state *shared_dpll;
2518621f407SFrançois Tigeot 	enum intel_dpll_id i;
2528621f407SFrançois Tigeot 
2538621f407SFrançois Tigeot 	shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
2548621f407SFrançois Tigeot 
2558621f407SFrançois Tigeot 	for (i = range_min; i <= range_max; i++) {
2568621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
2578621f407SFrançois Tigeot 
2588621f407SFrançois Tigeot 		/* Only want to check enabled timings first */
2598621f407SFrançois Tigeot 		if (shared_dpll[i].crtc_mask == 0)
2608621f407SFrançois Tigeot 			continue;
2618621f407SFrançois Tigeot 
2628621f407SFrançois Tigeot 		if (memcmp(&crtc_state->dpll_hw_state,
2638621f407SFrançois Tigeot 			   &shared_dpll[i].hw_state,
2648621f407SFrançois Tigeot 			   sizeof(crtc_state->dpll_hw_state)) == 0) {
2651487f786SFrançois Tigeot 			DRM_DEBUG_KMS("[CRTC:%d:%s] sharing existing %s (crtc mask 0x%08x, active %x)\n",
2661487f786SFrançois Tigeot 				      crtc->base.base.id, crtc->base.name, pll->name,
2678621f407SFrançois Tigeot 				      shared_dpll[i].crtc_mask,
2688621f407SFrançois Tigeot 				      pll->active_mask);
2698621f407SFrançois Tigeot 			return pll;
2708621f407SFrançois Tigeot 		}
2718621f407SFrançois Tigeot 	}
2728621f407SFrançois Tigeot 
2738621f407SFrançois Tigeot 	/* Ok no matching timings, maybe there's a free one? */
2748621f407SFrançois Tigeot 	for (i = range_min; i <= range_max; i++) {
2758621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
2768621f407SFrançois Tigeot 		if (shared_dpll[i].crtc_mask == 0) {
2771487f786SFrançois Tigeot 			DRM_DEBUG_KMS("[CRTC:%d:%s] allocated %s\n",
2781487f786SFrançois Tigeot 				      crtc->base.base.id, crtc->base.name, pll->name);
2798621f407SFrançois Tigeot 			return pll;
2808621f407SFrançois Tigeot 		}
2818621f407SFrançois Tigeot 	}
2828621f407SFrançois Tigeot 
2838621f407SFrançois Tigeot 	return NULL;
2848621f407SFrançois Tigeot }
2858621f407SFrançois Tigeot 
2868621f407SFrançois Tigeot static void
intel_reference_shared_dpll(struct intel_shared_dpll * pll,struct intel_crtc_state * crtc_state)2878621f407SFrançois Tigeot intel_reference_shared_dpll(struct intel_shared_dpll *pll,
2888621f407SFrançois Tigeot 			    struct intel_crtc_state *crtc_state)
2898621f407SFrançois Tigeot {
290a85cb24fSFrançois Tigeot 	struct intel_shared_dpll_state *shared_dpll;
2918621f407SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
2928621f407SFrançois Tigeot 	enum intel_dpll_id i = pll->id;
2938621f407SFrançois Tigeot 
2948621f407SFrançois Tigeot 	shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
2958621f407SFrançois Tigeot 
2968621f407SFrançois Tigeot 	if (shared_dpll[i].crtc_mask == 0)
2978621f407SFrançois Tigeot 		shared_dpll[i].hw_state =
2988621f407SFrançois Tigeot 			crtc_state->dpll_hw_state;
2998621f407SFrançois Tigeot 
3008621f407SFrançois Tigeot 	crtc_state->shared_dpll = pll;
3018621f407SFrançois Tigeot 	DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
3028621f407SFrançois Tigeot 			 pipe_name(crtc->pipe));
3038621f407SFrançois Tigeot 
304a85cb24fSFrançois Tigeot 	shared_dpll[pll->id].crtc_mask |= 1 << crtc->pipe;
3058621f407SFrançois Tigeot }
3068621f407SFrançois Tigeot 
307a85cb24fSFrançois Tigeot /**
308a85cb24fSFrançois Tigeot  * intel_shared_dpll_swap_state - make atomic DPLL configuration effective
309a85cb24fSFrançois Tigeot  * @state: atomic state
310a85cb24fSFrançois Tigeot  *
311a85cb24fSFrançois Tigeot  * This is the dpll version of drm_atomic_helper_swap_state() since the
312a85cb24fSFrançois Tigeot  * helper does not handle driver-specific global state.
313a85cb24fSFrançois Tigeot  *
314a85cb24fSFrançois Tigeot  * For consistency with atomic helpers this function does a complete swap,
315a85cb24fSFrançois Tigeot  * i.e. it also puts the current state into @state, even though there is no
316a85cb24fSFrançois Tigeot  * need for that at this moment.
317a85cb24fSFrançois Tigeot  */
intel_shared_dpll_swap_state(struct drm_atomic_state * state)318a85cb24fSFrançois Tigeot void intel_shared_dpll_swap_state(struct drm_atomic_state *state)
3198621f407SFrançois Tigeot {
3208621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(state->dev);
321a85cb24fSFrançois Tigeot 	struct intel_shared_dpll_state *shared_dpll;
3228621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
3238621f407SFrançois Tigeot 	enum intel_dpll_id i;
3248621f407SFrançois Tigeot 
3258621f407SFrançois Tigeot 	if (!to_intel_atomic_state(state)->dpll_set)
3268621f407SFrançois Tigeot 		return;
3278621f407SFrançois Tigeot 
3288621f407SFrançois Tigeot 	shared_dpll = to_intel_atomic_state(state)->shared_dpll;
3298621f407SFrançois Tigeot 	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
330a85cb24fSFrançois Tigeot 		struct intel_shared_dpll_state tmp;
331a85cb24fSFrançois Tigeot 
3328621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
333a85cb24fSFrançois Tigeot 
334a85cb24fSFrançois Tigeot 		tmp = pll->state;
335a85cb24fSFrançois Tigeot 		pll->state = shared_dpll[i];
336a85cb24fSFrançois Tigeot 		shared_dpll[i] = tmp;
3378621f407SFrançois Tigeot 	}
3388621f407SFrançois Tigeot }
3398621f407SFrançois Tigeot 
ibx_pch_dpll_get_hw_state(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll,struct intel_dpll_hw_state * hw_state)3408621f407SFrançois Tigeot static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
3418621f407SFrançois Tigeot 				      struct intel_shared_dpll *pll,
3428621f407SFrançois Tigeot 				      struct intel_dpll_hw_state *hw_state)
3438621f407SFrançois Tigeot {
3448621f407SFrançois Tigeot 	uint32_t val;
3458621f407SFrançois Tigeot 
3468621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
3478621f407SFrançois Tigeot 		return false;
3488621f407SFrançois Tigeot 
3498621f407SFrançois Tigeot 	val = I915_READ(PCH_DPLL(pll->id));
3508621f407SFrançois Tigeot 	hw_state->dpll = val;
3518621f407SFrançois Tigeot 	hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
3528621f407SFrançois Tigeot 	hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
3538621f407SFrançois Tigeot 
3548621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
3558621f407SFrançois Tigeot 
3568621f407SFrançois Tigeot 	return val & DPLL_VCO_ENABLE;
3578621f407SFrançois Tigeot }
3588621f407SFrançois Tigeot 
ibx_pch_dpll_prepare(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)359a85cb24fSFrançois Tigeot static void ibx_pch_dpll_prepare(struct drm_i915_private *dev_priv,
3608621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
3618621f407SFrançois Tigeot {
362a85cb24fSFrançois Tigeot 	I915_WRITE(PCH_FP0(pll->id), pll->state.hw_state.fp0);
363a85cb24fSFrançois Tigeot 	I915_WRITE(PCH_FP1(pll->id), pll->state.hw_state.fp1);
3648621f407SFrançois Tigeot }
3658621f407SFrançois Tigeot 
ibx_assert_pch_refclk_enabled(struct drm_i915_private * dev_priv)3668621f407SFrançois Tigeot static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
3678621f407SFrançois Tigeot {
3688621f407SFrançois Tigeot 	u32 val;
3698621f407SFrançois Tigeot 	bool enabled;
3708621f407SFrançois Tigeot 
3718621f407SFrançois Tigeot 	I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)));
3728621f407SFrançois Tigeot 
3738621f407SFrançois Tigeot 	val = I915_READ(PCH_DREF_CONTROL);
3748621f407SFrançois Tigeot 	enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
3758621f407SFrançois Tigeot 			    DREF_SUPERSPREAD_SOURCE_MASK));
3768621f407SFrançois Tigeot 	I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
3778621f407SFrançois Tigeot }
3788621f407SFrançois Tigeot 
ibx_pch_dpll_enable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)3798621f407SFrançois Tigeot static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
3808621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
3818621f407SFrançois Tigeot {
3828621f407SFrançois Tigeot 	/* PCH refclock must be enabled first */
3838621f407SFrançois Tigeot 	ibx_assert_pch_refclk_enabled(dev_priv);
3848621f407SFrançois Tigeot 
385a85cb24fSFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), pll->state.hw_state.dpll);
3868621f407SFrançois Tigeot 
3878621f407SFrançois Tigeot 	/* Wait for the clocks to stabilize. */
3888621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
3898621f407SFrançois Tigeot 	udelay(150);
3908621f407SFrançois Tigeot 
3918621f407SFrançois Tigeot 	/* The pixel multiplier can only be updated once the
3928621f407SFrançois Tigeot 	 * DPLL is enabled and the clocks are stable.
3938621f407SFrançois Tigeot 	 *
3948621f407SFrançois Tigeot 	 * So write it again.
3958621f407SFrançois Tigeot 	 */
396a85cb24fSFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), pll->state.hw_state.dpll);
3978621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
3988621f407SFrançois Tigeot 	udelay(200);
3998621f407SFrançois Tigeot }
4008621f407SFrançois Tigeot 
ibx_pch_dpll_disable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)4018621f407SFrançois Tigeot static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
4028621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
4038621f407SFrançois Tigeot {
404303bf270SFrançois Tigeot 	struct drm_device *dev = &dev_priv->drm;
4058621f407SFrançois Tigeot 	struct intel_crtc *crtc;
4068621f407SFrançois Tigeot 
4078621f407SFrançois Tigeot 	/* Make sure no transcoder isn't still depending on us. */
4088621f407SFrançois Tigeot 	for_each_intel_crtc(dev, crtc) {
4098621f407SFrançois Tigeot 		if (crtc->config->shared_dpll == pll)
4108621f407SFrançois Tigeot 			assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
4118621f407SFrançois Tigeot 	}
4128621f407SFrançois Tigeot 
4138621f407SFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), 0);
4148621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
4158621f407SFrançois Tigeot 	udelay(200);
4168621f407SFrançois Tigeot }
4178621f407SFrançois Tigeot 
4188621f407SFrançois Tigeot static struct intel_shared_dpll *
ibx_get_dpll(struct intel_crtc * crtc,struct intel_crtc_state * crtc_state,struct intel_encoder * encoder)4198621f407SFrançois Tigeot ibx_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
4208621f407SFrançois Tigeot 	     struct intel_encoder *encoder)
4218621f407SFrançois Tigeot {
4228621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
4238621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
4248621f407SFrançois Tigeot 	enum intel_dpll_id i;
4258621f407SFrançois Tigeot 
4268621f407SFrançois Tigeot 	if (HAS_PCH_IBX(dev_priv)) {
4278621f407SFrançois Tigeot 		/* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
4288621f407SFrançois Tigeot 		i = (enum intel_dpll_id) crtc->pipe;
4298621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
4308621f407SFrançois Tigeot 
4311487f786SFrançois Tigeot 		DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n",
4321487f786SFrançois Tigeot 			      crtc->base.base.id, crtc->base.name, pll->name);
4338621f407SFrançois Tigeot 	} else {
4348621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
4358621f407SFrançois Tigeot 					     DPLL_ID_PCH_PLL_A,
4368621f407SFrançois Tigeot 					     DPLL_ID_PCH_PLL_B);
4378621f407SFrançois Tigeot 	}
4388621f407SFrançois Tigeot 
4398621f407SFrançois Tigeot 	if (!pll)
4408621f407SFrançois Tigeot 		return NULL;
4418621f407SFrançois Tigeot 
4428621f407SFrançois Tigeot 	/* reference the pll */
4438621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
4448621f407SFrançois Tigeot 
4458621f407SFrançois Tigeot 	return pll;
4468621f407SFrançois Tigeot }
4478621f407SFrançois Tigeot 
ibx_dump_hw_state(struct drm_i915_private * dev_priv,struct intel_dpll_hw_state * hw_state)448a85cb24fSFrançois Tigeot static void ibx_dump_hw_state(struct drm_i915_private *dev_priv,
449a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
450a85cb24fSFrançois Tigeot {
451a85cb24fSFrançois Tigeot 	DRM_DEBUG_KMS("dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
452a85cb24fSFrançois Tigeot 		      "fp0: 0x%x, fp1: 0x%x\n",
453a85cb24fSFrançois Tigeot 		      hw_state->dpll,
454a85cb24fSFrançois Tigeot 		      hw_state->dpll_md,
455a85cb24fSFrançois Tigeot 		      hw_state->fp0,
456a85cb24fSFrançois Tigeot 		      hw_state->fp1);
457a85cb24fSFrançois Tigeot }
458a85cb24fSFrançois Tigeot 
4598621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
460a85cb24fSFrançois Tigeot 	.prepare = ibx_pch_dpll_prepare,
4618621f407SFrançois Tigeot 	.enable = ibx_pch_dpll_enable,
4628621f407SFrançois Tigeot 	.disable = ibx_pch_dpll_disable,
4638621f407SFrançois Tigeot 	.get_hw_state = ibx_pch_dpll_get_hw_state,
4648621f407SFrançois Tigeot };
4658621f407SFrançois Tigeot 
hsw_ddi_wrpll_enable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)4668621f407SFrançois Tigeot static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
4678621f407SFrançois Tigeot 			       struct intel_shared_dpll *pll)
4688621f407SFrançois Tigeot {
469a85cb24fSFrançois Tigeot 	I915_WRITE(WRPLL_CTL(pll->id), pll->state.hw_state.wrpll);
4708621f407SFrançois Tigeot 	POSTING_READ(WRPLL_CTL(pll->id));
4718621f407SFrançois Tigeot 	udelay(20);
4728621f407SFrançois Tigeot }
4738621f407SFrançois Tigeot 
hsw_ddi_spll_enable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)4748621f407SFrançois Tigeot static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
4758621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
4768621f407SFrançois Tigeot {
477a85cb24fSFrançois Tigeot 	I915_WRITE(SPLL_CTL, pll->state.hw_state.spll);
4788621f407SFrançois Tigeot 	POSTING_READ(SPLL_CTL);
4798621f407SFrançois Tigeot 	udelay(20);
4808621f407SFrançois Tigeot }
4818621f407SFrançois Tigeot 
hsw_ddi_wrpll_disable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)4828621f407SFrançois Tigeot static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
4838621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
4848621f407SFrançois Tigeot {
4858621f407SFrançois Tigeot 	uint32_t val;
4868621f407SFrançois Tigeot 
4878621f407SFrançois Tigeot 	val = I915_READ(WRPLL_CTL(pll->id));
4888621f407SFrançois Tigeot 	I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
4898621f407SFrançois Tigeot 	POSTING_READ(WRPLL_CTL(pll->id));
4908621f407SFrançois Tigeot }
4918621f407SFrançois Tigeot 
hsw_ddi_spll_disable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)4928621f407SFrançois Tigeot static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
4938621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
4948621f407SFrançois Tigeot {
4958621f407SFrançois Tigeot 	uint32_t val;
4968621f407SFrançois Tigeot 
4978621f407SFrançois Tigeot 	val = I915_READ(SPLL_CTL);
4988621f407SFrançois Tigeot 	I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
4998621f407SFrançois Tigeot 	POSTING_READ(SPLL_CTL);
5008621f407SFrançois Tigeot }
5018621f407SFrançois Tigeot 
hsw_ddi_wrpll_get_hw_state(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll,struct intel_dpll_hw_state * hw_state)5028621f407SFrançois Tigeot static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
5038621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
5048621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
5058621f407SFrançois Tigeot {
5068621f407SFrançois Tigeot 	uint32_t val;
5078621f407SFrançois Tigeot 
5088621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
5098621f407SFrançois Tigeot 		return false;
5108621f407SFrançois Tigeot 
5118621f407SFrançois Tigeot 	val = I915_READ(WRPLL_CTL(pll->id));
5128621f407SFrançois Tigeot 	hw_state->wrpll = val;
5138621f407SFrançois Tigeot 
5148621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
5158621f407SFrançois Tigeot 
5168621f407SFrançois Tigeot 	return val & WRPLL_PLL_ENABLE;
5178621f407SFrançois Tigeot }
5188621f407SFrançois Tigeot 
hsw_ddi_spll_get_hw_state(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll,struct intel_dpll_hw_state * hw_state)5198621f407SFrançois Tigeot static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
5208621f407SFrançois Tigeot 				      struct intel_shared_dpll *pll,
5218621f407SFrançois Tigeot 				      struct intel_dpll_hw_state *hw_state)
5228621f407SFrançois Tigeot {
5238621f407SFrançois Tigeot 	uint32_t val;
5248621f407SFrançois Tigeot 
5258621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
5268621f407SFrançois Tigeot 		return false;
5278621f407SFrançois Tigeot 
5288621f407SFrançois Tigeot 	val = I915_READ(SPLL_CTL);
5298621f407SFrançois Tigeot 	hw_state->spll = val;
5308621f407SFrançois Tigeot 
5318621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
5328621f407SFrançois Tigeot 
5338621f407SFrançois Tigeot 	return val & SPLL_PLL_ENABLE;
5348621f407SFrançois Tigeot }
5358621f407SFrançois Tigeot 
5368621f407SFrançois Tigeot #define LC_FREQ 2700
5378621f407SFrançois Tigeot #define LC_FREQ_2K U64_C(LC_FREQ * 2000)
5388621f407SFrançois Tigeot 
5398621f407SFrançois Tigeot #define P_MIN 2
5408621f407SFrançois Tigeot #define P_MAX 64
5418621f407SFrançois Tigeot #define P_INC 2
5428621f407SFrançois Tigeot 
5438621f407SFrançois Tigeot /* Constraints for PLL good behavior */
5448621f407SFrançois Tigeot #define REF_MIN 48
5458621f407SFrançois Tigeot #define REF_MAX 400
5468621f407SFrançois Tigeot #define VCO_MIN 2400
5478621f407SFrançois Tigeot #define VCO_MAX 4800
5488621f407SFrançois Tigeot 
5498621f407SFrançois Tigeot struct hsw_wrpll_rnp {
5508621f407SFrançois Tigeot 	unsigned p, n2, r2;
5518621f407SFrançois Tigeot };
5528621f407SFrançois Tigeot 
hsw_wrpll_get_budget_for_freq(int clock)5538621f407SFrançois Tigeot static unsigned hsw_wrpll_get_budget_for_freq(int clock)
5548621f407SFrançois Tigeot {
5558621f407SFrançois Tigeot 	unsigned budget;
5568621f407SFrançois Tigeot 
5578621f407SFrançois Tigeot 	switch (clock) {
5588621f407SFrançois Tigeot 	case 25175000:
5598621f407SFrançois Tigeot 	case 25200000:
5608621f407SFrançois Tigeot 	case 27000000:
5618621f407SFrançois Tigeot 	case 27027000:
5628621f407SFrançois Tigeot 	case 37762500:
5638621f407SFrançois Tigeot 	case 37800000:
5648621f407SFrançois Tigeot 	case 40500000:
5658621f407SFrançois Tigeot 	case 40541000:
5668621f407SFrançois Tigeot 	case 54000000:
5678621f407SFrançois Tigeot 	case 54054000:
5688621f407SFrançois Tigeot 	case 59341000:
5698621f407SFrançois Tigeot 	case 59400000:
5708621f407SFrançois Tigeot 	case 72000000:
5718621f407SFrançois Tigeot 	case 74176000:
5728621f407SFrançois Tigeot 	case 74250000:
5738621f407SFrançois Tigeot 	case 81000000:
5748621f407SFrançois Tigeot 	case 81081000:
5758621f407SFrançois Tigeot 	case 89012000:
5768621f407SFrançois Tigeot 	case 89100000:
5778621f407SFrançois Tigeot 	case 108000000:
5788621f407SFrançois Tigeot 	case 108108000:
5798621f407SFrançois Tigeot 	case 111264000:
5808621f407SFrançois Tigeot 	case 111375000:
5818621f407SFrançois Tigeot 	case 148352000:
5828621f407SFrançois Tigeot 	case 148500000:
5838621f407SFrançois Tigeot 	case 162000000:
5848621f407SFrançois Tigeot 	case 162162000:
5858621f407SFrançois Tigeot 	case 222525000:
5868621f407SFrançois Tigeot 	case 222750000:
5878621f407SFrançois Tigeot 	case 296703000:
5888621f407SFrançois Tigeot 	case 297000000:
5898621f407SFrançois Tigeot 		budget = 0;
5908621f407SFrançois Tigeot 		break;
5918621f407SFrançois Tigeot 	case 233500000:
5928621f407SFrançois Tigeot 	case 245250000:
5938621f407SFrançois Tigeot 	case 247750000:
5948621f407SFrançois Tigeot 	case 253250000:
5958621f407SFrançois Tigeot 	case 298000000:
5968621f407SFrançois Tigeot 		budget = 1500;
5978621f407SFrançois Tigeot 		break;
5988621f407SFrançois Tigeot 	case 169128000:
5998621f407SFrançois Tigeot 	case 169500000:
6008621f407SFrançois Tigeot 	case 179500000:
6018621f407SFrançois Tigeot 	case 202000000:
6028621f407SFrançois Tigeot 		budget = 2000;
6038621f407SFrançois Tigeot 		break;
6048621f407SFrançois Tigeot 	case 256250000:
6058621f407SFrançois Tigeot 	case 262500000:
6068621f407SFrançois Tigeot 	case 270000000:
6078621f407SFrançois Tigeot 	case 272500000:
6088621f407SFrançois Tigeot 	case 273750000:
6098621f407SFrançois Tigeot 	case 280750000:
6108621f407SFrançois Tigeot 	case 281250000:
6118621f407SFrançois Tigeot 	case 286000000:
6128621f407SFrançois Tigeot 	case 291750000:
6138621f407SFrançois Tigeot 		budget = 4000;
6148621f407SFrançois Tigeot 		break;
6158621f407SFrançois Tigeot 	case 267250000:
6168621f407SFrançois Tigeot 	case 268500000:
6178621f407SFrançois Tigeot 		budget = 5000;
6188621f407SFrançois Tigeot 		break;
6198621f407SFrançois Tigeot 	default:
6208621f407SFrançois Tigeot 		budget = 1000;
6218621f407SFrançois Tigeot 		break;
6228621f407SFrançois Tigeot 	}
6238621f407SFrançois Tigeot 
6248621f407SFrançois Tigeot 	return budget;
6258621f407SFrançois Tigeot }
6268621f407SFrançois Tigeot 
hsw_wrpll_update_rnp(uint64_t freq2k,unsigned budget,unsigned r2,unsigned n2,unsigned p,struct hsw_wrpll_rnp * best)6278621f407SFrançois Tigeot static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget,
6288621f407SFrançois Tigeot 				 unsigned r2, unsigned n2, unsigned p,
6298621f407SFrançois Tigeot 				 struct hsw_wrpll_rnp *best)
6308621f407SFrançois Tigeot {
6318621f407SFrançois Tigeot 	uint64_t a, b, c, d, diff, diff_best;
6328621f407SFrançois Tigeot 
6338621f407SFrançois Tigeot 	/* No best (r,n,p) yet */
6348621f407SFrançois Tigeot 	if (best->p == 0) {
6358621f407SFrançois Tigeot 		best->p = p;
6368621f407SFrançois Tigeot 		best->n2 = n2;
6378621f407SFrançois Tigeot 		best->r2 = r2;
6388621f407SFrançois Tigeot 		return;
6398621f407SFrançois Tigeot 	}
6408621f407SFrançois Tigeot 
6418621f407SFrançois Tigeot 	/*
6428621f407SFrançois Tigeot 	 * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
6438621f407SFrançois Tigeot 	 * freq2k.
6448621f407SFrançois Tigeot 	 *
6458621f407SFrançois Tigeot 	 * delta = 1e6 *
6468621f407SFrançois Tigeot 	 *	   abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
6478621f407SFrançois Tigeot 	 *	   freq2k;
6488621f407SFrançois Tigeot 	 *
6498621f407SFrançois Tigeot 	 * and we would like delta <= budget.
6508621f407SFrançois Tigeot 	 *
6518621f407SFrançois Tigeot 	 * If the discrepancy is above the PPM-based budget, always prefer to
6528621f407SFrançois Tigeot 	 * improve upon the previous solution.  However, if you're within the
6538621f407SFrançois Tigeot 	 * budget, try to maximize Ref * VCO, that is N / (P * R^2).
6548621f407SFrançois Tigeot 	 */
6558621f407SFrançois Tigeot 	a = freq2k * budget * p * r2;
6568621f407SFrançois Tigeot 	b = freq2k * budget * best->p * best->r2;
6578621f407SFrançois Tigeot 	diff = abs_diff((u64)freq2k * p * r2, LC_FREQ_2K * n2);
6588621f407SFrançois Tigeot 	diff_best = abs_diff((u64)freq2k * best->p * best->r2,
6598621f407SFrançois Tigeot 			     LC_FREQ_2K * best->n2);
6608621f407SFrançois Tigeot 	c = 1000000 * diff;
6618621f407SFrançois Tigeot 	d = 1000000 * diff_best;
6628621f407SFrançois Tigeot 
6638621f407SFrançois Tigeot 	if (a < c && b < d) {
6648621f407SFrançois Tigeot 		/* If both are above the budget, pick the closer */
6658621f407SFrançois Tigeot 		if (best->p * best->r2 * diff < p * r2 * diff_best) {
6668621f407SFrançois Tigeot 			best->p = p;
6678621f407SFrançois Tigeot 			best->n2 = n2;
6688621f407SFrançois Tigeot 			best->r2 = r2;
6698621f407SFrançois Tigeot 		}
6708621f407SFrançois Tigeot 	} else if (a >= c && b < d) {
6718621f407SFrançois Tigeot 		/* If A is below the threshold but B is above it?  Update. */
6728621f407SFrançois Tigeot 		best->p = p;
6738621f407SFrançois Tigeot 		best->n2 = n2;
6748621f407SFrançois Tigeot 		best->r2 = r2;
6758621f407SFrançois Tigeot 	} else if (a >= c && b >= d) {
6768621f407SFrançois Tigeot 		/* Both are below the limit, so pick the higher n2/(r2*r2) */
6778621f407SFrançois Tigeot 		if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) {
6788621f407SFrançois Tigeot 			best->p = p;
6798621f407SFrançois Tigeot 			best->n2 = n2;
6808621f407SFrançois Tigeot 			best->r2 = r2;
6818621f407SFrançois Tigeot 		}
6828621f407SFrançois Tigeot 	}
6838621f407SFrançois Tigeot 	/* Otherwise a < c && b >= d, do nothing */
6848621f407SFrançois Tigeot }
6858621f407SFrançois Tigeot 
6868621f407SFrançois Tigeot static void
hsw_ddi_calculate_wrpll(int clock,unsigned * r2_out,unsigned * n2_out,unsigned * p_out)6878621f407SFrançois Tigeot hsw_ddi_calculate_wrpll(int clock /* in Hz */,
6888621f407SFrançois Tigeot 			unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
6898621f407SFrançois Tigeot {
6908621f407SFrançois Tigeot 	uint64_t freq2k;
6918621f407SFrançois Tigeot 	unsigned p, n2, r2;
6928621f407SFrançois Tigeot 	struct hsw_wrpll_rnp best = { 0, 0, 0 };
6938621f407SFrançois Tigeot 	unsigned budget;
6948621f407SFrançois Tigeot 
6958621f407SFrançois Tigeot 	freq2k = clock / 100;
6968621f407SFrançois Tigeot 
6978621f407SFrançois Tigeot 	budget = hsw_wrpll_get_budget_for_freq(clock);
6988621f407SFrançois Tigeot 
6998621f407SFrançois Tigeot 	/* Special case handling for 540 pixel clock: bypass WR PLL entirely
7008621f407SFrançois Tigeot 	 * and directly pass the LC PLL to it. */
7018621f407SFrançois Tigeot 	if (freq2k == 5400000) {
7028621f407SFrançois Tigeot 		*n2_out = 2;
7038621f407SFrançois Tigeot 		*p_out = 1;
7048621f407SFrançois Tigeot 		*r2_out = 2;
7058621f407SFrançois Tigeot 		return;
7068621f407SFrançois Tigeot 	}
7078621f407SFrançois Tigeot 
7088621f407SFrançois Tigeot 	/*
7098621f407SFrançois Tigeot 	 * Ref = LC_FREQ / R, where Ref is the actual reference input seen by
7108621f407SFrançois Tigeot 	 * the WR PLL.
7118621f407SFrançois Tigeot 	 *
7128621f407SFrançois Tigeot 	 * We want R so that REF_MIN <= Ref <= REF_MAX.
7138621f407SFrançois Tigeot 	 * Injecting R2 = 2 * R gives:
7148621f407SFrançois Tigeot 	 *   REF_MAX * r2 > LC_FREQ * 2 and
7158621f407SFrançois Tigeot 	 *   REF_MIN * r2 < LC_FREQ * 2
7168621f407SFrançois Tigeot 	 *
7178621f407SFrançois Tigeot 	 * Which means the desired boundaries for r2 are:
7188621f407SFrançois Tigeot 	 *  LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
7198621f407SFrançois Tigeot 	 *
7208621f407SFrançois Tigeot 	 */
7218621f407SFrançois Tigeot 	for (r2 = LC_FREQ * 2 / REF_MAX + 1;
7228621f407SFrançois Tigeot 	     r2 <= LC_FREQ * 2 / REF_MIN;
7238621f407SFrançois Tigeot 	     r2++) {
7248621f407SFrançois Tigeot 
7258621f407SFrançois Tigeot 		/*
7268621f407SFrançois Tigeot 		 * VCO = N * Ref, that is: VCO = N * LC_FREQ / R
7278621f407SFrançois Tigeot 		 *
7288621f407SFrançois Tigeot 		 * Once again we want VCO_MIN <= VCO <= VCO_MAX.
7298621f407SFrançois Tigeot 		 * Injecting R2 = 2 * R and N2 = 2 * N, we get:
7308621f407SFrançois Tigeot 		 *   VCO_MAX * r2 > n2 * LC_FREQ and
7318621f407SFrançois Tigeot 		 *   VCO_MIN * r2 < n2 * LC_FREQ)
7328621f407SFrançois Tigeot 		 *
7338621f407SFrançois Tigeot 		 * Which means the desired boundaries for n2 are:
7348621f407SFrançois Tigeot 		 * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
7358621f407SFrançois Tigeot 		 */
7368621f407SFrançois Tigeot 		for (n2 = VCO_MIN * r2 / LC_FREQ + 1;
7378621f407SFrançois Tigeot 		     n2 <= VCO_MAX * r2 / LC_FREQ;
7388621f407SFrançois Tigeot 		     n2++) {
7398621f407SFrançois Tigeot 
7408621f407SFrançois Tigeot 			for (p = P_MIN; p <= P_MAX; p += P_INC)
7418621f407SFrançois Tigeot 				hsw_wrpll_update_rnp(freq2k, budget,
7428621f407SFrançois Tigeot 						     r2, n2, p, &best);
7438621f407SFrançois Tigeot 		}
7448621f407SFrançois Tigeot 	}
7458621f407SFrançois Tigeot 
7468621f407SFrançois Tigeot 	*n2_out = best.n2;
7478621f407SFrançois Tigeot 	*p_out = best.p;
7488621f407SFrançois Tigeot 	*r2_out = best.r2;
7498621f407SFrançois Tigeot }
7508621f407SFrançois Tigeot 
hsw_ddi_hdmi_get_dpll(int clock,struct intel_crtc * crtc,struct intel_crtc_state * crtc_state)7511e12ee3bSFrançois Tigeot static struct intel_shared_dpll *hsw_ddi_hdmi_get_dpll(int clock,
7521e12ee3bSFrançois Tigeot 						       struct intel_crtc *crtc,
7531e12ee3bSFrançois Tigeot 						       struct intel_crtc_state *crtc_state)
7548621f407SFrançois Tigeot {
7558621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
7568621f407SFrançois Tigeot 	uint32_t val;
7571e12ee3bSFrançois Tigeot 	unsigned int p, n2, r2;
7588621f407SFrançois Tigeot 
7598621f407SFrançois Tigeot 	hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
7608621f407SFrançois Tigeot 
7618621f407SFrançois Tigeot 	val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
7628621f407SFrançois Tigeot 	      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
7638621f407SFrançois Tigeot 	      WRPLL_DIVIDER_POST(p);
7648621f407SFrançois Tigeot 
7658621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.wrpll = val;
7668621f407SFrançois Tigeot 
7678621f407SFrançois Tigeot 	pll = intel_find_shared_dpll(crtc, crtc_state,
7688621f407SFrançois Tigeot 				     DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
7698621f407SFrançois Tigeot 
7701e12ee3bSFrançois Tigeot 	if (!pll)
7711e12ee3bSFrançois Tigeot 		return NULL;
7721e12ee3bSFrançois Tigeot 
7731e12ee3bSFrançois Tigeot 	return pll;
7741e12ee3bSFrançois Tigeot }
7751e12ee3bSFrançois Tigeot 
776a85cb24fSFrançois Tigeot static struct intel_shared_dpll *
hsw_ddi_dp_get_dpll(struct intel_encoder * encoder,int clock)777a85cb24fSFrançois Tigeot hsw_ddi_dp_get_dpll(struct intel_encoder *encoder, int clock)
7781e12ee3bSFrançois Tigeot {
7791e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
7801e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
7818621f407SFrançois Tigeot 	enum intel_dpll_id pll_id;
7828621f407SFrançois Tigeot 
7838621f407SFrançois Tigeot 	switch (clock / 2) {
7848621f407SFrançois Tigeot 	case 81000:
7858621f407SFrançois Tigeot 		pll_id = DPLL_ID_LCPLL_810;
7868621f407SFrançois Tigeot 		break;
7878621f407SFrançois Tigeot 	case 135000:
7888621f407SFrançois Tigeot 		pll_id = DPLL_ID_LCPLL_1350;
7898621f407SFrançois Tigeot 		break;
7908621f407SFrançois Tigeot 	case 270000:
7918621f407SFrançois Tigeot 		pll_id = DPLL_ID_LCPLL_2700;
7928621f407SFrançois Tigeot 		break;
7938621f407SFrançois Tigeot 	default:
7948621f407SFrançois Tigeot 		DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
7958621f407SFrançois Tigeot 		return NULL;
7968621f407SFrançois Tigeot 	}
7978621f407SFrançois Tigeot 
7988621f407SFrançois Tigeot 	pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
7998621f407SFrançois Tigeot 
8001e12ee3bSFrançois Tigeot 	if (!pll)
8011e12ee3bSFrançois Tigeot 		return NULL;
8021e12ee3bSFrançois Tigeot 
8031e12ee3bSFrançois Tigeot 	return pll;
8041e12ee3bSFrançois Tigeot }
8051e12ee3bSFrançois Tigeot 
8061e12ee3bSFrançois Tigeot static struct intel_shared_dpll *
hsw_get_dpll(struct intel_crtc * crtc,struct intel_crtc_state * crtc_state,struct intel_encoder * encoder)8071e12ee3bSFrançois Tigeot hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
8081e12ee3bSFrançois Tigeot 	     struct intel_encoder *encoder)
8091e12ee3bSFrançois Tigeot {
8101e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
8111e12ee3bSFrançois Tigeot 	int clock = crtc_state->port_clock;
8121e12ee3bSFrançois Tigeot 
8131e12ee3bSFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
8141e12ee3bSFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
8151e12ee3bSFrançois Tigeot 
8161e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI) {
8171e12ee3bSFrançois Tigeot 		pll = hsw_ddi_hdmi_get_dpll(clock, crtc, crtc_state);
8181e12ee3bSFrançois Tigeot 
8191e12ee3bSFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_DP ||
8201e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_DP_MST ||
8211e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_EDP) {
8221e12ee3bSFrançois Tigeot 		pll = hsw_ddi_dp_get_dpll(encoder, clock);
8231e12ee3bSFrançois Tigeot 
8248621f407SFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_ANALOG) {
8258621f407SFrançois Tigeot 		if (WARN_ON(crtc_state->port_clock / 2 != 135000))
8268621f407SFrançois Tigeot 			return NULL;
8278621f407SFrançois Tigeot 
8288621f407SFrançois Tigeot 		crtc_state->dpll_hw_state.spll =
8298621f407SFrançois Tigeot 			SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
8308621f407SFrançois Tigeot 
8318621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
8328621f407SFrançois Tigeot 					     DPLL_ID_SPLL, DPLL_ID_SPLL);
8338621f407SFrançois Tigeot 	} else {
8348621f407SFrançois Tigeot 		return NULL;
8358621f407SFrançois Tigeot 	}
8368621f407SFrançois Tigeot 
8378621f407SFrançois Tigeot 	if (!pll)
8388621f407SFrançois Tigeot 		return NULL;
8398621f407SFrançois Tigeot 
8408621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
8418621f407SFrançois Tigeot 
8428621f407SFrançois Tigeot 	return pll;
8438621f407SFrançois Tigeot }
8448621f407SFrançois Tigeot 
hsw_dump_hw_state(struct drm_i915_private * dev_priv,struct intel_dpll_hw_state * hw_state)845a85cb24fSFrançois Tigeot static void hsw_dump_hw_state(struct drm_i915_private *dev_priv,
846a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
847a85cb24fSFrançois Tigeot {
848a85cb24fSFrançois Tigeot 	DRM_DEBUG_KMS("dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
849a85cb24fSFrançois Tigeot 		      hw_state->wrpll, hw_state->spll);
850a85cb24fSFrançois Tigeot }
851a85cb24fSFrançois Tigeot 
8528621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
8538621f407SFrançois Tigeot 	.enable = hsw_ddi_wrpll_enable,
8548621f407SFrançois Tigeot 	.disable = hsw_ddi_wrpll_disable,
8558621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_wrpll_get_hw_state,
8568621f407SFrançois Tigeot };
8578621f407SFrançois Tigeot 
8588621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_spll_funcs = {
8598621f407SFrançois Tigeot 	.enable = hsw_ddi_spll_enable,
8608621f407SFrançois Tigeot 	.disable = hsw_ddi_spll_disable,
8618621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_spll_get_hw_state,
8628621f407SFrançois Tigeot };
8638621f407SFrançois Tigeot 
hsw_ddi_lcpll_enable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)8648621f407SFrançois Tigeot static void hsw_ddi_lcpll_enable(struct drm_i915_private *dev_priv,
8658621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
8668621f407SFrançois Tigeot {
8678621f407SFrançois Tigeot }
8688621f407SFrançois Tigeot 
hsw_ddi_lcpll_disable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)8698621f407SFrançois Tigeot static void hsw_ddi_lcpll_disable(struct drm_i915_private *dev_priv,
8708621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
8718621f407SFrançois Tigeot {
8728621f407SFrançois Tigeot }
8738621f407SFrançois Tigeot 
hsw_ddi_lcpll_get_hw_state(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll,struct intel_dpll_hw_state * hw_state)8748621f407SFrançois Tigeot static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,
8758621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
8768621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
8778621f407SFrançois Tigeot {
8788621f407SFrançois Tigeot 	return true;
8798621f407SFrançois Tigeot }
8808621f407SFrançois Tigeot 
8818621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = {
8828621f407SFrançois Tigeot 	.enable = hsw_ddi_lcpll_enable,
8838621f407SFrançois Tigeot 	.disable = hsw_ddi_lcpll_disable,
8848621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_lcpll_get_hw_state,
8858621f407SFrançois Tigeot };
8868621f407SFrançois Tigeot 
8878621f407SFrançois Tigeot struct skl_dpll_regs {
8888621f407SFrançois Tigeot 	i915_reg_t ctl, cfgcr1, cfgcr2;
8898621f407SFrançois Tigeot };
8908621f407SFrançois Tigeot 
8918621f407SFrançois Tigeot /* this array is indexed by the *shared* pll id */
8928621f407SFrançois Tigeot static const struct skl_dpll_regs skl_dpll_regs[4] = {
8938621f407SFrançois Tigeot 	{
8948621f407SFrançois Tigeot 		/* DPLL 0 */
8958621f407SFrançois Tigeot 		.ctl = LCPLL1_CTL,
8968621f407SFrançois Tigeot 		/* DPLL 0 doesn't support HDMI mode */
8978621f407SFrançois Tigeot 	},
8988621f407SFrançois Tigeot 	{
8998621f407SFrançois Tigeot 		/* DPLL 1 */
9008621f407SFrançois Tigeot 		.ctl = LCPLL2_CTL,
9018621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
9028621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
9038621f407SFrançois Tigeot 	},
9048621f407SFrançois Tigeot 	{
9058621f407SFrançois Tigeot 		/* DPLL 2 */
9068621f407SFrançois Tigeot 		.ctl = WRPLL_CTL(0),
9078621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
9088621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
9098621f407SFrançois Tigeot 	},
9108621f407SFrançois Tigeot 	{
9118621f407SFrançois Tigeot 		/* DPLL 3 */
9128621f407SFrançois Tigeot 		.ctl = WRPLL_CTL(1),
9138621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
9148621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
9158621f407SFrançois Tigeot 	},
9168621f407SFrançois Tigeot };
9178621f407SFrançois Tigeot 
skl_ddi_pll_write_ctrl1(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)9188621f407SFrançois Tigeot static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *dev_priv,
9198621f407SFrançois Tigeot 				    struct intel_shared_dpll *pll)
9208621f407SFrançois Tigeot {
9218621f407SFrançois Tigeot 	uint32_t val;
9228621f407SFrançois Tigeot 
9238621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
9248621f407SFrançois Tigeot 
9258621f407SFrançois Tigeot 	val &= ~(DPLL_CTRL1_HDMI_MODE(pll->id) | DPLL_CTRL1_SSC(pll->id) |
9268621f407SFrançois Tigeot 		 DPLL_CTRL1_LINK_RATE_MASK(pll->id));
927a85cb24fSFrançois Tigeot 	val |= pll->state.hw_state.ctrl1 << (pll->id * 6);
9288621f407SFrançois Tigeot 
9298621f407SFrançois Tigeot 	I915_WRITE(DPLL_CTRL1, val);
9308621f407SFrançois Tigeot 	POSTING_READ(DPLL_CTRL1);
9318621f407SFrançois Tigeot }
9328621f407SFrançois Tigeot 
skl_ddi_pll_enable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)9338621f407SFrançois Tigeot static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
9348621f407SFrançois Tigeot 			       struct intel_shared_dpll *pll)
9358621f407SFrançois Tigeot {
9368621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
9378621f407SFrançois Tigeot 
9388621f407SFrançois Tigeot 	skl_ddi_pll_write_ctrl1(dev_priv, pll);
9398621f407SFrançois Tigeot 
940a85cb24fSFrançois Tigeot 	I915_WRITE(regs[pll->id].cfgcr1, pll->state.hw_state.cfgcr1);
941a85cb24fSFrançois Tigeot 	I915_WRITE(regs[pll->id].cfgcr2, pll->state.hw_state.cfgcr2);
9428621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].cfgcr1);
9438621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].cfgcr2);
9448621f407SFrançois Tigeot 
9458621f407SFrançois Tigeot 	/* the enable bit is always bit 31 */
9468621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].ctl,
9478621f407SFrançois Tigeot 		   I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE);
9488621f407SFrançois Tigeot 
9491487f786SFrançois Tigeot 	if (intel_wait_for_register(dev_priv,
9501487f786SFrançois Tigeot 				    DPLL_STATUS,
9511487f786SFrançois Tigeot 				    DPLL_LOCK(pll->id),
9521487f786SFrançois Tigeot 				    DPLL_LOCK(pll->id),
9531487f786SFrançois Tigeot 				    5))
9548621f407SFrançois Tigeot 		DRM_ERROR("DPLL %d not locked\n", pll->id);
9558621f407SFrançois Tigeot }
9568621f407SFrançois Tigeot 
skl_ddi_dpll0_enable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)9578621f407SFrançois Tigeot static void skl_ddi_dpll0_enable(struct drm_i915_private *dev_priv,
9588621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
9598621f407SFrançois Tigeot {
9608621f407SFrançois Tigeot 	skl_ddi_pll_write_ctrl1(dev_priv, pll);
9618621f407SFrançois Tigeot }
9628621f407SFrançois Tigeot 
skl_ddi_pll_disable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)9638621f407SFrançois Tigeot static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
9648621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
9658621f407SFrançois Tigeot {
9668621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
9678621f407SFrançois Tigeot 
9688621f407SFrançois Tigeot 	/* the enable bit is always bit 31 */
9698621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].ctl,
9708621f407SFrançois Tigeot 		   I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE);
9718621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].ctl);
9728621f407SFrançois Tigeot }
9738621f407SFrançois Tigeot 
skl_ddi_dpll0_disable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)9748621f407SFrançois Tigeot static void skl_ddi_dpll0_disable(struct drm_i915_private *dev_priv,
9758621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
9768621f407SFrançois Tigeot {
9778621f407SFrançois Tigeot }
9788621f407SFrançois Tigeot 
skl_ddi_pll_get_hw_state(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll,struct intel_dpll_hw_state * hw_state)9798621f407SFrançois Tigeot static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
9808621f407SFrançois Tigeot 				     struct intel_shared_dpll *pll,
9818621f407SFrançois Tigeot 				     struct intel_dpll_hw_state *hw_state)
9828621f407SFrançois Tigeot {
9838621f407SFrançois Tigeot 	uint32_t val;
9848621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
9858621f407SFrançois Tigeot 	bool ret;
9868621f407SFrançois Tigeot 
9878621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
9888621f407SFrançois Tigeot 		return false;
9898621f407SFrançois Tigeot 
9908621f407SFrançois Tigeot 	ret = false;
9918621f407SFrançois Tigeot 
9928621f407SFrançois Tigeot 	val = I915_READ(regs[pll->id].ctl);
9938621f407SFrançois Tigeot 	if (!(val & LCPLL_PLL_ENABLE))
9948621f407SFrançois Tigeot 		goto out;
9958621f407SFrançois Tigeot 
9968621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
9978621f407SFrançois Tigeot 	hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
9988621f407SFrançois Tigeot 
9998621f407SFrançois Tigeot 	/* avoid reading back stale values if HDMI mode is not enabled */
10008621f407SFrançois Tigeot 	if (val & DPLL_CTRL1_HDMI_MODE(pll->id)) {
10018621f407SFrançois Tigeot 		hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
10028621f407SFrançois Tigeot 		hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
10038621f407SFrançois Tigeot 	}
10048621f407SFrançois Tigeot 	ret = true;
10058621f407SFrançois Tigeot 
10068621f407SFrançois Tigeot out:
10078621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
10088621f407SFrançois Tigeot 
10098621f407SFrançois Tigeot 	return ret;
10108621f407SFrançois Tigeot }
10118621f407SFrançois Tigeot 
skl_ddi_dpll0_get_hw_state(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll,struct intel_dpll_hw_state * hw_state)10128621f407SFrançois Tigeot static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
10138621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
10148621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
10158621f407SFrançois Tigeot {
10168621f407SFrançois Tigeot 	uint32_t val;
10178621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
10188621f407SFrançois Tigeot 	bool ret;
10198621f407SFrançois Tigeot 
10208621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
10218621f407SFrançois Tigeot 		return false;
10228621f407SFrançois Tigeot 
10238621f407SFrançois Tigeot 	ret = false;
10248621f407SFrançois Tigeot 
10258621f407SFrançois Tigeot 	/* DPLL0 is always enabled since it drives CDCLK */
10268621f407SFrançois Tigeot 	val = I915_READ(regs[pll->id].ctl);
10278621f407SFrançois Tigeot 	if (WARN_ON(!(val & LCPLL_PLL_ENABLE)))
10288621f407SFrançois Tigeot 		goto out;
10298621f407SFrançois Tigeot 
10308621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
10318621f407SFrançois Tigeot 	hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
10328621f407SFrançois Tigeot 
10338621f407SFrançois Tigeot 	ret = true;
10348621f407SFrançois Tigeot 
10358621f407SFrançois Tigeot out:
10368621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
10378621f407SFrançois Tigeot 
10388621f407SFrançois Tigeot 	return ret;
10398621f407SFrançois Tigeot }
10408621f407SFrançois Tigeot 
10418621f407SFrançois Tigeot struct skl_wrpll_context {
10428621f407SFrançois Tigeot 	uint64_t min_deviation;		/* current minimal deviation */
10438621f407SFrançois Tigeot 	uint64_t central_freq;		/* chosen central freq */
10448621f407SFrançois Tigeot 	uint64_t dco_freq;		/* chosen dco freq */
10458621f407SFrançois Tigeot 	unsigned int p;			/* chosen divider */
10468621f407SFrançois Tigeot };
10478621f407SFrançois Tigeot 
skl_wrpll_context_init(struct skl_wrpll_context * ctx)10488621f407SFrançois Tigeot static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
10498621f407SFrançois Tigeot {
10508621f407SFrançois Tigeot 	memset(ctx, 0, sizeof(*ctx));
10518621f407SFrançois Tigeot 
10528621f407SFrançois Tigeot 	ctx->min_deviation = U64_MAX;
10538621f407SFrançois Tigeot }
10548621f407SFrançois Tigeot 
10558621f407SFrançois Tigeot /* DCO freq must be within +1%/-6%  of the DCO central freq */
10568621f407SFrançois Tigeot #define SKL_DCO_MAX_PDEVIATION	100
10578621f407SFrançois Tigeot #define SKL_DCO_MAX_NDEVIATION	600
10588621f407SFrançois Tigeot 
skl_wrpll_try_divider(struct skl_wrpll_context * ctx,uint64_t central_freq,uint64_t dco_freq,unsigned int divider)10598621f407SFrançois Tigeot static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
10608621f407SFrançois Tigeot 				  uint64_t central_freq,
10618621f407SFrançois Tigeot 				  uint64_t dco_freq,
10628621f407SFrançois Tigeot 				  unsigned int divider)
10638621f407SFrançois Tigeot {
10648621f407SFrançois Tigeot 	uint64_t deviation;
10658621f407SFrançois Tigeot 
10668621f407SFrançois Tigeot 	deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
10678621f407SFrançois Tigeot 			      central_freq);
10688621f407SFrançois Tigeot 
10698621f407SFrançois Tigeot 	/* positive deviation */
10708621f407SFrançois Tigeot 	if (dco_freq >= central_freq) {
10718621f407SFrançois Tigeot 		if (deviation < SKL_DCO_MAX_PDEVIATION &&
10728621f407SFrançois Tigeot 		    deviation < ctx->min_deviation) {
10738621f407SFrançois Tigeot 			ctx->min_deviation = deviation;
10748621f407SFrançois Tigeot 			ctx->central_freq = central_freq;
10758621f407SFrançois Tigeot 			ctx->dco_freq = dco_freq;
10768621f407SFrançois Tigeot 			ctx->p = divider;
10778621f407SFrançois Tigeot 		}
10788621f407SFrançois Tigeot 	/* negative deviation */
10798621f407SFrançois Tigeot 	} else if (deviation < SKL_DCO_MAX_NDEVIATION &&
10808621f407SFrançois Tigeot 		   deviation < ctx->min_deviation) {
10818621f407SFrançois Tigeot 		ctx->min_deviation = deviation;
10828621f407SFrançois Tigeot 		ctx->central_freq = central_freq;
10838621f407SFrançois Tigeot 		ctx->dco_freq = dco_freq;
10848621f407SFrançois Tigeot 		ctx->p = divider;
10858621f407SFrançois Tigeot 	}
10868621f407SFrançois Tigeot }
10878621f407SFrançois Tigeot 
skl_wrpll_get_multipliers(unsigned int p,unsigned int * p0,unsigned int * p1,unsigned int * p2)10888621f407SFrançois Tigeot static void skl_wrpll_get_multipliers(unsigned int p,
10898621f407SFrançois Tigeot 				      unsigned int *p0 /* out */,
10908621f407SFrançois Tigeot 				      unsigned int *p1 /* out */,
10918621f407SFrançois Tigeot 				      unsigned int *p2 /* out */)
10928621f407SFrançois Tigeot {
10938621f407SFrançois Tigeot 	/* even dividers */
10948621f407SFrançois Tigeot 	if (p % 2 == 0) {
10958621f407SFrançois Tigeot 		unsigned int half = p / 2;
10968621f407SFrançois Tigeot 
10978621f407SFrançois Tigeot 		if (half == 1 || half == 2 || half == 3 || half == 5) {
10988621f407SFrançois Tigeot 			*p0 = 2;
10998621f407SFrançois Tigeot 			*p1 = 1;
11008621f407SFrançois Tigeot 			*p2 = half;
11018621f407SFrançois Tigeot 		} else if (half % 2 == 0) {
11028621f407SFrançois Tigeot 			*p0 = 2;
11038621f407SFrançois Tigeot 			*p1 = half / 2;
11048621f407SFrançois Tigeot 			*p2 = 2;
11058621f407SFrançois Tigeot 		} else if (half % 3 == 0) {
11068621f407SFrançois Tigeot 			*p0 = 3;
11078621f407SFrançois Tigeot 			*p1 = half / 3;
11088621f407SFrançois Tigeot 			*p2 = 2;
11098621f407SFrançois Tigeot 		} else if (half % 7 == 0) {
11108621f407SFrançois Tigeot 			*p0 = 7;
11118621f407SFrançois Tigeot 			*p1 = half / 7;
11128621f407SFrançois Tigeot 			*p2 = 2;
11138621f407SFrançois Tigeot 		}
11148621f407SFrançois Tigeot 	} else if (p == 3 || p == 9) {  /* 3, 5, 7, 9, 15, 21, 35 */
11158621f407SFrançois Tigeot 		*p0 = 3;
11168621f407SFrançois Tigeot 		*p1 = 1;
11178621f407SFrançois Tigeot 		*p2 = p / 3;
11188621f407SFrançois Tigeot 	} else if (p == 5 || p == 7) {
11198621f407SFrançois Tigeot 		*p0 = p;
11208621f407SFrançois Tigeot 		*p1 = 1;
11218621f407SFrançois Tigeot 		*p2 = 1;
11228621f407SFrançois Tigeot 	} else if (p == 15) {
11238621f407SFrançois Tigeot 		*p0 = 3;
11248621f407SFrançois Tigeot 		*p1 = 1;
11258621f407SFrançois Tigeot 		*p2 = 5;
11268621f407SFrançois Tigeot 	} else if (p == 21) {
11278621f407SFrançois Tigeot 		*p0 = 7;
11288621f407SFrançois Tigeot 		*p1 = 1;
11298621f407SFrançois Tigeot 		*p2 = 3;
11308621f407SFrançois Tigeot 	} else if (p == 35) {
11318621f407SFrançois Tigeot 		*p0 = 7;
11328621f407SFrançois Tigeot 		*p1 = 1;
11338621f407SFrançois Tigeot 		*p2 = 5;
11348621f407SFrançois Tigeot 	}
11358621f407SFrançois Tigeot }
11368621f407SFrançois Tigeot 
11378621f407SFrançois Tigeot struct skl_wrpll_params {
11388621f407SFrançois Tigeot 	uint32_t        dco_fraction;
11398621f407SFrançois Tigeot 	uint32_t        dco_integer;
11408621f407SFrançois Tigeot 	uint32_t        qdiv_ratio;
11418621f407SFrançois Tigeot 	uint32_t        qdiv_mode;
11428621f407SFrançois Tigeot 	uint32_t        kdiv;
11438621f407SFrançois Tigeot 	uint32_t        pdiv;
11448621f407SFrançois Tigeot 	uint32_t        central_freq;
11458621f407SFrançois Tigeot };
11468621f407SFrançois Tigeot 
skl_wrpll_params_populate(struct skl_wrpll_params * params,uint64_t afe_clock,uint64_t central_freq,uint32_t p0,uint32_t p1,uint32_t p2)11478621f407SFrançois Tigeot static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
11488621f407SFrançois Tigeot 				      uint64_t afe_clock,
11498621f407SFrançois Tigeot 				      uint64_t central_freq,
11508621f407SFrançois Tigeot 				      uint32_t p0, uint32_t p1, uint32_t p2)
11518621f407SFrançois Tigeot {
11528621f407SFrançois Tigeot 	uint64_t dco_freq;
11538621f407SFrançois Tigeot 
11548621f407SFrançois Tigeot 	switch (central_freq) {
11558621f407SFrançois Tigeot 	case 9600000000ULL:
11568621f407SFrançois Tigeot 		params->central_freq = 0;
11578621f407SFrançois Tigeot 		break;
11588621f407SFrançois Tigeot 	case 9000000000ULL:
11598621f407SFrançois Tigeot 		params->central_freq = 1;
11608621f407SFrançois Tigeot 		break;
11618621f407SFrançois Tigeot 	case 8400000000ULL:
11628621f407SFrançois Tigeot 		params->central_freq = 3;
11638621f407SFrançois Tigeot 	}
11648621f407SFrançois Tigeot 
11658621f407SFrançois Tigeot 	switch (p0) {
11668621f407SFrançois Tigeot 	case 1:
11678621f407SFrançois Tigeot 		params->pdiv = 0;
11688621f407SFrançois Tigeot 		break;
11698621f407SFrançois Tigeot 	case 2:
11708621f407SFrançois Tigeot 		params->pdiv = 1;
11718621f407SFrançois Tigeot 		break;
11728621f407SFrançois Tigeot 	case 3:
11738621f407SFrançois Tigeot 		params->pdiv = 2;
11748621f407SFrançois Tigeot 		break;
11758621f407SFrançois Tigeot 	case 7:
11768621f407SFrançois Tigeot 		params->pdiv = 4;
11778621f407SFrançois Tigeot 		break;
11788621f407SFrançois Tigeot 	default:
11798621f407SFrançois Tigeot 		WARN(1, "Incorrect PDiv\n");
11808621f407SFrançois Tigeot 	}
11818621f407SFrançois Tigeot 
11828621f407SFrançois Tigeot 	switch (p2) {
11838621f407SFrançois Tigeot 	case 5:
11848621f407SFrançois Tigeot 		params->kdiv = 0;
11858621f407SFrançois Tigeot 		break;
11868621f407SFrançois Tigeot 	case 2:
11878621f407SFrançois Tigeot 		params->kdiv = 1;
11888621f407SFrançois Tigeot 		break;
11898621f407SFrançois Tigeot 	case 3:
11908621f407SFrançois Tigeot 		params->kdiv = 2;
11918621f407SFrançois Tigeot 		break;
11928621f407SFrançois Tigeot 	case 1:
11938621f407SFrançois Tigeot 		params->kdiv = 3;
11948621f407SFrançois Tigeot 		break;
11958621f407SFrançois Tigeot 	default:
11968621f407SFrançois Tigeot 		WARN(1, "Incorrect KDiv\n");
11978621f407SFrançois Tigeot 	}
11988621f407SFrançois Tigeot 
11998621f407SFrançois Tigeot 	params->qdiv_ratio = p1;
12008621f407SFrançois Tigeot 	params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
12018621f407SFrançois Tigeot 
12028621f407SFrançois Tigeot 	dco_freq = p0 * p1 * p2 * afe_clock;
12038621f407SFrançois Tigeot 
12048621f407SFrançois Tigeot 	/*
12058621f407SFrançois Tigeot 	 * Intermediate values are in Hz.
12068621f407SFrançois Tigeot 	 * Divide by MHz to match bsepc
12078621f407SFrançois Tigeot 	 */
12088621f407SFrançois Tigeot 	params->dco_integer = div_u64(dco_freq, 24 * MHz(1));
12098621f407SFrançois Tigeot 	params->dco_fraction =
12108621f407SFrançois Tigeot 		div_u64((div_u64(dco_freq, 24) -
12118621f407SFrançois Tigeot 			 params->dco_integer * MHz(1)) * 0x8000, MHz(1));
12128621f407SFrançois Tigeot }
12138621f407SFrançois Tigeot 
12148621f407SFrançois Tigeot static bool
skl_ddi_calculate_wrpll(int clock,struct skl_wrpll_params * wrpll_params)12158621f407SFrançois Tigeot skl_ddi_calculate_wrpll(int clock /* in Hz */,
12168621f407SFrançois Tigeot 			struct skl_wrpll_params *wrpll_params)
12178621f407SFrançois Tigeot {
12188621f407SFrançois Tigeot 	uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
12198621f407SFrançois Tigeot 	uint64_t dco_central_freq[3] = {8400000000ULL,
12208621f407SFrançois Tigeot 					9000000000ULL,
12218621f407SFrançois Tigeot 					9600000000ULL};
12228621f407SFrançois Tigeot 	static const int even_dividers[] = {  4,  6,  8, 10, 12, 14, 16, 18, 20,
12238621f407SFrançois Tigeot 					     24, 28, 30, 32, 36, 40, 42, 44,
12248621f407SFrançois Tigeot 					     48, 52, 54, 56, 60, 64, 66, 68,
12258621f407SFrançois Tigeot 					     70, 72, 76, 78, 80, 84, 88, 90,
12268621f407SFrançois Tigeot 					     92, 96, 98 };
12278621f407SFrançois Tigeot 	static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
12288621f407SFrançois Tigeot 	static const struct {
12298621f407SFrançois Tigeot 		const int *list;
12308621f407SFrançois Tigeot 		int n_dividers;
12318621f407SFrançois Tigeot 	} dividers[] = {
12328621f407SFrançois Tigeot 		{ even_dividers, ARRAY_SIZE(even_dividers) },
12338621f407SFrançois Tigeot 		{ odd_dividers, ARRAY_SIZE(odd_dividers) },
12348621f407SFrançois Tigeot 	};
12358621f407SFrançois Tigeot 	struct skl_wrpll_context ctx;
12368621f407SFrançois Tigeot 	unsigned int dco, d, i;
12378621f407SFrançois Tigeot 	unsigned int p0, p1, p2;
12388621f407SFrançois Tigeot 
12398621f407SFrançois Tigeot 	skl_wrpll_context_init(&ctx);
12408621f407SFrançois Tigeot 
12418621f407SFrançois Tigeot 	for (d = 0; d < ARRAY_SIZE(dividers); d++) {
12428621f407SFrançois Tigeot 		for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
12438621f407SFrançois Tigeot 			for (i = 0; i < dividers[d].n_dividers; i++) {
12448621f407SFrançois Tigeot 				unsigned int p = dividers[d].list[i];
12458621f407SFrançois Tigeot 				uint64_t dco_freq = p * afe_clock;
12468621f407SFrançois Tigeot 
12478621f407SFrançois Tigeot 				skl_wrpll_try_divider(&ctx,
12488621f407SFrançois Tigeot 						      dco_central_freq[dco],
12498621f407SFrançois Tigeot 						      dco_freq,
12508621f407SFrançois Tigeot 						      p);
12518621f407SFrançois Tigeot 				/*
12528621f407SFrançois Tigeot 				 * Skip the remaining dividers if we're sure to
12538621f407SFrançois Tigeot 				 * have found the definitive divider, we can't
12548621f407SFrançois Tigeot 				 * improve a 0 deviation.
12558621f407SFrançois Tigeot 				 */
12568621f407SFrançois Tigeot 				if (ctx.min_deviation == 0)
12578621f407SFrançois Tigeot 					goto skip_remaining_dividers;
12588621f407SFrançois Tigeot 			}
12598621f407SFrançois Tigeot 		}
12608621f407SFrançois Tigeot 
12618621f407SFrançois Tigeot skip_remaining_dividers:
12628621f407SFrançois Tigeot 		/*
12638621f407SFrançois Tigeot 		 * If a solution is found with an even divider, prefer
12648621f407SFrançois Tigeot 		 * this one.
12658621f407SFrançois Tigeot 		 */
12668621f407SFrançois Tigeot 		if (d == 0 && ctx.p)
12678621f407SFrançois Tigeot 			break;
12688621f407SFrançois Tigeot 	}
12698621f407SFrançois Tigeot 
12708621f407SFrançois Tigeot 	if (!ctx.p) {
12718621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
12728621f407SFrançois Tigeot 		return false;
12738621f407SFrançois Tigeot 	}
12748621f407SFrançois Tigeot 
12758621f407SFrançois Tigeot 	/*
12768621f407SFrançois Tigeot 	 * gcc incorrectly analyses that these can be used without being
12778621f407SFrançois Tigeot 	 * initialized. To be fair, it's hard to guess.
12788621f407SFrançois Tigeot 	 */
12798621f407SFrançois Tigeot 	p0 = p1 = p2 = 0;
12808621f407SFrançois Tigeot 	skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
12818621f407SFrançois Tigeot 	skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq,
12828621f407SFrançois Tigeot 				  p0, p1, p2);
12838621f407SFrançois Tigeot 
12848621f407SFrançois Tigeot 	return true;
12858621f407SFrançois Tigeot }
12868621f407SFrançois Tigeot 
skl_ddi_hdmi_pll_dividers(struct intel_crtc * crtc,struct intel_crtc_state * crtc_state,int clock)12871e12ee3bSFrançois Tigeot static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc *crtc,
12881e12ee3bSFrançois Tigeot 				      struct intel_crtc_state *crtc_state,
12891e12ee3bSFrançois Tigeot 				      int clock)
12908621f407SFrançois Tigeot {
12918621f407SFrançois Tigeot 	uint32_t ctrl1, cfgcr1, cfgcr2;
12921e12ee3bSFrançois Tigeot 	struct skl_wrpll_params wrpll_params = { 0, };
12938621f407SFrançois Tigeot 
12948621f407SFrançois Tigeot 	/*
12958621f407SFrançois Tigeot 	 * See comment in intel_dpll_hw_state to understand why we always use 0
12968621f407SFrançois Tigeot 	 * as the DPLL id in this function.
12978621f407SFrançois Tigeot 	 */
12988621f407SFrançois Tigeot 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
12998621f407SFrançois Tigeot 
13008621f407SFrançois Tigeot 	ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
13018621f407SFrançois Tigeot 
13028621f407SFrançois Tigeot 	if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
13031e12ee3bSFrançois Tigeot 		return false;
13048621f407SFrançois Tigeot 
13058621f407SFrançois Tigeot 	cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
13068621f407SFrançois Tigeot 		DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
13078621f407SFrançois Tigeot 		wrpll_params.dco_integer;
13088621f407SFrançois Tigeot 
13098621f407SFrançois Tigeot 	cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
13108621f407SFrançois Tigeot 		DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
13118621f407SFrançois Tigeot 		DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
13128621f407SFrançois Tigeot 		DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
13138621f407SFrançois Tigeot 		wrpll_params.central_freq;
13141e12ee3bSFrançois Tigeot 
13151e12ee3bSFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
13161e12ee3bSFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
13171e12ee3bSFrançois Tigeot 
13181e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state.ctrl1 = ctrl1;
13191e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
13201e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
13211e12ee3bSFrançois Tigeot 	return true;
13221e12ee3bSFrançois Tigeot }
13231e12ee3bSFrançois Tigeot 
1324a85cb24fSFrançois Tigeot static bool
skl_ddi_dp_set_dpll_hw_state(int clock,struct intel_dpll_hw_state * dpll_hw_state)1325a85cb24fSFrançois Tigeot skl_ddi_dp_set_dpll_hw_state(int clock,
13261e12ee3bSFrançois Tigeot 			     struct intel_dpll_hw_state *dpll_hw_state)
13271e12ee3bSFrançois Tigeot {
13281e12ee3bSFrançois Tigeot 	uint32_t ctrl1;
13291e12ee3bSFrançois Tigeot 
13301e12ee3bSFrançois Tigeot 	/*
13311e12ee3bSFrançois Tigeot 	 * See comment in intel_dpll_hw_state to understand why we always use 0
13321e12ee3bSFrançois Tigeot 	 * as the DPLL id in this function.
13331e12ee3bSFrançois Tigeot 	 */
13341e12ee3bSFrançois Tigeot 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
13351e12ee3bSFrançois Tigeot 	switch (clock / 2) {
13368621f407SFrançois Tigeot 	case 81000:
13378621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
13388621f407SFrançois Tigeot 		break;
13398621f407SFrançois Tigeot 	case 135000:
13408621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
13418621f407SFrançois Tigeot 		break;
13428621f407SFrançois Tigeot 	case 270000:
13438621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
13448621f407SFrançois Tigeot 		break;
13458621f407SFrançois Tigeot 		/* eDP 1.4 rates */
13468621f407SFrançois Tigeot 	case 162000:
13478621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
13488621f407SFrançois Tigeot 		break;
13498621f407SFrançois Tigeot 	case 108000:
13508621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
13518621f407SFrançois Tigeot 		break;
13528621f407SFrançois Tigeot 	case 216000:
13538621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
13548621f407SFrançois Tigeot 		break;
13558621f407SFrançois Tigeot 	}
13568621f407SFrançois Tigeot 
13571e12ee3bSFrançois Tigeot 	dpll_hw_state->ctrl1 = ctrl1;
13581e12ee3bSFrançois Tigeot 	return true;
13591e12ee3bSFrançois Tigeot }
13601e12ee3bSFrançois Tigeot 
13611e12ee3bSFrançois Tigeot static struct intel_shared_dpll *
skl_get_dpll(struct intel_crtc * crtc,struct intel_crtc_state * crtc_state,struct intel_encoder * encoder)13621e12ee3bSFrançois Tigeot skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
13631e12ee3bSFrançois Tigeot 	     struct intel_encoder *encoder)
13641e12ee3bSFrançois Tigeot {
13651e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
13661e12ee3bSFrançois Tigeot 	int clock = crtc_state->port_clock;
13671e12ee3bSFrançois Tigeot 	bool bret;
13681e12ee3bSFrançois Tigeot 	struct intel_dpll_hw_state dpll_hw_state;
13691e12ee3bSFrançois Tigeot 
13701e12ee3bSFrançois Tigeot 	memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
13711e12ee3bSFrançois Tigeot 
13721e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI) {
13731e12ee3bSFrançois Tigeot 		bret = skl_ddi_hdmi_pll_dividers(crtc, crtc_state, clock);
13741e12ee3bSFrançois Tigeot 		if (!bret) {
13751e12ee3bSFrançois Tigeot 			DRM_DEBUG_KMS("Could not get HDMI pll dividers.\n");
13761e12ee3bSFrançois Tigeot 			return NULL;
13771e12ee3bSFrançois Tigeot 		}
13781e12ee3bSFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_DP ||
13791e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_DP_MST ||
13801e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_EDP) {
13811e12ee3bSFrançois Tigeot 		bret = skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state);
13821e12ee3bSFrançois Tigeot 		if (!bret) {
13831e12ee3bSFrançois Tigeot 			DRM_DEBUG_KMS("Could not set DP dpll HW state.\n");
13841e12ee3bSFrançois Tigeot 			return NULL;
13851e12ee3bSFrançois Tigeot 		}
13861e12ee3bSFrançois Tigeot 		crtc_state->dpll_hw_state = dpll_hw_state;
13878621f407SFrançois Tigeot 	} else {
13888621f407SFrançois Tigeot 		return NULL;
13898621f407SFrançois Tigeot 	}
13908621f407SFrançois Tigeot 
13918621f407SFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_EDP)
13928621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
13938621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL0,
13948621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL0);
13958621f407SFrançois Tigeot 	else
13968621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
13978621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL1,
13988621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL3);
13998621f407SFrançois Tigeot 	if (!pll)
14008621f407SFrançois Tigeot 		return NULL;
14018621f407SFrançois Tigeot 
14028621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
14038621f407SFrançois Tigeot 
14048621f407SFrançois Tigeot 	return pll;
14058621f407SFrançois Tigeot }
14068621f407SFrançois Tigeot 
skl_dump_hw_state(struct drm_i915_private * dev_priv,struct intel_dpll_hw_state * hw_state)1407a85cb24fSFrançois Tigeot static void skl_dump_hw_state(struct drm_i915_private *dev_priv,
1408a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
1409a85cb24fSFrançois Tigeot {
1410a85cb24fSFrançois Tigeot 	DRM_DEBUG_KMS("dpll_hw_state: "
1411a85cb24fSFrançois Tigeot 		      "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n",
1412a85cb24fSFrançois Tigeot 		      hw_state->ctrl1,
1413a85cb24fSFrançois Tigeot 		      hw_state->cfgcr1,
1414a85cb24fSFrançois Tigeot 		      hw_state->cfgcr2);
1415a85cb24fSFrançois Tigeot }
1416a85cb24fSFrançois Tigeot 
14178621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs skl_ddi_pll_funcs = {
14188621f407SFrançois Tigeot 	.enable = skl_ddi_pll_enable,
14198621f407SFrançois Tigeot 	.disable = skl_ddi_pll_disable,
14208621f407SFrançois Tigeot 	.get_hw_state = skl_ddi_pll_get_hw_state,
14218621f407SFrançois Tigeot };
14228621f407SFrançois Tigeot 
14238621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = {
14248621f407SFrançois Tigeot 	.enable = skl_ddi_dpll0_enable,
14258621f407SFrançois Tigeot 	.disable = skl_ddi_dpll0_disable,
14268621f407SFrançois Tigeot 	.get_hw_state = skl_ddi_dpll0_get_hw_state,
14278621f407SFrançois Tigeot };
14288621f407SFrançois Tigeot 
bxt_ddi_pll_enable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)14298621f407SFrançois Tigeot static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
14308621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
14318621f407SFrançois Tigeot {
14328621f407SFrançois Tigeot 	uint32_t temp;
14338621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
14344be47400SFrançois Tigeot 	enum dpio_phy phy;
14354be47400SFrançois Tigeot 	enum dpio_channel ch;
14364be47400SFrançois Tigeot 
1437a85cb24fSFrançois Tigeot 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
14388621f407SFrançois Tigeot 
14398621f407SFrançois Tigeot 	/* Non-SSC reference */
14408621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
14418621f407SFrançois Tigeot 	temp |= PORT_PLL_REF_SEL;
14428621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
14438621f407SFrançois Tigeot 
1444a85cb24fSFrançois Tigeot 	if (IS_GEMINILAKE(dev_priv)) {
1445a85cb24fSFrançois Tigeot 		temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
1446a85cb24fSFrançois Tigeot 		temp |= PORT_PLL_POWER_ENABLE;
1447a85cb24fSFrançois Tigeot 		I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
1448a85cb24fSFrançois Tigeot 
1449a85cb24fSFrançois Tigeot 		if (wait_for_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) &
1450a85cb24fSFrançois Tigeot 				 PORT_PLL_POWER_STATE), 200))
1451a85cb24fSFrançois Tigeot 			DRM_ERROR("Power state not set for PLL:%d\n", port);
1452a85cb24fSFrançois Tigeot 	}
1453a85cb24fSFrançois Tigeot 
14548621f407SFrançois Tigeot 	/* Disable 10 bit clock */
14554be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_4(phy, ch));
14568621f407SFrançois Tigeot 	temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
14574be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(phy, ch), temp);
14588621f407SFrançois Tigeot 
14598621f407SFrançois Tigeot 	/* Write P1 & P2 */
14604be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_0(phy, ch));
14618621f407SFrançois Tigeot 	temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK);
1462a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.ebb0;
14634be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_0(phy, ch), temp);
14648621f407SFrançois Tigeot 
14658621f407SFrançois Tigeot 	/* Write M2 integer */
14664be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 0));
14678621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_MASK;
1468a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll0;
14694be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 0), temp);
14708621f407SFrançois Tigeot 
14718621f407SFrançois Tigeot 	/* Write N */
14724be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 1));
14738621f407SFrançois Tigeot 	temp &= ~PORT_PLL_N_MASK;
1474a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll1;
14754be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 1), temp);
14768621f407SFrançois Tigeot 
14778621f407SFrançois Tigeot 	/* Write M2 fraction */
14784be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 2));
14798621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_FRAC_MASK;
1480a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll2;
14814be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 2), temp);
14828621f407SFrançois Tigeot 
14838621f407SFrançois Tigeot 	/* Write M2 fraction enable */
14844be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 3));
14858621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_FRAC_ENABLE;
1486a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll3;
14874be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 3), temp);
14888621f407SFrançois Tigeot 
14898621f407SFrançois Tigeot 	/* Write coeff */
14904be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 6));
14918621f407SFrançois Tigeot 	temp &= ~PORT_PLL_PROP_COEFF_MASK;
14928621f407SFrançois Tigeot 	temp &= ~PORT_PLL_INT_COEFF_MASK;
14938621f407SFrançois Tigeot 	temp &= ~PORT_PLL_GAIN_CTL_MASK;
1494a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll6;
14954be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 6), temp);
14968621f407SFrançois Tigeot 
14978621f407SFrançois Tigeot 	/* Write calibration val */
14984be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 8));
14998621f407SFrançois Tigeot 	temp &= ~PORT_PLL_TARGET_CNT_MASK;
1500a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll8;
15014be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 8), temp);
15028621f407SFrançois Tigeot 
15034be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 9));
15048621f407SFrançois Tigeot 	temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK;
1505a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll9;
15064be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 9), temp);
15078621f407SFrançois Tigeot 
15084be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(phy, ch, 10));
15098621f407SFrançois Tigeot 	temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H;
15108621f407SFrançois Tigeot 	temp &= ~PORT_PLL_DCO_AMP_MASK;
1511a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pll10;
15124be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(phy, ch, 10), temp);
15138621f407SFrançois Tigeot 
15148621f407SFrançois Tigeot 	/* Recalibrate with new settings */
15154be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_4(phy, ch));
15168621f407SFrançois Tigeot 	temp |= PORT_PLL_RECALIBRATE;
15174be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(phy, ch), temp);
15188621f407SFrançois Tigeot 	temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
1519a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.ebb4;
15204be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(phy, ch), temp);
15218621f407SFrançois Tigeot 
15228621f407SFrançois Tigeot 	/* Enable PLL */
15238621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
15248621f407SFrançois Tigeot 	temp |= PORT_PLL_ENABLE;
15258621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
15268621f407SFrançois Tigeot 	POSTING_READ(BXT_PORT_PLL_ENABLE(port));
15278621f407SFrançois Tigeot 
15288621f407SFrançois Tigeot 	if (wait_for_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_LOCK),
15298621f407SFrançois Tigeot 			200))
15308621f407SFrançois Tigeot 		DRM_ERROR("PLL %d not locked\n", port);
15318621f407SFrançois Tigeot 
1532a85cb24fSFrançois Tigeot 	if (IS_GEMINILAKE(dev_priv)) {
1533a85cb24fSFrançois Tigeot 		temp = I915_READ(BXT_PORT_TX_DW5_LN0(phy, ch));
1534a85cb24fSFrançois Tigeot 		temp |= DCC_DELAY_RANGE_2;
1535a85cb24fSFrançois Tigeot 		I915_WRITE(BXT_PORT_TX_DW5_GRP(phy, ch), temp);
1536a85cb24fSFrançois Tigeot 	}
1537a85cb24fSFrançois Tigeot 
15388621f407SFrançois Tigeot 	/*
15398621f407SFrançois Tigeot 	 * While we write to the group register to program all lanes at once we
15408621f407SFrançois Tigeot 	 * can read only lane registers and we pick lanes 0/1 for that.
15418621f407SFrançois Tigeot 	 */
15424be47400SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PCS_DW12_LN01(phy, ch));
15438621f407SFrançois Tigeot 	temp &= ~LANE_STAGGER_MASK;
15448621f407SFrançois Tigeot 	temp &= ~LANESTAGGER_STRAP_OVRD;
1545a85cb24fSFrançois Tigeot 	temp |= pll->state.hw_state.pcsdw12;
15464be47400SFrançois Tigeot 	I915_WRITE(BXT_PORT_PCS_DW12_GRP(phy, ch), temp);
15478621f407SFrançois Tigeot }
15488621f407SFrançois Tigeot 
bxt_ddi_pll_disable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)15498621f407SFrançois Tigeot static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
15508621f407SFrançois Tigeot 					struct intel_shared_dpll *pll)
15518621f407SFrançois Tigeot {
15528621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
15538621f407SFrançois Tigeot 	uint32_t temp;
15548621f407SFrançois Tigeot 
15558621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
15568621f407SFrançois Tigeot 	temp &= ~PORT_PLL_ENABLE;
15578621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
15588621f407SFrançois Tigeot 	POSTING_READ(BXT_PORT_PLL_ENABLE(port));
1559a85cb24fSFrançois Tigeot 
1560a85cb24fSFrançois Tigeot 	if (IS_GEMINILAKE(dev_priv)) {
1561a85cb24fSFrançois Tigeot 		temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
1562a85cb24fSFrançois Tigeot 		temp &= ~PORT_PLL_POWER_ENABLE;
1563a85cb24fSFrançois Tigeot 		I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
1564a85cb24fSFrançois Tigeot 
1565a85cb24fSFrançois Tigeot 		if (wait_for_us(!(I915_READ(BXT_PORT_PLL_ENABLE(port)) &
1566a85cb24fSFrançois Tigeot 				PORT_PLL_POWER_STATE), 200))
1567a85cb24fSFrançois Tigeot 			DRM_ERROR("Power state not reset for PLL:%d\n", port);
1568a85cb24fSFrançois Tigeot 	}
15698621f407SFrançois Tigeot }
15708621f407SFrançois Tigeot 
bxt_ddi_pll_get_hw_state(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll,struct intel_dpll_hw_state * hw_state)15718621f407SFrançois Tigeot static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
15728621f407SFrançois Tigeot 					struct intel_shared_dpll *pll,
15738621f407SFrançois Tigeot 					struct intel_dpll_hw_state *hw_state)
15748621f407SFrançois Tigeot {
15758621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
15768621f407SFrançois Tigeot 	uint32_t val;
15778621f407SFrançois Tigeot 	bool ret;
15784be47400SFrançois Tigeot 	enum dpio_phy phy;
15794be47400SFrançois Tigeot 	enum dpio_channel ch;
15804be47400SFrançois Tigeot 
1581a85cb24fSFrançois Tigeot 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
15828621f407SFrançois Tigeot 
15838621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
15848621f407SFrançois Tigeot 		return false;
15858621f407SFrançois Tigeot 
15868621f407SFrançois Tigeot 	ret = false;
15878621f407SFrançois Tigeot 
15888621f407SFrançois Tigeot 	val = I915_READ(BXT_PORT_PLL_ENABLE(port));
15898621f407SFrançois Tigeot 	if (!(val & PORT_PLL_ENABLE))
15908621f407SFrançois Tigeot 		goto out;
15918621f407SFrançois Tigeot 
15924be47400SFrançois Tigeot 	hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(phy, ch));
15938621f407SFrançois Tigeot 	hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
15948621f407SFrançois Tigeot 
15954be47400SFrançois Tigeot 	hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(phy, ch));
15968621f407SFrançois Tigeot 	hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
15978621f407SFrançois Tigeot 
15984be47400SFrançois Tigeot 	hw_state->pll0 = I915_READ(BXT_PORT_PLL(phy, ch, 0));
15998621f407SFrançois Tigeot 	hw_state->pll0 &= PORT_PLL_M2_MASK;
16008621f407SFrançois Tigeot 
16014be47400SFrançois Tigeot 	hw_state->pll1 = I915_READ(BXT_PORT_PLL(phy, ch, 1));
16028621f407SFrançois Tigeot 	hw_state->pll1 &= PORT_PLL_N_MASK;
16038621f407SFrançois Tigeot 
16044be47400SFrançois Tigeot 	hw_state->pll2 = I915_READ(BXT_PORT_PLL(phy, ch, 2));
16058621f407SFrançois Tigeot 	hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK;
16068621f407SFrançois Tigeot 
16074be47400SFrançois Tigeot 	hw_state->pll3 = I915_READ(BXT_PORT_PLL(phy, ch, 3));
16088621f407SFrançois Tigeot 	hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE;
16098621f407SFrançois Tigeot 
16104be47400SFrançois Tigeot 	hw_state->pll6 = I915_READ(BXT_PORT_PLL(phy, ch, 6));
16118621f407SFrançois Tigeot 	hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK |
16128621f407SFrançois Tigeot 			  PORT_PLL_INT_COEFF_MASK |
16138621f407SFrançois Tigeot 			  PORT_PLL_GAIN_CTL_MASK;
16148621f407SFrançois Tigeot 
16154be47400SFrançois Tigeot 	hw_state->pll8 = I915_READ(BXT_PORT_PLL(phy, ch, 8));
16168621f407SFrançois Tigeot 	hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK;
16178621f407SFrançois Tigeot 
16184be47400SFrançois Tigeot 	hw_state->pll9 = I915_READ(BXT_PORT_PLL(phy, ch, 9));
16198621f407SFrançois Tigeot 	hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK;
16208621f407SFrançois Tigeot 
16214be47400SFrançois Tigeot 	hw_state->pll10 = I915_READ(BXT_PORT_PLL(phy, ch, 10));
16228621f407SFrançois Tigeot 	hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H |
16238621f407SFrançois Tigeot 			   PORT_PLL_DCO_AMP_MASK;
16248621f407SFrançois Tigeot 
16258621f407SFrançois Tigeot 	/*
16268621f407SFrançois Tigeot 	 * While we write to the group register to program all lanes at once we
16278621f407SFrançois Tigeot 	 * can read only lane registers. We configure all lanes the same way, so
16288621f407SFrançois Tigeot 	 * here just read out lanes 0/1 and output a note if lanes 2/3 differ.
16298621f407SFrançois Tigeot 	 */
16304be47400SFrançois Tigeot 	hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(phy, ch));
16314be47400SFrançois Tigeot 	if (I915_READ(BXT_PORT_PCS_DW12_LN23(phy, ch)) != hw_state->pcsdw12)
16328621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
16338621f407SFrançois Tigeot 				 hw_state->pcsdw12,
16344be47400SFrançois Tigeot 				 I915_READ(BXT_PORT_PCS_DW12_LN23(phy, ch)));
16358621f407SFrançois Tigeot 	hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
16368621f407SFrançois Tigeot 
16378621f407SFrançois Tigeot 	ret = true;
16388621f407SFrançois Tigeot 
16398621f407SFrançois Tigeot out:
16408621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
16418621f407SFrançois Tigeot 
16428621f407SFrançois Tigeot 	return ret;
16438621f407SFrançois Tigeot }
16448621f407SFrançois Tigeot 
16458621f407SFrançois Tigeot /* bxt clock parameters */
16468621f407SFrançois Tigeot struct bxt_clk_div {
16478621f407SFrançois Tigeot 	int clock;
16488621f407SFrançois Tigeot 	uint32_t p1;
16498621f407SFrançois Tigeot 	uint32_t p2;
16508621f407SFrançois Tigeot 	uint32_t m2_int;
16518621f407SFrançois Tigeot 	uint32_t m2_frac;
16528621f407SFrançois Tigeot 	bool m2_frac_en;
16538621f407SFrançois Tigeot 	uint32_t n;
16541e12ee3bSFrançois Tigeot 
16551e12ee3bSFrançois Tigeot 	int vco;
16568621f407SFrançois Tigeot };
16578621f407SFrançois Tigeot 
16588621f407SFrançois Tigeot /* pre-calculated values for DP linkrates */
16598621f407SFrançois Tigeot static const struct bxt_clk_div bxt_dp_clk_val[] = {
16608621f407SFrançois Tigeot 	{162000, 4, 2, 32, 1677722, 1, 1},
16618621f407SFrançois Tigeot 	{270000, 4, 1, 27,       0, 0, 1},
16628621f407SFrançois Tigeot 	{540000, 2, 1, 27,       0, 0, 1},
16638621f407SFrançois Tigeot 	{216000, 3, 2, 32, 1677722, 1, 1},
16648621f407SFrançois Tigeot 	{243000, 4, 1, 24, 1258291, 1, 1},
16658621f407SFrançois Tigeot 	{324000, 4, 1, 32, 1677722, 1, 1},
16668621f407SFrançois Tigeot 	{432000, 3, 1, 32, 1677722, 1, 1}
16678621f407SFrançois Tigeot };
16688621f407SFrançois Tigeot 
16691e12ee3bSFrançois Tigeot static bool
bxt_ddi_hdmi_pll_dividers(struct intel_crtc * intel_crtc,struct intel_crtc_state * crtc_state,int clock,struct bxt_clk_div * clk_div)16701e12ee3bSFrançois Tigeot bxt_ddi_hdmi_pll_dividers(struct intel_crtc *intel_crtc,
16711e12ee3bSFrançois Tigeot 			  struct intel_crtc_state *crtc_state, int clock,
16721e12ee3bSFrançois Tigeot 			  struct bxt_clk_div *clk_div)
16738621f407SFrançois Tigeot {
16741487f786SFrançois Tigeot 	struct dpll best_clock;
16758621f407SFrançois Tigeot 
16768621f407SFrançois Tigeot 	/* Calculate HDMI div */
16778621f407SFrançois Tigeot 	/*
16788621f407SFrançois Tigeot 	 * FIXME: tie the following calculation into
16798621f407SFrançois Tigeot 	 * i9xx_crtc_compute_clock
16808621f407SFrançois Tigeot 	 */
16818621f407SFrançois Tigeot 	if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
16828621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
16831e12ee3bSFrançois Tigeot 				 clock, pipe_name(intel_crtc->pipe));
16841e12ee3bSFrançois Tigeot 		return false;
16858621f407SFrançois Tigeot 	}
16868621f407SFrançois Tigeot 
16871e12ee3bSFrançois Tigeot 	clk_div->p1 = best_clock.p1;
16881e12ee3bSFrançois Tigeot 	clk_div->p2 = best_clock.p2;
16898621f407SFrançois Tigeot 	WARN_ON(best_clock.m1 != 2);
16901e12ee3bSFrançois Tigeot 	clk_div->n = best_clock.n;
16911e12ee3bSFrançois Tigeot 	clk_div->m2_int = best_clock.m2 >> 22;
16921e12ee3bSFrançois Tigeot 	clk_div->m2_frac = best_clock.m2 & ((1 << 22) - 1);
16931e12ee3bSFrançois Tigeot 	clk_div->m2_frac_en = clk_div->m2_frac != 0;
16948621f407SFrançois Tigeot 
16951e12ee3bSFrançois Tigeot 	clk_div->vco = best_clock.vco;
16961e12ee3bSFrançois Tigeot 
16971e12ee3bSFrançois Tigeot 	return true;
16981e12ee3bSFrançois Tigeot }
16991e12ee3bSFrançois Tigeot 
bxt_ddi_dp_pll_dividers(int clock,struct bxt_clk_div * clk_div)17001e12ee3bSFrançois Tigeot static void bxt_ddi_dp_pll_dividers(int clock, struct bxt_clk_div *clk_div)
17011e12ee3bSFrançois Tigeot {
17028621f407SFrançois Tigeot 	int i;
17038621f407SFrançois Tigeot 
17041e12ee3bSFrançois Tigeot 	*clk_div = bxt_dp_clk_val[0];
17058621f407SFrançois Tigeot 	for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
17068621f407SFrançois Tigeot 		if (bxt_dp_clk_val[i].clock == clock) {
17071e12ee3bSFrançois Tigeot 			*clk_div = bxt_dp_clk_val[i];
17088621f407SFrançois Tigeot 			break;
17098621f407SFrançois Tigeot 		}
17108621f407SFrançois Tigeot 	}
17111e12ee3bSFrançois Tigeot 
17121e12ee3bSFrançois Tigeot 	clk_div->vco = clock * 10 / 2 * clk_div->p1 * clk_div->p2;
17138621f407SFrançois Tigeot }
17148621f407SFrançois Tigeot 
bxt_ddi_set_dpll_hw_state(int clock,struct bxt_clk_div * clk_div,struct intel_dpll_hw_state * dpll_hw_state)17151e12ee3bSFrançois Tigeot static bool bxt_ddi_set_dpll_hw_state(int clock,
17161e12ee3bSFrançois Tigeot 			  struct bxt_clk_div *clk_div,
17171e12ee3bSFrançois Tigeot 			  struct intel_dpll_hw_state *dpll_hw_state)
17181e12ee3bSFrançois Tigeot {
17191e12ee3bSFrançois Tigeot 	int vco = clk_div->vco;
17201e12ee3bSFrançois Tigeot 	uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
17211e12ee3bSFrançois Tigeot 	uint32_t lanestagger;
17221e12ee3bSFrançois Tigeot 
17238621f407SFrançois Tigeot 	if (vco >= 6200000 && vco <= 6700000) {
17248621f407SFrançois Tigeot 		prop_coef = 4;
17258621f407SFrançois Tigeot 		int_coef = 9;
17268621f407SFrançois Tigeot 		gain_ctl = 3;
17278621f407SFrançois Tigeot 		targ_cnt = 8;
17288621f407SFrançois Tigeot 	} else if ((vco > 5400000 && vco < 6200000) ||
17298621f407SFrançois Tigeot 			(vco >= 4800000 && vco < 5400000)) {
17308621f407SFrançois Tigeot 		prop_coef = 5;
17318621f407SFrançois Tigeot 		int_coef = 11;
17328621f407SFrançois Tigeot 		gain_ctl = 3;
17338621f407SFrançois Tigeot 		targ_cnt = 9;
17348621f407SFrançois Tigeot 	} else if (vco == 5400000) {
17358621f407SFrançois Tigeot 		prop_coef = 3;
17368621f407SFrançois Tigeot 		int_coef = 8;
17378621f407SFrançois Tigeot 		gain_ctl = 1;
17388621f407SFrançois Tigeot 		targ_cnt = 9;
17398621f407SFrançois Tigeot 	} else {
17408621f407SFrançois Tigeot 		DRM_ERROR("Invalid VCO\n");
17411e12ee3bSFrançois Tigeot 		return false;
17428621f407SFrançois Tigeot 	}
17438621f407SFrançois Tigeot 
17448621f407SFrançois Tigeot 	if (clock > 270000)
17458621f407SFrançois Tigeot 		lanestagger = 0x18;
17468621f407SFrançois Tigeot 	else if (clock > 135000)
17478621f407SFrançois Tigeot 		lanestagger = 0x0d;
17488621f407SFrançois Tigeot 	else if (clock > 67000)
17498621f407SFrançois Tigeot 		lanestagger = 0x07;
17508621f407SFrançois Tigeot 	else if (clock > 33000)
17518621f407SFrançois Tigeot 		lanestagger = 0x04;
17528621f407SFrançois Tigeot 	else
17538621f407SFrançois Tigeot 		lanestagger = 0x02;
17548621f407SFrançois Tigeot 
17551e12ee3bSFrançois Tigeot 	dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2);
17561e12ee3bSFrançois Tigeot 	dpll_hw_state->pll0 = clk_div->m2_int;
17571e12ee3bSFrançois Tigeot 	dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n);
17581e12ee3bSFrançois Tigeot 	dpll_hw_state->pll2 = clk_div->m2_frac;
17598621f407SFrançois Tigeot 
17601e12ee3bSFrançois Tigeot 	if (clk_div->m2_frac_en)
17611e12ee3bSFrançois Tigeot 		dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE;
17628621f407SFrançois Tigeot 
17631e12ee3bSFrançois Tigeot 	dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef);
17641e12ee3bSFrançois Tigeot 	dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl);
17658621f407SFrançois Tigeot 
17661e12ee3bSFrançois Tigeot 	dpll_hw_state->pll8 = targ_cnt;
17678621f407SFrançois Tigeot 
17681e12ee3bSFrançois Tigeot 	dpll_hw_state->pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
17698621f407SFrançois Tigeot 
17701e12ee3bSFrançois Tigeot 	dpll_hw_state->pll10 =
17718621f407SFrançois Tigeot 		PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
17728621f407SFrançois Tigeot 		| PORT_PLL_DCO_AMP_OVR_EN_H;
17738621f407SFrançois Tigeot 
17741e12ee3bSFrançois Tigeot 	dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
17758621f407SFrançois Tigeot 
17761e12ee3bSFrançois Tigeot 	dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger;
17778621f407SFrançois Tigeot 
17781e12ee3bSFrançois Tigeot 	return true;
17791e12ee3bSFrançois Tigeot }
17801e12ee3bSFrançois Tigeot 
1781a85cb24fSFrançois Tigeot static bool
bxt_ddi_dp_set_dpll_hw_state(int clock,struct intel_dpll_hw_state * dpll_hw_state)1782a85cb24fSFrançois Tigeot bxt_ddi_dp_set_dpll_hw_state(int clock,
17831e12ee3bSFrançois Tigeot 			     struct intel_dpll_hw_state *dpll_hw_state)
17841e12ee3bSFrançois Tigeot {
17851e12ee3bSFrançois Tigeot 	struct bxt_clk_div clk_div = {0};
17861e12ee3bSFrançois Tigeot 
17871e12ee3bSFrançois Tigeot 	bxt_ddi_dp_pll_dividers(clock, &clk_div);
17881e12ee3bSFrançois Tigeot 
17891e12ee3bSFrançois Tigeot 	return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state);
17901e12ee3bSFrançois Tigeot }
17911e12ee3bSFrançois Tigeot 
17921e12ee3bSFrançois Tigeot static bool
bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc * intel_crtc,struct intel_crtc_state * crtc_state,int clock,struct intel_dpll_hw_state * dpll_hw_state)17931e12ee3bSFrançois Tigeot bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc *intel_crtc,
17941e12ee3bSFrançois Tigeot 			       struct intel_crtc_state *crtc_state, int clock,
17951e12ee3bSFrançois Tigeot 			       struct intel_dpll_hw_state *dpll_hw_state)
17961e12ee3bSFrançois Tigeot {
17971e12ee3bSFrançois Tigeot 	struct bxt_clk_div clk_div = { };
17981e12ee3bSFrançois Tigeot 
17991e12ee3bSFrançois Tigeot 	bxt_ddi_hdmi_pll_dividers(intel_crtc, crtc_state, clock, &clk_div);
18001e12ee3bSFrançois Tigeot 
18011e12ee3bSFrançois Tigeot 	return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state);
18021e12ee3bSFrançois Tigeot }
18031e12ee3bSFrançois Tigeot 
18041e12ee3bSFrançois Tigeot static struct intel_shared_dpll *
bxt_get_dpll(struct intel_crtc * crtc,struct intel_crtc_state * crtc_state,struct intel_encoder * encoder)18051e12ee3bSFrançois Tigeot bxt_get_dpll(struct intel_crtc *crtc,
18061e12ee3bSFrançois Tigeot 		struct intel_crtc_state *crtc_state,
18071e12ee3bSFrançois Tigeot 		struct intel_encoder *encoder)
18081e12ee3bSFrançois Tigeot {
18091e12ee3bSFrançois Tigeot 	struct intel_dpll_hw_state dpll_hw_state = { };
18101e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
18111e12ee3bSFrançois Tigeot 	struct intel_digital_port *intel_dig_port;
18121e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
18131e12ee3bSFrançois Tigeot 	int i, clock = crtc_state->port_clock;
18141e12ee3bSFrançois Tigeot 
18151e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI &&
18161e12ee3bSFrançois Tigeot 	    !bxt_ddi_hdmi_set_dpll_hw_state(crtc, crtc_state, clock,
18171e12ee3bSFrançois Tigeot 					    &dpll_hw_state))
18181e12ee3bSFrançois Tigeot 		return NULL;
18191e12ee3bSFrançois Tigeot 
18201e12ee3bSFrançois Tigeot 	if ((encoder->type == INTEL_OUTPUT_DP ||
18214be47400SFrançois Tigeot 	     encoder->type == INTEL_OUTPUT_EDP ||
18224be47400SFrançois Tigeot 	     encoder->type == INTEL_OUTPUT_DP_MST) &&
18231e12ee3bSFrançois Tigeot 	    !bxt_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
18241e12ee3bSFrançois Tigeot 		return NULL;
18251e12ee3bSFrançois Tigeot 
18261e12ee3bSFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
18271e12ee3bSFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
18281e12ee3bSFrançois Tigeot 
18291e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state = dpll_hw_state;
18301e12ee3bSFrançois Tigeot 
18311e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_DP_MST) {
18321e12ee3bSFrançois Tigeot 		struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
18331e12ee3bSFrançois Tigeot 
18341e12ee3bSFrançois Tigeot 		intel_dig_port = intel_mst->primary;
18351e12ee3bSFrançois Tigeot 	} else
18368621f407SFrançois Tigeot 		intel_dig_port = enc_to_dig_port(&encoder->base);
18378621f407SFrançois Tigeot 
18388621f407SFrançois Tigeot 	/* 1:1 mapping between ports and PLLs */
18398621f407SFrançois Tigeot 	i = (enum intel_dpll_id) intel_dig_port->port;
18408621f407SFrançois Tigeot 	pll = intel_get_shared_dpll_by_id(dev_priv, i);
18418621f407SFrançois Tigeot 
18421487f786SFrançois Tigeot 	DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n",
18431487f786SFrançois Tigeot 		      crtc->base.base.id, crtc->base.name, pll->name);
18448621f407SFrançois Tigeot 
18458621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
18468621f407SFrançois Tigeot 
18478621f407SFrançois Tigeot 	return pll;
18488621f407SFrançois Tigeot }
18498621f407SFrançois Tigeot 
bxt_dump_hw_state(struct drm_i915_private * dev_priv,struct intel_dpll_hw_state * hw_state)1850a85cb24fSFrançois Tigeot static void bxt_dump_hw_state(struct drm_i915_private *dev_priv,
1851a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
1852a85cb24fSFrançois Tigeot {
1853a85cb24fSFrançois Tigeot 	DRM_DEBUG_KMS("dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x,"
1854a85cb24fSFrançois Tigeot 		      "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, "
1855a85cb24fSFrançois Tigeot 		      "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pll10: 0x%x, pcsdw12: 0x%x\n",
1856a85cb24fSFrançois Tigeot 		      hw_state->ebb0,
1857a85cb24fSFrançois Tigeot 		      hw_state->ebb4,
1858a85cb24fSFrançois Tigeot 		      hw_state->pll0,
1859a85cb24fSFrançois Tigeot 		      hw_state->pll1,
1860a85cb24fSFrançois Tigeot 		      hw_state->pll2,
1861a85cb24fSFrançois Tigeot 		      hw_state->pll3,
1862a85cb24fSFrançois Tigeot 		      hw_state->pll6,
1863a85cb24fSFrançois Tigeot 		      hw_state->pll8,
1864a85cb24fSFrançois Tigeot 		      hw_state->pll9,
1865a85cb24fSFrançois Tigeot 		      hw_state->pll10,
1866a85cb24fSFrançois Tigeot 		      hw_state->pcsdw12);
1867a85cb24fSFrançois Tigeot }
1868a85cb24fSFrançois Tigeot 
18698621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = {
18708621f407SFrançois Tigeot 	.enable = bxt_ddi_pll_enable,
18718621f407SFrançois Tigeot 	.disable = bxt_ddi_pll_disable,
18728621f407SFrançois Tigeot 	.get_hw_state = bxt_ddi_pll_get_hw_state,
18738621f407SFrançois Tigeot };
18748621f407SFrançois Tigeot 
intel_ddi_pll_init(struct drm_device * dev)18758621f407SFrançois Tigeot static void intel_ddi_pll_init(struct drm_device *dev)
18768621f407SFrançois Tigeot {
1877303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
18781487f786SFrançois Tigeot 
18791487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 9) {
18808621f407SFrançois Tigeot 		uint32_t val = I915_READ(LCPLL_CTL);
18818621f407SFrançois Tigeot 
18828621f407SFrançois Tigeot 		/*
18838621f407SFrançois Tigeot 		 * The LCPLL register should be turned on by the BIOS. For now
18848621f407SFrançois Tigeot 		 * let's just check its state and print errors in case
18858621f407SFrançois Tigeot 		 * something is wrong.  Don't even try to turn it on.
18868621f407SFrançois Tigeot 		 */
18878621f407SFrançois Tigeot 
18888621f407SFrançois Tigeot 		if (val & LCPLL_CD_SOURCE_FCLK)
18898621f407SFrançois Tigeot 			DRM_ERROR("CDCLK source is not LCPLL\n");
18908621f407SFrançois Tigeot 
18918621f407SFrançois Tigeot 		if (val & LCPLL_PLL_DISABLE)
18928621f407SFrançois Tigeot 			DRM_ERROR("LCPLL is disabled\n");
18938621f407SFrançois Tigeot 	}
18948621f407SFrançois Tigeot }
18958621f407SFrançois Tigeot 
18968621f407SFrançois Tigeot struct dpll_info {
18978621f407SFrançois Tigeot 	const char *name;
18988621f407SFrançois Tigeot 	const int id;
18998621f407SFrançois Tigeot 	const struct intel_shared_dpll_funcs *funcs;
19008621f407SFrançois Tigeot 	uint32_t flags;
19018621f407SFrançois Tigeot };
19028621f407SFrançois Tigeot 
19038621f407SFrançois Tigeot struct intel_dpll_mgr {
19048621f407SFrançois Tigeot 	const struct dpll_info *dpll_info;
19058621f407SFrançois Tigeot 
19068621f407SFrançois Tigeot 	struct intel_shared_dpll *(*get_dpll)(struct intel_crtc *crtc,
19078621f407SFrançois Tigeot 					      struct intel_crtc_state *crtc_state,
19088621f407SFrançois Tigeot 					      struct intel_encoder *encoder);
1909a85cb24fSFrançois Tigeot 
1910a85cb24fSFrançois Tigeot 	void (*dump_hw_state)(struct drm_i915_private *dev_priv,
1911a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state);
19128621f407SFrançois Tigeot };
19138621f407SFrançois Tigeot 
19148621f407SFrançois Tigeot static const struct dpll_info pch_plls[] = {
19158621f407SFrançois Tigeot 	{ "PCH DPLL A", DPLL_ID_PCH_PLL_A, &ibx_pch_dpll_funcs, 0 },
19168621f407SFrançois Tigeot 	{ "PCH DPLL B", DPLL_ID_PCH_PLL_B, &ibx_pch_dpll_funcs, 0 },
19178621f407SFrançois Tigeot 	{ NULL, -1, NULL, 0 },
19188621f407SFrançois Tigeot };
19198621f407SFrançois Tigeot 
19208621f407SFrançois Tigeot static const struct intel_dpll_mgr pch_pll_mgr = {
19218621f407SFrançois Tigeot 	.dpll_info = pch_plls,
19228621f407SFrançois Tigeot 	.get_dpll = ibx_get_dpll,
1923a85cb24fSFrançois Tigeot 	.dump_hw_state = ibx_dump_hw_state,
19248621f407SFrançois Tigeot };
19258621f407SFrançois Tigeot 
19268621f407SFrançois Tigeot static const struct dpll_info hsw_plls[] = {
19278621f407SFrançois Tigeot 	{ "WRPLL 1",    DPLL_ID_WRPLL1,     &hsw_ddi_wrpll_funcs, 0 },
19288621f407SFrançois Tigeot 	{ "WRPLL 2",    DPLL_ID_WRPLL2,     &hsw_ddi_wrpll_funcs, 0 },
19298621f407SFrançois Tigeot 	{ "SPLL",       DPLL_ID_SPLL,       &hsw_ddi_spll_funcs,  0 },
19308621f407SFrançois Tigeot 	{ "LCPLL 810",  DPLL_ID_LCPLL_810,  &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
19318621f407SFrançois Tigeot 	{ "LCPLL 1350", DPLL_ID_LCPLL_1350, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
19328621f407SFrançois Tigeot 	{ "LCPLL 2700", DPLL_ID_LCPLL_2700, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
19338621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
19348621f407SFrançois Tigeot };
19358621f407SFrançois Tigeot 
19368621f407SFrançois Tigeot static const struct intel_dpll_mgr hsw_pll_mgr = {
19378621f407SFrançois Tigeot 	.dpll_info = hsw_plls,
19388621f407SFrançois Tigeot 	.get_dpll = hsw_get_dpll,
1939a85cb24fSFrançois Tigeot 	.dump_hw_state = hsw_dump_hw_state,
19408621f407SFrançois Tigeot };
19418621f407SFrançois Tigeot 
19428621f407SFrançois Tigeot static const struct dpll_info skl_plls[] = {
19438621f407SFrançois Tigeot 	{ "DPLL 0", DPLL_ID_SKL_DPLL0, &skl_ddi_dpll0_funcs, INTEL_DPLL_ALWAYS_ON },
19448621f407SFrançois Tigeot 	{ "DPLL 1", DPLL_ID_SKL_DPLL1, &skl_ddi_pll_funcs,   0 },
19458621f407SFrançois Tigeot 	{ "DPLL 2", DPLL_ID_SKL_DPLL2, &skl_ddi_pll_funcs,   0 },
19468621f407SFrançois Tigeot 	{ "DPLL 3", DPLL_ID_SKL_DPLL3, &skl_ddi_pll_funcs,   0 },
19478621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
19488621f407SFrançois Tigeot };
19498621f407SFrançois Tigeot 
19508621f407SFrançois Tigeot static const struct intel_dpll_mgr skl_pll_mgr = {
19518621f407SFrançois Tigeot 	.dpll_info = skl_plls,
19528621f407SFrançois Tigeot 	.get_dpll = skl_get_dpll,
1953a85cb24fSFrançois Tigeot 	.dump_hw_state = skl_dump_hw_state,
19548621f407SFrançois Tigeot };
19558621f407SFrançois Tigeot 
19568621f407SFrançois Tigeot static const struct dpll_info bxt_plls[] = {
19578621f407SFrançois Tigeot 	{ "PORT PLL A", DPLL_ID_SKL_DPLL0, &bxt_ddi_pll_funcs, 0 },
19588621f407SFrançois Tigeot 	{ "PORT PLL B", DPLL_ID_SKL_DPLL1, &bxt_ddi_pll_funcs, 0 },
19598621f407SFrançois Tigeot 	{ "PORT PLL C", DPLL_ID_SKL_DPLL2, &bxt_ddi_pll_funcs, 0 },
19608621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
19618621f407SFrançois Tigeot };
19628621f407SFrançois Tigeot 
19638621f407SFrançois Tigeot static const struct intel_dpll_mgr bxt_pll_mgr = {
19648621f407SFrançois Tigeot 	.dpll_info = bxt_plls,
19658621f407SFrançois Tigeot 	.get_dpll = bxt_get_dpll,
1966a85cb24fSFrançois Tigeot 	.dump_hw_state = bxt_dump_hw_state,
19678621f407SFrançois Tigeot };
19688621f407SFrançois Tigeot 
cnl_ddi_pll_enable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)1969*3f2dd94aSFrançois Tigeot static void cnl_ddi_pll_enable(struct drm_i915_private *dev_priv,
1970*3f2dd94aSFrançois Tigeot 			       struct intel_shared_dpll *pll)
1971*3f2dd94aSFrançois Tigeot {
1972*3f2dd94aSFrançois Tigeot 	uint32_t val;
1973*3f2dd94aSFrançois Tigeot 
1974*3f2dd94aSFrançois Tigeot 	/* 1. Enable DPLL power in DPLL_ENABLE. */
1975*3f2dd94aSFrançois Tigeot 	val = I915_READ(CNL_DPLL_ENABLE(pll->id));
1976*3f2dd94aSFrançois Tigeot 	val |= PLL_POWER_ENABLE;
1977*3f2dd94aSFrançois Tigeot 	I915_WRITE(CNL_DPLL_ENABLE(pll->id), val);
1978*3f2dd94aSFrançois Tigeot 
1979*3f2dd94aSFrançois Tigeot 	/* 2. Wait for DPLL power state enabled in DPLL_ENABLE. */
1980*3f2dd94aSFrançois Tigeot 	if (intel_wait_for_register(dev_priv,
1981*3f2dd94aSFrançois Tigeot 				    CNL_DPLL_ENABLE(pll->id),
1982*3f2dd94aSFrançois Tigeot 				    PLL_POWER_STATE,
1983*3f2dd94aSFrançois Tigeot 				    PLL_POWER_STATE,
1984*3f2dd94aSFrançois Tigeot 				    5))
1985*3f2dd94aSFrançois Tigeot 		DRM_ERROR("PLL %d Power not enabled\n", pll->id);
1986*3f2dd94aSFrançois Tigeot 
1987*3f2dd94aSFrançois Tigeot 	/*
1988*3f2dd94aSFrançois Tigeot 	 * 3. Configure DPLL_CFGCR0 to set SSC enable/disable,
1989*3f2dd94aSFrançois Tigeot 	 * select DP mode, and set DP link rate.
1990*3f2dd94aSFrançois Tigeot 	 */
1991*3f2dd94aSFrançois Tigeot 	val = pll->state.hw_state.cfgcr0;
1992*3f2dd94aSFrançois Tigeot 	I915_WRITE(CNL_DPLL_CFGCR0(pll->id), val);
1993*3f2dd94aSFrançois Tigeot 
1994*3f2dd94aSFrançois Tigeot 	/* 4. Reab back to ensure writes completed */
1995*3f2dd94aSFrançois Tigeot 	POSTING_READ(CNL_DPLL_CFGCR0(pll->id));
1996*3f2dd94aSFrançois Tigeot 
1997*3f2dd94aSFrançois Tigeot 	/* 3. Configure DPLL_CFGCR0 */
1998*3f2dd94aSFrançois Tigeot 	/* Avoid touch CFGCR1 if HDMI mode is not enabled */
1999*3f2dd94aSFrançois Tigeot 	if (pll->state.hw_state.cfgcr0 & DPLL_CFGCR0_HDMI_MODE) {
2000*3f2dd94aSFrançois Tigeot 		val = pll->state.hw_state.cfgcr1;
2001*3f2dd94aSFrançois Tigeot 		I915_WRITE(CNL_DPLL_CFGCR1(pll->id), val);
2002*3f2dd94aSFrançois Tigeot 		/* 4. Reab back to ensure writes completed */
2003*3f2dd94aSFrançois Tigeot 		POSTING_READ(CNL_DPLL_CFGCR1(pll->id));
2004*3f2dd94aSFrançois Tigeot 	}
2005*3f2dd94aSFrançois Tigeot 
2006*3f2dd94aSFrançois Tigeot 	/*
2007*3f2dd94aSFrançois Tigeot 	 * 5. If the frequency will result in a change to the voltage
2008*3f2dd94aSFrançois Tigeot 	 * requirement, follow the Display Voltage Frequency Switching
2009*3f2dd94aSFrançois Tigeot 	 * Sequence Before Frequency Change
2010*3f2dd94aSFrançois Tigeot 	 *
2011*3f2dd94aSFrançois Tigeot 	 * FIXME: (DVFS) is used to adjust the display voltage to match the
2012*3f2dd94aSFrançois Tigeot 	 * display clock frequencies
2013*3f2dd94aSFrançois Tigeot 	 */
2014*3f2dd94aSFrançois Tigeot 
2015*3f2dd94aSFrançois Tigeot 	/* 6. Enable DPLL in DPLL_ENABLE. */
2016*3f2dd94aSFrançois Tigeot 	val = I915_READ(CNL_DPLL_ENABLE(pll->id));
2017*3f2dd94aSFrançois Tigeot 	val |= PLL_ENABLE;
2018*3f2dd94aSFrançois Tigeot 	I915_WRITE(CNL_DPLL_ENABLE(pll->id), val);
2019*3f2dd94aSFrançois Tigeot 
2020*3f2dd94aSFrançois Tigeot 	/* 7. Wait for PLL lock status in DPLL_ENABLE. */
2021*3f2dd94aSFrançois Tigeot 	if (intel_wait_for_register(dev_priv,
2022*3f2dd94aSFrançois Tigeot 				    CNL_DPLL_ENABLE(pll->id),
2023*3f2dd94aSFrançois Tigeot 				    PLL_LOCK,
2024*3f2dd94aSFrançois Tigeot 				    PLL_LOCK,
2025*3f2dd94aSFrançois Tigeot 				    5))
2026*3f2dd94aSFrançois Tigeot 		DRM_ERROR("PLL %d not locked\n", pll->id);
2027*3f2dd94aSFrançois Tigeot 
2028*3f2dd94aSFrançois Tigeot 	/*
2029*3f2dd94aSFrançois Tigeot 	 * 8. If the frequency will result in a change to the voltage
2030*3f2dd94aSFrançois Tigeot 	 * requirement, follow the Display Voltage Frequency Switching
2031*3f2dd94aSFrançois Tigeot 	 * Sequence After Frequency Change
2032*3f2dd94aSFrançois Tigeot 	 *
2033*3f2dd94aSFrançois Tigeot 	 * FIXME: (DVFS) is used to adjust the display voltage to match the
2034*3f2dd94aSFrançois Tigeot 	 * display clock frequencies
2035*3f2dd94aSFrançois Tigeot 	 */
2036*3f2dd94aSFrançois Tigeot 
2037*3f2dd94aSFrançois Tigeot 	/*
2038*3f2dd94aSFrançois Tigeot 	 * 9. turn on the clock for the DDI and map the DPLL to the DDI
2039*3f2dd94aSFrançois Tigeot 	 * Done at intel_ddi_clk_select
2040*3f2dd94aSFrançois Tigeot 	 */
2041*3f2dd94aSFrançois Tigeot }
2042*3f2dd94aSFrançois Tigeot 
cnl_ddi_pll_disable(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll)2043*3f2dd94aSFrançois Tigeot static void cnl_ddi_pll_disable(struct drm_i915_private *dev_priv,
2044*3f2dd94aSFrançois Tigeot 				struct intel_shared_dpll *pll)
2045*3f2dd94aSFrançois Tigeot {
2046*3f2dd94aSFrançois Tigeot 	uint32_t val;
2047*3f2dd94aSFrançois Tigeot 
2048*3f2dd94aSFrançois Tigeot 	/*
2049*3f2dd94aSFrançois Tigeot 	 * 1. Configure DPCLKA_CFGCR0 to turn off the clock for the DDI.
2050*3f2dd94aSFrançois Tigeot 	 * Done at intel_ddi_post_disable
2051*3f2dd94aSFrançois Tigeot 	 */
2052*3f2dd94aSFrançois Tigeot 
2053*3f2dd94aSFrançois Tigeot 	/*
2054*3f2dd94aSFrançois Tigeot 	 * 2. If the frequency will result in a change to the voltage
2055*3f2dd94aSFrançois Tigeot 	 * requirement, follow the Display Voltage Frequency Switching
2056*3f2dd94aSFrançois Tigeot 	 * Sequence Before Frequency Change
2057*3f2dd94aSFrançois Tigeot 	 *
2058*3f2dd94aSFrançois Tigeot 	 * FIXME: (DVFS) is used to adjust the display voltage to match the
2059*3f2dd94aSFrançois Tigeot 	 * display clock frequencies
2060*3f2dd94aSFrançois Tigeot 	 */
2061*3f2dd94aSFrançois Tigeot 
2062*3f2dd94aSFrançois Tigeot 	/* 3. Disable DPLL through DPLL_ENABLE. */
2063*3f2dd94aSFrançois Tigeot 	val = I915_READ(CNL_DPLL_ENABLE(pll->id));
2064*3f2dd94aSFrançois Tigeot 	val &= ~PLL_ENABLE;
2065*3f2dd94aSFrançois Tigeot 	I915_WRITE(CNL_DPLL_ENABLE(pll->id), val);
2066*3f2dd94aSFrançois Tigeot 
2067*3f2dd94aSFrançois Tigeot 	/* 4. Wait for PLL not locked status in DPLL_ENABLE. */
2068*3f2dd94aSFrançois Tigeot 	if (intel_wait_for_register(dev_priv,
2069*3f2dd94aSFrançois Tigeot 				    CNL_DPLL_ENABLE(pll->id),
2070*3f2dd94aSFrançois Tigeot 				    PLL_LOCK,
2071*3f2dd94aSFrançois Tigeot 				    0,
2072*3f2dd94aSFrançois Tigeot 				    5))
2073*3f2dd94aSFrançois Tigeot 		DRM_ERROR("PLL %d locked\n", pll->id);
2074*3f2dd94aSFrançois Tigeot 
2075*3f2dd94aSFrançois Tigeot 	/*
2076*3f2dd94aSFrançois Tigeot 	 * 5. If the frequency will result in a change to the voltage
2077*3f2dd94aSFrançois Tigeot 	 * requirement, follow the Display Voltage Frequency Switching
2078*3f2dd94aSFrançois Tigeot 	 * Sequence After Frequency Change
2079*3f2dd94aSFrançois Tigeot 	 *
2080*3f2dd94aSFrançois Tigeot 	 * FIXME: (DVFS) is used to adjust the display voltage to match the
2081*3f2dd94aSFrançois Tigeot 	 * display clock frequencies
2082*3f2dd94aSFrançois Tigeot 	 */
2083*3f2dd94aSFrançois Tigeot 
2084*3f2dd94aSFrançois Tigeot 	/* 6. Disable DPLL power in DPLL_ENABLE. */
2085*3f2dd94aSFrançois Tigeot 	val = I915_READ(CNL_DPLL_ENABLE(pll->id));
2086*3f2dd94aSFrançois Tigeot 	val &= ~PLL_POWER_ENABLE;
2087*3f2dd94aSFrançois Tigeot 	I915_WRITE(CNL_DPLL_ENABLE(pll->id), val);
2088*3f2dd94aSFrançois Tigeot 
2089*3f2dd94aSFrançois Tigeot 	/* 7. Wait for DPLL power state disabled in DPLL_ENABLE. */
2090*3f2dd94aSFrançois Tigeot 	if (intel_wait_for_register(dev_priv,
2091*3f2dd94aSFrançois Tigeot 				    CNL_DPLL_ENABLE(pll->id),
2092*3f2dd94aSFrançois Tigeot 				    PLL_POWER_STATE,
2093*3f2dd94aSFrançois Tigeot 				    0,
2094*3f2dd94aSFrançois Tigeot 				    5))
2095*3f2dd94aSFrançois Tigeot 		DRM_ERROR("PLL %d Power not disabled\n", pll->id);
2096*3f2dd94aSFrançois Tigeot }
2097*3f2dd94aSFrançois Tigeot 
cnl_ddi_pll_get_hw_state(struct drm_i915_private * dev_priv,struct intel_shared_dpll * pll,struct intel_dpll_hw_state * hw_state)2098*3f2dd94aSFrançois Tigeot static bool cnl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
2099*3f2dd94aSFrançois Tigeot 				     struct intel_shared_dpll *pll,
2100*3f2dd94aSFrançois Tigeot 				     struct intel_dpll_hw_state *hw_state)
2101*3f2dd94aSFrançois Tigeot {
2102*3f2dd94aSFrançois Tigeot 	uint32_t val;
2103*3f2dd94aSFrançois Tigeot 	bool ret;
2104*3f2dd94aSFrançois Tigeot 
2105*3f2dd94aSFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
2106*3f2dd94aSFrançois Tigeot 		return false;
2107*3f2dd94aSFrançois Tigeot 
2108*3f2dd94aSFrançois Tigeot 	ret = false;
2109*3f2dd94aSFrançois Tigeot 
2110*3f2dd94aSFrançois Tigeot 	val = I915_READ(CNL_DPLL_ENABLE(pll->id));
2111*3f2dd94aSFrançois Tigeot 	if (!(val & PLL_ENABLE))
2112*3f2dd94aSFrançois Tigeot 		goto out;
2113*3f2dd94aSFrançois Tigeot 
2114*3f2dd94aSFrançois Tigeot 	val = I915_READ(CNL_DPLL_CFGCR0(pll->id));
2115*3f2dd94aSFrançois Tigeot 	hw_state->cfgcr0 = val;
2116*3f2dd94aSFrançois Tigeot 
2117*3f2dd94aSFrançois Tigeot 	/* avoid reading back stale values if HDMI mode is not enabled */
2118*3f2dd94aSFrançois Tigeot 	if (val & DPLL_CFGCR0_HDMI_MODE) {
2119*3f2dd94aSFrançois Tigeot 		hw_state->cfgcr1 = I915_READ(CNL_DPLL_CFGCR1(pll->id));
2120*3f2dd94aSFrançois Tigeot 	}
2121*3f2dd94aSFrançois Tigeot 	ret = true;
2122*3f2dd94aSFrançois Tigeot 
2123*3f2dd94aSFrançois Tigeot out:
2124*3f2dd94aSFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
2125*3f2dd94aSFrançois Tigeot 
2126*3f2dd94aSFrançois Tigeot 	return ret;
2127*3f2dd94aSFrançois Tigeot }
2128*3f2dd94aSFrançois Tigeot 
cnl_wrpll_get_multipliers(unsigned int bestdiv,unsigned int * pdiv,unsigned int * qdiv,unsigned int * kdiv)2129*3f2dd94aSFrançois Tigeot static void cnl_wrpll_get_multipliers(unsigned int bestdiv,
2130*3f2dd94aSFrançois Tigeot 				      unsigned int *pdiv,
2131*3f2dd94aSFrançois Tigeot 				      unsigned int *qdiv,
2132*3f2dd94aSFrançois Tigeot 				      unsigned int *kdiv)
2133*3f2dd94aSFrançois Tigeot {
2134*3f2dd94aSFrançois Tigeot 	/* even dividers */
2135*3f2dd94aSFrançois Tigeot 	if (bestdiv % 2 == 0) {
2136*3f2dd94aSFrançois Tigeot 		if (bestdiv == 2) {
2137*3f2dd94aSFrançois Tigeot 			*pdiv = 2;
2138*3f2dd94aSFrançois Tigeot 			*qdiv = 1;
2139*3f2dd94aSFrançois Tigeot 			*kdiv = 1;
2140*3f2dd94aSFrançois Tigeot 		} else if (bestdiv % 4 == 0) {
2141*3f2dd94aSFrançois Tigeot 			*pdiv = 2;
2142*3f2dd94aSFrançois Tigeot 			*qdiv = bestdiv / 4;
2143*3f2dd94aSFrançois Tigeot 			*kdiv = 2;
2144*3f2dd94aSFrançois Tigeot 		} else if (bestdiv % 6 == 0) {
2145*3f2dd94aSFrançois Tigeot 			*pdiv = 3;
2146*3f2dd94aSFrançois Tigeot 			*qdiv = bestdiv / 6;
2147*3f2dd94aSFrançois Tigeot 			*kdiv = 2;
2148*3f2dd94aSFrançois Tigeot 		} else if (bestdiv % 5 == 0) {
2149*3f2dd94aSFrançois Tigeot 			*pdiv = 5;
2150*3f2dd94aSFrançois Tigeot 			*qdiv = bestdiv / 10;
2151*3f2dd94aSFrançois Tigeot 			*kdiv = 2;
2152*3f2dd94aSFrançois Tigeot 		} else if (bestdiv % 14 == 0) {
2153*3f2dd94aSFrançois Tigeot 			*pdiv = 7;
2154*3f2dd94aSFrançois Tigeot 			*qdiv = bestdiv / 14;
2155*3f2dd94aSFrançois Tigeot 			*kdiv = 2;
2156*3f2dd94aSFrançois Tigeot 		}
2157*3f2dd94aSFrançois Tigeot 	} else {
2158*3f2dd94aSFrançois Tigeot 		if (bestdiv == 3 || bestdiv == 5 || bestdiv == 7) {
2159*3f2dd94aSFrançois Tigeot 			*pdiv = bestdiv;
2160*3f2dd94aSFrançois Tigeot 			*qdiv = 1;
2161*3f2dd94aSFrançois Tigeot 			*kdiv = 1;
2162*3f2dd94aSFrançois Tigeot 		} else { /* 9, 15, 21 */
2163*3f2dd94aSFrançois Tigeot 			*pdiv = bestdiv / 3;
2164*3f2dd94aSFrançois Tigeot 			*qdiv = 1;
2165*3f2dd94aSFrançois Tigeot 			*kdiv = 3;
2166*3f2dd94aSFrançois Tigeot 		}
2167*3f2dd94aSFrançois Tigeot 	}
2168*3f2dd94aSFrançois Tigeot }
2169*3f2dd94aSFrançois Tigeot 
cnl_wrpll_params_populate(struct skl_wrpll_params * params,uint32_t dco_freq,uint32_t ref_freq,uint32_t pdiv,uint32_t qdiv,uint32_t kdiv)2170*3f2dd94aSFrançois Tigeot static void cnl_wrpll_params_populate(struct skl_wrpll_params *params, uint32_t dco_freq,
2171*3f2dd94aSFrançois Tigeot 				      uint32_t ref_freq, uint32_t pdiv, uint32_t qdiv,
2172*3f2dd94aSFrançois Tigeot 				      uint32_t kdiv)
2173*3f2dd94aSFrançois Tigeot {
2174*3f2dd94aSFrançois Tigeot 	switch (kdiv) {
2175*3f2dd94aSFrançois Tigeot 	case 1:
2176*3f2dd94aSFrançois Tigeot 		params->kdiv = 1;
2177*3f2dd94aSFrançois Tigeot 		break;
2178*3f2dd94aSFrançois Tigeot 	case 2:
2179*3f2dd94aSFrançois Tigeot 		params->kdiv = 2;
2180*3f2dd94aSFrançois Tigeot 		break;
2181*3f2dd94aSFrançois Tigeot 	case 3:
2182*3f2dd94aSFrançois Tigeot 		params->kdiv = 4;
2183*3f2dd94aSFrançois Tigeot 		break;
2184*3f2dd94aSFrançois Tigeot 	default:
2185*3f2dd94aSFrançois Tigeot 		WARN(1, "Incorrect KDiv\n");
2186*3f2dd94aSFrançois Tigeot 	}
2187*3f2dd94aSFrançois Tigeot 
2188*3f2dd94aSFrançois Tigeot 	switch (pdiv) {
2189*3f2dd94aSFrançois Tigeot 	case 2:
2190*3f2dd94aSFrançois Tigeot 		params->pdiv = 1;
2191*3f2dd94aSFrançois Tigeot 		break;
2192*3f2dd94aSFrançois Tigeot 	case 3:
2193*3f2dd94aSFrançois Tigeot 		params->pdiv = 2;
2194*3f2dd94aSFrançois Tigeot 		break;
2195*3f2dd94aSFrançois Tigeot 	case 5:
2196*3f2dd94aSFrançois Tigeot 		params->pdiv = 4;
2197*3f2dd94aSFrançois Tigeot 		break;
2198*3f2dd94aSFrançois Tigeot 	case 7:
2199*3f2dd94aSFrançois Tigeot 		params->pdiv = 8;
2200*3f2dd94aSFrançois Tigeot 		break;
2201*3f2dd94aSFrançois Tigeot 	default:
2202*3f2dd94aSFrançois Tigeot 		WARN(1, "Incorrect PDiv\n");
2203*3f2dd94aSFrançois Tigeot 	}
2204*3f2dd94aSFrançois Tigeot 
2205*3f2dd94aSFrançois Tigeot 	if (kdiv != 2)
2206*3f2dd94aSFrançois Tigeot 		qdiv = 1;
2207*3f2dd94aSFrançois Tigeot 
2208*3f2dd94aSFrançois Tigeot 	params->qdiv_ratio = qdiv;
2209*3f2dd94aSFrançois Tigeot 	params->qdiv_mode = (qdiv == 1) ? 0 : 1;
2210*3f2dd94aSFrançois Tigeot 
2211*3f2dd94aSFrançois Tigeot 	params->dco_integer = div_u64(dco_freq, ref_freq);
2212*3f2dd94aSFrançois Tigeot 	params->dco_fraction = div_u64((div_u64((uint64_t)dco_freq<<15, (uint64_t)ref_freq) -
2213*3f2dd94aSFrançois Tigeot 					((uint64_t)params->dco_integer<<15)) * 0x8000, 0x8000);
2214*3f2dd94aSFrançois Tigeot }
2215*3f2dd94aSFrançois Tigeot 
2216*3f2dd94aSFrançois Tigeot static bool
cnl_ddi_calculate_wrpll(int clock,struct drm_i915_private * dev_priv,struct skl_wrpll_params * wrpll_params)2217*3f2dd94aSFrançois Tigeot cnl_ddi_calculate_wrpll(int clock /* in Hz */,
2218*3f2dd94aSFrançois Tigeot 			struct drm_i915_private *dev_priv,
2219*3f2dd94aSFrançois Tigeot 			struct skl_wrpll_params *wrpll_params)
2220*3f2dd94aSFrançois Tigeot {
2221*3f2dd94aSFrançois Tigeot 	uint64_t afe_clock = clock * 5 / KHz(1); /* clocks in kHz */
2222*3f2dd94aSFrançois Tigeot 	unsigned int dco_min = 7998 * KHz(1);
2223*3f2dd94aSFrançois Tigeot 	unsigned int dco_max = 10000 * KHz(1);
2224*3f2dd94aSFrançois Tigeot 	unsigned int dco_mid = (dco_min + dco_max) / 2;
2225*3f2dd94aSFrançois Tigeot 
2226*3f2dd94aSFrançois Tigeot 	static const int dividers[] = {  2,  4,  6,  8, 10, 12,  14,  16,
2227*3f2dd94aSFrançois Tigeot 					 18, 20, 24, 28, 30, 32,  36,  40,
2228*3f2dd94aSFrançois Tigeot 					 42, 44, 48, 50, 52, 54,  56,  60,
2229*3f2dd94aSFrançois Tigeot 					 64, 66, 68, 70, 72, 76,  78,  80,
2230*3f2dd94aSFrançois Tigeot 					 84, 88, 90, 92, 96, 98, 100, 102,
2231*3f2dd94aSFrançois Tigeot 					  3,  5,  7,  9, 15, 21 };
2232*3f2dd94aSFrançois Tigeot 	unsigned int d, dco;
2233*3f2dd94aSFrançois Tigeot 	unsigned int dco_centrality = 0;
2234*3f2dd94aSFrançois Tigeot 	unsigned int best_dco_centrality = 999999;
2235*3f2dd94aSFrançois Tigeot 	unsigned int best_div = 0;
2236*3f2dd94aSFrançois Tigeot 	unsigned int best_dco = 0;
2237*3f2dd94aSFrançois Tigeot 	unsigned int pdiv = 0, qdiv = 0, kdiv = 0;
2238*3f2dd94aSFrançois Tigeot 
2239*3f2dd94aSFrançois Tigeot 	for (d = 0; d < ARRAY_SIZE(dividers); d++) {
2240*3f2dd94aSFrançois Tigeot 		dco = afe_clock * dividers[d];
2241*3f2dd94aSFrançois Tigeot 
2242*3f2dd94aSFrançois Tigeot 		if ((dco <= dco_max) && (dco >= dco_min)) {
2243*3f2dd94aSFrançois Tigeot 			dco_centrality = abs(dco - dco_mid);
2244*3f2dd94aSFrançois Tigeot 
2245*3f2dd94aSFrançois Tigeot 			if (dco_centrality < best_dco_centrality) {
2246*3f2dd94aSFrançois Tigeot 				best_dco_centrality = dco_centrality;
2247*3f2dd94aSFrançois Tigeot 				best_div = dividers[d];
2248*3f2dd94aSFrançois Tigeot 				best_dco = dco;
2249*3f2dd94aSFrançois Tigeot 			}
2250*3f2dd94aSFrançois Tigeot 		}
2251*3f2dd94aSFrançois Tigeot 	}
2252*3f2dd94aSFrançois Tigeot 
2253*3f2dd94aSFrançois Tigeot 	if (best_div == 0)
2254*3f2dd94aSFrançois Tigeot 		return false;
2255*3f2dd94aSFrançois Tigeot 
2256*3f2dd94aSFrançois Tigeot 	cnl_wrpll_get_multipliers(best_div, &pdiv, &qdiv, &kdiv);
2257*3f2dd94aSFrançois Tigeot 
2258*3f2dd94aSFrançois Tigeot 	cnl_wrpll_params_populate(wrpll_params, best_dco,
2259*3f2dd94aSFrançois Tigeot 				  dev_priv->cdclk.hw.ref, pdiv, qdiv, kdiv);
2260*3f2dd94aSFrançois Tigeot 
2261*3f2dd94aSFrançois Tigeot 	return true;
2262*3f2dd94aSFrançois Tigeot }
2263*3f2dd94aSFrançois Tigeot 
cnl_ddi_hdmi_pll_dividers(struct intel_crtc * crtc,struct intel_crtc_state * crtc_state,int clock)2264*3f2dd94aSFrançois Tigeot static bool cnl_ddi_hdmi_pll_dividers(struct intel_crtc *crtc,
2265*3f2dd94aSFrançois Tigeot 				      struct intel_crtc_state *crtc_state,
2266*3f2dd94aSFrançois Tigeot 				      int clock)
2267*3f2dd94aSFrançois Tigeot {
2268*3f2dd94aSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
2269*3f2dd94aSFrançois Tigeot 	uint32_t cfgcr0, cfgcr1;
2270*3f2dd94aSFrançois Tigeot 	struct skl_wrpll_params wrpll_params = { 0, };
2271*3f2dd94aSFrançois Tigeot 
2272*3f2dd94aSFrançois Tigeot 	cfgcr0 = DPLL_CFGCR0_HDMI_MODE;
2273*3f2dd94aSFrançois Tigeot 
2274*3f2dd94aSFrançois Tigeot 	if (!cnl_ddi_calculate_wrpll(clock * 1000, dev_priv, &wrpll_params))
2275*3f2dd94aSFrançois Tigeot 		return false;
2276*3f2dd94aSFrançois Tigeot 
2277*3f2dd94aSFrançois Tigeot 	cfgcr0 |= DPLL_CFGCR0_DCO_FRACTION(wrpll_params.dco_fraction) |
2278*3f2dd94aSFrançois Tigeot 		wrpll_params.dco_integer;
2279*3f2dd94aSFrançois Tigeot 
2280*3f2dd94aSFrançois Tigeot 	cfgcr1 = DPLL_CFGCR1_QDIV_RATIO(wrpll_params.qdiv_ratio) |
2281*3f2dd94aSFrançois Tigeot 		DPLL_CFGCR1_QDIV_MODE(wrpll_params.qdiv_mode) |
2282*3f2dd94aSFrançois Tigeot 		DPLL_CFGCR1_KDIV(wrpll_params.kdiv) |
2283*3f2dd94aSFrançois Tigeot 		DPLL_CFGCR1_PDIV(wrpll_params.pdiv) |
2284*3f2dd94aSFrançois Tigeot 		wrpll_params.central_freq |
2285*3f2dd94aSFrançois Tigeot 		DPLL_CFGCR1_CENTRAL_FREQ;
2286*3f2dd94aSFrançois Tigeot 
2287*3f2dd94aSFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
2288*3f2dd94aSFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
2289*3f2dd94aSFrançois Tigeot 
2290*3f2dd94aSFrançois Tigeot 	crtc_state->dpll_hw_state.cfgcr0 = cfgcr0;
2291*3f2dd94aSFrançois Tigeot 	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
2292*3f2dd94aSFrançois Tigeot 	return true;
2293*3f2dd94aSFrançois Tigeot }
2294*3f2dd94aSFrançois Tigeot 
2295*3f2dd94aSFrançois Tigeot static bool
cnl_ddi_dp_set_dpll_hw_state(int clock,struct intel_dpll_hw_state * dpll_hw_state)2296*3f2dd94aSFrançois Tigeot cnl_ddi_dp_set_dpll_hw_state(int clock,
2297*3f2dd94aSFrançois Tigeot 			     struct intel_dpll_hw_state *dpll_hw_state)
2298*3f2dd94aSFrançois Tigeot {
2299*3f2dd94aSFrançois Tigeot 	uint32_t cfgcr0;
2300*3f2dd94aSFrançois Tigeot 
2301*3f2dd94aSFrançois Tigeot 	cfgcr0 = DPLL_CFGCR0_SSC_ENABLE;
2302*3f2dd94aSFrançois Tigeot 
2303*3f2dd94aSFrançois Tigeot 	switch (clock / 2) {
2304*3f2dd94aSFrançois Tigeot 	case 81000:
2305*3f2dd94aSFrançois Tigeot 		cfgcr0 |= DPLL_CFGCR0_LINK_RATE_810;
2306*3f2dd94aSFrançois Tigeot 		break;
2307*3f2dd94aSFrançois Tigeot 	case 135000:
2308*3f2dd94aSFrançois Tigeot 		cfgcr0 |= DPLL_CFGCR0_LINK_RATE_1350;
2309*3f2dd94aSFrançois Tigeot 		break;
2310*3f2dd94aSFrançois Tigeot 	case 270000:
2311*3f2dd94aSFrançois Tigeot 		cfgcr0 |= DPLL_CFGCR0_LINK_RATE_2700;
2312*3f2dd94aSFrançois Tigeot 		break;
2313*3f2dd94aSFrançois Tigeot 		/* eDP 1.4 rates */
2314*3f2dd94aSFrançois Tigeot 	case 162000:
2315*3f2dd94aSFrançois Tigeot 		cfgcr0 |= DPLL_CFGCR0_LINK_RATE_1620;
2316*3f2dd94aSFrançois Tigeot 		break;
2317*3f2dd94aSFrançois Tigeot 	case 108000:
2318*3f2dd94aSFrançois Tigeot 		cfgcr0 |= DPLL_CFGCR0_LINK_RATE_1080;
2319*3f2dd94aSFrançois Tigeot 		break;
2320*3f2dd94aSFrançois Tigeot 	case 216000:
2321*3f2dd94aSFrançois Tigeot 		cfgcr0 |= DPLL_CFGCR0_LINK_RATE_2160;
2322*3f2dd94aSFrançois Tigeot 		break;
2323*3f2dd94aSFrançois Tigeot 	case 324000:
2324*3f2dd94aSFrançois Tigeot 		/* Some SKUs may require elevated I/O voltage to support this */
2325*3f2dd94aSFrançois Tigeot 		cfgcr0 |= DPLL_CFGCR0_LINK_RATE_3240;
2326*3f2dd94aSFrançois Tigeot 		break;
2327*3f2dd94aSFrançois Tigeot 	case 405000:
2328*3f2dd94aSFrançois Tigeot 		/* Some SKUs may require elevated I/O voltage to support this */
2329*3f2dd94aSFrançois Tigeot 		cfgcr0 |= DPLL_CFGCR0_LINK_RATE_4050;
2330*3f2dd94aSFrançois Tigeot 		break;
2331*3f2dd94aSFrançois Tigeot 	}
2332*3f2dd94aSFrançois Tigeot 
2333*3f2dd94aSFrançois Tigeot 	dpll_hw_state->cfgcr0 = cfgcr0;
2334*3f2dd94aSFrançois Tigeot 	return true;
2335*3f2dd94aSFrançois Tigeot }
2336*3f2dd94aSFrançois Tigeot 
2337*3f2dd94aSFrançois Tigeot static struct intel_shared_dpll *
cnl_get_dpll(struct intel_crtc * crtc,struct intel_crtc_state * crtc_state,struct intel_encoder * encoder)2338*3f2dd94aSFrançois Tigeot cnl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
2339*3f2dd94aSFrançois Tigeot 	     struct intel_encoder *encoder)
2340*3f2dd94aSFrançois Tigeot {
2341*3f2dd94aSFrançois Tigeot 	struct intel_shared_dpll *pll;
2342*3f2dd94aSFrançois Tigeot 	int clock = crtc_state->port_clock;
2343*3f2dd94aSFrançois Tigeot 	bool bret;
2344*3f2dd94aSFrançois Tigeot 	struct intel_dpll_hw_state dpll_hw_state;
2345*3f2dd94aSFrançois Tigeot 
2346*3f2dd94aSFrançois Tigeot 	memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
2347*3f2dd94aSFrançois Tigeot 
2348*3f2dd94aSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI) {
2349*3f2dd94aSFrançois Tigeot 		bret = cnl_ddi_hdmi_pll_dividers(crtc, crtc_state, clock);
2350*3f2dd94aSFrançois Tigeot 		if (!bret) {
2351*3f2dd94aSFrançois Tigeot 			DRM_DEBUG_KMS("Could not get HDMI pll dividers.\n");
2352*3f2dd94aSFrançois Tigeot 			return NULL;
2353*3f2dd94aSFrançois Tigeot 		}
2354*3f2dd94aSFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_DP ||
2355*3f2dd94aSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_DP_MST ||
2356*3f2dd94aSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_EDP) {
2357*3f2dd94aSFrançois Tigeot 		bret = cnl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state);
2358*3f2dd94aSFrançois Tigeot 		if (!bret) {
2359*3f2dd94aSFrançois Tigeot 			DRM_DEBUG_KMS("Could not set DP dpll HW state.\n");
2360*3f2dd94aSFrançois Tigeot 			return NULL;
2361*3f2dd94aSFrançois Tigeot 		}
2362*3f2dd94aSFrançois Tigeot 		crtc_state->dpll_hw_state = dpll_hw_state;
2363*3f2dd94aSFrançois Tigeot 	} else {
2364*3f2dd94aSFrançois Tigeot 		DRM_DEBUG_KMS("Skip DPLL setup for encoder %d\n",
2365*3f2dd94aSFrançois Tigeot 			      encoder->type);
2366*3f2dd94aSFrançois Tigeot 		return NULL;
2367*3f2dd94aSFrançois Tigeot 	}
2368*3f2dd94aSFrançois Tigeot 
2369*3f2dd94aSFrançois Tigeot 	pll = intel_find_shared_dpll(crtc, crtc_state,
2370*3f2dd94aSFrançois Tigeot 				     DPLL_ID_SKL_DPLL0,
2371*3f2dd94aSFrançois Tigeot 				     DPLL_ID_SKL_DPLL2);
2372*3f2dd94aSFrançois Tigeot 	if (!pll) {
2373*3f2dd94aSFrançois Tigeot 		DRM_DEBUG_KMS("No PLL selected\n");
2374*3f2dd94aSFrançois Tigeot 		return NULL;
2375*3f2dd94aSFrançois Tigeot 	}
2376*3f2dd94aSFrançois Tigeot 
2377*3f2dd94aSFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
2378*3f2dd94aSFrançois Tigeot 
2379*3f2dd94aSFrançois Tigeot 	return pll;
2380*3f2dd94aSFrançois Tigeot }
2381*3f2dd94aSFrançois Tigeot 
cnl_dump_hw_state(struct drm_i915_private * dev_priv,struct intel_dpll_hw_state * hw_state)2382*3f2dd94aSFrançois Tigeot static void cnl_dump_hw_state(struct drm_i915_private *dev_priv,
2383*3f2dd94aSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
2384*3f2dd94aSFrançois Tigeot {
2385*3f2dd94aSFrançois Tigeot 	DRM_DEBUG_KMS("dpll_hw_state: "
2386*3f2dd94aSFrançois Tigeot 		      "cfgcr0: 0x%x, cfgcr1: 0x%x\n",
2387*3f2dd94aSFrançois Tigeot 		      hw_state->cfgcr0,
2388*3f2dd94aSFrançois Tigeot 		      hw_state->cfgcr1);
2389*3f2dd94aSFrançois Tigeot }
2390*3f2dd94aSFrançois Tigeot 
2391*3f2dd94aSFrançois Tigeot static const struct intel_shared_dpll_funcs cnl_ddi_pll_funcs = {
2392*3f2dd94aSFrançois Tigeot 	.enable = cnl_ddi_pll_enable,
2393*3f2dd94aSFrançois Tigeot 	.disable = cnl_ddi_pll_disable,
2394*3f2dd94aSFrançois Tigeot 	.get_hw_state = cnl_ddi_pll_get_hw_state,
2395*3f2dd94aSFrançois Tigeot };
2396*3f2dd94aSFrançois Tigeot 
2397*3f2dd94aSFrançois Tigeot static const struct dpll_info cnl_plls[] = {
2398*3f2dd94aSFrançois Tigeot 	{ "DPLL 0", DPLL_ID_SKL_DPLL0, &cnl_ddi_pll_funcs, 0 },
2399*3f2dd94aSFrançois Tigeot 	{ "DPLL 1", DPLL_ID_SKL_DPLL1, &cnl_ddi_pll_funcs, 0 },
2400*3f2dd94aSFrançois Tigeot 	{ "DPLL 2", DPLL_ID_SKL_DPLL2, &cnl_ddi_pll_funcs, 0 },
2401*3f2dd94aSFrançois Tigeot 	{ NULL, -1, NULL, },
2402*3f2dd94aSFrançois Tigeot };
2403*3f2dd94aSFrançois Tigeot 
2404*3f2dd94aSFrançois Tigeot static const struct intel_dpll_mgr cnl_pll_mgr = {
2405*3f2dd94aSFrançois Tigeot 	.dpll_info = cnl_plls,
2406*3f2dd94aSFrançois Tigeot 	.get_dpll = cnl_get_dpll,
2407*3f2dd94aSFrançois Tigeot 	.dump_hw_state = cnl_dump_hw_state,
2408*3f2dd94aSFrançois Tigeot };
2409*3f2dd94aSFrançois Tigeot 
2410a85cb24fSFrançois Tigeot /**
2411a85cb24fSFrançois Tigeot  * intel_shared_dpll_init - Initialize shared DPLLs
2412a85cb24fSFrançois Tigeot  * @dev: drm device
2413a85cb24fSFrançois Tigeot  *
2414a85cb24fSFrançois Tigeot  * Initialize shared DPLLs for @dev.
2415a85cb24fSFrançois Tigeot  */
intel_shared_dpll_init(struct drm_device * dev)24168621f407SFrançois Tigeot void intel_shared_dpll_init(struct drm_device *dev)
24178621f407SFrançois Tigeot {
2418303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
24198621f407SFrançois Tigeot 	const struct intel_dpll_mgr *dpll_mgr = NULL;
24208621f407SFrançois Tigeot 	const struct dpll_info *dpll_info;
24218621f407SFrançois Tigeot 	int i;
24228621f407SFrançois Tigeot 
2423*3f2dd94aSFrançois Tigeot 	if (IS_CANNONLAKE(dev_priv))
2424*3f2dd94aSFrançois Tigeot 		dpll_mgr = &cnl_pll_mgr;
2425*3f2dd94aSFrançois Tigeot 	else if (IS_GEN9_BC(dev_priv))
24268621f407SFrançois Tigeot 		dpll_mgr = &skl_pll_mgr;
2427a85cb24fSFrançois Tigeot 	else if (IS_GEN9_LP(dev_priv))
24288621f407SFrançois Tigeot 		dpll_mgr = &bxt_pll_mgr;
24291e12ee3bSFrançois Tigeot 	else if (HAS_DDI(dev_priv))
24308621f407SFrançois Tigeot 		dpll_mgr = &hsw_pll_mgr;
24311e12ee3bSFrançois Tigeot 	else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))
24328621f407SFrançois Tigeot 		dpll_mgr = &pch_pll_mgr;
24338621f407SFrançois Tigeot 
24348621f407SFrançois Tigeot 	if (!dpll_mgr) {
24358621f407SFrançois Tigeot 		dev_priv->num_shared_dpll = 0;
24368621f407SFrançois Tigeot 		return;
24378621f407SFrançois Tigeot 	}
24388621f407SFrançois Tigeot 
24398621f407SFrançois Tigeot 	dpll_info = dpll_mgr->dpll_info;
24408621f407SFrançois Tigeot 
24418621f407SFrançois Tigeot 	for (i = 0; dpll_info[i].id >= 0; i++) {
24428621f407SFrançois Tigeot 		WARN_ON(i != dpll_info[i].id);
24438621f407SFrançois Tigeot 
24448621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].id = dpll_info[i].id;
24458621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].name = dpll_info[i].name;
24468621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].funcs = *dpll_info[i].funcs;
24478621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].flags = dpll_info[i].flags;
24488621f407SFrançois Tigeot 	}
24498621f407SFrançois Tigeot 
24508621f407SFrançois Tigeot 	dev_priv->dpll_mgr = dpll_mgr;
24518621f407SFrançois Tigeot 	dev_priv->num_shared_dpll = i;
24528621f407SFrançois Tigeot 	lockinit(&dev_priv->dpll_lock, "dpll_lock", 0, LK_CANRECURSE);
24538621f407SFrançois Tigeot 
24548621f407SFrançois Tigeot 	BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
24558621f407SFrançois Tigeot 
24568621f407SFrançois Tigeot 	/* FIXME: Move this to a more suitable place */
24571e12ee3bSFrançois Tigeot 	if (HAS_DDI(dev_priv))
24588621f407SFrançois Tigeot 		intel_ddi_pll_init(dev);
24598621f407SFrançois Tigeot }
24608621f407SFrançois Tigeot 
2461a85cb24fSFrançois Tigeot /**
2462a85cb24fSFrançois Tigeot  * intel_get_shared_dpll - get a shared DPLL for CRTC and encoder combination
2463a85cb24fSFrançois Tigeot  * @crtc: CRTC
2464a85cb24fSFrançois Tigeot  * @crtc_state: atomic state for @crtc
2465a85cb24fSFrançois Tigeot  * @encoder: encoder
2466a85cb24fSFrançois Tigeot  *
2467a85cb24fSFrançois Tigeot  * Find an appropriate DPLL for the given CRTC and encoder combination. A
2468a85cb24fSFrançois Tigeot  * reference from the @crtc to the returned pll is registered in the atomic
2469a85cb24fSFrançois Tigeot  * state. That configuration is made effective by calling
2470a85cb24fSFrançois Tigeot  * intel_shared_dpll_swap_state(). The reference should be released by calling
2471a85cb24fSFrançois Tigeot  * intel_release_shared_dpll().
2472a85cb24fSFrançois Tigeot  *
2473a85cb24fSFrançois Tigeot  * Returns:
2474a85cb24fSFrançois Tigeot  * A shared DPLL to be used by @crtc and @encoder with the given @crtc_state.
2475a85cb24fSFrançois Tigeot  */
24768621f407SFrançois Tigeot struct intel_shared_dpll *
intel_get_shared_dpll(struct intel_crtc * crtc,struct intel_crtc_state * crtc_state,struct intel_encoder * encoder)24778621f407SFrançois Tigeot intel_get_shared_dpll(struct intel_crtc *crtc,
24788621f407SFrançois Tigeot 		      struct intel_crtc_state *crtc_state,
24798621f407SFrançois Tigeot 		      struct intel_encoder *encoder)
24808621f407SFrançois Tigeot {
24818621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
24828621f407SFrançois Tigeot 	const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll_mgr;
24838621f407SFrançois Tigeot 
24848621f407SFrançois Tigeot 	if (WARN_ON(!dpll_mgr))
24858621f407SFrançois Tigeot 		return NULL;
24868621f407SFrançois Tigeot 
24878621f407SFrançois Tigeot 	return dpll_mgr->get_dpll(crtc, crtc_state, encoder);
24888621f407SFrançois Tigeot }
2489a85cb24fSFrançois Tigeot 
2490a85cb24fSFrançois Tigeot /**
2491a85cb24fSFrançois Tigeot  * intel_release_shared_dpll - end use of DPLL by CRTC in atomic state
2492a85cb24fSFrançois Tigeot  * @dpll: dpll in use by @crtc
2493a85cb24fSFrançois Tigeot  * @crtc: crtc
2494a85cb24fSFrançois Tigeot  * @state: atomic state
2495a85cb24fSFrançois Tigeot  *
2496a85cb24fSFrançois Tigeot  * This function releases the reference from @crtc to @dpll from the
2497a85cb24fSFrançois Tigeot  * atomic @state. The new configuration is made effective by calling
2498a85cb24fSFrançois Tigeot  * intel_shared_dpll_swap_state().
2499a85cb24fSFrançois Tigeot  */
intel_release_shared_dpll(struct intel_shared_dpll * dpll,struct intel_crtc * crtc,struct drm_atomic_state * state)2500a85cb24fSFrançois Tigeot void intel_release_shared_dpll(struct intel_shared_dpll *dpll,
2501a85cb24fSFrançois Tigeot 			       struct intel_crtc *crtc,
2502a85cb24fSFrançois Tigeot 			       struct drm_atomic_state *state)
2503a85cb24fSFrançois Tigeot {
2504a85cb24fSFrançois Tigeot 	struct intel_shared_dpll_state *shared_dpll_state;
2505a85cb24fSFrançois Tigeot 
2506a85cb24fSFrançois Tigeot 	shared_dpll_state = intel_atomic_get_shared_dpll_state(state);
2507a85cb24fSFrançois Tigeot 	shared_dpll_state[dpll->id].crtc_mask &= ~(1 << crtc->pipe);
2508a85cb24fSFrançois Tigeot }
2509a85cb24fSFrançois Tigeot 
2510a85cb24fSFrançois Tigeot /**
2511a85cb24fSFrançois Tigeot  * intel_shared_dpll_dump_hw_state - write hw_state to dmesg
2512a85cb24fSFrançois Tigeot  * @dev_priv: i915 drm device
2513a85cb24fSFrançois Tigeot  * @hw_state: hw state to be written to the log
2514a85cb24fSFrançois Tigeot  *
2515a85cb24fSFrançois Tigeot  * Write the relevant values in @hw_state to dmesg using DRM_DEBUG_KMS.
2516a85cb24fSFrançois Tigeot  */
intel_dpll_dump_hw_state(struct drm_i915_private * dev_priv,struct intel_dpll_hw_state * hw_state)2517a85cb24fSFrançois Tigeot void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv,
2518a85cb24fSFrançois Tigeot 			      struct intel_dpll_hw_state *hw_state)
2519a85cb24fSFrançois Tigeot {
2520a85cb24fSFrançois Tigeot 	if (dev_priv->dpll_mgr) {
2521a85cb24fSFrançois Tigeot 		dev_priv->dpll_mgr->dump_hw_state(dev_priv, hw_state);
2522a85cb24fSFrançois Tigeot 	} else {
2523a85cb24fSFrançois Tigeot 		/* fallback for platforms that don't use the shared dpll
2524a85cb24fSFrançois Tigeot 		 * infrastructure
2525a85cb24fSFrançois Tigeot 		 */
2526a85cb24fSFrançois Tigeot 		DRM_DEBUG_KMS("dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
2527a85cb24fSFrançois Tigeot 			      "fp0: 0x%x, fp1: 0x%x\n",
2528a85cb24fSFrançois Tigeot 			      hw_state->dpll,
2529a85cb24fSFrançois Tigeot 			      hw_state->dpll_md,
2530a85cb24fSFrançois Tigeot 			      hw_state->fp0,
2531a85cb24fSFrançois Tigeot 			      hw_state->fp1);
2532a85cb24fSFrançois Tigeot 	}
2533a85cb24fSFrançois Tigeot }
2534