xref: /dflybsd-src/sys/dev/drm/i915/intel_dpll_mgr.c (revision 8621f4070e7cb342161183c980ae7fce2fd8124e)
1*8621f407SFrançois Tigeot /*
2*8621f407SFrançois Tigeot  * Copyright © 2006-2016 Intel Corporation
3*8621f407SFrançois Tigeot  *
4*8621f407SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5*8621f407SFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6*8621f407SFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7*8621f407SFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*8621f407SFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9*8621f407SFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
10*8621f407SFrançois Tigeot  *
11*8621f407SFrançois Tigeot  * The above copyright notice and this permission notice (including the next
12*8621f407SFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
13*8621f407SFrançois Tigeot  * Software.
14*8621f407SFrançois Tigeot  *
15*8621f407SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*8621f407SFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*8621f407SFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*8621f407SFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*8621f407SFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*8621f407SFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*8621f407SFrançois Tigeot  * DEALINGS IN THE SOFTWARE.
22*8621f407SFrançois Tigeot  */
23*8621f407SFrançois Tigeot 
24*8621f407SFrançois Tigeot #include "intel_drv.h"
25*8621f407SFrançois Tigeot #include <asm/int-ll64.h>
26*8621f407SFrançois Tigeot 
27*8621f407SFrançois Tigeot struct intel_shared_dpll *
28*8621f407SFrançois Tigeot intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
29*8621f407SFrançois Tigeot 			    enum intel_dpll_id id)
30*8621f407SFrançois Tigeot {
31*8621f407SFrançois Tigeot 	return &dev_priv->shared_dplls[id];
32*8621f407SFrançois Tigeot }
33*8621f407SFrançois Tigeot 
34*8621f407SFrançois Tigeot enum intel_dpll_id
35*8621f407SFrançois Tigeot intel_get_shared_dpll_id(struct drm_i915_private *dev_priv,
36*8621f407SFrançois Tigeot 			 struct intel_shared_dpll *pll)
37*8621f407SFrançois Tigeot {
38*8621f407SFrançois Tigeot 	if (WARN_ON(pll < dev_priv->shared_dplls||
39*8621f407SFrançois Tigeot 		    pll > &dev_priv->shared_dplls[dev_priv->num_shared_dpll]))
40*8621f407SFrançois Tigeot 		return -1;
41*8621f407SFrançois Tigeot 
42*8621f407SFrançois Tigeot 	return (enum intel_dpll_id) (pll - dev_priv->shared_dplls);
43*8621f407SFrançois Tigeot }
44*8621f407SFrançois Tigeot 
45*8621f407SFrançois Tigeot void
46*8621f407SFrançois Tigeot intel_shared_dpll_config_get(struct intel_shared_dpll_config *config,
47*8621f407SFrançois Tigeot 			     struct intel_shared_dpll *pll,
48*8621f407SFrançois Tigeot 			     struct intel_crtc *crtc)
49*8621f407SFrançois Tigeot {
50*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
51*8621f407SFrançois Tigeot 	enum intel_dpll_id id = intel_get_shared_dpll_id(dev_priv, pll);
52*8621f407SFrançois Tigeot 
53*8621f407SFrançois Tigeot 	config[id].crtc_mask |= 1 << crtc->pipe;
54*8621f407SFrançois Tigeot }
55*8621f407SFrançois Tigeot 
56*8621f407SFrançois Tigeot void
57*8621f407SFrançois Tigeot intel_shared_dpll_config_put(struct intel_shared_dpll_config *config,
58*8621f407SFrançois Tigeot 			     struct intel_shared_dpll *pll,
59*8621f407SFrançois Tigeot 			     struct intel_crtc *crtc)
60*8621f407SFrançois Tigeot {
61*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
62*8621f407SFrançois Tigeot 	enum intel_dpll_id id = intel_get_shared_dpll_id(dev_priv, pll);
63*8621f407SFrançois Tigeot 
64*8621f407SFrançois Tigeot 	config[id].crtc_mask &= ~(1 << crtc->pipe);
65*8621f407SFrançois Tigeot }
66*8621f407SFrançois Tigeot 
67*8621f407SFrançois Tigeot /* For ILK+ */
68*8621f407SFrançois Tigeot void assert_shared_dpll(struct drm_i915_private *dev_priv,
69*8621f407SFrançois Tigeot 			struct intel_shared_dpll *pll,
70*8621f407SFrançois Tigeot 			bool state)
71*8621f407SFrançois Tigeot {
72*8621f407SFrançois Tigeot 	bool cur_state;
73*8621f407SFrançois Tigeot 	struct intel_dpll_hw_state hw_state;
74*8621f407SFrançois Tigeot 
75*8621f407SFrançois Tigeot 	if (WARN(!pll, "asserting DPLL %s with no DPLL\n", onoff(state)))
76*8621f407SFrançois Tigeot 		return;
77*8621f407SFrançois Tigeot 
78*8621f407SFrançois Tigeot 	cur_state = pll->funcs.get_hw_state(dev_priv, pll, &hw_state);
79*8621f407SFrançois Tigeot 	I915_STATE_WARN(cur_state != state,
80*8621f407SFrançois Tigeot 	     "%s assertion failure (expected %s, current %s)\n",
81*8621f407SFrançois Tigeot 			pll->name, onoff(state), onoff(cur_state));
82*8621f407SFrançois Tigeot }
83*8621f407SFrançois Tigeot 
84*8621f407SFrançois Tigeot void intel_prepare_shared_dpll(struct intel_crtc *crtc)
85*8621f407SFrançois Tigeot {
86*8621f407SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
87*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
88*8621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
89*8621f407SFrançois Tigeot 
90*8621f407SFrançois Tigeot 	if (WARN_ON(pll == NULL))
91*8621f407SFrançois Tigeot 		return;
92*8621f407SFrançois Tigeot 
93*8621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
94*8621f407SFrançois Tigeot 	WARN_ON(!pll->config.crtc_mask);
95*8621f407SFrançois Tigeot 	if (!pll->active_mask) {
96*8621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("setting up %s\n", pll->name);
97*8621f407SFrançois Tigeot 		WARN_ON(pll->on);
98*8621f407SFrançois Tigeot 		assert_shared_dpll_disabled(dev_priv, pll);
99*8621f407SFrançois Tigeot 
100*8621f407SFrançois Tigeot 		pll->funcs.mode_set(dev_priv, pll);
101*8621f407SFrançois Tigeot 	}
102*8621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
103*8621f407SFrançois Tigeot }
104*8621f407SFrançois Tigeot 
105*8621f407SFrançois Tigeot /**
106*8621f407SFrançois Tigeot  * intel_enable_shared_dpll - enable PCH PLL
107*8621f407SFrançois Tigeot  * @dev_priv: i915 private structure
108*8621f407SFrançois Tigeot  * @pipe: pipe PLL to enable
109*8621f407SFrançois Tigeot  *
110*8621f407SFrançois Tigeot  * The PCH PLL needs to be enabled before the PCH transcoder, since it
111*8621f407SFrançois Tigeot  * drives the transcoder clock.
112*8621f407SFrançois Tigeot  */
113*8621f407SFrançois Tigeot void intel_enable_shared_dpll(struct intel_crtc *crtc)
114*8621f407SFrançois Tigeot {
115*8621f407SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
116*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
117*8621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
118*8621f407SFrançois Tigeot 	unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base);
119*8621f407SFrançois Tigeot 	unsigned old_mask;
120*8621f407SFrançois Tigeot 
121*8621f407SFrançois Tigeot 	if (WARN_ON(pll == NULL))
122*8621f407SFrançois Tigeot 		return;
123*8621f407SFrançois Tigeot 
124*8621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
125*8621f407SFrançois Tigeot 	old_mask = pll->active_mask;
126*8621f407SFrançois Tigeot 
127*8621f407SFrançois Tigeot 	if (WARN_ON(!(pll->config.crtc_mask & crtc_mask)) ||
128*8621f407SFrançois Tigeot 	    WARN_ON(pll->active_mask & crtc_mask))
129*8621f407SFrançois Tigeot 		goto out;
130*8621f407SFrançois Tigeot 
131*8621f407SFrançois Tigeot 	pll->active_mask |= crtc_mask;
132*8621f407SFrançois Tigeot 
133*8621f407SFrançois Tigeot 	DRM_DEBUG_KMS("enable %s (active %x, on? %d) for crtc %d\n",
134*8621f407SFrançois Tigeot 		      pll->name, pll->active_mask, pll->on,
135*8621f407SFrançois Tigeot 		      crtc->base.base.id);
136*8621f407SFrançois Tigeot 
137*8621f407SFrançois Tigeot 	if (old_mask) {
138*8621f407SFrançois Tigeot 		WARN_ON(!pll->on);
139*8621f407SFrançois Tigeot 		assert_shared_dpll_enabled(dev_priv, pll);
140*8621f407SFrançois Tigeot 		goto out;
141*8621f407SFrançois Tigeot 	}
142*8621f407SFrançois Tigeot 	WARN_ON(pll->on);
143*8621f407SFrançois Tigeot 
144*8621f407SFrançois Tigeot 	DRM_DEBUG_KMS("enabling %s\n", pll->name);
145*8621f407SFrançois Tigeot 	pll->funcs.enable(dev_priv, pll);
146*8621f407SFrançois Tigeot 	pll->on = true;
147*8621f407SFrançois Tigeot 
148*8621f407SFrançois Tigeot out:
149*8621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
150*8621f407SFrançois Tigeot }
151*8621f407SFrançois Tigeot 
152*8621f407SFrançois Tigeot void intel_disable_shared_dpll(struct intel_crtc *crtc)
153*8621f407SFrançois Tigeot {
154*8621f407SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
155*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
156*8621f407SFrançois Tigeot 	struct intel_shared_dpll *pll = crtc->config->shared_dpll;
157*8621f407SFrançois Tigeot 	unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base);
158*8621f407SFrançois Tigeot 
159*8621f407SFrançois Tigeot 	/* PCH only available on ILK+ */
160*8621f407SFrançois Tigeot 	if (INTEL_INFO(dev)->gen < 5)
161*8621f407SFrançois Tigeot 		return;
162*8621f407SFrançois Tigeot 
163*8621f407SFrançois Tigeot 	if (pll == NULL)
164*8621f407SFrançois Tigeot 		return;
165*8621f407SFrançois Tigeot 
166*8621f407SFrançois Tigeot 	mutex_lock(&dev_priv->dpll_lock);
167*8621f407SFrançois Tigeot 	if (WARN_ON(!(pll->active_mask & crtc_mask)))
168*8621f407SFrançois Tigeot 		goto out;
169*8621f407SFrançois Tigeot 
170*8621f407SFrançois Tigeot 	DRM_DEBUG_KMS("disable %s (active %x, on? %d) for crtc %d\n",
171*8621f407SFrançois Tigeot 		      pll->name, pll->active_mask, pll->on,
172*8621f407SFrançois Tigeot 		      crtc->base.base.id);
173*8621f407SFrançois Tigeot 
174*8621f407SFrançois Tigeot 	assert_shared_dpll_enabled(dev_priv, pll);
175*8621f407SFrançois Tigeot 	WARN_ON(!pll->on);
176*8621f407SFrançois Tigeot 
177*8621f407SFrançois Tigeot 	pll->active_mask &= ~crtc_mask;
178*8621f407SFrançois Tigeot 	if (pll->active_mask)
179*8621f407SFrançois Tigeot 		goto out;
180*8621f407SFrançois Tigeot 
181*8621f407SFrançois Tigeot 	DRM_DEBUG_KMS("disabling %s\n", pll->name);
182*8621f407SFrançois Tigeot 	pll->funcs.disable(dev_priv, pll);
183*8621f407SFrançois Tigeot 	pll->on = false;
184*8621f407SFrançois Tigeot 
185*8621f407SFrançois Tigeot out:
186*8621f407SFrançois Tigeot 	mutex_unlock(&dev_priv->dpll_lock);
187*8621f407SFrançois Tigeot }
188*8621f407SFrançois Tigeot 
189*8621f407SFrançois Tigeot static struct intel_shared_dpll *
190*8621f407SFrançois Tigeot intel_find_shared_dpll(struct intel_crtc *crtc,
191*8621f407SFrançois Tigeot 		       struct intel_crtc_state *crtc_state,
192*8621f407SFrançois Tigeot 		       enum intel_dpll_id range_min,
193*8621f407SFrançois Tigeot 		       enum intel_dpll_id range_max)
194*8621f407SFrançois Tigeot {
195*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
196*8621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
197*8621f407SFrançois Tigeot 	struct intel_shared_dpll_config *shared_dpll;
198*8621f407SFrançois Tigeot 	enum intel_dpll_id i;
199*8621f407SFrançois Tigeot 
200*8621f407SFrançois Tigeot 	shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
201*8621f407SFrançois Tigeot 
202*8621f407SFrançois Tigeot 	for (i = range_min; i <= range_max; i++) {
203*8621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
204*8621f407SFrançois Tigeot 
205*8621f407SFrançois Tigeot 		/* Only want to check enabled timings first */
206*8621f407SFrançois Tigeot 		if (shared_dpll[i].crtc_mask == 0)
207*8621f407SFrançois Tigeot 			continue;
208*8621f407SFrançois Tigeot 
209*8621f407SFrançois Tigeot 		if (memcmp(&crtc_state->dpll_hw_state,
210*8621f407SFrançois Tigeot 			   &shared_dpll[i].hw_state,
211*8621f407SFrançois Tigeot 			   sizeof(crtc_state->dpll_hw_state)) == 0) {
212*8621f407SFrançois Tigeot 			DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, active %x)\n",
213*8621f407SFrançois Tigeot 				      crtc->base.base.id, pll->name,
214*8621f407SFrançois Tigeot 				      shared_dpll[i].crtc_mask,
215*8621f407SFrançois Tigeot 				      pll->active_mask);
216*8621f407SFrançois Tigeot 			return pll;
217*8621f407SFrançois Tigeot 		}
218*8621f407SFrançois Tigeot 	}
219*8621f407SFrançois Tigeot 
220*8621f407SFrançois Tigeot 	/* Ok no matching timings, maybe there's a free one? */
221*8621f407SFrançois Tigeot 	for (i = range_min; i <= range_max; i++) {
222*8621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
223*8621f407SFrançois Tigeot 		if (shared_dpll[i].crtc_mask == 0) {
224*8621f407SFrançois Tigeot 			DRM_DEBUG_KMS("CRTC:%d allocated %s\n",
225*8621f407SFrançois Tigeot 				      crtc->base.base.id, pll->name);
226*8621f407SFrançois Tigeot 			return pll;
227*8621f407SFrançois Tigeot 		}
228*8621f407SFrançois Tigeot 	}
229*8621f407SFrançois Tigeot 
230*8621f407SFrançois Tigeot 	return NULL;
231*8621f407SFrançois Tigeot }
232*8621f407SFrançois Tigeot 
233*8621f407SFrançois Tigeot static void
234*8621f407SFrançois Tigeot intel_reference_shared_dpll(struct intel_shared_dpll *pll,
235*8621f407SFrançois Tigeot 			    struct intel_crtc_state *crtc_state)
236*8621f407SFrançois Tigeot {
237*8621f407SFrançois Tigeot 	struct intel_shared_dpll_config *shared_dpll;
238*8621f407SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
239*8621f407SFrançois Tigeot 	enum intel_dpll_id i = pll->id;
240*8621f407SFrançois Tigeot 
241*8621f407SFrançois Tigeot 	shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
242*8621f407SFrançois Tigeot 
243*8621f407SFrançois Tigeot 	if (shared_dpll[i].crtc_mask == 0)
244*8621f407SFrançois Tigeot 		shared_dpll[i].hw_state =
245*8621f407SFrançois Tigeot 			crtc_state->dpll_hw_state;
246*8621f407SFrançois Tigeot 
247*8621f407SFrançois Tigeot 	crtc_state->shared_dpll = pll;
248*8621f407SFrançois Tigeot 	DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
249*8621f407SFrançois Tigeot 			 pipe_name(crtc->pipe));
250*8621f407SFrançois Tigeot 
251*8621f407SFrançois Tigeot 	intel_shared_dpll_config_get(shared_dpll, pll, crtc);
252*8621f407SFrançois Tigeot }
253*8621f407SFrançois Tigeot 
254*8621f407SFrançois Tigeot void intel_shared_dpll_commit(struct drm_atomic_state *state)
255*8621f407SFrançois Tigeot {
256*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(state->dev);
257*8621f407SFrançois Tigeot 	struct intel_shared_dpll_config *shared_dpll;
258*8621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
259*8621f407SFrançois Tigeot 	enum intel_dpll_id i;
260*8621f407SFrançois Tigeot 
261*8621f407SFrançois Tigeot 	if (!to_intel_atomic_state(state)->dpll_set)
262*8621f407SFrançois Tigeot 		return;
263*8621f407SFrançois Tigeot 
264*8621f407SFrançois Tigeot 	shared_dpll = to_intel_atomic_state(state)->shared_dpll;
265*8621f407SFrançois Tigeot 	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
266*8621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
267*8621f407SFrançois Tigeot 		pll->config = shared_dpll[i];
268*8621f407SFrançois Tigeot 	}
269*8621f407SFrançois Tigeot }
270*8621f407SFrançois Tigeot 
271*8621f407SFrançois Tigeot static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
272*8621f407SFrançois Tigeot 				      struct intel_shared_dpll *pll,
273*8621f407SFrançois Tigeot 				      struct intel_dpll_hw_state *hw_state)
274*8621f407SFrançois Tigeot {
275*8621f407SFrançois Tigeot 	uint32_t val;
276*8621f407SFrançois Tigeot 
277*8621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
278*8621f407SFrançois Tigeot 		return false;
279*8621f407SFrançois Tigeot 
280*8621f407SFrançois Tigeot 	val = I915_READ(PCH_DPLL(pll->id));
281*8621f407SFrançois Tigeot 	hw_state->dpll = val;
282*8621f407SFrançois Tigeot 	hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
283*8621f407SFrançois Tigeot 	hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
284*8621f407SFrançois Tigeot 
285*8621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
286*8621f407SFrançois Tigeot 
287*8621f407SFrançois Tigeot 	return val & DPLL_VCO_ENABLE;
288*8621f407SFrançois Tigeot }
289*8621f407SFrançois Tigeot 
290*8621f407SFrançois Tigeot static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv,
291*8621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
292*8621f407SFrançois Tigeot {
293*8621f407SFrançois Tigeot 	I915_WRITE(PCH_FP0(pll->id), pll->config.hw_state.fp0);
294*8621f407SFrançois Tigeot 	I915_WRITE(PCH_FP1(pll->id), pll->config.hw_state.fp1);
295*8621f407SFrançois Tigeot }
296*8621f407SFrançois Tigeot 
297*8621f407SFrançois Tigeot static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
298*8621f407SFrançois Tigeot {
299*8621f407SFrançois Tigeot 	u32 val;
300*8621f407SFrançois Tigeot 	bool enabled;
301*8621f407SFrançois Tigeot 
302*8621f407SFrançois Tigeot 	I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)));
303*8621f407SFrançois Tigeot 
304*8621f407SFrançois Tigeot 	val = I915_READ(PCH_DREF_CONTROL);
305*8621f407SFrançois Tigeot 	enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
306*8621f407SFrançois Tigeot 			    DREF_SUPERSPREAD_SOURCE_MASK));
307*8621f407SFrançois Tigeot 	I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
308*8621f407SFrançois Tigeot }
309*8621f407SFrançois Tigeot 
310*8621f407SFrançois Tigeot static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
311*8621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
312*8621f407SFrançois Tigeot {
313*8621f407SFrançois Tigeot 	/* PCH refclock must be enabled first */
314*8621f407SFrançois Tigeot 	ibx_assert_pch_refclk_enabled(dev_priv);
315*8621f407SFrançois Tigeot 
316*8621f407SFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
317*8621f407SFrançois Tigeot 
318*8621f407SFrançois Tigeot 	/* Wait for the clocks to stabilize. */
319*8621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
320*8621f407SFrançois Tigeot 	udelay(150);
321*8621f407SFrançois Tigeot 
322*8621f407SFrançois Tigeot 	/* The pixel multiplier can only be updated once the
323*8621f407SFrançois Tigeot 	 * DPLL is enabled and the clocks are stable.
324*8621f407SFrançois Tigeot 	 *
325*8621f407SFrançois Tigeot 	 * So write it again.
326*8621f407SFrançois Tigeot 	 */
327*8621f407SFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
328*8621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
329*8621f407SFrançois Tigeot 	udelay(200);
330*8621f407SFrançois Tigeot }
331*8621f407SFrançois Tigeot 
332*8621f407SFrançois Tigeot static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
333*8621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
334*8621f407SFrançois Tigeot {
335*8621f407SFrançois Tigeot 	struct drm_device *dev = dev_priv->dev;
336*8621f407SFrançois Tigeot 	struct intel_crtc *crtc;
337*8621f407SFrançois Tigeot 
338*8621f407SFrançois Tigeot 	/* Make sure no transcoder isn't still depending on us. */
339*8621f407SFrançois Tigeot 	for_each_intel_crtc(dev, crtc) {
340*8621f407SFrançois Tigeot 		if (crtc->config->shared_dpll == pll)
341*8621f407SFrançois Tigeot 			assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
342*8621f407SFrançois Tigeot 	}
343*8621f407SFrançois Tigeot 
344*8621f407SFrançois Tigeot 	I915_WRITE(PCH_DPLL(pll->id), 0);
345*8621f407SFrançois Tigeot 	POSTING_READ(PCH_DPLL(pll->id));
346*8621f407SFrançois Tigeot 	udelay(200);
347*8621f407SFrançois Tigeot }
348*8621f407SFrançois Tigeot 
349*8621f407SFrançois Tigeot static struct intel_shared_dpll *
350*8621f407SFrançois Tigeot ibx_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
351*8621f407SFrançois Tigeot 	     struct intel_encoder *encoder)
352*8621f407SFrançois Tigeot {
353*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
354*8621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
355*8621f407SFrançois Tigeot 	enum intel_dpll_id i;
356*8621f407SFrançois Tigeot 
357*8621f407SFrançois Tigeot 	if (HAS_PCH_IBX(dev_priv)) {
358*8621f407SFrançois Tigeot 		/* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
359*8621f407SFrançois Tigeot 		i = (enum intel_dpll_id) crtc->pipe;
360*8621f407SFrançois Tigeot 		pll = &dev_priv->shared_dplls[i];
361*8621f407SFrançois Tigeot 
362*8621f407SFrançois Tigeot 		DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
363*8621f407SFrançois Tigeot 			      crtc->base.base.id, pll->name);
364*8621f407SFrançois Tigeot 	} else {
365*8621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
366*8621f407SFrançois Tigeot 					     DPLL_ID_PCH_PLL_A,
367*8621f407SFrançois Tigeot 					     DPLL_ID_PCH_PLL_B);
368*8621f407SFrançois Tigeot 	}
369*8621f407SFrançois Tigeot 
370*8621f407SFrançois Tigeot 	if (!pll)
371*8621f407SFrançois Tigeot 		return NULL;
372*8621f407SFrançois Tigeot 
373*8621f407SFrançois Tigeot 	/* reference the pll */
374*8621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
375*8621f407SFrançois Tigeot 
376*8621f407SFrançois Tigeot 	return pll;
377*8621f407SFrançois Tigeot }
378*8621f407SFrançois Tigeot 
379*8621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
380*8621f407SFrançois Tigeot 	.mode_set = ibx_pch_dpll_mode_set,
381*8621f407SFrançois Tigeot 	.enable = ibx_pch_dpll_enable,
382*8621f407SFrançois Tigeot 	.disable = ibx_pch_dpll_disable,
383*8621f407SFrançois Tigeot 	.get_hw_state = ibx_pch_dpll_get_hw_state,
384*8621f407SFrançois Tigeot };
385*8621f407SFrançois Tigeot 
386*8621f407SFrançois Tigeot static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
387*8621f407SFrançois Tigeot 			       struct intel_shared_dpll *pll)
388*8621f407SFrançois Tigeot {
389*8621f407SFrançois Tigeot 	I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
390*8621f407SFrançois Tigeot 	POSTING_READ(WRPLL_CTL(pll->id));
391*8621f407SFrançois Tigeot 	udelay(20);
392*8621f407SFrançois Tigeot }
393*8621f407SFrançois Tigeot 
394*8621f407SFrançois Tigeot static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
395*8621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
396*8621f407SFrançois Tigeot {
397*8621f407SFrançois Tigeot 	I915_WRITE(SPLL_CTL, pll->config.hw_state.spll);
398*8621f407SFrançois Tigeot 	POSTING_READ(SPLL_CTL);
399*8621f407SFrançois Tigeot 	udelay(20);
400*8621f407SFrançois Tigeot }
401*8621f407SFrançois Tigeot 
402*8621f407SFrançois Tigeot static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
403*8621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
404*8621f407SFrançois Tigeot {
405*8621f407SFrançois Tigeot 	uint32_t val;
406*8621f407SFrançois Tigeot 
407*8621f407SFrançois Tigeot 	val = I915_READ(WRPLL_CTL(pll->id));
408*8621f407SFrançois Tigeot 	I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
409*8621f407SFrançois Tigeot 	POSTING_READ(WRPLL_CTL(pll->id));
410*8621f407SFrançois Tigeot }
411*8621f407SFrançois Tigeot 
412*8621f407SFrançois Tigeot static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
413*8621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
414*8621f407SFrançois Tigeot {
415*8621f407SFrançois Tigeot 	uint32_t val;
416*8621f407SFrançois Tigeot 
417*8621f407SFrançois Tigeot 	val = I915_READ(SPLL_CTL);
418*8621f407SFrançois Tigeot 	I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
419*8621f407SFrançois Tigeot 	POSTING_READ(SPLL_CTL);
420*8621f407SFrançois Tigeot }
421*8621f407SFrançois Tigeot 
422*8621f407SFrançois Tigeot static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
423*8621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
424*8621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
425*8621f407SFrançois Tigeot {
426*8621f407SFrançois Tigeot 	uint32_t val;
427*8621f407SFrançois Tigeot 
428*8621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
429*8621f407SFrançois Tigeot 		return false;
430*8621f407SFrançois Tigeot 
431*8621f407SFrançois Tigeot 	val = I915_READ(WRPLL_CTL(pll->id));
432*8621f407SFrançois Tigeot 	hw_state->wrpll = val;
433*8621f407SFrançois Tigeot 
434*8621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
435*8621f407SFrançois Tigeot 
436*8621f407SFrançois Tigeot 	return val & WRPLL_PLL_ENABLE;
437*8621f407SFrançois Tigeot }
438*8621f407SFrançois Tigeot 
439*8621f407SFrançois Tigeot static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
440*8621f407SFrançois Tigeot 				      struct intel_shared_dpll *pll,
441*8621f407SFrançois Tigeot 				      struct intel_dpll_hw_state *hw_state)
442*8621f407SFrançois Tigeot {
443*8621f407SFrançois Tigeot 	uint32_t val;
444*8621f407SFrançois Tigeot 
445*8621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
446*8621f407SFrançois Tigeot 		return false;
447*8621f407SFrançois Tigeot 
448*8621f407SFrançois Tigeot 	val = I915_READ(SPLL_CTL);
449*8621f407SFrançois Tigeot 	hw_state->spll = val;
450*8621f407SFrançois Tigeot 
451*8621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
452*8621f407SFrançois Tigeot 
453*8621f407SFrançois Tigeot 	return val & SPLL_PLL_ENABLE;
454*8621f407SFrançois Tigeot }
455*8621f407SFrançois Tigeot 
456*8621f407SFrançois Tigeot static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
457*8621f407SFrançois Tigeot {
458*8621f407SFrançois Tigeot 	switch (pll->id) {
459*8621f407SFrançois Tigeot 	case DPLL_ID_WRPLL1:
460*8621f407SFrançois Tigeot 		return PORT_CLK_SEL_WRPLL1;
461*8621f407SFrançois Tigeot 	case DPLL_ID_WRPLL2:
462*8621f407SFrançois Tigeot 		return PORT_CLK_SEL_WRPLL2;
463*8621f407SFrançois Tigeot 	case DPLL_ID_SPLL:
464*8621f407SFrançois Tigeot 		return PORT_CLK_SEL_SPLL;
465*8621f407SFrançois Tigeot 	case DPLL_ID_LCPLL_810:
466*8621f407SFrançois Tigeot 		return PORT_CLK_SEL_LCPLL_810;
467*8621f407SFrançois Tigeot 	case DPLL_ID_LCPLL_1350:
468*8621f407SFrançois Tigeot 		return PORT_CLK_SEL_LCPLL_1350;
469*8621f407SFrançois Tigeot 	case DPLL_ID_LCPLL_2700:
470*8621f407SFrançois Tigeot 		return PORT_CLK_SEL_LCPLL_2700;
471*8621f407SFrançois Tigeot 	default:
472*8621f407SFrançois Tigeot 		return PORT_CLK_SEL_NONE;
473*8621f407SFrançois Tigeot 	}
474*8621f407SFrançois Tigeot }
475*8621f407SFrançois Tigeot 
476*8621f407SFrançois Tigeot #define LC_FREQ 2700
477*8621f407SFrançois Tigeot #define LC_FREQ_2K U64_C(LC_FREQ * 2000)
478*8621f407SFrançois Tigeot 
479*8621f407SFrançois Tigeot #define P_MIN 2
480*8621f407SFrançois Tigeot #define P_MAX 64
481*8621f407SFrançois Tigeot #define P_INC 2
482*8621f407SFrançois Tigeot 
483*8621f407SFrançois Tigeot /* Constraints for PLL good behavior */
484*8621f407SFrançois Tigeot #define REF_MIN 48
485*8621f407SFrançois Tigeot #define REF_MAX 400
486*8621f407SFrançois Tigeot #define VCO_MIN 2400
487*8621f407SFrançois Tigeot #define VCO_MAX 4800
488*8621f407SFrançois Tigeot 
489*8621f407SFrançois Tigeot struct hsw_wrpll_rnp {
490*8621f407SFrançois Tigeot 	unsigned p, n2, r2;
491*8621f407SFrançois Tigeot };
492*8621f407SFrançois Tigeot 
493*8621f407SFrançois Tigeot static unsigned hsw_wrpll_get_budget_for_freq(int clock)
494*8621f407SFrançois Tigeot {
495*8621f407SFrançois Tigeot 	unsigned budget;
496*8621f407SFrançois Tigeot 
497*8621f407SFrançois Tigeot 	switch (clock) {
498*8621f407SFrançois Tigeot 	case 25175000:
499*8621f407SFrançois Tigeot 	case 25200000:
500*8621f407SFrançois Tigeot 	case 27000000:
501*8621f407SFrançois Tigeot 	case 27027000:
502*8621f407SFrançois Tigeot 	case 37762500:
503*8621f407SFrançois Tigeot 	case 37800000:
504*8621f407SFrançois Tigeot 	case 40500000:
505*8621f407SFrançois Tigeot 	case 40541000:
506*8621f407SFrançois Tigeot 	case 54000000:
507*8621f407SFrançois Tigeot 	case 54054000:
508*8621f407SFrançois Tigeot 	case 59341000:
509*8621f407SFrançois Tigeot 	case 59400000:
510*8621f407SFrançois Tigeot 	case 72000000:
511*8621f407SFrançois Tigeot 	case 74176000:
512*8621f407SFrançois Tigeot 	case 74250000:
513*8621f407SFrançois Tigeot 	case 81000000:
514*8621f407SFrançois Tigeot 	case 81081000:
515*8621f407SFrançois Tigeot 	case 89012000:
516*8621f407SFrançois Tigeot 	case 89100000:
517*8621f407SFrançois Tigeot 	case 108000000:
518*8621f407SFrançois Tigeot 	case 108108000:
519*8621f407SFrançois Tigeot 	case 111264000:
520*8621f407SFrançois Tigeot 	case 111375000:
521*8621f407SFrançois Tigeot 	case 148352000:
522*8621f407SFrançois Tigeot 	case 148500000:
523*8621f407SFrançois Tigeot 	case 162000000:
524*8621f407SFrançois Tigeot 	case 162162000:
525*8621f407SFrançois Tigeot 	case 222525000:
526*8621f407SFrançois Tigeot 	case 222750000:
527*8621f407SFrançois Tigeot 	case 296703000:
528*8621f407SFrançois Tigeot 	case 297000000:
529*8621f407SFrançois Tigeot 		budget = 0;
530*8621f407SFrançois Tigeot 		break;
531*8621f407SFrançois Tigeot 	case 233500000:
532*8621f407SFrançois Tigeot 	case 245250000:
533*8621f407SFrançois Tigeot 	case 247750000:
534*8621f407SFrançois Tigeot 	case 253250000:
535*8621f407SFrançois Tigeot 	case 298000000:
536*8621f407SFrançois Tigeot 		budget = 1500;
537*8621f407SFrançois Tigeot 		break;
538*8621f407SFrançois Tigeot 	case 169128000:
539*8621f407SFrançois Tigeot 	case 169500000:
540*8621f407SFrançois Tigeot 	case 179500000:
541*8621f407SFrançois Tigeot 	case 202000000:
542*8621f407SFrançois Tigeot 		budget = 2000;
543*8621f407SFrançois Tigeot 		break;
544*8621f407SFrançois Tigeot 	case 256250000:
545*8621f407SFrançois Tigeot 	case 262500000:
546*8621f407SFrançois Tigeot 	case 270000000:
547*8621f407SFrançois Tigeot 	case 272500000:
548*8621f407SFrançois Tigeot 	case 273750000:
549*8621f407SFrançois Tigeot 	case 280750000:
550*8621f407SFrançois Tigeot 	case 281250000:
551*8621f407SFrançois Tigeot 	case 286000000:
552*8621f407SFrançois Tigeot 	case 291750000:
553*8621f407SFrançois Tigeot 		budget = 4000;
554*8621f407SFrançois Tigeot 		break;
555*8621f407SFrançois Tigeot 	case 267250000:
556*8621f407SFrançois Tigeot 	case 268500000:
557*8621f407SFrançois Tigeot 		budget = 5000;
558*8621f407SFrançois Tigeot 		break;
559*8621f407SFrançois Tigeot 	default:
560*8621f407SFrançois Tigeot 		budget = 1000;
561*8621f407SFrançois Tigeot 		break;
562*8621f407SFrançois Tigeot 	}
563*8621f407SFrançois Tigeot 
564*8621f407SFrançois Tigeot 	return budget;
565*8621f407SFrançois Tigeot }
566*8621f407SFrançois Tigeot 
567*8621f407SFrançois Tigeot static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget,
568*8621f407SFrançois Tigeot 				 unsigned r2, unsigned n2, unsigned p,
569*8621f407SFrançois Tigeot 				 struct hsw_wrpll_rnp *best)
570*8621f407SFrançois Tigeot {
571*8621f407SFrançois Tigeot 	uint64_t a, b, c, d, diff, diff_best;
572*8621f407SFrançois Tigeot 
573*8621f407SFrançois Tigeot 	/* No best (r,n,p) yet */
574*8621f407SFrançois Tigeot 	if (best->p == 0) {
575*8621f407SFrançois Tigeot 		best->p = p;
576*8621f407SFrançois Tigeot 		best->n2 = n2;
577*8621f407SFrançois Tigeot 		best->r2 = r2;
578*8621f407SFrançois Tigeot 		return;
579*8621f407SFrançois Tigeot 	}
580*8621f407SFrançois Tigeot 
581*8621f407SFrançois Tigeot 	/*
582*8621f407SFrançois Tigeot 	 * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
583*8621f407SFrançois Tigeot 	 * freq2k.
584*8621f407SFrançois Tigeot 	 *
585*8621f407SFrançois Tigeot 	 * delta = 1e6 *
586*8621f407SFrançois Tigeot 	 *	   abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
587*8621f407SFrançois Tigeot 	 *	   freq2k;
588*8621f407SFrançois Tigeot 	 *
589*8621f407SFrançois Tigeot 	 * and we would like delta <= budget.
590*8621f407SFrançois Tigeot 	 *
591*8621f407SFrançois Tigeot 	 * If the discrepancy is above the PPM-based budget, always prefer to
592*8621f407SFrançois Tigeot 	 * improve upon the previous solution.  However, if you're within the
593*8621f407SFrançois Tigeot 	 * budget, try to maximize Ref * VCO, that is N / (P * R^2).
594*8621f407SFrançois Tigeot 	 */
595*8621f407SFrançois Tigeot 	a = freq2k * budget * p * r2;
596*8621f407SFrançois Tigeot 	b = freq2k * budget * best->p * best->r2;
597*8621f407SFrançois Tigeot 	diff = abs_diff((u64)freq2k * p * r2, LC_FREQ_2K * n2);
598*8621f407SFrançois Tigeot 	diff_best = abs_diff((u64)freq2k * best->p * best->r2,
599*8621f407SFrançois Tigeot 			     LC_FREQ_2K * best->n2);
600*8621f407SFrançois Tigeot 	c = 1000000 * diff;
601*8621f407SFrançois Tigeot 	d = 1000000 * diff_best;
602*8621f407SFrançois Tigeot 
603*8621f407SFrançois Tigeot 	if (a < c && b < d) {
604*8621f407SFrançois Tigeot 		/* If both are above the budget, pick the closer */
605*8621f407SFrançois Tigeot 		if (best->p * best->r2 * diff < p * r2 * diff_best) {
606*8621f407SFrançois Tigeot 			best->p = p;
607*8621f407SFrançois Tigeot 			best->n2 = n2;
608*8621f407SFrançois Tigeot 			best->r2 = r2;
609*8621f407SFrançois Tigeot 		}
610*8621f407SFrançois Tigeot 	} else if (a >= c && b < d) {
611*8621f407SFrançois Tigeot 		/* If A is below the threshold but B is above it?  Update. */
612*8621f407SFrançois Tigeot 		best->p = p;
613*8621f407SFrançois Tigeot 		best->n2 = n2;
614*8621f407SFrançois Tigeot 		best->r2 = r2;
615*8621f407SFrançois Tigeot 	} else if (a >= c && b >= d) {
616*8621f407SFrançois Tigeot 		/* Both are below the limit, so pick the higher n2/(r2*r2) */
617*8621f407SFrançois Tigeot 		if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) {
618*8621f407SFrançois Tigeot 			best->p = p;
619*8621f407SFrançois Tigeot 			best->n2 = n2;
620*8621f407SFrançois Tigeot 			best->r2 = r2;
621*8621f407SFrançois Tigeot 		}
622*8621f407SFrançois Tigeot 	}
623*8621f407SFrançois Tigeot 	/* Otherwise a < c && b >= d, do nothing */
624*8621f407SFrançois Tigeot }
625*8621f407SFrançois Tigeot 
626*8621f407SFrançois Tigeot static void
627*8621f407SFrançois Tigeot hsw_ddi_calculate_wrpll(int clock /* in Hz */,
628*8621f407SFrançois Tigeot 			unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
629*8621f407SFrançois Tigeot {
630*8621f407SFrançois Tigeot 	uint64_t freq2k;
631*8621f407SFrançois Tigeot 	unsigned p, n2, r2;
632*8621f407SFrançois Tigeot 	struct hsw_wrpll_rnp best = { 0, 0, 0 };
633*8621f407SFrançois Tigeot 	unsigned budget;
634*8621f407SFrançois Tigeot 
635*8621f407SFrançois Tigeot 	freq2k = clock / 100;
636*8621f407SFrançois Tigeot 
637*8621f407SFrançois Tigeot 	budget = hsw_wrpll_get_budget_for_freq(clock);
638*8621f407SFrançois Tigeot 
639*8621f407SFrançois Tigeot 	/* Special case handling for 540 pixel clock: bypass WR PLL entirely
640*8621f407SFrançois Tigeot 	 * and directly pass the LC PLL to it. */
641*8621f407SFrançois Tigeot 	if (freq2k == 5400000) {
642*8621f407SFrançois Tigeot 		*n2_out = 2;
643*8621f407SFrançois Tigeot 		*p_out = 1;
644*8621f407SFrançois Tigeot 		*r2_out = 2;
645*8621f407SFrançois Tigeot 		return;
646*8621f407SFrançois Tigeot 	}
647*8621f407SFrançois Tigeot 
648*8621f407SFrançois Tigeot 	/*
649*8621f407SFrançois Tigeot 	 * Ref = LC_FREQ / R, where Ref is the actual reference input seen by
650*8621f407SFrançois Tigeot 	 * the WR PLL.
651*8621f407SFrançois Tigeot 	 *
652*8621f407SFrançois Tigeot 	 * We want R so that REF_MIN <= Ref <= REF_MAX.
653*8621f407SFrançois Tigeot 	 * Injecting R2 = 2 * R gives:
654*8621f407SFrançois Tigeot 	 *   REF_MAX * r2 > LC_FREQ * 2 and
655*8621f407SFrançois Tigeot 	 *   REF_MIN * r2 < LC_FREQ * 2
656*8621f407SFrançois Tigeot 	 *
657*8621f407SFrançois Tigeot 	 * Which means the desired boundaries for r2 are:
658*8621f407SFrançois Tigeot 	 *  LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
659*8621f407SFrançois Tigeot 	 *
660*8621f407SFrançois Tigeot 	 */
661*8621f407SFrançois Tigeot 	for (r2 = LC_FREQ * 2 / REF_MAX + 1;
662*8621f407SFrançois Tigeot 	     r2 <= LC_FREQ * 2 / REF_MIN;
663*8621f407SFrançois Tigeot 	     r2++) {
664*8621f407SFrançois Tigeot 
665*8621f407SFrançois Tigeot 		/*
666*8621f407SFrançois Tigeot 		 * VCO = N * Ref, that is: VCO = N * LC_FREQ / R
667*8621f407SFrançois Tigeot 		 *
668*8621f407SFrançois Tigeot 		 * Once again we want VCO_MIN <= VCO <= VCO_MAX.
669*8621f407SFrançois Tigeot 		 * Injecting R2 = 2 * R and N2 = 2 * N, we get:
670*8621f407SFrançois Tigeot 		 *   VCO_MAX * r2 > n2 * LC_FREQ and
671*8621f407SFrançois Tigeot 		 *   VCO_MIN * r2 < n2 * LC_FREQ)
672*8621f407SFrançois Tigeot 		 *
673*8621f407SFrançois Tigeot 		 * Which means the desired boundaries for n2 are:
674*8621f407SFrançois Tigeot 		 * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
675*8621f407SFrançois Tigeot 		 */
676*8621f407SFrançois Tigeot 		for (n2 = VCO_MIN * r2 / LC_FREQ + 1;
677*8621f407SFrançois Tigeot 		     n2 <= VCO_MAX * r2 / LC_FREQ;
678*8621f407SFrançois Tigeot 		     n2++) {
679*8621f407SFrançois Tigeot 
680*8621f407SFrançois Tigeot 			for (p = P_MIN; p <= P_MAX; p += P_INC)
681*8621f407SFrançois Tigeot 				hsw_wrpll_update_rnp(freq2k, budget,
682*8621f407SFrançois Tigeot 						     r2, n2, p, &best);
683*8621f407SFrançois Tigeot 		}
684*8621f407SFrançois Tigeot 	}
685*8621f407SFrançois Tigeot 
686*8621f407SFrançois Tigeot 	*n2_out = best.n2;
687*8621f407SFrançois Tigeot 	*p_out = best.p;
688*8621f407SFrançois Tigeot 	*r2_out = best.r2;
689*8621f407SFrançois Tigeot }
690*8621f407SFrançois Tigeot 
691*8621f407SFrançois Tigeot static struct intel_shared_dpll *
692*8621f407SFrançois Tigeot hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
693*8621f407SFrançois Tigeot 	     struct intel_encoder *encoder)
694*8621f407SFrançois Tigeot {
695*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
696*8621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
697*8621f407SFrançois Tigeot 	int clock = crtc_state->port_clock;
698*8621f407SFrançois Tigeot 
699*8621f407SFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
700*8621f407SFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
701*8621f407SFrançois Tigeot 
702*8621f407SFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI) {
703*8621f407SFrançois Tigeot 		uint32_t val;
704*8621f407SFrançois Tigeot 		unsigned p, n2, r2;
705*8621f407SFrançois Tigeot 
706*8621f407SFrançois Tigeot 		hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
707*8621f407SFrançois Tigeot 
708*8621f407SFrançois Tigeot 		val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
709*8621f407SFrançois Tigeot 		      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
710*8621f407SFrançois Tigeot 		      WRPLL_DIVIDER_POST(p);
711*8621f407SFrançois Tigeot 
712*8621f407SFrançois Tigeot 		crtc_state->dpll_hw_state.wrpll = val;
713*8621f407SFrançois Tigeot 
714*8621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
715*8621f407SFrançois Tigeot 					     DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
716*8621f407SFrançois Tigeot 
717*8621f407SFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
718*8621f407SFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_DP_MST ||
719*8621f407SFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_EDP) {
720*8621f407SFrançois Tigeot 		enum intel_dpll_id pll_id;
721*8621f407SFrançois Tigeot 
722*8621f407SFrançois Tigeot 		switch (clock / 2) {
723*8621f407SFrançois Tigeot 		case 81000:
724*8621f407SFrançois Tigeot 			pll_id = DPLL_ID_LCPLL_810;
725*8621f407SFrançois Tigeot 			break;
726*8621f407SFrançois Tigeot 		case 135000:
727*8621f407SFrançois Tigeot 			pll_id = DPLL_ID_LCPLL_1350;
728*8621f407SFrançois Tigeot 			break;
729*8621f407SFrançois Tigeot 		case 270000:
730*8621f407SFrançois Tigeot 			pll_id = DPLL_ID_LCPLL_2700;
731*8621f407SFrançois Tigeot 			break;
732*8621f407SFrançois Tigeot 		default:
733*8621f407SFrançois Tigeot 			DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
734*8621f407SFrançois Tigeot 			return NULL;
735*8621f407SFrançois Tigeot 		}
736*8621f407SFrançois Tigeot 
737*8621f407SFrançois Tigeot 		pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
738*8621f407SFrançois Tigeot 
739*8621f407SFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_ANALOG) {
740*8621f407SFrançois Tigeot 		if (WARN_ON(crtc_state->port_clock / 2 != 135000))
741*8621f407SFrançois Tigeot 			return NULL;
742*8621f407SFrançois Tigeot 
743*8621f407SFrançois Tigeot 		crtc_state->dpll_hw_state.spll =
744*8621f407SFrançois Tigeot 			SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
745*8621f407SFrançois Tigeot 
746*8621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
747*8621f407SFrançois Tigeot 					     DPLL_ID_SPLL, DPLL_ID_SPLL);
748*8621f407SFrançois Tigeot 	} else {
749*8621f407SFrançois Tigeot 		return NULL;
750*8621f407SFrançois Tigeot 	}
751*8621f407SFrançois Tigeot 
752*8621f407SFrançois Tigeot 	if (!pll)
753*8621f407SFrançois Tigeot 		return NULL;
754*8621f407SFrançois Tigeot 
755*8621f407SFrançois Tigeot 	crtc_state->ddi_pll_sel = hsw_pll_to_ddi_pll_sel(pll);
756*8621f407SFrançois Tigeot 
757*8621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
758*8621f407SFrançois Tigeot 
759*8621f407SFrançois Tigeot 	return pll;
760*8621f407SFrançois Tigeot }
761*8621f407SFrançois Tigeot 
762*8621f407SFrançois Tigeot 
763*8621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
764*8621f407SFrançois Tigeot 	.enable = hsw_ddi_wrpll_enable,
765*8621f407SFrançois Tigeot 	.disable = hsw_ddi_wrpll_disable,
766*8621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_wrpll_get_hw_state,
767*8621f407SFrançois Tigeot };
768*8621f407SFrançois Tigeot 
769*8621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_spll_funcs = {
770*8621f407SFrançois Tigeot 	.enable = hsw_ddi_spll_enable,
771*8621f407SFrançois Tigeot 	.disable = hsw_ddi_spll_disable,
772*8621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_spll_get_hw_state,
773*8621f407SFrançois Tigeot };
774*8621f407SFrançois Tigeot 
775*8621f407SFrançois Tigeot static void hsw_ddi_lcpll_enable(struct drm_i915_private *dev_priv,
776*8621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
777*8621f407SFrançois Tigeot {
778*8621f407SFrançois Tigeot }
779*8621f407SFrançois Tigeot 
780*8621f407SFrançois Tigeot static void hsw_ddi_lcpll_disable(struct drm_i915_private *dev_priv,
781*8621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
782*8621f407SFrançois Tigeot {
783*8621f407SFrançois Tigeot }
784*8621f407SFrançois Tigeot 
785*8621f407SFrançois Tigeot static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,
786*8621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
787*8621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
788*8621f407SFrançois Tigeot {
789*8621f407SFrançois Tigeot 	return true;
790*8621f407SFrançois Tigeot }
791*8621f407SFrançois Tigeot 
792*8621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = {
793*8621f407SFrançois Tigeot 	.enable = hsw_ddi_lcpll_enable,
794*8621f407SFrançois Tigeot 	.disable = hsw_ddi_lcpll_disable,
795*8621f407SFrançois Tigeot 	.get_hw_state = hsw_ddi_lcpll_get_hw_state,
796*8621f407SFrançois Tigeot };
797*8621f407SFrançois Tigeot 
798*8621f407SFrançois Tigeot struct skl_dpll_regs {
799*8621f407SFrançois Tigeot 	i915_reg_t ctl, cfgcr1, cfgcr2;
800*8621f407SFrançois Tigeot };
801*8621f407SFrançois Tigeot 
802*8621f407SFrançois Tigeot /* this array is indexed by the *shared* pll id */
803*8621f407SFrançois Tigeot static const struct skl_dpll_regs skl_dpll_regs[4] = {
804*8621f407SFrançois Tigeot 	{
805*8621f407SFrançois Tigeot 		/* DPLL 0 */
806*8621f407SFrançois Tigeot 		.ctl = LCPLL1_CTL,
807*8621f407SFrançois Tigeot 		/* DPLL 0 doesn't support HDMI mode */
808*8621f407SFrançois Tigeot 	},
809*8621f407SFrançois Tigeot 	{
810*8621f407SFrançois Tigeot 		/* DPLL 1 */
811*8621f407SFrançois Tigeot 		.ctl = LCPLL2_CTL,
812*8621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
813*8621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
814*8621f407SFrançois Tigeot 	},
815*8621f407SFrançois Tigeot 	{
816*8621f407SFrançois Tigeot 		/* DPLL 2 */
817*8621f407SFrançois Tigeot 		.ctl = WRPLL_CTL(0),
818*8621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
819*8621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
820*8621f407SFrançois Tigeot 	},
821*8621f407SFrançois Tigeot 	{
822*8621f407SFrançois Tigeot 		/* DPLL 3 */
823*8621f407SFrançois Tigeot 		.ctl = WRPLL_CTL(1),
824*8621f407SFrançois Tigeot 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
825*8621f407SFrançois Tigeot 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
826*8621f407SFrançois Tigeot 	},
827*8621f407SFrançois Tigeot };
828*8621f407SFrançois Tigeot 
829*8621f407SFrançois Tigeot static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *dev_priv,
830*8621f407SFrançois Tigeot 				    struct intel_shared_dpll *pll)
831*8621f407SFrançois Tigeot {
832*8621f407SFrançois Tigeot 	uint32_t val;
833*8621f407SFrançois Tigeot 
834*8621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
835*8621f407SFrançois Tigeot 
836*8621f407SFrançois Tigeot 	val &= ~(DPLL_CTRL1_HDMI_MODE(pll->id) | DPLL_CTRL1_SSC(pll->id) |
837*8621f407SFrançois Tigeot 		 DPLL_CTRL1_LINK_RATE_MASK(pll->id));
838*8621f407SFrançois Tigeot 	val |= pll->config.hw_state.ctrl1 << (pll->id * 6);
839*8621f407SFrançois Tigeot 
840*8621f407SFrançois Tigeot 	I915_WRITE(DPLL_CTRL1, val);
841*8621f407SFrançois Tigeot 	POSTING_READ(DPLL_CTRL1);
842*8621f407SFrançois Tigeot }
843*8621f407SFrançois Tigeot 
844*8621f407SFrançois Tigeot static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
845*8621f407SFrançois Tigeot 			       struct intel_shared_dpll *pll)
846*8621f407SFrançois Tigeot {
847*8621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
848*8621f407SFrançois Tigeot 
849*8621f407SFrançois Tigeot 	skl_ddi_pll_write_ctrl1(dev_priv, pll);
850*8621f407SFrançois Tigeot 
851*8621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].cfgcr1, pll->config.hw_state.cfgcr1);
852*8621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].cfgcr2, pll->config.hw_state.cfgcr2);
853*8621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].cfgcr1);
854*8621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].cfgcr2);
855*8621f407SFrançois Tigeot 
856*8621f407SFrançois Tigeot 	/* the enable bit is always bit 31 */
857*8621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].ctl,
858*8621f407SFrançois Tigeot 		   I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE);
859*8621f407SFrançois Tigeot 
860*8621f407SFrançois Tigeot 	if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(pll->id), 5))
861*8621f407SFrançois Tigeot 		DRM_ERROR("DPLL %d not locked\n", pll->id);
862*8621f407SFrançois Tigeot }
863*8621f407SFrançois Tigeot 
864*8621f407SFrançois Tigeot static void skl_ddi_dpll0_enable(struct drm_i915_private *dev_priv,
865*8621f407SFrançois Tigeot 				 struct intel_shared_dpll *pll)
866*8621f407SFrançois Tigeot {
867*8621f407SFrançois Tigeot 	skl_ddi_pll_write_ctrl1(dev_priv, pll);
868*8621f407SFrançois Tigeot }
869*8621f407SFrançois Tigeot 
870*8621f407SFrançois Tigeot static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
871*8621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
872*8621f407SFrançois Tigeot {
873*8621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
874*8621f407SFrançois Tigeot 
875*8621f407SFrançois Tigeot 	/* the enable bit is always bit 31 */
876*8621f407SFrançois Tigeot 	I915_WRITE(regs[pll->id].ctl,
877*8621f407SFrançois Tigeot 		   I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE);
878*8621f407SFrançois Tigeot 	POSTING_READ(regs[pll->id].ctl);
879*8621f407SFrançois Tigeot }
880*8621f407SFrançois Tigeot 
881*8621f407SFrançois Tigeot static void skl_ddi_dpll0_disable(struct drm_i915_private *dev_priv,
882*8621f407SFrançois Tigeot 				  struct intel_shared_dpll *pll)
883*8621f407SFrançois Tigeot {
884*8621f407SFrançois Tigeot }
885*8621f407SFrançois Tigeot 
886*8621f407SFrançois Tigeot static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
887*8621f407SFrançois Tigeot 				     struct intel_shared_dpll *pll,
888*8621f407SFrançois Tigeot 				     struct intel_dpll_hw_state *hw_state)
889*8621f407SFrançois Tigeot {
890*8621f407SFrançois Tigeot 	uint32_t val;
891*8621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
892*8621f407SFrançois Tigeot 	bool ret;
893*8621f407SFrançois Tigeot 
894*8621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
895*8621f407SFrançois Tigeot 		return false;
896*8621f407SFrançois Tigeot 
897*8621f407SFrançois Tigeot 	ret = false;
898*8621f407SFrançois Tigeot 
899*8621f407SFrançois Tigeot 	val = I915_READ(regs[pll->id].ctl);
900*8621f407SFrançois Tigeot 	if (!(val & LCPLL_PLL_ENABLE))
901*8621f407SFrançois Tigeot 		goto out;
902*8621f407SFrançois Tigeot 
903*8621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
904*8621f407SFrançois Tigeot 	hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
905*8621f407SFrançois Tigeot 
906*8621f407SFrançois Tigeot 	/* avoid reading back stale values if HDMI mode is not enabled */
907*8621f407SFrançois Tigeot 	if (val & DPLL_CTRL1_HDMI_MODE(pll->id)) {
908*8621f407SFrançois Tigeot 		hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
909*8621f407SFrançois Tigeot 		hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
910*8621f407SFrançois Tigeot 	}
911*8621f407SFrançois Tigeot 	ret = true;
912*8621f407SFrançois Tigeot 
913*8621f407SFrançois Tigeot out:
914*8621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
915*8621f407SFrançois Tigeot 
916*8621f407SFrançois Tigeot 	return ret;
917*8621f407SFrançois Tigeot }
918*8621f407SFrançois Tigeot 
919*8621f407SFrançois Tigeot static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
920*8621f407SFrançois Tigeot 				       struct intel_shared_dpll *pll,
921*8621f407SFrançois Tigeot 				       struct intel_dpll_hw_state *hw_state)
922*8621f407SFrançois Tigeot {
923*8621f407SFrançois Tigeot 	uint32_t val;
924*8621f407SFrançois Tigeot 	const struct skl_dpll_regs *regs = skl_dpll_regs;
925*8621f407SFrançois Tigeot 	bool ret;
926*8621f407SFrançois Tigeot 
927*8621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
928*8621f407SFrançois Tigeot 		return false;
929*8621f407SFrançois Tigeot 
930*8621f407SFrançois Tigeot 	ret = false;
931*8621f407SFrançois Tigeot 
932*8621f407SFrançois Tigeot 	/* DPLL0 is always enabled since it drives CDCLK */
933*8621f407SFrançois Tigeot 	val = I915_READ(regs[pll->id].ctl);
934*8621f407SFrançois Tigeot 	if (WARN_ON(!(val & LCPLL_PLL_ENABLE)))
935*8621f407SFrançois Tigeot 		goto out;
936*8621f407SFrançois Tigeot 
937*8621f407SFrançois Tigeot 	val = I915_READ(DPLL_CTRL1);
938*8621f407SFrançois Tigeot 	hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
939*8621f407SFrançois Tigeot 
940*8621f407SFrançois Tigeot 	ret = true;
941*8621f407SFrançois Tigeot 
942*8621f407SFrançois Tigeot out:
943*8621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
944*8621f407SFrançois Tigeot 
945*8621f407SFrançois Tigeot 	return ret;
946*8621f407SFrançois Tigeot }
947*8621f407SFrançois Tigeot 
948*8621f407SFrançois Tigeot struct skl_wrpll_context {
949*8621f407SFrançois Tigeot 	uint64_t min_deviation;		/* current minimal deviation */
950*8621f407SFrançois Tigeot 	uint64_t central_freq;		/* chosen central freq */
951*8621f407SFrançois Tigeot 	uint64_t dco_freq;		/* chosen dco freq */
952*8621f407SFrançois Tigeot 	unsigned int p;			/* chosen divider */
953*8621f407SFrançois Tigeot };
954*8621f407SFrançois Tigeot 
955*8621f407SFrançois Tigeot static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
956*8621f407SFrançois Tigeot {
957*8621f407SFrançois Tigeot 	memset(ctx, 0, sizeof(*ctx));
958*8621f407SFrançois Tigeot 
959*8621f407SFrançois Tigeot 	ctx->min_deviation = U64_MAX;
960*8621f407SFrançois Tigeot }
961*8621f407SFrançois Tigeot 
962*8621f407SFrançois Tigeot /* DCO freq must be within +1%/-6%  of the DCO central freq */
963*8621f407SFrançois Tigeot #define SKL_DCO_MAX_PDEVIATION	100
964*8621f407SFrançois Tigeot #define SKL_DCO_MAX_NDEVIATION	600
965*8621f407SFrançois Tigeot 
966*8621f407SFrançois Tigeot static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
967*8621f407SFrançois Tigeot 				  uint64_t central_freq,
968*8621f407SFrançois Tigeot 				  uint64_t dco_freq,
969*8621f407SFrançois Tigeot 				  unsigned int divider)
970*8621f407SFrançois Tigeot {
971*8621f407SFrançois Tigeot 	uint64_t deviation;
972*8621f407SFrançois Tigeot 
973*8621f407SFrançois Tigeot 	deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
974*8621f407SFrançois Tigeot 			      central_freq);
975*8621f407SFrançois Tigeot 
976*8621f407SFrançois Tigeot 	/* positive deviation */
977*8621f407SFrançois Tigeot 	if (dco_freq >= central_freq) {
978*8621f407SFrançois Tigeot 		if (deviation < SKL_DCO_MAX_PDEVIATION &&
979*8621f407SFrançois Tigeot 		    deviation < ctx->min_deviation) {
980*8621f407SFrançois Tigeot 			ctx->min_deviation = deviation;
981*8621f407SFrançois Tigeot 			ctx->central_freq = central_freq;
982*8621f407SFrançois Tigeot 			ctx->dco_freq = dco_freq;
983*8621f407SFrançois Tigeot 			ctx->p = divider;
984*8621f407SFrançois Tigeot 		}
985*8621f407SFrançois Tigeot 	/* negative deviation */
986*8621f407SFrançois Tigeot 	} else if (deviation < SKL_DCO_MAX_NDEVIATION &&
987*8621f407SFrançois Tigeot 		   deviation < ctx->min_deviation) {
988*8621f407SFrançois Tigeot 		ctx->min_deviation = deviation;
989*8621f407SFrançois Tigeot 		ctx->central_freq = central_freq;
990*8621f407SFrançois Tigeot 		ctx->dco_freq = dco_freq;
991*8621f407SFrançois Tigeot 		ctx->p = divider;
992*8621f407SFrançois Tigeot 	}
993*8621f407SFrançois Tigeot }
994*8621f407SFrançois Tigeot 
995*8621f407SFrançois Tigeot static void skl_wrpll_get_multipliers(unsigned int p,
996*8621f407SFrançois Tigeot 				      unsigned int *p0 /* out */,
997*8621f407SFrançois Tigeot 				      unsigned int *p1 /* out */,
998*8621f407SFrançois Tigeot 				      unsigned int *p2 /* out */)
999*8621f407SFrançois Tigeot {
1000*8621f407SFrançois Tigeot 	/* even dividers */
1001*8621f407SFrançois Tigeot 	if (p % 2 == 0) {
1002*8621f407SFrançois Tigeot 		unsigned int half = p / 2;
1003*8621f407SFrançois Tigeot 
1004*8621f407SFrançois Tigeot 		if (half == 1 || half == 2 || half == 3 || half == 5) {
1005*8621f407SFrançois Tigeot 			*p0 = 2;
1006*8621f407SFrançois Tigeot 			*p1 = 1;
1007*8621f407SFrançois Tigeot 			*p2 = half;
1008*8621f407SFrançois Tigeot 		} else if (half % 2 == 0) {
1009*8621f407SFrançois Tigeot 			*p0 = 2;
1010*8621f407SFrançois Tigeot 			*p1 = half / 2;
1011*8621f407SFrançois Tigeot 			*p2 = 2;
1012*8621f407SFrançois Tigeot 		} else if (half % 3 == 0) {
1013*8621f407SFrançois Tigeot 			*p0 = 3;
1014*8621f407SFrançois Tigeot 			*p1 = half / 3;
1015*8621f407SFrançois Tigeot 			*p2 = 2;
1016*8621f407SFrançois Tigeot 		} else if (half % 7 == 0) {
1017*8621f407SFrançois Tigeot 			*p0 = 7;
1018*8621f407SFrançois Tigeot 			*p1 = half / 7;
1019*8621f407SFrançois Tigeot 			*p2 = 2;
1020*8621f407SFrançois Tigeot 		}
1021*8621f407SFrançois Tigeot 	} else if (p == 3 || p == 9) {  /* 3, 5, 7, 9, 15, 21, 35 */
1022*8621f407SFrançois Tigeot 		*p0 = 3;
1023*8621f407SFrançois Tigeot 		*p1 = 1;
1024*8621f407SFrançois Tigeot 		*p2 = p / 3;
1025*8621f407SFrançois Tigeot 	} else if (p == 5 || p == 7) {
1026*8621f407SFrançois Tigeot 		*p0 = p;
1027*8621f407SFrançois Tigeot 		*p1 = 1;
1028*8621f407SFrançois Tigeot 		*p2 = 1;
1029*8621f407SFrançois Tigeot 	} else if (p == 15) {
1030*8621f407SFrançois Tigeot 		*p0 = 3;
1031*8621f407SFrançois Tigeot 		*p1 = 1;
1032*8621f407SFrançois Tigeot 		*p2 = 5;
1033*8621f407SFrançois Tigeot 	} else if (p == 21) {
1034*8621f407SFrançois Tigeot 		*p0 = 7;
1035*8621f407SFrançois Tigeot 		*p1 = 1;
1036*8621f407SFrançois Tigeot 		*p2 = 3;
1037*8621f407SFrançois Tigeot 	} else if (p == 35) {
1038*8621f407SFrançois Tigeot 		*p0 = 7;
1039*8621f407SFrançois Tigeot 		*p1 = 1;
1040*8621f407SFrançois Tigeot 		*p2 = 5;
1041*8621f407SFrançois Tigeot 	}
1042*8621f407SFrançois Tigeot }
1043*8621f407SFrançois Tigeot 
1044*8621f407SFrançois Tigeot struct skl_wrpll_params {
1045*8621f407SFrançois Tigeot 	uint32_t        dco_fraction;
1046*8621f407SFrançois Tigeot 	uint32_t        dco_integer;
1047*8621f407SFrançois Tigeot 	uint32_t        qdiv_ratio;
1048*8621f407SFrançois Tigeot 	uint32_t        qdiv_mode;
1049*8621f407SFrançois Tigeot 	uint32_t        kdiv;
1050*8621f407SFrançois Tigeot 	uint32_t        pdiv;
1051*8621f407SFrançois Tigeot 	uint32_t        central_freq;
1052*8621f407SFrançois Tigeot };
1053*8621f407SFrançois Tigeot 
1054*8621f407SFrançois Tigeot static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
1055*8621f407SFrançois Tigeot 				      uint64_t afe_clock,
1056*8621f407SFrançois Tigeot 				      uint64_t central_freq,
1057*8621f407SFrançois Tigeot 				      uint32_t p0, uint32_t p1, uint32_t p2)
1058*8621f407SFrançois Tigeot {
1059*8621f407SFrançois Tigeot 	uint64_t dco_freq;
1060*8621f407SFrançois Tigeot 
1061*8621f407SFrançois Tigeot 	switch (central_freq) {
1062*8621f407SFrançois Tigeot 	case 9600000000ULL:
1063*8621f407SFrançois Tigeot 		params->central_freq = 0;
1064*8621f407SFrançois Tigeot 		break;
1065*8621f407SFrançois Tigeot 	case 9000000000ULL:
1066*8621f407SFrançois Tigeot 		params->central_freq = 1;
1067*8621f407SFrançois Tigeot 		break;
1068*8621f407SFrançois Tigeot 	case 8400000000ULL:
1069*8621f407SFrançois Tigeot 		params->central_freq = 3;
1070*8621f407SFrançois Tigeot 	}
1071*8621f407SFrançois Tigeot 
1072*8621f407SFrançois Tigeot 	switch (p0) {
1073*8621f407SFrançois Tigeot 	case 1:
1074*8621f407SFrançois Tigeot 		params->pdiv = 0;
1075*8621f407SFrançois Tigeot 		break;
1076*8621f407SFrançois Tigeot 	case 2:
1077*8621f407SFrançois Tigeot 		params->pdiv = 1;
1078*8621f407SFrançois Tigeot 		break;
1079*8621f407SFrançois Tigeot 	case 3:
1080*8621f407SFrançois Tigeot 		params->pdiv = 2;
1081*8621f407SFrançois Tigeot 		break;
1082*8621f407SFrançois Tigeot 	case 7:
1083*8621f407SFrançois Tigeot 		params->pdiv = 4;
1084*8621f407SFrançois Tigeot 		break;
1085*8621f407SFrançois Tigeot 	default:
1086*8621f407SFrançois Tigeot 		WARN(1, "Incorrect PDiv\n");
1087*8621f407SFrançois Tigeot 	}
1088*8621f407SFrançois Tigeot 
1089*8621f407SFrançois Tigeot 	switch (p2) {
1090*8621f407SFrançois Tigeot 	case 5:
1091*8621f407SFrançois Tigeot 		params->kdiv = 0;
1092*8621f407SFrançois Tigeot 		break;
1093*8621f407SFrançois Tigeot 	case 2:
1094*8621f407SFrançois Tigeot 		params->kdiv = 1;
1095*8621f407SFrançois Tigeot 		break;
1096*8621f407SFrançois Tigeot 	case 3:
1097*8621f407SFrançois Tigeot 		params->kdiv = 2;
1098*8621f407SFrançois Tigeot 		break;
1099*8621f407SFrançois Tigeot 	case 1:
1100*8621f407SFrançois Tigeot 		params->kdiv = 3;
1101*8621f407SFrançois Tigeot 		break;
1102*8621f407SFrançois Tigeot 	default:
1103*8621f407SFrançois Tigeot 		WARN(1, "Incorrect KDiv\n");
1104*8621f407SFrançois Tigeot 	}
1105*8621f407SFrançois Tigeot 
1106*8621f407SFrançois Tigeot 	params->qdiv_ratio = p1;
1107*8621f407SFrançois Tigeot 	params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
1108*8621f407SFrançois Tigeot 
1109*8621f407SFrançois Tigeot 	dco_freq = p0 * p1 * p2 * afe_clock;
1110*8621f407SFrançois Tigeot 
1111*8621f407SFrançois Tigeot 	/*
1112*8621f407SFrançois Tigeot 	 * Intermediate values are in Hz.
1113*8621f407SFrançois Tigeot 	 * Divide by MHz to match bsepc
1114*8621f407SFrançois Tigeot 	 */
1115*8621f407SFrançois Tigeot 	params->dco_integer = div_u64(dco_freq, 24 * MHz(1));
1116*8621f407SFrançois Tigeot 	params->dco_fraction =
1117*8621f407SFrançois Tigeot 		div_u64((div_u64(dco_freq, 24) -
1118*8621f407SFrançois Tigeot 			 params->dco_integer * MHz(1)) * 0x8000, MHz(1));
1119*8621f407SFrançois Tigeot }
1120*8621f407SFrançois Tigeot 
1121*8621f407SFrançois Tigeot static bool
1122*8621f407SFrançois Tigeot skl_ddi_calculate_wrpll(int clock /* in Hz */,
1123*8621f407SFrançois Tigeot 			struct skl_wrpll_params *wrpll_params)
1124*8621f407SFrançois Tigeot {
1125*8621f407SFrançois Tigeot 	uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
1126*8621f407SFrançois Tigeot 	uint64_t dco_central_freq[3] = {8400000000ULL,
1127*8621f407SFrançois Tigeot 					9000000000ULL,
1128*8621f407SFrançois Tigeot 					9600000000ULL};
1129*8621f407SFrançois Tigeot 	static const int even_dividers[] = {  4,  6,  8, 10, 12, 14, 16, 18, 20,
1130*8621f407SFrançois Tigeot 					     24, 28, 30, 32, 36, 40, 42, 44,
1131*8621f407SFrançois Tigeot 					     48, 52, 54, 56, 60, 64, 66, 68,
1132*8621f407SFrançois Tigeot 					     70, 72, 76, 78, 80, 84, 88, 90,
1133*8621f407SFrançois Tigeot 					     92, 96, 98 };
1134*8621f407SFrançois Tigeot 	static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
1135*8621f407SFrançois Tigeot 	static const struct {
1136*8621f407SFrançois Tigeot 		const int *list;
1137*8621f407SFrançois Tigeot 		int n_dividers;
1138*8621f407SFrançois Tigeot 	} dividers[] = {
1139*8621f407SFrançois Tigeot 		{ even_dividers, ARRAY_SIZE(even_dividers) },
1140*8621f407SFrançois Tigeot 		{ odd_dividers, ARRAY_SIZE(odd_dividers) },
1141*8621f407SFrançois Tigeot 	};
1142*8621f407SFrançois Tigeot 	struct skl_wrpll_context ctx;
1143*8621f407SFrançois Tigeot 	unsigned int dco, d, i;
1144*8621f407SFrançois Tigeot 	unsigned int p0, p1, p2;
1145*8621f407SFrançois Tigeot 
1146*8621f407SFrançois Tigeot 	skl_wrpll_context_init(&ctx);
1147*8621f407SFrançois Tigeot 
1148*8621f407SFrançois Tigeot 	for (d = 0; d < ARRAY_SIZE(dividers); d++) {
1149*8621f407SFrançois Tigeot 		for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
1150*8621f407SFrançois Tigeot 			for (i = 0; i < dividers[d].n_dividers; i++) {
1151*8621f407SFrançois Tigeot 				unsigned int p = dividers[d].list[i];
1152*8621f407SFrançois Tigeot 				uint64_t dco_freq = p * afe_clock;
1153*8621f407SFrançois Tigeot 
1154*8621f407SFrançois Tigeot 				skl_wrpll_try_divider(&ctx,
1155*8621f407SFrançois Tigeot 						      dco_central_freq[dco],
1156*8621f407SFrançois Tigeot 						      dco_freq,
1157*8621f407SFrançois Tigeot 						      p);
1158*8621f407SFrançois Tigeot 				/*
1159*8621f407SFrançois Tigeot 				 * Skip the remaining dividers if we're sure to
1160*8621f407SFrançois Tigeot 				 * have found the definitive divider, we can't
1161*8621f407SFrançois Tigeot 				 * improve a 0 deviation.
1162*8621f407SFrançois Tigeot 				 */
1163*8621f407SFrançois Tigeot 				if (ctx.min_deviation == 0)
1164*8621f407SFrançois Tigeot 					goto skip_remaining_dividers;
1165*8621f407SFrançois Tigeot 			}
1166*8621f407SFrançois Tigeot 		}
1167*8621f407SFrançois Tigeot 
1168*8621f407SFrançois Tigeot skip_remaining_dividers:
1169*8621f407SFrançois Tigeot 		/*
1170*8621f407SFrançois Tigeot 		 * If a solution is found with an even divider, prefer
1171*8621f407SFrançois Tigeot 		 * this one.
1172*8621f407SFrançois Tigeot 		 */
1173*8621f407SFrançois Tigeot 		if (d == 0 && ctx.p)
1174*8621f407SFrançois Tigeot 			break;
1175*8621f407SFrançois Tigeot 	}
1176*8621f407SFrançois Tigeot 
1177*8621f407SFrançois Tigeot 	if (!ctx.p) {
1178*8621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
1179*8621f407SFrançois Tigeot 		return false;
1180*8621f407SFrançois Tigeot 	}
1181*8621f407SFrançois Tigeot 
1182*8621f407SFrançois Tigeot 	/*
1183*8621f407SFrançois Tigeot 	 * gcc incorrectly analyses that these can be used without being
1184*8621f407SFrançois Tigeot 	 * initialized. To be fair, it's hard to guess.
1185*8621f407SFrançois Tigeot 	 */
1186*8621f407SFrançois Tigeot 	p0 = p1 = p2 = 0;
1187*8621f407SFrançois Tigeot 	skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
1188*8621f407SFrançois Tigeot 	skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq,
1189*8621f407SFrançois Tigeot 				  p0, p1, p2);
1190*8621f407SFrançois Tigeot 
1191*8621f407SFrançois Tigeot 	return true;
1192*8621f407SFrançois Tigeot }
1193*8621f407SFrançois Tigeot 
1194*8621f407SFrançois Tigeot static struct intel_shared_dpll *
1195*8621f407SFrançois Tigeot skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
1196*8621f407SFrançois Tigeot 	     struct intel_encoder *encoder)
1197*8621f407SFrançois Tigeot {
1198*8621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
1199*8621f407SFrançois Tigeot 	uint32_t ctrl1, cfgcr1, cfgcr2;
1200*8621f407SFrançois Tigeot 	int clock = crtc_state->port_clock;
1201*8621f407SFrançois Tigeot 
1202*8621f407SFrançois Tigeot 	/*
1203*8621f407SFrançois Tigeot 	 * See comment in intel_dpll_hw_state to understand why we always use 0
1204*8621f407SFrançois Tigeot 	 * as the DPLL id in this function.
1205*8621f407SFrançois Tigeot 	 */
1206*8621f407SFrançois Tigeot 
1207*8621f407SFrançois Tigeot 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
1208*8621f407SFrançois Tigeot 
1209*8621f407SFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI) {
1210*8621f407SFrançois Tigeot 		struct skl_wrpll_params wrpll_params = { 0, };
1211*8621f407SFrançois Tigeot 
1212*8621f407SFrançois Tigeot 		ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
1213*8621f407SFrançois Tigeot 
1214*8621f407SFrançois Tigeot 		if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
1215*8621f407SFrançois Tigeot 			return NULL;
1216*8621f407SFrançois Tigeot 
1217*8621f407SFrançois Tigeot 		cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
1218*8621f407SFrançois Tigeot 			 DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
1219*8621f407SFrançois Tigeot 			 wrpll_params.dco_integer;
1220*8621f407SFrançois Tigeot 
1221*8621f407SFrançois Tigeot 		cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
1222*8621f407SFrançois Tigeot 			 DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
1223*8621f407SFrançois Tigeot 			 DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
1224*8621f407SFrançois Tigeot 			 DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
1225*8621f407SFrançois Tigeot 			 wrpll_params.central_freq;
1226*8621f407SFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
1227*8621f407SFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_DP_MST ||
1228*8621f407SFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_EDP) {
1229*8621f407SFrançois Tigeot 		switch (crtc_state->port_clock / 2) {
1230*8621f407SFrançois Tigeot 		case 81000:
1231*8621f407SFrançois Tigeot 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
1232*8621f407SFrançois Tigeot 			break;
1233*8621f407SFrançois Tigeot 		case 135000:
1234*8621f407SFrançois Tigeot 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
1235*8621f407SFrançois Tigeot 			break;
1236*8621f407SFrançois Tigeot 		case 270000:
1237*8621f407SFrançois Tigeot 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
1238*8621f407SFrançois Tigeot 			break;
1239*8621f407SFrançois Tigeot 		/* eDP 1.4 rates */
1240*8621f407SFrançois Tigeot 		case 162000:
1241*8621f407SFrançois Tigeot 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
1242*8621f407SFrançois Tigeot 			break;
1243*8621f407SFrançois Tigeot 		/* TBD: For DP link rates 2.16 GHz and 4.32 GHz, VCO is 8640 which
1244*8621f407SFrançois Tigeot 		results in CDCLK change. Need to handle the change of CDCLK by
1245*8621f407SFrançois Tigeot 		disabling pipes and re-enabling them */
1246*8621f407SFrançois Tigeot 		case 108000:
1247*8621f407SFrançois Tigeot 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
1248*8621f407SFrançois Tigeot 			break;
1249*8621f407SFrançois Tigeot 		case 216000:
1250*8621f407SFrançois Tigeot 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
1251*8621f407SFrançois Tigeot 			break;
1252*8621f407SFrançois Tigeot 		}
1253*8621f407SFrançois Tigeot 
1254*8621f407SFrançois Tigeot 		cfgcr1 = cfgcr2 = 0;
1255*8621f407SFrançois Tigeot 	} else {
1256*8621f407SFrançois Tigeot 		return NULL;
1257*8621f407SFrançois Tigeot 	}
1258*8621f407SFrançois Tigeot 
1259*8621f407SFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
1260*8621f407SFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
1261*8621f407SFrançois Tigeot 
1262*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.ctrl1 = ctrl1;
1263*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
1264*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
1265*8621f407SFrançois Tigeot 
1266*8621f407SFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_EDP)
1267*8621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
1268*8621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL0,
1269*8621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL0);
1270*8621f407SFrançois Tigeot 	else
1271*8621f407SFrançois Tigeot 		pll = intel_find_shared_dpll(crtc, crtc_state,
1272*8621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL1,
1273*8621f407SFrançois Tigeot 					     DPLL_ID_SKL_DPLL3);
1274*8621f407SFrançois Tigeot 	if (!pll)
1275*8621f407SFrançois Tigeot 		return NULL;
1276*8621f407SFrançois Tigeot 
1277*8621f407SFrançois Tigeot 	crtc_state->ddi_pll_sel = pll->id;
1278*8621f407SFrançois Tigeot 
1279*8621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
1280*8621f407SFrançois Tigeot 
1281*8621f407SFrançois Tigeot 	return pll;
1282*8621f407SFrançois Tigeot }
1283*8621f407SFrançois Tigeot 
1284*8621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs skl_ddi_pll_funcs = {
1285*8621f407SFrançois Tigeot 	.enable = skl_ddi_pll_enable,
1286*8621f407SFrançois Tigeot 	.disable = skl_ddi_pll_disable,
1287*8621f407SFrançois Tigeot 	.get_hw_state = skl_ddi_pll_get_hw_state,
1288*8621f407SFrançois Tigeot };
1289*8621f407SFrançois Tigeot 
1290*8621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = {
1291*8621f407SFrançois Tigeot 	.enable = skl_ddi_dpll0_enable,
1292*8621f407SFrançois Tigeot 	.disable = skl_ddi_dpll0_disable,
1293*8621f407SFrançois Tigeot 	.get_hw_state = skl_ddi_dpll0_get_hw_state,
1294*8621f407SFrançois Tigeot };
1295*8621f407SFrançois Tigeot 
1296*8621f407SFrançois Tigeot static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
1297*8621f407SFrançois Tigeot 				struct intel_shared_dpll *pll)
1298*8621f407SFrançois Tigeot {
1299*8621f407SFrançois Tigeot 	uint32_t temp;
1300*8621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
1301*8621f407SFrançois Tigeot 
1302*8621f407SFrançois Tigeot 	/* Non-SSC reference */
1303*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
1304*8621f407SFrançois Tigeot 	temp |= PORT_PLL_REF_SEL;
1305*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
1306*8621f407SFrançois Tigeot 
1307*8621f407SFrançois Tigeot 	/* Disable 10 bit clock */
1308*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
1309*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
1310*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
1311*8621f407SFrançois Tigeot 
1312*8621f407SFrançois Tigeot 	/* Write P1 & P2 */
1313*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_0(port));
1314*8621f407SFrançois Tigeot 	temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK);
1315*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.ebb0;
1316*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_0(port), temp);
1317*8621f407SFrançois Tigeot 
1318*8621f407SFrançois Tigeot 	/* Write M2 integer */
1319*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 0));
1320*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_MASK;
1321*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll0;
1322*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 0), temp);
1323*8621f407SFrançois Tigeot 
1324*8621f407SFrançois Tigeot 	/* Write N */
1325*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 1));
1326*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_N_MASK;
1327*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll1;
1328*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 1), temp);
1329*8621f407SFrançois Tigeot 
1330*8621f407SFrançois Tigeot 	/* Write M2 fraction */
1331*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 2));
1332*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_FRAC_MASK;
1333*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll2;
1334*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 2), temp);
1335*8621f407SFrançois Tigeot 
1336*8621f407SFrançois Tigeot 	/* Write M2 fraction enable */
1337*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 3));
1338*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_M2_FRAC_ENABLE;
1339*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll3;
1340*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 3), temp);
1341*8621f407SFrançois Tigeot 
1342*8621f407SFrançois Tigeot 	/* Write coeff */
1343*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 6));
1344*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_PROP_COEFF_MASK;
1345*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_INT_COEFF_MASK;
1346*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_GAIN_CTL_MASK;
1347*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll6;
1348*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 6), temp);
1349*8621f407SFrançois Tigeot 
1350*8621f407SFrançois Tigeot 	/* Write calibration val */
1351*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 8));
1352*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_TARGET_CNT_MASK;
1353*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll8;
1354*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 8), temp);
1355*8621f407SFrançois Tigeot 
1356*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 9));
1357*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK;
1358*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll9;
1359*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 9), temp);
1360*8621f407SFrançois Tigeot 
1361*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL(port, 10));
1362*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H;
1363*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_DCO_AMP_MASK;
1364*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pll10;
1365*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL(port, 10), temp);
1366*8621f407SFrançois Tigeot 
1367*8621f407SFrançois Tigeot 	/* Recalibrate with new settings */
1368*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
1369*8621f407SFrançois Tigeot 	temp |= PORT_PLL_RECALIBRATE;
1370*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
1371*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
1372*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.ebb4;
1373*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
1374*8621f407SFrançois Tigeot 
1375*8621f407SFrançois Tigeot 	/* Enable PLL */
1376*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
1377*8621f407SFrançois Tigeot 	temp |= PORT_PLL_ENABLE;
1378*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
1379*8621f407SFrançois Tigeot 	POSTING_READ(BXT_PORT_PLL_ENABLE(port));
1380*8621f407SFrançois Tigeot 
1381*8621f407SFrançois Tigeot 	if (wait_for_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_LOCK),
1382*8621f407SFrançois Tigeot 			200))
1383*8621f407SFrançois Tigeot 		DRM_ERROR("PLL %d not locked\n", port);
1384*8621f407SFrançois Tigeot 
1385*8621f407SFrançois Tigeot 	/*
1386*8621f407SFrançois Tigeot 	 * While we write to the group register to program all lanes at once we
1387*8621f407SFrançois Tigeot 	 * can read only lane registers and we pick lanes 0/1 for that.
1388*8621f407SFrançois Tigeot 	 */
1389*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
1390*8621f407SFrançois Tigeot 	temp &= ~LANE_STAGGER_MASK;
1391*8621f407SFrançois Tigeot 	temp &= ~LANESTAGGER_STRAP_OVRD;
1392*8621f407SFrançois Tigeot 	temp |= pll->config.hw_state.pcsdw12;
1393*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PCS_DW12_GRP(port), temp);
1394*8621f407SFrançois Tigeot }
1395*8621f407SFrançois Tigeot 
1396*8621f407SFrançois Tigeot static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
1397*8621f407SFrançois Tigeot 					struct intel_shared_dpll *pll)
1398*8621f407SFrançois Tigeot {
1399*8621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
1400*8621f407SFrançois Tigeot 	uint32_t temp;
1401*8621f407SFrançois Tigeot 
1402*8621f407SFrançois Tigeot 	temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
1403*8621f407SFrançois Tigeot 	temp &= ~PORT_PLL_ENABLE;
1404*8621f407SFrançois Tigeot 	I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
1405*8621f407SFrançois Tigeot 	POSTING_READ(BXT_PORT_PLL_ENABLE(port));
1406*8621f407SFrançois Tigeot }
1407*8621f407SFrançois Tigeot 
1408*8621f407SFrançois Tigeot static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
1409*8621f407SFrançois Tigeot 					struct intel_shared_dpll *pll,
1410*8621f407SFrançois Tigeot 					struct intel_dpll_hw_state *hw_state)
1411*8621f407SFrançois Tigeot {
1412*8621f407SFrançois Tigeot 	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
1413*8621f407SFrançois Tigeot 	uint32_t val;
1414*8621f407SFrançois Tigeot 	bool ret;
1415*8621f407SFrançois Tigeot 
1416*8621f407SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
1417*8621f407SFrançois Tigeot 		return false;
1418*8621f407SFrançois Tigeot 
1419*8621f407SFrançois Tigeot 	ret = false;
1420*8621f407SFrançois Tigeot 
1421*8621f407SFrançois Tigeot 	val = I915_READ(BXT_PORT_PLL_ENABLE(port));
1422*8621f407SFrançois Tigeot 	if (!(val & PORT_PLL_ENABLE))
1423*8621f407SFrançois Tigeot 		goto out;
1424*8621f407SFrançois Tigeot 
1425*8621f407SFrançois Tigeot 	hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
1426*8621f407SFrançois Tigeot 	hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
1427*8621f407SFrançois Tigeot 
1428*8621f407SFrançois Tigeot 	hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port));
1429*8621f407SFrançois Tigeot 	hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
1430*8621f407SFrançois Tigeot 
1431*8621f407SFrançois Tigeot 	hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0));
1432*8621f407SFrançois Tigeot 	hw_state->pll0 &= PORT_PLL_M2_MASK;
1433*8621f407SFrançois Tigeot 
1434*8621f407SFrançois Tigeot 	hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1));
1435*8621f407SFrançois Tigeot 	hw_state->pll1 &= PORT_PLL_N_MASK;
1436*8621f407SFrançois Tigeot 
1437*8621f407SFrançois Tigeot 	hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2));
1438*8621f407SFrançois Tigeot 	hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK;
1439*8621f407SFrançois Tigeot 
1440*8621f407SFrançois Tigeot 	hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3));
1441*8621f407SFrançois Tigeot 	hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE;
1442*8621f407SFrançois Tigeot 
1443*8621f407SFrançois Tigeot 	hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6));
1444*8621f407SFrançois Tigeot 	hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK |
1445*8621f407SFrançois Tigeot 			  PORT_PLL_INT_COEFF_MASK |
1446*8621f407SFrançois Tigeot 			  PORT_PLL_GAIN_CTL_MASK;
1447*8621f407SFrançois Tigeot 
1448*8621f407SFrançois Tigeot 	hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8));
1449*8621f407SFrançois Tigeot 	hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK;
1450*8621f407SFrançois Tigeot 
1451*8621f407SFrançois Tigeot 	hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9));
1452*8621f407SFrançois Tigeot 	hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK;
1453*8621f407SFrançois Tigeot 
1454*8621f407SFrançois Tigeot 	hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10));
1455*8621f407SFrançois Tigeot 	hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H |
1456*8621f407SFrançois Tigeot 			   PORT_PLL_DCO_AMP_MASK;
1457*8621f407SFrançois Tigeot 
1458*8621f407SFrançois Tigeot 	/*
1459*8621f407SFrançois Tigeot 	 * While we write to the group register to program all lanes at once we
1460*8621f407SFrançois Tigeot 	 * can read only lane registers. We configure all lanes the same way, so
1461*8621f407SFrançois Tigeot 	 * here just read out lanes 0/1 and output a note if lanes 2/3 differ.
1462*8621f407SFrançois Tigeot 	 */
1463*8621f407SFrançois Tigeot 	hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
1464*8621f407SFrançois Tigeot 	if (I915_READ(BXT_PORT_PCS_DW12_LN23(port)) != hw_state->pcsdw12)
1465*8621f407SFrançois Tigeot 		DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
1466*8621f407SFrançois Tigeot 				 hw_state->pcsdw12,
1467*8621f407SFrançois Tigeot 				 I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
1468*8621f407SFrançois Tigeot 	hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
1469*8621f407SFrançois Tigeot 
1470*8621f407SFrançois Tigeot 	ret = true;
1471*8621f407SFrançois Tigeot 
1472*8621f407SFrançois Tigeot out:
1473*8621f407SFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
1474*8621f407SFrançois Tigeot 
1475*8621f407SFrançois Tigeot 	return ret;
1476*8621f407SFrançois Tigeot }
1477*8621f407SFrançois Tigeot 
1478*8621f407SFrançois Tigeot /* bxt clock parameters */
1479*8621f407SFrançois Tigeot struct bxt_clk_div {
1480*8621f407SFrançois Tigeot 	int clock;
1481*8621f407SFrançois Tigeot 	uint32_t p1;
1482*8621f407SFrançois Tigeot 	uint32_t p2;
1483*8621f407SFrançois Tigeot 	uint32_t m2_int;
1484*8621f407SFrançois Tigeot 	uint32_t m2_frac;
1485*8621f407SFrançois Tigeot 	bool m2_frac_en;
1486*8621f407SFrançois Tigeot 	uint32_t n;
1487*8621f407SFrançois Tigeot };
1488*8621f407SFrançois Tigeot 
1489*8621f407SFrançois Tigeot /* pre-calculated values for DP linkrates */
1490*8621f407SFrançois Tigeot static const struct bxt_clk_div bxt_dp_clk_val[] = {
1491*8621f407SFrançois Tigeot 	{162000, 4, 2, 32, 1677722, 1, 1},
1492*8621f407SFrançois Tigeot 	{270000, 4, 1, 27,       0, 0, 1},
1493*8621f407SFrançois Tigeot 	{540000, 2, 1, 27,       0, 0, 1},
1494*8621f407SFrançois Tigeot 	{216000, 3, 2, 32, 1677722, 1, 1},
1495*8621f407SFrançois Tigeot 	{243000, 4, 1, 24, 1258291, 1, 1},
1496*8621f407SFrançois Tigeot 	{324000, 4, 1, 32, 1677722, 1, 1},
1497*8621f407SFrançois Tigeot 	{432000, 3, 1, 32, 1677722, 1, 1}
1498*8621f407SFrançois Tigeot };
1499*8621f407SFrançois Tigeot 
1500*8621f407SFrançois Tigeot static struct intel_shared_dpll *
1501*8621f407SFrançois Tigeot bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
1502*8621f407SFrançois Tigeot 	     struct intel_encoder *encoder)
1503*8621f407SFrançois Tigeot {
1504*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
1505*8621f407SFrançois Tigeot 	struct intel_shared_dpll *pll;
1506*8621f407SFrançois Tigeot 	enum intel_dpll_id i;
1507*8621f407SFrançois Tigeot 	struct intel_digital_port *intel_dig_port;
1508*8621f407SFrançois Tigeot 	struct bxt_clk_div clk_div = {0};
1509*8621f407SFrançois Tigeot 	int vco = 0;
1510*8621f407SFrançois Tigeot 	uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
1511*8621f407SFrançois Tigeot 	uint32_t lanestagger;
1512*8621f407SFrançois Tigeot 	int clock = crtc_state->port_clock;
1513*8621f407SFrançois Tigeot 
1514*8621f407SFrançois Tigeot 	if (encoder->type == INTEL_OUTPUT_HDMI) {
1515*8621f407SFrançois Tigeot 		intel_clock_t best_clock;
1516*8621f407SFrançois Tigeot 
1517*8621f407SFrançois Tigeot 		/* Calculate HDMI div */
1518*8621f407SFrançois Tigeot 		/*
1519*8621f407SFrançois Tigeot 		 * FIXME: tie the following calculation into
1520*8621f407SFrançois Tigeot 		 * i9xx_crtc_compute_clock
1521*8621f407SFrançois Tigeot 		 */
1522*8621f407SFrançois Tigeot 		if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
1523*8621f407SFrançois Tigeot 			DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
1524*8621f407SFrançois Tigeot 					 clock, pipe_name(crtc->pipe));
1525*8621f407SFrançois Tigeot 			return NULL;
1526*8621f407SFrançois Tigeot 		}
1527*8621f407SFrançois Tigeot 
1528*8621f407SFrançois Tigeot 		clk_div.p1 = best_clock.p1;
1529*8621f407SFrançois Tigeot 		clk_div.p2 = best_clock.p2;
1530*8621f407SFrançois Tigeot 		WARN_ON(best_clock.m1 != 2);
1531*8621f407SFrançois Tigeot 		clk_div.n = best_clock.n;
1532*8621f407SFrançois Tigeot 		clk_div.m2_int = best_clock.m2 >> 22;
1533*8621f407SFrançois Tigeot 		clk_div.m2_frac = best_clock.m2 & ((1 << 22) - 1);
1534*8621f407SFrançois Tigeot 		clk_div.m2_frac_en = clk_div.m2_frac != 0;
1535*8621f407SFrançois Tigeot 
1536*8621f407SFrançois Tigeot 		vco = best_clock.vco;
1537*8621f407SFrançois Tigeot 	} else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
1538*8621f407SFrançois Tigeot 		   encoder->type == INTEL_OUTPUT_EDP) {
1539*8621f407SFrançois Tigeot 		int i;
1540*8621f407SFrançois Tigeot 
1541*8621f407SFrançois Tigeot 		clk_div = bxt_dp_clk_val[0];
1542*8621f407SFrançois Tigeot 		for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
1543*8621f407SFrançois Tigeot 			if (bxt_dp_clk_val[i].clock == clock) {
1544*8621f407SFrançois Tigeot 				clk_div = bxt_dp_clk_val[i];
1545*8621f407SFrançois Tigeot 				break;
1546*8621f407SFrançois Tigeot 			}
1547*8621f407SFrançois Tigeot 		}
1548*8621f407SFrançois Tigeot 		vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2;
1549*8621f407SFrançois Tigeot 	}
1550*8621f407SFrançois Tigeot 
1551*8621f407SFrançois Tigeot 	if (vco >= 6200000 && vco <= 6700000) {
1552*8621f407SFrançois Tigeot 		prop_coef = 4;
1553*8621f407SFrançois Tigeot 		int_coef = 9;
1554*8621f407SFrançois Tigeot 		gain_ctl = 3;
1555*8621f407SFrançois Tigeot 		targ_cnt = 8;
1556*8621f407SFrançois Tigeot 	} else if ((vco > 5400000 && vco < 6200000) ||
1557*8621f407SFrançois Tigeot 			(vco >= 4800000 && vco < 5400000)) {
1558*8621f407SFrançois Tigeot 		prop_coef = 5;
1559*8621f407SFrançois Tigeot 		int_coef = 11;
1560*8621f407SFrançois Tigeot 		gain_ctl = 3;
1561*8621f407SFrançois Tigeot 		targ_cnt = 9;
1562*8621f407SFrançois Tigeot 	} else if (vco == 5400000) {
1563*8621f407SFrançois Tigeot 		prop_coef = 3;
1564*8621f407SFrançois Tigeot 		int_coef = 8;
1565*8621f407SFrançois Tigeot 		gain_ctl = 1;
1566*8621f407SFrançois Tigeot 		targ_cnt = 9;
1567*8621f407SFrançois Tigeot 	} else {
1568*8621f407SFrançois Tigeot 		DRM_ERROR("Invalid VCO\n");
1569*8621f407SFrançois Tigeot 		return NULL;
1570*8621f407SFrançois Tigeot 	}
1571*8621f407SFrançois Tigeot 
1572*8621f407SFrançois Tigeot 	memset(&crtc_state->dpll_hw_state, 0,
1573*8621f407SFrançois Tigeot 	       sizeof(crtc_state->dpll_hw_state));
1574*8621f407SFrançois Tigeot 
1575*8621f407SFrançois Tigeot 	if (clock > 270000)
1576*8621f407SFrançois Tigeot 		lanestagger = 0x18;
1577*8621f407SFrançois Tigeot 	else if (clock > 135000)
1578*8621f407SFrançois Tigeot 		lanestagger = 0x0d;
1579*8621f407SFrançois Tigeot 	else if (clock > 67000)
1580*8621f407SFrançois Tigeot 		lanestagger = 0x07;
1581*8621f407SFrançois Tigeot 	else if (clock > 33000)
1582*8621f407SFrançois Tigeot 		lanestagger = 0x04;
1583*8621f407SFrançois Tigeot 	else
1584*8621f407SFrançois Tigeot 		lanestagger = 0x02;
1585*8621f407SFrançois Tigeot 
1586*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.ebb0 =
1587*8621f407SFrançois Tigeot 		PORT_PLL_P1(clk_div.p1) | PORT_PLL_P2(clk_div.p2);
1588*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.pll0 = clk_div.m2_int;
1589*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.pll1 = PORT_PLL_N(clk_div.n);
1590*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.pll2 = clk_div.m2_frac;
1591*8621f407SFrançois Tigeot 
1592*8621f407SFrançois Tigeot 	if (clk_div.m2_frac_en)
1593*8621f407SFrançois Tigeot 		crtc_state->dpll_hw_state.pll3 =
1594*8621f407SFrançois Tigeot 			PORT_PLL_M2_FRAC_ENABLE;
1595*8621f407SFrançois Tigeot 
1596*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.pll6 =
1597*8621f407SFrançois Tigeot 		prop_coef | PORT_PLL_INT_COEFF(int_coef);
1598*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.pll6 |=
1599*8621f407SFrançois Tigeot 		PORT_PLL_GAIN_CTL(gain_ctl);
1600*8621f407SFrançois Tigeot 
1601*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.pll8 = targ_cnt;
1602*8621f407SFrançois Tigeot 
1603*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
1604*8621f407SFrançois Tigeot 
1605*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.pll10 =
1606*8621f407SFrançois Tigeot 		PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
1607*8621f407SFrançois Tigeot 		| PORT_PLL_DCO_AMP_OVR_EN_H;
1608*8621f407SFrançois Tigeot 
1609*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
1610*8621f407SFrançois Tigeot 
1611*8621f407SFrançois Tigeot 	crtc_state->dpll_hw_state.pcsdw12 =
1612*8621f407SFrançois Tigeot 		LANESTAGGER_STRAP_OVRD | lanestagger;
1613*8621f407SFrançois Tigeot 
1614*8621f407SFrançois Tigeot 	intel_dig_port = enc_to_dig_port(&encoder->base);
1615*8621f407SFrançois Tigeot 
1616*8621f407SFrançois Tigeot 	/* 1:1 mapping between ports and PLLs */
1617*8621f407SFrançois Tigeot 	i = (enum intel_dpll_id) intel_dig_port->port;
1618*8621f407SFrançois Tigeot 	pll = intel_get_shared_dpll_by_id(dev_priv, i);
1619*8621f407SFrançois Tigeot 
1620*8621f407SFrançois Tigeot 	DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
1621*8621f407SFrançois Tigeot 		crtc->base.base.id, pll->name);
1622*8621f407SFrançois Tigeot 
1623*8621f407SFrançois Tigeot 	intel_reference_shared_dpll(pll, crtc_state);
1624*8621f407SFrançois Tigeot 
1625*8621f407SFrançois Tigeot 	/* shared DPLL id 0 is DPLL A */
1626*8621f407SFrançois Tigeot 	crtc_state->ddi_pll_sel = pll->id;
1627*8621f407SFrançois Tigeot 
1628*8621f407SFrançois Tigeot 	return pll;
1629*8621f407SFrançois Tigeot }
1630*8621f407SFrançois Tigeot 
1631*8621f407SFrançois Tigeot static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = {
1632*8621f407SFrançois Tigeot 	.enable = bxt_ddi_pll_enable,
1633*8621f407SFrançois Tigeot 	.disable = bxt_ddi_pll_disable,
1634*8621f407SFrançois Tigeot 	.get_hw_state = bxt_ddi_pll_get_hw_state,
1635*8621f407SFrançois Tigeot };
1636*8621f407SFrançois Tigeot 
1637*8621f407SFrançois Tigeot static void intel_ddi_pll_init(struct drm_device *dev)
1638*8621f407SFrançois Tigeot {
1639*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1640*8621f407SFrançois Tigeot 	uint32_t val = I915_READ(LCPLL_CTL);
1641*8621f407SFrançois Tigeot 
1642*8621f407SFrançois Tigeot 	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
1643*8621f407SFrançois Tigeot 		int cdclk_freq;
1644*8621f407SFrançois Tigeot 
1645*8621f407SFrançois Tigeot 		cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
1646*8621f407SFrançois Tigeot 		dev_priv->skl_boot_cdclk = cdclk_freq;
1647*8621f407SFrançois Tigeot 		if (skl_sanitize_cdclk(dev_priv))
1648*8621f407SFrançois Tigeot 			DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n");
1649*8621f407SFrançois Tigeot 		if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE))
1650*8621f407SFrançois Tigeot 			DRM_ERROR("LCPLL1 is disabled\n");
1651*8621f407SFrançois Tigeot 	} else if (!IS_BROXTON(dev_priv)) {
1652*8621f407SFrançois Tigeot 		/*
1653*8621f407SFrançois Tigeot 		 * The LCPLL register should be turned on by the BIOS. For now
1654*8621f407SFrançois Tigeot 		 * let's just check its state and print errors in case
1655*8621f407SFrançois Tigeot 		 * something is wrong.  Don't even try to turn it on.
1656*8621f407SFrançois Tigeot 		 */
1657*8621f407SFrançois Tigeot 
1658*8621f407SFrançois Tigeot 		if (val & LCPLL_CD_SOURCE_FCLK)
1659*8621f407SFrançois Tigeot 			DRM_ERROR("CDCLK source is not LCPLL\n");
1660*8621f407SFrançois Tigeot 
1661*8621f407SFrançois Tigeot 		if (val & LCPLL_PLL_DISABLE)
1662*8621f407SFrançois Tigeot 			DRM_ERROR("LCPLL is disabled\n");
1663*8621f407SFrançois Tigeot 	}
1664*8621f407SFrançois Tigeot }
1665*8621f407SFrançois Tigeot 
1666*8621f407SFrançois Tigeot struct dpll_info {
1667*8621f407SFrançois Tigeot 	const char *name;
1668*8621f407SFrançois Tigeot 	const int id;
1669*8621f407SFrançois Tigeot 	const struct intel_shared_dpll_funcs *funcs;
1670*8621f407SFrançois Tigeot 	uint32_t flags;
1671*8621f407SFrançois Tigeot };
1672*8621f407SFrançois Tigeot 
1673*8621f407SFrançois Tigeot struct intel_dpll_mgr {
1674*8621f407SFrançois Tigeot 	const struct dpll_info *dpll_info;
1675*8621f407SFrançois Tigeot 
1676*8621f407SFrançois Tigeot 	struct intel_shared_dpll *(*get_dpll)(struct intel_crtc *crtc,
1677*8621f407SFrançois Tigeot 					      struct intel_crtc_state *crtc_state,
1678*8621f407SFrançois Tigeot 					      struct intel_encoder *encoder);
1679*8621f407SFrançois Tigeot };
1680*8621f407SFrançois Tigeot 
1681*8621f407SFrançois Tigeot static const struct dpll_info pch_plls[] = {
1682*8621f407SFrançois Tigeot 	{ "PCH DPLL A", DPLL_ID_PCH_PLL_A, &ibx_pch_dpll_funcs, 0 },
1683*8621f407SFrançois Tigeot 	{ "PCH DPLL B", DPLL_ID_PCH_PLL_B, &ibx_pch_dpll_funcs, 0 },
1684*8621f407SFrançois Tigeot 	{ NULL, -1, NULL, 0 },
1685*8621f407SFrançois Tigeot };
1686*8621f407SFrançois Tigeot 
1687*8621f407SFrançois Tigeot static const struct intel_dpll_mgr pch_pll_mgr = {
1688*8621f407SFrançois Tigeot 	.dpll_info = pch_plls,
1689*8621f407SFrançois Tigeot 	.get_dpll = ibx_get_dpll,
1690*8621f407SFrançois Tigeot };
1691*8621f407SFrançois Tigeot 
1692*8621f407SFrançois Tigeot static const struct dpll_info hsw_plls[] = {
1693*8621f407SFrançois Tigeot 	{ "WRPLL 1",    DPLL_ID_WRPLL1,     &hsw_ddi_wrpll_funcs, 0 },
1694*8621f407SFrançois Tigeot 	{ "WRPLL 2",    DPLL_ID_WRPLL2,     &hsw_ddi_wrpll_funcs, 0 },
1695*8621f407SFrançois Tigeot 	{ "SPLL",       DPLL_ID_SPLL,       &hsw_ddi_spll_funcs,  0 },
1696*8621f407SFrançois Tigeot 	{ "LCPLL 810",  DPLL_ID_LCPLL_810,  &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
1697*8621f407SFrançois Tigeot 	{ "LCPLL 1350", DPLL_ID_LCPLL_1350, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
1698*8621f407SFrançois Tigeot 	{ "LCPLL 2700", DPLL_ID_LCPLL_2700, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
1699*8621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
1700*8621f407SFrançois Tigeot };
1701*8621f407SFrançois Tigeot 
1702*8621f407SFrançois Tigeot static const struct intel_dpll_mgr hsw_pll_mgr = {
1703*8621f407SFrançois Tigeot 	.dpll_info = hsw_plls,
1704*8621f407SFrançois Tigeot 	.get_dpll = hsw_get_dpll,
1705*8621f407SFrançois Tigeot };
1706*8621f407SFrançois Tigeot 
1707*8621f407SFrançois Tigeot static const struct dpll_info skl_plls[] = {
1708*8621f407SFrançois Tigeot 	{ "DPLL 0", DPLL_ID_SKL_DPLL0, &skl_ddi_dpll0_funcs, INTEL_DPLL_ALWAYS_ON },
1709*8621f407SFrançois Tigeot 	{ "DPLL 1", DPLL_ID_SKL_DPLL1, &skl_ddi_pll_funcs,   0 },
1710*8621f407SFrançois Tigeot 	{ "DPLL 2", DPLL_ID_SKL_DPLL2, &skl_ddi_pll_funcs,   0 },
1711*8621f407SFrançois Tigeot 	{ "DPLL 3", DPLL_ID_SKL_DPLL3, &skl_ddi_pll_funcs,   0 },
1712*8621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
1713*8621f407SFrançois Tigeot };
1714*8621f407SFrançois Tigeot 
1715*8621f407SFrançois Tigeot static const struct intel_dpll_mgr skl_pll_mgr = {
1716*8621f407SFrançois Tigeot 	.dpll_info = skl_plls,
1717*8621f407SFrançois Tigeot 	.get_dpll = skl_get_dpll,
1718*8621f407SFrançois Tigeot };
1719*8621f407SFrançois Tigeot 
1720*8621f407SFrançois Tigeot static const struct dpll_info bxt_plls[] = {
1721*8621f407SFrançois Tigeot 	{ "PORT PLL A", DPLL_ID_SKL_DPLL0, &bxt_ddi_pll_funcs, 0 },
1722*8621f407SFrançois Tigeot 	{ "PORT PLL B", DPLL_ID_SKL_DPLL1, &bxt_ddi_pll_funcs, 0 },
1723*8621f407SFrançois Tigeot 	{ "PORT PLL C", DPLL_ID_SKL_DPLL2, &bxt_ddi_pll_funcs, 0 },
1724*8621f407SFrançois Tigeot 	{ NULL, -1, NULL, },
1725*8621f407SFrançois Tigeot };
1726*8621f407SFrançois Tigeot 
1727*8621f407SFrançois Tigeot static const struct intel_dpll_mgr bxt_pll_mgr = {
1728*8621f407SFrançois Tigeot 	.dpll_info = bxt_plls,
1729*8621f407SFrançois Tigeot 	.get_dpll = bxt_get_dpll,
1730*8621f407SFrançois Tigeot };
1731*8621f407SFrançois Tigeot 
1732*8621f407SFrançois Tigeot void intel_shared_dpll_init(struct drm_device *dev)
1733*8621f407SFrançois Tigeot {
1734*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1735*8621f407SFrançois Tigeot 	const struct intel_dpll_mgr *dpll_mgr = NULL;
1736*8621f407SFrançois Tigeot 	const struct dpll_info *dpll_info;
1737*8621f407SFrançois Tigeot 	int i;
1738*8621f407SFrançois Tigeot 
1739*8621f407SFrançois Tigeot 	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
1740*8621f407SFrançois Tigeot 		dpll_mgr = &skl_pll_mgr;
1741*8621f407SFrançois Tigeot 	else if (IS_BROXTON(dev))
1742*8621f407SFrançois Tigeot 		dpll_mgr = &bxt_pll_mgr;
1743*8621f407SFrançois Tigeot 	else if (HAS_DDI(dev))
1744*8621f407SFrançois Tigeot 		dpll_mgr = &hsw_pll_mgr;
1745*8621f407SFrançois Tigeot 	else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
1746*8621f407SFrançois Tigeot 		dpll_mgr = &pch_pll_mgr;
1747*8621f407SFrançois Tigeot 
1748*8621f407SFrançois Tigeot 	if (!dpll_mgr) {
1749*8621f407SFrançois Tigeot 		dev_priv->num_shared_dpll = 0;
1750*8621f407SFrançois Tigeot 		return;
1751*8621f407SFrançois Tigeot 	}
1752*8621f407SFrançois Tigeot 
1753*8621f407SFrançois Tigeot 	dpll_info = dpll_mgr->dpll_info;
1754*8621f407SFrançois Tigeot 
1755*8621f407SFrançois Tigeot 	for (i = 0; dpll_info[i].id >= 0; i++) {
1756*8621f407SFrançois Tigeot 		WARN_ON(i != dpll_info[i].id);
1757*8621f407SFrançois Tigeot 
1758*8621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].id = dpll_info[i].id;
1759*8621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].name = dpll_info[i].name;
1760*8621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].funcs = *dpll_info[i].funcs;
1761*8621f407SFrançois Tigeot 		dev_priv->shared_dplls[i].flags = dpll_info[i].flags;
1762*8621f407SFrançois Tigeot 	}
1763*8621f407SFrançois Tigeot 
1764*8621f407SFrançois Tigeot 	dev_priv->dpll_mgr = dpll_mgr;
1765*8621f407SFrançois Tigeot 	dev_priv->num_shared_dpll = i;
1766*8621f407SFrançois Tigeot 	lockinit(&dev_priv->dpll_lock, "dpll_lock", 0, LK_CANRECURSE);
1767*8621f407SFrançois Tigeot 
1768*8621f407SFrançois Tigeot 	BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
1769*8621f407SFrançois Tigeot 
1770*8621f407SFrançois Tigeot 	/* FIXME: Move this to a more suitable place */
1771*8621f407SFrançois Tigeot 	if (HAS_DDI(dev))
1772*8621f407SFrançois Tigeot 		intel_ddi_pll_init(dev);
1773*8621f407SFrançois Tigeot }
1774*8621f407SFrançois Tigeot 
1775*8621f407SFrançois Tigeot struct intel_shared_dpll *
1776*8621f407SFrançois Tigeot intel_get_shared_dpll(struct intel_crtc *crtc,
1777*8621f407SFrançois Tigeot 		      struct intel_crtc_state *crtc_state,
1778*8621f407SFrançois Tigeot 		      struct intel_encoder *encoder)
1779*8621f407SFrançois Tigeot {
1780*8621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
1781*8621f407SFrançois Tigeot 	const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll_mgr;
1782*8621f407SFrançois Tigeot 
1783*8621f407SFrançois Tigeot 	if (WARN_ON(!dpll_mgr))
1784*8621f407SFrançois Tigeot 		return NULL;
1785*8621f407SFrançois Tigeot 
1786*8621f407SFrançois Tigeot 	return dpll_mgr->get_dpll(crtc, crtc_state, encoder);
1787*8621f407SFrançois Tigeot }
1788