xref: /dflybsd-src/sys/dev/drm/i915/intel_dpll_mgr.c (revision 1e12ee3baa16120663cde9c6c4c8e92b69b00794)
18621f407SFrançois Tigeot /*
28621f407SFrançois Tigeot  * Copyright © 2006-2016 Intel Corporation
38621f407SFrançois Tigeot  *
48621f407SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
58621f407SFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
68621f407SFrançois Tigeot  * to deal in the Software without restriction, including without limitation
78621f407SFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88621f407SFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
98621f407SFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
108621f407SFrançois Tigeot  *
118621f407SFrançois Tigeot  * The above copyright notice and this permission notice (including the next
128621f407SFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
138621f407SFrançois Tigeot  * Software.
148621f407SFrançois Tigeot  *
158621f407SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168621f407SFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178621f407SFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188621f407SFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
198621f407SFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
208621f407SFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
218621f407SFrançois Tigeot  * DEALINGS IN THE SOFTWARE.
228621f407SFrançois Tigeot  */
238621f407SFrançois Tigeot 
248621f407SFrançois Tigeot #include "intel_drv.h"
258621f407SFrançois Tigeot #include <asm/int-ll64.h>
268621f407SFrançois Tigeot 
278621f407SFrançois Tigeot struct intel_shared_dpll *
28*1e12ee3bSFrançois Tigeot skl_find_link_pll(struct drm_i915_private *dev_priv, int clock)
29*1e12ee3bSFrançois Tigeot {
30*1e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll = NULL;
31*1e12ee3bSFrançois Tigeot 	struct intel_dpll_hw_state dpll_hw_state;
32*1e12ee3bSFrançois Tigeot 	enum intel_dpll_id i;
33*1e12ee3bSFrançois Tigeot 	bool found = false;
34*1e12ee3bSFrançois Tigeot 
35*1e12ee3bSFrançois Tigeot 	if (!skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
36*1e12ee3bSFrançois Tigeot 		return pll;
37*1e12ee3bSFrançois Tigeot 
38*1e12ee3bSFrançois Tigeot 	for (i = DPLL_ID_SKL_DPLL1; i <= DPLL_ID_SKL_DPLL3; i++) {
39*1e12ee3bSFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
40*1e12ee3bSFrançois Tigeot 
41*1e12ee3bSFrançois Tigeot 		/* Only want to check enabled timings first */
42*1e12ee3bSFrançois Tigeot 		if (pll->config.crtc_mask == 0)
43*1e12ee3bSFrançois Tigeot 			continue;
44*1e12ee3bSFrançois Tigeot 
45*1e12ee3bSFrançois Tigeot 		if (memcmp(&dpll_hw_state, &pll->config.hw_state,
46*1e12ee3bSFrançois Tigeot 			   sizeof(pll->config.hw_state)) == 0) {
47*1e12ee3bSFrançois Tigeot 			found = true;
48*1e12ee3bSFrançois Tigeot 			break;
49*1e12ee3bSFrançois Tigeot 		}
50*1e12ee3bSFrançois Tigeot 	}
51*1e12ee3bSFrançois Tigeot 
52*1e12ee3bSFrançois Tigeot 	/* Ok no matching timings, maybe there's a free one? */
53*1e12ee3bSFrançois Tigeot 	for (i = DPLL_ID_SKL_DPLL1;
54*1e12ee3bSFrançois Tigeot 	     ((found == false) && (i <= DPLL_ID_SKL_DPLL3)); i++) {
55*1e12ee3bSFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
56*1e12ee3bSFrançois Tigeot 		if (pll->config.crtc_mask == 0) {
57*1e12ee3bSFrançois Tigeot 			pll->config.hw_state = dpll_hw_state;
58*1e12ee3bSFrançois Tigeot 			break;
59*1e12ee3bSFrançois Tigeot 		}
60*1e12ee3bSFrançois Tigeot 	}
61*1e12ee3bSFrançois Tigeot 
62*1e12ee3bSFrançois Tigeot 	return pll;
63*1e12ee3bSFrançois Tigeot }
64*1e12ee3bSFrançois Tigeot 
65*1e12ee3bSFrançois Tigeot struct intel_shared_dpll *
668621f407SFrançois Tigeot intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
678621f407SFrançois Tigeot 			    enum intel_dpll_id id)
688621f407SFrançois Tigeot {
698621f407SFrançois Tigeot 	return &dev_priv->shared_dplls[id];
708621f407SFrançois Tigeot }
718621f407SFrançois Tigeot 
728621f407SFrançois Tigeot enum intel_dpll_id
738621f407SFrançois Tigeot intel_get_shared_dpll_id(struct drm_i915_private *dev_priv,
748621f407SFrançois Tigeot 			 struct intel_shared_dpll *pll)
758621f407SFrançois Tigeot {
768621f407SFrançois Tigeot 	if (WARN_ON(pll < dev_priv->shared_dplls||
778621f407SFrançois Tigeot 		    pll > &dev_priv->shared_dplls[dev_priv->num_shared_dpll]))
788621f407SFrançois Tigeot 		return -1;
798621f407SFrançois Tigeot 
808621f407SFrançois Tigeot 	return (enum intel_dpll_id) (pll - dev_priv->shared_dplls);
818621f407SFrançois Tigeot }
828621f407SFrançois Tigeot 
838621f407SFrançois Tigeot void
848621f407SFrançois Tigeot intel_shared_dpll_config_get(struct intel_shared_dpll_config *config,
858621f407SFrançois Tigeot 			     struct intel_shared_dpll *pll,
868621f407SFrançois Tigeot 			     struct intel_crtc *crtc)
878621f407SFrançois Tigeot {
888621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
898621f407SFrançois Tigeot 	enum intel_dpll_id id = intel_get_shared_dpll_id(dev_priv, pll);
908621f407SFrançois Tigeot 
918621f407SFrançois Tigeot 	config[id].crtc_mask |= 1 << crtc->pipe;
928621f407SFrançois Tigeot }
938621f407SFrançois Tigeot 
948621f407SFrançois Tigeot void
958621f407SFrançois Tigeot intel_shared_dpll_config_put(struct intel_shared_dpll_config *config,
968621f407SFrançois Tigeot 			     struct intel_shared_dpll *pll,
978621f407SFrançois Tigeot 			     struct intel_crtc *crtc)
988621f407SFrançois Tigeot {
998621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
1008621f407SFrançois Tigeot 	enum intel_dpll_id id = intel_get_shared_dpll_id(dev_priv, pll);
1018621f407SFrançois Tigeot 
1028621f407SFrançois Tigeot 	config[id].crtc_mask &= ~(1 << crtc->pipe);
1038621f407SFrançois Tigeot }
1048621f407SFrançois Tigeot 
1058621f407SFrançois Tigeot /* For ILK+ */
1068621f407SFrançois Tigeot void assert_shared_dpll(struct drm_i915_private *dev_priv,
1078621f407SFrançois Tigeot 			struct intel_shared_dpll *pll,
1088621f407SFrançois Tigeot 			bool state)
1098621f407SFrançois Tigeot {
1108621f407SFrançois Tigeot 	bool cur_state;
1118621f407SFrançois Tigeot 	struct intel_dpll_hw_state hw_state;
1128621f407SFrançois Tigeot 
1138621f407SFrançois Tigeot 	if (WARN(!pll, "asserting DPLL %s with no DPLL\n", onoff(state)))
1148621f407SFrançois Tigeot 		return;
1158621f407SFrançois Tigeot 
1168621f407SFrançois Tigeot 	cur_state = pll->funcs.get_hw_state(dev_priv, pll, &hw_state);
1178621f407SFrançois Tigeot 	I915_STATE_WARN(cur_state != state,
1188621f407SFrançois Tigeot 	     "%s assertion failure (expected %s, current %s)\n",
1198621f407SFrançois Tigeot 			pll->name, onoff(state), onoff(cur_state));
1208621f407SFrançois Tigeot }
1218621f407SFrançois Tigeot 
1228621f407SFrançois Tigeot void intel_prepare_shared_dpll(struct intel_crtc *crtc)
1238621f407SFrançois Tigeot {
1248621f407SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
125303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1268621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
1278621f407SFrançois Tigeot 
1288621f407SFrançois Tigeot 	if (WARN_ON(pll == NULL))
1298621f407SFrançois Tigeot 		return;
1308621f407SFrançois Tigeot 
1318621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
1328621f407SFrançois Tigeot 	WARN_ON(!pll->config.crtc_mask);
1338621f407SFrançois Tigeot 	if (!pll->active_mask) {
1348621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("setting up %s\n", pll->name);
1358621f407SFrançois Tigeot 		WARN_ON(pll->on);
1368621f407SFrançois Tigeot 		assert_shared_dpll_disabled(dev_priv, pll);
1378621f407SFrançois Tigeot 
1388621f407SFrançois Tigeot 		pll->funcs.mode_set(dev_priv, pll);
1398621f407SFrançois Tigeot 	}
1408621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
1418621f407SFrançois Tigeot }
1428621f407SFrançois Tigeot 
1438621f407SFrançois Tigeot /**
1448621f407SFrançois Tigeot  * intel_enable_shared_dpll - enable PCH PLL
1458621f407SFrançois Tigeot  * @dev_priv: i915 private structure
1468621f407SFrançois Tigeot  * @pipe: pipe PLL to enable
1478621f407SFrançois Tigeot  *
1488621f407SFrançois Tigeot  * The PCH PLL needs to be enabled before the PCH transcoder, since it
1498621f407SFrançois Tigeot  * drives the transcoder clock.
1508621f407SFrançois Tigeot  */
1518621f407SFrançois Tigeot void intel_enable_shared_dpll(struct intel_crtc *crtc)
1528621f407SFrançois Tigeot {
1538621f407SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
154303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1558621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
1568621f407SFrançois Tigeot 	unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base);
1578621f407SFrançois Tigeot 	unsigned old_mask;
1588621f407SFrançois Tigeot 
1598621f407SFrançois Tigeot 	if (WARN_ON(pll == NULL))
1608621f407SFrançois Tigeot 		return;
1618621f407SFrançois Tigeot 
1628621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
1638621f407SFrançois Tigeot 	old_mask = pll->active_mask;
1648621f407SFrançois Tigeot 
1658621f407SFrançois Tigeot 	if (WARN_ON(!(pll->config.crtc_mask & crtc_mask)) ||
1668621f407SFrançois Tigeot 	    WARN_ON(pll->active_mask & crtc_mask))
1678621f407SFrançois Tigeot 		goto out;
1688621f407SFrançois Tigeot 
1698621f407SFrançois Tigeot 	pll->active_mask |= crtc_mask;
1708621f407SFrançois Tigeot 
1718621f407SFrançois Tigeot 	DRM_DEBUG_KMS("enable %s (active %x, on? %d) for crtc %d\n",
1728621f407SFrançois Tigeot 		      pll->name, pll->active_mask, pll->on,
1738621f407SFrançois Tigeot 		      crtc->base.base.id);
1748621f407SFrançois Tigeot 
1758621f407SFrançois Tigeot 	if (old_mask) {
1768621f407SFrançois Tigeot 		WARN_ON(!pll->on);
1778621f407SFrançois Tigeot 		assert_shared_dpll_enabled(dev_priv, pll);
1788621f407SFrançois Tigeot 		goto out;
1798621f407SFrançois Tigeot 	}
1808621f407SFrançois Tigeot 	WARN_ON(pll->on);
1818621f407SFrançois Tigeot 
1828621f407SFrançois Tigeot 	DRM_DEBUG_KMS("enabling %s\n", pll->name);
1838621f407SFrançois Tigeot 	pll->funcs.enable(dev_priv, pll);
1848621f407SFrançois Tigeot 	pll->on = true;
1858621f407SFrançois Tigeot 
1868621f407SFrançois Tigeot out:
1878621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
1888621f407SFrançois Tigeot }
1898621f407SFrançois Tigeot 
1908621f407SFrançois Tigeot void intel_disable_shared_dpll(struct intel_crtc *crtc)
1918621f407SFrançois Tigeot {
1928621f407SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
193303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1948621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
1958621f407SFrançois Tigeot 	unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base);
1968621f407SFrançois Tigeot 
1978621f407SFrançois Tigeot 	/* PCH only available on ILK+ */
1988621f407SFrançois Tigeot 	if (INTEL_INFO(dev)->gen < 5)
1998621f407SFrançois Tigeot 		return;
2008621f407SFrançois Tigeot 
2018621f407SFrançois Tigeot 	if (pll == NULL)
2028621f407SFrançois Tigeot 		return;
2038621f407SFrançois Tigeot 
2048621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
2058621f407SFrançois Tigeot 	if (WARN_ON(!(pll->active_mask & crtc_mask)))
2068621f407SFrançois Tigeot 		goto out;
2078621f407SFrançois Tigeot 
2088621f407SFrançois Tigeot 	DRM_DEBUG_KMS("disable %s (active %x, on? %d) for crtc %d\n",
2098621f407SFrançois Tigeot 		      pll->name, pll->active_mask, pll->on,
2108621f407SFrançois Tigeot 		      crtc->base.base.id);
2118621f407SFrançois Tigeot 
2128621f407SFrançois Tigeot 	assert_shared_dpll_enabled(dev_priv, pll);
2138621f407SFrançois Tigeot 	WARN_ON(!pll->on);
2148621f407SFrançois Tigeot 
2158621f407SFrançois Tigeot 	pll->active_mask &= ~crtc_mask;
2168621f407SFrançois Tigeot 	if (pll->active_mask)
2178621f407SFrançois Tigeot 		goto out;
2188621f407SFrançois Tigeot 
2198621f407SFrançois Tigeot 	DRM_DEBUG_KMS("disabling %s\n", pll->name);
2208621f407SFrançois Tigeot 	pll->funcs.disable(dev_priv, pll);
2218621f407SFrançois Tigeot 	pll->on = false;
2228621f407SFrançois Tigeot 
2238621f407SFrançois Tigeot out:
2248621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
2258621f407SFrançois Tigeot }
2268621f407SFrançois Tigeot 
2278621f407SFrançois Tigeot static struct intel_shared_dpll *
2288621f407SFrançois Tigeot intel_find_shared_dpll(struct intel_crtc *crtc,
2298621f407SFrançois Tigeot 		       struct intel_crtc_state *crtc_state,
2308621f407SFrançois Tigeot 		       enum intel_dpll_id range_min,
2318621f407SFrançois Tigeot 		       enum intel_dpll_id range_max)
2328621f407SFrançois Tigeot {
233303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
2348621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
2358621f407SFrançois Tigeot 	struct intel_shared_dpll_config *shared_dpll;
2368621f407SFrançois Tigeot 	enum intel_dpll_id i;
2378621f407SFrançois Tigeot 
2388621f407SFrançois Tigeot 	shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
2398621f407SFrançois Tigeot 
2408621f407SFrançois Tigeot 	for (i = range_min; i <= range_max; i++) {
2418621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
2428621f407SFrançois Tigeot 
2438621f407SFrançois Tigeot 		/* Only want to check enabled timings first */
2448621f407SFrançois Tigeot 		if (shared_dpll[i].crtc_mask == 0)
2458621f407SFrançois Tigeot 			continue;
2468621f407SFrançois Tigeot 
2478621f407SFrançois Tigeot 		if (memcmp(&crtc_state->dpll_hw_state,
2488621f407SFrançois Tigeot 			   &shared_dpll[i].hw_state,
2498621f407SFrançois Tigeot 			   sizeof(crtc_state->dpll_hw_state)) == 0) {
2501487f786SFrançois Tigeot 			DRM_DEBUG_KMS("[CRTC:%d:%s] sharing existing %s (crtc mask 0x%08x, active %x)\n",
2511487f786SFrançois Tigeot 				      crtc->base.base.id, crtc->base.name, pll->name,
2528621f407SFrançois Tigeot 				      shared_dpll[i].crtc_mask,
2538621f407SFrançois Tigeot 				      pll->active_mask);
2548621f407SFrançois Tigeot 			return pll;
2558621f407SFrançois Tigeot 		}
2568621f407SFrançois Tigeot 	}
2578621f407SFrançois Tigeot 
2588621f407SFrançois Tigeot 	/* Ok no matching timings, maybe there's a free one? */
2598621f407SFrançois Tigeot 	for (i = range_min; i <= range_max; i++) {
2608621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
2618621f407SFrançois Tigeot 		if (shared_dpll[i].crtc_mask == 0) {
2621487f786SFrançois Tigeot 			DRM_DEBUG_KMS("[CRTC:%d:%s] allocated %s\n",
2631487f786SFrançois Tigeot 				      crtc->base.base.id, crtc->base.name, pll->name);
2648621f407SFrançois Tigeot 			return pll;
2658621f407SFrançois Tigeot 		}
2668621f407SFrançois Tigeot 	}
2678621f407SFrançois Tigeot 
2688621f407SFrançois Tigeot 	return NULL;
2698621f407SFrançois Tigeot }
2708621f407SFrançois Tigeot 
2718621f407SFrançois Tigeot static void
2728621f407SFrançois Tigeot intel_reference_shared_dpll(struct intel_shared_dpll *pll,
2738621f407SFrançois Tigeot 			    struct intel_crtc_state *crtc_state)
2748621f407SFrançois Tigeot {
2758621f407SFrançois Tigeot 	struct intel_shared_dpll_config *shared_dpll;
2768621f407SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
2778621f407SFrançois Tigeot 	enum intel_dpll_id i = pll->id;
2788621f407SFrançois Tigeot 
2798621f407SFrançois Tigeot 	shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
2808621f407SFrançois Tigeot 
2818621f407SFrançois Tigeot 	if (shared_dpll[i].crtc_mask == 0)
2828621f407SFrançois Tigeot 		shared_dpll[i].hw_state =
2838621f407SFrançois Tigeot 			crtc_state->dpll_hw_state;
2848621f407SFrançois Tigeot 
2858621f407SFrançois Tigeot 	crtc_state->shared_dpll = pll;
2868621f407SFrançois Tigeot 	DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
2878621f407SFrançois Tigeot 			 pipe_name(crtc->pipe));
2888621f407SFrançois Tigeot 
2898621f407SFrançois Tigeot 	intel_shared_dpll_config_get(shared_dpll, pll, crtc);
2908621f407SFrançois Tigeot }
2918621f407SFrançois Tigeot 
2928621f407SFrançois Tigeot void intel_shared_dpll_commit(struct drm_atomic_state *state)
2938621f407SFrançois Tigeot {
2948621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(state->dev);
2958621f407SFrançois Tigeot 	struct intel_shared_dpll_config *shared_dpll;
2968621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
2978621f407SFrançois Tigeot 	enum intel_dpll_id i;
2988621f407SFrançois Tigeot 
2998621f407SFrançois Tigeot 	if (!to_intel_atomic_state(state)->dpll_set)
3008621f407SFrançois Tigeot 		return;
3018621f407SFrançois Tigeot 
3028621f407SFrançois Tigeot 	shared_dpll = to_intel_atomic_state(state)->shared_dpll;
3038621f407SFrançois Tigeot 	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
3048621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
3058621f407SFrançois Tigeot 		pll->config = shared_dpll[i];
3068621f407SFrançois Tigeot 	}
3078621f407SFrançois Tigeot }
3088621f407SFrançois Tigeot 
3098621f407SFrançois Tigeot static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
3108621f407SFrançois Tigeot 				      struct intel_shared_dpll *pll,
3118621f407SFrançois Tigeot 				      struct intel_dpll_hw_state *hw_state)
3128621f407SFrançois Tigeot {
3138621f407SFrançois Tigeot 	uint32_t val;
3148621f407SFrançois Tigeot 
3158621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
3168621f407SFrançois Tigeot 		return false;
3178621f407SFrançois Tigeot 
3188621f407SFrançois Tigeot 	val = I915_READ(PCH_DPLL(pll->id));
3198621f407SFrançois Tigeot 	hw_state->dpll = val;
3208621f407SFrançois Tigeot 	hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
3218621f407SFrançois Tigeot 	hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
3228621f407SFrançois Tigeot 
3238621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
3248621f407SFrançois Tigeot 
3258621f407SFrançois Tigeot 	return val & DPLL_VCO_ENABLE;
3268621f407SFrançois Tigeot }
3278621f407SFrançois Tigeot 
3288621f407SFrançois Tigeot static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv,
3298621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
3308621f407SFrançois Tigeot {
3318621f407SFrançois Tigeot 	I915_WRITE(PCH_FP0(pll->id), pll->config.hw_state.fp0);
3328621f407SFrançois Tigeot 	I915_WRITE(PCH_FP1(pll->id), pll->config.hw_state.fp1);
3338621f407SFrançois Tigeot }
3348621f407SFrançois Tigeot 
3358621f407SFrançois Tigeot static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
3368621f407SFrançois Tigeot {
3378621f407SFrançois Tigeot 	u32 val;
3388621f407SFrançois Tigeot 	bool enabled;
3398621f407SFrançois Tigeot 
3408621f407SFrançois Tigeot 	I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)));
3418621f407SFrançois Tigeot 
3428621f407SFrançois Tigeot 	val = I915_READ(PCH_DREF_CONTROL);
3438621f407SFrançois Tigeot 	enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
3448621f407SFrançois Tigeot 			    DREF_SUPERSPREAD_SOURCE_MASK));
3458621f407SFrançois Tigeot 	I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
3468621f407SFrançois Tigeot }
3478621f407SFrançois Tigeot 
3488621f407SFrançois Tigeot static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
3498621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
3508621f407SFrançois Tigeot {
3518621f407SFrançois Tigeot 	/* PCH refclock must be enabled first */
3528621f407SFrançois Tigeot 	ibx_assert_pch_refclk_enabled(dev_priv);
3538621f407SFrançois Tigeot 
3548621f407SFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
3558621f407SFrançois Tigeot 
3568621f407SFrançois Tigeot 	/* Wait for the clocks to stabilize. */
3578621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
3588621f407SFrançois Tigeot 	udelay(150);
3598621f407SFrançois Tigeot 
3608621f407SFrançois Tigeot 	/* The pixel multiplier can only be updated once the
3618621f407SFrançois Tigeot 	 * DPLL is enabled and the clocks are stable.
3628621f407SFrançois Tigeot 	 *
3638621f407SFrançois Tigeot 	 * So write it again.
3648621f407SFrançois Tigeot 	 */
3658621f407SFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
3668621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
3678621f407SFrançois Tigeot 	udelay(200);
3688621f407SFrançois Tigeot }
3698621f407SFrançois Tigeot 
3708621f407SFrançois Tigeot static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
3718621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
3728621f407SFrançois Tigeot {
373303bf270SFrançois Tigeot 	struct drm_device *dev = &dev_priv->drm;
3748621f407SFrançois Tigeot 	struct intel_crtc *crtc;
3758621f407SFrançois Tigeot 
3768621f407SFrançois Tigeot 	/* Make sure no transcoder isn't still depending on us. */
3778621f407SFrançois Tigeot 	for_each_intel_crtc(dev, crtc) {
3788621f407SFrançois Tigeot 		if (crtc->config->shared_dpll == pll)
3798621f407SFrançois Tigeot 			assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
3808621f407SFrançois Tigeot 	}
3818621f407SFrançois Tigeot 
3828621f407SFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), 0);
3838621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
3848621f407SFrançois Tigeot 	udelay(200);
3858621f407SFrançois Tigeot }
3868621f407SFrançois Tigeot 
3878621f407SFrançois Tigeot static struct intel_shared_dpll *
3888621f407SFrançois Tigeot ibx_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
3898621f407SFrançois Tigeot 	     struct intel_encoder *encoder)
3908621f407SFrançois Tigeot {
3918621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
3928621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
3938621f407SFrançois Tigeot 	enum intel_dpll_id i;
3948621f407SFrançois Tigeot 
3958621f407SFrançois Tigeot 	if (HAS_PCH_IBX(dev_priv)) {
3968621f407SFrançois Tigeot 		/* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
3978621f407SFrançois Tigeot 		i = (enum intel_dpll_id) crtc->pipe;
3988621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
3998621f407SFrançois Tigeot 
4001487f786SFrançois Tigeot 		DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n",
4011487f786SFrançois Tigeot 			      crtc->base.base.id, crtc->base.name, pll->name);
4028621f407SFrançois Tigeot 	} else {
4038621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
4048621f407SFrançois Tigeot 					     DPLL_ID_PCH_PLL_A,
4058621f407SFrançois Tigeot 					     DPLL_ID_PCH_PLL_B);
4068621f407SFrançois Tigeot 	}
4078621f407SFrançois Tigeot 
4088621f407SFrançois Tigeot 	if (!pll)
4098621f407SFrançois Tigeot 		return NULL;
4108621f407SFrançois Tigeot 
4118621f407SFrançois Tigeot 	/* reference the pll */
4128621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
4138621f407SFrançois Tigeot 
4148621f407SFrançois Tigeot 	return pll;
4158621f407SFrançois Tigeot }
4168621f407SFrançois Tigeot 
4178621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
4188621f407SFrançois Tigeot 	.mode_set = ibx_pch_dpll_mode_set,
4198621f407SFrançois Tigeot 	.enable = ibx_pch_dpll_enable,
4208621f407SFrançois Tigeot 	.disable = ibx_pch_dpll_disable,
4218621f407SFrançois Tigeot 	.get_hw_state = ibx_pch_dpll_get_hw_state,
4228621f407SFrançois Tigeot };
4238621f407SFrançois Tigeot 
4248621f407SFrançois Tigeot static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
4258621f407SFrançois Tigeot 			       struct intel_shared_dpll *pll)
4268621f407SFrançois Tigeot {
4278621f407SFrançois Tigeot 	I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
4288621f407SFrançois Tigeot 	POSTING_READ(WRPLL_CTL(pll->id));
4298621f407SFrançois Tigeot 	udelay(20);
4308621f407SFrançois Tigeot }
4318621f407SFrançois Tigeot 
4328621f407SFrançois Tigeot static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
4338621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
4348621f407SFrançois Tigeot {
4358621f407SFrançois Tigeot 	I915_WRITE(SPLL_CTL, pll->config.hw_state.spll);
4368621f407SFrançois Tigeot 	POSTING_READ(SPLL_CTL);
4378621f407SFrançois Tigeot 	udelay(20);
4388621f407SFrançois Tigeot }
4398621f407SFrançois Tigeot 
4408621f407SFrançois Tigeot static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
4418621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
4428621f407SFrançois Tigeot {
4438621f407SFrançois Tigeot 	uint32_t val;
4448621f407SFrançois Tigeot 
4458621f407SFrançois Tigeot 	val = I915_READ(WRPLL_CTL(pll->id));
4468621f407SFrançois Tigeot 	I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
4478621f407SFrançois Tigeot 	POSTING_READ(WRPLL_CTL(pll->id));
4488621f407SFrançois Tigeot }
4498621f407SFrançois Tigeot 
4508621f407SFrançois Tigeot static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
4518621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
4528621f407SFrançois Tigeot {
4538621f407SFrançois Tigeot 	uint32_t val;
4548621f407SFrançois Tigeot 
4558621f407SFrançois Tigeot 	val = I915_READ(SPLL_CTL);
4568621f407SFrançois Tigeot 	I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
4578621f407SFrançois Tigeot 	POSTING_READ(SPLL_CTL);
4588621f407SFrançois Tigeot }
4598621f407SFrançois Tigeot 
4608621f407SFrançois Tigeot static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
4618621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
4628621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
4638621f407SFrançois Tigeot {
4648621f407SFrançois Tigeot 	uint32_t val;
4658621f407SFrançois Tigeot 
4668621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
4678621f407SFrançois Tigeot 		return false;
4688621f407SFrançois Tigeot 
4698621f407SFrançois Tigeot 	val = I915_READ(WRPLL_CTL(pll->id));
4708621f407SFrançois Tigeot 	hw_state->wrpll = val;
4718621f407SFrançois Tigeot 
4728621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
4738621f407SFrançois Tigeot 
4748621f407SFrançois Tigeot 	return val & WRPLL_PLL_ENABLE;
4758621f407SFrançois Tigeot }
4768621f407SFrançois Tigeot 
4778621f407SFrançois Tigeot static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
4788621f407SFrançois Tigeot 				      struct intel_shared_dpll *pll,
4798621f407SFrançois Tigeot 				      struct intel_dpll_hw_state *hw_state)
4808621f407SFrançois Tigeot {
4818621f407SFrançois Tigeot 	uint32_t val;
4828621f407SFrançois Tigeot 
4838621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
4848621f407SFrançois Tigeot 		return false;
4858621f407SFrançois Tigeot 
4868621f407SFrançois Tigeot 	val = I915_READ(SPLL_CTL);
4878621f407SFrançois Tigeot 	hw_state->spll = val;
4888621f407SFrançois Tigeot 
4898621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
4908621f407SFrançois Tigeot 
4918621f407SFrançois Tigeot 	return val & SPLL_PLL_ENABLE;
4928621f407SFrançois Tigeot }
4938621f407SFrançois Tigeot 
4948621f407SFrançois Tigeot #define LC_FREQ 2700
4958621f407SFrançois Tigeot #define LC_FREQ_2K U64_C(LC_FREQ * 2000)
4968621f407SFrançois Tigeot 
4978621f407SFrançois Tigeot #define P_MIN 2
4988621f407SFrançois Tigeot #define P_MAX 64
4998621f407SFrançois Tigeot #define P_INC 2
5008621f407SFrançois Tigeot 
5018621f407SFrançois Tigeot /* Constraints for PLL good behavior */
5028621f407SFrançois Tigeot #define REF_MIN 48
5038621f407SFrançois Tigeot #define REF_MAX 400
5048621f407SFrançois Tigeot #define VCO_MIN 2400
5058621f407SFrançois Tigeot #define VCO_MAX 4800
5068621f407SFrançois Tigeot 
5078621f407SFrançois Tigeot struct hsw_wrpll_rnp {
5088621f407SFrançois Tigeot 	unsigned p, n2, r2;
5098621f407SFrançois Tigeot };
5108621f407SFrançois Tigeot 
5118621f407SFrançois Tigeot static unsigned hsw_wrpll_get_budget_for_freq(int clock)
5128621f407SFrançois Tigeot {
5138621f407SFrançois Tigeot 	unsigned budget;
5148621f407SFrançois Tigeot 
5158621f407SFrançois Tigeot 	switch (clock) {
5168621f407SFrançois Tigeot 	case 25175000:
5178621f407SFrançois Tigeot 	case 25200000:
5188621f407SFrançois Tigeot 	case 27000000:
5198621f407SFrançois Tigeot 	case 27027000:
5208621f407SFrançois Tigeot 	case 37762500:
5218621f407SFrançois Tigeot 	case 37800000:
5228621f407SFrançois Tigeot 	case 40500000:
5238621f407SFrançois Tigeot 	case 40541000:
5248621f407SFrançois Tigeot 	case 54000000:
5258621f407SFrançois Tigeot 	case 54054000:
5268621f407SFrançois Tigeot 	case 59341000:
5278621f407SFrançois Tigeot 	case 59400000:
5288621f407SFrançois Tigeot 	case 72000000:
5298621f407SFrançois Tigeot 	case 74176000:
5308621f407SFrançois Tigeot 	case 74250000:
5318621f407SFrançois Tigeot 	case 81000000:
5328621f407SFrançois Tigeot 	case 81081000:
5338621f407SFrançois Tigeot 	case 89012000:
5348621f407SFrançois Tigeot 	case 89100000:
5358621f407SFrançois Tigeot 	case 108000000:
5368621f407SFrançois Tigeot 	case 108108000:
5378621f407SFrançois Tigeot 	case 111264000:
5388621f407SFrançois Tigeot 	case 111375000:
5398621f407SFrançois Tigeot 	case 148352000:
5408621f407SFrançois Tigeot 	case 148500000:
5418621f407SFrançois Tigeot 	case 162000000:
5428621f407SFrançois Tigeot 	case 162162000:
5438621f407SFrançois Tigeot 	case 222525000:
5448621f407SFrançois Tigeot 	case 222750000:
5458621f407SFrançois Tigeot 	case 296703000:
5468621f407SFrançois Tigeot 	case 297000000:
5478621f407SFrançois Tigeot 		budget = 0;
5488621f407SFrançois Tigeot 		break;
5498621f407SFrançois Tigeot 	case 233500000:
5508621f407SFrançois Tigeot 	case 245250000:
5518621f407SFrançois Tigeot 	case 247750000:
5528621f407SFrançois Tigeot 	case 253250000:
5538621f407SFrançois Tigeot 	case 298000000:
5548621f407SFrançois Tigeot 		budget = 1500;
5558621f407SFrançois Tigeot 		break;
5568621f407SFrançois Tigeot 	case 169128000:
5578621f407SFrançois Tigeot 	case 169500000:
5588621f407SFrançois Tigeot 	case 179500000:
5598621f407SFrançois Tigeot 	case 202000000:
5608621f407SFrançois Tigeot 		budget = 2000;
5618621f407SFrançois Tigeot 		break;
5628621f407SFrançois Tigeot 	case 256250000:
5638621f407SFrançois Tigeot 	case 262500000:
5648621f407SFrançois Tigeot 	case 270000000:
5658621f407SFrançois Tigeot 	case 272500000:
5668621f407SFrançois Tigeot 	case 273750000:
5678621f407SFrançois Tigeot 	case 280750000:
5688621f407SFrançois Tigeot 	case 281250000:
5698621f407SFrançois Tigeot 	case 286000000:
5708621f407SFrançois Tigeot 	case 291750000:
5718621f407SFrançois Tigeot 		budget = 4000;
5728621f407SFrançois Tigeot 		break;
5738621f407SFrançois Tigeot 	case 267250000:
5748621f407SFrançois Tigeot 	case 268500000:
5758621f407SFrançois Tigeot 		budget = 5000;
5768621f407SFrançois Tigeot 		break;
5778621f407SFrançois Tigeot 	default:
5788621f407SFrançois Tigeot 		budget = 1000;
5798621f407SFrançois Tigeot 		break;
5808621f407SFrançois Tigeot 	}
5818621f407SFrançois Tigeot 
5828621f407SFrançois Tigeot 	return budget;
5838621f407SFrançois Tigeot }
5848621f407SFrançois Tigeot 
5858621f407SFrançois Tigeot static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget,
5868621f407SFrançois Tigeot 				 unsigned r2, unsigned n2, unsigned p,
5878621f407SFrançois Tigeot 				 struct hsw_wrpll_rnp *best)
5888621f407SFrançois Tigeot {
5898621f407SFrançois Tigeot 	uint64_t a, b, c, d, diff, diff_best;
5908621f407SFrançois Tigeot 
5918621f407SFrançois Tigeot 	/* No best (r,n,p) yet */
5928621f407SFrançois Tigeot 	if (best->p == 0) {
5938621f407SFrançois Tigeot 		best->p = p;
5948621f407SFrançois Tigeot 		best->n2 = n2;
5958621f407SFrançois Tigeot 		best->r2 = r2;
5968621f407SFrançois Tigeot 		return;
5978621f407SFrançois Tigeot 	}
5988621f407SFrançois Tigeot 
5998621f407SFrançois Tigeot 	/*
6008621f407SFrançois Tigeot 	 * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
6018621f407SFrançois Tigeot 	 * freq2k.
6028621f407SFrançois Tigeot 	 *
6038621f407SFrançois Tigeot 	 * delta = 1e6 *
6048621f407SFrançois Tigeot 	 *	   abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
6058621f407SFrançois Tigeot 	 *	   freq2k;
6068621f407SFrançois Tigeot 	 *
6078621f407SFrançois Tigeot 	 * and we would like delta <= budget.
6088621f407SFrançois Tigeot 	 *
6098621f407SFrançois Tigeot 	 * If the discrepancy is above the PPM-based budget, always prefer to
6108621f407SFrançois Tigeot 	 * improve upon the previous solution.  However, if you're within the
6118621f407SFrançois Tigeot 	 * budget, try to maximize Ref * VCO, that is N / (P * R^2).
6128621f407SFrançois Tigeot 	 */
6138621f407SFrançois Tigeot 	a = freq2k * budget * p * r2;
6148621f407SFrançois Tigeot 	b = freq2k * budget * best->p * best->r2;
6158621f407SFrançois Tigeot 	diff = abs_diff((u64)freq2k * p * r2, LC_FREQ_2K * n2);
6168621f407SFrançois Tigeot 	diff_best = abs_diff((u64)freq2k * best->p * best->r2,
6178621f407SFrançois Tigeot 			     LC_FREQ_2K * best->n2);
6188621f407SFrançois Tigeot 	c = 1000000 * diff;
6198621f407SFrançois Tigeot 	d = 1000000 * diff_best;
6208621f407SFrançois Tigeot 
6218621f407SFrançois Tigeot 	if (a < c && b < d) {
6228621f407SFrançois Tigeot 		/* If both are above the budget, pick the closer */
6238621f407SFrançois Tigeot 		if (best->p * best->r2 * diff < p * r2 * diff_best) {
6248621f407SFrançois Tigeot 			best->p = p;
6258621f407SFrançois Tigeot 			best->n2 = n2;
6268621f407SFrançois Tigeot 			best->r2 = r2;
6278621f407SFrançois Tigeot 		}
6288621f407SFrançois Tigeot 	} else if (a >= c && b < d) {
6298621f407SFrançois Tigeot 		/* If A is below the threshold but B is above it?  Update. */
6308621f407SFrançois Tigeot 		best->p = p;
6318621f407SFrançois Tigeot 		best->n2 = n2;
6328621f407SFrançois Tigeot 		best->r2 = r2;
6338621f407SFrançois Tigeot 	} else if (a >= c && b >= d) {
6348621f407SFrançois Tigeot 		/* Both are below the limit, so pick the higher n2/(r2*r2) */
6358621f407SFrançois Tigeot 		if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) {
6368621f407SFrançois Tigeot 			best->p = p;
6378621f407SFrançois Tigeot 			best->n2 = n2;
6388621f407SFrançois Tigeot 			best->r2 = r2;
6398621f407SFrançois Tigeot 		}
6408621f407SFrançois Tigeot 	}
6418621f407SFrançois Tigeot 	/* Otherwise a < c && b >= d, do nothing */
6428621f407SFrançois Tigeot }
6438621f407SFrançois Tigeot 
6448621f407SFrançois Tigeot static void
6458621f407SFrançois Tigeot hsw_ddi_calculate_wrpll(int clock /* in Hz */,
6468621f407SFrançois Tigeot 			unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
6478621f407SFrançois Tigeot {
6488621f407SFrançois Tigeot 	uint64_t freq2k;
6498621f407SFrançois Tigeot 	unsigned p, n2, r2;
6508621f407SFrançois Tigeot 	struct hsw_wrpll_rnp best = { 0, 0, 0 };
6518621f407SFrançois Tigeot 	unsigned budget;
6528621f407SFrançois Tigeot 
6538621f407SFrançois Tigeot 	freq2k = clock / 100;
6548621f407SFrançois Tigeot 
6558621f407SFrançois Tigeot 	budget = hsw_wrpll_get_budget_for_freq(clock);
6568621f407SFrançois Tigeot 
6578621f407SFrançois Tigeot 	/* Special case handling for 540 pixel clock: bypass WR PLL entirely
6588621f407SFrançois Tigeot 	 * and directly pass the LC PLL to it. */
6598621f407SFrançois Tigeot 	if (freq2k == 5400000) {
6608621f407SFrançois Tigeot 		*n2_out = 2;
6618621f407SFrançois Tigeot 		*p_out = 1;
6628621f407SFrançois Tigeot 		*r2_out = 2;
6638621f407SFrançois Tigeot 		return;
6648621f407SFrançois Tigeot 	}
6658621f407SFrançois Tigeot 
6668621f407SFrançois Tigeot 	/*
6678621f407SFrançois Tigeot 	 * Ref = LC_FREQ / R, where Ref is the actual reference input seen by
6688621f407SFrançois Tigeot 	 * the WR PLL.
6698621f407SFrançois Tigeot 	 *
6708621f407SFrançois Tigeot 	 * We want R so that REF_MIN <= Ref <= REF_MAX.
6718621f407SFrançois Tigeot 	 * Injecting R2 = 2 * R gives:
6728621f407SFrançois Tigeot 	 *   REF_MAX * r2 > LC_FREQ * 2 and
6738621f407SFrançois Tigeot 	 *   REF_MIN * r2 < LC_FREQ * 2
6748621f407SFrançois Tigeot 	 *
6758621f407SFrançois Tigeot 	 * Which means the desired boundaries for r2 are:
6768621f407SFrançois Tigeot 	 *  LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
6778621f407SFrançois Tigeot 	 *
6788621f407SFrançois Tigeot 	 */
6798621f407SFrançois Tigeot 	for (r2 = LC_FREQ * 2 / REF_MAX + 1;
6808621f407SFrançois Tigeot 	     r2 <= LC_FREQ * 2 / REF_MIN;
6818621f407SFrançois Tigeot 	     r2++) {
6828621f407SFrançois Tigeot 
6838621f407SFrançois Tigeot 		/*
6848621f407SFrançois Tigeot 		 * VCO = N * Ref, that is: VCO = N * LC_FREQ / R
6858621f407SFrançois Tigeot 		 *
6868621f407SFrançois Tigeot 		 * Once again we want VCO_MIN <= VCO <= VCO_MAX.
6878621f407SFrançois Tigeot 		 * Injecting R2 = 2 * R and N2 = 2 * N, we get:
6888621f407SFrançois Tigeot 		 *   VCO_MAX * r2 > n2 * LC_FREQ and
6898621f407SFrançois Tigeot 		 *   VCO_MIN * r2 < n2 * LC_FREQ)
6908621f407SFrançois Tigeot 		 *
6918621f407SFrançois Tigeot 		 * Which means the desired boundaries for n2 are:
6928621f407SFrançois Tigeot 		 * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
6938621f407SFrançois Tigeot 		 */
6948621f407SFrançois Tigeot 		for (n2 = VCO_MIN * r2 / LC_FREQ + 1;
6958621f407SFrançois Tigeot 		     n2 <= VCO_MAX * r2 / LC_FREQ;
6968621f407SFrançois Tigeot 		     n2++) {
6978621f407SFrançois Tigeot 
6988621f407SFrançois Tigeot 			for (p = P_MIN; p <= P_MAX; p += P_INC)
6998621f407SFrançois Tigeot 				hsw_wrpll_update_rnp(freq2k, budget,
7008621f407SFrançois Tigeot 						     r2, n2, p, &best);
7018621f407SFrançois Tigeot 		}
7028621f407SFrançois Tigeot 	}
7038621f407SFrançois Tigeot 
7048621f407SFrançois Tigeot 	*n2_out = best.n2;
7058621f407SFrançois Tigeot 	*p_out = best.p;
7068621f407SFrançois Tigeot 	*r2_out = best.r2;
7078621f407SFrançois Tigeot }
7088621f407SFrançois Tigeot 
709*1e12ee3bSFrançois Tigeot static struct intel_shared_dpll *hsw_ddi_hdmi_get_dpll(int clock,
710*1e12ee3bSFrançois Tigeot 						       struct intel_crtc *crtc,
711*1e12ee3bSFrançois Tigeot 						       struct intel_crtc_state *crtc_state)
7128621f407SFrançois Tigeot {
7138621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
7148621f407SFrançois Tigeot 	uint32_t val;
715*1e12ee3bSFrançois Tigeot 	unsigned int p, n2, r2;
7168621f407SFrançois Tigeot 
7178621f407SFrançois Tigeot 	hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
7188621f407SFrançois Tigeot 
7198621f407SFrançois Tigeot 	val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
7208621f407SFrançois Tigeot 	      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
7218621f407SFrançois Tigeot 	      WRPLL_DIVIDER_POST(p);
7228621f407SFrançois Tigeot 
7238621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.wrpll = val;
7248621f407SFrançois Tigeot 
7258621f407SFrançois Tigeot 	pll = intel_find_shared_dpll(crtc, crtc_state,
7268621f407SFrançois Tigeot 				     DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
7278621f407SFrançois Tigeot 
728*1e12ee3bSFrançois Tigeot 	if (!pll)
729*1e12ee3bSFrançois Tigeot 		return NULL;
730*1e12ee3bSFrançois Tigeot 
731*1e12ee3bSFrançois Tigeot 	return pll;
732*1e12ee3bSFrançois Tigeot }
733*1e12ee3bSFrançois Tigeot 
734*1e12ee3bSFrançois Tigeot struct intel_shared_dpll *hsw_ddi_dp_get_dpll(struct intel_encoder *encoder,
735*1e12ee3bSFrançois Tigeot 					      int clock)
736*1e12ee3bSFrançois Tigeot {
737*1e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
738*1e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
7398621f407SFrançois Tigeot 	enum intel_dpll_id pll_id;
7408621f407SFrançois Tigeot 
7418621f407SFrançois Tigeot 	switch (clock / 2) {
7428621f407SFrançois Tigeot 	case 81000:
7438621f407SFrançois Tigeot 		pll_id = DPLL_ID_LCPLL_810;
7448621f407SFrançois Tigeot 		break;
7458621f407SFrançois Tigeot 	case 135000:
7468621f407SFrançois Tigeot 		pll_id = DPLL_ID_LCPLL_1350;
7478621f407SFrançois Tigeot 		break;
7488621f407SFrançois Tigeot 	case 270000:
7498621f407SFrançois Tigeot 		pll_id = DPLL_ID_LCPLL_2700;
7508621f407SFrançois Tigeot 		break;
7518621f407SFrançois Tigeot 	default:
7528621f407SFrançois Tigeot 		DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
7538621f407SFrançois Tigeot 		return NULL;
7548621f407SFrançois Tigeot 	}
7558621f407SFrançois Tigeot 
7568621f407SFrançois Tigeot 	pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
7578621f407SFrançois Tigeot 
758*1e12ee3bSFrançois Tigeot 	if (!pll)
759*1e12ee3bSFrançois Tigeot 		return NULL;
760*1e12ee3bSFrançois Tigeot 
761*1e12ee3bSFrançois Tigeot 	return pll;
762*1e12ee3bSFrançois Tigeot }
763*1e12ee3bSFrançois Tigeot 
764*1e12ee3bSFrançois Tigeot static struct intel_shared_dpll *
765*1e12ee3bSFrançois Tigeot hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
766*1e12ee3bSFrançois Tigeot 	     struct intel_encoder *encoder)
767*1e12ee3bSFrançois Tigeot {
768*1e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
769*1e12ee3bSFrançois Tigeot 	int clock = crtc_state->port_clock;
770*1e12ee3bSFrançois Tigeot 
771*1e12ee3bSFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
772*1e12ee3bSFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
773*1e12ee3bSFrançois Tigeot 
774*1e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI) {
775*1e12ee3bSFrançois Tigeot 		pll = hsw_ddi_hdmi_get_dpll(clock, crtc, crtc_state);
776*1e12ee3bSFrançois Tigeot 
777*1e12ee3bSFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_DP ||
778*1e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_DP_MST ||
779*1e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_EDP) {
780*1e12ee3bSFrançois Tigeot 		pll = hsw_ddi_dp_get_dpll(encoder, clock);
781*1e12ee3bSFrançois Tigeot 
7828621f407SFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_ANALOG) {
7838621f407SFrançois Tigeot 		if (WARN_ON(crtc_state->port_clock / 2 != 135000))
7848621f407SFrançois Tigeot 			return NULL;
7858621f407SFrançois Tigeot 
7868621f407SFrançois Tigeot 		crtc_state->dpll_hw_state.spll =
7878621f407SFrançois Tigeot 			SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
7888621f407SFrançois Tigeot 
7898621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
7908621f407SFrançois Tigeot 					     DPLL_ID_SPLL, DPLL_ID_SPLL);
7918621f407SFrançois Tigeot 	} else {
7928621f407SFrançois Tigeot 		return NULL;
7938621f407SFrançois Tigeot 	}
7948621f407SFrançois Tigeot 
7958621f407SFrançois Tigeot 	if (!pll)
7968621f407SFrançois Tigeot 		return NULL;
7978621f407SFrançois Tigeot 
7988621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
7998621f407SFrançois Tigeot 
8008621f407SFrançois Tigeot 	return pll;
8018621f407SFrançois Tigeot }
8028621f407SFrançois Tigeot 
8038621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
8048621f407SFrançois Tigeot 	.enable = hsw_ddi_wrpll_enable,
8058621f407SFrançois Tigeot 	.disable = hsw_ddi_wrpll_disable,
8068621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_wrpll_get_hw_state,
8078621f407SFrançois Tigeot };
8088621f407SFrançois Tigeot 
8098621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_spll_funcs = {
8108621f407SFrançois Tigeot 	.enable = hsw_ddi_spll_enable,
8118621f407SFrançois Tigeot 	.disable = hsw_ddi_spll_disable,
8128621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_spll_get_hw_state,
8138621f407SFrançois Tigeot };
8148621f407SFrançois Tigeot 
8158621f407SFrançois Tigeot static void hsw_ddi_lcpll_enable(struct drm_i915_private *dev_priv,
8168621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
8178621f407SFrançois Tigeot {
8188621f407SFrançois Tigeot }
8198621f407SFrançois Tigeot 
8208621f407SFrançois Tigeot static void hsw_ddi_lcpll_disable(struct drm_i915_private *dev_priv,
8218621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
8228621f407SFrançois Tigeot {
8238621f407SFrançois Tigeot }
8248621f407SFrançois Tigeot 
8258621f407SFrançois Tigeot static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,
8268621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
8278621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
8288621f407SFrançois Tigeot {
8298621f407SFrançois Tigeot 	return true;
8308621f407SFrançois Tigeot }
8318621f407SFrançois Tigeot 
8328621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = {
8338621f407SFrançois Tigeot 	.enable = hsw_ddi_lcpll_enable,
8348621f407SFrançois Tigeot 	.disable = hsw_ddi_lcpll_disable,
8358621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_lcpll_get_hw_state,
8368621f407SFrançois Tigeot };
8378621f407SFrançois Tigeot 
8388621f407SFrançois Tigeot struct skl_dpll_regs {
8398621f407SFrançois Tigeot 	i915_reg_t ctl, cfgcr1, cfgcr2;
8408621f407SFrançois Tigeot };
8418621f407SFrançois Tigeot 
8428621f407SFrançois Tigeot /* this array is indexed by the *shared* pll id */
8438621f407SFrançois Tigeot static const struct skl_dpll_regs skl_dpll_regs[4] = {
8448621f407SFrançois Tigeot 	{
8458621f407SFrançois Tigeot 		/* DPLL 0 */
8468621f407SFrançois Tigeot 		.ctl = LCPLL1_CTL,
8478621f407SFrançois Tigeot 		/* DPLL 0 doesn't support HDMI mode */
8488621f407SFrançois Tigeot 	},
8498621f407SFrançois Tigeot 	{
8508621f407SFrançois Tigeot 		/* DPLL 1 */
8518621f407SFrançois Tigeot 		.ctl = LCPLL2_CTL,
8528621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
8538621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
8548621f407SFrançois Tigeot 	},
8558621f407SFrançois Tigeot 	{
8568621f407SFrançois Tigeot 		/* DPLL 2 */
8578621f407SFrançois Tigeot 		.ctl = WRPLL_CTL(0),
8588621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
8598621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
8608621f407SFrançois Tigeot 	},
8618621f407SFrançois Tigeot 	{
8628621f407SFrançois Tigeot 		/* DPLL 3 */
8638621f407SFrançois Tigeot 		.ctl = WRPLL_CTL(1),
8648621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
8658621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
8668621f407SFrançois Tigeot 	},
8678621f407SFrançois Tigeot };
8688621f407SFrançois Tigeot 
8698621f407SFrançois Tigeot static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *dev_priv,
8708621f407SFrançois Tigeot 				    struct intel_shared_dpll *pll)
8718621f407SFrançois Tigeot {
8728621f407SFrançois Tigeot 	uint32_t val;
8738621f407SFrançois Tigeot 
8748621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
8758621f407SFrançois Tigeot 
8768621f407SFrançois Tigeot 	val &= ~(DPLL_CTRL1_HDMI_MODE(pll->id) | DPLL_CTRL1_SSC(pll->id) |
8778621f407SFrançois Tigeot 		 DPLL_CTRL1_LINK_RATE_MASK(pll->id));
8788621f407SFrançois Tigeot 	val |= pll->config.hw_state.ctrl1 << (pll->id * 6);
8798621f407SFrançois Tigeot 
8808621f407SFrançois Tigeot 	I915_WRITE(DPLL_CTRL1, val);
8818621f407SFrançois Tigeot 	POSTING_READ(DPLL_CTRL1);
8828621f407SFrançois Tigeot }
8838621f407SFrançois Tigeot 
8848621f407SFrançois Tigeot static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
8858621f407SFrançois Tigeot 			       struct intel_shared_dpll *pll)
8868621f407SFrançois Tigeot {
8878621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
8888621f407SFrançois Tigeot 
8898621f407SFrançois Tigeot 	skl_ddi_pll_write_ctrl1(dev_priv, pll);
8908621f407SFrançois Tigeot 
8918621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].cfgcr1, pll->config.hw_state.cfgcr1);
8928621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].cfgcr2, pll->config.hw_state.cfgcr2);
8938621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].cfgcr1);
8948621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].cfgcr2);
8958621f407SFrançois Tigeot 
8968621f407SFrançois Tigeot 	/* the enable bit is always bit 31 */
8978621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].ctl,
8988621f407SFrançois Tigeot 		   I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE);
8998621f407SFrançois Tigeot 
9001487f786SFrançois Tigeot 	if (intel_wait_for_register(dev_priv,
9011487f786SFrançois Tigeot 				    DPLL_STATUS,
9021487f786SFrançois Tigeot 				    DPLL_LOCK(pll->id),
9031487f786SFrançois Tigeot 				    DPLL_LOCK(pll->id),
9041487f786SFrançois Tigeot 				    5))
9058621f407SFrançois Tigeot 		DRM_ERROR("DPLL %d not locked\n", pll->id);
9068621f407SFrançois Tigeot }
9078621f407SFrançois Tigeot 
9088621f407SFrançois Tigeot static void skl_ddi_dpll0_enable(struct drm_i915_private *dev_priv,
9098621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
9108621f407SFrançois Tigeot {
9118621f407SFrançois Tigeot 	skl_ddi_pll_write_ctrl1(dev_priv, pll);
9128621f407SFrançois Tigeot }
9138621f407SFrançois Tigeot 
9148621f407SFrançois Tigeot static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
9158621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
9168621f407SFrançois Tigeot {
9178621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
9188621f407SFrançois Tigeot 
9198621f407SFrançois Tigeot 	/* the enable bit is always bit 31 */
9208621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].ctl,
9218621f407SFrançois Tigeot 		   I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE);
9228621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].ctl);
9238621f407SFrançois Tigeot }
9248621f407SFrançois Tigeot 
9258621f407SFrançois Tigeot static void skl_ddi_dpll0_disable(struct drm_i915_private *dev_priv,
9268621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
9278621f407SFrançois Tigeot {
9288621f407SFrançois Tigeot }
9298621f407SFrançois Tigeot 
9308621f407SFrançois Tigeot static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
9318621f407SFrançois Tigeot 				     struct intel_shared_dpll *pll,
9328621f407SFrançois Tigeot 				     struct intel_dpll_hw_state *hw_state)
9338621f407SFrançois Tigeot {
9348621f407SFrançois Tigeot 	uint32_t val;
9358621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
9368621f407SFrançois Tigeot 	bool ret;
9378621f407SFrançois Tigeot 
9388621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
9398621f407SFrançois Tigeot 		return false;
9408621f407SFrançois Tigeot 
9418621f407SFrançois Tigeot 	ret = false;
9428621f407SFrançois Tigeot 
9438621f407SFrançois Tigeot 	val = I915_READ(regs[pll->id].ctl);
9448621f407SFrançois Tigeot 	if (!(val & LCPLL_PLL_ENABLE))
9458621f407SFrançois Tigeot 		goto out;
9468621f407SFrançois Tigeot 
9478621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
9488621f407SFrançois Tigeot 	hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
9498621f407SFrançois Tigeot 
9508621f407SFrançois Tigeot 	/* avoid reading back stale values if HDMI mode is not enabled */
9518621f407SFrançois Tigeot 	if (val & DPLL_CTRL1_HDMI_MODE(pll->id)) {
9528621f407SFrançois Tigeot 		hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
9538621f407SFrançois Tigeot 		hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
9548621f407SFrançois Tigeot 	}
9558621f407SFrançois Tigeot 	ret = true;
9568621f407SFrançois Tigeot 
9578621f407SFrançois Tigeot out:
9588621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
9598621f407SFrançois Tigeot 
9608621f407SFrançois Tigeot 	return ret;
9618621f407SFrançois Tigeot }
9628621f407SFrançois Tigeot 
9638621f407SFrançois Tigeot static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
9648621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
9658621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
9668621f407SFrançois Tigeot {
9678621f407SFrançois Tigeot 	uint32_t val;
9688621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
9698621f407SFrançois Tigeot 	bool ret;
9708621f407SFrançois Tigeot 
9718621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
9728621f407SFrançois Tigeot 		return false;
9738621f407SFrançois Tigeot 
9748621f407SFrançois Tigeot 	ret = false;
9758621f407SFrançois Tigeot 
9768621f407SFrançois Tigeot 	/* DPLL0 is always enabled since it drives CDCLK */
9778621f407SFrançois Tigeot 	val = I915_READ(regs[pll->id].ctl);
9788621f407SFrançois Tigeot 	if (WARN_ON(!(val & LCPLL_PLL_ENABLE)))
9798621f407SFrançois Tigeot 		goto out;
9808621f407SFrançois Tigeot 
9818621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
9828621f407SFrançois Tigeot 	hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
9838621f407SFrançois Tigeot 
9848621f407SFrançois Tigeot 	ret = true;
9858621f407SFrançois Tigeot 
9868621f407SFrançois Tigeot out:
9878621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
9888621f407SFrançois Tigeot 
9898621f407SFrançois Tigeot 	return ret;
9908621f407SFrançois Tigeot }
9918621f407SFrançois Tigeot 
9928621f407SFrançois Tigeot struct skl_wrpll_context {
9938621f407SFrançois Tigeot 	uint64_t min_deviation;		/* current minimal deviation */
9948621f407SFrançois Tigeot 	uint64_t central_freq;		/* chosen central freq */
9958621f407SFrançois Tigeot 	uint64_t dco_freq;		/* chosen dco freq */
9968621f407SFrançois Tigeot 	unsigned int p;			/* chosen divider */
9978621f407SFrançois Tigeot };
9988621f407SFrançois Tigeot 
9998621f407SFrançois Tigeot static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
10008621f407SFrançois Tigeot {
10018621f407SFrançois Tigeot 	memset(ctx, 0, sizeof(*ctx));
10028621f407SFrançois Tigeot 
10038621f407SFrançois Tigeot 	ctx->min_deviation = U64_MAX;
10048621f407SFrançois Tigeot }
10058621f407SFrançois Tigeot 
10068621f407SFrançois Tigeot /* DCO freq must be within +1%/-6%  of the DCO central freq */
10078621f407SFrançois Tigeot #define SKL_DCO_MAX_PDEVIATION	100
10088621f407SFrançois Tigeot #define SKL_DCO_MAX_NDEVIATION	600
10098621f407SFrançois Tigeot 
10108621f407SFrançois Tigeot static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
10118621f407SFrançois Tigeot 				  uint64_t central_freq,
10128621f407SFrançois Tigeot 				  uint64_t dco_freq,
10138621f407SFrançois Tigeot 				  unsigned int divider)
10148621f407SFrançois Tigeot {
10158621f407SFrançois Tigeot 	uint64_t deviation;
10168621f407SFrançois Tigeot 
10178621f407SFrançois Tigeot 	deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
10188621f407SFrançois Tigeot 			      central_freq);
10198621f407SFrançois Tigeot 
10208621f407SFrançois Tigeot 	/* positive deviation */
10218621f407SFrançois Tigeot 	if (dco_freq >= central_freq) {
10228621f407SFrançois Tigeot 		if (deviation < SKL_DCO_MAX_PDEVIATION &&
10238621f407SFrançois Tigeot 		    deviation < ctx->min_deviation) {
10248621f407SFrançois Tigeot 			ctx->min_deviation = deviation;
10258621f407SFrançois Tigeot 			ctx->central_freq = central_freq;
10268621f407SFrançois Tigeot 			ctx->dco_freq = dco_freq;
10278621f407SFrançois Tigeot 			ctx->p = divider;
10288621f407SFrançois Tigeot 		}
10298621f407SFrançois Tigeot 	/* negative deviation */
10308621f407SFrançois Tigeot 	} else if (deviation < SKL_DCO_MAX_NDEVIATION &&
10318621f407SFrançois Tigeot 		   deviation < ctx->min_deviation) {
10328621f407SFrançois Tigeot 		ctx->min_deviation = deviation;
10338621f407SFrançois Tigeot 		ctx->central_freq = central_freq;
10348621f407SFrançois Tigeot 		ctx->dco_freq = dco_freq;
10358621f407SFrançois Tigeot 		ctx->p = divider;
10368621f407SFrançois Tigeot 	}
10378621f407SFrançois Tigeot }
10388621f407SFrançois Tigeot 
10398621f407SFrançois Tigeot static void skl_wrpll_get_multipliers(unsigned int p,
10408621f407SFrançois Tigeot 				      unsigned int *p0 /* out */,
10418621f407SFrançois Tigeot 				      unsigned int *p1 /* out */,
10428621f407SFrançois Tigeot 				      unsigned int *p2 /* out */)
10438621f407SFrançois Tigeot {
10448621f407SFrançois Tigeot 	/* even dividers */
10458621f407SFrançois Tigeot 	if (p % 2 == 0) {
10468621f407SFrançois Tigeot 		unsigned int half = p / 2;
10478621f407SFrançois Tigeot 
10488621f407SFrançois Tigeot 		if (half == 1 || half == 2 || half == 3 || half == 5) {
10498621f407SFrançois Tigeot 			*p0 = 2;
10508621f407SFrançois Tigeot 			*p1 = 1;
10518621f407SFrançois Tigeot 			*p2 = half;
10528621f407SFrançois Tigeot 		} else if (half % 2 == 0) {
10538621f407SFrançois Tigeot 			*p0 = 2;
10548621f407SFrançois Tigeot 			*p1 = half / 2;
10558621f407SFrançois Tigeot 			*p2 = 2;
10568621f407SFrançois Tigeot 		} else if (half % 3 == 0) {
10578621f407SFrançois Tigeot 			*p0 = 3;
10588621f407SFrançois Tigeot 			*p1 = half / 3;
10598621f407SFrançois Tigeot 			*p2 = 2;
10608621f407SFrançois Tigeot 		} else if (half % 7 == 0) {
10618621f407SFrançois Tigeot 			*p0 = 7;
10628621f407SFrançois Tigeot 			*p1 = half / 7;
10638621f407SFrançois Tigeot 			*p2 = 2;
10648621f407SFrançois Tigeot 		}
10658621f407SFrançois Tigeot 	} else if (p == 3 || p == 9) {  /* 3, 5, 7, 9, 15, 21, 35 */
10668621f407SFrançois Tigeot 		*p0 = 3;
10678621f407SFrançois Tigeot 		*p1 = 1;
10688621f407SFrançois Tigeot 		*p2 = p / 3;
10698621f407SFrançois Tigeot 	} else if (p == 5 || p == 7) {
10708621f407SFrançois Tigeot 		*p0 = p;
10718621f407SFrançois Tigeot 		*p1 = 1;
10728621f407SFrançois Tigeot 		*p2 = 1;
10738621f407SFrançois Tigeot 	} else if (p == 15) {
10748621f407SFrançois Tigeot 		*p0 = 3;
10758621f407SFrançois Tigeot 		*p1 = 1;
10768621f407SFrançois Tigeot 		*p2 = 5;
10778621f407SFrançois Tigeot 	} else if (p == 21) {
10788621f407SFrançois Tigeot 		*p0 = 7;
10798621f407SFrançois Tigeot 		*p1 = 1;
10808621f407SFrançois Tigeot 		*p2 = 3;
10818621f407SFrançois Tigeot 	} else if (p == 35) {
10828621f407SFrançois Tigeot 		*p0 = 7;
10838621f407SFrançois Tigeot 		*p1 = 1;
10848621f407SFrançois Tigeot 		*p2 = 5;
10858621f407SFrançois Tigeot 	}
10868621f407SFrançois Tigeot }
10878621f407SFrançois Tigeot 
10888621f407SFrançois Tigeot struct skl_wrpll_params {
10898621f407SFrançois Tigeot 	uint32_t        dco_fraction;
10908621f407SFrançois Tigeot 	uint32_t        dco_integer;
10918621f407SFrançois Tigeot 	uint32_t        qdiv_ratio;
10928621f407SFrançois Tigeot 	uint32_t        qdiv_mode;
10938621f407SFrançois Tigeot 	uint32_t        kdiv;
10948621f407SFrançois Tigeot 	uint32_t        pdiv;
10958621f407SFrançois Tigeot 	uint32_t        central_freq;
10968621f407SFrançois Tigeot };
10978621f407SFrançois Tigeot 
10988621f407SFrançois Tigeot static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
10998621f407SFrançois Tigeot 				      uint64_t afe_clock,
11008621f407SFrançois Tigeot 				      uint64_t central_freq,
11018621f407SFrançois Tigeot 				      uint32_t p0, uint32_t p1, uint32_t p2)
11028621f407SFrançois Tigeot {
11038621f407SFrançois Tigeot 	uint64_t dco_freq;
11048621f407SFrançois Tigeot 
11058621f407SFrançois Tigeot 	switch (central_freq) {
11068621f407SFrançois Tigeot 	case 9600000000ULL:
11078621f407SFrançois Tigeot 		params->central_freq = 0;
11088621f407SFrançois Tigeot 		break;
11098621f407SFrançois Tigeot 	case 9000000000ULL:
11108621f407SFrançois Tigeot 		params->central_freq = 1;
11118621f407SFrançois Tigeot 		break;
11128621f407SFrançois Tigeot 	case 8400000000ULL:
11138621f407SFrançois Tigeot 		params->central_freq = 3;
11148621f407SFrançois Tigeot 	}
11158621f407SFrançois Tigeot 
11168621f407SFrançois Tigeot 	switch (p0) {
11178621f407SFrançois Tigeot 	case 1:
11188621f407SFrançois Tigeot 		params->pdiv = 0;
11198621f407SFrançois Tigeot 		break;
11208621f407SFrançois Tigeot 	case 2:
11218621f407SFrançois Tigeot 		params->pdiv = 1;
11228621f407SFrançois Tigeot 		break;
11238621f407SFrançois Tigeot 	case 3:
11248621f407SFrançois Tigeot 		params->pdiv = 2;
11258621f407SFrançois Tigeot 		break;
11268621f407SFrançois Tigeot 	case 7:
11278621f407SFrançois Tigeot 		params->pdiv = 4;
11288621f407SFrançois Tigeot 		break;
11298621f407SFrançois Tigeot 	default:
11308621f407SFrançois Tigeot 		WARN(1, "Incorrect PDiv\n");
11318621f407SFrançois Tigeot 	}
11328621f407SFrançois Tigeot 
11338621f407SFrançois Tigeot 	switch (p2) {
11348621f407SFrançois Tigeot 	case 5:
11358621f407SFrançois Tigeot 		params->kdiv = 0;
11368621f407SFrançois Tigeot 		break;
11378621f407SFrançois Tigeot 	case 2:
11388621f407SFrançois Tigeot 		params->kdiv = 1;
11398621f407SFrançois Tigeot 		break;
11408621f407SFrançois Tigeot 	case 3:
11418621f407SFrançois Tigeot 		params->kdiv = 2;
11428621f407SFrançois Tigeot 		break;
11438621f407SFrançois Tigeot 	case 1:
11448621f407SFrançois Tigeot 		params->kdiv = 3;
11458621f407SFrançois Tigeot 		break;
11468621f407SFrançois Tigeot 	default:
11478621f407SFrançois Tigeot 		WARN(1, "Incorrect KDiv\n");
11488621f407SFrançois Tigeot 	}
11498621f407SFrançois Tigeot 
11508621f407SFrançois Tigeot 	params->qdiv_ratio = p1;
11518621f407SFrançois Tigeot 	params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
11528621f407SFrançois Tigeot 
11538621f407SFrançois Tigeot 	dco_freq = p0 * p1 * p2 * afe_clock;
11548621f407SFrançois Tigeot 
11558621f407SFrançois Tigeot 	/*
11568621f407SFrançois Tigeot 	 * Intermediate values are in Hz.
11578621f407SFrançois Tigeot 	 * Divide by MHz to match bsepc
11588621f407SFrançois Tigeot 	 */
11598621f407SFrançois Tigeot 	params->dco_integer = div_u64(dco_freq, 24 * MHz(1));
11608621f407SFrançois Tigeot 	params->dco_fraction =
11618621f407SFrançois Tigeot 		div_u64((div_u64(dco_freq, 24) -
11628621f407SFrançois Tigeot 			 params->dco_integer * MHz(1)) * 0x8000, MHz(1));
11638621f407SFrançois Tigeot }
11648621f407SFrançois Tigeot 
11658621f407SFrançois Tigeot static bool
11668621f407SFrançois Tigeot skl_ddi_calculate_wrpll(int clock /* in Hz */,
11678621f407SFrançois Tigeot 			struct skl_wrpll_params *wrpll_params)
11688621f407SFrançois Tigeot {
11698621f407SFrançois Tigeot 	uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
11708621f407SFrançois Tigeot 	uint64_t dco_central_freq[3] = {8400000000ULL,
11718621f407SFrançois Tigeot 					9000000000ULL,
11728621f407SFrançois Tigeot 					9600000000ULL};
11738621f407SFrançois Tigeot 	static const int even_dividers[] = {  4,  6,  8, 10, 12, 14, 16, 18, 20,
11748621f407SFrançois Tigeot 					     24, 28, 30, 32, 36, 40, 42, 44,
11758621f407SFrançois Tigeot 					     48, 52, 54, 56, 60, 64, 66, 68,
11768621f407SFrançois Tigeot 					     70, 72, 76, 78, 80, 84, 88, 90,
11778621f407SFrançois Tigeot 					     92, 96, 98 };
11788621f407SFrançois Tigeot 	static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
11798621f407SFrançois Tigeot 	static const struct {
11808621f407SFrançois Tigeot 		const int *list;
11818621f407SFrançois Tigeot 		int n_dividers;
11828621f407SFrançois Tigeot 	} dividers[] = {
11838621f407SFrançois Tigeot 		{ even_dividers, ARRAY_SIZE(even_dividers) },
11848621f407SFrançois Tigeot 		{ odd_dividers, ARRAY_SIZE(odd_dividers) },
11858621f407SFrançois Tigeot 	};
11868621f407SFrançois Tigeot 	struct skl_wrpll_context ctx;
11878621f407SFrançois Tigeot 	unsigned int dco, d, i;
11888621f407SFrançois Tigeot 	unsigned int p0, p1, p2;
11898621f407SFrançois Tigeot 
11908621f407SFrançois Tigeot 	skl_wrpll_context_init(&ctx);
11918621f407SFrançois Tigeot 
11928621f407SFrançois Tigeot 	for (d = 0; d < ARRAY_SIZE(dividers); d++) {
11938621f407SFrançois Tigeot 		for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
11948621f407SFrançois Tigeot 			for (i = 0; i < dividers[d].n_dividers; i++) {
11958621f407SFrançois Tigeot 				unsigned int p = dividers[d].list[i];
11968621f407SFrançois Tigeot 				uint64_t dco_freq = p * afe_clock;
11978621f407SFrançois Tigeot 
11988621f407SFrançois Tigeot 				skl_wrpll_try_divider(&ctx,
11998621f407SFrançois Tigeot 						      dco_central_freq[dco],
12008621f407SFrançois Tigeot 						      dco_freq,
12018621f407SFrançois Tigeot 						      p);
12028621f407SFrançois Tigeot 				/*
12038621f407SFrançois Tigeot 				 * Skip the remaining dividers if we're sure to
12048621f407SFrançois Tigeot 				 * have found the definitive divider, we can't
12058621f407SFrançois Tigeot 				 * improve a 0 deviation.
12068621f407SFrançois Tigeot 				 */
12078621f407SFrançois Tigeot 				if (ctx.min_deviation == 0)
12088621f407SFrançois Tigeot 					goto skip_remaining_dividers;
12098621f407SFrançois Tigeot 			}
12108621f407SFrançois Tigeot 		}
12118621f407SFrançois Tigeot 
12128621f407SFrançois Tigeot skip_remaining_dividers:
12138621f407SFrançois Tigeot 		/*
12148621f407SFrançois Tigeot 		 * If a solution is found with an even divider, prefer
12158621f407SFrançois Tigeot 		 * this one.
12168621f407SFrançois Tigeot 		 */
12178621f407SFrançois Tigeot 		if (d == 0 && ctx.p)
12188621f407SFrançois Tigeot 			break;
12198621f407SFrançois Tigeot 	}
12208621f407SFrançois Tigeot 
12218621f407SFrançois Tigeot 	if (!ctx.p) {
12228621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
12238621f407SFrançois Tigeot 		return false;
12248621f407SFrançois Tigeot 	}
12258621f407SFrançois Tigeot 
12268621f407SFrançois Tigeot 	/*
12278621f407SFrançois Tigeot 	 * gcc incorrectly analyses that these can be used without being
12288621f407SFrançois Tigeot 	 * initialized. To be fair, it's hard to guess.
12298621f407SFrançois Tigeot 	 */
12308621f407SFrançois Tigeot 	p0 = p1 = p2 = 0;
12318621f407SFrançois Tigeot 	skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
12328621f407SFrançois Tigeot 	skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq,
12338621f407SFrançois Tigeot 				  p0, p1, p2);
12348621f407SFrançois Tigeot 
12358621f407SFrançois Tigeot 	return true;
12368621f407SFrançois Tigeot }
12378621f407SFrançois Tigeot 
1238*1e12ee3bSFrançois Tigeot static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc *crtc,
1239*1e12ee3bSFrançois Tigeot 				      struct intel_crtc_state *crtc_state,
1240*1e12ee3bSFrançois Tigeot 				      int clock)
12418621f407SFrançois Tigeot {
12428621f407SFrançois Tigeot 	uint32_t ctrl1, cfgcr1, cfgcr2;
1243*1e12ee3bSFrançois Tigeot 	struct skl_wrpll_params wrpll_params = { 0, };
12448621f407SFrançois Tigeot 
12458621f407SFrançois Tigeot 	/*
12468621f407SFrançois Tigeot 	 * See comment in intel_dpll_hw_state to understand why we always use 0
12478621f407SFrançois Tigeot 	 * as the DPLL id in this function.
12488621f407SFrançois Tigeot 	 */
12498621f407SFrançois Tigeot 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
12508621f407SFrançois Tigeot 
12518621f407SFrançois Tigeot 	ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
12528621f407SFrançois Tigeot 
12538621f407SFrançois Tigeot 	if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
1254*1e12ee3bSFrançois Tigeot 		return false;
12558621f407SFrançois Tigeot 
12568621f407SFrançois Tigeot 	cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
12578621f407SFrançois Tigeot 		DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
12588621f407SFrançois Tigeot 		wrpll_params.dco_integer;
12598621f407SFrançois Tigeot 
12608621f407SFrançois Tigeot 	cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
12618621f407SFrançois Tigeot 		DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
12628621f407SFrançois Tigeot 		DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
12638621f407SFrançois Tigeot 		DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
12648621f407SFrançois Tigeot 		wrpll_params.central_freq;
1265*1e12ee3bSFrançois Tigeot 
1266*1e12ee3bSFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
1267*1e12ee3bSFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
1268*1e12ee3bSFrançois Tigeot 
1269*1e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state.ctrl1 = ctrl1;
1270*1e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
1271*1e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
1272*1e12ee3bSFrançois Tigeot 	return true;
1273*1e12ee3bSFrançois Tigeot }
1274*1e12ee3bSFrançois Tigeot 
1275*1e12ee3bSFrançois Tigeot 
1276*1e12ee3bSFrançois Tigeot bool skl_ddi_dp_set_dpll_hw_state(int clock,
1277*1e12ee3bSFrançois Tigeot 				  struct intel_dpll_hw_state *dpll_hw_state)
1278*1e12ee3bSFrançois Tigeot {
1279*1e12ee3bSFrançois Tigeot 	uint32_t ctrl1;
1280*1e12ee3bSFrançois Tigeot 
1281*1e12ee3bSFrançois Tigeot 	/*
1282*1e12ee3bSFrançois Tigeot 	 * See comment in intel_dpll_hw_state to understand why we always use 0
1283*1e12ee3bSFrançois Tigeot 	 * as the DPLL id in this function.
1284*1e12ee3bSFrançois Tigeot 	 */
1285*1e12ee3bSFrançois Tigeot 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
1286*1e12ee3bSFrançois Tigeot 	switch (clock / 2) {
12878621f407SFrançois Tigeot 	case 81000:
12888621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
12898621f407SFrançois Tigeot 		break;
12908621f407SFrançois Tigeot 	case 135000:
12918621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
12928621f407SFrançois Tigeot 		break;
12938621f407SFrançois Tigeot 	case 270000:
12948621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
12958621f407SFrançois Tigeot 		break;
12968621f407SFrançois Tigeot 		/* eDP 1.4 rates */
12978621f407SFrançois Tigeot 	case 162000:
12988621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
12998621f407SFrançois Tigeot 		break;
13008621f407SFrançois Tigeot 	case 108000:
13018621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
13028621f407SFrançois Tigeot 		break;
13038621f407SFrançois Tigeot 	case 216000:
13048621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
13058621f407SFrançois Tigeot 		break;
13068621f407SFrançois Tigeot 	}
13078621f407SFrançois Tigeot 
1308*1e12ee3bSFrançois Tigeot 	dpll_hw_state->ctrl1 = ctrl1;
1309*1e12ee3bSFrançois Tigeot 	return true;
1310*1e12ee3bSFrançois Tigeot }
1311*1e12ee3bSFrançois Tigeot 
1312*1e12ee3bSFrançois Tigeot static struct intel_shared_dpll *
1313*1e12ee3bSFrançois Tigeot skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
1314*1e12ee3bSFrançois Tigeot 	     struct intel_encoder *encoder)
1315*1e12ee3bSFrançois Tigeot {
1316*1e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
1317*1e12ee3bSFrançois Tigeot 	int clock = crtc_state->port_clock;
1318*1e12ee3bSFrançois Tigeot 	bool bret;
1319*1e12ee3bSFrançois Tigeot 	struct intel_dpll_hw_state dpll_hw_state;
1320*1e12ee3bSFrançois Tigeot 
1321*1e12ee3bSFrançois Tigeot 	memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
1322*1e12ee3bSFrançois Tigeot 
1323*1e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI) {
1324*1e12ee3bSFrançois Tigeot 		bret = skl_ddi_hdmi_pll_dividers(crtc, crtc_state, clock);
1325*1e12ee3bSFrançois Tigeot 		if (!bret) {
1326*1e12ee3bSFrançois Tigeot 			DRM_DEBUG_KMS("Could not get HDMI pll dividers.\n");
1327*1e12ee3bSFrançois Tigeot 			return NULL;
1328*1e12ee3bSFrançois Tigeot 		}
1329*1e12ee3bSFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_DP ||
1330*1e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_DP_MST ||
1331*1e12ee3bSFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_EDP) {
1332*1e12ee3bSFrançois Tigeot 		bret = skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state);
1333*1e12ee3bSFrançois Tigeot 		if (!bret) {
1334*1e12ee3bSFrançois Tigeot 			DRM_DEBUG_KMS("Could not set DP dpll HW state.\n");
1335*1e12ee3bSFrançois Tigeot 			return NULL;
1336*1e12ee3bSFrançois Tigeot 		}
1337*1e12ee3bSFrançois Tigeot 		crtc_state->dpll_hw_state = dpll_hw_state;
13388621f407SFrançois Tigeot 	} else {
13398621f407SFrançois Tigeot 		return NULL;
13408621f407SFrançois Tigeot 	}
13418621f407SFrançois Tigeot 
13428621f407SFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_EDP)
13438621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
13448621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL0,
13458621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL0);
13468621f407SFrançois Tigeot 	else
13478621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
13488621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL1,
13498621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL3);
13508621f407SFrançois Tigeot 	if (!pll)
13518621f407SFrançois Tigeot 		return NULL;
13528621f407SFrançois Tigeot 
13538621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
13548621f407SFrançois Tigeot 
13558621f407SFrançois Tigeot 	return pll;
13568621f407SFrançois Tigeot }
13578621f407SFrançois Tigeot 
13588621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs skl_ddi_pll_funcs = {
13598621f407SFrançois Tigeot 	.enable = skl_ddi_pll_enable,
13608621f407SFrançois Tigeot 	.disable = skl_ddi_pll_disable,
13618621f407SFrançois Tigeot 	.get_hw_state = skl_ddi_pll_get_hw_state,
13628621f407SFrançois Tigeot };
13638621f407SFrançois Tigeot 
13648621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = {
13658621f407SFrançois Tigeot 	.enable = skl_ddi_dpll0_enable,
13668621f407SFrançois Tigeot 	.disable = skl_ddi_dpll0_disable,
13678621f407SFrançois Tigeot 	.get_hw_state = skl_ddi_dpll0_get_hw_state,
13688621f407SFrançois Tigeot };
13698621f407SFrançois Tigeot 
13708621f407SFrançois Tigeot static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
13718621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
13728621f407SFrançois Tigeot {
13738621f407SFrançois Tigeot 	uint32_t temp;
13748621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
13758621f407SFrançois Tigeot 
13768621f407SFrançois Tigeot 	/* Non-SSC reference */
13778621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
13788621f407SFrançois Tigeot 	temp |= PORT_PLL_REF_SEL;
13798621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
13808621f407SFrançois Tigeot 
13818621f407SFrançois Tigeot 	/* Disable 10 bit clock */
13828621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
13838621f407SFrançois Tigeot 	temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
13848621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
13858621f407SFrançois Tigeot 
13868621f407SFrançois Tigeot 	/* Write P1 & P2 */
13878621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_0(port));
13888621f407SFrançois Tigeot 	temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK);
13898621f407SFrançois Tigeot 	temp |= pll->config.hw_state.ebb0;
13908621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_0(port), temp);
13918621f407SFrançois Tigeot 
13928621f407SFrançois Tigeot 	/* Write M2 integer */
13938621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 0));
13948621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_MASK;
13958621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll0;
13968621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 0), temp);
13978621f407SFrançois Tigeot 
13988621f407SFrançois Tigeot 	/* Write N */
13998621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 1));
14008621f407SFrançois Tigeot 	temp &= ~PORT_PLL_N_MASK;
14018621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll1;
14028621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 1), temp);
14038621f407SFrançois Tigeot 
14048621f407SFrançois Tigeot 	/* Write M2 fraction */
14058621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 2));
14068621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_FRAC_MASK;
14078621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll2;
14088621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 2), temp);
14098621f407SFrançois Tigeot 
14108621f407SFrançois Tigeot 	/* Write M2 fraction enable */
14118621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 3));
14128621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_FRAC_ENABLE;
14138621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll3;
14148621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 3), temp);
14158621f407SFrançois Tigeot 
14168621f407SFrançois Tigeot 	/* Write coeff */
14178621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 6));
14188621f407SFrançois Tigeot 	temp &= ~PORT_PLL_PROP_COEFF_MASK;
14198621f407SFrançois Tigeot 	temp &= ~PORT_PLL_INT_COEFF_MASK;
14208621f407SFrançois Tigeot 	temp &= ~PORT_PLL_GAIN_CTL_MASK;
14218621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll6;
14228621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 6), temp);
14238621f407SFrançois Tigeot 
14248621f407SFrançois Tigeot 	/* Write calibration val */
14258621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 8));
14268621f407SFrançois Tigeot 	temp &= ~PORT_PLL_TARGET_CNT_MASK;
14278621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll8;
14288621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 8), temp);
14298621f407SFrançois Tigeot 
14308621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 9));
14318621f407SFrançois Tigeot 	temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK;
14328621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll9;
14338621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 9), temp);
14348621f407SFrançois Tigeot 
14358621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 10));
14368621f407SFrançois Tigeot 	temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H;
14378621f407SFrançois Tigeot 	temp &= ~PORT_PLL_DCO_AMP_MASK;
14388621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll10;
14398621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 10), temp);
14408621f407SFrançois Tigeot 
14418621f407SFrançois Tigeot 	/* Recalibrate with new settings */
14428621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
14438621f407SFrançois Tigeot 	temp |= PORT_PLL_RECALIBRATE;
14448621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
14458621f407SFrançois Tigeot 	temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
14468621f407SFrançois Tigeot 	temp |= pll->config.hw_state.ebb4;
14478621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
14488621f407SFrançois Tigeot 
14498621f407SFrançois Tigeot 	/* Enable PLL */
14508621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
14518621f407SFrançois Tigeot 	temp |= PORT_PLL_ENABLE;
14528621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
14538621f407SFrançois Tigeot 	POSTING_READ(BXT_PORT_PLL_ENABLE(port));
14548621f407SFrançois Tigeot 
14558621f407SFrançois Tigeot 	if (wait_for_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_LOCK),
14568621f407SFrançois Tigeot 			200))
14578621f407SFrançois Tigeot 		DRM_ERROR("PLL %d not locked\n", port);
14588621f407SFrançois Tigeot 
14598621f407SFrançois Tigeot 	/*
14608621f407SFrançois Tigeot 	 * While we write to the group register to program all lanes at once we
14618621f407SFrançois Tigeot 	 * can read only lane registers and we pick lanes 0/1 for that.
14628621f407SFrançois Tigeot 	 */
14638621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
14648621f407SFrançois Tigeot 	temp &= ~LANE_STAGGER_MASK;
14658621f407SFrançois Tigeot 	temp &= ~LANESTAGGER_STRAP_OVRD;
14668621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pcsdw12;
14678621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PCS_DW12_GRP(port), temp);
14688621f407SFrançois Tigeot }
14698621f407SFrançois Tigeot 
14708621f407SFrançois Tigeot static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
14718621f407SFrançois Tigeot 					struct intel_shared_dpll *pll)
14728621f407SFrançois Tigeot {
14738621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
14748621f407SFrançois Tigeot 	uint32_t temp;
14758621f407SFrançois Tigeot 
14768621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
14778621f407SFrançois Tigeot 	temp &= ~PORT_PLL_ENABLE;
14788621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
14798621f407SFrançois Tigeot 	POSTING_READ(BXT_PORT_PLL_ENABLE(port));
14808621f407SFrançois Tigeot }
14818621f407SFrançois Tigeot 
14828621f407SFrançois Tigeot static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
14838621f407SFrançois Tigeot 					struct intel_shared_dpll *pll,
14848621f407SFrançois Tigeot 					struct intel_dpll_hw_state *hw_state)
14858621f407SFrançois Tigeot {
14868621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
14878621f407SFrançois Tigeot 	uint32_t val;
14888621f407SFrançois Tigeot 	bool ret;
14898621f407SFrançois Tigeot 
14908621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
14918621f407SFrançois Tigeot 		return false;
14928621f407SFrançois Tigeot 
14938621f407SFrançois Tigeot 	ret = false;
14948621f407SFrançois Tigeot 
14958621f407SFrançois Tigeot 	val = I915_READ(BXT_PORT_PLL_ENABLE(port));
14968621f407SFrançois Tigeot 	if (!(val & PORT_PLL_ENABLE))
14978621f407SFrançois Tigeot 		goto out;
14988621f407SFrançois Tigeot 
14998621f407SFrançois Tigeot 	hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
15008621f407SFrançois Tigeot 	hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
15018621f407SFrançois Tigeot 
15028621f407SFrançois Tigeot 	hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port));
15038621f407SFrançois Tigeot 	hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
15048621f407SFrançois Tigeot 
15058621f407SFrançois Tigeot 	hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0));
15068621f407SFrançois Tigeot 	hw_state->pll0 &= PORT_PLL_M2_MASK;
15078621f407SFrançois Tigeot 
15088621f407SFrançois Tigeot 	hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1));
15098621f407SFrançois Tigeot 	hw_state->pll1 &= PORT_PLL_N_MASK;
15108621f407SFrançois Tigeot 
15118621f407SFrançois Tigeot 	hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2));
15128621f407SFrançois Tigeot 	hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK;
15138621f407SFrançois Tigeot 
15148621f407SFrançois Tigeot 	hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3));
15158621f407SFrançois Tigeot 	hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE;
15168621f407SFrançois Tigeot 
15178621f407SFrançois Tigeot 	hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6));
15188621f407SFrançois Tigeot 	hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK |
15198621f407SFrançois Tigeot 			  PORT_PLL_INT_COEFF_MASK |
15208621f407SFrançois Tigeot 			  PORT_PLL_GAIN_CTL_MASK;
15218621f407SFrançois Tigeot 
15228621f407SFrançois Tigeot 	hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8));
15238621f407SFrançois Tigeot 	hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK;
15248621f407SFrançois Tigeot 
15258621f407SFrançois Tigeot 	hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9));
15268621f407SFrançois Tigeot 	hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK;
15278621f407SFrançois Tigeot 
15288621f407SFrançois Tigeot 	hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10));
15298621f407SFrançois Tigeot 	hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H |
15308621f407SFrançois Tigeot 			   PORT_PLL_DCO_AMP_MASK;
15318621f407SFrançois Tigeot 
15328621f407SFrançois Tigeot 	/*
15338621f407SFrançois Tigeot 	 * While we write to the group register to program all lanes at once we
15348621f407SFrançois Tigeot 	 * can read only lane registers. We configure all lanes the same way, so
15358621f407SFrançois Tigeot 	 * here just read out lanes 0/1 and output a note if lanes 2/3 differ.
15368621f407SFrançois Tigeot 	 */
15378621f407SFrançois Tigeot 	hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
15388621f407SFrançois Tigeot 	if (I915_READ(BXT_PORT_PCS_DW12_LN23(port)) != hw_state->pcsdw12)
15398621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
15408621f407SFrançois Tigeot 				 hw_state->pcsdw12,
15418621f407SFrançois Tigeot 				 I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
15428621f407SFrançois Tigeot 	hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
15438621f407SFrançois Tigeot 
15448621f407SFrançois Tigeot 	ret = true;
15458621f407SFrançois Tigeot 
15468621f407SFrançois Tigeot out:
15478621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
15488621f407SFrançois Tigeot 
15498621f407SFrançois Tigeot 	return ret;
15508621f407SFrançois Tigeot }
15518621f407SFrançois Tigeot 
15528621f407SFrançois Tigeot /* bxt clock parameters */
15538621f407SFrançois Tigeot struct bxt_clk_div {
15548621f407SFrançois Tigeot 	int clock;
15558621f407SFrançois Tigeot 	uint32_t p1;
15568621f407SFrançois Tigeot 	uint32_t p2;
15578621f407SFrançois Tigeot 	uint32_t m2_int;
15588621f407SFrançois Tigeot 	uint32_t m2_frac;
15598621f407SFrançois Tigeot 	bool m2_frac_en;
15608621f407SFrançois Tigeot 	uint32_t n;
1561*1e12ee3bSFrançois Tigeot 
1562*1e12ee3bSFrançois Tigeot 	int vco;
15638621f407SFrançois Tigeot };
15648621f407SFrançois Tigeot 
15658621f407SFrançois Tigeot /* pre-calculated values for DP linkrates */
15668621f407SFrançois Tigeot static const struct bxt_clk_div bxt_dp_clk_val[] = {
15678621f407SFrançois Tigeot 	{162000, 4, 2, 32, 1677722, 1, 1},
15688621f407SFrançois Tigeot 	{270000, 4, 1, 27,       0, 0, 1},
15698621f407SFrançois Tigeot 	{540000, 2, 1, 27,       0, 0, 1},
15708621f407SFrançois Tigeot 	{216000, 3, 2, 32, 1677722, 1, 1},
15718621f407SFrançois Tigeot 	{243000, 4, 1, 24, 1258291, 1, 1},
15728621f407SFrançois Tigeot 	{324000, 4, 1, 32, 1677722, 1, 1},
15738621f407SFrançois Tigeot 	{432000, 3, 1, 32, 1677722, 1, 1}
15748621f407SFrançois Tigeot };
15758621f407SFrançois Tigeot 
1576*1e12ee3bSFrançois Tigeot static bool
1577*1e12ee3bSFrançois Tigeot bxt_ddi_hdmi_pll_dividers(struct intel_crtc *intel_crtc,
1578*1e12ee3bSFrançois Tigeot 			  struct intel_crtc_state *crtc_state, int clock,
1579*1e12ee3bSFrançois Tigeot 			  struct bxt_clk_div *clk_div)
15808621f407SFrançois Tigeot {
15811487f786SFrançois Tigeot 	struct dpll best_clock;
15828621f407SFrançois Tigeot 
15838621f407SFrançois Tigeot 	/* Calculate HDMI div */
15848621f407SFrançois Tigeot 	/*
15858621f407SFrançois Tigeot 	 * FIXME: tie the following calculation into
15868621f407SFrançois Tigeot 	 * i9xx_crtc_compute_clock
15878621f407SFrançois Tigeot 	 */
15888621f407SFrançois Tigeot 	if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
15898621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
1590*1e12ee3bSFrançois Tigeot 				 clock, pipe_name(intel_crtc->pipe));
1591*1e12ee3bSFrançois Tigeot 		return false;
15928621f407SFrançois Tigeot 	}
15938621f407SFrançois Tigeot 
1594*1e12ee3bSFrançois Tigeot 	clk_div->p1 = best_clock.p1;
1595*1e12ee3bSFrançois Tigeot 	clk_div->p2 = best_clock.p2;
15968621f407SFrançois Tigeot 	WARN_ON(best_clock.m1 != 2);
1597*1e12ee3bSFrançois Tigeot 	clk_div->n = best_clock.n;
1598*1e12ee3bSFrançois Tigeot 	clk_div->m2_int = best_clock.m2 >> 22;
1599*1e12ee3bSFrançois Tigeot 	clk_div->m2_frac = best_clock.m2 & ((1 << 22) - 1);
1600*1e12ee3bSFrançois Tigeot 	clk_div->m2_frac_en = clk_div->m2_frac != 0;
16018621f407SFrançois Tigeot 
1602*1e12ee3bSFrançois Tigeot 	clk_div->vco = best_clock.vco;
1603*1e12ee3bSFrançois Tigeot 
1604*1e12ee3bSFrançois Tigeot 	return true;
1605*1e12ee3bSFrançois Tigeot }
1606*1e12ee3bSFrançois Tigeot 
1607*1e12ee3bSFrançois Tigeot static void bxt_ddi_dp_pll_dividers(int clock, struct bxt_clk_div *clk_div)
1608*1e12ee3bSFrançois Tigeot {
16098621f407SFrançois Tigeot 	int i;
16108621f407SFrançois Tigeot 
1611*1e12ee3bSFrançois Tigeot 	*clk_div = bxt_dp_clk_val[0];
16128621f407SFrançois Tigeot 	for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
16138621f407SFrançois Tigeot 		if (bxt_dp_clk_val[i].clock == clock) {
1614*1e12ee3bSFrançois Tigeot 			*clk_div = bxt_dp_clk_val[i];
16158621f407SFrançois Tigeot 			break;
16168621f407SFrançois Tigeot 		}
16178621f407SFrançois Tigeot 	}
1618*1e12ee3bSFrançois Tigeot 
1619*1e12ee3bSFrançois Tigeot 	clk_div->vco = clock * 10 / 2 * clk_div->p1 * clk_div->p2;
16208621f407SFrançois Tigeot }
16218621f407SFrançois Tigeot 
1622*1e12ee3bSFrançois Tigeot static bool bxt_ddi_set_dpll_hw_state(int clock,
1623*1e12ee3bSFrançois Tigeot 			  struct bxt_clk_div *clk_div,
1624*1e12ee3bSFrançois Tigeot 			  struct intel_dpll_hw_state *dpll_hw_state)
1625*1e12ee3bSFrançois Tigeot {
1626*1e12ee3bSFrançois Tigeot 	int vco = clk_div->vco;
1627*1e12ee3bSFrançois Tigeot 	uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
1628*1e12ee3bSFrançois Tigeot 	uint32_t lanestagger;
1629*1e12ee3bSFrançois Tigeot 
16308621f407SFrançois Tigeot 	if (vco >= 6200000 && vco <= 6700000) {
16318621f407SFrançois Tigeot 		prop_coef = 4;
16328621f407SFrançois Tigeot 		int_coef = 9;
16338621f407SFrançois Tigeot 		gain_ctl = 3;
16348621f407SFrançois Tigeot 		targ_cnt = 8;
16358621f407SFrançois Tigeot 	} else if ((vco > 5400000 && vco < 6200000) ||
16368621f407SFrançois Tigeot 			(vco >= 4800000 && vco < 5400000)) {
16378621f407SFrançois Tigeot 		prop_coef = 5;
16388621f407SFrançois Tigeot 		int_coef = 11;
16398621f407SFrançois Tigeot 		gain_ctl = 3;
16408621f407SFrançois Tigeot 		targ_cnt = 9;
16418621f407SFrançois Tigeot 	} else if (vco == 5400000) {
16428621f407SFrançois Tigeot 		prop_coef = 3;
16438621f407SFrançois Tigeot 		int_coef = 8;
16448621f407SFrançois Tigeot 		gain_ctl = 1;
16458621f407SFrançois Tigeot 		targ_cnt = 9;
16468621f407SFrançois Tigeot 	} else {
16478621f407SFrançois Tigeot 		DRM_ERROR("Invalid VCO\n");
1648*1e12ee3bSFrançois Tigeot 		return false;
16498621f407SFrançois Tigeot 	}
16508621f407SFrançois Tigeot 
16518621f407SFrançois Tigeot 	if (clock > 270000)
16528621f407SFrançois Tigeot 		lanestagger = 0x18;
16538621f407SFrançois Tigeot 	else if (clock > 135000)
16548621f407SFrançois Tigeot 		lanestagger = 0x0d;
16558621f407SFrançois Tigeot 	else if (clock > 67000)
16568621f407SFrançois Tigeot 		lanestagger = 0x07;
16578621f407SFrançois Tigeot 	else if (clock > 33000)
16588621f407SFrançois Tigeot 		lanestagger = 0x04;
16598621f407SFrançois Tigeot 	else
16608621f407SFrançois Tigeot 		lanestagger = 0x02;
16618621f407SFrançois Tigeot 
1662*1e12ee3bSFrançois Tigeot 	dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2);
1663*1e12ee3bSFrançois Tigeot 	dpll_hw_state->pll0 = clk_div->m2_int;
1664*1e12ee3bSFrançois Tigeot 	dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n);
1665*1e12ee3bSFrançois Tigeot 	dpll_hw_state->pll2 = clk_div->m2_frac;
16668621f407SFrançois Tigeot 
1667*1e12ee3bSFrançois Tigeot 	if (clk_div->m2_frac_en)
1668*1e12ee3bSFrançois Tigeot 		dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE;
16698621f407SFrançois Tigeot 
1670*1e12ee3bSFrançois Tigeot 	dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef);
1671*1e12ee3bSFrançois Tigeot 	dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl);
16728621f407SFrançois Tigeot 
1673*1e12ee3bSFrançois Tigeot 	dpll_hw_state->pll8 = targ_cnt;
16748621f407SFrançois Tigeot 
1675*1e12ee3bSFrançois Tigeot 	dpll_hw_state->pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
16768621f407SFrançois Tigeot 
1677*1e12ee3bSFrançois Tigeot 	dpll_hw_state->pll10 =
16788621f407SFrançois Tigeot 		PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
16798621f407SFrançois Tigeot 		| PORT_PLL_DCO_AMP_OVR_EN_H;
16808621f407SFrançois Tigeot 
1681*1e12ee3bSFrançois Tigeot 	dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
16828621f407SFrançois Tigeot 
1683*1e12ee3bSFrançois Tigeot 	dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger;
16848621f407SFrançois Tigeot 
1685*1e12ee3bSFrançois Tigeot 	return true;
1686*1e12ee3bSFrançois Tigeot }
1687*1e12ee3bSFrançois Tigeot 
1688*1e12ee3bSFrançois Tigeot bool bxt_ddi_dp_set_dpll_hw_state(int clock,
1689*1e12ee3bSFrançois Tigeot 			  struct intel_dpll_hw_state *dpll_hw_state)
1690*1e12ee3bSFrançois Tigeot {
1691*1e12ee3bSFrançois Tigeot 	struct bxt_clk_div clk_div = {0};
1692*1e12ee3bSFrançois Tigeot 
1693*1e12ee3bSFrançois Tigeot 	bxt_ddi_dp_pll_dividers(clock, &clk_div);
1694*1e12ee3bSFrançois Tigeot 
1695*1e12ee3bSFrançois Tigeot 	return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state);
1696*1e12ee3bSFrançois Tigeot }
1697*1e12ee3bSFrançois Tigeot 
1698*1e12ee3bSFrançois Tigeot static bool
1699*1e12ee3bSFrançois Tigeot bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc *intel_crtc,
1700*1e12ee3bSFrançois Tigeot 			       struct intel_crtc_state *crtc_state, int clock,
1701*1e12ee3bSFrançois Tigeot 			       struct intel_dpll_hw_state *dpll_hw_state)
1702*1e12ee3bSFrançois Tigeot {
1703*1e12ee3bSFrançois Tigeot 	struct bxt_clk_div clk_div = { };
1704*1e12ee3bSFrançois Tigeot 
1705*1e12ee3bSFrançois Tigeot 	bxt_ddi_hdmi_pll_dividers(intel_crtc, crtc_state, clock, &clk_div);
1706*1e12ee3bSFrançois Tigeot 
1707*1e12ee3bSFrançois Tigeot 	return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state);
1708*1e12ee3bSFrançois Tigeot }
1709*1e12ee3bSFrançois Tigeot 
1710*1e12ee3bSFrançois Tigeot static struct intel_shared_dpll *
1711*1e12ee3bSFrançois Tigeot bxt_get_dpll(struct intel_crtc *crtc,
1712*1e12ee3bSFrançois Tigeot 		struct intel_crtc_state *crtc_state,
1713*1e12ee3bSFrançois Tigeot 		struct intel_encoder *encoder)
1714*1e12ee3bSFrançois Tigeot {
1715*1e12ee3bSFrançois Tigeot 	struct intel_dpll_hw_state dpll_hw_state = { };
1716*1e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
1717*1e12ee3bSFrançois Tigeot 	struct intel_digital_port *intel_dig_port;
1718*1e12ee3bSFrançois Tigeot 	struct intel_shared_dpll *pll;
1719*1e12ee3bSFrançois Tigeot 	int i, clock = crtc_state->port_clock;
1720*1e12ee3bSFrançois Tigeot 
1721*1e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI &&
1722*1e12ee3bSFrançois Tigeot 	    !bxt_ddi_hdmi_set_dpll_hw_state(crtc, crtc_state, clock,
1723*1e12ee3bSFrançois Tigeot 					    &dpll_hw_state))
1724*1e12ee3bSFrançois Tigeot 		return NULL;
1725*1e12ee3bSFrançois Tigeot 
1726*1e12ee3bSFrançois Tigeot 	if ((encoder->type == INTEL_OUTPUT_DP ||
1727*1e12ee3bSFrançois Tigeot 	     encoder->type == INTEL_OUTPUT_EDP) &&
1728*1e12ee3bSFrançois Tigeot 	    !bxt_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
1729*1e12ee3bSFrançois Tigeot 		return NULL;
1730*1e12ee3bSFrançois Tigeot 
1731*1e12ee3bSFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
1732*1e12ee3bSFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
1733*1e12ee3bSFrançois Tigeot 
1734*1e12ee3bSFrançois Tigeot 	crtc_state->dpll_hw_state = dpll_hw_state;
1735*1e12ee3bSFrançois Tigeot 
1736*1e12ee3bSFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_DP_MST) {
1737*1e12ee3bSFrançois Tigeot 		struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
1738*1e12ee3bSFrançois Tigeot 
1739*1e12ee3bSFrançois Tigeot 		intel_dig_port = intel_mst->primary;
1740*1e12ee3bSFrançois Tigeot 	} else
17418621f407SFrançois Tigeot 		intel_dig_port = enc_to_dig_port(&encoder->base);
17428621f407SFrançois Tigeot 
17438621f407SFrançois Tigeot 	/* 1:1 mapping between ports and PLLs */
17448621f407SFrançois Tigeot 	i = (enum intel_dpll_id) intel_dig_port->port;
17458621f407SFrançois Tigeot 	pll = intel_get_shared_dpll_by_id(dev_priv, i);
17468621f407SFrançois Tigeot 
17471487f786SFrançois Tigeot 	DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n",
17481487f786SFrançois Tigeot 		      crtc->base.base.id, crtc->base.name, pll->name);
17498621f407SFrançois Tigeot 
17508621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
17518621f407SFrançois Tigeot 
17528621f407SFrançois Tigeot 	return pll;
17538621f407SFrançois Tigeot }
17548621f407SFrançois Tigeot 
17558621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = {
17568621f407SFrançois Tigeot 	.enable = bxt_ddi_pll_enable,
17578621f407SFrançois Tigeot 	.disable = bxt_ddi_pll_disable,
17588621f407SFrançois Tigeot 	.get_hw_state = bxt_ddi_pll_get_hw_state,
17598621f407SFrançois Tigeot };
17608621f407SFrançois Tigeot 
17618621f407SFrançois Tigeot static void intel_ddi_pll_init(struct drm_device *dev)
17628621f407SFrançois Tigeot {
1763303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
17641487f786SFrançois Tigeot 
17651487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 9) {
17668621f407SFrançois Tigeot 		uint32_t val = I915_READ(LCPLL_CTL);
17678621f407SFrançois Tigeot 
17688621f407SFrançois Tigeot 		/*
17698621f407SFrançois Tigeot 		 * The LCPLL register should be turned on by the BIOS. For now
17708621f407SFrançois Tigeot 		 * let's just check its state and print errors in case
17718621f407SFrançois Tigeot 		 * something is wrong.  Don't even try to turn it on.
17728621f407SFrançois Tigeot 		 */
17738621f407SFrançois Tigeot 
17748621f407SFrançois Tigeot 		if (val & LCPLL_CD_SOURCE_FCLK)
17758621f407SFrançois Tigeot 			DRM_ERROR("CDCLK source is not LCPLL\n");
17768621f407SFrançois Tigeot 
17778621f407SFrançois Tigeot 		if (val & LCPLL_PLL_DISABLE)
17788621f407SFrançois Tigeot 			DRM_ERROR("LCPLL is disabled\n");
17798621f407SFrançois Tigeot 	}
17808621f407SFrançois Tigeot }
17818621f407SFrançois Tigeot 
17828621f407SFrançois Tigeot struct dpll_info {
17838621f407SFrançois Tigeot 	const char *name;
17848621f407SFrançois Tigeot 	const int id;
17858621f407SFrançois Tigeot 	const struct intel_shared_dpll_funcs *funcs;
17868621f407SFrançois Tigeot 	uint32_t flags;
17878621f407SFrançois Tigeot };
17888621f407SFrançois Tigeot 
17898621f407SFrançois Tigeot struct intel_dpll_mgr {
17908621f407SFrançois Tigeot 	const struct dpll_info *dpll_info;
17918621f407SFrançois Tigeot 
17928621f407SFrançois Tigeot 	struct intel_shared_dpll *(*get_dpll)(struct intel_crtc *crtc,
17938621f407SFrançois Tigeot 					      struct intel_crtc_state *crtc_state,
17948621f407SFrançois Tigeot 					      struct intel_encoder *encoder);
17958621f407SFrançois Tigeot };
17968621f407SFrançois Tigeot 
17978621f407SFrançois Tigeot static const struct dpll_info pch_plls[] = {
17988621f407SFrançois Tigeot 	{ "PCH DPLL A", DPLL_ID_PCH_PLL_A, &ibx_pch_dpll_funcs, 0 },
17998621f407SFrançois Tigeot 	{ "PCH DPLL B", DPLL_ID_PCH_PLL_B, &ibx_pch_dpll_funcs, 0 },
18008621f407SFrançois Tigeot 	{ NULL, -1, NULL, 0 },
18018621f407SFrançois Tigeot };
18028621f407SFrançois Tigeot 
18038621f407SFrançois Tigeot static const struct intel_dpll_mgr pch_pll_mgr = {
18048621f407SFrançois Tigeot 	.dpll_info = pch_plls,
18058621f407SFrançois Tigeot 	.get_dpll = ibx_get_dpll,
18068621f407SFrançois Tigeot };
18078621f407SFrançois Tigeot 
18088621f407SFrançois Tigeot static const struct dpll_info hsw_plls[] = {
18098621f407SFrançois Tigeot 	{ "WRPLL 1",    DPLL_ID_WRPLL1,     &hsw_ddi_wrpll_funcs, 0 },
18108621f407SFrançois Tigeot 	{ "WRPLL 2",    DPLL_ID_WRPLL2,     &hsw_ddi_wrpll_funcs, 0 },
18118621f407SFrançois Tigeot 	{ "SPLL",       DPLL_ID_SPLL,       &hsw_ddi_spll_funcs,  0 },
18128621f407SFrançois Tigeot 	{ "LCPLL 810",  DPLL_ID_LCPLL_810,  &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
18138621f407SFrançois Tigeot 	{ "LCPLL 1350", DPLL_ID_LCPLL_1350, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
18148621f407SFrançois Tigeot 	{ "LCPLL 2700", DPLL_ID_LCPLL_2700, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
18158621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
18168621f407SFrançois Tigeot };
18178621f407SFrançois Tigeot 
18188621f407SFrançois Tigeot static const struct intel_dpll_mgr hsw_pll_mgr = {
18198621f407SFrançois Tigeot 	.dpll_info = hsw_plls,
18208621f407SFrançois Tigeot 	.get_dpll = hsw_get_dpll,
18218621f407SFrançois Tigeot };
18228621f407SFrançois Tigeot 
18238621f407SFrançois Tigeot static const struct dpll_info skl_plls[] = {
18248621f407SFrançois Tigeot 	{ "DPLL 0", DPLL_ID_SKL_DPLL0, &skl_ddi_dpll0_funcs, INTEL_DPLL_ALWAYS_ON },
18258621f407SFrançois Tigeot 	{ "DPLL 1", DPLL_ID_SKL_DPLL1, &skl_ddi_pll_funcs,   0 },
18268621f407SFrançois Tigeot 	{ "DPLL 2", DPLL_ID_SKL_DPLL2, &skl_ddi_pll_funcs,   0 },
18278621f407SFrançois Tigeot 	{ "DPLL 3", DPLL_ID_SKL_DPLL3, &skl_ddi_pll_funcs,   0 },
18288621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
18298621f407SFrançois Tigeot };
18308621f407SFrançois Tigeot 
18318621f407SFrançois Tigeot static const struct intel_dpll_mgr skl_pll_mgr = {
18328621f407SFrançois Tigeot 	.dpll_info = skl_plls,
18338621f407SFrançois Tigeot 	.get_dpll = skl_get_dpll,
18348621f407SFrançois Tigeot };
18358621f407SFrançois Tigeot 
18368621f407SFrançois Tigeot static const struct dpll_info bxt_plls[] = {
18378621f407SFrançois Tigeot 	{ "PORT PLL A", DPLL_ID_SKL_DPLL0, &bxt_ddi_pll_funcs, 0 },
18388621f407SFrançois Tigeot 	{ "PORT PLL B", DPLL_ID_SKL_DPLL1, &bxt_ddi_pll_funcs, 0 },
18398621f407SFrançois Tigeot 	{ "PORT PLL C", DPLL_ID_SKL_DPLL2, &bxt_ddi_pll_funcs, 0 },
18408621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
18418621f407SFrançois Tigeot };
18428621f407SFrançois Tigeot 
18438621f407SFrançois Tigeot static const struct intel_dpll_mgr bxt_pll_mgr = {
18448621f407SFrançois Tigeot 	.dpll_info = bxt_plls,
18458621f407SFrançois Tigeot 	.get_dpll = bxt_get_dpll,
18468621f407SFrançois Tigeot };
18478621f407SFrançois Tigeot 
18488621f407SFrançois Tigeot void intel_shared_dpll_init(struct drm_device *dev)
18498621f407SFrançois Tigeot {
1850303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
18518621f407SFrançois Tigeot 	const struct intel_dpll_mgr *dpll_mgr = NULL;
18528621f407SFrançois Tigeot 	const struct dpll_info *dpll_info;
18538621f407SFrançois Tigeot 	int i;
18548621f407SFrançois Tigeot 
1855*1e12ee3bSFrançois Tigeot 	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
18568621f407SFrançois Tigeot 		dpll_mgr = &skl_pll_mgr;
1857*1e12ee3bSFrançois Tigeot 	else if (IS_BROXTON(dev_priv))
18588621f407SFrançois Tigeot 		dpll_mgr = &bxt_pll_mgr;
1859*1e12ee3bSFrançois Tigeot 	else if (HAS_DDI(dev_priv))
18608621f407SFrançois Tigeot 		dpll_mgr = &hsw_pll_mgr;
1861*1e12ee3bSFrançois Tigeot 	else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))
18628621f407SFrançois Tigeot 		dpll_mgr = &pch_pll_mgr;
18638621f407SFrançois Tigeot 
18648621f407SFrançois Tigeot 	if (!dpll_mgr) {
18658621f407SFrançois Tigeot 		dev_priv->num_shared_dpll = 0;
18668621f407SFrançois Tigeot 		return;
18678621f407SFrançois Tigeot 	}
18688621f407SFrançois Tigeot 
18698621f407SFrançois Tigeot 	dpll_info = dpll_mgr->dpll_info;
18708621f407SFrançois Tigeot 
18718621f407SFrançois Tigeot 	for (i = 0; dpll_info[i].id >= 0; i++) {
18728621f407SFrançois Tigeot 		WARN_ON(i != dpll_info[i].id);
18738621f407SFrançois Tigeot 
18748621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].id = dpll_info[i].id;
18758621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].name = dpll_info[i].name;
18768621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].funcs = *dpll_info[i].funcs;
18778621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].flags = dpll_info[i].flags;
18788621f407SFrançois Tigeot 	}
18798621f407SFrançois Tigeot 
18808621f407SFrançois Tigeot 	dev_priv->dpll_mgr = dpll_mgr;
18818621f407SFrançois Tigeot 	dev_priv->num_shared_dpll = i;
18828621f407SFrançois Tigeot 	lockinit(&dev_priv->dpll_lock, "dpll_lock", 0, LK_CANRECURSE);
18838621f407SFrançois Tigeot 
18848621f407SFrançois Tigeot 	BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
18858621f407SFrançois Tigeot 
18868621f407SFrançois Tigeot 	/* FIXME: Move this to a more suitable place */
1887*1e12ee3bSFrançois Tigeot 	if (HAS_DDI(dev_priv))
18888621f407SFrançois Tigeot 		intel_ddi_pll_init(dev);
18898621f407SFrançois Tigeot }
18908621f407SFrançois Tigeot 
18918621f407SFrançois Tigeot struct intel_shared_dpll *
18928621f407SFrançois Tigeot intel_get_shared_dpll(struct intel_crtc *crtc,
18938621f407SFrançois Tigeot 		      struct intel_crtc_state *crtc_state,
18948621f407SFrançois Tigeot 		      struct intel_encoder *encoder)
18958621f407SFrançois Tigeot {
18968621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
18978621f407SFrançois Tigeot 	const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll_mgr;
18988621f407SFrançois Tigeot 
18998621f407SFrançois Tigeot 	if (WARN_ON(!dpll_mgr))
19008621f407SFrançois Tigeot 		return NULL;
19018621f407SFrançois Tigeot 
19028621f407SFrançois Tigeot 	return dpll_mgr->get_dpll(crtc, crtc_state, encoder);
19038621f407SFrançois Tigeot }
1904