xref: /openbsd-src/sys/dev/pci/drm/i915/display/intel_dpll_mgr.c (revision 8e8fc6d26dd88a2a42b6a2e99d42b8960de88b6d)
1c349dbc7Sjsg /*
2c349dbc7Sjsg  * Copyright © 2006-2016 Intel Corporation
3c349dbc7Sjsg  *
4c349dbc7Sjsg  * Permission is hereby granted, free of charge, to any person obtaining a
5c349dbc7Sjsg  * copy of this software and associated documentation files (the "Software"),
6c349dbc7Sjsg  * to deal in the Software without restriction, including without limitation
7c349dbc7Sjsg  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c349dbc7Sjsg  * and/or sell copies of the Software, and to permit persons to whom the
9c349dbc7Sjsg  * Software is furnished to do so, subject to the following conditions:
10c349dbc7Sjsg  *
11c349dbc7Sjsg  * The above copyright notice and this permission notice (including the next
12c349dbc7Sjsg  * paragraph) shall be included in all copies or substantial portions of the
13c349dbc7Sjsg  * Software.
14c349dbc7Sjsg  *
15c349dbc7Sjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16c349dbc7Sjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17c349dbc7Sjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18c349dbc7Sjsg  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19c349dbc7Sjsg  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20c349dbc7Sjsg  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21c349dbc7Sjsg  * DEALINGS IN THE SOFTWARE.
22c349dbc7Sjsg  */
23c349dbc7Sjsg 
24f005ef32Sjsg #include <linux/math.h>
251bb76ff1Sjsg #include <linux/string_helpers.h>
261bb76ff1Sjsg 
27f005ef32Sjsg #include "i915_reg.h"
285ca02815Sjsg #include "intel_de.h"
29c349dbc7Sjsg #include "intel_display_types.h"
301bb76ff1Sjsg #include "intel_dkl_phy.h"
31f005ef32Sjsg #include "intel_dkl_phy_regs.h"
32c349dbc7Sjsg #include "intel_dpio_phy.h"
335ca02815Sjsg #include "intel_dpll.h"
34c349dbc7Sjsg #include "intel_dpll_mgr.h"
35f005ef32Sjsg #include "intel_hti.h"
36f005ef32Sjsg #include "intel_mg_phy_regs.h"
371bb76ff1Sjsg #include "intel_pch_refclk.h"
381bb76ff1Sjsg #include "intel_tc.h"
39c349dbc7Sjsg 
40c349dbc7Sjsg /**
41c349dbc7Sjsg  * DOC: Display PLLs
42c349dbc7Sjsg  *
43c349dbc7Sjsg  * Display PLLs used for driving outputs vary by platform. While some have
44c349dbc7Sjsg  * per-pipe or per-encoder dedicated PLLs, others allow the use of any PLL
45c349dbc7Sjsg  * from a pool. In the latter scenario, it is possible that multiple pipes
46c349dbc7Sjsg  * share a PLL if their configurations match.
47c349dbc7Sjsg  *
48c349dbc7Sjsg  * This file provides an abstraction over display PLLs. The function
49c349dbc7Sjsg  * intel_shared_dpll_init() initializes the PLLs for the given platform.  The
50c349dbc7Sjsg  * users of a PLL are tracked and that tracking is integrated with the atomic
51c349dbc7Sjsg  * modset interface. During an atomic operation, required PLLs can be reserved
52c349dbc7Sjsg  * for a given CRTC and encoder configuration by calling
53c349dbc7Sjsg  * intel_reserve_shared_dplls() and previously reserved PLLs can be released
54c349dbc7Sjsg  * with intel_release_shared_dplls().
55c349dbc7Sjsg  * Changes to the users are first staged in the atomic state, and then made
56c349dbc7Sjsg  * effective by calling intel_shared_dpll_swap_state() during the atomic
57c349dbc7Sjsg  * commit phase.
58c349dbc7Sjsg  */
59c349dbc7Sjsg 
601bb76ff1Sjsg /* platform specific hooks for managing DPLLs */
611bb76ff1Sjsg struct intel_shared_dpll_funcs {
621bb76ff1Sjsg 	/*
631bb76ff1Sjsg 	 * Hook for enabling the pll, called from intel_enable_shared_dpll() if
641bb76ff1Sjsg 	 * the pll is not already enabled.
651bb76ff1Sjsg 	 */
661bb76ff1Sjsg 	void (*enable)(struct drm_i915_private *i915,
671bb76ff1Sjsg 		       struct intel_shared_dpll *pll);
681bb76ff1Sjsg 
691bb76ff1Sjsg 	/*
701bb76ff1Sjsg 	 * Hook for disabling the pll, called from intel_disable_shared_dpll()
711bb76ff1Sjsg 	 * only when it is safe to disable the pll, i.e., there are no more
721bb76ff1Sjsg 	 * tracked users for it.
731bb76ff1Sjsg 	 */
741bb76ff1Sjsg 	void (*disable)(struct drm_i915_private *i915,
751bb76ff1Sjsg 			struct intel_shared_dpll *pll);
761bb76ff1Sjsg 
771bb76ff1Sjsg 	/*
781bb76ff1Sjsg 	 * Hook for reading the values currently programmed to the DPLL
791bb76ff1Sjsg 	 * registers. This is used for initial hw state readout and state
801bb76ff1Sjsg 	 * verification after a mode set.
811bb76ff1Sjsg 	 */
821bb76ff1Sjsg 	bool (*get_hw_state)(struct drm_i915_private *i915,
831bb76ff1Sjsg 			     struct intel_shared_dpll *pll,
841bb76ff1Sjsg 			     struct intel_dpll_hw_state *hw_state);
851bb76ff1Sjsg 
861bb76ff1Sjsg 	/*
871bb76ff1Sjsg 	 * Hook for calculating the pll's output frequency based on its passed
881bb76ff1Sjsg 	 * in state.
891bb76ff1Sjsg 	 */
901bb76ff1Sjsg 	int (*get_freq)(struct drm_i915_private *i915,
911bb76ff1Sjsg 			const struct intel_shared_dpll *pll,
921bb76ff1Sjsg 			const struct intel_dpll_hw_state *pll_state);
931bb76ff1Sjsg };
941bb76ff1Sjsg 
95c349dbc7Sjsg struct intel_dpll_mgr {
96c349dbc7Sjsg 	const struct dpll_info *dpll_info;
97c349dbc7Sjsg 
981bb76ff1Sjsg 	int (*compute_dplls)(struct intel_atomic_state *state,
991bb76ff1Sjsg 			     struct intel_crtc *crtc,
1001bb76ff1Sjsg 			     struct intel_encoder *encoder);
1011bb76ff1Sjsg 	int (*get_dplls)(struct intel_atomic_state *state,
102c349dbc7Sjsg 			 struct intel_crtc *crtc,
103c349dbc7Sjsg 			 struct intel_encoder *encoder);
104c349dbc7Sjsg 	void (*put_dplls)(struct intel_atomic_state *state,
105c349dbc7Sjsg 			  struct intel_crtc *crtc);
106c349dbc7Sjsg 	void (*update_active_dpll)(struct intel_atomic_state *state,
107c349dbc7Sjsg 				   struct intel_crtc *crtc,
108c349dbc7Sjsg 				   struct intel_encoder *encoder);
109c349dbc7Sjsg 	void (*update_ref_clks)(struct drm_i915_private *i915);
110c349dbc7Sjsg 	void (*dump_hw_state)(struct drm_i915_private *dev_priv,
111c349dbc7Sjsg 			      const struct intel_dpll_hw_state *hw_state);
112c349dbc7Sjsg };
113c349dbc7Sjsg 
114c349dbc7Sjsg static void
115c349dbc7Sjsg intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv,
116c349dbc7Sjsg 				  struct intel_shared_dpll_state *shared_dpll)
117c349dbc7Sjsg {
118c349dbc7Sjsg 	enum intel_dpll_id i;
119c349dbc7Sjsg 
120c349dbc7Sjsg 	/* Copy shared dpll state */
1211bb76ff1Sjsg 	for (i = 0; i < dev_priv->display.dpll.num_shared_dpll; i++) {
1221bb76ff1Sjsg 		struct intel_shared_dpll *pll = &dev_priv->display.dpll.shared_dplls[i];
123c349dbc7Sjsg 
124c349dbc7Sjsg 		shared_dpll[i] = pll->state;
125c349dbc7Sjsg 	}
126c349dbc7Sjsg }
127c349dbc7Sjsg 
128c349dbc7Sjsg static struct intel_shared_dpll_state *
129c349dbc7Sjsg intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s)
130c349dbc7Sjsg {
131c349dbc7Sjsg 	struct intel_atomic_state *state = to_intel_atomic_state(s);
132c349dbc7Sjsg 
133ad8b1aafSjsg 	drm_WARN_ON(s->dev, !drm_modeset_is_locked(&s->dev->mode_config.connection_mutex));
134c349dbc7Sjsg 
135c349dbc7Sjsg 	if (!state->dpll_set) {
136c349dbc7Sjsg 		state->dpll_set = true;
137c349dbc7Sjsg 
138c349dbc7Sjsg 		intel_atomic_duplicate_dpll_state(to_i915(s->dev),
139c349dbc7Sjsg 						  state->shared_dpll);
140c349dbc7Sjsg 	}
141c349dbc7Sjsg 
142c349dbc7Sjsg 	return state->shared_dpll;
143c349dbc7Sjsg }
144c349dbc7Sjsg 
145c349dbc7Sjsg /**
146c349dbc7Sjsg  * intel_get_shared_dpll_by_id - get a DPLL given its id
147c349dbc7Sjsg  * @dev_priv: i915 device instance
148c349dbc7Sjsg  * @id: pll id
149c349dbc7Sjsg  *
150c349dbc7Sjsg  * Returns:
151c349dbc7Sjsg  * A pointer to the DPLL with @id
152c349dbc7Sjsg  */
153c349dbc7Sjsg struct intel_shared_dpll *
154c349dbc7Sjsg intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
155c349dbc7Sjsg 			    enum intel_dpll_id id)
156c349dbc7Sjsg {
1571bb76ff1Sjsg 	return &dev_priv->display.dpll.shared_dplls[id];
158c349dbc7Sjsg }
159c349dbc7Sjsg 
160c349dbc7Sjsg /* For ILK+ */
161c349dbc7Sjsg void assert_shared_dpll(struct drm_i915_private *dev_priv,
162c349dbc7Sjsg 			struct intel_shared_dpll *pll,
163c349dbc7Sjsg 			bool state)
164c349dbc7Sjsg {
165c349dbc7Sjsg 	bool cur_state;
166c349dbc7Sjsg 	struct intel_dpll_hw_state hw_state;
167c349dbc7Sjsg 
168c349dbc7Sjsg 	if (drm_WARN(&dev_priv->drm, !pll,
1691bb76ff1Sjsg 		     "asserting DPLL %s with no DPLL\n", str_on_off(state)))
170c349dbc7Sjsg 		return;
171c349dbc7Sjsg 
1725ca02815Sjsg 	cur_state = intel_dpll_get_hw_state(dev_priv, pll, &hw_state);
173f005ef32Sjsg 	I915_STATE_WARN(dev_priv, cur_state != state,
174c349dbc7Sjsg 			"%s assertion failure (expected %s, current %s)\n",
1751bb76ff1Sjsg 			pll->info->name, str_on_off(state),
1761bb76ff1Sjsg 			str_on_off(cur_state));
177c349dbc7Sjsg }
178c349dbc7Sjsg 
1795ca02815Sjsg static enum tc_port icl_pll_id_to_tc_port(enum intel_dpll_id id)
1805ca02815Sjsg {
1815ca02815Sjsg 	return TC_PORT_1 + id - DPLL_ID_ICL_MGPLL1;
1825ca02815Sjsg }
1835ca02815Sjsg 
1845ca02815Sjsg enum intel_dpll_id icl_tc_port_to_pll_id(enum tc_port tc_port)
1855ca02815Sjsg {
1865ca02815Sjsg 	return tc_port - TC_PORT_1 + DPLL_ID_ICL_MGPLL1;
1875ca02815Sjsg }
1885ca02815Sjsg 
189ad8b1aafSjsg static i915_reg_t
190ad8b1aafSjsg intel_combo_pll_enable_reg(struct drm_i915_private *i915,
191ad8b1aafSjsg 			   struct intel_shared_dpll *pll)
192ad8b1aafSjsg {
1935ca02815Sjsg 	if (IS_DG1(i915))
1945ca02815Sjsg 		return DG1_DPLL_ENABLE(pll->info->id);
195f005ef32Sjsg 	else if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) &&
196f005ef32Sjsg 		 (pll->info->id == DPLL_ID_EHL_DPLL4))
197ad8b1aafSjsg 		return MG_PLL_ENABLE(0);
198ad8b1aafSjsg 
1995ca02815Sjsg 	return ICL_DPLL_ENABLE(pll->info->id);
200ad8b1aafSjsg }
2015ca02815Sjsg 
2025ca02815Sjsg static i915_reg_t
2035ca02815Sjsg intel_tc_pll_enable_reg(struct drm_i915_private *i915,
2045ca02815Sjsg 			struct intel_shared_dpll *pll)
2055ca02815Sjsg {
2065ca02815Sjsg 	const enum intel_dpll_id id = pll->info->id;
2075ca02815Sjsg 	enum tc_port tc_port = icl_pll_id_to_tc_port(id);
2085ca02815Sjsg 
2095ca02815Sjsg 	if (IS_ALDERLAKE_P(i915))
2105ca02815Sjsg 		return ADLP_PORTTC_PLL_ENABLE(tc_port);
2115ca02815Sjsg 
2125ca02815Sjsg 	return MG_PLL_ENABLE(tc_port);
2135ca02815Sjsg }
2145ca02815Sjsg 
215c349dbc7Sjsg /**
216c349dbc7Sjsg  * intel_enable_shared_dpll - enable a CRTC's shared DPLL
217c349dbc7Sjsg  * @crtc_state: CRTC, and its state, which has a shared DPLL
218c349dbc7Sjsg  *
219c349dbc7Sjsg  * Enable the shared DPLL used by @crtc.
220c349dbc7Sjsg  */
221c349dbc7Sjsg void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state)
222c349dbc7Sjsg {
223c349dbc7Sjsg 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
224c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
225c349dbc7Sjsg 	struct intel_shared_dpll *pll = crtc_state->shared_dpll;
2265ca02815Sjsg 	unsigned int pipe_mask = BIT(crtc->pipe);
227c349dbc7Sjsg 	unsigned int old_mask;
228c349dbc7Sjsg 
229c349dbc7Sjsg 	if (drm_WARN_ON(&dev_priv->drm, pll == NULL))
230c349dbc7Sjsg 		return;
231c349dbc7Sjsg 
2321bb76ff1Sjsg 	mutex_lock(&dev_priv->display.dpll.lock);
233c349dbc7Sjsg 	old_mask = pll->active_mask;
234c349dbc7Sjsg 
2355ca02815Sjsg 	if (drm_WARN_ON(&dev_priv->drm, !(pll->state.pipe_mask & pipe_mask)) ||
2365ca02815Sjsg 	    drm_WARN_ON(&dev_priv->drm, pll->active_mask & pipe_mask))
237c349dbc7Sjsg 		goto out;
238c349dbc7Sjsg 
2395ca02815Sjsg 	pll->active_mask |= pipe_mask;
240c349dbc7Sjsg 
241c349dbc7Sjsg 	drm_dbg_kms(&dev_priv->drm,
2425ca02815Sjsg 		    "enable %s (active 0x%x, on? %d) for [CRTC:%d:%s]\n",
243c349dbc7Sjsg 		    pll->info->name, pll->active_mask, pll->on,
2445ca02815Sjsg 		    crtc->base.base.id, crtc->base.name);
245c349dbc7Sjsg 
246c349dbc7Sjsg 	if (old_mask) {
247c349dbc7Sjsg 		drm_WARN_ON(&dev_priv->drm, !pll->on);
248c349dbc7Sjsg 		assert_shared_dpll_enabled(dev_priv, pll);
249c349dbc7Sjsg 		goto out;
250c349dbc7Sjsg 	}
251c349dbc7Sjsg 	drm_WARN_ON(&dev_priv->drm, pll->on);
252c349dbc7Sjsg 
253c349dbc7Sjsg 	drm_dbg_kms(&dev_priv->drm, "enabling %s\n", pll->info->name);
254c349dbc7Sjsg 	pll->info->funcs->enable(dev_priv, pll);
255c349dbc7Sjsg 	pll->on = true;
256c349dbc7Sjsg 
257c349dbc7Sjsg out:
2581bb76ff1Sjsg 	mutex_unlock(&dev_priv->display.dpll.lock);
259c349dbc7Sjsg }
260c349dbc7Sjsg 
261c349dbc7Sjsg /**
262c349dbc7Sjsg  * intel_disable_shared_dpll - disable a CRTC's shared DPLL
263c349dbc7Sjsg  * @crtc_state: CRTC, and its state, which has a shared DPLL
264c349dbc7Sjsg  *
265c349dbc7Sjsg  * Disable the shared DPLL used by @crtc.
266c349dbc7Sjsg  */
267c349dbc7Sjsg void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state)
268c349dbc7Sjsg {
269c349dbc7Sjsg 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
270c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
271c349dbc7Sjsg 	struct intel_shared_dpll *pll = crtc_state->shared_dpll;
2725ca02815Sjsg 	unsigned int pipe_mask = BIT(crtc->pipe);
273c349dbc7Sjsg 
274c349dbc7Sjsg 	/* PCH only available on ILK+ */
2755ca02815Sjsg 	if (DISPLAY_VER(dev_priv) < 5)
276c349dbc7Sjsg 		return;
277c349dbc7Sjsg 
278c349dbc7Sjsg 	if (pll == NULL)
279c349dbc7Sjsg 		return;
280c349dbc7Sjsg 
2811bb76ff1Sjsg 	mutex_lock(&dev_priv->display.dpll.lock);
2825ca02815Sjsg 	if (drm_WARN(&dev_priv->drm, !(pll->active_mask & pipe_mask),
2835ca02815Sjsg 		     "%s not used by [CRTC:%d:%s]\n", pll->info->name,
2845ca02815Sjsg 		     crtc->base.base.id, crtc->base.name))
285c349dbc7Sjsg 		goto out;
286c349dbc7Sjsg 
287c349dbc7Sjsg 	drm_dbg_kms(&dev_priv->drm,
2885ca02815Sjsg 		    "disable %s (active 0x%x, on? %d) for [CRTC:%d:%s]\n",
289c349dbc7Sjsg 		    pll->info->name, pll->active_mask, pll->on,
2905ca02815Sjsg 		    crtc->base.base.id, crtc->base.name);
291c349dbc7Sjsg 
292c349dbc7Sjsg 	assert_shared_dpll_enabled(dev_priv, pll);
293c349dbc7Sjsg 	drm_WARN_ON(&dev_priv->drm, !pll->on);
294c349dbc7Sjsg 
2955ca02815Sjsg 	pll->active_mask &= ~pipe_mask;
296c349dbc7Sjsg 	if (pll->active_mask)
297c349dbc7Sjsg 		goto out;
298c349dbc7Sjsg 
299c349dbc7Sjsg 	drm_dbg_kms(&dev_priv->drm, "disabling %s\n", pll->info->name);
300c349dbc7Sjsg 	pll->info->funcs->disable(dev_priv, pll);
301c349dbc7Sjsg 	pll->on = false;
302c349dbc7Sjsg 
303c349dbc7Sjsg out:
3041bb76ff1Sjsg 	mutex_unlock(&dev_priv->display.dpll.lock);
305c349dbc7Sjsg }
306c349dbc7Sjsg 
307c349dbc7Sjsg static struct intel_shared_dpll *
308c349dbc7Sjsg intel_find_shared_dpll(struct intel_atomic_state *state,
309c349dbc7Sjsg 		       const struct intel_crtc *crtc,
310c349dbc7Sjsg 		       const struct intel_dpll_hw_state *pll_state,
311c349dbc7Sjsg 		       unsigned long dpll_mask)
312c349dbc7Sjsg {
313c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
314c349dbc7Sjsg 	struct intel_shared_dpll *pll, *unused_pll = NULL;
315c349dbc7Sjsg 	struct intel_shared_dpll_state *shared_dpll;
316c349dbc7Sjsg 	enum intel_dpll_id i;
317c349dbc7Sjsg 
318c349dbc7Sjsg 	shared_dpll = intel_atomic_get_shared_dpll_state(&state->base);
319c349dbc7Sjsg 
320c349dbc7Sjsg 	drm_WARN_ON(&dev_priv->drm, dpll_mask & ~(BIT(I915_NUM_PLLS) - 1));
321c349dbc7Sjsg 
322c349dbc7Sjsg 	for_each_set_bit(i, &dpll_mask, I915_NUM_PLLS) {
3231bb76ff1Sjsg 		pll = &dev_priv->display.dpll.shared_dplls[i];
324c349dbc7Sjsg 
325c349dbc7Sjsg 		/* Only want to check enabled timings first */
3265ca02815Sjsg 		if (shared_dpll[i].pipe_mask == 0) {
327c349dbc7Sjsg 			if (!unused_pll)
328c349dbc7Sjsg 				unused_pll = pll;
329c349dbc7Sjsg 			continue;
330c349dbc7Sjsg 		}
331c349dbc7Sjsg 
332c349dbc7Sjsg 		if (memcmp(pll_state,
333c349dbc7Sjsg 			   &shared_dpll[i].hw_state,
334c349dbc7Sjsg 			   sizeof(*pll_state)) == 0) {
335c349dbc7Sjsg 			drm_dbg_kms(&dev_priv->drm,
3365ca02815Sjsg 				    "[CRTC:%d:%s] sharing existing %s (pipe mask 0x%x, active 0x%x)\n",
337c349dbc7Sjsg 				    crtc->base.base.id, crtc->base.name,
338c349dbc7Sjsg 				    pll->info->name,
3395ca02815Sjsg 				    shared_dpll[i].pipe_mask,
340c349dbc7Sjsg 				    pll->active_mask);
341c349dbc7Sjsg 			return pll;
342c349dbc7Sjsg 		}
343c349dbc7Sjsg 	}
344c349dbc7Sjsg 
345c349dbc7Sjsg 	/* Ok no matching timings, maybe there's a free one? */
346c349dbc7Sjsg 	if (unused_pll) {
347c349dbc7Sjsg 		drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] allocated %s\n",
348c349dbc7Sjsg 			    crtc->base.base.id, crtc->base.name,
349c349dbc7Sjsg 			    unused_pll->info->name);
350c349dbc7Sjsg 		return unused_pll;
351c349dbc7Sjsg 	}
352c349dbc7Sjsg 
353c349dbc7Sjsg 	return NULL;
354c349dbc7Sjsg }
355c349dbc7Sjsg 
356f005ef32Sjsg /**
357f005ef32Sjsg  * intel_reference_shared_dpll_crtc - Get a DPLL reference for a CRTC
358f005ef32Sjsg  * @crtc: CRTC on which behalf the reference is taken
359f005ef32Sjsg  * @pll: DPLL for which the reference is taken
360f005ef32Sjsg  * @shared_dpll_state: the DPLL atomic state in which the reference is tracked
361f005ef32Sjsg  *
362f005ef32Sjsg  * Take a reference for @pll tracking the use of it by @crtc.
363f005ef32Sjsg  */
364f005ef32Sjsg static void
365f005ef32Sjsg intel_reference_shared_dpll_crtc(const struct intel_crtc *crtc,
366f005ef32Sjsg 				 const struct intel_shared_dpll *pll,
367f005ef32Sjsg 				 struct intel_shared_dpll_state *shared_dpll_state)
368f005ef32Sjsg {
369f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(crtc->base.dev);
370f005ef32Sjsg 
371f005ef32Sjsg 	drm_WARN_ON(&i915->drm, (shared_dpll_state->pipe_mask & BIT(crtc->pipe)) != 0);
372f005ef32Sjsg 
373f005ef32Sjsg 	shared_dpll_state->pipe_mask |= BIT(crtc->pipe);
374f005ef32Sjsg 
375f005ef32Sjsg 	drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] reserving %s\n",
376f005ef32Sjsg 		    crtc->base.base.id, crtc->base.name, pll->info->name);
377f005ef32Sjsg }
378f005ef32Sjsg 
379c349dbc7Sjsg static void
380c349dbc7Sjsg intel_reference_shared_dpll(struct intel_atomic_state *state,
381c349dbc7Sjsg 			    const struct intel_crtc *crtc,
382c349dbc7Sjsg 			    const struct intel_shared_dpll *pll,
383c349dbc7Sjsg 			    const struct intel_dpll_hw_state *pll_state)
384c349dbc7Sjsg {
385c349dbc7Sjsg 	struct intel_shared_dpll_state *shared_dpll;
386c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
387c349dbc7Sjsg 
388c349dbc7Sjsg 	shared_dpll = intel_atomic_get_shared_dpll_state(&state->base);
389c349dbc7Sjsg 
3905ca02815Sjsg 	if (shared_dpll[id].pipe_mask == 0)
391c349dbc7Sjsg 		shared_dpll[id].hw_state = *pll_state;
392c349dbc7Sjsg 
393f005ef32Sjsg 	intel_reference_shared_dpll_crtc(crtc, pll, &shared_dpll[id]);
394f005ef32Sjsg }
395c349dbc7Sjsg 
396f005ef32Sjsg /**
397f005ef32Sjsg  * intel_unreference_shared_dpll_crtc - Drop a DPLL reference for a CRTC
398f005ef32Sjsg  * @crtc: CRTC on which behalf the reference is dropped
399f005ef32Sjsg  * @pll: DPLL for which the reference is dropped
400f005ef32Sjsg  * @shared_dpll_state: the DPLL atomic state in which the reference is tracked
401f005ef32Sjsg  *
402f005ef32Sjsg  * Drop a reference for @pll tracking the end of use of it by @crtc.
403f005ef32Sjsg  */
404f005ef32Sjsg void
405f005ef32Sjsg intel_unreference_shared_dpll_crtc(const struct intel_crtc *crtc,
406f005ef32Sjsg 				   const struct intel_shared_dpll *pll,
407f005ef32Sjsg 				   struct intel_shared_dpll_state *shared_dpll_state)
408f005ef32Sjsg {
409f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(crtc->base.dev);
410f005ef32Sjsg 
411f005ef32Sjsg 	drm_WARN_ON(&i915->drm, (shared_dpll_state->pipe_mask & BIT(crtc->pipe)) == 0);
412f005ef32Sjsg 
413f005ef32Sjsg 	shared_dpll_state->pipe_mask &= ~BIT(crtc->pipe);
414f005ef32Sjsg 
415f005ef32Sjsg 	drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] releasing %s\n",
416f005ef32Sjsg 		    crtc->base.base.id, crtc->base.name, pll->info->name);
417c349dbc7Sjsg }
418c349dbc7Sjsg 
419c349dbc7Sjsg static void intel_unreference_shared_dpll(struct intel_atomic_state *state,
420c349dbc7Sjsg 					  const struct intel_crtc *crtc,
421c349dbc7Sjsg 					  const struct intel_shared_dpll *pll)
422c349dbc7Sjsg {
423c349dbc7Sjsg 	struct intel_shared_dpll_state *shared_dpll;
424f005ef32Sjsg 	const enum intel_dpll_id id = pll->info->id;
425c349dbc7Sjsg 
426c349dbc7Sjsg 	shared_dpll = intel_atomic_get_shared_dpll_state(&state->base);
427f005ef32Sjsg 
428f005ef32Sjsg 	intel_unreference_shared_dpll_crtc(crtc, pll, &shared_dpll[id]);
429c349dbc7Sjsg }
430c349dbc7Sjsg 
431c349dbc7Sjsg static void intel_put_dpll(struct intel_atomic_state *state,
432c349dbc7Sjsg 			   struct intel_crtc *crtc)
433c349dbc7Sjsg {
434c349dbc7Sjsg 	const struct intel_crtc_state *old_crtc_state =
435c349dbc7Sjsg 		intel_atomic_get_old_crtc_state(state, crtc);
436c349dbc7Sjsg 	struct intel_crtc_state *new_crtc_state =
437c349dbc7Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
438c349dbc7Sjsg 
439c349dbc7Sjsg 	new_crtc_state->shared_dpll = NULL;
440c349dbc7Sjsg 
441c349dbc7Sjsg 	if (!old_crtc_state->shared_dpll)
442c349dbc7Sjsg 		return;
443c349dbc7Sjsg 
444c349dbc7Sjsg 	intel_unreference_shared_dpll(state, crtc, old_crtc_state->shared_dpll);
445c349dbc7Sjsg }
446c349dbc7Sjsg 
447c349dbc7Sjsg /**
448c349dbc7Sjsg  * intel_shared_dpll_swap_state - make atomic DPLL configuration effective
449c349dbc7Sjsg  * @state: atomic state
450c349dbc7Sjsg  *
451c349dbc7Sjsg  * This is the dpll version of drm_atomic_helper_swap_state() since the
452c349dbc7Sjsg  * helper does not handle driver-specific global state.
453c349dbc7Sjsg  *
454c349dbc7Sjsg  * For consistency with atomic helpers this function does a complete swap,
455c349dbc7Sjsg  * i.e. it also puts the current state into @state, even though there is no
456c349dbc7Sjsg  * need for that at this moment.
457c349dbc7Sjsg  */
458c349dbc7Sjsg void intel_shared_dpll_swap_state(struct intel_atomic_state *state)
459c349dbc7Sjsg {
460c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
461c349dbc7Sjsg 	struct intel_shared_dpll_state *shared_dpll = state->shared_dpll;
462c349dbc7Sjsg 	enum intel_dpll_id i;
463c349dbc7Sjsg 
464c349dbc7Sjsg 	if (!state->dpll_set)
465c349dbc7Sjsg 		return;
466c349dbc7Sjsg 
4671bb76ff1Sjsg 	for (i = 0; i < dev_priv->display.dpll.num_shared_dpll; i++) {
468c349dbc7Sjsg 		struct intel_shared_dpll *pll =
4691bb76ff1Sjsg 			&dev_priv->display.dpll.shared_dplls[i];
470c349dbc7Sjsg 
471c349dbc7Sjsg 		swap(pll->state, shared_dpll[i]);
472c349dbc7Sjsg 	}
473c349dbc7Sjsg }
474c349dbc7Sjsg 
475c349dbc7Sjsg static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
476c349dbc7Sjsg 				      struct intel_shared_dpll *pll,
477c349dbc7Sjsg 				      struct intel_dpll_hw_state *hw_state)
478c349dbc7Sjsg {
479c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
480c349dbc7Sjsg 	intel_wakeref_t wakeref;
481c349dbc7Sjsg 	u32 val;
482c349dbc7Sjsg 
483c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv,
484c349dbc7Sjsg 						     POWER_DOMAIN_DISPLAY_CORE);
485c349dbc7Sjsg 	if (!wakeref)
486c349dbc7Sjsg 		return false;
487c349dbc7Sjsg 
488c349dbc7Sjsg 	val = intel_de_read(dev_priv, PCH_DPLL(id));
489c349dbc7Sjsg 	hw_state->dpll = val;
490c349dbc7Sjsg 	hw_state->fp0 = intel_de_read(dev_priv, PCH_FP0(id));
491c349dbc7Sjsg 	hw_state->fp1 = intel_de_read(dev_priv, PCH_FP1(id));
492c349dbc7Sjsg 
493c349dbc7Sjsg 	intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref);
494c349dbc7Sjsg 
495c349dbc7Sjsg 	return val & DPLL_VCO_ENABLE;
496c349dbc7Sjsg }
497c349dbc7Sjsg 
498c349dbc7Sjsg static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
499c349dbc7Sjsg {
500c349dbc7Sjsg 	u32 val;
501c349dbc7Sjsg 	bool enabled;
502c349dbc7Sjsg 
503c349dbc7Sjsg 	val = intel_de_read(dev_priv, PCH_DREF_CONTROL);
504c349dbc7Sjsg 	enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
505c349dbc7Sjsg 			    DREF_SUPERSPREAD_SOURCE_MASK));
506f005ef32Sjsg 	I915_STATE_WARN(dev_priv, !enabled,
507f005ef32Sjsg 			"PCH refclk assertion failure, should be active but is disabled\n");
508c349dbc7Sjsg }
509c349dbc7Sjsg 
510c349dbc7Sjsg static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
511c349dbc7Sjsg 				struct intel_shared_dpll *pll)
512c349dbc7Sjsg {
513c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
514c349dbc7Sjsg 
515c349dbc7Sjsg 	/* PCH refclock must be enabled first */
516c349dbc7Sjsg 	ibx_assert_pch_refclk_enabled(dev_priv);
517c349dbc7Sjsg 
5181bb76ff1Sjsg 	intel_de_write(dev_priv, PCH_FP0(id), pll->state.hw_state.fp0);
5191bb76ff1Sjsg 	intel_de_write(dev_priv, PCH_FP1(id), pll->state.hw_state.fp1);
5201bb76ff1Sjsg 
521c349dbc7Sjsg 	intel_de_write(dev_priv, PCH_DPLL(id), pll->state.hw_state.dpll);
522c349dbc7Sjsg 
523c349dbc7Sjsg 	/* Wait for the clocks to stabilize. */
524c349dbc7Sjsg 	intel_de_posting_read(dev_priv, PCH_DPLL(id));
525c349dbc7Sjsg 	udelay(150);
526c349dbc7Sjsg 
527c349dbc7Sjsg 	/* The pixel multiplier can only be updated once the
528c349dbc7Sjsg 	 * DPLL is enabled and the clocks are stable.
529c349dbc7Sjsg 	 *
530c349dbc7Sjsg 	 * So write it again.
531c349dbc7Sjsg 	 */
532c349dbc7Sjsg 	intel_de_write(dev_priv, PCH_DPLL(id), pll->state.hw_state.dpll);
533c349dbc7Sjsg 	intel_de_posting_read(dev_priv, PCH_DPLL(id));
534c349dbc7Sjsg 	udelay(200);
535c349dbc7Sjsg }
536c349dbc7Sjsg 
537c349dbc7Sjsg static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
538c349dbc7Sjsg 				 struct intel_shared_dpll *pll)
539c349dbc7Sjsg {
540c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
541c349dbc7Sjsg 
542c349dbc7Sjsg 	intel_de_write(dev_priv, PCH_DPLL(id), 0);
543c349dbc7Sjsg 	intel_de_posting_read(dev_priv, PCH_DPLL(id));
544c349dbc7Sjsg 	udelay(200);
545c349dbc7Sjsg }
546c349dbc7Sjsg 
5471bb76ff1Sjsg static int ibx_compute_dpll(struct intel_atomic_state *state,
5481bb76ff1Sjsg 			    struct intel_crtc *crtc,
5491bb76ff1Sjsg 			    struct intel_encoder *encoder)
5501bb76ff1Sjsg {
5511bb76ff1Sjsg 	return 0;
5521bb76ff1Sjsg }
5531bb76ff1Sjsg 
5541bb76ff1Sjsg static int ibx_get_dpll(struct intel_atomic_state *state,
555c349dbc7Sjsg 			struct intel_crtc *crtc,
556c349dbc7Sjsg 			struct intel_encoder *encoder)
557c349dbc7Sjsg {
558c349dbc7Sjsg 	struct intel_crtc_state *crtc_state =
559c349dbc7Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
560c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
561c349dbc7Sjsg 	struct intel_shared_dpll *pll;
562c349dbc7Sjsg 	enum intel_dpll_id i;
563c349dbc7Sjsg 
564c349dbc7Sjsg 	if (HAS_PCH_IBX(dev_priv)) {
565c349dbc7Sjsg 		/* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
566c349dbc7Sjsg 		i = (enum intel_dpll_id) crtc->pipe;
5671bb76ff1Sjsg 		pll = &dev_priv->display.dpll.shared_dplls[i];
568c349dbc7Sjsg 
569c349dbc7Sjsg 		drm_dbg_kms(&dev_priv->drm,
570c349dbc7Sjsg 			    "[CRTC:%d:%s] using pre-allocated %s\n",
571c349dbc7Sjsg 			    crtc->base.base.id, crtc->base.name,
572c349dbc7Sjsg 			    pll->info->name);
573c349dbc7Sjsg 	} else {
574c349dbc7Sjsg 		pll = intel_find_shared_dpll(state, crtc,
575c349dbc7Sjsg 					     &crtc_state->dpll_hw_state,
576c349dbc7Sjsg 					     BIT(DPLL_ID_PCH_PLL_B) |
577c349dbc7Sjsg 					     BIT(DPLL_ID_PCH_PLL_A));
578c349dbc7Sjsg 	}
579c349dbc7Sjsg 
580c349dbc7Sjsg 	if (!pll)
5811bb76ff1Sjsg 		return -EINVAL;
582c349dbc7Sjsg 
583c349dbc7Sjsg 	/* reference the pll */
584c349dbc7Sjsg 	intel_reference_shared_dpll(state, crtc,
585c349dbc7Sjsg 				    pll, &crtc_state->dpll_hw_state);
586c349dbc7Sjsg 
587c349dbc7Sjsg 	crtc_state->shared_dpll = pll;
588c349dbc7Sjsg 
5891bb76ff1Sjsg 	return 0;
590c349dbc7Sjsg }
591c349dbc7Sjsg 
592c349dbc7Sjsg static void ibx_dump_hw_state(struct drm_i915_private *dev_priv,
593c349dbc7Sjsg 			      const struct intel_dpll_hw_state *hw_state)
594c349dbc7Sjsg {
595c349dbc7Sjsg 	drm_dbg_kms(&dev_priv->drm,
596c349dbc7Sjsg 		    "dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
597c349dbc7Sjsg 		    "fp0: 0x%x, fp1: 0x%x\n",
598c349dbc7Sjsg 		    hw_state->dpll,
599c349dbc7Sjsg 		    hw_state->dpll_md,
600c349dbc7Sjsg 		    hw_state->fp0,
601c349dbc7Sjsg 		    hw_state->fp1);
602c349dbc7Sjsg }
603c349dbc7Sjsg 
604c349dbc7Sjsg static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
605c349dbc7Sjsg 	.enable = ibx_pch_dpll_enable,
606c349dbc7Sjsg 	.disable = ibx_pch_dpll_disable,
607c349dbc7Sjsg 	.get_hw_state = ibx_pch_dpll_get_hw_state,
608c349dbc7Sjsg };
609c349dbc7Sjsg 
610c349dbc7Sjsg static const struct dpll_info pch_plls[] = {
611c349dbc7Sjsg 	{ "PCH DPLL A", &ibx_pch_dpll_funcs, DPLL_ID_PCH_PLL_A, 0 },
612c349dbc7Sjsg 	{ "PCH DPLL B", &ibx_pch_dpll_funcs, DPLL_ID_PCH_PLL_B, 0 },
613c349dbc7Sjsg 	{ },
614c349dbc7Sjsg };
615c349dbc7Sjsg 
616c349dbc7Sjsg static const struct intel_dpll_mgr pch_pll_mgr = {
617c349dbc7Sjsg 	.dpll_info = pch_plls,
6181bb76ff1Sjsg 	.compute_dplls = ibx_compute_dpll,
619c349dbc7Sjsg 	.get_dplls = ibx_get_dpll,
620c349dbc7Sjsg 	.put_dplls = intel_put_dpll,
621c349dbc7Sjsg 	.dump_hw_state = ibx_dump_hw_state,
622c349dbc7Sjsg };
623c349dbc7Sjsg 
624c349dbc7Sjsg static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
625c349dbc7Sjsg 				 struct intel_shared_dpll *pll)
626c349dbc7Sjsg {
627c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
628c349dbc7Sjsg 
629c349dbc7Sjsg 	intel_de_write(dev_priv, WRPLL_CTL(id), pll->state.hw_state.wrpll);
630c349dbc7Sjsg 	intel_de_posting_read(dev_priv, WRPLL_CTL(id));
631c349dbc7Sjsg 	udelay(20);
632c349dbc7Sjsg }
633c349dbc7Sjsg 
634c349dbc7Sjsg static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
635c349dbc7Sjsg 				struct intel_shared_dpll *pll)
636c349dbc7Sjsg {
637c349dbc7Sjsg 	intel_de_write(dev_priv, SPLL_CTL, pll->state.hw_state.spll);
638c349dbc7Sjsg 	intel_de_posting_read(dev_priv, SPLL_CTL);
639c349dbc7Sjsg 	udelay(20);
640c349dbc7Sjsg }
641c349dbc7Sjsg 
642c349dbc7Sjsg static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
643c349dbc7Sjsg 				  struct intel_shared_dpll *pll)
644c349dbc7Sjsg {
645c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
646c349dbc7Sjsg 
647f005ef32Sjsg 	intel_de_rmw(dev_priv, WRPLL_CTL(id), WRPLL_PLL_ENABLE, 0);
648c349dbc7Sjsg 	intel_de_posting_read(dev_priv, WRPLL_CTL(id));
649c349dbc7Sjsg 
650c349dbc7Sjsg 	/*
651c349dbc7Sjsg 	 * Try to set up the PCH reference clock once all DPLLs
652c349dbc7Sjsg 	 * that depend on it have been shut down.
653c349dbc7Sjsg 	 */
654f005ef32Sjsg 	if (dev_priv->display.dpll.pch_ssc_use & BIT(id))
655c349dbc7Sjsg 		intel_init_pch_refclk(dev_priv);
656c349dbc7Sjsg }
657c349dbc7Sjsg 
658c349dbc7Sjsg static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
659c349dbc7Sjsg 				 struct intel_shared_dpll *pll)
660c349dbc7Sjsg {
661c349dbc7Sjsg 	enum intel_dpll_id id = pll->info->id;
662c349dbc7Sjsg 
663f005ef32Sjsg 	intel_de_rmw(dev_priv, SPLL_CTL, SPLL_PLL_ENABLE, 0);
664c349dbc7Sjsg 	intel_de_posting_read(dev_priv, SPLL_CTL);
665c349dbc7Sjsg 
666c349dbc7Sjsg 	/*
667c349dbc7Sjsg 	 * Try to set up the PCH reference clock once all DPLLs
668c349dbc7Sjsg 	 * that depend on it have been shut down.
669c349dbc7Sjsg 	 */
670f005ef32Sjsg 	if (dev_priv->display.dpll.pch_ssc_use & BIT(id))
671c349dbc7Sjsg 		intel_init_pch_refclk(dev_priv);
672c349dbc7Sjsg }
673c349dbc7Sjsg 
674c349dbc7Sjsg static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
675c349dbc7Sjsg 				       struct intel_shared_dpll *pll,
676c349dbc7Sjsg 				       struct intel_dpll_hw_state *hw_state)
677c349dbc7Sjsg {
678c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
679c349dbc7Sjsg 	intel_wakeref_t wakeref;
680c349dbc7Sjsg 	u32 val;
681c349dbc7Sjsg 
682c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv,
683c349dbc7Sjsg 						     POWER_DOMAIN_DISPLAY_CORE);
684c349dbc7Sjsg 	if (!wakeref)
685c349dbc7Sjsg 		return false;
686c349dbc7Sjsg 
687c349dbc7Sjsg 	val = intel_de_read(dev_priv, WRPLL_CTL(id));
688c349dbc7Sjsg 	hw_state->wrpll = val;
689c349dbc7Sjsg 
690c349dbc7Sjsg 	intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref);
691c349dbc7Sjsg 
692c349dbc7Sjsg 	return val & WRPLL_PLL_ENABLE;
693c349dbc7Sjsg }
694c349dbc7Sjsg 
695c349dbc7Sjsg static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
696c349dbc7Sjsg 				      struct intel_shared_dpll *pll,
697c349dbc7Sjsg 				      struct intel_dpll_hw_state *hw_state)
698c349dbc7Sjsg {
699c349dbc7Sjsg 	intel_wakeref_t wakeref;
700c349dbc7Sjsg 	u32 val;
701c349dbc7Sjsg 
702c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv,
703c349dbc7Sjsg 						     POWER_DOMAIN_DISPLAY_CORE);
704c349dbc7Sjsg 	if (!wakeref)
705c349dbc7Sjsg 		return false;
706c349dbc7Sjsg 
707c349dbc7Sjsg 	val = intel_de_read(dev_priv, SPLL_CTL);
708c349dbc7Sjsg 	hw_state->spll = val;
709c349dbc7Sjsg 
710c349dbc7Sjsg 	intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref);
711c349dbc7Sjsg 
712c349dbc7Sjsg 	return val & SPLL_PLL_ENABLE;
713c349dbc7Sjsg }
714c349dbc7Sjsg 
715c349dbc7Sjsg #define LC_FREQ 2700
716c349dbc7Sjsg #define LC_FREQ_2K U64_C(LC_FREQ * 2000)
717c349dbc7Sjsg 
718c349dbc7Sjsg #define P_MIN 2
719c349dbc7Sjsg #define P_MAX 64
720c349dbc7Sjsg #define P_INC 2
721c349dbc7Sjsg 
722c349dbc7Sjsg /* Constraints for PLL good behavior */
723c349dbc7Sjsg #define REF_MIN 48
724c349dbc7Sjsg #define REF_MAX 400
725c349dbc7Sjsg #define VCO_MIN 2400
726c349dbc7Sjsg #define VCO_MAX 4800
727c349dbc7Sjsg 
728c349dbc7Sjsg struct hsw_wrpll_rnp {
729c349dbc7Sjsg 	unsigned p, n2, r2;
730c349dbc7Sjsg };
731c349dbc7Sjsg 
732c349dbc7Sjsg static unsigned hsw_wrpll_get_budget_for_freq(int clock)
733c349dbc7Sjsg {
734c349dbc7Sjsg 	switch (clock) {
735c349dbc7Sjsg 	case 25175000:
736c349dbc7Sjsg 	case 25200000:
737c349dbc7Sjsg 	case 27000000:
738c349dbc7Sjsg 	case 27027000:
739c349dbc7Sjsg 	case 37762500:
740c349dbc7Sjsg 	case 37800000:
741c349dbc7Sjsg 	case 40500000:
742c349dbc7Sjsg 	case 40541000:
743c349dbc7Sjsg 	case 54000000:
744c349dbc7Sjsg 	case 54054000:
745c349dbc7Sjsg 	case 59341000:
746c349dbc7Sjsg 	case 59400000:
747c349dbc7Sjsg 	case 72000000:
748c349dbc7Sjsg 	case 74176000:
749c349dbc7Sjsg 	case 74250000:
750c349dbc7Sjsg 	case 81000000:
751c349dbc7Sjsg 	case 81081000:
752c349dbc7Sjsg 	case 89012000:
753c349dbc7Sjsg 	case 89100000:
754c349dbc7Sjsg 	case 108000000:
755c349dbc7Sjsg 	case 108108000:
756c349dbc7Sjsg 	case 111264000:
757c349dbc7Sjsg 	case 111375000:
758c349dbc7Sjsg 	case 148352000:
759c349dbc7Sjsg 	case 148500000:
760c349dbc7Sjsg 	case 162000000:
761c349dbc7Sjsg 	case 162162000:
762c349dbc7Sjsg 	case 222525000:
763c349dbc7Sjsg 	case 222750000:
764c349dbc7Sjsg 	case 296703000:
765c349dbc7Sjsg 	case 297000000:
766f005ef32Sjsg 		return 0;
767c349dbc7Sjsg 	case 233500000:
768c349dbc7Sjsg 	case 245250000:
769c349dbc7Sjsg 	case 247750000:
770c349dbc7Sjsg 	case 253250000:
771c349dbc7Sjsg 	case 298000000:
772f005ef32Sjsg 		return 1500;
773c349dbc7Sjsg 	case 169128000:
774c349dbc7Sjsg 	case 169500000:
775c349dbc7Sjsg 	case 179500000:
776c349dbc7Sjsg 	case 202000000:
777f005ef32Sjsg 		return 2000;
778c349dbc7Sjsg 	case 256250000:
779c349dbc7Sjsg 	case 262500000:
780c349dbc7Sjsg 	case 270000000:
781c349dbc7Sjsg 	case 272500000:
782c349dbc7Sjsg 	case 273750000:
783c349dbc7Sjsg 	case 280750000:
784c349dbc7Sjsg 	case 281250000:
785c349dbc7Sjsg 	case 286000000:
786c349dbc7Sjsg 	case 291750000:
787f005ef32Sjsg 		return 4000;
788c349dbc7Sjsg 	case 267250000:
789c349dbc7Sjsg 	case 268500000:
790f005ef32Sjsg 		return 5000;
791c349dbc7Sjsg 	default:
792f005ef32Sjsg 		return 1000;
793c349dbc7Sjsg 	}
794c349dbc7Sjsg }
795c349dbc7Sjsg 
796c349dbc7Sjsg static void hsw_wrpll_update_rnp(u64 freq2k, unsigned int budget,
797c349dbc7Sjsg 				 unsigned int r2, unsigned int n2,
798c349dbc7Sjsg 				 unsigned int p,
799c349dbc7Sjsg 				 struct hsw_wrpll_rnp *best)
800c349dbc7Sjsg {
801c349dbc7Sjsg 	u64 a, b, c, d, diff, diff_best;
802c349dbc7Sjsg 
803c349dbc7Sjsg 	/* No best (r,n,p) yet */
804c349dbc7Sjsg 	if (best->p == 0) {
805c349dbc7Sjsg 		best->p = p;
806c349dbc7Sjsg 		best->n2 = n2;
807c349dbc7Sjsg 		best->r2 = r2;
808c349dbc7Sjsg 		return;
809c349dbc7Sjsg 	}
810c349dbc7Sjsg 
811c349dbc7Sjsg 	/*
812c349dbc7Sjsg 	 * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
813c349dbc7Sjsg 	 * freq2k.
814c349dbc7Sjsg 	 *
815c349dbc7Sjsg 	 * delta = 1e6 *
816c349dbc7Sjsg 	 *	   abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
817c349dbc7Sjsg 	 *	   freq2k;
818c349dbc7Sjsg 	 *
819c349dbc7Sjsg 	 * and we would like delta <= budget.
820c349dbc7Sjsg 	 *
821c349dbc7Sjsg 	 * If the discrepancy is above the PPM-based budget, always prefer to
822c349dbc7Sjsg 	 * improve upon the previous solution.  However, if you're within the
823c349dbc7Sjsg 	 * budget, try to maximize Ref * VCO, that is N / (P * R^2).
824c349dbc7Sjsg 	 */
825c349dbc7Sjsg 	a = freq2k * budget * p * r2;
826c349dbc7Sjsg 	b = freq2k * budget * best->p * best->r2;
827c349dbc7Sjsg 	diff = abs_diff(freq2k * p * r2, LC_FREQ_2K * n2);
828c349dbc7Sjsg 	diff_best = abs_diff(freq2k * best->p * best->r2,
829c349dbc7Sjsg 			     LC_FREQ_2K * best->n2);
830c349dbc7Sjsg 	c = 1000000 * diff;
831c349dbc7Sjsg 	d = 1000000 * diff_best;
832c349dbc7Sjsg 
833c349dbc7Sjsg 	if (a < c && b < d) {
834c349dbc7Sjsg 		/* If both are above the budget, pick the closer */
835c349dbc7Sjsg 		if (best->p * best->r2 * diff < p * r2 * diff_best) {
836c349dbc7Sjsg 			best->p = p;
837c349dbc7Sjsg 			best->n2 = n2;
838c349dbc7Sjsg 			best->r2 = r2;
839c349dbc7Sjsg 		}
840c349dbc7Sjsg 	} else if (a >= c && b < d) {
841c349dbc7Sjsg 		/* If A is below the threshold but B is above it?  Update. */
842c349dbc7Sjsg 		best->p = p;
843c349dbc7Sjsg 		best->n2 = n2;
844c349dbc7Sjsg 		best->r2 = r2;
845c349dbc7Sjsg 	} else if (a >= c && b >= d) {
846c349dbc7Sjsg 		/* Both are below the limit, so pick the higher n2/(r2*r2) */
847c349dbc7Sjsg 		if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) {
848c349dbc7Sjsg 			best->p = p;
849c349dbc7Sjsg 			best->n2 = n2;
850c349dbc7Sjsg 			best->r2 = r2;
851c349dbc7Sjsg 		}
852c349dbc7Sjsg 	}
853c349dbc7Sjsg 	/* Otherwise a < c && b >= d, do nothing */
854c349dbc7Sjsg }
855c349dbc7Sjsg 
856c349dbc7Sjsg static void
857c349dbc7Sjsg hsw_ddi_calculate_wrpll(int clock /* in Hz */,
858c349dbc7Sjsg 			unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
859c349dbc7Sjsg {
860c349dbc7Sjsg 	u64 freq2k;
861c349dbc7Sjsg 	unsigned p, n2, r2;
8621bb76ff1Sjsg 	struct hsw_wrpll_rnp best = {};
863c349dbc7Sjsg 	unsigned budget;
864c349dbc7Sjsg 
865c349dbc7Sjsg 	freq2k = clock / 100;
866c349dbc7Sjsg 
867c349dbc7Sjsg 	budget = hsw_wrpll_get_budget_for_freq(clock);
868c349dbc7Sjsg 
869c349dbc7Sjsg 	/* Special case handling for 540 pixel clock: bypass WR PLL entirely
870c349dbc7Sjsg 	 * and directly pass the LC PLL to it. */
871c349dbc7Sjsg 	if (freq2k == 5400000) {
872c349dbc7Sjsg 		*n2_out = 2;
873c349dbc7Sjsg 		*p_out = 1;
874c349dbc7Sjsg 		*r2_out = 2;
875c349dbc7Sjsg 		return;
876c349dbc7Sjsg 	}
877c349dbc7Sjsg 
878c349dbc7Sjsg 	/*
879c349dbc7Sjsg 	 * Ref = LC_FREQ / R, where Ref is the actual reference input seen by
880c349dbc7Sjsg 	 * the WR PLL.
881c349dbc7Sjsg 	 *
882c349dbc7Sjsg 	 * We want R so that REF_MIN <= Ref <= REF_MAX.
883c349dbc7Sjsg 	 * Injecting R2 = 2 * R gives:
884c349dbc7Sjsg 	 *   REF_MAX * r2 > LC_FREQ * 2 and
885c349dbc7Sjsg 	 *   REF_MIN * r2 < LC_FREQ * 2
886c349dbc7Sjsg 	 *
887c349dbc7Sjsg 	 * Which means the desired boundaries for r2 are:
888c349dbc7Sjsg 	 *  LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
889c349dbc7Sjsg 	 *
890c349dbc7Sjsg 	 */
891c349dbc7Sjsg 	for (r2 = LC_FREQ * 2 / REF_MAX + 1;
892c349dbc7Sjsg 	     r2 <= LC_FREQ * 2 / REF_MIN;
893c349dbc7Sjsg 	     r2++) {
894c349dbc7Sjsg 
895c349dbc7Sjsg 		/*
896c349dbc7Sjsg 		 * VCO = N * Ref, that is: VCO = N * LC_FREQ / R
897c349dbc7Sjsg 		 *
898c349dbc7Sjsg 		 * Once again we want VCO_MIN <= VCO <= VCO_MAX.
899c349dbc7Sjsg 		 * Injecting R2 = 2 * R and N2 = 2 * N, we get:
900c349dbc7Sjsg 		 *   VCO_MAX * r2 > n2 * LC_FREQ and
901c349dbc7Sjsg 		 *   VCO_MIN * r2 < n2 * LC_FREQ)
902c349dbc7Sjsg 		 *
903c349dbc7Sjsg 		 * Which means the desired boundaries for n2 are:
904c349dbc7Sjsg 		 * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
905c349dbc7Sjsg 		 */
906c349dbc7Sjsg 		for (n2 = VCO_MIN * r2 / LC_FREQ + 1;
907c349dbc7Sjsg 		     n2 <= VCO_MAX * r2 / LC_FREQ;
908c349dbc7Sjsg 		     n2++) {
909c349dbc7Sjsg 
910c349dbc7Sjsg 			for (p = P_MIN; p <= P_MAX; p += P_INC)
911c349dbc7Sjsg 				hsw_wrpll_update_rnp(freq2k, budget,
912c349dbc7Sjsg 						     r2, n2, p, &best);
913c349dbc7Sjsg 		}
914c349dbc7Sjsg 	}
915c349dbc7Sjsg 
916c349dbc7Sjsg 	*n2_out = best.n2;
917c349dbc7Sjsg 	*p_out = best.p;
918c349dbc7Sjsg 	*r2_out = best.r2;
919c349dbc7Sjsg }
920c349dbc7Sjsg 
921c349dbc7Sjsg static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
9225ca02815Sjsg 				  const struct intel_shared_dpll *pll,
9235ca02815Sjsg 				  const struct intel_dpll_hw_state *pll_state)
924c349dbc7Sjsg {
925c349dbc7Sjsg 	int refclk;
926c349dbc7Sjsg 	int n, p, r;
9275ca02815Sjsg 	u32 wrpll = pll_state->wrpll;
928c349dbc7Sjsg 
929c349dbc7Sjsg 	switch (wrpll & WRPLL_REF_MASK) {
930c349dbc7Sjsg 	case WRPLL_REF_SPECIAL_HSW:
931c349dbc7Sjsg 		/* Muxed-SSC for BDW, non-SSC for non-ULT HSW. */
932f005ef32Sjsg 		if (IS_HASWELL(dev_priv) && !IS_HASWELL_ULT(dev_priv)) {
9331bb76ff1Sjsg 			refclk = dev_priv->display.dpll.ref_clks.nssc;
934c349dbc7Sjsg 			break;
935c349dbc7Sjsg 		}
936ad8b1aafSjsg 		fallthrough;
937c349dbc7Sjsg 	case WRPLL_REF_PCH_SSC:
938c349dbc7Sjsg 		/*
939c349dbc7Sjsg 		 * We could calculate spread here, but our checking
940c349dbc7Sjsg 		 * code only cares about 5% accuracy, and spread is a max of
941c349dbc7Sjsg 		 * 0.5% downspread.
942c349dbc7Sjsg 		 */
9431bb76ff1Sjsg 		refclk = dev_priv->display.dpll.ref_clks.ssc;
944c349dbc7Sjsg 		break;
945c349dbc7Sjsg 	case WRPLL_REF_LCPLL:
946c349dbc7Sjsg 		refclk = 2700000;
947c349dbc7Sjsg 		break;
948c349dbc7Sjsg 	default:
949c349dbc7Sjsg 		MISSING_CASE(wrpll);
950c349dbc7Sjsg 		return 0;
951c349dbc7Sjsg 	}
952c349dbc7Sjsg 
953c349dbc7Sjsg 	r = wrpll & WRPLL_DIVIDER_REF_MASK;
954c349dbc7Sjsg 	p = (wrpll & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT;
955c349dbc7Sjsg 	n = (wrpll & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT;
956c349dbc7Sjsg 
957c349dbc7Sjsg 	/* Convert to KHz, p & r have a fixed point portion */
958c349dbc7Sjsg 	return (refclk * n / 10) / (p * r) * 2;
959c349dbc7Sjsg }
960c349dbc7Sjsg 
9611bb76ff1Sjsg static int
9621bb76ff1Sjsg hsw_ddi_wrpll_compute_dpll(struct intel_atomic_state *state,
9631bb76ff1Sjsg 			   struct intel_crtc *crtc)
9641bb76ff1Sjsg {
9651bb76ff1Sjsg 	struct drm_i915_private *i915 = to_i915(state->base.dev);
9661bb76ff1Sjsg 	struct intel_crtc_state *crtc_state =
9671bb76ff1Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
9681bb76ff1Sjsg 	unsigned int p, n2, r2;
9691bb76ff1Sjsg 
9701bb76ff1Sjsg 	hsw_ddi_calculate_wrpll(crtc_state->port_clock * 1000, &r2, &n2, &p);
9711bb76ff1Sjsg 
9721bb76ff1Sjsg 	crtc_state->dpll_hw_state.wrpll =
9731bb76ff1Sjsg 		WRPLL_PLL_ENABLE | WRPLL_REF_LCPLL |
9741bb76ff1Sjsg 		WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
9751bb76ff1Sjsg 		WRPLL_DIVIDER_POST(p);
9761bb76ff1Sjsg 
9771bb76ff1Sjsg 	crtc_state->port_clock = hsw_ddi_wrpll_get_freq(i915, NULL,
9781bb76ff1Sjsg 							&crtc_state->dpll_hw_state);
9791bb76ff1Sjsg 
9801bb76ff1Sjsg 	return 0;
9811bb76ff1Sjsg }
9821bb76ff1Sjsg 
9831bb76ff1Sjsg static struct intel_shared_dpll *
9841bb76ff1Sjsg hsw_ddi_wrpll_get_dpll(struct intel_atomic_state *state,
9851bb76ff1Sjsg 		       struct intel_crtc *crtc)
9861bb76ff1Sjsg {
9871bb76ff1Sjsg 	struct intel_crtc_state *crtc_state =
9881bb76ff1Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
9891bb76ff1Sjsg 
9901bb76ff1Sjsg 	return intel_find_shared_dpll(state, crtc,
9911bb76ff1Sjsg 				      &crtc_state->dpll_hw_state,
9921bb76ff1Sjsg 				      BIT(DPLL_ID_WRPLL2) |
9931bb76ff1Sjsg 				      BIT(DPLL_ID_WRPLL1));
9941bb76ff1Sjsg }
9951bb76ff1Sjsg 
9961bb76ff1Sjsg static int
9971bb76ff1Sjsg hsw_ddi_lcpll_compute_dpll(struct intel_crtc_state *crtc_state)
9981bb76ff1Sjsg {
9991bb76ff1Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
10001bb76ff1Sjsg 	int clock = crtc_state->port_clock;
10011bb76ff1Sjsg 
10021bb76ff1Sjsg 	switch (clock / 2) {
10031bb76ff1Sjsg 	case 81000:
10041bb76ff1Sjsg 	case 135000:
10051bb76ff1Sjsg 	case 270000:
10061bb76ff1Sjsg 		return 0;
10071bb76ff1Sjsg 	default:
10081bb76ff1Sjsg 		drm_dbg_kms(&dev_priv->drm, "Invalid clock for DP: %d\n",
10091bb76ff1Sjsg 			    clock);
10101bb76ff1Sjsg 		return -EINVAL;
10111bb76ff1Sjsg 	}
10121bb76ff1Sjsg }
10131bb76ff1Sjsg 
1014c349dbc7Sjsg static struct intel_shared_dpll *
1015c349dbc7Sjsg hsw_ddi_lcpll_get_dpll(struct intel_crtc_state *crtc_state)
1016c349dbc7Sjsg {
1017c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
1018c349dbc7Sjsg 	struct intel_shared_dpll *pll;
1019c349dbc7Sjsg 	enum intel_dpll_id pll_id;
1020c349dbc7Sjsg 	int clock = crtc_state->port_clock;
1021c349dbc7Sjsg 
1022c349dbc7Sjsg 	switch (clock / 2) {
1023c349dbc7Sjsg 	case 81000:
1024c349dbc7Sjsg 		pll_id = DPLL_ID_LCPLL_810;
1025c349dbc7Sjsg 		break;
1026c349dbc7Sjsg 	case 135000:
1027c349dbc7Sjsg 		pll_id = DPLL_ID_LCPLL_1350;
1028c349dbc7Sjsg 		break;
1029c349dbc7Sjsg 	case 270000:
1030c349dbc7Sjsg 		pll_id = DPLL_ID_LCPLL_2700;
1031c349dbc7Sjsg 		break;
1032c349dbc7Sjsg 	default:
10331bb76ff1Sjsg 		MISSING_CASE(clock / 2);
1034c349dbc7Sjsg 		return NULL;
1035c349dbc7Sjsg 	}
1036c349dbc7Sjsg 
1037c349dbc7Sjsg 	pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
1038c349dbc7Sjsg 
1039c349dbc7Sjsg 	if (!pll)
1040c349dbc7Sjsg 		return NULL;
1041c349dbc7Sjsg 
1042c349dbc7Sjsg 	return pll;
1043c349dbc7Sjsg }
1044c349dbc7Sjsg 
1045c349dbc7Sjsg static int hsw_ddi_lcpll_get_freq(struct drm_i915_private *i915,
10465ca02815Sjsg 				  const struct intel_shared_dpll *pll,
10475ca02815Sjsg 				  const struct intel_dpll_hw_state *pll_state)
1048c349dbc7Sjsg {
1049c349dbc7Sjsg 	int link_clock = 0;
1050c349dbc7Sjsg 
1051c349dbc7Sjsg 	switch (pll->info->id) {
1052c349dbc7Sjsg 	case DPLL_ID_LCPLL_810:
1053c349dbc7Sjsg 		link_clock = 81000;
1054c349dbc7Sjsg 		break;
1055c349dbc7Sjsg 	case DPLL_ID_LCPLL_1350:
1056c349dbc7Sjsg 		link_clock = 135000;
1057c349dbc7Sjsg 		break;
1058c349dbc7Sjsg 	case DPLL_ID_LCPLL_2700:
1059c349dbc7Sjsg 		link_clock = 270000;
1060c349dbc7Sjsg 		break;
1061c349dbc7Sjsg 	default:
1062c349dbc7Sjsg 		drm_WARN(&i915->drm, 1, "bad port clock sel\n");
1063c349dbc7Sjsg 		break;
1064c349dbc7Sjsg 	}
1065c349dbc7Sjsg 
1066c349dbc7Sjsg 	return link_clock * 2;
1067c349dbc7Sjsg }
1068c349dbc7Sjsg 
10691bb76ff1Sjsg static int
10701bb76ff1Sjsg hsw_ddi_spll_compute_dpll(struct intel_atomic_state *state,
1071c349dbc7Sjsg 			  struct intel_crtc *crtc)
1072c349dbc7Sjsg {
1073c349dbc7Sjsg 	struct intel_crtc_state *crtc_state =
1074c349dbc7Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
1075c349dbc7Sjsg 
1076ad8b1aafSjsg 	if (drm_WARN_ON(crtc->base.dev, crtc_state->port_clock / 2 != 135000))
10771bb76ff1Sjsg 		return -EINVAL;
1078c349dbc7Sjsg 
10791bb76ff1Sjsg 	crtc_state->dpll_hw_state.spll =
10801bb76ff1Sjsg 		SPLL_PLL_ENABLE | SPLL_FREQ_1350MHz | SPLL_REF_MUXED_SSC;
10811bb76ff1Sjsg 
10821bb76ff1Sjsg 	return 0;
10831bb76ff1Sjsg }
10841bb76ff1Sjsg 
10851bb76ff1Sjsg static struct intel_shared_dpll *
10861bb76ff1Sjsg hsw_ddi_spll_get_dpll(struct intel_atomic_state *state,
10871bb76ff1Sjsg 		      struct intel_crtc *crtc)
10881bb76ff1Sjsg {
10891bb76ff1Sjsg 	struct intel_crtc_state *crtc_state =
10901bb76ff1Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
1091c349dbc7Sjsg 
1092c349dbc7Sjsg 	return intel_find_shared_dpll(state, crtc, &crtc_state->dpll_hw_state,
1093c349dbc7Sjsg 				      BIT(DPLL_ID_SPLL));
1094c349dbc7Sjsg }
1095c349dbc7Sjsg 
1096c349dbc7Sjsg static int hsw_ddi_spll_get_freq(struct drm_i915_private *i915,
10975ca02815Sjsg 				 const struct intel_shared_dpll *pll,
10985ca02815Sjsg 				 const struct intel_dpll_hw_state *pll_state)
1099c349dbc7Sjsg {
1100c349dbc7Sjsg 	int link_clock = 0;
1101c349dbc7Sjsg 
11025ca02815Sjsg 	switch (pll_state->spll & SPLL_FREQ_MASK) {
1103c349dbc7Sjsg 	case SPLL_FREQ_810MHz:
1104c349dbc7Sjsg 		link_clock = 81000;
1105c349dbc7Sjsg 		break;
1106c349dbc7Sjsg 	case SPLL_FREQ_1350MHz:
1107c349dbc7Sjsg 		link_clock = 135000;
1108c349dbc7Sjsg 		break;
1109c349dbc7Sjsg 	case SPLL_FREQ_2700MHz:
1110c349dbc7Sjsg 		link_clock = 270000;
1111c349dbc7Sjsg 		break;
1112c349dbc7Sjsg 	default:
1113c349dbc7Sjsg 		drm_WARN(&i915->drm, 1, "bad spll freq\n");
1114c349dbc7Sjsg 		break;
1115c349dbc7Sjsg 	}
1116c349dbc7Sjsg 
1117c349dbc7Sjsg 	return link_clock * 2;
1118c349dbc7Sjsg }
1119c349dbc7Sjsg 
11201bb76ff1Sjsg static int hsw_compute_dpll(struct intel_atomic_state *state,
1121c349dbc7Sjsg 			    struct intel_crtc *crtc,
1122c349dbc7Sjsg 			    struct intel_encoder *encoder)
1123c349dbc7Sjsg {
1124c349dbc7Sjsg 	struct intel_crtc_state *crtc_state =
1125c349dbc7Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
1126c349dbc7Sjsg 
11271bb76ff1Sjsg 	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
11281bb76ff1Sjsg 		return hsw_ddi_wrpll_compute_dpll(state, crtc);
11291bb76ff1Sjsg 	else if (intel_crtc_has_dp_encoder(crtc_state))
11301bb76ff1Sjsg 		return hsw_ddi_lcpll_compute_dpll(crtc_state);
11311bb76ff1Sjsg 	else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
11321bb76ff1Sjsg 		return hsw_ddi_spll_compute_dpll(state, crtc);
11331bb76ff1Sjsg 	else
11341bb76ff1Sjsg 		return -EINVAL;
11351bb76ff1Sjsg }
11361bb76ff1Sjsg 
11371bb76ff1Sjsg static int hsw_get_dpll(struct intel_atomic_state *state,
11381bb76ff1Sjsg 			struct intel_crtc *crtc,
11391bb76ff1Sjsg 			struct intel_encoder *encoder)
11401bb76ff1Sjsg {
11411bb76ff1Sjsg 	struct intel_crtc_state *crtc_state =
11421bb76ff1Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
11431bb76ff1Sjsg 	struct intel_shared_dpll *pll = NULL;
1144c349dbc7Sjsg 
1145c349dbc7Sjsg 	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
1146c349dbc7Sjsg 		pll = hsw_ddi_wrpll_get_dpll(state, crtc);
1147c349dbc7Sjsg 	else if (intel_crtc_has_dp_encoder(crtc_state))
1148c349dbc7Sjsg 		pll = hsw_ddi_lcpll_get_dpll(crtc_state);
1149c349dbc7Sjsg 	else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
1150c349dbc7Sjsg 		pll = hsw_ddi_spll_get_dpll(state, crtc);
1151c349dbc7Sjsg 
1152c349dbc7Sjsg 	if (!pll)
11531bb76ff1Sjsg 		return -EINVAL;
1154c349dbc7Sjsg 
1155c349dbc7Sjsg 	intel_reference_shared_dpll(state, crtc,
1156c349dbc7Sjsg 				    pll, &crtc_state->dpll_hw_state);
1157c349dbc7Sjsg 
1158c349dbc7Sjsg 	crtc_state->shared_dpll = pll;
1159c349dbc7Sjsg 
11601bb76ff1Sjsg 	return 0;
1161c349dbc7Sjsg }
1162c349dbc7Sjsg 
1163c349dbc7Sjsg static void hsw_update_dpll_ref_clks(struct drm_i915_private *i915)
1164c349dbc7Sjsg {
11651bb76ff1Sjsg 	i915->display.dpll.ref_clks.ssc = 135000;
1166c349dbc7Sjsg 	/* Non-SSC is only used on non-ULT HSW. */
1167c349dbc7Sjsg 	if (intel_de_read(i915, FUSE_STRAP3) & HSW_REF_CLK_SELECT)
11681bb76ff1Sjsg 		i915->display.dpll.ref_clks.nssc = 24000;
1169c349dbc7Sjsg 	else
11701bb76ff1Sjsg 		i915->display.dpll.ref_clks.nssc = 135000;
1171c349dbc7Sjsg }
1172c349dbc7Sjsg 
1173c349dbc7Sjsg static void hsw_dump_hw_state(struct drm_i915_private *dev_priv,
1174c349dbc7Sjsg 			      const struct intel_dpll_hw_state *hw_state)
1175c349dbc7Sjsg {
1176c349dbc7Sjsg 	drm_dbg_kms(&dev_priv->drm, "dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
1177c349dbc7Sjsg 		    hw_state->wrpll, hw_state->spll);
1178c349dbc7Sjsg }
1179c349dbc7Sjsg 
1180c349dbc7Sjsg static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
1181c349dbc7Sjsg 	.enable = hsw_ddi_wrpll_enable,
1182c349dbc7Sjsg 	.disable = hsw_ddi_wrpll_disable,
1183c349dbc7Sjsg 	.get_hw_state = hsw_ddi_wrpll_get_hw_state,
1184c349dbc7Sjsg 	.get_freq = hsw_ddi_wrpll_get_freq,
1185c349dbc7Sjsg };
1186c349dbc7Sjsg 
1187c349dbc7Sjsg static const struct intel_shared_dpll_funcs hsw_ddi_spll_funcs = {
1188c349dbc7Sjsg 	.enable = hsw_ddi_spll_enable,
1189c349dbc7Sjsg 	.disable = hsw_ddi_spll_disable,
1190c349dbc7Sjsg 	.get_hw_state = hsw_ddi_spll_get_hw_state,
1191c349dbc7Sjsg 	.get_freq = hsw_ddi_spll_get_freq,
1192c349dbc7Sjsg };
1193c349dbc7Sjsg 
1194c349dbc7Sjsg static void hsw_ddi_lcpll_enable(struct drm_i915_private *dev_priv,
1195c349dbc7Sjsg 				 struct intel_shared_dpll *pll)
1196c349dbc7Sjsg {
1197c349dbc7Sjsg }
1198c349dbc7Sjsg 
1199c349dbc7Sjsg static void hsw_ddi_lcpll_disable(struct drm_i915_private *dev_priv,
1200c349dbc7Sjsg 				  struct intel_shared_dpll *pll)
1201c349dbc7Sjsg {
1202c349dbc7Sjsg }
1203c349dbc7Sjsg 
1204c349dbc7Sjsg static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,
1205c349dbc7Sjsg 				       struct intel_shared_dpll *pll,
1206c349dbc7Sjsg 				       struct intel_dpll_hw_state *hw_state)
1207c349dbc7Sjsg {
1208c349dbc7Sjsg 	return true;
1209c349dbc7Sjsg }
1210c349dbc7Sjsg 
1211c349dbc7Sjsg static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = {
1212c349dbc7Sjsg 	.enable = hsw_ddi_lcpll_enable,
1213c349dbc7Sjsg 	.disable = hsw_ddi_lcpll_disable,
1214c349dbc7Sjsg 	.get_hw_state = hsw_ddi_lcpll_get_hw_state,
1215c349dbc7Sjsg 	.get_freq = hsw_ddi_lcpll_get_freq,
1216c349dbc7Sjsg };
1217c349dbc7Sjsg 
1218c349dbc7Sjsg static const struct dpll_info hsw_plls[] = {
1219c349dbc7Sjsg 	{ "WRPLL 1",    &hsw_ddi_wrpll_funcs, DPLL_ID_WRPLL1,     0 },
1220c349dbc7Sjsg 	{ "WRPLL 2",    &hsw_ddi_wrpll_funcs, DPLL_ID_WRPLL2,     0 },
1221c349dbc7Sjsg 	{ "SPLL",       &hsw_ddi_spll_funcs,  DPLL_ID_SPLL,       0 },
1222c349dbc7Sjsg 	{ "LCPLL 810",  &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_810,  INTEL_DPLL_ALWAYS_ON },
1223c349dbc7Sjsg 	{ "LCPLL 1350", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_1350, INTEL_DPLL_ALWAYS_ON },
1224c349dbc7Sjsg 	{ "LCPLL 2700", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_2700, INTEL_DPLL_ALWAYS_ON },
1225c349dbc7Sjsg 	{ },
1226c349dbc7Sjsg };
1227c349dbc7Sjsg 
1228c349dbc7Sjsg static const struct intel_dpll_mgr hsw_pll_mgr = {
1229c349dbc7Sjsg 	.dpll_info = hsw_plls,
12301bb76ff1Sjsg 	.compute_dplls = hsw_compute_dpll,
1231c349dbc7Sjsg 	.get_dplls = hsw_get_dpll,
1232c349dbc7Sjsg 	.put_dplls = intel_put_dpll,
1233c349dbc7Sjsg 	.update_ref_clks = hsw_update_dpll_ref_clks,
1234c349dbc7Sjsg 	.dump_hw_state = hsw_dump_hw_state,
1235c349dbc7Sjsg };
1236c349dbc7Sjsg 
1237c349dbc7Sjsg struct skl_dpll_regs {
1238c349dbc7Sjsg 	i915_reg_t ctl, cfgcr1, cfgcr2;
1239c349dbc7Sjsg };
1240c349dbc7Sjsg 
1241c349dbc7Sjsg /* this array is indexed by the *shared* pll id */
1242c349dbc7Sjsg static const struct skl_dpll_regs skl_dpll_regs[4] = {
1243c349dbc7Sjsg 	{
1244c349dbc7Sjsg 		/* DPLL 0 */
1245c349dbc7Sjsg 		.ctl = LCPLL1_CTL,
1246c349dbc7Sjsg 		/* DPLL 0 doesn't support HDMI mode */
1247c349dbc7Sjsg 	},
1248c349dbc7Sjsg 	{
1249c349dbc7Sjsg 		/* DPLL 1 */
1250c349dbc7Sjsg 		.ctl = LCPLL2_CTL,
1251c349dbc7Sjsg 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
1252c349dbc7Sjsg 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
1253c349dbc7Sjsg 	},
1254c349dbc7Sjsg 	{
1255c349dbc7Sjsg 		/* DPLL 2 */
1256c349dbc7Sjsg 		.ctl = WRPLL_CTL(0),
1257c349dbc7Sjsg 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
1258c349dbc7Sjsg 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
1259c349dbc7Sjsg 	},
1260c349dbc7Sjsg 	{
1261c349dbc7Sjsg 		/* DPLL 3 */
1262c349dbc7Sjsg 		.ctl = WRPLL_CTL(1),
1263c349dbc7Sjsg 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
1264c349dbc7Sjsg 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
1265c349dbc7Sjsg 	},
1266c349dbc7Sjsg };
1267c349dbc7Sjsg 
1268c349dbc7Sjsg static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *dev_priv,
1269c349dbc7Sjsg 				    struct intel_shared_dpll *pll)
1270c349dbc7Sjsg {
1271c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
1272c349dbc7Sjsg 
1273f005ef32Sjsg 	intel_de_rmw(dev_priv, DPLL_CTRL1,
1274f005ef32Sjsg 		     DPLL_CTRL1_HDMI_MODE(id) | DPLL_CTRL1_SSC(id) | DPLL_CTRL1_LINK_RATE_MASK(id),
1275f005ef32Sjsg 		     pll->state.hw_state.ctrl1 << (id * 6));
1276c349dbc7Sjsg 	intel_de_posting_read(dev_priv, DPLL_CTRL1);
1277c349dbc7Sjsg }
1278c349dbc7Sjsg 
1279c349dbc7Sjsg static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
1280c349dbc7Sjsg 			       struct intel_shared_dpll *pll)
1281c349dbc7Sjsg {
1282c349dbc7Sjsg 	const struct skl_dpll_regs *regs = skl_dpll_regs;
1283c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
1284c349dbc7Sjsg 
1285c349dbc7Sjsg 	skl_ddi_pll_write_ctrl1(dev_priv, pll);
1286c349dbc7Sjsg 
1287c349dbc7Sjsg 	intel_de_write(dev_priv, regs[id].cfgcr1, pll->state.hw_state.cfgcr1);
1288c349dbc7Sjsg 	intel_de_write(dev_priv, regs[id].cfgcr2, pll->state.hw_state.cfgcr2);
1289c349dbc7Sjsg 	intel_de_posting_read(dev_priv, regs[id].cfgcr1);
1290c349dbc7Sjsg 	intel_de_posting_read(dev_priv, regs[id].cfgcr2);
1291c349dbc7Sjsg 
1292c349dbc7Sjsg 	/* the enable bit is always bit 31 */
1293f005ef32Sjsg 	intel_de_rmw(dev_priv, regs[id].ctl, 0, LCPLL_PLL_ENABLE);
1294c349dbc7Sjsg 
1295c349dbc7Sjsg 	if (intel_de_wait_for_set(dev_priv, DPLL_STATUS, DPLL_LOCK(id), 5))
1296c349dbc7Sjsg 		drm_err(&dev_priv->drm, "DPLL %d not locked\n", id);
1297c349dbc7Sjsg }
1298c349dbc7Sjsg 
1299c349dbc7Sjsg static void skl_ddi_dpll0_enable(struct drm_i915_private *dev_priv,
1300c349dbc7Sjsg 				 struct intel_shared_dpll *pll)
1301c349dbc7Sjsg {
1302c349dbc7Sjsg 	skl_ddi_pll_write_ctrl1(dev_priv, pll);
1303c349dbc7Sjsg }
1304c349dbc7Sjsg 
1305c349dbc7Sjsg static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
1306c349dbc7Sjsg 				struct intel_shared_dpll *pll)
1307c349dbc7Sjsg {
1308c349dbc7Sjsg 	const struct skl_dpll_regs *regs = skl_dpll_regs;
1309c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
1310c349dbc7Sjsg 
1311c349dbc7Sjsg 	/* the enable bit is always bit 31 */
1312f005ef32Sjsg 	intel_de_rmw(dev_priv, regs[id].ctl, LCPLL_PLL_ENABLE, 0);
1313c349dbc7Sjsg 	intel_de_posting_read(dev_priv, regs[id].ctl);
1314c349dbc7Sjsg }
1315c349dbc7Sjsg 
1316c349dbc7Sjsg static void skl_ddi_dpll0_disable(struct drm_i915_private *dev_priv,
1317c349dbc7Sjsg 				  struct intel_shared_dpll *pll)
1318c349dbc7Sjsg {
1319c349dbc7Sjsg }
1320c349dbc7Sjsg 
1321c349dbc7Sjsg static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
1322c349dbc7Sjsg 				     struct intel_shared_dpll *pll,
1323c349dbc7Sjsg 				     struct intel_dpll_hw_state *hw_state)
1324c349dbc7Sjsg {
1325c349dbc7Sjsg 	u32 val;
1326c349dbc7Sjsg 	const struct skl_dpll_regs *regs = skl_dpll_regs;
1327c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
1328c349dbc7Sjsg 	intel_wakeref_t wakeref;
1329c349dbc7Sjsg 	bool ret;
1330c349dbc7Sjsg 
1331c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv,
1332c349dbc7Sjsg 						     POWER_DOMAIN_DISPLAY_CORE);
1333c349dbc7Sjsg 	if (!wakeref)
1334c349dbc7Sjsg 		return false;
1335c349dbc7Sjsg 
1336c349dbc7Sjsg 	ret = false;
1337c349dbc7Sjsg 
1338c349dbc7Sjsg 	val = intel_de_read(dev_priv, regs[id].ctl);
1339c349dbc7Sjsg 	if (!(val & LCPLL_PLL_ENABLE))
1340c349dbc7Sjsg 		goto out;
1341c349dbc7Sjsg 
1342c349dbc7Sjsg 	val = intel_de_read(dev_priv, DPLL_CTRL1);
1343c349dbc7Sjsg 	hw_state->ctrl1 = (val >> (id * 6)) & 0x3f;
1344c349dbc7Sjsg 
1345c349dbc7Sjsg 	/* avoid reading back stale values if HDMI mode is not enabled */
1346c349dbc7Sjsg 	if (val & DPLL_CTRL1_HDMI_MODE(id)) {
1347c349dbc7Sjsg 		hw_state->cfgcr1 = intel_de_read(dev_priv, regs[id].cfgcr1);
1348c349dbc7Sjsg 		hw_state->cfgcr2 = intel_de_read(dev_priv, regs[id].cfgcr2);
1349c349dbc7Sjsg 	}
1350c349dbc7Sjsg 	ret = true;
1351c349dbc7Sjsg 
1352c349dbc7Sjsg out:
1353c349dbc7Sjsg 	intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref);
1354c349dbc7Sjsg 
1355c349dbc7Sjsg 	return ret;
1356c349dbc7Sjsg }
1357c349dbc7Sjsg 
1358c349dbc7Sjsg static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
1359c349dbc7Sjsg 				       struct intel_shared_dpll *pll,
1360c349dbc7Sjsg 				       struct intel_dpll_hw_state *hw_state)
1361c349dbc7Sjsg {
1362c349dbc7Sjsg 	const struct skl_dpll_regs *regs = skl_dpll_regs;
1363c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
1364c349dbc7Sjsg 	intel_wakeref_t wakeref;
1365c349dbc7Sjsg 	u32 val;
1366c349dbc7Sjsg 	bool ret;
1367c349dbc7Sjsg 
1368c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv,
1369c349dbc7Sjsg 						     POWER_DOMAIN_DISPLAY_CORE);
1370c349dbc7Sjsg 	if (!wakeref)
1371c349dbc7Sjsg 		return false;
1372c349dbc7Sjsg 
1373c349dbc7Sjsg 	ret = false;
1374c349dbc7Sjsg 
1375c349dbc7Sjsg 	/* DPLL0 is always enabled since it drives CDCLK */
1376c349dbc7Sjsg 	val = intel_de_read(dev_priv, regs[id].ctl);
1377c349dbc7Sjsg 	if (drm_WARN_ON(&dev_priv->drm, !(val & LCPLL_PLL_ENABLE)))
1378c349dbc7Sjsg 		goto out;
1379c349dbc7Sjsg 
1380c349dbc7Sjsg 	val = intel_de_read(dev_priv, DPLL_CTRL1);
1381c349dbc7Sjsg 	hw_state->ctrl1 = (val >> (id * 6)) & 0x3f;
1382c349dbc7Sjsg 
1383c349dbc7Sjsg 	ret = true;
1384c349dbc7Sjsg 
1385c349dbc7Sjsg out:
1386c349dbc7Sjsg 	intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref);
1387c349dbc7Sjsg 
1388c349dbc7Sjsg 	return ret;
1389c349dbc7Sjsg }
1390c349dbc7Sjsg 
1391c349dbc7Sjsg struct skl_wrpll_context {
1392c349dbc7Sjsg 	u64 min_deviation;		/* current minimal deviation */
1393c349dbc7Sjsg 	u64 central_freq;		/* chosen central freq */
1394c349dbc7Sjsg 	u64 dco_freq;			/* chosen dco freq */
1395c349dbc7Sjsg 	unsigned int p;			/* chosen divider */
1396c349dbc7Sjsg };
1397c349dbc7Sjsg 
1398c349dbc7Sjsg /* DCO freq must be within +1%/-6%  of the DCO central freq */
1399c349dbc7Sjsg #define SKL_DCO_MAX_PDEVIATION	100
1400c349dbc7Sjsg #define SKL_DCO_MAX_NDEVIATION	600
1401c349dbc7Sjsg 
1402c349dbc7Sjsg static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
1403c349dbc7Sjsg 				  u64 central_freq,
1404c349dbc7Sjsg 				  u64 dco_freq,
1405c349dbc7Sjsg 				  unsigned int divider)
1406c349dbc7Sjsg {
1407c349dbc7Sjsg 	u64 deviation;
1408c349dbc7Sjsg 
1409c349dbc7Sjsg 	deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
1410c349dbc7Sjsg 			      central_freq);
1411c349dbc7Sjsg 
1412c349dbc7Sjsg 	/* positive deviation */
1413c349dbc7Sjsg 	if (dco_freq >= central_freq) {
1414c349dbc7Sjsg 		if (deviation < SKL_DCO_MAX_PDEVIATION &&
1415c349dbc7Sjsg 		    deviation < ctx->min_deviation) {
1416c349dbc7Sjsg 			ctx->min_deviation = deviation;
1417c349dbc7Sjsg 			ctx->central_freq = central_freq;
1418c349dbc7Sjsg 			ctx->dco_freq = dco_freq;
1419c349dbc7Sjsg 			ctx->p = divider;
1420c349dbc7Sjsg 		}
1421c349dbc7Sjsg 	/* negative deviation */
1422c349dbc7Sjsg 	} else if (deviation < SKL_DCO_MAX_NDEVIATION &&
1423c349dbc7Sjsg 		   deviation < ctx->min_deviation) {
1424c349dbc7Sjsg 		ctx->min_deviation = deviation;
1425c349dbc7Sjsg 		ctx->central_freq = central_freq;
1426c349dbc7Sjsg 		ctx->dco_freq = dco_freq;
1427c349dbc7Sjsg 		ctx->p = divider;
1428c349dbc7Sjsg 	}
1429c349dbc7Sjsg }
1430c349dbc7Sjsg 
1431c349dbc7Sjsg static void skl_wrpll_get_multipliers(unsigned int p,
1432c349dbc7Sjsg 				      unsigned int *p0 /* out */,
1433c349dbc7Sjsg 				      unsigned int *p1 /* out */,
1434c349dbc7Sjsg 				      unsigned int *p2 /* out */)
1435c349dbc7Sjsg {
1436c349dbc7Sjsg 	/* even dividers */
1437c349dbc7Sjsg 	if (p % 2 == 0) {
1438c349dbc7Sjsg 		unsigned int half = p / 2;
1439c349dbc7Sjsg 
1440c349dbc7Sjsg 		if (half == 1 || half == 2 || half == 3 || half == 5) {
1441c349dbc7Sjsg 			*p0 = 2;
1442c349dbc7Sjsg 			*p1 = 1;
1443c349dbc7Sjsg 			*p2 = half;
1444c349dbc7Sjsg 		} else if (half % 2 == 0) {
1445c349dbc7Sjsg 			*p0 = 2;
1446c349dbc7Sjsg 			*p1 = half / 2;
1447c349dbc7Sjsg 			*p2 = 2;
1448c349dbc7Sjsg 		} else if (half % 3 == 0) {
1449c349dbc7Sjsg 			*p0 = 3;
1450c349dbc7Sjsg 			*p1 = half / 3;
1451c349dbc7Sjsg 			*p2 = 2;
1452c349dbc7Sjsg 		} else if (half % 7 == 0) {
1453c349dbc7Sjsg 			*p0 = 7;
1454c349dbc7Sjsg 			*p1 = half / 7;
1455c349dbc7Sjsg 			*p2 = 2;
1456c349dbc7Sjsg 		}
1457c349dbc7Sjsg 	} else if (p == 3 || p == 9) {  /* 3, 5, 7, 9, 15, 21, 35 */
1458c349dbc7Sjsg 		*p0 = 3;
1459c349dbc7Sjsg 		*p1 = 1;
1460c349dbc7Sjsg 		*p2 = p / 3;
1461c349dbc7Sjsg 	} else if (p == 5 || p == 7) {
1462c349dbc7Sjsg 		*p0 = p;
1463c349dbc7Sjsg 		*p1 = 1;
1464c349dbc7Sjsg 		*p2 = 1;
1465c349dbc7Sjsg 	} else if (p == 15) {
1466c349dbc7Sjsg 		*p0 = 3;
1467c349dbc7Sjsg 		*p1 = 1;
1468c349dbc7Sjsg 		*p2 = 5;
1469c349dbc7Sjsg 	} else if (p == 21) {
1470c349dbc7Sjsg 		*p0 = 7;
1471c349dbc7Sjsg 		*p1 = 1;
1472c349dbc7Sjsg 		*p2 = 3;
1473c349dbc7Sjsg 	} else if (p == 35) {
1474c349dbc7Sjsg 		*p0 = 7;
1475c349dbc7Sjsg 		*p1 = 1;
1476c349dbc7Sjsg 		*p2 = 5;
1477c349dbc7Sjsg 	}
1478c349dbc7Sjsg }
1479c349dbc7Sjsg 
1480c349dbc7Sjsg struct skl_wrpll_params {
1481c349dbc7Sjsg 	u32 dco_fraction;
1482c349dbc7Sjsg 	u32 dco_integer;
1483c349dbc7Sjsg 	u32 qdiv_ratio;
1484c349dbc7Sjsg 	u32 qdiv_mode;
1485c349dbc7Sjsg 	u32 kdiv;
1486c349dbc7Sjsg 	u32 pdiv;
1487c349dbc7Sjsg 	u32 central_freq;
1488c349dbc7Sjsg };
1489c349dbc7Sjsg 
1490c349dbc7Sjsg static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
1491c349dbc7Sjsg 				      u64 afe_clock,
1492c349dbc7Sjsg 				      int ref_clock,
1493c349dbc7Sjsg 				      u64 central_freq,
1494c349dbc7Sjsg 				      u32 p0, u32 p1, u32 p2)
1495c349dbc7Sjsg {
1496c349dbc7Sjsg 	u64 dco_freq;
1497c349dbc7Sjsg 
1498c349dbc7Sjsg 	switch (central_freq) {
1499c349dbc7Sjsg 	case 9600000000ULL:
1500c349dbc7Sjsg 		params->central_freq = 0;
1501c349dbc7Sjsg 		break;
1502c349dbc7Sjsg 	case 9000000000ULL:
1503c349dbc7Sjsg 		params->central_freq = 1;
1504c349dbc7Sjsg 		break;
1505c349dbc7Sjsg 	case 8400000000ULL:
1506c349dbc7Sjsg 		params->central_freq = 3;
1507c349dbc7Sjsg 	}
1508c349dbc7Sjsg 
1509c349dbc7Sjsg 	switch (p0) {
1510c349dbc7Sjsg 	case 1:
1511c349dbc7Sjsg 		params->pdiv = 0;
1512c349dbc7Sjsg 		break;
1513c349dbc7Sjsg 	case 2:
1514c349dbc7Sjsg 		params->pdiv = 1;
1515c349dbc7Sjsg 		break;
1516c349dbc7Sjsg 	case 3:
1517c349dbc7Sjsg 		params->pdiv = 2;
1518c349dbc7Sjsg 		break;
1519c349dbc7Sjsg 	case 7:
1520c349dbc7Sjsg 		params->pdiv = 4;
1521c349dbc7Sjsg 		break;
1522c349dbc7Sjsg 	default:
1523c349dbc7Sjsg 		WARN(1, "Incorrect PDiv\n");
1524c349dbc7Sjsg 	}
1525c349dbc7Sjsg 
1526c349dbc7Sjsg 	switch (p2) {
1527c349dbc7Sjsg 	case 5:
1528c349dbc7Sjsg 		params->kdiv = 0;
1529c349dbc7Sjsg 		break;
1530c349dbc7Sjsg 	case 2:
1531c349dbc7Sjsg 		params->kdiv = 1;
1532c349dbc7Sjsg 		break;
1533c349dbc7Sjsg 	case 3:
1534c349dbc7Sjsg 		params->kdiv = 2;
1535c349dbc7Sjsg 		break;
1536c349dbc7Sjsg 	case 1:
1537c349dbc7Sjsg 		params->kdiv = 3;
1538c349dbc7Sjsg 		break;
1539c349dbc7Sjsg 	default:
1540c349dbc7Sjsg 		WARN(1, "Incorrect KDiv\n");
1541c349dbc7Sjsg 	}
1542c349dbc7Sjsg 
1543c349dbc7Sjsg 	params->qdiv_ratio = p1;
1544c349dbc7Sjsg 	params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
1545c349dbc7Sjsg 
1546c349dbc7Sjsg 	dco_freq = p0 * p1 * p2 * afe_clock;
1547c349dbc7Sjsg 
1548c349dbc7Sjsg 	/*
1549c349dbc7Sjsg 	 * Intermediate values are in Hz.
1550c349dbc7Sjsg 	 * Divide by MHz to match bsepc
1551c349dbc7Sjsg 	 */
1552c349dbc7Sjsg 	params->dco_integer = div_u64(dco_freq, ref_clock * KHz(1));
1553c349dbc7Sjsg 	params->dco_fraction =
1554c349dbc7Sjsg 		div_u64((div_u64(dco_freq, ref_clock / KHz(1)) -
1555c349dbc7Sjsg 			 params->dco_integer * MHz(1)) * 0x8000, MHz(1));
1556c349dbc7Sjsg }
1557c349dbc7Sjsg 
15581bb76ff1Sjsg static int
1559*8e8fc6d2Sjsg skl_ddi_calculate_wrpll(int clock,
1560c349dbc7Sjsg 			int ref_clock,
1561c349dbc7Sjsg 			struct skl_wrpll_params *wrpll_params)
1562c349dbc7Sjsg {
15631bb76ff1Sjsg 	static const u64 dco_central_freq[3] = { 8400000000ULL,
1564c349dbc7Sjsg 						 9000000000ULL,
1565c349dbc7Sjsg 						 9600000000ULL };
15661bb76ff1Sjsg 	static const u8 even_dividers[] = {  4,  6,  8, 10, 12, 14, 16, 18, 20,
1567c349dbc7Sjsg 					    24, 28, 30, 32, 36, 40, 42, 44,
1568c349dbc7Sjsg 					    48, 52, 54, 56, 60, 64, 66, 68,
1569c349dbc7Sjsg 					    70, 72, 76, 78, 80, 84, 88, 90,
1570c349dbc7Sjsg 					    92, 96, 98 };
15711bb76ff1Sjsg 	static const u8 odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
1572c349dbc7Sjsg 	static const struct {
15731bb76ff1Sjsg 		const u8 *list;
1574c349dbc7Sjsg 		int n_dividers;
1575c349dbc7Sjsg 	} dividers[] = {
1576c349dbc7Sjsg 		{ even_dividers, ARRAY_SIZE(even_dividers) },
1577c349dbc7Sjsg 		{ odd_dividers, ARRAY_SIZE(odd_dividers) },
1578c349dbc7Sjsg 	};
15791bb76ff1Sjsg 	struct skl_wrpll_context ctx = {
15801bb76ff1Sjsg 		.min_deviation = U64_MAX,
15811bb76ff1Sjsg 	};
1582c349dbc7Sjsg 	unsigned int dco, d, i;
1583c349dbc7Sjsg 	unsigned int p0, p1, p2;
1584*8e8fc6d2Sjsg 	u64 afe_clock = (u64)clock * 1000 * 5; /* AFE Clock is 5x Pixel clock, in Hz */
1585c349dbc7Sjsg 
1586c349dbc7Sjsg 	for (d = 0; d < ARRAY_SIZE(dividers); d++) {
1587c349dbc7Sjsg 		for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
1588c349dbc7Sjsg 			for (i = 0; i < dividers[d].n_dividers; i++) {
1589c349dbc7Sjsg 				unsigned int p = dividers[d].list[i];
1590c349dbc7Sjsg 				u64 dco_freq = p * afe_clock;
1591c349dbc7Sjsg 
1592c349dbc7Sjsg 				skl_wrpll_try_divider(&ctx,
1593c349dbc7Sjsg 						      dco_central_freq[dco],
1594c349dbc7Sjsg 						      dco_freq,
1595c349dbc7Sjsg 						      p);
1596c349dbc7Sjsg 				/*
1597c349dbc7Sjsg 				 * Skip the remaining dividers if we're sure to
1598c349dbc7Sjsg 				 * have found the definitive divider, we can't
1599c349dbc7Sjsg 				 * improve a 0 deviation.
1600c349dbc7Sjsg 				 */
1601c349dbc7Sjsg 				if (ctx.min_deviation == 0)
1602c349dbc7Sjsg 					goto skip_remaining_dividers;
1603c349dbc7Sjsg 			}
1604c349dbc7Sjsg 		}
1605c349dbc7Sjsg 
1606c349dbc7Sjsg skip_remaining_dividers:
1607c349dbc7Sjsg 		/*
1608c349dbc7Sjsg 		 * If a solution is found with an even divider, prefer
1609c349dbc7Sjsg 		 * this one.
1610c349dbc7Sjsg 		 */
1611c349dbc7Sjsg 		if (d == 0 && ctx.p)
1612c349dbc7Sjsg 			break;
1613c349dbc7Sjsg 	}
1614c349dbc7Sjsg 
16151bb76ff1Sjsg 	if (!ctx.p)
16161bb76ff1Sjsg 		return -EINVAL;
1617c349dbc7Sjsg 
1618c349dbc7Sjsg 	/*
1619c349dbc7Sjsg 	 * gcc incorrectly analyses that these can be used without being
1620c349dbc7Sjsg 	 * initialized. To be fair, it's hard to guess.
1621c349dbc7Sjsg 	 */
1622c349dbc7Sjsg 	p0 = p1 = p2 = 0;
1623c349dbc7Sjsg 	skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
1624c349dbc7Sjsg 	skl_wrpll_params_populate(wrpll_params, afe_clock, ref_clock,
1625c349dbc7Sjsg 				  ctx.central_freq, p0, p1, p2);
1626c349dbc7Sjsg 
16271bb76ff1Sjsg 	return 0;
1628c349dbc7Sjsg }
1629c349dbc7Sjsg 
1630c349dbc7Sjsg static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
16315ca02815Sjsg 				  const struct intel_shared_dpll *pll,
16325ca02815Sjsg 				  const struct intel_dpll_hw_state *pll_state)
1633c349dbc7Sjsg {
16341bb76ff1Sjsg 	int ref_clock = i915->display.dpll.ref_clks.nssc;
1635c349dbc7Sjsg 	u32 p0, p1, p2, dco_freq;
1636c349dbc7Sjsg 
1637c349dbc7Sjsg 	p0 = pll_state->cfgcr2 & DPLL_CFGCR2_PDIV_MASK;
1638c349dbc7Sjsg 	p2 = pll_state->cfgcr2 & DPLL_CFGCR2_KDIV_MASK;
1639c349dbc7Sjsg 
1640c349dbc7Sjsg 	if (pll_state->cfgcr2 &  DPLL_CFGCR2_QDIV_MODE(1))
1641c349dbc7Sjsg 		p1 = (pll_state->cfgcr2 & DPLL_CFGCR2_QDIV_RATIO_MASK) >> 8;
1642c349dbc7Sjsg 	else
1643c349dbc7Sjsg 		p1 = 1;
1644c349dbc7Sjsg 
1645c349dbc7Sjsg 
1646c349dbc7Sjsg 	switch (p0) {
1647c349dbc7Sjsg 	case DPLL_CFGCR2_PDIV_1:
1648c349dbc7Sjsg 		p0 = 1;
1649c349dbc7Sjsg 		break;
1650c349dbc7Sjsg 	case DPLL_CFGCR2_PDIV_2:
1651c349dbc7Sjsg 		p0 = 2;
1652c349dbc7Sjsg 		break;
1653c349dbc7Sjsg 	case DPLL_CFGCR2_PDIV_3:
1654c349dbc7Sjsg 		p0 = 3;
1655c349dbc7Sjsg 		break;
16565ca02815Sjsg 	case DPLL_CFGCR2_PDIV_7_INVALID:
16575ca02815Sjsg 		/*
16585ca02815Sjsg 		 * Incorrect ASUS-Z170M BIOS setting, the HW seems to ignore bit#0,
16595ca02815Sjsg 		 * handling it the same way as PDIV_7.
16605ca02815Sjsg 		 */
16615ca02815Sjsg 		drm_dbg_kms(&i915->drm, "Invalid WRPLL PDIV divider value, fixing it.\n");
16625ca02815Sjsg 		fallthrough;
1663c349dbc7Sjsg 	case DPLL_CFGCR2_PDIV_7:
1664c349dbc7Sjsg 		p0 = 7;
1665c349dbc7Sjsg 		break;
16665ca02815Sjsg 	default:
16675ca02815Sjsg 		MISSING_CASE(p0);
16685ca02815Sjsg 		return 0;
1669c349dbc7Sjsg 	}
1670c349dbc7Sjsg 
1671c349dbc7Sjsg 	switch (p2) {
1672c349dbc7Sjsg 	case DPLL_CFGCR2_KDIV_5:
1673c349dbc7Sjsg 		p2 = 5;
1674c349dbc7Sjsg 		break;
1675c349dbc7Sjsg 	case DPLL_CFGCR2_KDIV_2:
1676c349dbc7Sjsg 		p2 = 2;
1677c349dbc7Sjsg 		break;
1678c349dbc7Sjsg 	case DPLL_CFGCR2_KDIV_3:
1679c349dbc7Sjsg 		p2 = 3;
1680c349dbc7Sjsg 		break;
1681c349dbc7Sjsg 	case DPLL_CFGCR2_KDIV_1:
1682c349dbc7Sjsg 		p2 = 1;
1683c349dbc7Sjsg 		break;
16845ca02815Sjsg 	default:
16855ca02815Sjsg 		MISSING_CASE(p2);
16865ca02815Sjsg 		return 0;
1687c349dbc7Sjsg 	}
1688c349dbc7Sjsg 
1689c349dbc7Sjsg 	dco_freq = (pll_state->cfgcr1 & DPLL_CFGCR1_DCO_INTEGER_MASK) *
1690c349dbc7Sjsg 		   ref_clock;
1691c349dbc7Sjsg 
1692c349dbc7Sjsg 	dco_freq += ((pll_state->cfgcr1 & DPLL_CFGCR1_DCO_FRACTION_MASK) >> 9) *
1693c349dbc7Sjsg 		    ref_clock / 0x8000;
1694c349dbc7Sjsg 
1695ad8b1aafSjsg 	if (drm_WARN_ON(&i915->drm, p0 == 0 || p1 == 0 || p2 == 0))
1696c349dbc7Sjsg 		return 0;
1697c349dbc7Sjsg 
1698c349dbc7Sjsg 	return dco_freq / (p0 * p1 * p2 * 5);
1699c349dbc7Sjsg }
1700c349dbc7Sjsg 
17011bb76ff1Sjsg static int skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
17021bb76ff1Sjsg {
17031bb76ff1Sjsg 	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
17041bb76ff1Sjsg 	struct skl_wrpll_params wrpll_params = {};
17051bb76ff1Sjsg 	u32 ctrl1, cfgcr1, cfgcr2;
17061bb76ff1Sjsg 	int ret;
17071bb76ff1Sjsg 
17081bb76ff1Sjsg 	/*
17091bb76ff1Sjsg 	 * See comment in intel_dpll_hw_state to understand why we always use 0
17101bb76ff1Sjsg 	 * as the DPLL id in this function.
17111bb76ff1Sjsg 	 */
17121bb76ff1Sjsg 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
17131bb76ff1Sjsg 
17141bb76ff1Sjsg 	ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
17151bb76ff1Sjsg 
1716*8e8fc6d2Sjsg 	ret = skl_ddi_calculate_wrpll(crtc_state->port_clock,
17171bb76ff1Sjsg 				      i915->display.dpll.ref_clks.nssc, &wrpll_params);
17181bb76ff1Sjsg 	if (ret)
17191bb76ff1Sjsg 		return ret;
17201bb76ff1Sjsg 
17211bb76ff1Sjsg 	cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
17221bb76ff1Sjsg 		DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
17231bb76ff1Sjsg 		wrpll_params.dco_integer;
17241bb76ff1Sjsg 
17251bb76ff1Sjsg 	cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
17261bb76ff1Sjsg 		DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
17271bb76ff1Sjsg 		DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
17281bb76ff1Sjsg 		DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
17291bb76ff1Sjsg 		wrpll_params.central_freq;
17301bb76ff1Sjsg 
17311bb76ff1Sjsg 	crtc_state->dpll_hw_state.ctrl1 = ctrl1;
17321bb76ff1Sjsg 	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
17331bb76ff1Sjsg 	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
17341bb76ff1Sjsg 
17351bb76ff1Sjsg 	crtc_state->port_clock = skl_ddi_wrpll_get_freq(i915, NULL,
17361bb76ff1Sjsg 							&crtc_state->dpll_hw_state);
17371bb76ff1Sjsg 
17381bb76ff1Sjsg 	return 0;
17391bb76ff1Sjsg }
17401bb76ff1Sjsg 
17411bb76ff1Sjsg static int
1742c349dbc7Sjsg skl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
1743c349dbc7Sjsg {
1744c349dbc7Sjsg 	u32 ctrl1;
1745c349dbc7Sjsg 
1746c349dbc7Sjsg 	/*
1747c349dbc7Sjsg 	 * See comment in intel_dpll_hw_state to understand why we always use 0
1748c349dbc7Sjsg 	 * as the DPLL id in this function.
1749c349dbc7Sjsg 	 */
1750c349dbc7Sjsg 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
1751c349dbc7Sjsg 	switch (crtc_state->port_clock / 2) {
1752c349dbc7Sjsg 	case 81000:
1753c349dbc7Sjsg 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
1754c349dbc7Sjsg 		break;
1755c349dbc7Sjsg 	case 135000:
1756c349dbc7Sjsg 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
1757c349dbc7Sjsg 		break;
1758c349dbc7Sjsg 	case 270000:
1759c349dbc7Sjsg 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
1760c349dbc7Sjsg 		break;
1761c349dbc7Sjsg 		/* eDP 1.4 rates */
1762c349dbc7Sjsg 	case 162000:
1763c349dbc7Sjsg 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
1764c349dbc7Sjsg 		break;
1765c349dbc7Sjsg 	case 108000:
1766c349dbc7Sjsg 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
1767c349dbc7Sjsg 		break;
1768c349dbc7Sjsg 	case 216000:
1769c349dbc7Sjsg 		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
1770c349dbc7Sjsg 		break;
1771c349dbc7Sjsg 	}
1772c349dbc7Sjsg 
1773c349dbc7Sjsg 	crtc_state->dpll_hw_state.ctrl1 = ctrl1;
1774c349dbc7Sjsg 
17751bb76ff1Sjsg 	return 0;
1776c349dbc7Sjsg }
1777c349dbc7Sjsg 
1778c349dbc7Sjsg static int skl_ddi_lcpll_get_freq(struct drm_i915_private *i915,
17795ca02815Sjsg 				  const struct intel_shared_dpll *pll,
17805ca02815Sjsg 				  const struct intel_dpll_hw_state *pll_state)
1781c349dbc7Sjsg {
1782c349dbc7Sjsg 	int link_clock = 0;
1783c349dbc7Sjsg 
17845ca02815Sjsg 	switch ((pll_state->ctrl1 & DPLL_CTRL1_LINK_RATE_MASK(0)) >>
1785c349dbc7Sjsg 		DPLL_CTRL1_LINK_RATE_SHIFT(0)) {
1786c349dbc7Sjsg 	case DPLL_CTRL1_LINK_RATE_810:
1787c349dbc7Sjsg 		link_clock = 81000;
1788c349dbc7Sjsg 		break;
1789c349dbc7Sjsg 	case DPLL_CTRL1_LINK_RATE_1080:
1790c349dbc7Sjsg 		link_clock = 108000;
1791c349dbc7Sjsg 		break;
1792c349dbc7Sjsg 	case DPLL_CTRL1_LINK_RATE_1350:
1793c349dbc7Sjsg 		link_clock = 135000;
1794c349dbc7Sjsg 		break;
1795c349dbc7Sjsg 	case DPLL_CTRL1_LINK_RATE_1620:
1796c349dbc7Sjsg 		link_clock = 162000;
1797c349dbc7Sjsg 		break;
1798c349dbc7Sjsg 	case DPLL_CTRL1_LINK_RATE_2160:
1799c349dbc7Sjsg 		link_clock = 216000;
1800c349dbc7Sjsg 		break;
1801c349dbc7Sjsg 	case DPLL_CTRL1_LINK_RATE_2700:
1802c349dbc7Sjsg 		link_clock = 270000;
1803c349dbc7Sjsg 		break;
1804c349dbc7Sjsg 	default:
1805c349dbc7Sjsg 		drm_WARN(&i915->drm, 1, "Unsupported link rate\n");
1806c349dbc7Sjsg 		break;
1807c349dbc7Sjsg 	}
1808c349dbc7Sjsg 
1809c349dbc7Sjsg 	return link_clock * 2;
1810c349dbc7Sjsg }
1811c349dbc7Sjsg 
18121bb76ff1Sjsg static int skl_compute_dpll(struct intel_atomic_state *state,
1813c349dbc7Sjsg 			    struct intel_crtc *crtc,
1814c349dbc7Sjsg 			    struct intel_encoder *encoder)
1815c349dbc7Sjsg {
1816c349dbc7Sjsg 	struct intel_crtc_state *crtc_state =
1817c349dbc7Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
1818c349dbc7Sjsg 
18191bb76ff1Sjsg 	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
18201bb76ff1Sjsg 		return skl_ddi_hdmi_pll_dividers(crtc_state);
18211bb76ff1Sjsg 	else if (intel_crtc_has_dp_encoder(crtc_state))
18221bb76ff1Sjsg 		return skl_ddi_dp_set_dpll_hw_state(crtc_state);
18231bb76ff1Sjsg 	else
18241bb76ff1Sjsg 		return -EINVAL;
1825c349dbc7Sjsg }
18261bb76ff1Sjsg 
18271bb76ff1Sjsg static int skl_get_dpll(struct intel_atomic_state *state,
18281bb76ff1Sjsg 			struct intel_crtc *crtc,
18291bb76ff1Sjsg 			struct intel_encoder *encoder)
18301bb76ff1Sjsg {
18311bb76ff1Sjsg 	struct intel_crtc_state *crtc_state =
18321bb76ff1Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
18331bb76ff1Sjsg 	struct intel_shared_dpll *pll;
1834c349dbc7Sjsg 
1835c349dbc7Sjsg 	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
1836c349dbc7Sjsg 		pll = intel_find_shared_dpll(state, crtc,
1837c349dbc7Sjsg 					     &crtc_state->dpll_hw_state,
1838c349dbc7Sjsg 					     BIT(DPLL_ID_SKL_DPLL0));
1839c349dbc7Sjsg 	else
1840c349dbc7Sjsg 		pll = intel_find_shared_dpll(state, crtc,
1841c349dbc7Sjsg 					     &crtc_state->dpll_hw_state,
1842c349dbc7Sjsg 					     BIT(DPLL_ID_SKL_DPLL3) |
1843c349dbc7Sjsg 					     BIT(DPLL_ID_SKL_DPLL2) |
1844c349dbc7Sjsg 					     BIT(DPLL_ID_SKL_DPLL1));
1845c349dbc7Sjsg 	if (!pll)
18461bb76ff1Sjsg 		return -EINVAL;
1847c349dbc7Sjsg 
1848c349dbc7Sjsg 	intel_reference_shared_dpll(state, crtc,
1849c349dbc7Sjsg 				    pll, &crtc_state->dpll_hw_state);
1850c349dbc7Sjsg 
1851c349dbc7Sjsg 	crtc_state->shared_dpll = pll;
1852c349dbc7Sjsg 
18531bb76ff1Sjsg 	return 0;
1854c349dbc7Sjsg }
1855c349dbc7Sjsg 
1856c349dbc7Sjsg static int skl_ddi_pll_get_freq(struct drm_i915_private *i915,
18575ca02815Sjsg 				const struct intel_shared_dpll *pll,
18585ca02815Sjsg 				const struct intel_dpll_hw_state *pll_state)
1859c349dbc7Sjsg {
1860c349dbc7Sjsg 	/*
1861c349dbc7Sjsg 	 * ctrl1 register is already shifted for each pll, just use 0 to get
1862c349dbc7Sjsg 	 * the internal shift for each field
1863c349dbc7Sjsg 	 */
18645ca02815Sjsg 	if (pll_state->ctrl1 & DPLL_CTRL1_HDMI_MODE(0))
18655ca02815Sjsg 		return skl_ddi_wrpll_get_freq(i915, pll, pll_state);
1866c349dbc7Sjsg 	else
18675ca02815Sjsg 		return skl_ddi_lcpll_get_freq(i915, pll, pll_state);
1868c349dbc7Sjsg }
1869c349dbc7Sjsg 
1870c349dbc7Sjsg static void skl_update_dpll_ref_clks(struct drm_i915_private *i915)
1871c349dbc7Sjsg {
1872c349dbc7Sjsg 	/* No SSC ref */
18731bb76ff1Sjsg 	i915->display.dpll.ref_clks.nssc = i915->display.cdclk.hw.ref;
1874c349dbc7Sjsg }
1875c349dbc7Sjsg 
1876c349dbc7Sjsg static void skl_dump_hw_state(struct drm_i915_private *dev_priv,
1877c349dbc7Sjsg 			      const struct intel_dpll_hw_state *hw_state)
1878c349dbc7Sjsg {
1879c349dbc7Sjsg 	drm_dbg_kms(&dev_priv->drm, "dpll_hw_state: "
1880c349dbc7Sjsg 		      "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n",
1881c349dbc7Sjsg 		      hw_state->ctrl1,
1882c349dbc7Sjsg 		      hw_state->cfgcr1,
1883c349dbc7Sjsg 		      hw_state->cfgcr2);
1884c349dbc7Sjsg }
1885c349dbc7Sjsg 
1886c349dbc7Sjsg static const struct intel_shared_dpll_funcs skl_ddi_pll_funcs = {
1887c349dbc7Sjsg 	.enable = skl_ddi_pll_enable,
1888c349dbc7Sjsg 	.disable = skl_ddi_pll_disable,
1889c349dbc7Sjsg 	.get_hw_state = skl_ddi_pll_get_hw_state,
1890c349dbc7Sjsg 	.get_freq = skl_ddi_pll_get_freq,
1891c349dbc7Sjsg };
1892c349dbc7Sjsg 
1893c349dbc7Sjsg static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = {
1894c349dbc7Sjsg 	.enable = skl_ddi_dpll0_enable,
1895c349dbc7Sjsg 	.disable = skl_ddi_dpll0_disable,
1896c349dbc7Sjsg 	.get_hw_state = skl_ddi_dpll0_get_hw_state,
1897c349dbc7Sjsg 	.get_freq = skl_ddi_pll_get_freq,
1898c349dbc7Sjsg };
1899c349dbc7Sjsg 
1900c349dbc7Sjsg static const struct dpll_info skl_plls[] = {
1901c349dbc7Sjsg 	{ "DPLL 0", &skl_ddi_dpll0_funcs, DPLL_ID_SKL_DPLL0, INTEL_DPLL_ALWAYS_ON },
1902c349dbc7Sjsg 	{ "DPLL 1", &skl_ddi_pll_funcs,   DPLL_ID_SKL_DPLL1, 0 },
1903c349dbc7Sjsg 	{ "DPLL 2", &skl_ddi_pll_funcs,   DPLL_ID_SKL_DPLL2, 0 },
1904c349dbc7Sjsg 	{ "DPLL 3", &skl_ddi_pll_funcs,   DPLL_ID_SKL_DPLL3, 0 },
1905c349dbc7Sjsg 	{ },
1906c349dbc7Sjsg };
1907c349dbc7Sjsg 
1908c349dbc7Sjsg static const struct intel_dpll_mgr skl_pll_mgr = {
1909c349dbc7Sjsg 	.dpll_info = skl_plls,
19101bb76ff1Sjsg 	.compute_dplls = skl_compute_dpll,
1911c349dbc7Sjsg 	.get_dplls = skl_get_dpll,
1912c349dbc7Sjsg 	.put_dplls = intel_put_dpll,
1913c349dbc7Sjsg 	.update_ref_clks = skl_update_dpll_ref_clks,
1914c349dbc7Sjsg 	.dump_hw_state = skl_dump_hw_state,
1915c349dbc7Sjsg };
1916c349dbc7Sjsg 
1917c349dbc7Sjsg static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
1918c349dbc7Sjsg 				struct intel_shared_dpll *pll)
1919c349dbc7Sjsg {
1920c349dbc7Sjsg 	u32 temp;
1921c349dbc7Sjsg 	enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */
1922c349dbc7Sjsg 	enum dpio_phy phy;
1923c349dbc7Sjsg 	enum dpio_channel ch;
1924c349dbc7Sjsg 
1925c349dbc7Sjsg 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
1926c349dbc7Sjsg 
1927c349dbc7Sjsg 	/* Non-SSC reference */
1928f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_REF_SEL);
1929c349dbc7Sjsg 
1930c349dbc7Sjsg 	if (IS_GEMINILAKE(dev_priv)) {
1931f005ef32Sjsg 		intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port),
1932f005ef32Sjsg 			     0, PORT_PLL_POWER_ENABLE);
1933c349dbc7Sjsg 
1934c349dbc7Sjsg 		if (wait_for_us((intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)) &
1935c349dbc7Sjsg 				 PORT_PLL_POWER_STATE), 200))
1936c349dbc7Sjsg 			drm_err(&dev_priv->drm,
1937c349dbc7Sjsg 				"Power state not set for PLL:%d\n", port);
1938c349dbc7Sjsg 	}
1939c349dbc7Sjsg 
1940c349dbc7Sjsg 	/* Disable 10 bit clock */
1941f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch),
1942f005ef32Sjsg 		     PORT_PLL_10BIT_CLK_ENABLE, 0);
1943c349dbc7Sjsg 
1944c349dbc7Sjsg 	/* Write P1 & P2 */
1945f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL_EBB_0(phy, ch),
1946f005ef32Sjsg 		     PORT_PLL_P1_MASK | PORT_PLL_P2_MASK, pll->state.hw_state.ebb0);
1947c349dbc7Sjsg 
1948c349dbc7Sjsg 	/* Write M2 integer */
1949f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 0),
1950f005ef32Sjsg 		     PORT_PLL_M2_INT_MASK, pll->state.hw_state.pll0);
1951c349dbc7Sjsg 
1952c349dbc7Sjsg 	/* Write N */
1953f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 1),
1954f005ef32Sjsg 		     PORT_PLL_N_MASK, pll->state.hw_state.pll1);
1955c349dbc7Sjsg 
1956c349dbc7Sjsg 	/* Write M2 fraction */
1957f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 2),
1958f005ef32Sjsg 		     PORT_PLL_M2_FRAC_MASK, pll->state.hw_state.pll2);
1959c349dbc7Sjsg 
1960c349dbc7Sjsg 	/* Write M2 fraction enable */
1961f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 3),
1962f005ef32Sjsg 		     PORT_PLL_M2_FRAC_ENABLE, pll->state.hw_state.pll3);
1963c349dbc7Sjsg 
1964c349dbc7Sjsg 	/* Write coeff */
1965c349dbc7Sjsg 	temp = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 6));
1966c349dbc7Sjsg 	temp &= ~PORT_PLL_PROP_COEFF_MASK;
1967c349dbc7Sjsg 	temp &= ~PORT_PLL_INT_COEFF_MASK;
1968c349dbc7Sjsg 	temp &= ~PORT_PLL_GAIN_CTL_MASK;
1969c349dbc7Sjsg 	temp |= pll->state.hw_state.pll6;
1970c349dbc7Sjsg 	intel_de_write(dev_priv, BXT_PORT_PLL(phy, ch, 6), temp);
1971c349dbc7Sjsg 
1972c349dbc7Sjsg 	/* Write calibration val */
1973f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 8),
1974f005ef32Sjsg 		     PORT_PLL_TARGET_CNT_MASK, pll->state.hw_state.pll8);
1975c349dbc7Sjsg 
1976f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 9),
1977f005ef32Sjsg 		     PORT_PLL_LOCK_THRESHOLD_MASK, pll->state.hw_state.pll9);
1978c349dbc7Sjsg 
1979c349dbc7Sjsg 	temp = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 10));
1980c349dbc7Sjsg 	temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H;
1981c349dbc7Sjsg 	temp &= ~PORT_PLL_DCO_AMP_MASK;
1982c349dbc7Sjsg 	temp |= pll->state.hw_state.pll10;
1983c349dbc7Sjsg 	intel_de_write(dev_priv, BXT_PORT_PLL(phy, ch, 10), temp);
1984c349dbc7Sjsg 
1985c349dbc7Sjsg 	/* Recalibrate with new settings */
1986c349dbc7Sjsg 	temp = intel_de_read(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch));
1987c349dbc7Sjsg 	temp |= PORT_PLL_RECALIBRATE;
1988c349dbc7Sjsg 	intel_de_write(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch), temp);
1989c349dbc7Sjsg 	temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
1990c349dbc7Sjsg 	temp |= pll->state.hw_state.ebb4;
1991c349dbc7Sjsg 	intel_de_write(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch), temp);
1992c349dbc7Sjsg 
1993c349dbc7Sjsg 	/* Enable PLL */
1994f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_ENABLE);
1995c349dbc7Sjsg 	intel_de_posting_read(dev_priv, BXT_PORT_PLL_ENABLE(port));
1996c349dbc7Sjsg 
1997c349dbc7Sjsg 	if (wait_for_us((intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_LOCK),
1998c349dbc7Sjsg 			200))
1999c349dbc7Sjsg 		drm_err(&dev_priv->drm, "PLL %d not locked\n", port);
2000c349dbc7Sjsg 
2001c349dbc7Sjsg 	if (IS_GEMINILAKE(dev_priv)) {
2002c349dbc7Sjsg 		temp = intel_de_read(dev_priv, BXT_PORT_TX_DW5_LN0(phy, ch));
2003c349dbc7Sjsg 		temp |= DCC_DELAY_RANGE_2;
2004c349dbc7Sjsg 		intel_de_write(dev_priv, BXT_PORT_TX_DW5_GRP(phy, ch), temp);
2005c349dbc7Sjsg 	}
2006c349dbc7Sjsg 
2007c349dbc7Sjsg 	/*
2008c349dbc7Sjsg 	 * While we write to the group register to program all lanes at once we
2009c349dbc7Sjsg 	 * can read only lane registers and we pick lanes 0/1 for that.
2010c349dbc7Sjsg 	 */
2011c349dbc7Sjsg 	temp = intel_de_read(dev_priv, BXT_PORT_PCS_DW12_LN01(phy, ch));
2012c349dbc7Sjsg 	temp &= ~LANE_STAGGER_MASK;
2013c349dbc7Sjsg 	temp &= ~LANESTAGGER_STRAP_OVRD;
2014c349dbc7Sjsg 	temp |= pll->state.hw_state.pcsdw12;
2015c349dbc7Sjsg 	intel_de_write(dev_priv, BXT_PORT_PCS_DW12_GRP(phy, ch), temp);
2016c349dbc7Sjsg }
2017c349dbc7Sjsg 
2018c349dbc7Sjsg static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
2019c349dbc7Sjsg 					struct intel_shared_dpll *pll)
2020c349dbc7Sjsg {
2021c349dbc7Sjsg 	enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */
2022c349dbc7Sjsg 
2023f005ef32Sjsg 	intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), PORT_PLL_ENABLE, 0);
2024c349dbc7Sjsg 	intel_de_posting_read(dev_priv, BXT_PORT_PLL_ENABLE(port));
2025c349dbc7Sjsg 
2026c349dbc7Sjsg 	if (IS_GEMINILAKE(dev_priv)) {
2027f005ef32Sjsg 		intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port),
2028f005ef32Sjsg 			     PORT_PLL_POWER_ENABLE, 0);
2029c349dbc7Sjsg 
2030c349dbc7Sjsg 		if (wait_for_us(!(intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)) &
2031c349dbc7Sjsg 				  PORT_PLL_POWER_STATE), 200))
2032c349dbc7Sjsg 			drm_err(&dev_priv->drm,
2033c349dbc7Sjsg 				"Power state not reset for PLL:%d\n", port);
2034c349dbc7Sjsg 	}
2035c349dbc7Sjsg }
2036c349dbc7Sjsg 
2037c349dbc7Sjsg static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
2038c349dbc7Sjsg 					struct intel_shared_dpll *pll,
2039c349dbc7Sjsg 					struct intel_dpll_hw_state *hw_state)
2040c349dbc7Sjsg {
2041c349dbc7Sjsg 	enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */
2042c349dbc7Sjsg 	intel_wakeref_t wakeref;
2043c349dbc7Sjsg 	enum dpio_phy phy;
2044c349dbc7Sjsg 	enum dpio_channel ch;
2045c349dbc7Sjsg 	u32 val;
2046c349dbc7Sjsg 	bool ret;
2047c349dbc7Sjsg 
2048c349dbc7Sjsg 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
2049c349dbc7Sjsg 
2050c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv,
2051c349dbc7Sjsg 						     POWER_DOMAIN_DISPLAY_CORE);
2052c349dbc7Sjsg 	if (!wakeref)
2053c349dbc7Sjsg 		return false;
2054c349dbc7Sjsg 
2055c349dbc7Sjsg 	ret = false;
2056c349dbc7Sjsg 
2057c349dbc7Sjsg 	val = intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port));
2058c349dbc7Sjsg 	if (!(val & PORT_PLL_ENABLE))
2059c349dbc7Sjsg 		goto out;
2060c349dbc7Sjsg 
2061c349dbc7Sjsg 	hw_state->ebb0 = intel_de_read(dev_priv, BXT_PORT_PLL_EBB_0(phy, ch));
2062c349dbc7Sjsg 	hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
2063c349dbc7Sjsg 
2064c349dbc7Sjsg 	hw_state->ebb4 = intel_de_read(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch));
2065c349dbc7Sjsg 	hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
2066c349dbc7Sjsg 
2067c349dbc7Sjsg 	hw_state->pll0 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 0));
20681bb76ff1Sjsg 	hw_state->pll0 &= PORT_PLL_M2_INT_MASK;
2069c349dbc7Sjsg 
2070c349dbc7Sjsg 	hw_state->pll1 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 1));
2071c349dbc7Sjsg 	hw_state->pll1 &= PORT_PLL_N_MASK;
2072c349dbc7Sjsg 
2073c349dbc7Sjsg 	hw_state->pll2 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 2));
2074c349dbc7Sjsg 	hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK;
2075c349dbc7Sjsg 
2076c349dbc7Sjsg 	hw_state->pll3 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 3));
2077c349dbc7Sjsg 	hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE;
2078c349dbc7Sjsg 
2079c349dbc7Sjsg 	hw_state->pll6 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 6));
2080c349dbc7Sjsg 	hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK |
2081c349dbc7Sjsg 			  PORT_PLL_INT_COEFF_MASK |
2082c349dbc7Sjsg 			  PORT_PLL_GAIN_CTL_MASK;
2083c349dbc7Sjsg 
2084c349dbc7Sjsg 	hw_state->pll8 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 8));
2085c349dbc7Sjsg 	hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK;
2086c349dbc7Sjsg 
2087c349dbc7Sjsg 	hw_state->pll9 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 9));
2088c349dbc7Sjsg 	hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK;
2089c349dbc7Sjsg 
2090c349dbc7Sjsg 	hw_state->pll10 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 10));
2091c349dbc7Sjsg 	hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H |
2092c349dbc7Sjsg 			   PORT_PLL_DCO_AMP_MASK;
2093c349dbc7Sjsg 
2094c349dbc7Sjsg 	/*
2095c349dbc7Sjsg 	 * While we write to the group register to program all lanes at once we
2096c349dbc7Sjsg 	 * can read only lane registers. We configure all lanes the same way, so
2097c349dbc7Sjsg 	 * here just read out lanes 0/1 and output a note if lanes 2/3 differ.
2098c349dbc7Sjsg 	 */
2099c349dbc7Sjsg 	hw_state->pcsdw12 = intel_de_read(dev_priv,
2100c349dbc7Sjsg 					  BXT_PORT_PCS_DW12_LN01(phy, ch));
2101c349dbc7Sjsg 	if (intel_de_read(dev_priv, BXT_PORT_PCS_DW12_LN23(phy, ch)) != hw_state->pcsdw12)
2102c349dbc7Sjsg 		drm_dbg(&dev_priv->drm,
2103c349dbc7Sjsg 			"lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
2104c349dbc7Sjsg 			hw_state->pcsdw12,
2105c349dbc7Sjsg 			intel_de_read(dev_priv,
2106c349dbc7Sjsg 				      BXT_PORT_PCS_DW12_LN23(phy, ch)));
2107c349dbc7Sjsg 	hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
2108c349dbc7Sjsg 
2109c349dbc7Sjsg 	ret = true;
2110c349dbc7Sjsg 
2111c349dbc7Sjsg out:
2112c349dbc7Sjsg 	intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref);
2113c349dbc7Sjsg 
2114c349dbc7Sjsg 	return ret;
2115c349dbc7Sjsg }
2116c349dbc7Sjsg 
2117c349dbc7Sjsg /* pre-calculated values for DP linkrates */
21181bb76ff1Sjsg static const struct dpll bxt_dp_clk_val[] = {
21191bb76ff1Sjsg 	/* m2 is .22 binary fixed point */
21201bb76ff1Sjsg 	{ .dot = 162000, .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
21211bb76ff1Sjsg 	{ .dot = 270000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ },
21221bb76ff1Sjsg 	{ .dot = 540000, .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ },
21231bb76ff1Sjsg 	{ .dot = 216000, .p1 = 3, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
21241bb76ff1Sjsg 	{ .dot = 243000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6133333 /* 24.3 */ },
21251bb76ff1Sjsg 	{ .dot = 324000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
21261bb76ff1Sjsg 	{ .dot = 432000, .p1 = 3, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ },
2127c349dbc7Sjsg };
2128c349dbc7Sjsg 
21291bb76ff1Sjsg static int
2130c349dbc7Sjsg bxt_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state,
21311bb76ff1Sjsg 			  struct dpll *clk_div)
2132c349dbc7Sjsg {
2133c349dbc7Sjsg 	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
2134c349dbc7Sjsg 
2135c349dbc7Sjsg 	/* Calculate HDMI div */
2136c349dbc7Sjsg 	/*
2137c349dbc7Sjsg 	 * FIXME: tie the following calculation into
2138c349dbc7Sjsg 	 * i9xx_crtc_compute_clock
2139c349dbc7Sjsg 	 */
21401bb76ff1Sjsg 	if (!bxt_find_best_dpll(crtc_state, clk_div))
21411bb76ff1Sjsg 		return -EINVAL;
2142c349dbc7Sjsg 
21431bb76ff1Sjsg 	drm_WARN_ON(&i915->drm, clk_div->m1 != 2);
2144c349dbc7Sjsg 
21451bb76ff1Sjsg 	return 0;
2146c349dbc7Sjsg }
2147c349dbc7Sjsg 
2148c349dbc7Sjsg static void bxt_ddi_dp_pll_dividers(struct intel_crtc_state *crtc_state,
21491bb76ff1Sjsg 				    struct dpll *clk_div)
2150c349dbc7Sjsg {
21511bb76ff1Sjsg 	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
2152c349dbc7Sjsg 	int i;
2153c349dbc7Sjsg 
2154c349dbc7Sjsg 	*clk_div = bxt_dp_clk_val[0];
2155c349dbc7Sjsg 	for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
21561bb76ff1Sjsg 		if (crtc_state->port_clock == bxt_dp_clk_val[i].dot) {
2157c349dbc7Sjsg 			*clk_div = bxt_dp_clk_val[i];
2158c349dbc7Sjsg 			break;
2159c349dbc7Sjsg 		}
2160c349dbc7Sjsg 	}
2161c349dbc7Sjsg 
21621bb76ff1Sjsg 	chv_calc_dpll_params(i915->display.dpll.ref_clks.nssc, clk_div);
21631bb76ff1Sjsg 
21641bb76ff1Sjsg 	drm_WARN_ON(&i915->drm, clk_div->vco == 0 ||
21651bb76ff1Sjsg 		    clk_div->dot != crtc_state->port_clock);
2166c349dbc7Sjsg }
2167c349dbc7Sjsg 
21681bb76ff1Sjsg static int bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state,
21691bb76ff1Sjsg 				     const struct dpll *clk_div)
2170c349dbc7Sjsg {
2171c349dbc7Sjsg 	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
2172c349dbc7Sjsg 	struct intel_dpll_hw_state *dpll_hw_state = &crtc_state->dpll_hw_state;
2173c349dbc7Sjsg 	int clock = crtc_state->port_clock;
2174c349dbc7Sjsg 	int vco = clk_div->vco;
2175c349dbc7Sjsg 	u32 prop_coef, int_coef, gain_ctl, targ_cnt;
2176c349dbc7Sjsg 	u32 lanestagger;
2177c349dbc7Sjsg 
2178c349dbc7Sjsg 	if (vco >= 6200000 && vco <= 6700000) {
2179c349dbc7Sjsg 		prop_coef = 4;
2180c349dbc7Sjsg 		int_coef = 9;
2181c349dbc7Sjsg 		gain_ctl = 3;
2182c349dbc7Sjsg 		targ_cnt = 8;
2183c349dbc7Sjsg 	} else if ((vco > 5400000 && vco < 6200000) ||
2184c349dbc7Sjsg 			(vco >= 4800000 && vco < 5400000)) {
2185c349dbc7Sjsg 		prop_coef = 5;
2186c349dbc7Sjsg 		int_coef = 11;
2187c349dbc7Sjsg 		gain_ctl = 3;
2188c349dbc7Sjsg 		targ_cnt = 9;
2189c349dbc7Sjsg 	} else if (vco == 5400000) {
2190c349dbc7Sjsg 		prop_coef = 3;
2191c349dbc7Sjsg 		int_coef = 8;
2192c349dbc7Sjsg 		gain_ctl = 1;
2193c349dbc7Sjsg 		targ_cnt = 9;
2194c349dbc7Sjsg 	} else {
2195c349dbc7Sjsg 		drm_err(&i915->drm, "Invalid VCO\n");
21961bb76ff1Sjsg 		return -EINVAL;
2197c349dbc7Sjsg 	}
2198c349dbc7Sjsg 
2199c349dbc7Sjsg 	if (clock > 270000)
2200c349dbc7Sjsg 		lanestagger = 0x18;
2201c349dbc7Sjsg 	else if (clock > 135000)
2202c349dbc7Sjsg 		lanestagger = 0x0d;
2203c349dbc7Sjsg 	else if (clock > 67000)
2204c349dbc7Sjsg 		lanestagger = 0x07;
2205c349dbc7Sjsg 	else if (clock > 33000)
2206c349dbc7Sjsg 		lanestagger = 0x04;
2207c349dbc7Sjsg 	else
2208c349dbc7Sjsg 		lanestagger = 0x02;
2209c349dbc7Sjsg 
2210c349dbc7Sjsg 	dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2);
22111bb76ff1Sjsg 	dpll_hw_state->pll0 = PORT_PLL_M2_INT(clk_div->m2 >> 22);
2212c349dbc7Sjsg 	dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n);
22131bb76ff1Sjsg 	dpll_hw_state->pll2 = PORT_PLL_M2_FRAC(clk_div->m2 & 0x3fffff);
2214c349dbc7Sjsg 
22151bb76ff1Sjsg 	if (clk_div->m2 & 0x3fffff)
2216c349dbc7Sjsg 		dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE;
2217c349dbc7Sjsg 
22181bb76ff1Sjsg 	dpll_hw_state->pll6 = PORT_PLL_PROP_COEFF(prop_coef) |
22191bb76ff1Sjsg 		PORT_PLL_INT_COEFF(int_coef) |
22201bb76ff1Sjsg 		PORT_PLL_GAIN_CTL(gain_ctl);
2221c349dbc7Sjsg 
22221bb76ff1Sjsg 	dpll_hw_state->pll8 = PORT_PLL_TARGET_CNT(targ_cnt);
2223c349dbc7Sjsg 
22241bb76ff1Sjsg 	dpll_hw_state->pll9 = PORT_PLL_LOCK_THRESHOLD(5);
2225c349dbc7Sjsg 
22261bb76ff1Sjsg 	dpll_hw_state->pll10 = PORT_PLL_DCO_AMP(15) |
22271bb76ff1Sjsg 		PORT_PLL_DCO_AMP_OVR_EN_H;
2228c349dbc7Sjsg 
2229c349dbc7Sjsg 	dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
2230c349dbc7Sjsg 
2231c349dbc7Sjsg 	dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger;
2232c349dbc7Sjsg 
22331bb76ff1Sjsg 	return 0;
2234c349dbc7Sjsg }
2235c349dbc7Sjsg 
2236c349dbc7Sjsg static int bxt_ddi_pll_get_freq(struct drm_i915_private *i915,
22375ca02815Sjsg 				const struct intel_shared_dpll *pll,
22385ca02815Sjsg 				const struct intel_dpll_hw_state *pll_state)
2239c349dbc7Sjsg {
2240c349dbc7Sjsg 	struct dpll clock;
2241c349dbc7Sjsg 
2242c349dbc7Sjsg 	clock.m1 = 2;
22431bb76ff1Sjsg 	clock.m2 = REG_FIELD_GET(PORT_PLL_M2_INT_MASK, pll_state->pll0) << 22;
2244c349dbc7Sjsg 	if (pll_state->pll3 & PORT_PLL_M2_FRAC_ENABLE)
22451bb76ff1Sjsg 		clock.m2 |= REG_FIELD_GET(PORT_PLL_M2_FRAC_MASK, pll_state->pll2);
22461bb76ff1Sjsg 	clock.n = REG_FIELD_GET(PORT_PLL_N_MASK, pll_state->pll1);
22471bb76ff1Sjsg 	clock.p1 = REG_FIELD_GET(PORT_PLL_P1_MASK, pll_state->ebb0);
22481bb76ff1Sjsg 	clock.p2 = REG_FIELD_GET(PORT_PLL_P2_MASK, pll_state->ebb0);
2249c349dbc7Sjsg 
22501bb76ff1Sjsg 	return chv_calc_dpll_params(i915->display.dpll.ref_clks.nssc, &clock);
2251c349dbc7Sjsg }
2252c349dbc7Sjsg 
22531bb76ff1Sjsg static int
22541bb76ff1Sjsg bxt_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
22551bb76ff1Sjsg {
22561bb76ff1Sjsg 	struct dpll clk_div = {};
22571bb76ff1Sjsg 
22581bb76ff1Sjsg 	bxt_ddi_dp_pll_dividers(crtc_state, &clk_div);
22591bb76ff1Sjsg 
22601bb76ff1Sjsg 	return bxt_ddi_set_dpll_hw_state(crtc_state, &clk_div);
22611bb76ff1Sjsg }
22621bb76ff1Sjsg 
22631bb76ff1Sjsg static int
22641bb76ff1Sjsg bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
22651bb76ff1Sjsg {
22661bb76ff1Sjsg 	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
22671bb76ff1Sjsg 	struct dpll clk_div = {};
22681bb76ff1Sjsg 	int ret;
22691bb76ff1Sjsg 
22701bb76ff1Sjsg 	bxt_ddi_hdmi_pll_dividers(crtc_state, &clk_div);
22711bb76ff1Sjsg 
22721bb76ff1Sjsg 	ret = bxt_ddi_set_dpll_hw_state(crtc_state, &clk_div);
22731bb76ff1Sjsg 	if (ret)
22741bb76ff1Sjsg 		return ret;
22751bb76ff1Sjsg 
22761bb76ff1Sjsg 	crtc_state->port_clock = bxt_ddi_pll_get_freq(i915, NULL,
22771bb76ff1Sjsg 						      &crtc_state->dpll_hw_state);
22781bb76ff1Sjsg 
22791bb76ff1Sjsg 	return 0;
22801bb76ff1Sjsg }
22811bb76ff1Sjsg 
22821bb76ff1Sjsg static int bxt_compute_dpll(struct intel_atomic_state *state,
22831bb76ff1Sjsg 			    struct intel_crtc *crtc,
22841bb76ff1Sjsg 			    struct intel_encoder *encoder)
22851bb76ff1Sjsg {
22861bb76ff1Sjsg 	struct intel_crtc_state *crtc_state =
22871bb76ff1Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
22881bb76ff1Sjsg 
22891bb76ff1Sjsg 	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
22901bb76ff1Sjsg 		return bxt_ddi_hdmi_set_dpll_hw_state(crtc_state);
22911bb76ff1Sjsg 	else if (intel_crtc_has_dp_encoder(crtc_state))
22921bb76ff1Sjsg 		return bxt_ddi_dp_set_dpll_hw_state(crtc_state);
22931bb76ff1Sjsg 	else
22941bb76ff1Sjsg 		return -EINVAL;
22951bb76ff1Sjsg }
22961bb76ff1Sjsg 
22971bb76ff1Sjsg static int bxt_get_dpll(struct intel_atomic_state *state,
2298c349dbc7Sjsg 			struct intel_crtc *crtc,
2299c349dbc7Sjsg 			struct intel_encoder *encoder)
2300c349dbc7Sjsg {
2301c349dbc7Sjsg 	struct intel_crtc_state *crtc_state =
2302c349dbc7Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
2303c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
2304c349dbc7Sjsg 	struct intel_shared_dpll *pll;
2305c349dbc7Sjsg 	enum intel_dpll_id id;
2306c349dbc7Sjsg 
2307c349dbc7Sjsg 	/* 1:1 mapping between ports and PLLs */
2308c349dbc7Sjsg 	id = (enum intel_dpll_id) encoder->port;
2309c349dbc7Sjsg 	pll = intel_get_shared_dpll_by_id(dev_priv, id);
2310c349dbc7Sjsg 
2311c349dbc7Sjsg 	drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] using pre-allocated %s\n",
2312c349dbc7Sjsg 		    crtc->base.base.id, crtc->base.name, pll->info->name);
2313c349dbc7Sjsg 
2314c349dbc7Sjsg 	intel_reference_shared_dpll(state, crtc,
2315c349dbc7Sjsg 				    pll, &crtc_state->dpll_hw_state);
2316c349dbc7Sjsg 
2317c349dbc7Sjsg 	crtc_state->shared_dpll = pll;
2318c349dbc7Sjsg 
23191bb76ff1Sjsg 	return 0;
2320c349dbc7Sjsg }
2321c349dbc7Sjsg 
2322c349dbc7Sjsg static void bxt_update_dpll_ref_clks(struct drm_i915_private *i915)
2323c349dbc7Sjsg {
23241bb76ff1Sjsg 	i915->display.dpll.ref_clks.ssc = 100000;
23251bb76ff1Sjsg 	i915->display.dpll.ref_clks.nssc = 100000;
2326c349dbc7Sjsg 	/* DSI non-SSC ref 19.2MHz */
2327c349dbc7Sjsg }
2328c349dbc7Sjsg 
2329c349dbc7Sjsg static void bxt_dump_hw_state(struct drm_i915_private *dev_priv,
2330c349dbc7Sjsg 			      const struct intel_dpll_hw_state *hw_state)
2331c349dbc7Sjsg {
2332c349dbc7Sjsg 	drm_dbg_kms(&dev_priv->drm, "dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x,"
2333c349dbc7Sjsg 		    "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, "
2334c349dbc7Sjsg 		    "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pll10: 0x%x, pcsdw12: 0x%x\n",
2335c349dbc7Sjsg 		    hw_state->ebb0,
2336c349dbc7Sjsg 		    hw_state->ebb4,
2337c349dbc7Sjsg 		    hw_state->pll0,
2338c349dbc7Sjsg 		    hw_state->pll1,
2339c349dbc7Sjsg 		    hw_state->pll2,
2340c349dbc7Sjsg 		    hw_state->pll3,
2341c349dbc7Sjsg 		    hw_state->pll6,
2342c349dbc7Sjsg 		    hw_state->pll8,
2343c349dbc7Sjsg 		    hw_state->pll9,
2344c349dbc7Sjsg 		    hw_state->pll10,
2345c349dbc7Sjsg 		    hw_state->pcsdw12);
2346c349dbc7Sjsg }
2347c349dbc7Sjsg 
2348c349dbc7Sjsg static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = {
2349c349dbc7Sjsg 	.enable = bxt_ddi_pll_enable,
2350c349dbc7Sjsg 	.disable = bxt_ddi_pll_disable,
2351c349dbc7Sjsg 	.get_hw_state = bxt_ddi_pll_get_hw_state,
2352c349dbc7Sjsg 	.get_freq = bxt_ddi_pll_get_freq,
2353c349dbc7Sjsg };
2354c349dbc7Sjsg 
2355c349dbc7Sjsg static const struct dpll_info bxt_plls[] = {
2356c349dbc7Sjsg 	{ "PORT PLL A", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL0, 0 },
2357c349dbc7Sjsg 	{ "PORT PLL B", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL1, 0 },
2358c349dbc7Sjsg 	{ "PORT PLL C", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL2, 0 },
2359c349dbc7Sjsg 	{ },
2360c349dbc7Sjsg };
2361c349dbc7Sjsg 
2362c349dbc7Sjsg static const struct intel_dpll_mgr bxt_pll_mgr = {
2363c349dbc7Sjsg 	.dpll_info = bxt_plls,
23641bb76ff1Sjsg 	.compute_dplls = bxt_compute_dpll,
2365c349dbc7Sjsg 	.get_dplls = bxt_get_dpll,
2366c349dbc7Sjsg 	.put_dplls = intel_put_dpll,
2367c349dbc7Sjsg 	.update_ref_clks = bxt_update_dpll_ref_clks,
2368c349dbc7Sjsg 	.dump_hw_state = bxt_dump_hw_state,
2369c349dbc7Sjsg };
2370c349dbc7Sjsg 
23715ca02815Sjsg static void icl_wrpll_get_multipliers(int bestdiv, int *pdiv,
2372c349dbc7Sjsg 				      int *qdiv, int *kdiv)
2373c349dbc7Sjsg {
2374c349dbc7Sjsg 	/* even dividers */
2375c349dbc7Sjsg 	if (bestdiv % 2 == 0) {
2376c349dbc7Sjsg 		if (bestdiv == 2) {
2377c349dbc7Sjsg 			*pdiv = 2;
2378c349dbc7Sjsg 			*qdiv = 1;
2379c349dbc7Sjsg 			*kdiv = 1;
2380c349dbc7Sjsg 		} else if (bestdiv % 4 == 0) {
2381c349dbc7Sjsg 			*pdiv = 2;
2382c349dbc7Sjsg 			*qdiv = bestdiv / 4;
2383c349dbc7Sjsg 			*kdiv = 2;
2384c349dbc7Sjsg 		} else if (bestdiv % 6 == 0) {
2385c349dbc7Sjsg 			*pdiv = 3;
2386c349dbc7Sjsg 			*qdiv = bestdiv / 6;
2387c349dbc7Sjsg 			*kdiv = 2;
2388c349dbc7Sjsg 		} else if (bestdiv % 5 == 0) {
2389c349dbc7Sjsg 			*pdiv = 5;
2390c349dbc7Sjsg 			*qdiv = bestdiv / 10;
2391c349dbc7Sjsg 			*kdiv = 2;
2392c349dbc7Sjsg 		} else if (bestdiv % 14 == 0) {
2393c349dbc7Sjsg 			*pdiv = 7;
2394c349dbc7Sjsg 			*qdiv = bestdiv / 14;
2395c349dbc7Sjsg 			*kdiv = 2;
2396c349dbc7Sjsg 		}
2397c349dbc7Sjsg 	} else {
2398c349dbc7Sjsg 		if (bestdiv == 3 || bestdiv == 5 || bestdiv == 7) {
2399c349dbc7Sjsg 			*pdiv = bestdiv;
2400c349dbc7Sjsg 			*qdiv = 1;
2401c349dbc7Sjsg 			*kdiv = 1;
2402c349dbc7Sjsg 		} else { /* 9, 15, 21 */
2403c349dbc7Sjsg 			*pdiv = bestdiv / 3;
2404c349dbc7Sjsg 			*qdiv = 1;
2405c349dbc7Sjsg 			*kdiv = 3;
2406c349dbc7Sjsg 		}
2407c349dbc7Sjsg 	}
2408c349dbc7Sjsg }
2409c349dbc7Sjsg 
24105ca02815Sjsg static void icl_wrpll_params_populate(struct skl_wrpll_params *params,
2411c349dbc7Sjsg 				      u32 dco_freq, u32 ref_freq,
2412c349dbc7Sjsg 				      int pdiv, int qdiv, int kdiv)
2413c349dbc7Sjsg {
2414c349dbc7Sjsg 	u32 dco;
2415c349dbc7Sjsg 
2416c349dbc7Sjsg 	switch (kdiv) {
2417c349dbc7Sjsg 	case 1:
2418c349dbc7Sjsg 		params->kdiv = 1;
2419c349dbc7Sjsg 		break;
2420c349dbc7Sjsg 	case 2:
2421c349dbc7Sjsg 		params->kdiv = 2;
2422c349dbc7Sjsg 		break;
2423c349dbc7Sjsg 	case 3:
2424c349dbc7Sjsg 		params->kdiv = 4;
2425c349dbc7Sjsg 		break;
2426c349dbc7Sjsg 	default:
2427c349dbc7Sjsg 		WARN(1, "Incorrect KDiv\n");
2428c349dbc7Sjsg 	}
2429c349dbc7Sjsg 
2430c349dbc7Sjsg 	switch (pdiv) {
2431c349dbc7Sjsg 	case 2:
2432c349dbc7Sjsg 		params->pdiv = 1;
2433c349dbc7Sjsg 		break;
2434c349dbc7Sjsg 	case 3:
2435c349dbc7Sjsg 		params->pdiv = 2;
2436c349dbc7Sjsg 		break;
2437c349dbc7Sjsg 	case 5:
2438c349dbc7Sjsg 		params->pdiv = 4;
2439c349dbc7Sjsg 		break;
2440c349dbc7Sjsg 	case 7:
2441c349dbc7Sjsg 		params->pdiv = 8;
2442c349dbc7Sjsg 		break;
2443c349dbc7Sjsg 	default:
2444c349dbc7Sjsg 		WARN(1, "Incorrect PDiv\n");
2445c349dbc7Sjsg 	}
2446c349dbc7Sjsg 
2447c349dbc7Sjsg 	WARN_ON(kdiv != 2 && qdiv != 1);
2448c349dbc7Sjsg 
2449c349dbc7Sjsg 	params->qdiv_ratio = qdiv;
2450c349dbc7Sjsg 	params->qdiv_mode = (qdiv == 1) ? 0 : 1;
2451c349dbc7Sjsg 
2452c349dbc7Sjsg 	dco = div_u64((u64)dco_freq << 15, ref_freq);
2453c349dbc7Sjsg 
2454c349dbc7Sjsg 	params->dco_integer = dco >> 15;
2455c349dbc7Sjsg 	params->dco_fraction = dco & 0x7fff;
2456c349dbc7Sjsg }
2457c349dbc7Sjsg 
2458ad8b1aafSjsg /*
2459e8d47841Sjsg  * Display WA #22010492432: ehl, tgl, adl-s, adl-p
2460ad8b1aafSjsg  * Program half of the nominal DCO divider fraction value.
2461ad8b1aafSjsg  */
2462ad8b1aafSjsg static bool
24635ca02815Sjsg ehl_combo_pll_div_frac_wa_needed(struct drm_i915_private *i915)
2464ad8b1aafSjsg {
2465ac407e1eSjsg 	return ((IS_ELKHARTLAKE(i915) &&
2466f005ef32Sjsg 		 IS_DISPLAY_STEP(i915, STEP_B0, STEP_FOREVER)) ||
2467e8d47841Sjsg 		 IS_TIGERLAKE(i915) || IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) &&
24681bb76ff1Sjsg 		 i915->display.dpll.ref_clks.nssc == 38400;
2469ad8b1aafSjsg }
2470ad8b1aafSjsg 
2471c349dbc7Sjsg struct icl_combo_pll_params {
2472c349dbc7Sjsg 	int clock;
2473c349dbc7Sjsg 	struct skl_wrpll_params wrpll;
2474c349dbc7Sjsg };
2475c349dbc7Sjsg 
2476c349dbc7Sjsg /*
2477c349dbc7Sjsg  * These values alrea already adjusted: they're the bits we write to the
2478c349dbc7Sjsg  * registers, not the logical values.
2479c349dbc7Sjsg  */
2480c349dbc7Sjsg static const struct icl_combo_pll_params icl_dp_combo_pll_24MHz_values[] = {
2481c349dbc7Sjsg 	{ 540000,
2482c349dbc7Sjsg 	  { .dco_integer = 0x151, .dco_fraction = 0x4000,		/* [0]: 5.4 */
2483c349dbc7Sjsg 	    .pdiv = 0x2 /* 3 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2484c349dbc7Sjsg 	{ 270000,
2485c349dbc7Sjsg 	  { .dco_integer = 0x151, .dco_fraction = 0x4000,		/* [1]: 2.7 */
2486c349dbc7Sjsg 	    .pdiv = 0x2 /* 3 */, .kdiv = 2, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2487c349dbc7Sjsg 	{ 162000,
2488c349dbc7Sjsg 	  { .dco_integer = 0x151, .dco_fraction = 0x4000,		/* [2]: 1.62 */
2489c349dbc7Sjsg 	    .pdiv = 0x4 /* 5 */, .kdiv = 2, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2490c349dbc7Sjsg 	{ 324000,
2491c349dbc7Sjsg 	  { .dco_integer = 0x151, .dco_fraction = 0x4000,		/* [3]: 3.24 */
2492c349dbc7Sjsg 	    .pdiv = 0x4 /* 5 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2493c349dbc7Sjsg 	{ 216000,
2494c349dbc7Sjsg 	  { .dco_integer = 0x168, .dco_fraction = 0x0000,		/* [4]: 2.16 */
2495c349dbc7Sjsg 	    .pdiv = 0x1 /* 2 */, .kdiv = 2, .qdiv_mode = 1, .qdiv_ratio = 2, }, },
2496c349dbc7Sjsg 	{ 432000,
2497c349dbc7Sjsg 	  { .dco_integer = 0x168, .dco_fraction = 0x0000,		/* [5]: 4.32 */
2498c349dbc7Sjsg 	    .pdiv = 0x1 /* 2 */, .kdiv = 2, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2499c349dbc7Sjsg 	{ 648000,
2500c349dbc7Sjsg 	  { .dco_integer = 0x195, .dco_fraction = 0x0000,		/* [6]: 6.48 */
2501c349dbc7Sjsg 	    .pdiv = 0x2 /* 3 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2502c349dbc7Sjsg 	{ 810000,
2503c349dbc7Sjsg 	  { .dco_integer = 0x151, .dco_fraction = 0x4000,		/* [7]: 8.1 */
2504c349dbc7Sjsg 	    .pdiv = 0x1 /* 2 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2505c349dbc7Sjsg };
2506c349dbc7Sjsg 
2507c349dbc7Sjsg 
2508c349dbc7Sjsg /* Also used for 38.4 MHz values. */
2509c349dbc7Sjsg static const struct icl_combo_pll_params icl_dp_combo_pll_19_2MHz_values[] = {
2510c349dbc7Sjsg 	{ 540000,
2511c349dbc7Sjsg 	  { .dco_integer = 0x1A5, .dco_fraction = 0x7000,		/* [0]: 5.4 */
2512c349dbc7Sjsg 	    .pdiv = 0x2 /* 3 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2513c349dbc7Sjsg 	{ 270000,
2514c349dbc7Sjsg 	  { .dco_integer = 0x1A5, .dco_fraction = 0x7000,		/* [1]: 2.7 */
2515c349dbc7Sjsg 	    .pdiv = 0x2 /* 3 */, .kdiv = 2, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2516c349dbc7Sjsg 	{ 162000,
2517c349dbc7Sjsg 	  { .dco_integer = 0x1A5, .dco_fraction = 0x7000,		/* [2]: 1.62 */
2518c349dbc7Sjsg 	    .pdiv = 0x4 /* 5 */, .kdiv = 2, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2519c349dbc7Sjsg 	{ 324000,
2520c349dbc7Sjsg 	  { .dco_integer = 0x1A5, .dco_fraction = 0x7000,		/* [3]: 3.24 */
2521c349dbc7Sjsg 	    .pdiv = 0x4 /* 5 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2522c349dbc7Sjsg 	{ 216000,
2523c349dbc7Sjsg 	  { .dco_integer = 0x1C2, .dco_fraction = 0x0000,		/* [4]: 2.16 */
2524c349dbc7Sjsg 	    .pdiv = 0x1 /* 2 */, .kdiv = 2, .qdiv_mode = 1, .qdiv_ratio = 2, }, },
2525c349dbc7Sjsg 	{ 432000,
2526c349dbc7Sjsg 	  { .dco_integer = 0x1C2, .dco_fraction = 0x0000,		/* [5]: 4.32 */
2527c349dbc7Sjsg 	    .pdiv = 0x1 /* 2 */, .kdiv = 2, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2528c349dbc7Sjsg 	{ 648000,
2529c349dbc7Sjsg 	  { .dco_integer = 0x1FA, .dco_fraction = 0x2000,		/* [6]: 6.48 */
2530c349dbc7Sjsg 	    .pdiv = 0x2 /* 3 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2531c349dbc7Sjsg 	{ 810000,
2532c349dbc7Sjsg 	  { .dco_integer = 0x1A5, .dco_fraction = 0x7000,		/* [7]: 8.1 */
2533c349dbc7Sjsg 	    .pdiv = 0x1 /* 2 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0, }, },
2534c349dbc7Sjsg };
2535c349dbc7Sjsg 
2536c349dbc7Sjsg static const struct skl_wrpll_params icl_tbt_pll_24MHz_values = {
2537c349dbc7Sjsg 	.dco_integer = 0x151, .dco_fraction = 0x4000,
2538c349dbc7Sjsg 	.pdiv = 0x4 /* 5 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0,
2539c349dbc7Sjsg };
2540c349dbc7Sjsg 
2541c349dbc7Sjsg static const struct skl_wrpll_params icl_tbt_pll_19_2MHz_values = {
2542c349dbc7Sjsg 	.dco_integer = 0x1A5, .dco_fraction = 0x7000,
2543c349dbc7Sjsg 	.pdiv = 0x4 /* 5 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0,
2544c349dbc7Sjsg };
2545c349dbc7Sjsg 
2546c349dbc7Sjsg static const struct skl_wrpll_params tgl_tbt_pll_19_2MHz_values = {
2547c349dbc7Sjsg 	.dco_integer = 0x54, .dco_fraction = 0x3000,
2548c349dbc7Sjsg 	/* the following params are unused */
2549c349dbc7Sjsg 	.pdiv = 0, .kdiv = 0, .qdiv_mode = 0, .qdiv_ratio = 0,
2550c349dbc7Sjsg };
2551c349dbc7Sjsg 
2552c349dbc7Sjsg static const struct skl_wrpll_params tgl_tbt_pll_24MHz_values = {
2553c349dbc7Sjsg 	.dco_integer = 0x43, .dco_fraction = 0x4000,
2554c349dbc7Sjsg 	/* the following params are unused */
2555c349dbc7Sjsg };
2556c349dbc7Sjsg 
25571bb76ff1Sjsg static int icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state,
2558c349dbc7Sjsg 				 struct skl_wrpll_params *pll_params)
2559c349dbc7Sjsg {
2560c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
2561c349dbc7Sjsg 	const struct icl_combo_pll_params *params =
25621bb76ff1Sjsg 		dev_priv->display.dpll.ref_clks.nssc == 24000 ?
2563c349dbc7Sjsg 		icl_dp_combo_pll_24MHz_values :
2564c349dbc7Sjsg 		icl_dp_combo_pll_19_2MHz_values;
2565c349dbc7Sjsg 	int clock = crtc_state->port_clock;
2566c349dbc7Sjsg 	int i;
2567c349dbc7Sjsg 
2568c349dbc7Sjsg 	for (i = 0; i < ARRAY_SIZE(icl_dp_combo_pll_24MHz_values); i++) {
2569c349dbc7Sjsg 		if (clock == params[i].clock) {
2570c349dbc7Sjsg 			*pll_params = params[i].wrpll;
25711bb76ff1Sjsg 			return 0;
2572c349dbc7Sjsg 		}
2573c349dbc7Sjsg 	}
2574c349dbc7Sjsg 
2575c349dbc7Sjsg 	MISSING_CASE(clock);
25761bb76ff1Sjsg 	return -EINVAL;
2577c349dbc7Sjsg }
2578c349dbc7Sjsg 
25791bb76ff1Sjsg static int icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
2580c349dbc7Sjsg 			    struct skl_wrpll_params *pll_params)
2581c349dbc7Sjsg {
2582c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
2583c349dbc7Sjsg 
25845ca02815Sjsg 	if (DISPLAY_VER(dev_priv) >= 12) {
25851bb76ff1Sjsg 		switch (dev_priv->display.dpll.ref_clks.nssc) {
2586c349dbc7Sjsg 		default:
25871bb76ff1Sjsg 			MISSING_CASE(dev_priv->display.dpll.ref_clks.nssc);
2588ad8b1aafSjsg 			fallthrough;
2589c349dbc7Sjsg 		case 19200:
2590c349dbc7Sjsg 		case 38400:
2591c349dbc7Sjsg 			*pll_params = tgl_tbt_pll_19_2MHz_values;
2592c349dbc7Sjsg 			break;
2593c349dbc7Sjsg 		case 24000:
2594c349dbc7Sjsg 			*pll_params = tgl_tbt_pll_24MHz_values;
2595c349dbc7Sjsg 			break;
2596c349dbc7Sjsg 		}
2597c349dbc7Sjsg 	} else {
25981bb76ff1Sjsg 		switch (dev_priv->display.dpll.ref_clks.nssc) {
2599c349dbc7Sjsg 		default:
26001bb76ff1Sjsg 			MISSING_CASE(dev_priv->display.dpll.ref_clks.nssc);
2601ad8b1aafSjsg 			fallthrough;
2602c349dbc7Sjsg 		case 19200:
2603c349dbc7Sjsg 		case 38400:
2604c349dbc7Sjsg 			*pll_params = icl_tbt_pll_19_2MHz_values;
2605c349dbc7Sjsg 			break;
2606c349dbc7Sjsg 		case 24000:
2607c349dbc7Sjsg 			*pll_params = icl_tbt_pll_24MHz_values;
2608c349dbc7Sjsg 			break;
2609c349dbc7Sjsg 		}
2610c349dbc7Sjsg 	}
2611c349dbc7Sjsg 
26121bb76ff1Sjsg 	return 0;
2613c349dbc7Sjsg }
2614c349dbc7Sjsg 
2615c349dbc7Sjsg static int icl_ddi_tbt_pll_get_freq(struct drm_i915_private *i915,
26165ca02815Sjsg 				    const struct intel_shared_dpll *pll,
26175ca02815Sjsg 				    const struct intel_dpll_hw_state *pll_state)
2618c349dbc7Sjsg {
2619c349dbc7Sjsg 	/*
2620c349dbc7Sjsg 	 * The PLL outputs multiple frequencies at the same time, selection is
2621c349dbc7Sjsg 	 * made at DDI clock mux level.
2622c349dbc7Sjsg 	 */
2623c349dbc7Sjsg 	drm_WARN_ON(&i915->drm, 1);
2624c349dbc7Sjsg 
2625c349dbc7Sjsg 	return 0;
2626c349dbc7Sjsg }
2627c349dbc7Sjsg 
2628c349dbc7Sjsg static int icl_wrpll_ref_clock(struct drm_i915_private *i915)
2629c349dbc7Sjsg {
26301bb76ff1Sjsg 	int ref_clock = i915->display.dpll.ref_clks.nssc;
2631c349dbc7Sjsg 
2632c349dbc7Sjsg 	/*
2633c349dbc7Sjsg 	 * For ICL+, the spec states: if reference frequency is 38.4,
2634c349dbc7Sjsg 	 * use 19.2 because the DPLL automatically divides that by 2.
2635c349dbc7Sjsg 	 */
2636c349dbc7Sjsg 	if (ref_clock == 38400)
2637c349dbc7Sjsg 		ref_clock = 19200;
2638c349dbc7Sjsg 
2639c349dbc7Sjsg 	return ref_clock;
2640c349dbc7Sjsg }
2641c349dbc7Sjsg 
26421bb76ff1Sjsg static int
2643c349dbc7Sjsg icl_calc_wrpll(struct intel_crtc_state *crtc_state,
2644c349dbc7Sjsg 	       struct skl_wrpll_params *wrpll_params)
2645c349dbc7Sjsg {
2646c349dbc7Sjsg 	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
26475ca02815Sjsg 	int ref_clock = icl_wrpll_ref_clock(i915);
26485ca02815Sjsg 	u32 afe_clock = crtc_state->port_clock * 5;
26495ca02815Sjsg 	u32 dco_min = 7998000;
26505ca02815Sjsg 	u32 dco_max = 10000000;
26515ca02815Sjsg 	u32 dco_mid = (dco_min + dco_max) / 2;
26525ca02815Sjsg 	static const int dividers[] = {  2,  4,  6,  8, 10, 12,  14,  16,
26535ca02815Sjsg 					 18, 20, 24, 28, 30, 32,  36,  40,
26545ca02815Sjsg 					 42, 44, 48, 50, 52, 54,  56,  60,
26555ca02815Sjsg 					 64, 66, 68, 70, 72, 76,  78,  80,
26565ca02815Sjsg 					 84, 88, 90, 92, 96, 98, 100, 102,
26575ca02815Sjsg 					  3,  5,  7,  9, 15, 21 };
26585ca02815Sjsg 	u32 dco, best_dco = 0, dco_centrality = 0;
26595ca02815Sjsg 	u32 best_dco_centrality = U32_MAX; /* Spec meaning of 999999 MHz */
26605ca02815Sjsg 	int d, best_div = 0, pdiv = 0, qdiv = 0, kdiv = 0;
2661c349dbc7Sjsg 
26625ca02815Sjsg 	for (d = 0; d < ARRAY_SIZE(dividers); d++) {
26635ca02815Sjsg 		dco = afe_clock * dividers[d];
26645ca02815Sjsg 
26655ca02815Sjsg 		if (dco <= dco_max && dco >= dco_min) {
26665ca02815Sjsg 			dco_centrality = abs(dco - dco_mid);
26675ca02815Sjsg 
26685ca02815Sjsg 			if (dco_centrality < best_dco_centrality) {
26695ca02815Sjsg 				best_dco_centrality = dco_centrality;
26705ca02815Sjsg 				best_div = dividers[d];
26715ca02815Sjsg 				best_dco = dco;
26725ca02815Sjsg 			}
26735ca02815Sjsg 		}
26745ca02815Sjsg 	}
26755ca02815Sjsg 
26765ca02815Sjsg 	if (best_div == 0)
26771bb76ff1Sjsg 		return -EINVAL;
26785ca02815Sjsg 
26795ca02815Sjsg 	icl_wrpll_get_multipliers(best_div, &pdiv, &qdiv, &kdiv);
26805ca02815Sjsg 	icl_wrpll_params_populate(wrpll_params, best_dco, ref_clock,
26815ca02815Sjsg 				  pdiv, qdiv, kdiv);
26825ca02815Sjsg 
26831bb76ff1Sjsg 	return 0;
2684c349dbc7Sjsg }
2685c349dbc7Sjsg 
2686c349dbc7Sjsg static int icl_ddi_combo_pll_get_freq(struct drm_i915_private *i915,
26875ca02815Sjsg 				      const struct intel_shared_dpll *pll,
26885ca02815Sjsg 				      const struct intel_dpll_hw_state *pll_state)
2689c349dbc7Sjsg {
26905ca02815Sjsg 	int ref_clock = icl_wrpll_ref_clock(i915);
26915ca02815Sjsg 	u32 dco_fraction;
26925ca02815Sjsg 	u32 p0, p1, p2, dco_freq;
26935ca02815Sjsg 
26945ca02815Sjsg 	p0 = pll_state->cfgcr1 & DPLL_CFGCR1_PDIV_MASK;
26955ca02815Sjsg 	p2 = pll_state->cfgcr1 & DPLL_CFGCR1_KDIV_MASK;
26965ca02815Sjsg 
26975ca02815Sjsg 	if (pll_state->cfgcr1 & DPLL_CFGCR1_QDIV_MODE(1))
26985ca02815Sjsg 		p1 = (pll_state->cfgcr1 & DPLL_CFGCR1_QDIV_RATIO_MASK) >>
26995ca02815Sjsg 			DPLL_CFGCR1_QDIV_RATIO_SHIFT;
27005ca02815Sjsg 	else
27015ca02815Sjsg 		p1 = 1;
27025ca02815Sjsg 
27035ca02815Sjsg 	switch (p0) {
27045ca02815Sjsg 	case DPLL_CFGCR1_PDIV_2:
27055ca02815Sjsg 		p0 = 2;
27065ca02815Sjsg 		break;
27075ca02815Sjsg 	case DPLL_CFGCR1_PDIV_3:
27085ca02815Sjsg 		p0 = 3;
27095ca02815Sjsg 		break;
27105ca02815Sjsg 	case DPLL_CFGCR1_PDIV_5:
27115ca02815Sjsg 		p0 = 5;
27125ca02815Sjsg 		break;
27135ca02815Sjsg 	case DPLL_CFGCR1_PDIV_7:
27145ca02815Sjsg 		p0 = 7;
27155ca02815Sjsg 		break;
27165ca02815Sjsg 	}
27175ca02815Sjsg 
27185ca02815Sjsg 	switch (p2) {
27195ca02815Sjsg 	case DPLL_CFGCR1_KDIV_1:
27205ca02815Sjsg 		p2 = 1;
27215ca02815Sjsg 		break;
27225ca02815Sjsg 	case DPLL_CFGCR1_KDIV_2:
27235ca02815Sjsg 		p2 = 2;
27245ca02815Sjsg 		break;
27255ca02815Sjsg 	case DPLL_CFGCR1_KDIV_3:
27265ca02815Sjsg 		p2 = 3;
27275ca02815Sjsg 		break;
27285ca02815Sjsg 	}
27295ca02815Sjsg 
27305ca02815Sjsg 	dco_freq = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK) *
27315ca02815Sjsg 		   ref_clock;
27325ca02815Sjsg 
27335ca02815Sjsg 	dco_fraction = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >>
27345ca02815Sjsg 		       DPLL_CFGCR0_DCO_FRACTION_SHIFT;
27355ca02815Sjsg 
27365ca02815Sjsg 	if (ehl_combo_pll_div_frac_wa_needed(i915))
27375ca02815Sjsg 		dco_fraction *= 2;
27385ca02815Sjsg 
27395ca02815Sjsg 	dco_freq += (dco_fraction * ref_clock) / 0x8000;
27405ca02815Sjsg 
27415ca02815Sjsg 	if (drm_WARN_ON(&i915->drm, p0 == 0 || p1 == 0 || p2 == 0))
27425ca02815Sjsg 		return 0;
27435ca02815Sjsg 
27445ca02815Sjsg 	return dco_freq / (p0 * p1 * p2 * 5);
2745c349dbc7Sjsg }
2746c349dbc7Sjsg 
2747ad8b1aafSjsg static void icl_calc_dpll_state(struct drm_i915_private *i915,
2748ad8b1aafSjsg 				const struct skl_wrpll_params *pll_params,
2749c349dbc7Sjsg 				struct intel_dpll_hw_state *pll_state)
2750c349dbc7Sjsg {
2751ad8b1aafSjsg 	u32 dco_fraction = pll_params->dco_fraction;
2752c349dbc7Sjsg 
27535ca02815Sjsg 	if (ehl_combo_pll_div_frac_wa_needed(i915))
2754ad8b1aafSjsg 		dco_fraction = DIV_ROUND_CLOSEST(dco_fraction, 2);
2755c349dbc7Sjsg 
2756ad8b1aafSjsg 	pll_state->cfgcr0 = DPLL_CFGCR0_DCO_FRACTION(dco_fraction) |
2757ad8b1aafSjsg 			    pll_params->dco_integer;
2758ad8b1aafSjsg 
2759ad8b1aafSjsg 	pll_state->cfgcr1 = DPLL_CFGCR1_QDIV_RATIO(pll_params->qdiv_ratio) |
2760ad8b1aafSjsg 			    DPLL_CFGCR1_QDIV_MODE(pll_params->qdiv_mode) |
2761ad8b1aafSjsg 			    DPLL_CFGCR1_KDIV(pll_params->kdiv) |
2762ad8b1aafSjsg 			    DPLL_CFGCR1_PDIV(pll_params->pdiv);
2763ad8b1aafSjsg 
27645ca02815Sjsg 	if (DISPLAY_VER(i915) >= 12)
2765ad8b1aafSjsg 		pll_state->cfgcr1 |= TGL_DPLL_CFGCR1_CFSELOVRD_NORMAL_XTAL;
2766ad8b1aafSjsg 	else
2767ad8b1aafSjsg 		pll_state->cfgcr1 |= DPLL_CFGCR1_CENTRAL_FREQ_8400;
27681bb76ff1Sjsg 
27691bb76ff1Sjsg 	if (i915->display.vbt.override_afc_startup)
27701bb76ff1Sjsg 		pll_state->div0 = TGL_DPLL0_DIV0_AFC_STARTUP(i915->display.vbt.override_afc_startup_val);
2771c349dbc7Sjsg }
2772c349dbc7Sjsg 
27731bb76ff1Sjsg static int icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc,
2774c349dbc7Sjsg 				    u32 *target_dco_khz,
2775c349dbc7Sjsg 				    struct intel_dpll_hw_state *state,
2776c349dbc7Sjsg 				    bool is_dkl)
2777c349dbc7Sjsg {
27781bb76ff1Sjsg 	static const u8 div1_vals[] = { 7, 5, 3, 2 };
2779c349dbc7Sjsg 	u32 dco_min_freq, dco_max_freq;
2780c349dbc7Sjsg 	unsigned int i;
2781c349dbc7Sjsg 	int div2;
2782c349dbc7Sjsg 
2783c349dbc7Sjsg 	dco_min_freq = is_dp ? 8100000 : use_ssc ? 8000000 : 7992000;
2784c349dbc7Sjsg 	dco_max_freq = is_dp ? 8100000 : 10000000;
2785c349dbc7Sjsg 
2786c349dbc7Sjsg 	for (i = 0; i < ARRAY_SIZE(div1_vals); i++) {
2787c349dbc7Sjsg 		int div1 = div1_vals[i];
2788c349dbc7Sjsg 
2789c349dbc7Sjsg 		for (div2 = 10; div2 > 0; div2--) {
2790c349dbc7Sjsg 			int dco = div1 * div2 * clock_khz * 5;
2791c349dbc7Sjsg 			int a_divratio, tlinedrv, inputsel;
2792c349dbc7Sjsg 			u32 hsdiv;
2793c349dbc7Sjsg 
2794c349dbc7Sjsg 			if (dco < dco_min_freq || dco > dco_max_freq)
2795c349dbc7Sjsg 				continue;
2796c349dbc7Sjsg 
2797c349dbc7Sjsg 			if (div2 >= 2) {
2798c349dbc7Sjsg 				/*
2799c349dbc7Sjsg 				 * Note: a_divratio not matching TGL BSpec
2800c349dbc7Sjsg 				 * algorithm but matching hardcoded values and
2801c349dbc7Sjsg 				 * working on HW for DP alt-mode at least
2802c349dbc7Sjsg 				 */
2803c349dbc7Sjsg 				a_divratio = is_dp ? 10 : 5;
2804c349dbc7Sjsg 				tlinedrv = is_dkl ? 1 : 2;
2805c349dbc7Sjsg 			} else {
2806c349dbc7Sjsg 				a_divratio = 5;
2807c349dbc7Sjsg 				tlinedrv = 0;
2808c349dbc7Sjsg 			}
2809c349dbc7Sjsg 			inputsel = is_dp ? 0 : 1;
2810c349dbc7Sjsg 
2811c349dbc7Sjsg 			switch (div1) {
2812c349dbc7Sjsg 			default:
2813c349dbc7Sjsg 				MISSING_CASE(div1);
2814ad8b1aafSjsg 				fallthrough;
2815c349dbc7Sjsg 			case 2:
2816c349dbc7Sjsg 				hsdiv = MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_2;
2817c349dbc7Sjsg 				break;
2818c349dbc7Sjsg 			case 3:
2819c349dbc7Sjsg 				hsdiv = MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_3;
2820c349dbc7Sjsg 				break;
2821c349dbc7Sjsg 			case 5:
2822c349dbc7Sjsg 				hsdiv = MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_5;
2823c349dbc7Sjsg 				break;
2824c349dbc7Sjsg 			case 7:
2825c349dbc7Sjsg 				hsdiv = MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_7;
2826c349dbc7Sjsg 				break;
2827c349dbc7Sjsg 			}
2828c349dbc7Sjsg 
2829c349dbc7Sjsg 			*target_dco_khz = dco;
2830c349dbc7Sjsg 
2831c349dbc7Sjsg 			state->mg_refclkin_ctl = MG_REFCLKIN_CTL_OD_2_MUX(1);
2832c349dbc7Sjsg 
2833c349dbc7Sjsg 			state->mg_clktop2_coreclkctl1 =
2834c349dbc7Sjsg 				MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO(a_divratio);
2835c349dbc7Sjsg 
2836c349dbc7Sjsg 			state->mg_clktop2_hsclkctl =
2837c349dbc7Sjsg 				MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL(tlinedrv) |
2838c349dbc7Sjsg 				MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL(inputsel) |
2839c349dbc7Sjsg 				hsdiv |
2840c349dbc7Sjsg 				MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO(div2);
2841c349dbc7Sjsg 
28421bb76ff1Sjsg 			return 0;
2843c349dbc7Sjsg 		}
2844c349dbc7Sjsg 	}
2845c349dbc7Sjsg 
28461bb76ff1Sjsg 	return -EINVAL;
2847c349dbc7Sjsg }
2848c349dbc7Sjsg 
2849c349dbc7Sjsg /*
2850c349dbc7Sjsg  * The specification for this function uses real numbers, so the math had to be
2851c349dbc7Sjsg  * adapted to integer-only calculation, that's why it looks so different.
2852c349dbc7Sjsg  */
28531bb76ff1Sjsg static int icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
2854c349dbc7Sjsg 				 struct intel_dpll_hw_state *pll_state)
2855c349dbc7Sjsg {
2856c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
28571bb76ff1Sjsg 	int refclk_khz = dev_priv->display.dpll.ref_clks.nssc;
2858c349dbc7Sjsg 	int clock = crtc_state->port_clock;
2859c349dbc7Sjsg 	u32 dco_khz, m1div, m2div_int, m2div_rem, m2div_frac;
2860c349dbc7Sjsg 	u32 iref_ndiv, iref_trim, iref_pulse_w;
2861c349dbc7Sjsg 	u32 prop_coeff, int_coeff;
2862c349dbc7Sjsg 	u32 tdc_targetcnt, feedfwgain;
2863c349dbc7Sjsg 	u64 ssc_stepsize, ssc_steplen, ssc_steplog;
2864c349dbc7Sjsg 	u64 tmp;
2865c349dbc7Sjsg 	bool use_ssc = false;
2866c349dbc7Sjsg 	bool is_dp = !intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI);
28675ca02815Sjsg 	bool is_dkl = DISPLAY_VER(dev_priv) >= 12;
28681bb76ff1Sjsg 	int ret;
2869c349dbc7Sjsg 
28701bb76ff1Sjsg 	ret = icl_mg_pll_find_divisors(clock, is_dp, use_ssc, &dco_khz,
28711bb76ff1Sjsg 				       pll_state, is_dkl);
28721bb76ff1Sjsg 	if (ret)
28731bb76ff1Sjsg 		return ret;
2874c349dbc7Sjsg 
2875c349dbc7Sjsg 	m1div = 2;
2876c349dbc7Sjsg 	m2div_int = dco_khz / (refclk_khz * m1div);
2877c349dbc7Sjsg 	if (m2div_int > 255) {
2878c349dbc7Sjsg 		if (!is_dkl) {
2879c349dbc7Sjsg 			m1div = 4;
2880c349dbc7Sjsg 			m2div_int = dco_khz / (refclk_khz * m1div);
2881c349dbc7Sjsg 		}
2882c349dbc7Sjsg 
28831bb76ff1Sjsg 		if (m2div_int > 255)
28841bb76ff1Sjsg 			return -EINVAL;
2885c349dbc7Sjsg 	}
2886c349dbc7Sjsg 	m2div_rem = dco_khz % (refclk_khz * m1div);
2887c349dbc7Sjsg 
2888c349dbc7Sjsg 	tmp = (u64)m2div_rem * (1 << 22);
2889c349dbc7Sjsg 	do_div(tmp, refclk_khz * m1div);
2890c349dbc7Sjsg 	m2div_frac = tmp;
2891c349dbc7Sjsg 
2892c349dbc7Sjsg 	switch (refclk_khz) {
2893c349dbc7Sjsg 	case 19200:
2894c349dbc7Sjsg 		iref_ndiv = 1;
2895c349dbc7Sjsg 		iref_trim = 28;
2896c349dbc7Sjsg 		iref_pulse_w = 1;
2897c349dbc7Sjsg 		break;
2898c349dbc7Sjsg 	case 24000:
2899c349dbc7Sjsg 		iref_ndiv = 1;
2900c349dbc7Sjsg 		iref_trim = 25;
2901c349dbc7Sjsg 		iref_pulse_w = 2;
2902c349dbc7Sjsg 		break;
2903c349dbc7Sjsg 	case 38400:
2904c349dbc7Sjsg 		iref_ndiv = 2;
2905c349dbc7Sjsg 		iref_trim = 28;
2906c349dbc7Sjsg 		iref_pulse_w = 1;
2907c349dbc7Sjsg 		break;
2908c349dbc7Sjsg 	default:
2909c349dbc7Sjsg 		MISSING_CASE(refclk_khz);
29101bb76ff1Sjsg 		return -EINVAL;
2911c349dbc7Sjsg 	}
2912c349dbc7Sjsg 
2913c349dbc7Sjsg 	/*
2914c349dbc7Sjsg 	 * tdc_res = 0.000003
2915c349dbc7Sjsg 	 * tdc_targetcnt = int(2 / (tdc_res * 8 * 50 * 1.1) / refclk_mhz + 0.5)
2916c349dbc7Sjsg 	 *
2917c349dbc7Sjsg 	 * The multiplication by 1000 is due to refclk MHz to KHz conversion. It
2918c349dbc7Sjsg 	 * was supposed to be a division, but we rearranged the operations of
2919c349dbc7Sjsg 	 * the formula to avoid early divisions so we don't multiply the
2920c349dbc7Sjsg 	 * rounding errors.
2921c349dbc7Sjsg 	 *
2922c349dbc7Sjsg 	 * 0.000003 * 8 * 50 * 1.1 = 0.00132, also known as 132 / 100000, which
2923c349dbc7Sjsg 	 * we also rearrange to work with integers.
2924c349dbc7Sjsg 	 *
2925c349dbc7Sjsg 	 * The 0.5 transformed to 5 results in a multiplication by 10 and the
2926c349dbc7Sjsg 	 * last division by 10.
2927c349dbc7Sjsg 	 */
2928c349dbc7Sjsg 	tdc_targetcnt = (2 * 1000 * 100000 * 10 / (132 * refclk_khz) + 5) / 10;
2929c349dbc7Sjsg 
2930c349dbc7Sjsg 	/*
2931c349dbc7Sjsg 	 * Here we divide dco_khz by 10 in order to allow the dividend to fit in
2932c349dbc7Sjsg 	 * 32 bits. That's not a problem since we round the division down
2933c349dbc7Sjsg 	 * anyway.
2934c349dbc7Sjsg 	 */
2935c349dbc7Sjsg 	feedfwgain = (use_ssc || m2div_rem > 0) ?
2936c349dbc7Sjsg 		m1div * 1000000 * 100 / (dco_khz * 3 / 10) : 0;
2937c349dbc7Sjsg 
2938c349dbc7Sjsg 	if (dco_khz >= 9000000) {
2939c349dbc7Sjsg 		prop_coeff = 5;
2940c349dbc7Sjsg 		int_coeff = 10;
2941c349dbc7Sjsg 	} else {
2942c349dbc7Sjsg 		prop_coeff = 4;
2943c349dbc7Sjsg 		int_coeff = 8;
2944c349dbc7Sjsg 	}
2945c349dbc7Sjsg 
2946c349dbc7Sjsg 	if (use_ssc) {
2947c349dbc7Sjsg 		tmp = mul_u32_u32(dco_khz, 47 * 32);
2948c349dbc7Sjsg 		do_div(tmp, refclk_khz * m1div * 10000);
2949c349dbc7Sjsg 		ssc_stepsize = tmp;
2950c349dbc7Sjsg 
2951c349dbc7Sjsg 		tmp = mul_u32_u32(dco_khz, 1000);
2952c349dbc7Sjsg 		ssc_steplen = DIV_ROUND_UP_ULL(tmp, 32 * 2 * 32);
2953c349dbc7Sjsg 	} else {
2954c349dbc7Sjsg 		ssc_stepsize = 0;
2955c349dbc7Sjsg 		ssc_steplen = 0;
2956c349dbc7Sjsg 	}
2957c349dbc7Sjsg 	ssc_steplog = 4;
2958c349dbc7Sjsg 
2959c349dbc7Sjsg 	/* write pll_state calculations */
2960c349dbc7Sjsg 	if (is_dkl) {
2961c349dbc7Sjsg 		pll_state->mg_pll_div0 = DKL_PLL_DIV0_INTEG_COEFF(int_coeff) |
2962c349dbc7Sjsg 					 DKL_PLL_DIV0_PROP_COEFF(prop_coeff) |
2963c349dbc7Sjsg 					 DKL_PLL_DIV0_FBPREDIV(m1div) |
2964c349dbc7Sjsg 					 DKL_PLL_DIV0_FBDIV_INT(m2div_int);
29651bb76ff1Sjsg 		if (dev_priv->display.vbt.override_afc_startup) {
29661bb76ff1Sjsg 			u8 val = dev_priv->display.vbt.override_afc_startup_val;
29671bb76ff1Sjsg 
29681bb76ff1Sjsg 			pll_state->mg_pll_div0 |= DKL_PLL_DIV0_AFC_STARTUP(val);
29691bb76ff1Sjsg 		}
2970c349dbc7Sjsg 
2971c349dbc7Sjsg 		pll_state->mg_pll_div1 = DKL_PLL_DIV1_IREF_TRIM(iref_trim) |
2972c349dbc7Sjsg 					 DKL_PLL_DIV1_TDC_TARGET_CNT(tdc_targetcnt);
2973c349dbc7Sjsg 
2974c349dbc7Sjsg 		pll_state->mg_pll_ssc = DKL_PLL_SSC_IREF_NDIV_RATIO(iref_ndiv) |
2975c349dbc7Sjsg 					DKL_PLL_SSC_STEP_LEN(ssc_steplen) |
2976c349dbc7Sjsg 					DKL_PLL_SSC_STEP_NUM(ssc_steplog) |
2977c349dbc7Sjsg 					(use_ssc ? DKL_PLL_SSC_EN : 0);
2978c349dbc7Sjsg 
2979c349dbc7Sjsg 		pll_state->mg_pll_bias = (m2div_frac ? DKL_PLL_BIAS_FRAC_EN_H : 0) |
2980c349dbc7Sjsg 					  DKL_PLL_BIAS_FBDIV_FRAC(m2div_frac);
2981c349dbc7Sjsg 
2982c349dbc7Sjsg 		pll_state->mg_pll_tdc_coldst_bias =
2983c349dbc7Sjsg 				DKL_PLL_TDC_SSC_STEP_SIZE(ssc_stepsize) |
2984c349dbc7Sjsg 				DKL_PLL_TDC_FEED_FWD_GAIN(feedfwgain);
2985c349dbc7Sjsg 
2986c349dbc7Sjsg 	} else {
2987c349dbc7Sjsg 		pll_state->mg_pll_div0 =
2988c349dbc7Sjsg 			(m2div_rem > 0 ? MG_PLL_DIV0_FRACNEN_H : 0) |
2989c349dbc7Sjsg 			MG_PLL_DIV0_FBDIV_FRAC(m2div_frac) |
2990c349dbc7Sjsg 			MG_PLL_DIV0_FBDIV_INT(m2div_int);
2991c349dbc7Sjsg 
2992c349dbc7Sjsg 		pll_state->mg_pll_div1 =
2993c349dbc7Sjsg 			MG_PLL_DIV1_IREF_NDIVRATIO(iref_ndiv) |
2994c349dbc7Sjsg 			MG_PLL_DIV1_DITHER_DIV_2 |
2995c349dbc7Sjsg 			MG_PLL_DIV1_NDIVRATIO(1) |
2996c349dbc7Sjsg 			MG_PLL_DIV1_FBPREDIV(m1div);
2997c349dbc7Sjsg 
2998c349dbc7Sjsg 		pll_state->mg_pll_lf =
2999c349dbc7Sjsg 			MG_PLL_LF_TDCTARGETCNT(tdc_targetcnt) |
3000c349dbc7Sjsg 			MG_PLL_LF_AFCCNTSEL_512 |
3001c349dbc7Sjsg 			MG_PLL_LF_GAINCTRL(1) |
3002c349dbc7Sjsg 			MG_PLL_LF_INT_COEFF(int_coeff) |
3003c349dbc7Sjsg 			MG_PLL_LF_PROP_COEFF(prop_coeff);
3004c349dbc7Sjsg 
3005c349dbc7Sjsg 		pll_state->mg_pll_frac_lock =
3006c349dbc7Sjsg 			MG_PLL_FRAC_LOCK_TRUELOCK_CRIT_32 |
3007c349dbc7Sjsg 			MG_PLL_FRAC_LOCK_EARLYLOCK_CRIT_32 |
3008c349dbc7Sjsg 			MG_PLL_FRAC_LOCK_LOCKTHRESH(10) |
3009c349dbc7Sjsg 			MG_PLL_FRAC_LOCK_DCODITHEREN |
3010c349dbc7Sjsg 			MG_PLL_FRAC_LOCK_FEEDFWRDGAIN(feedfwgain);
3011c349dbc7Sjsg 		if (use_ssc || m2div_rem > 0)
3012c349dbc7Sjsg 			pll_state->mg_pll_frac_lock |=
3013c349dbc7Sjsg 				MG_PLL_FRAC_LOCK_FEEDFWRDCAL_EN;
3014c349dbc7Sjsg 
3015c349dbc7Sjsg 		pll_state->mg_pll_ssc =
3016c349dbc7Sjsg 			(use_ssc ? MG_PLL_SSC_EN : 0) |
3017c349dbc7Sjsg 			MG_PLL_SSC_TYPE(2) |
3018c349dbc7Sjsg 			MG_PLL_SSC_STEPLENGTH(ssc_steplen) |
3019c349dbc7Sjsg 			MG_PLL_SSC_STEPNUM(ssc_steplog) |
3020c349dbc7Sjsg 			MG_PLL_SSC_FLLEN |
3021c349dbc7Sjsg 			MG_PLL_SSC_STEPSIZE(ssc_stepsize);
3022c349dbc7Sjsg 
3023c349dbc7Sjsg 		pll_state->mg_pll_tdc_coldst_bias =
3024c349dbc7Sjsg 			MG_PLL_TDC_COLDST_COLDSTART |
3025c349dbc7Sjsg 			MG_PLL_TDC_COLDST_IREFINT_EN |
3026c349dbc7Sjsg 			MG_PLL_TDC_COLDST_REFBIAS_START_PULSE_W(iref_pulse_w) |
3027c349dbc7Sjsg 			MG_PLL_TDC_TDCOVCCORR_EN |
3028c349dbc7Sjsg 			MG_PLL_TDC_TDCSEL(3);
3029c349dbc7Sjsg 
3030c349dbc7Sjsg 		pll_state->mg_pll_bias =
3031c349dbc7Sjsg 			MG_PLL_BIAS_BIAS_GB_SEL(3) |
3032c349dbc7Sjsg 			MG_PLL_BIAS_INIT_DCOAMP(0x3F) |
3033c349dbc7Sjsg 			MG_PLL_BIAS_BIAS_BONUS(10) |
3034c349dbc7Sjsg 			MG_PLL_BIAS_BIASCAL_EN |
3035c349dbc7Sjsg 			MG_PLL_BIAS_CTRIM(12) |
3036c349dbc7Sjsg 			MG_PLL_BIAS_VREF_RDAC(4) |
3037c349dbc7Sjsg 			MG_PLL_BIAS_IREFTRIM(iref_trim);
3038c349dbc7Sjsg 
3039c349dbc7Sjsg 		if (refclk_khz == 38400) {
3040c349dbc7Sjsg 			pll_state->mg_pll_tdc_coldst_bias_mask =
3041c349dbc7Sjsg 				MG_PLL_TDC_COLDST_COLDSTART;
3042c349dbc7Sjsg 			pll_state->mg_pll_bias_mask = 0;
3043c349dbc7Sjsg 		} else {
3044c349dbc7Sjsg 			pll_state->mg_pll_tdc_coldst_bias_mask = -1U;
3045c349dbc7Sjsg 			pll_state->mg_pll_bias_mask = -1U;
3046c349dbc7Sjsg 		}
3047c349dbc7Sjsg 
3048c349dbc7Sjsg 		pll_state->mg_pll_tdc_coldst_bias &=
3049c349dbc7Sjsg 			pll_state->mg_pll_tdc_coldst_bias_mask;
3050c349dbc7Sjsg 		pll_state->mg_pll_bias &= pll_state->mg_pll_bias_mask;
3051c349dbc7Sjsg 	}
3052c349dbc7Sjsg 
30531bb76ff1Sjsg 	return 0;
3054c349dbc7Sjsg }
3055c349dbc7Sjsg 
3056c349dbc7Sjsg static int icl_ddi_mg_pll_get_freq(struct drm_i915_private *dev_priv,
30575ca02815Sjsg 				   const struct intel_shared_dpll *pll,
30585ca02815Sjsg 				   const struct intel_dpll_hw_state *pll_state)
3059c349dbc7Sjsg {
3060c349dbc7Sjsg 	u32 m1, m2_int, m2_frac, div1, div2, ref_clock;
3061c349dbc7Sjsg 	u64 tmp;
3062c349dbc7Sjsg 
30631bb76ff1Sjsg 	ref_clock = dev_priv->display.dpll.ref_clks.nssc;
3064c349dbc7Sjsg 
30655ca02815Sjsg 	if (DISPLAY_VER(dev_priv) >= 12) {
3066c349dbc7Sjsg 		m1 = pll_state->mg_pll_div0 & DKL_PLL_DIV0_FBPREDIV_MASK;
3067c349dbc7Sjsg 		m1 = m1 >> DKL_PLL_DIV0_FBPREDIV_SHIFT;
3068c349dbc7Sjsg 		m2_int = pll_state->mg_pll_div0 & DKL_PLL_DIV0_FBDIV_INT_MASK;
3069c349dbc7Sjsg 
3070c349dbc7Sjsg 		if (pll_state->mg_pll_bias & DKL_PLL_BIAS_FRAC_EN_H) {
3071c349dbc7Sjsg 			m2_frac = pll_state->mg_pll_bias &
3072c349dbc7Sjsg 				  DKL_PLL_BIAS_FBDIV_FRAC_MASK;
3073c349dbc7Sjsg 			m2_frac = m2_frac >> DKL_PLL_BIAS_FBDIV_SHIFT;
3074c349dbc7Sjsg 		} else {
3075c349dbc7Sjsg 			m2_frac = 0;
3076c349dbc7Sjsg 		}
3077c349dbc7Sjsg 	} else {
3078c349dbc7Sjsg 		m1 = pll_state->mg_pll_div1 & MG_PLL_DIV1_FBPREDIV_MASK;
3079c349dbc7Sjsg 		m2_int = pll_state->mg_pll_div0 & MG_PLL_DIV0_FBDIV_INT_MASK;
3080c349dbc7Sjsg 
3081c349dbc7Sjsg 		if (pll_state->mg_pll_div0 & MG_PLL_DIV0_FRACNEN_H) {
3082c349dbc7Sjsg 			m2_frac = pll_state->mg_pll_div0 &
3083c349dbc7Sjsg 				  MG_PLL_DIV0_FBDIV_FRAC_MASK;
3084c349dbc7Sjsg 			m2_frac = m2_frac >> MG_PLL_DIV0_FBDIV_FRAC_SHIFT;
3085c349dbc7Sjsg 		} else {
3086c349dbc7Sjsg 			m2_frac = 0;
3087c349dbc7Sjsg 		}
3088c349dbc7Sjsg 	}
3089c349dbc7Sjsg 
3090c349dbc7Sjsg 	switch (pll_state->mg_clktop2_hsclkctl &
3091c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK) {
3092c349dbc7Sjsg 	case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_2:
3093c349dbc7Sjsg 		div1 = 2;
3094c349dbc7Sjsg 		break;
3095c349dbc7Sjsg 	case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_3:
3096c349dbc7Sjsg 		div1 = 3;
3097c349dbc7Sjsg 		break;
3098c349dbc7Sjsg 	case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_5:
3099c349dbc7Sjsg 		div1 = 5;
3100c349dbc7Sjsg 		break;
3101c349dbc7Sjsg 	case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_7:
3102c349dbc7Sjsg 		div1 = 7;
3103c349dbc7Sjsg 		break;
3104c349dbc7Sjsg 	default:
3105c349dbc7Sjsg 		MISSING_CASE(pll_state->mg_clktop2_hsclkctl);
3106c349dbc7Sjsg 		return 0;
3107c349dbc7Sjsg 	}
3108c349dbc7Sjsg 
3109c349dbc7Sjsg 	div2 = (pll_state->mg_clktop2_hsclkctl &
3110c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK) >>
3111c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_SHIFT;
3112c349dbc7Sjsg 
3113c349dbc7Sjsg 	/* div2 value of 0 is same as 1 means no div */
3114c349dbc7Sjsg 	if (div2 == 0)
3115c349dbc7Sjsg 		div2 = 1;
3116c349dbc7Sjsg 
3117c349dbc7Sjsg 	/*
3118c349dbc7Sjsg 	 * Adjust the original formula to delay the division by 2^22 in order to
3119c349dbc7Sjsg 	 * minimize possible rounding errors.
3120c349dbc7Sjsg 	 */
3121c349dbc7Sjsg 	tmp = (u64)m1 * m2_int * ref_clock +
3122c349dbc7Sjsg 	      (((u64)m1 * m2_frac * ref_clock) >> 22);
3123c349dbc7Sjsg 	tmp = div_u64(tmp, 5 * div1 * div2);
3124c349dbc7Sjsg 
3125c349dbc7Sjsg 	return tmp;
3126c349dbc7Sjsg }
3127c349dbc7Sjsg 
3128c349dbc7Sjsg /**
3129c349dbc7Sjsg  * icl_set_active_port_dpll - select the active port DPLL for a given CRTC
3130c349dbc7Sjsg  * @crtc_state: state for the CRTC to select the DPLL for
3131c349dbc7Sjsg  * @port_dpll_id: the active @port_dpll_id to select
3132c349dbc7Sjsg  *
3133c349dbc7Sjsg  * Select the given @port_dpll_id instance from the DPLLs reserved for the
3134c349dbc7Sjsg  * CRTC.
3135c349dbc7Sjsg  */
3136c349dbc7Sjsg void icl_set_active_port_dpll(struct intel_crtc_state *crtc_state,
3137c349dbc7Sjsg 			      enum icl_port_dpll_id port_dpll_id)
3138c349dbc7Sjsg {
3139c349dbc7Sjsg 	struct icl_port_dpll *port_dpll =
3140c349dbc7Sjsg 		&crtc_state->icl_port_dplls[port_dpll_id];
3141c349dbc7Sjsg 
3142c349dbc7Sjsg 	crtc_state->shared_dpll = port_dpll->pll;
3143c349dbc7Sjsg 	crtc_state->dpll_hw_state = port_dpll->hw_state;
3144c349dbc7Sjsg }
3145c349dbc7Sjsg 
3146c349dbc7Sjsg static void icl_update_active_dpll(struct intel_atomic_state *state,
3147c349dbc7Sjsg 				   struct intel_crtc *crtc,
3148c349dbc7Sjsg 				   struct intel_encoder *encoder)
3149c349dbc7Sjsg {
3150c349dbc7Sjsg 	struct intel_crtc_state *crtc_state =
3151c349dbc7Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
3152c349dbc7Sjsg 	struct intel_digital_port *primary_port;
3153c349dbc7Sjsg 	enum icl_port_dpll_id port_dpll_id = ICL_PORT_DPLL_DEFAULT;
3154c349dbc7Sjsg 
3155c349dbc7Sjsg 	primary_port = encoder->type == INTEL_OUTPUT_DP_MST ?
3156c349dbc7Sjsg 		enc_to_mst(encoder)->primary :
3157c349dbc7Sjsg 		enc_to_dig_port(encoder);
3158c349dbc7Sjsg 
3159c349dbc7Sjsg 	if (primary_port &&
31601bb76ff1Sjsg 	    (intel_tc_port_in_dp_alt_mode(primary_port) ||
31611bb76ff1Sjsg 	     intel_tc_port_in_legacy_mode(primary_port)))
3162c349dbc7Sjsg 		port_dpll_id = ICL_PORT_DPLL_MG_PHY;
3163c349dbc7Sjsg 
3164c349dbc7Sjsg 	icl_set_active_port_dpll(crtc_state, port_dpll_id);
3165c349dbc7Sjsg }
3166c349dbc7Sjsg 
31671bb76ff1Sjsg static int icl_compute_combo_phy_dpll(struct intel_atomic_state *state,
31681bb76ff1Sjsg 				      struct intel_crtc *crtc)
3169c349dbc7Sjsg {
31701bb76ff1Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
3171c349dbc7Sjsg 	struct intel_crtc_state *crtc_state =
3172c349dbc7Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
3173c349dbc7Sjsg 	struct icl_port_dpll *port_dpll =
3174c349dbc7Sjsg 		&crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
31751bb76ff1Sjsg 	struct skl_wrpll_params pll_params = {};
3176ad8b1aafSjsg 	int ret;
3177c349dbc7Sjsg 
3178ad8b1aafSjsg 	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) ||
3179ad8b1aafSjsg 	    intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
3180ad8b1aafSjsg 		ret = icl_calc_wrpll(crtc_state, &pll_params);
3181ad8b1aafSjsg 	else
3182ad8b1aafSjsg 		ret = icl_calc_dp_combo_pll(crtc_state, &pll_params);
3183ad8b1aafSjsg 
31841bb76ff1Sjsg 	if (ret)
31851bb76ff1Sjsg 		return ret;
3186c349dbc7Sjsg 
3187ad8b1aafSjsg 	icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state);
3188ad8b1aafSjsg 
31891bb76ff1Sjsg 	/* this is mainly for the fastset check */
31901bb76ff1Sjsg 	icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT);
31911bb76ff1Sjsg 
31921bb76ff1Sjsg 	crtc_state->port_clock = icl_ddi_combo_pll_get_freq(dev_priv, NULL,
31931bb76ff1Sjsg 							    &port_dpll->hw_state);
31941bb76ff1Sjsg 
31951bb76ff1Sjsg 	return 0;
31961bb76ff1Sjsg }
31971bb76ff1Sjsg 
31981bb76ff1Sjsg static int icl_get_combo_phy_dpll(struct intel_atomic_state *state,
31991bb76ff1Sjsg 				  struct intel_crtc *crtc,
32001bb76ff1Sjsg 				  struct intel_encoder *encoder)
32011bb76ff1Sjsg {
32021bb76ff1Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
32031bb76ff1Sjsg 	struct intel_crtc_state *crtc_state =
32041bb76ff1Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
32051bb76ff1Sjsg 	struct icl_port_dpll *port_dpll =
32061bb76ff1Sjsg 		&crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
32071bb76ff1Sjsg 	enum port port = encoder->port;
32081bb76ff1Sjsg 	unsigned long dpll_mask;
32091bb76ff1Sjsg 
32105ca02815Sjsg 	if (IS_ALDERLAKE_S(dev_priv)) {
32115ca02815Sjsg 		dpll_mask =
32125ca02815Sjsg 			BIT(DPLL_ID_DG1_DPLL3) |
32135ca02815Sjsg 			BIT(DPLL_ID_DG1_DPLL2) |
32145ca02815Sjsg 			BIT(DPLL_ID_ICL_DPLL1) |
32155ca02815Sjsg 			BIT(DPLL_ID_ICL_DPLL0);
32165ca02815Sjsg 	} else if (IS_DG1(dev_priv)) {
32175ca02815Sjsg 		if (port == PORT_D || port == PORT_E) {
32185ca02815Sjsg 			dpll_mask =
32195ca02815Sjsg 				BIT(DPLL_ID_DG1_DPLL2) |
32205ca02815Sjsg 				BIT(DPLL_ID_DG1_DPLL3);
32215ca02815Sjsg 		} else {
32225ca02815Sjsg 			dpll_mask =
32235ca02815Sjsg 				BIT(DPLL_ID_DG1_DPLL0) |
32245ca02815Sjsg 				BIT(DPLL_ID_DG1_DPLL1);
32255ca02815Sjsg 		}
32265ca02815Sjsg 	} else if (IS_ROCKETLAKE(dev_priv)) {
3227c349dbc7Sjsg 		dpll_mask =
3228c349dbc7Sjsg 			BIT(DPLL_ID_EHL_DPLL4) |
3229c349dbc7Sjsg 			BIT(DPLL_ID_ICL_DPLL1) |
3230c349dbc7Sjsg 			BIT(DPLL_ID_ICL_DPLL0);
3231f005ef32Sjsg 	} else if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) &&
3232f005ef32Sjsg 				port != PORT_A) {
3233ad8b1aafSjsg 		dpll_mask =
3234ad8b1aafSjsg 			BIT(DPLL_ID_EHL_DPLL4) |
3235ad8b1aafSjsg 			BIT(DPLL_ID_ICL_DPLL1) |
3236ad8b1aafSjsg 			BIT(DPLL_ID_ICL_DPLL0);
3237ad8b1aafSjsg 	} else {
3238c349dbc7Sjsg 		dpll_mask = BIT(DPLL_ID_ICL_DPLL1) | BIT(DPLL_ID_ICL_DPLL0);
3239ad8b1aafSjsg 	}
3240ad8b1aafSjsg 
3241ad8b1aafSjsg 	/* Eliminate DPLLs from consideration if reserved by HTI */
3242f005ef32Sjsg 	dpll_mask &= ~intel_hti_dpll_mask(dev_priv);
3243c349dbc7Sjsg 
3244c349dbc7Sjsg 	port_dpll->pll = intel_find_shared_dpll(state, crtc,
3245c349dbc7Sjsg 						&port_dpll->hw_state,
3246c349dbc7Sjsg 						dpll_mask);
32471bb76ff1Sjsg 	if (!port_dpll->pll)
32481bb76ff1Sjsg 		return -EINVAL;
3249c349dbc7Sjsg 
3250c349dbc7Sjsg 	intel_reference_shared_dpll(state, crtc,
3251c349dbc7Sjsg 				    port_dpll->pll, &port_dpll->hw_state);
3252c349dbc7Sjsg 
3253c349dbc7Sjsg 	icl_update_active_dpll(state, crtc, encoder);
3254c349dbc7Sjsg 
32551bb76ff1Sjsg 	return 0;
3256c349dbc7Sjsg }
3257c349dbc7Sjsg 
32581bb76ff1Sjsg static int icl_compute_tc_phy_dplls(struct intel_atomic_state *state,
32591bb76ff1Sjsg 				    struct intel_crtc *crtc)
32601bb76ff1Sjsg {
32611bb76ff1Sjsg 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
32621bb76ff1Sjsg 	struct intel_crtc_state *crtc_state =
32631bb76ff1Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
32641bb76ff1Sjsg 	struct icl_port_dpll *port_dpll =
32651bb76ff1Sjsg 		&crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
32661bb76ff1Sjsg 	struct skl_wrpll_params pll_params = {};
32671bb76ff1Sjsg 	int ret;
32681bb76ff1Sjsg 
32691bb76ff1Sjsg 	port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
32701bb76ff1Sjsg 	ret = icl_calc_tbt_pll(crtc_state, &pll_params);
32711bb76ff1Sjsg 	if (ret)
32721bb76ff1Sjsg 		return ret;
32731bb76ff1Sjsg 
32741bb76ff1Sjsg 	icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state);
32751bb76ff1Sjsg 
32761bb76ff1Sjsg 	port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY];
32771bb76ff1Sjsg 	ret = icl_calc_mg_pll_state(crtc_state, &port_dpll->hw_state);
32781bb76ff1Sjsg 	if (ret)
32791bb76ff1Sjsg 		return ret;
32801bb76ff1Sjsg 
32811bb76ff1Sjsg 	/* this is mainly for the fastset check */
32821bb76ff1Sjsg 	icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_MG_PHY);
32831bb76ff1Sjsg 
32841bb76ff1Sjsg 	crtc_state->port_clock = icl_ddi_mg_pll_get_freq(dev_priv, NULL,
32851bb76ff1Sjsg 							 &port_dpll->hw_state);
32861bb76ff1Sjsg 
32871bb76ff1Sjsg 	return 0;
32881bb76ff1Sjsg }
32891bb76ff1Sjsg 
32901bb76ff1Sjsg static int icl_get_tc_phy_dplls(struct intel_atomic_state *state,
3291c349dbc7Sjsg 				struct intel_crtc *crtc,
3292c349dbc7Sjsg 				struct intel_encoder *encoder)
3293c349dbc7Sjsg {
3294c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
3295c349dbc7Sjsg 	struct intel_crtc_state *crtc_state =
3296c349dbc7Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
32971bb76ff1Sjsg 	struct icl_port_dpll *port_dpll =
32981bb76ff1Sjsg 		&crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
3299c349dbc7Sjsg 	enum intel_dpll_id dpll_id;
33001bb76ff1Sjsg 	int ret;
3301c349dbc7Sjsg 
3302c349dbc7Sjsg 	port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
3303c349dbc7Sjsg 	port_dpll->pll = intel_find_shared_dpll(state, crtc,
3304c349dbc7Sjsg 						&port_dpll->hw_state,
3305c349dbc7Sjsg 						BIT(DPLL_ID_ICL_TBTPLL));
33061bb76ff1Sjsg 	if (!port_dpll->pll)
33071bb76ff1Sjsg 		return -EINVAL;
3308c349dbc7Sjsg 	intel_reference_shared_dpll(state, crtc,
3309c349dbc7Sjsg 				    port_dpll->pll, &port_dpll->hw_state);
3310c349dbc7Sjsg 
3311c349dbc7Sjsg 
3312c349dbc7Sjsg 	port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY];
3313c349dbc7Sjsg 	dpll_id = icl_tc_port_to_pll_id(intel_port_to_tc(dev_priv,
3314c349dbc7Sjsg 							 encoder->port));
3315c349dbc7Sjsg 	port_dpll->pll = intel_find_shared_dpll(state, crtc,
3316c349dbc7Sjsg 						&port_dpll->hw_state,
3317c349dbc7Sjsg 						BIT(dpll_id));
3318c349dbc7Sjsg 	if (!port_dpll->pll) {
33191bb76ff1Sjsg 		ret = -EINVAL;
3320c349dbc7Sjsg 		goto err_unreference_tbt_pll;
3321c349dbc7Sjsg 	}
3322c349dbc7Sjsg 	intel_reference_shared_dpll(state, crtc,
3323c349dbc7Sjsg 				    port_dpll->pll, &port_dpll->hw_state);
3324c349dbc7Sjsg 
3325c349dbc7Sjsg 	icl_update_active_dpll(state, crtc, encoder);
3326c349dbc7Sjsg 
33271bb76ff1Sjsg 	return 0;
3328c349dbc7Sjsg 
3329c349dbc7Sjsg err_unreference_tbt_pll:
3330c349dbc7Sjsg 	port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT];
3331c349dbc7Sjsg 	intel_unreference_shared_dpll(state, crtc, port_dpll->pll);
3332c349dbc7Sjsg 
33331bb76ff1Sjsg 	return ret;
3334c349dbc7Sjsg }
3335c349dbc7Sjsg 
33361bb76ff1Sjsg static int icl_compute_dplls(struct intel_atomic_state *state,
33371bb76ff1Sjsg 			     struct intel_crtc *crtc,
33381bb76ff1Sjsg 			     struct intel_encoder *encoder)
33391bb76ff1Sjsg {
33401bb76ff1Sjsg 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
33411bb76ff1Sjsg 	enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
33421bb76ff1Sjsg 
33431bb76ff1Sjsg 	if (intel_phy_is_combo(dev_priv, phy))
33441bb76ff1Sjsg 		return icl_compute_combo_phy_dpll(state, crtc);
33451bb76ff1Sjsg 	else if (intel_phy_is_tc(dev_priv, phy))
33461bb76ff1Sjsg 		return icl_compute_tc_phy_dplls(state, crtc);
33471bb76ff1Sjsg 
33481bb76ff1Sjsg 	MISSING_CASE(phy);
33491bb76ff1Sjsg 
33501bb76ff1Sjsg 	return 0;
33511bb76ff1Sjsg }
33521bb76ff1Sjsg 
33531bb76ff1Sjsg static int icl_get_dplls(struct intel_atomic_state *state,
3354c349dbc7Sjsg 			 struct intel_crtc *crtc,
3355c349dbc7Sjsg 			 struct intel_encoder *encoder)
3356c349dbc7Sjsg {
3357c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
3358c349dbc7Sjsg 	enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
3359c349dbc7Sjsg 
3360c349dbc7Sjsg 	if (intel_phy_is_combo(dev_priv, phy))
3361c349dbc7Sjsg 		return icl_get_combo_phy_dpll(state, crtc, encoder);
3362c349dbc7Sjsg 	else if (intel_phy_is_tc(dev_priv, phy))
3363c349dbc7Sjsg 		return icl_get_tc_phy_dplls(state, crtc, encoder);
3364c349dbc7Sjsg 
3365c349dbc7Sjsg 	MISSING_CASE(phy);
3366c349dbc7Sjsg 
33671bb76ff1Sjsg 	return -EINVAL;
3368c349dbc7Sjsg }
3369c349dbc7Sjsg 
3370c349dbc7Sjsg static void icl_put_dplls(struct intel_atomic_state *state,
3371c349dbc7Sjsg 			  struct intel_crtc *crtc)
3372c349dbc7Sjsg {
3373c349dbc7Sjsg 	const struct intel_crtc_state *old_crtc_state =
3374c349dbc7Sjsg 		intel_atomic_get_old_crtc_state(state, crtc);
3375c349dbc7Sjsg 	struct intel_crtc_state *new_crtc_state =
3376c349dbc7Sjsg 		intel_atomic_get_new_crtc_state(state, crtc);
3377c349dbc7Sjsg 	enum icl_port_dpll_id id;
3378c349dbc7Sjsg 
3379c349dbc7Sjsg 	new_crtc_state->shared_dpll = NULL;
3380c349dbc7Sjsg 
3381c349dbc7Sjsg 	for (id = ICL_PORT_DPLL_DEFAULT; id < ICL_PORT_DPLL_COUNT; id++) {
3382c349dbc7Sjsg 		const struct icl_port_dpll *old_port_dpll =
3383c349dbc7Sjsg 			&old_crtc_state->icl_port_dplls[id];
3384c349dbc7Sjsg 		struct icl_port_dpll *new_port_dpll =
3385c349dbc7Sjsg 			&new_crtc_state->icl_port_dplls[id];
3386c349dbc7Sjsg 
3387c349dbc7Sjsg 		new_port_dpll->pll = NULL;
3388c349dbc7Sjsg 
3389c349dbc7Sjsg 		if (!old_port_dpll->pll)
3390c349dbc7Sjsg 			continue;
3391c349dbc7Sjsg 
3392c349dbc7Sjsg 		intel_unreference_shared_dpll(state, crtc, old_port_dpll->pll);
3393c349dbc7Sjsg 	}
3394c349dbc7Sjsg }
3395c349dbc7Sjsg 
3396c349dbc7Sjsg static bool mg_pll_get_hw_state(struct drm_i915_private *dev_priv,
3397c349dbc7Sjsg 				struct intel_shared_dpll *pll,
3398c349dbc7Sjsg 				struct intel_dpll_hw_state *hw_state)
3399c349dbc7Sjsg {
3400c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
3401c349dbc7Sjsg 	enum tc_port tc_port = icl_pll_id_to_tc_port(id);
3402c349dbc7Sjsg 	intel_wakeref_t wakeref;
3403c349dbc7Sjsg 	bool ret = false;
3404c349dbc7Sjsg 	u32 val;
3405c349dbc7Sjsg 
34065ca02815Sjsg 	i915_reg_t enable_reg = intel_tc_pll_enable_reg(dev_priv, pll);
34075ca02815Sjsg 
3408c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv,
3409c349dbc7Sjsg 						     POWER_DOMAIN_DISPLAY_CORE);
3410c349dbc7Sjsg 	if (!wakeref)
3411c349dbc7Sjsg 		return false;
3412c349dbc7Sjsg 
34135ca02815Sjsg 	val = intel_de_read(dev_priv, enable_reg);
3414c349dbc7Sjsg 	if (!(val & PLL_ENABLE))
3415c349dbc7Sjsg 		goto out;
3416c349dbc7Sjsg 
3417c349dbc7Sjsg 	hw_state->mg_refclkin_ctl = intel_de_read(dev_priv,
3418c349dbc7Sjsg 						  MG_REFCLKIN_CTL(tc_port));
3419c349dbc7Sjsg 	hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK;
3420c349dbc7Sjsg 
3421c349dbc7Sjsg 	hw_state->mg_clktop2_coreclkctl1 =
3422c349dbc7Sjsg 		intel_de_read(dev_priv, MG_CLKTOP2_CORECLKCTL1(tc_port));
3423c349dbc7Sjsg 	hw_state->mg_clktop2_coreclkctl1 &=
3424c349dbc7Sjsg 		MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK;
3425c349dbc7Sjsg 
3426c349dbc7Sjsg 	hw_state->mg_clktop2_hsclkctl =
3427c349dbc7Sjsg 		intel_de_read(dev_priv, MG_CLKTOP2_HSCLKCTL(tc_port));
3428c349dbc7Sjsg 	hw_state->mg_clktop2_hsclkctl &=
3429c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK |
3430c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK |
3431c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK |
3432c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK;
3433c349dbc7Sjsg 
3434c349dbc7Sjsg 	hw_state->mg_pll_div0 = intel_de_read(dev_priv, MG_PLL_DIV0(tc_port));
3435c349dbc7Sjsg 	hw_state->mg_pll_div1 = intel_de_read(dev_priv, MG_PLL_DIV1(tc_port));
3436c349dbc7Sjsg 	hw_state->mg_pll_lf = intel_de_read(dev_priv, MG_PLL_LF(tc_port));
3437c349dbc7Sjsg 	hw_state->mg_pll_frac_lock = intel_de_read(dev_priv,
3438c349dbc7Sjsg 						   MG_PLL_FRAC_LOCK(tc_port));
3439c349dbc7Sjsg 	hw_state->mg_pll_ssc = intel_de_read(dev_priv, MG_PLL_SSC(tc_port));
3440c349dbc7Sjsg 
3441c349dbc7Sjsg 	hw_state->mg_pll_bias = intel_de_read(dev_priv, MG_PLL_BIAS(tc_port));
3442c349dbc7Sjsg 	hw_state->mg_pll_tdc_coldst_bias =
3443c349dbc7Sjsg 		intel_de_read(dev_priv, MG_PLL_TDC_COLDST_BIAS(tc_port));
3444c349dbc7Sjsg 
34451bb76ff1Sjsg 	if (dev_priv->display.dpll.ref_clks.nssc == 38400) {
3446c349dbc7Sjsg 		hw_state->mg_pll_tdc_coldst_bias_mask = MG_PLL_TDC_COLDST_COLDSTART;
3447c349dbc7Sjsg 		hw_state->mg_pll_bias_mask = 0;
3448c349dbc7Sjsg 	} else {
3449c349dbc7Sjsg 		hw_state->mg_pll_tdc_coldst_bias_mask = -1U;
3450c349dbc7Sjsg 		hw_state->mg_pll_bias_mask = -1U;
3451c349dbc7Sjsg 	}
3452c349dbc7Sjsg 
3453c349dbc7Sjsg 	hw_state->mg_pll_tdc_coldst_bias &= hw_state->mg_pll_tdc_coldst_bias_mask;
3454c349dbc7Sjsg 	hw_state->mg_pll_bias &= hw_state->mg_pll_bias_mask;
3455c349dbc7Sjsg 
3456c349dbc7Sjsg 	ret = true;
3457c349dbc7Sjsg out:
3458c349dbc7Sjsg 	intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref);
3459c349dbc7Sjsg 	return ret;
3460c349dbc7Sjsg }
3461c349dbc7Sjsg 
3462c349dbc7Sjsg static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv,
3463c349dbc7Sjsg 				 struct intel_shared_dpll *pll,
3464c349dbc7Sjsg 				 struct intel_dpll_hw_state *hw_state)
3465c349dbc7Sjsg {
3466c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
3467c349dbc7Sjsg 	enum tc_port tc_port = icl_pll_id_to_tc_port(id);
3468c349dbc7Sjsg 	intel_wakeref_t wakeref;
3469c349dbc7Sjsg 	bool ret = false;
3470c349dbc7Sjsg 	u32 val;
3471c349dbc7Sjsg 
3472c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv,
3473c349dbc7Sjsg 						     POWER_DOMAIN_DISPLAY_CORE);
3474c349dbc7Sjsg 	if (!wakeref)
3475c349dbc7Sjsg 		return false;
3476c349dbc7Sjsg 
34775ca02815Sjsg 	val = intel_de_read(dev_priv, intel_tc_pll_enable_reg(dev_priv, pll));
3478c349dbc7Sjsg 	if (!(val & PLL_ENABLE))
3479c349dbc7Sjsg 		goto out;
3480c349dbc7Sjsg 
3481c349dbc7Sjsg 	/*
3482c349dbc7Sjsg 	 * All registers read here have the same HIP_INDEX_REG even though
3483c349dbc7Sjsg 	 * they are on different building blocks
3484c349dbc7Sjsg 	 */
34851bb76ff1Sjsg 	hw_state->mg_refclkin_ctl = intel_dkl_phy_read(dev_priv,
3486f005ef32Sjsg 						       DKL_REFCLKIN_CTL(tc_port));
3487c349dbc7Sjsg 	hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK;
3488c349dbc7Sjsg 
3489c349dbc7Sjsg 	hw_state->mg_clktop2_hsclkctl =
3490f005ef32Sjsg 		intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port));
3491c349dbc7Sjsg 	hw_state->mg_clktop2_hsclkctl &=
3492c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK |
3493c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK |
3494c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK |
3495c349dbc7Sjsg 		MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK;
3496c349dbc7Sjsg 
3497c349dbc7Sjsg 	hw_state->mg_clktop2_coreclkctl1 =
3498f005ef32Sjsg 		intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port));
3499c349dbc7Sjsg 	hw_state->mg_clktop2_coreclkctl1 &=
3500c349dbc7Sjsg 		MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK;
3501c349dbc7Sjsg 
3502f005ef32Sjsg 	hw_state->mg_pll_div0 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV0(tc_port));
35031bb76ff1Sjsg 	val = DKL_PLL_DIV0_MASK;
35041bb76ff1Sjsg 	if (dev_priv->display.vbt.override_afc_startup)
35051bb76ff1Sjsg 		val |= DKL_PLL_DIV0_AFC_STARTUP_MASK;
35061bb76ff1Sjsg 	hw_state->mg_pll_div0 &= val;
3507c349dbc7Sjsg 
3508f005ef32Sjsg 	hw_state->mg_pll_div1 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port));
3509c349dbc7Sjsg 	hw_state->mg_pll_div1 &= (DKL_PLL_DIV1_IREF_TRIM_MASK |
3510c349dbc7Sjsg 				  DKL_PLL_DIV1_TDC_TARGET_CNT_MASK);
3511c349dbc7Sjsg 
3512f005ef32Sjsg 	hw_state->mg_pll_ssc = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port));
3513c349dbc7Sjsg 	hw_state->mg_pll_ssc &= (DKL_PLL_SSC_IREF_NDIV_RATIO_MASK |
3514c349dbc7Sjsg 				 DKL_PLL_SSC_STEP_LEN_MASK |
3515c349dbc7Sjsg 				 DKL_PLL_SSC_STEP_NUM_MASK |
3516c349dbc7Sjsg 				 DKL_PLL_SSC_EN);
3517c349dbc7Sjsg 
3518f005ef32Sjsg 	hw_state->mg_pll_bias = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port));
3519c349dbc7Sjsg 	hw_state->mg_pll_bias &= (DKL_PLL_BIAS_FRAC_EN_H |
3520c349dbc7Sjsg 				  DKL_PLL_BIAS_FBDIV_FRAC_MASK);
3521c349dbc7Sjsg 
3522c349dbc7Sjsg 	hw_state->mg_pll_tdc_coldst_bias =
3523f005ef32Sjsg 		intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port));
3524c349dbc7Sjsg 	hw_state->mg_pll_tdc_coldst_bias &= (DKL_PLL_TDC_SSC_STEP_SIZE_MASK |
3525c349dbc7Sjsg 					     DKL_PLL_TDC_FEED_FWD_GAIN_MASK);
3526c349dbc7Sjsg 
3527c349dbc7Sjsg 	ret = true;
3528c349dbc7Sjsg out:
3529c349dbc7Sjsg 	intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref);
3530c349dbc7Sjsg 	return ret;
3531c349dbc7Sjsg }
3532c349dbc7Sjsg 
3533c349dbc7Sjsg static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
3534c349dbc7Sjsg 				 struct intel_shared_dpll *pll,
3535c349dbc7Sjsg 				 struct intel_dpll_hw_state *hw_state,
3536c349dbc7Sjsg 				 i915_reg_t enable_reg)
3537c349dbc7Sjsg {
3538c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
3539c349dbc7Sjsg 	intel_wakeref_t wakeref;
3540c349dbc7Sjsg 	bool ret = false;
3541c349dbc7Sjsg 	u32 val;
3542c349dbc7Sjsg 
3543c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv,
3544c349dbc7Sjsg 						     POWER_DOMAIN_DISPLAY_CORE);
3545c349dbc7Sjsg 	if (!wakeref)
3546c349dbc7Sjsg 		return false;
3547c349dbc7Sjsg 
3548c349dbc7Sjsg 	val = intel_de_read(dev_priv, enable_reg);
3549c349dbc7Sjsg 	if (!(val & PLL_ENABLE))
3550c349dbc7Sjsg 		goto out;
3551c349dbc7Sjsg 
35525ca02815Sjsg 	if (IS_ALDERLAKE_S(dev_priv)) {
35535ca02815Sjsg 		hw_state->cfgcr0 = intel_de_read(dev_priv, ADLS_DPLL_CFGCR0(id));
35545ca02815Sjsg 		hw_state->cfgcr1 = intel_de_read(dev_priv, ADLS_DPLL_CFGCR1(id));
35555ca02815Sjsg 	} else if (IS_DG1(dev_priv)) {
35565ca02815Sjsg 		hw_state->cfgcr0 = intel_de_read(dev_priv, DG1_DPLL_CFGCR0(id));
35575ca02815Sjsg 		hw_state->cfgcr1 = intel_de_read(dev_priv, DG1_DPLL_CFGCR1(id));
35585ca02815Sjsg 	} else if (IS_ROCKETLAKE(dev_priv)) {
3559ad8b1aafSjsg 		hw_state->cfgcr0 = intel_de_read(dev_priv,
3560ad8b1aafSjsg 						 RKL_DPLL_CFGCR0(id));
3561ad8b1aafSjsg 		hw_state->cfgcr1 = intel_de_read(dev_priv,
3562ad8b1aafSjsg 						 RKL_DPLL_CFGCR1(id));
35635ca02815Sjsg 	} else if (DISPLAY_VER(dev_priv) >= 12) {
3564c349dbc7Sjsg 		hw_state->cfgcr0 = intel_de_read(dev_priv,
3565c349dbc7Sjsg 						 TGL_DPLL_CFGCR0(id));
3566c349dbc7Sjsg 		hw_state->cfgcr1 = intel_de_read(dev_priv,
3567c349dbc7Sjsg 						 TGL_DPLL_CFGCR1(id));
35681bb76ff1Sjsg 		if (dev_priv->display.vbt.override_afc_startup) {
35691bb76ff1Sjsg 			hw_state->div0 = intel_de_read(dev_priv, TGL_DPLL0_DIV0(id));
35701bb76ff1Sjsg 			hw_state->div0 &= TGL_DPLL0_DIV0_AFC_STARTUP_MASK;
35711bb76ff1Sjsg 		}
3572c349dbc7Sjsg 	} else {
3573f005ef32Sjsg 		if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) &&
3574f005ef32Sjsg 		    id == DPLL_ID_EHL_DPLL4) {
3575c349dbc7Sjsg 			hw_state->cfgcr0 = intel_de_read(dev_priv,
3576c349dbc7Sjsg 							 ICL_DPLL_CFGCR0(4));
3577c349dbc7Sjsg 			hw_state->cfgcr1 = intel_de_read(dev_priv,
3578c349dbc7Sjsg 							 ICL_DPLL_CFGCR1(4));
3579c349dbc7Sjsg 		} else {
3580c349dbc7Sjsg 			hw_state->cfgcr0 = intel_de_read(dev_priv,
3581c349dbc7Sjsg 							 ICL_DPLL_CFGCR0(id));
3582c349dbc7Sjsg 			hw_state->cfgcr1 = intel_de_read(dev_priv,
3583c349dbc7Sjsg 							 ICL_DPLL_CFGCR1(id));
3584c349dbc7Sjsg 		}
3585c349dbc7Sjsg 	}
3586c349dbc7Sjsg 
3587c349dbc7Sjsg 	ret = true;
3588c349dbc7Sjsg out:
3589c349dbc7Sjsg 	intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref);
3590c349dbc7Sjsg 	return ret;
3591c349dbc7Sjsg }
3592c349dbc7Sjsg 
3593c349dbc7Sjsg static bool combo_pll_get_hw_state(struct drm_i915_private *dev_priv,
3594c349dbc7Sjsg 				   struct intel_shared_dpll *pll,
3595c349dbc7Sjsg 				   struct intel_dpll_hw_state *hw_state)
3596c349dbc7Sjsg {
3597ad8b1aafSjsg 	i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll);
3598c349dbc7Sjsg 
3599c349dbc7Sjsg 	return icl_pll_get_hw_state(dev_priv, pll, hw_state, enable_reg);
3600c349dbc7Sjsg }
3601c349dbc7Sjsg 
3602c349dbc7Sjsg static bool tbt_pll_get_hw_state(struct drm_i915_private *dev_priv,
3603c349dbc7Sjsg 				 struct intel_shared_dpll *pll,
3604c349dbc7Sjsg 				 struct intel_dpll_hw_state *hw_state)
3605c349dbc7Sjsg {
3606c349dbc7Sjsg 	return icl_pll_get_hw_state(dev_priv, pll, hw_state, TBT_PLL_ENABLE);
3607c349dbc7Sjsg }
3608c349dbc7Sjsg 
3609c349dbc7Sjsg static void icl_dpll_write(struct drm_i915_private *dev_priv,
3610c349dbc7Sjsg 			   struct intel_shared_dpll *pll)
3611c349dbc7Sjsg {
3612c349dbc7Sjsg 	struct intel_dpll_hw_state *hw_state = &pll->state.hw_state;
3613c349dbc7Sjsg 	const enum intel_dpll_id id = pll->info->id;
36141bb76ff1Sjsg 	i915_reg_t cfgcr0_reg, cfgcr1_reg, div0_reg = INVALID_MMIO_REG;
3615c349dbc7Sjsg 
36165ca02815Sjsg 	if (IS_ALDERLAKE_S(dev_priv)) {
36175ca02815Sjsg 		cfgcr0_reg = ADLS_DPLL_CFGCR0(id);
36185ca02815Sjsg 		cfgcr1_reg = ADLS_DPLL_CFGCR1(id);
36195ca02815Sjsg 	} else if (IS_DG1(dev_priv)) {
36205ca02815Sjsg 		cfgcr0_reg = DG1_DPLL_CFGCR0(id);
36215ca02815Sjsg 		cfgcr1_reg = DG1_DPLL_CFGCR1(id);
36225ca02815Sjsg 	} else if (IS_ROCKETLAKE(dev_priv)) {
3623ad8b1aafSjsg 		cfgcr0_reg = RKL_DPLL_CFGCR0(id);
3624ad8b1aafSjsg 		cfgcr1_reg = RKL_DPLL_CFGCR1(id);
36255ca02815Sjsg 	} else if (DISPLAY_VER(dev_priv) >= 12) {
3626c349dbc7Sjsg 		cfgcr0_reg = TGL_DPLL_CFGCR0(id);
3627c349dbc7Sjsg 		cfgcr1_reg = TGL_DPLL_CFGCR1(id);
36281bb76ff1Sjsg 		div0_reg = TGL_DPLL0_DIV0(id);
3629c349dbc7Sjsg 	} else {
3630f005ef32Sjsg 		if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) &&
3631f005ef32Sjsg 		    id == DPLL_ID_EHL_DPLL4) {
3632c349dbc7Sjsg 			cfgcr0_reg = ICL_DPLL_CFGCR0(4);
3633c349dbc7Sjsg 			cfgcr1_reg = ICL_DPLL_CFGCR1(4);
3634c349dbc7Sjsg 		} else {
3635c349dbc7Sjsg 			cfgcr0_reg = ICL_DPLL_CFGCR0(id);
3636c349dbc7Sjsg 			cfgcr1_reg = ICL_DPLL_CFGCR1(id);
3637c349dbc7Sjsg 		}
3638c349dbc7Sjsg 	}
3639c349dbc7Sjsg 
3640c349dbc7Sjsg 	intel_de_write(dev_priv, cfgcr0_reg, hw_state->cfgcr0);
3641c349dbc7Sjsg 	intel_de_write(dev_priv, cfgcr1_reg, hw_state->cfgcr1);
36421bb76ff1Sjsg 	drm_WARN_ON_ONCE(&dev_priv->drm, dev_priv->display.vbt.override_afc_startup &&
36431bb76ff1Sjsg 			 !i915_mmio_reg_valid(div0_reg));
36441bb76ff1Sjsg 	if (dev_priv->display.vbt.override_afc_startup &&
36451bb76ff1Sjsg 	    i915_mmio_reg_valid(div0_reg))
3646f005ef32Sjsg 		intel_de_rmw(dev_priv, div0_reg,
3647f005ef32Sjsg 			     TGL_DPLL0_DIV0_AFC_STARTUP_MASK, hw_state->div0);
3648c349dbc7Sjsg 	intel_de_posting_read(dev_priv, cfgcr1_reg);
3649c349dbc7Sjsg }
3650c349dbc7Sjsg 
3651c349dbc7Sjsg static void icl_mg_pll_write(struct drm_i915_private *dev_priv,
3652c349dbc7Sjsg 			     struct intel_shared_dpll *pll)
3653c349dbc7Sjsg {
3654c349dbc7Sjsg 	struct intel_dpll_hw_state *hw_state = &pll->state.hw_state;
3655c349dbc7Sjsg 	enum tc_port tc_port = icl_pll_id_to_tc_port(pll->info->id);
3656c349dbc7Sjsg 
3657c349dbc7Sjsg 	/*
3658c349dbc7Sjsg 	 * Some of the following registers have reserved fields, so program
3659c349dbc7Sjsg 	 * these with RMW based on a mask. The mask can be fixed or generated
3660c349dbc7Sjsg 	 * during the calc/readout phase if the mask depends on some other HW
3661c349dbc7Sjsg 	 * state like refclk, see icl_calc_mg_pll_state().
3662c349dbc7Sjsg 	 */
3663f005ef32Sjsg 	intel_de_rmw(dev_priv, MG_REFCLKIN_CTL(tc_port),
3664f005ef32Sjsg 		     MG_REFCLKIN_CTL_OD_2_MUX_MASK, hw_state->mg_refclkin_ctl);
3665c349dbc7Sjsg 
3666f005ef32Sjsg 	intel_de_rmw(dev_priv, MG_CLKTOP2_CORECLKCTL1(tc_port),
3667f005ef32Sjsg 		     MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK,
3668f005ef32Sjsg 		     hw_state->mg_clktop2_coreclkctl1);
3669c349dbc7Sjsg 
3670f005ef32Sjsg 	intel_de_rmw(dev_priv, MG_CLKTOP2_HSCLKCTL(tc_port),
3671f005ef32Sjsg 		     MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK |
3672c349dbc7Sjsg 		     MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK |
3673c349dbc7Sjsg 		     MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK |
3674f005ef32Sjsg 		     MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK,
3675f005ef32Sjsg 		     hw_state->mg_clktop2_hsclkctl);
3676c349dbc7Sjsg 
3677c349dbc7Sjsg 	intel_de_write(dev_priv, MG_PLL_DIV0(tc_port), hw_state->mg_pll_div0);
3678c349dbc7Sjsg 	intel_de_write(dev_priv, MG_PLL_DIV1(tc_port), hw_state->mg_pll_div1);
3679c349dbc7Sjsg 	intel_de_write(dev_priv, MG_PLL_LF(tc_port), hw_state->mg_pll_lf);
3680c349dbc7Sjsg 	intel_de_write(dev_priv, MG_PLL_FRAC_LOCK(tc_port),
3681c349dbc7Sjsg 		       hw_state->mg_pll_frac_lock);
3682c349dbc7Sjsg 	intel_de_write(dev_priv, MG_PLL_SSC(tc_port), hw_state->mg_pll_ssc);
3683c349dbc7Sjsg 
3684f005ef32Sjsg 	intel_de_rmw(dev_priv, MG_PLL_BIAS(tc_port),
3685f005ef32Sjsg 		     hw_state->mg_pll_bias_mask, hw_state->mg_pll_bias);
3686c349dbc7Sjsg 
3687f005ef32Sjsg 	intel_de_rmw(dev_priv, MG_PLL_TDC_COLDST_BIAS(tc_port),
3688f005ef32Sjsg 		     hw_state->mg_pll_tdc_coldst_bias_mask,
3689f005ef32Sjsg 		     hw_state->mg_pll_tdc_coldst_bias);
3690c349dbc7Sjsg 
3691c349dbc7Sjsg 	intel_de_posting_read(dev_priv, MG_PLL_TDC_COLDST_BIAS(tc_port));
3692c349dbc7Sjsg }
3693c349dbc7Sjsg 
3694c349dbc7Sjsg static void dkl_pll_write(struct drm_i915_private *dev_priv,
3695c349dbc7Sjsg 			  struct intel_shared_dpll *pll)
3696c349dbc7Sjsg {
3697c349dbc7Sjsg 	struct intel_dpll_hw_state *hw_state = &pll->state.hw_state;
3698c349dbc7Sjsg 	enum tc_port tc_port = icl_pll_id_to_tc_port(pll->info->id);
3699c349dbc7Sjsg 	u32 val;
3700c349dbc7Sjsg 
3701c349dbc7Sjsg 	/*
3702c349dbc7Sjsg 	 * All registers programmed here have the same HIP_INDEX_REG even
3703c349dbc7Sjsg 	 * though on different building block
3704c349dbc7Sjsg 	 */
3705c349dbc7Sjsg 	/* All the registers are RMW */
3706f005ef32Sjsg 	val = intel_dkl_phy_read(dev_priv, DKL_REFCLKIN_CTL(tc_port));
3707c349dbc7Sjsg 	val &= ~MG_REFCLKIN_CTL_OD_2_MUX_MASK;
3708c349dbc7Sjsg 	val |= hw_state->mg_refclkin_ctl;
3709f005ef32Sjsg 	intel_dkl_phy_write(dev_priv, DKL_REFCLKIN_CTL(tc_port), val);
3710c349dbc7Sjsg 
3711f005ef32Sjsg 	val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port));
3712c349dbc7Sjsg 	val &= ~MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK;
3713c349dbc7Sjsg 	val |= hw_state->mg_clktop2_coreclkctl1;
3714f005ef32Sjsg 	intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), val);
3715c349dbc7Sjsg 
3716f005ef32Sjsg 	val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port));
3717c349dbc7Sjsg 	val &= ~(MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK |
3718c349dbc7Sjsg 		 MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK |
3719c349dbc7Sjsg 		 MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK |
3720c349dbc7Sjsg 		 MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK);
3721c349dbc7Sjsg 	val |= hw_state->mg_clktop2_hsclkctl;
3722f005ef32Sjsg 	intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), val);
3723c349dbc7Sjsg 
37241bb76ff1Sjsg 	val = DKL_PLL_DIV0_MASK;
37251bb76ff1Sjsg 	if (dev_priv->display.vbt.override_afc_startup)
37261bb76ff1Sjsg 		val |= DKL_PLL_DIV0_AFC_STARTUP_MASK;
3727f005ef32Sjsg 	intel_dkl_phy_rmw(dev_priv, DKL_PLL_DIV0(tc_port), val,
37281bb76ff1Sjsg 			  hw_state->mg_pll_div0);
3729c349dbc7Sjsg 
3730f005ef32Sjsg 	val = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port));
3731c349dbc7Sjsg 	val &= ~(DKL_PLL_DIV1_IREF_TRIM_MASK |
3732c349dbc7Sjsg 		 DKL_PLL_DIV1_TDC_TARGET_CNT_MASK);
3733c349dbc7Sjsg 	val |= hw_state->mg_pll_div1;
3734f005ef32Sjsg 	intel_dkl_phy_write(dev_priv, DKL_PLL_DIV1(tc_port), val);
3735c349dbc7Sjsg 
3736f005ef32Sjsg 	val = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port));
3737c349dbc7Sjsg 	val &= ~(DKL_PLL_SSC_IREF_NDIV_RATIO_MASK |
3738c349dbc7Sjsg 		 DKL_PLL_SSC_STEP_LEN_MASK |
3739c349dbc7Sjsg 		 DKL_PLL_SSC_STEP_NUM_MASK |
3740c349dbc7Sjsg 		 DKL_PLL_SSC_EN);
3741c349dbc7Sjsg 	val |= hw_state->mg_pll_ssc;
3742f005ef32Sjsg 	intel_dkl_phy_write(dev_priv, DKL_PLL_SSC(tc_port), val);
3743c349dbc7Sjsg 
3744f005ef32Sjsg 	val = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port));
3745c349dbc7Sjsg 	val &= ~(DKL_PLL_BIAS_FRAC_EN_H |
3746c349dbc7Sjsg 		 DKL_PLL_BIAS_FBDIV_FRAC_MASK);
3747c349dbc7Sjsg 	val |= hw_state->mg_pll_bias;
3748f005ef32Sjsg 	intel_dkl_phy_write(dev_priv, DKL_PLL_BIAS(tc_port), val);
3749c349dbc7Sjsg 
3750f005ef32Sjsg 	val = intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port));
3751c349dbc7Sjsg 	val &= ~(DKL_PLL_TDC_SSC_STEP_SIZE_MASK |
3752c349dbc7Sjsg 		 DKL_PLL_TDC_FEED_FWD_GAIN_MASK);
3753c349dbc7Sjsg 	val |= hw_state->mg_pll_tdc_coldst_bias;
3754f005ef32Sjsg 	intel_dkl_phy_write(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), val);
3755c349dbc7Sjsg 
3756f005ef32Sjsg 	intel_dkl_phy_posting_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port));
3757c349dbc7Sjsg }
3758c349dbc7Sjsg 
3759c349dbc7Sjsg static void icl_pll_power_enable(struct drm_i915_private *dev_priv,
3760c349dbc7Sjsg 				 struct intel_shared_dpll *pll,
3761c349dbc7Sjsg 				 i915_reg_t enable_reg)
3762c349dbc7Sjsg {
3763f005ef32Sjsg 	intel_de_rmw(dev_priv, enable_reg, 0, PLL_POWER_ENABLE);
3764c349dbc7Sjsg 
3765c349dbc7Sjsg 	/*
3766c349dbc7Sjsg 	 * The spec says we need to "wait" but it also says it should be
3767c349dbc7Sjsg 	 * immediate.
3768c349dbc7Sjsg 	 */
3769c349dbc7Sjsg 	if (intel_de_wait_for_set(dev_priv, enable_reg, PLL_POWER_STATE, 1))
3770c349dbc7Sjsg 		drm_err(&dev_priv->drm, "PLL %d Power not enabled\n",
3771c349dbc7Sjsg 			pll->info->id);
3772c349dbc7Sjsg }
3773c349dbc7Sjsg 
3774c349dbc7Sjsg static void icl_pll_enable(struct drm_i915_private *dev_priv,
3775c349dbc7Sjsg 			   struct intel_shared_dpll *pll,
3776c349dbc7Sjsg 			   i915_reg_t enable_reg)
3777c349dbc7Sjsg {
3778f005ef32Sjsg 	intel_de_rmw(dev_priv, enable_reg, 0, PLL_ENABLE);
3779c349dbc7Sjsg 
3780c349dbc7Sjsg 	/* Timeout is actually 600us. */
3781c349dbc7Sjsg 	if (intel_de_wait_for_set(dev_priv, enable_reg, PLL_LOCK, 1))
3782c349dbc7Sjsg 		drm_err(&dev_priv->drm, "PLL %d not locked\n", pll->info->id);
3783c349dbc7Sjsg }
3784c349dbc7Sjsg 
37855ca02815Sjsg static void adlp_cmtg_clock_gating_wa(struct drm_i915_private *i915, struct intel_shared_dpll *pll)
37865ca02815Sjsg {
37875ca02815Sjsg 	u32 val;
37885ca02815Sjsg 
3789f005ef32Sjsg 	if (!(IS_ALDERLAKE_P(i915) && IS_DISPLAY_STEP(i915, STEP_A0, STEP_B0)) ||
37905ca02815Sjsg 	    pll->info->id != DPLL_ID_ICL_DPLL0)
37915ca02815Sjsg 		return;
37925ca02815Sjsg 	/*
37935ca02815Sjsg 	 * Wa_16011069516:adl-p[a0]
37945ca02815Sjsg 	 *
37955ca02815Sjsg 	 * All CMTG regs are unreliable until CMTG clock gating is disabled,
37965ca02815Sjsg 	 * so we can only assume the default TRANS_CMTG_CHICKEN reg value and
37975ca02815Sjsg 	 * sanity check this assumption with a double read, which presumably
37985ca02815Sjsg 	 * returns the correct value even with clock gating on.
37995ca02815Sjsg 	 *
38005ca02815Sjsg 	 * Instead of the usual place for workarounds we apply this one here,
38015ca02815Sjsg 	 * since TRANS_CMTG_CHICKEN is only accessible while DPLL0 is enabled.
38025ca02815Sjsg 	 */
38035ca02815Sjsg 	val = intel_de_read(i915, TRANS_CMTG_CHICKEN);
3804f005ef32Sjsg 	val = intel_de_rmw(i915, TRANS_CMTG_CHICKEN, ~0, DISABLE_DPT_CLK_GATING);
38055ca02815Sjsg 	if (drm_WARN_ON(&i915->drm, val & ~DISABLE_DPT_CLK_GATING))
38065ca02815Sjsg 		drm_dbg_kms(&i915->drm, "Unexpected flags in TRANS_CMTG_CHICKEN: %08x\n", val);
38075ca02815Sjsg }
38085ca02815Sjsg 
3809c349dbc7Sjsg static void combo_pll_enable(struct drm_i915_private *dev_priv,
3810c349dbc7Sjsg 			     struct intel_shared_dpll *pll)
3811c349dbc7Sjsg {
3812ad8b1aafSjsg 	i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll);
3813c349dbc7Sjsg 
3814f005ef32Sjsg 	if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) &&
3815c349dbc7Sjsg 	    pll->info->id == DPLL_ID_EHL_DPLL4) {
3816c349dbc7Sjsg 
3817c349dbc7Sjsg 		/*
3818c349dbc7Sjsg 		 * We need to disable DC states when this DPLL is enabled.
3819c349dbc7Sjsg 		 * This can be done by taking a reference on DPLL4 power
3820c349dbc7Sjsg 		 * domain.
3821c349dbc7Sjsg 		 */
3822c349dbc7Sjsg 		pll->wakeref = intel_display_power_get(dev_priv,
38231bb76ff1Sjsg 						       POWER_DOMAIN_DC_OFF);
3824c349dbc7Sjsg 	}
3825c349dbc7Sjsg 
3826c349dbc7Sjsg 	icl_pll_power_enable(dev_priv, pll, enable_reg);
3827c349dbc7Sjsg 
3828c349dbc7Sjsg 	icl_dpll_write(dev_priv, pll);
3829c349dbc7Sjsg 
3830c349dbc7Sjsg 	/*
3831c349dbc7Sjsg 	 * DVFS pre sequence would be here, but in our driver the cdclk code
3832c349dbc7Sjsg 	 * paths should already be setting the appropriate voltage, hence we do
3833c349dbc7Sjsg 	 * nothing here.
3834c349dbc7Sjsg 	 */
3835c349dbc7Sjsg 
3836c349dbc7Sjsg 	icl_pll_enable(dev_priv, pll, enable_reg);
3837c349dbc7Sjsg 
38385ca02815Sjsg 	adlp_cmtg_clock_gating_wa(dev_priv, pll);
38395ca02815Sjsg 
3840c349dbc7Sjsg 	/* DVFS post sequence would be here. See the comment above. */
3841c349dbc7Sjsg }
3842c349dbc7Sjsg 
3843c349dbc7Sjsg static void tbt_pll_enable(struct drm_i915_private *dev_priv,
3844c349dbc7Sjsg 			   struct intel_shared_dpll *pll)
3845c349dbc7Sjsg {
3846c349dbc7Sjsg 	icl_pll_power_enable(dev_priv, pll, TBT_PLL_ENABLE);
3847c349dbc7Sjsg 
3848c349dbc7Sjsg 	icl_dpll_write(dev_priv, pll);
3849c349dbc7Sjsg 
3850c349dbc7Sjsg 	/*
3851c349dbc7Sjsg 	 * DVFS pre sequence would be here, but in our driver the cdclk code
3852c349dbc7Sjsg 	 * paths should already be setting the appropriate voltage, hence we do
3853c349dbc7Sjsg 	 * nothing here.
3854c349dbc7Sjsg 	 */
3855c349dbc7Sjsg 
3856c349dbc7Sjsg 	icl_pll_enable(dev_priv, pll, TBT_PLL_ENABLE);
3857c349dbc7Sjsg 
3858c349dbc7Sjsg 	/* DVFS post sequence would be here. See the comment above. */
3859c349dbc7Sjsg }
3860c349dbc7Sjsg 
3861c349dbc7Sjsg static void mg_pll_enable(struct drm_i915_private *dev_priv,
3862c349dbc7Sjsg 			  struct intel_shared_dpll *pll)
3863c349dbc7Sjsg {
38645ca02815Sjsg 	i915_reg_t enable_reg = intel_tc_pll_enable_reg(dev_priv, pll);
3865c349dbc7Sjsg 
3866c349dbc7Sjsg 	icl_pll_power_enable(dev_priv, pll, enable_reg);
3867c349dbc7Sjsg 
38685ca02815Sjsg 	if (DISPLAY_VER(dev_priv) >= 12)
3869c349dbc7Sjsg 		dkl_pll_write(dev_priv, pll);
3870c349dbc7Sjsg 	else
3871c349dbc7Sjsg 		icl_mg_pll_write(dev_priv, pll);
3872c349dbc7Sjsg 
3873c349dbc7Sjsg 	/*
3874c349dbc7Sjsg 	 * DVFS pre sequence would be here, but in our driver the cdclk code
3875c349dbc7Sjsg 	 * paths should already be setting the appropriate voltage, hence we do
3876c349dbc7Sjsg 	 * nothing here.
3877c349dbc7Sjsg 	 */
3878c349dbc7Sjsg 
3879c349dbc7Sjsg 	icl_pll_enable(dev_priv, pll, enable_reg);
3880c349dbc7Sjsg 
3881c349dbc7Sjsg 	/* DVFS post sequence would be here. See the comment above. */
3882c349dbc7Sjsg }
3883c349dbc7Sjsg 
3884c349dbc7Sjsg static void icl_pll_disable(struct drm_i915_private *dev_priv,
3885c349dbc7Sjsg 			    struct intel_shared_dpll *pll,
3886c349dbc7Sjsg 			    i915_reg_t enable_reg)
3887c349dbc7Sjsg {
3888c349dbc7Sjsg 	/* The first steps are done by intel_ddi_post_disable(). */
3889c349dbc7Sjsg 
3890c349dbc7Sjsg 	/*
3891c349dbc7Sjsg 	 * DVFS pre sequence would be here, but in our driver the cdclk code
3892c349dbc7Sjsg 	 * paths should already be setting the appropriate voltage, hence we do
38935ca02815Sjsg 	 * nothing here.
3894c349dbc7Sjsg 	 */
3895c349dbc7Sjsg 
3896f005ef32Sjsg 	intel_de_rmw(dev_priv, enable_reg, PLL_ENABLE, 0);
3897c349dbc7Sjsg 
3898c349dbc7Sjsg 	/* Timeout is actually 1us. */
3899c349dbc7Sjsg 	if (intel_de_wait_for_clear(dev_priv, enable_reg, PLL_LOCK, 1))
3900c349dbc7Sjsg 		drm_err(&dev_priv->drm, "PLL %d locked\n", pll->info->id);
3901c349dbc7Sjsg 
3902c349dbc7Sjsg 	/* DVFS post sequence would be here. See the comment above. */
3903c349dbc7Sjsg 
3904f005ef32Sjsg 	intel_de_rmw(dev_priv, enable_reg, PLL_POWER_ENABLE, 0);
3905c349dbc7Sjsg 
3906c349dbc7Sjsg 	/*
3907c349dbc7Sjsg 	 * The spec says we need to "wait" but it also says it should be
3908c349dbc7Sjsg 	 * immediate.
3909c349dbc7Sjsg 	 */
3910c349dbc7Sjsg 	if (intel_de_wait_for_clear(dev_priv, enable_reg, PLL_POWER_STATE, 1))
3911c349dbc7Sjsg 		drm_err(&dev_priv->drm, "PLL %d Power not disabled\n",
3912c349dbc7Sjsg 			pll->info->id);
3913c349dbc7Sjsg }
3914c349dbc7Sjsg 
3915c349dbc7Sjsg static void combo_pll_disable(struct drm_i915_private *dev_priv,
3916c349dbc7Sjsg 			      struct intel_shared_dpll *pll)
3917c349dbc7Sjsg {
3918ad8b1aafSjsg 	i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll);
3919ad8b1aafSjsg 
3920ad8b1aafSjsg 	icl_pll_disable(dev_priv, pll, enable_reg);
3921c349dbc7Sjsg 
3922f005ef32Sjsg 	if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) &&
3923ad8b1aafSjsg 	    pll->info->id == DPLL_ID_EHL_DPLL4)
39241bb76ff1Sjsg 		intel_display_power_put(dev_priv, POWER_DOMAIN_DC_OFF,
3925c349dbc7Sjsg 					pll->wakeref);
3926c349dbc7Sjsg }
3927c349dbc7Sjsg 
3928c349dbc7Sjsg static void tbt_pll_disable(struct drm_i915_private *dev_priv,
3929c349dbc7Sjsg 			    struct intel_shared_dpll *pll)
3930c349dbc7Sjsg {
3931c349dbc7Sjsg 	icl_pll_disable(dev_priv, pll, TBT_PLL_ENABLE);
3932c349dbc7Sjsg }
3933c349dbc7Sjsg 
3934c349dbc7Sjsg static void mg_pll_disable(struct drm_i915_private *dev_priv,
3935c349dbc7Sjsg 			   struct intel_shared_dpll *pll)
3936c349dbc7Sjsg {
39375ca02815Sjsg 	i915_reg_t enable_reg = intel_tc_pll_enable_reg(dev_priv, pll);
3938c349dbc7Sjsg 
3939c349dbc7Sjsg 	icl_pll_disable(dev_priv, pll, enable_reg);
3940c349dbc7Sjsg }
3941c349dbc7Sjsg 
3942c349dbc7Sjsg static void icl_update_dpll_ref_clks(struct drm_i915_private *i915)
3943c349dbc7Sjsg {
3944c349dbc7Sjsg 	/* No SSC ref */
39451bb76ff1Sjsg 	i915->display.dpll.ref_clks.nssc = i915->display.cdclk.hw.ref;
3946c349dbc7Sjsg }
3947c349dbc7Sjsg 
3948c349dbc7Sjsg static void icl_dump_hw_state(struct drm_i915_private *dev_priv,
3949c349dbc7Sjsg 			      const struct intel_dpll_hw_state *hw_state)
3950c349dbc7Sjsg {
3951c349dbc7Sjsg 	drm_dbg_kms(&dev_priv->drm,
39521bb76ff1Sjsg 		    "dpll_hw_state: cfgcr0: 0x%x, cfgcr1: 0x%x, div0: 0x%x, "
3953c349dbc7Sjsg 		    "mg_refclkin_ctl: 0x%x, hg_clktop2_coreclkctl1: 0x%x, "
3954c349dbc7Sjsg 		    "mg_clktop2_hsclkctl: 0x%x, mg_pll_div0: 0x%x, "
3955c349dbc7Sjsg 		    "mg_pll_div2: 0x%x, mg_pll_lf: 0x%x, "
3956c349dbc7Sjsg 		    "mg_pll_frac_lock: 0x%x, mg_pll_ssc: 0x%x, "
3957c349dbc7Sjsg 		    "mg_pll_bias: 0x%x, mg_pll_tdc_coldst_bias: 0x%x\n",
3958c349dbc7Sjsg 		    hw_state->cfgcr0, hw_state->cfgcr1,
39591bb76ff1Sjsg 		    hw_state->div0,
3960c349dbc7Sjsg 		    hw_state->mg_refclkin_ctl,
3961c349dbc7Sjsg 		    hw_state->mg_clktop2_coreclkctl1,
3962c349dbc7Sjsg 		    hw_state->mg_clktop2_hsclkctl,
3963c349dbc7Sjsg 		    hw_state->mg_pll_div0,
3964c349dbc7Sjsg 		    hw_state->mg_pll_div1,
3965c349dbc7Sjsg 		    hw_state->mg_pll_lf,
3966c349dbc7Sjsg 		    hw_state->mg_pll_frac_lock,
3967c349dbc7Sjsg 		    hw_state->mg_pll_ssc,
3968c349dbc7Sjsg 		    hw_state->mg_pll_bias,
3969c349dbc7Sjsg 		    hw_state->mg_pll_tdc_coldst_bias);
3970c349dbc7Sjsg }
3971c349dbc7Sjsg 
3972c349dbc7Sjsg static const struct intel_shared_dpll_funcs combo_pll_funcs = {
3973c349dbc7Sjsg 	.enable = combo_pll_enable,
3974c349dbc7Sjsg 	.disable = combo_pll_disable,
3975c349dbc7Sjsg 	.get_hw_state = combo_pll_get_hw_state,
3976c349dbc7Sjsg 	.get_freq = icl_ddi_combo_pll_get_freq,
3977c349dbc7Sjsg };
3978c349dbc7Sjsg 
3979c349dbc7Sjsg static const struct intel_shared_dpll_funcs tbt_pll_funcs = {
3980c349dbc7Sjsg 	.enable = tbt_pll_enable,
3981c349dbc7Sjsg 	.disable = tbt_pll_disable,
3982c349dbc7Sjsg 	.get_hw_state = tbt_pll_get_hw_state,
3983c349dbc7Sjsg 	.get_freq = icl_ddi_tbt_pll_get_freq,
3984c349dbc7Sjsg };
3985c349dbc7Sjsg 
3986c349dbc7Sjsg static const struct intel_shared_dpll_funcs mg_pll_funcs = {
3987c349dbc7Sjsg 	.enable = mg_pll_enable,
3988c349dbc7Sjsg 	.disable = mg_pll_disable,
3989c349dbc7Sjsg 	.get_hw_state = mg_pll_get_hw_state,
3990c349dbc7Sjsg 	.get_freq = icl_ddi_mg_pll_get_freq,
3991c349dbc7Sjsg };
3992c349dbc7Sjsg 
3993c349dbc7Sjsg static const struct dpll_info icl_plls[] = {
3994c349dbc7Sjsg 	{ "DPLL 0",   &combo_pll_funcs, DPLL_ID_ICL_DPLL0,  0 },
3995c349dbc7Sjsg 	{ "DPLL 1",   &combo_pll_funcs, DPLL_ID_ICL_DPLL1,  0 },
3996c349dbc7Sjsg 	{ "TBT PLL",  &tbt_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 },
3997c349dbc7Sjsg 	{ "MG PLL 1", &mg_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 },
3998c349dbc7Sjsg 	{ "MG PLL 2", &mg_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 },
3999c349dbc7Sjsg 	{ "MG PLL 3", &mg_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 },
4000c349dbc7Sjsg 	{ "MG PLL 4", &mg_pll_funcs, DPLL_ID_ICL_MGPLL4, 0 },
4001c349dbc7Sjsg 	{ },
4002c349dbc7Sjsg };
4003c349dbc7Sjsg 
4004c349dbc7Sjsg static const struct intel_dpll_mgr icl_pll_mgr = {
4005c349dbc7Sjsg 	.dpll_info = icl_plls,
40061bb76ff1Sjsg 	.compute_dplls = icl_compute_dplls,
4007c349dbc7Sjsg 	.get_dplls = icl_get_dplls,
4008c349dbc7Sjsg 	.put_dplls = icl_put_dplls,
4009c349dbc7Sjsg 	.update_active_dpll = icl_update_active_dpll,
4010c349dbc7Sjsg 	.update_ref_clks = icl_update_dpll_ref_clks,
4011c349dbc7Sjsg 	.dump_hw_state = icl_dump_hw_state,
4012c349dbc7Sjsg };
4013c349dbc7Sjsg 
4014c349dbc7Sjsg static const struct dpll_info ehl_plls[] = {
4015c349dbc7Sjsg 	{ "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 },
4016c349dbc7Sjsg 	{ "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 },
4017c349dbc7Sjsg 	{ "DPLL 4", &combo_pll_funcs, DPLL_ID_EHL_DPLL4, 0 },
4018c349dbc7Sjsg 	{ },
4019c349dbc7Sjsg };
4020c349dbc7Sjsg 
4021c349dbc7Sjsg static const struct intel_dpll_mgr ehl_pll_mgr = {
4022c349dbc7Sjsg 	.dpll_info = ehl_plls,
40231bb76ff1Sjsg 	.compute_dplls = icl_compute_dplls,
4024c349dbc7Sjsg 	.get_dplls = icl_get_dplls,
4025c349dbc7Sjsg 	.put_dplls = icl_put_dplls,
4026c349dbc7Sjsg 	.update_ref_clks = icl_update_dpll_ref_clks,
4027c349dbc7Sjsg 	.dump_hw_state = icl_dump_hw_state,
4028c349dbc7Sjsg };
4029c349dbc7Sjsg 
4030c349dbc7Sjsg static const struct intel_shared_dpll_funcs dkl_pll_funcs = {
4031c349dbc7Sjsg 	.enable = mg_pll_enable,
4032c349dbc7Sjsg 	.disable = mg_pll_disable,
4033c349dbc7Sjsg 	.get_hw_state = dkl_pll_get_hw_state,
4034c349dbc7Sjsg 	.get_freq = icl_ddi_mg_pll_get_freq,
4035c349dbc7Sjsg };
4036c349dbc7Sjsg 
4037c349dbc7Sjsg static const struct dpll_info tgl_plls[] = {
4038c349dbc7Sjsg 	{ "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0,  0 },
4039c349dbc7Sjsg 	{ "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1,  0 },
4040c349dbc7Sjsg 	{ "TBT PLL",  &tbt_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 },
4041c349dbc7Sjsg 	{ "TC PLL 1", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 },
4042c349dbc7Sjsg 	{ "TC PLL 2", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 },
4043c349dbc7Sjsg 	{ "TC PLL 3", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 },
4044c349dbc7Sjsg 	{ "TC PLL 4", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL4, 0 },
4045c349dbc7Sjsg 	{ "TC PLL 5", &dkl_pll_funcs, DPLL_ID_TGL_MGPLL5, 0 },
4046c349dbc7Sjsg 	{ "TC PLL 6", &dkl_pll_funcs, DPLL_ID_TGL_MGPLL6, 0 },
4047c349dbc7Sjsg 	{ },
4048c349dbc7Sjsg };
4049c349dbc7Sjsg 
4050c349dbc7Sjsg static const struct intel_dpll_mgr tgl_pll_mgr = {
4051c349dbc7Sjsg 	.dpll_info = tgl_plls,
40521bb76ff1Sjsg 	.compute_dplls = icl_compute_dplls,
4053c349dbc7Sjsg 	.get_dplls = icl_get_dplls,
4054c349dbc7Sjsg 	.put_dplls = icl_put_dplls,
4055c349dbc7Sjsg 	.update_active_dpll = icl_update_active_dpll,
4056c349dbc7Sjsg 	.update_ref_clks = icl_update_dpll_ref_clks,
4057c349dbc7Sjsg 	.dump_hw_state = icl_dump_hw_state,
4058c349dbc7Sjsg };
4059c349dbc7Sjsg 
4060ad8b1aafSjsg static const struct dpll_info rkl_plls[] = {
4061ad8b1aafSjsg 	{ "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 },
4062ad8b1aafSjsg 	{ "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 },
4063ad8b1aafSjsg 	{ "DPLL 4", &combo_pll_funcs, DPLL_ID_EHL_DPLL4, 0 },
4064ad8b1aafSjsg 	{ },
4065ad8b1aafSjsg };
4066ad8b1aafSjsg 
4067ad8b1aafSjsg static const struct intel_dpll_mgr rkl_pll_mgr = {
4068ad8b1aafSjsg 	.dpll_info = rkl_plls,
40691bb76ff1Sjsg 	.compute_dplls = icl_compute_dplls,
4070ad8b1aafSjsg 	.get_dplls = icl_get_dplls,
4071ad8b1aafSjsg 	.put_dplls = icl_put_dplls,
4072ad8b1aafSjsg 	.update_ref_clks = icl_update_dpll_ref_clks,
4073ad8b1aafSjsg 	.dump_hw_state = icl_dump_hw_state,
4074ad8b1aafSjsg };
4075ad8b1aafSjsg 
40765ca02815Sjsg static const struct dpll_info dg1_plls[] = {
40775ca02815Sjsg 	{ "DPLL 0", &combo_pll_funcs, DPLL_ID_DG1_DPLL0, 0 },
40785ca02815Sjsg 	{ "DPLL 1", &combo_pll_funcs, DPLL_ID_DG1_DPLL1, 0 },
40795ca02815Sjsg 	{ "DPLL 2", &combo_pll_funcs, DPLL_ID_DG1_DPLL2, 0 },
40805ca02815Sjsg 	{ "DPLL 3", &combo_pll_funcs, DPLL_ID_DG1_DPLL3, 0 },
40815ca02815Sjsg 	{ },
40825ca02815Sjsg };
40835ca02815Sjsg 
40845ca02815Sjsg static const struct intel_dpll_mgr dg1_pll_mgr = {
40855ca02815Sjsg 	.dpll_info = dg1_plls,
40861bb76ff1Sjsg 	.compute_dplls = icl_compute_dplls,
40875ca02815Sjsg 	.get_dplls = icl_get_dplls,
40885ca02815Sjsg 	.put_dplls = icl_put_dplls,
40895ca02815Sjsg 	.update_ref_clks = icl_update_dpll_ref_clks,
40905ca02815Sjsg 	.dump_hw_state = icl_dump_hw_state,
40915ca02815Sjsg };
40925ca02815Sjsg 
40935ca02815Sjsg static const struct dpll_info adls_plls[] = {
40945ca02815Sjsg 	{ "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 },
40955ca02815Sjsg 	{ "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 },
40965ca02815Sjsg 	{ "DPLL 2", &combo_pll_funcs, DPLL_ID_DG1_DPLL2, 0 },
40975ca02815Sjsg 	{ "DPLL 3", &combo_pll_funcs, DPLL_ID_DG1_DPLL3, 0 },
40985ca02815Sjsg 	{ },
40995ca02815Sjsg };
41005ca02815Sjsg 
41015ca02815Sjsg static const struct intel_dpll_mgr adls_pll_mgr = {
41025ca02815Sjsg 	.dpll_info = adls_plls,
41031bb76ff1Sjsg 	.compute_dplls = icl_compute_dplls,
41045ca02815Sjsg 	.get_dplls = icl_get_dplls,
41055ca02815Sjsg 	.put_dplls = icl_put_dplls,
41065ca02815Sjsg 	.update_ref_clks = icl_update_dpll_ref_clks,
41075ca02815Sjsg 	.dump_hw_state = icl_dump_hw_state,
41085ca02815Sjsg };
41095ca02815Sjsg 
41105ca02815Sjsg static const struct dpll_info adlp_plls[] = {
41115ca02815Sjsg 	{ "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0,  0 },
41125ca02815Sjsg 	{ "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1,  0 },
41135ca02815Sjsg 	{ "TBT PLL",  &tbt_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 },
41145ca02815Sjsg 	{ "TC PLL 1", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 },
41155ca02815Sjsg 	{ "TC PLL 2", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 },
41165ca02815Sjsg 	{ "TC PLL 3", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 },
41175ca02815Sjsg 	{ "TC PLL 4", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL4, 0 },
41185ca02815Sjsg 	{ },
41195ca02815Sjsg };
41205ca02815Sjsg 
41215ca02815Sjsg static const struct intel_dpll_mgr adlp_pll_mgr = {
41225ca02815Sjsg 	.dpll_info = adlp_plls,
41231bb76ff1Sjsg 	.compute_dplls = icl_compute_dplls,
41245ca02815Sjsg 	.get_dplls = icl_get_dplls,
41255ca02815Sjsg 	.put_dplls = icl_put_dplls,
41265ca02815Sjsg 	.update_active_dpll = icl_update_active_dpll,
41275ca02815Sjsg 	.update_ref_clks = icl_update_dpll_ref_clks,
41285ca02815Sjsg 	.dump_hw_state = icl_dump_hw_state,
41295ca02815Sjsg };
41305ca02815Sjsg 
4131c349dbc7Sjsg /**
4132c349dbc7Sjsg  * intel_shared_dpll_init - Initialize shared DPLLs
41331bb76ff1Sjsg  * @dev_priv: i915 device
4134c349dbc7Sjsg  *
41351bb76ff1Sjsg  * Initialize shared DPLLs for @dev_priv.
4136c349dbc7Sjsg  */
41371bb76ff1Sjsg void intel_shared_dpll_init(struct drm_i915_private *dev_priv)
4138c349dbc7Sjsg {
4139c349dbc7Sjsg 	const struct intel_dpll_mgr *dpll_mgr = NULL;
4140c349dbc7Sjsg 	const struct dpll_info *dpll_info;
4141c349dbc7Sjsg 	int i;
4142c349dbc7Sjsg 
4143f005ef32Sjsg 	rw_init(&dev_priv->display.dpll.lock, "dplllk");
4144f005ef32Sjsg 
4145f005ef32Sjsg 	if (DISPLAY_VER(dev_priv) >= 14 || IS_DG2(dev_priv))
41465ca02815Sjsg 		/* No shared DPLLs on DG2; port PLLs are part of the PHY */
41475ca02815Sjsg 		dpll_mgr = NULL;
41485ca02815Sjsg 	else if (IS_ALDERLAKE_P(dev_priv))
41495ca02815Sjsg 		dpll_mgr = &adlp_pll_mgr;
41505ca02815Sjsg 	else if (IS_ALDERLAKE_S(dev_priv))
41515ca02815Sjsg 		dpll_mgr = &adls_pll_mgr;
41525ca02815Sjsg 	else if (IS_DG1(dev_priv))
41535ca02815Sjsg 		dpll_mgr = &dg1_pll_mgr;
41545ca02815Sjsg 	else if (IS_ROCKETLAKE(dev_priv))
4155ad8b1aafSjsg 		dpll_mgr = &rkl_pll_mgr;
41565ca02815Sjsg 	else if (DISPLAY_VER(dev_priv) >= 12)
4157c349dbc7Sjsg 		dpll_mgr = &tgl_pll_mgr;
4158f005ef32Sjsg 	else if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv))
4159c349dbc7Sjsg 		dpll_mgr = &ehl_pll_mgr;
41605ca02815Sjsg 	else if (DISPLAY_VER(dev_priv) >= 11)
4161c349dbc7Sjsg 		dpll_mgr = &icl_pll_mgr;
41625ca02815Sjsg 	else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv))
4163c349dbc7Sjsg 		dpll_mgr = &bxt_pll_mgr;
41645ca02815Sjsg 	else if (DISPLAY_VER(dev_priv) == 9)
41655ca02815Sjsg 		dpll_mgr = &skl_pll_mgr;
4166c349dbc7Sjsg 	else if (HAS_DDI(dev_priv))
4167c349dbc7Sjsg 		dpll_mgr = &hsw_pll_mgr;
4168c349dbc7Sjsg 	else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))
4169c349dbc7Sjsg 		dpll_mgr = &pch_pll_mgr;
4170c349dbc7Sjsg 
4171c349dbc7Sjsg 	if (!dpll_mgr) {
41721bb76ff1Sjsg 		dev_priv->display.dpll.num_shared_dpll = 0;
4173c349dbc7Sjsg 		return;
4174c349dbc7Sjsg 	}
4175c349dbc7Sjsg 
4176c349dbc7Sjsg 	dpll_info = dpll_mgr->dpll_info;
4177c349dbc7Sjsg 
4178c349dbc7Sjsg 	for (i = 0; dpll_info[i].name; i++) {
41791bb76ff1Sjsg 		if (drm_WARN_ON(&dev_priv->drm,
41801bb76ff1Sjsg 				i >= ARRAY_SIZE(dev_priv->display.dpll.shared_dplls)))
41811bb76ff1Sjsg 			break;
41821bb76ff1Sjsg 
41831bb76ff1Sjsg 		drm_WARN_ON(&dev_priv->drm, i != dpll_info[i].id);
41841bb76ff1Sjsg 		dev_priv->display.dpll.shared_dplls[i].info = &dpll_info[i];
4185c349dbc7Sjsg 	}
4186c349dbc7Sjsg 
41871bb76ff1Sjsg 	dev_priv->display.dpll.mgr = dpll_mgr;
41881bb76ff1Sjsg 	dev_priv->display.dpll.num_shared_dpll = i;
41891bb76ff1Sjsg }
4190c349dbc7Sjsg 
41911bb76ff1Sjsg /**
41921bb76ff1Sjsg  * intel_compute_shared_dplls - compute DPLL state CRTC and encoder combination
41931bb76ff1Sjsg  * @state: atomic state
41941bb76ff1Sjsg  * @crtc: CRTC to compute DPLLs for
41951bb76ff1Sjsg  * @encoder: encoder
41961bb76ff1Sjsg  *
41971bb76ff1Sjsg  * This function computes the DPLL state for the given CRTC and encoder.
41981bb76ff1Sjsg  *
41991bb76ff1Sjsg  * The new configuration in the atomic commit @state is made effective by
42001bb76ff1Sjsg  * calling intel_shared_dpll_swap_state().
42011bb76ff1Sjsg  *
42021bb76ff1Sjsg  * Returns:
42031bb76ff1Sjsg  * 0 on success, negative error code on falure.
42041bb76ff1Sjsg  */
42051bb76ff1Sjsg int intel_compute_shared_dplls(struct intel_atomic_state *state,
42061bb76ff1Sjsg 			       struct intel_crtc *crtc,
42071bb76ff1Sjsg 			       struct intel_encoder *encoder)
42081bb76ff1Sjsg {
42091bb76ff1Sjsg 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
42101bb76ff1Sjsg 	const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr;
42111bb76ff1Sjsg 
42121bb76ff1Sjsg 	if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr))
42131bb76ff1Sjsg 		return -EINVAL;
42141bb76ff1Sjsg 
42151bb76ff1Sjsg 	return dpll_mgr->compute_dplls(state, crtc, encoder);
4216c349dbc7Sjsg }
4217c349dbc7Sjsg 
4218c349dbc7Sjsg /**
4219c349dbc7Sjsg  * intel_reserve_shared_dplls - reserve DPLLs for CRTC and encoder combination
4220c349dbc7Sjsg  * @state: atomic state
4221c349dbc7Sjsg  * @crtc: CRTC to reserve DPLLs for
4222c349dbc7Sjsg  * @encoder: encoder
4223c349dbc7Sjsg  *
4224c349dbc7Sjsg  * This function reserves all required DPLLs for the given CRTC and encoder
4225c349dbc7Sjsg  * combination in the current atomic commit @state and the new @crtc atomic
4226c349dbc7Sjsg  * state.
4227c349dbc7Sjsg  *
4228c349dbc7Sjsg  * The new configuration in the atomic commit @state is made effective by
4229c349dbc7Sjsg  * calling intel_shared_dpll_swap_state().
4230c349dbc7Sjsg  *
4231c349dbc7Sjsg  * The reserved DPLLs should be released by calling
4232c349dbc7Sjsg  * intel_release_shared_dplls().
4233c349dbc7Sjsg  *
4234c349dbc7Sjsg  * Returns:
42351bb76ff1Sjsg  * 0 if all required DPLLs were successfully reserved,
42361bb76ff1Sjsg  * negative error code otherwise.
4237c349dbc7Sjsg  */
42381bb76ff1Sjsg int intel_reserve_shared_dplls(struct intel_atomic_state *state,
4239c349dbc7Sjsg 			       struct intel_crtc *crtc,
4240c349dbc7Sjsg 			       struct intel_encoder *encoder)
4241c349dbc7Sjsg {
4242c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
42431bb76ff1Sjsg 	const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr;
4244c349dbc7Sjsg 
4245c349dbc7Sjsg 	if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr))
42461bb76ff1Sjsg 		return -EINVAL;
4247c349dbc7Sjsg 
4248c349dbc7Sjsg 	return dpll_mgr->get_dplls(state, crtc, encoder);
4249c349dbc7Sjsg }
4250c349dbc7Sjsg 
4251c349dbc7Sjsg /**
4252c349dbc7Sjsg  * intel_release_shared_dplls - end use of DPLLs by CRTC in atomic state
4253c349dbc7Sjsg  * @state: atomic state
4254c349dbc7Sjsg  * @crtc: crtc from which the DPLLs are to be released
4255c349dbc7Sjsg  *
4256c349dbc7Sjsg  * This function releases all DPLLs reserved by intel_reserve_shared_dplls()
4257c349dbc7Sjsg  * from the current atomic commit @state and the old @crtc atomic state.
4258c349dbc7Sjsg  *
4259c349dbc7Sjsg  * The new configuration in the atomic commit @state is made effective by
4260c349dbc7Sjsg  * calling intel_shared_dpll_swap_state().
4261c349dbc7Sjsg  */
4262c349dbc7Sjsg void intel_release_shared_dplls(struct intel_atomic_state *state,
4263c349dbc7Sjsg 				struct intel_crtc *crtc)
4264c349dbc7Sjsg {
4265c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
42661bb76ff1Sjsg 	const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr;
4267c349dbc7Sjsg 
4268c349dbc7Sjsg 	/*
4269c349dbc7Sjsg 	 * FIXME: this function is called for every platform having a
4270c349dbc7Sjsg 	 * compute_clock hook, even though the platform doesn't yet support
4271c349dbc7Sjsg 	 * the shared DPLL framework and intel_reserve_shared_dplls() is not
4272c349dbc7Sjsg 	 * called on those.
4273c349dbc7Sjsg 	 */
4274c349dbc7Sjsg 	if (!dpll_mgr)
4275c349dbc7Sjsg 		return;
4276c349dbc7Sjsg 
4277c349dbc7Sjsg 	dpll_mgr->put_dplls(state, crtc);
4278c349dbc7Sjsg }
4279c349dbc7Sjsg 
4280c349dbc7Sjsg /**
4281c349dbc7Sjsg  * intel_update_active_dpll - update the active DPLL for a CRTC/encoder
4282c349dbc7Sjsg  * @state: atomic state
4283c349dbc7Sjsg  * @crtc: the CRTC for which to update the active DPLL
4284c349dbc7Sjsg  * @encoder: encoder determining the type of port DPLL
4285c349dbc7Sjsg  *
4286c349dbc7Sjsg  * Update the active DPLL for the given @crtc/@encoder in @crtc's atomic state,
4287c349dbc7Sjsg  * from the port DPLLs reserved previously by intel_reserve_shared_dplls(). The
4288c349dbc7Sjsg  * DPLL selected will be based on the current mode of the encoder's port.
4289c349dbc7Sjsg  */
4290c349dbc7Sjsg void intel_update_active_dpll(struct intel_atomic_state *state,
4291c349dbc7Sjsg 			      struct intel_crtc *crtc,
4292c349dbc7Sjsg 			      struct intel_encoder *encoder)
4293c349dbc7Sjsg {
4294c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
42951bb76ff1Sjsg 	const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr;
4296c349dbc7Sjsg 
4297c349dbc7Sjsg 	if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr))
4298c349dbc7Sjsg 		return;
4299c349dbc7Sjsg 
4300c349dbc7Sjsg 	dpll_mgr->update_active_dpll(state, crtc, encoder);
4301c349dbc7Sjsg }
4302c349dbc7Sjsg 
4303c349dbc7Sjsg /**
4304c349dbc7Sjsg  * intel_dpll_get_freq - calculate the DPLL's output frequency
4305c349dbc7Sjsg  * @i915: i915 device
4306c349dbc7Sjsg  * @pll: DPLL for which to calculate the output frequency
43075ca02815Sjsg  * @pll_state: DPLL state from which to calculate the output frequency
4308c349dbc7Sjsg  *
43095ca02815Sjsg  * Return the output frequency corresponding to @pll's passed in @pll_state.
4310c349dbc7Sjsg  */
4311c349dbc7Sjsg int intel_dpll_get_freq(struct drm_i915_private *i915,
43125ca02815Sjsg 			const struct intel_shared_dpll *pll,
43135ca02815Sjsg 			const struct intel_dpll_hw_state *pll_state)
4314c349dbc7Sjsg {
4315c349dbc7Sjsg 	if (drm_WARN_ON(&i915->drm, !pll->info->funcs->get_freq))
4316c349dbc7Sjsg 		return 0;
4317c349dbc7Sjsg 
43185ca02815Sjsg 	return pll->info->funcs->get_freq(i915, pll, pll_state);
43195ca02815Sjsg }
43205ca02815Sjsg 
43215ca02815Sjsg /**
43225ca02815Sjsg  * intel_dpll_get_hw_state - readout the DPLL's hardware state
43235ca02815Sjsg  * @i915: i915 device
43245ca02815Sjsg  * @pll: DPLL for which to calculate the output frequency
43255ca02815Sjsg  * @hw_state: DPLL's hardware state
43265ca02815Sjsg  *
43275ca02815Sjsg  * Read out @pll's hardware state into @hw_state.
43285ca02815Sjsg  */
43295ca02815Sjsg bool intel_dpll_get_hw_state(struct drm_i915_private *i915,
43305ca02815Sjsg 			     struct intel_shared_dpll *pll,
43315ca02815Sjsg 			     struct intel_dpll_hw_state *hw_state)
43325ca02815Sjsg {
43335ca02815Sjsg 	return pll->info->funcs->get_hw_state(i915, pll, hw_state);
4334c349dbc7Sjsg }
4335c349dbc7Sjsg 
4336c349dbc7Sjsg static void readout_dpll_hw_state(struct drm_i915_private *i915,
4337c349dbc7Sjsg 				  struct intel_shared_dpll *pll)
4338c349dbc7Sjsg {
4339c349dbc7Sjsg 	struct intel_crtc *crtc;
4340c349dbc7Sjsg 
43415ca02815Sjsg 	pll->on = intel_dpll_get_hw_state(i915, pll, &pll->state.hw_state);
4342c349dbc7Sjsg 
4343f005ef32Sjsg 	if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) &&
4344f005ef32Sjsg 	    pll->on &&
4345c349dbc7Sjsg 	    pll->info->id == DPLL_ID_EHL_DPLL4) {
4346c349dbc7Sjsg 		pll->wakeref = intel_display_power_get(i915,
43471bb76ff1Sjsg 						       POWER_DOMAIN_DC_OFF);
4348c349dbc7Sjsg 	}
4349c349dbc7Sjsg 
43505ca02815Sjsg 	pll->state.pipe_mask = 0;
4351c349dbc7Sjsg 	for_each_intel_crtc(&i915->drm, crtc) {
4352c349dbc7Sjsg 		struct intel_crtc_state *crtc_state =
4353c349dbc7Sjsg 			to_intel_crtc_state(crtc->base.state);
4354c349dbc7Sjsg 
4355c349dbc7Sjsg 		if (crtc_state->hw.active && crtc_state->shared_dpll == pll)
4356f005ef32Sjsg 			intel_reference_shared_dpll_crtc(crtc, pll, &pll->state);
4357c349dbc7Sjsg 	}
43585ca02815Sjsg 	pll->active_mask = pll->state.pipe_mask;
4359c349dbc7Sjsg 
4360c349dbc7Sjsg 	drm_dbg_kms(&i915->drm,
43615ca02815Sjsg 		    "%s hw state readout: pipe_mask 0x%x, on %i\n",
43625ca02815Sjsg 		    pll->info->name, pll->state.pipe_mask, pll->on);
43635ca02815Sjsg }
43645ca02815Sjsg 
43655ca02815Sjsg void intel_dpll_update_ref_clks(struct drm_i915_private *i915)
43665ca02815Sjsg {
43671bb76ff1Sjsg 	if (i915->display.dpll.mgr && i915->display.dpll.mgr->update_ref_clks)
43681bb76ff1Sjsg 		i915->display.dpll.mgr->update_ref_clks(i915);
4369c349dbc7Sjsg }
4370c349dbc7Sjsg 
4371c349dbc7Sjsg void intel_dpll_readout_hw_state(struct drm_i915_private *i915)
4372c349dbc7Sjsg {
4373c349dbc7Sjsg 	int i;
4374c349dbc7Sjsg 
43751bb76ff1Sjsg 	for (i = 0; i < i915->display.dpll.num_shared_dpll; i++)
43761bb76ff1Sjsg 		readout_dpll_hw_state(i915, &i915->display.dpll.shared_dplls[i]);
4377c349dbc7Sjsg }
4378c349dbc7Sjsg 
4379c349dbc7Sjsg static void sanitize_dpll_state(struct drm_i915_private *i915,
4380c349dbc7Sjsg 				struct intel_shared_dpll *pll)
4381c349dbc7Sjsg {
43825ca02815Sjsg 	if (!pll->on)
43835ca02815Sjsg 		return;
43845ca02815Sjsg 
43855ca02815Sjsg 	adlp_cmtg_clock_gating_wa(i915, pll);
43865ca02815Sjsg 
43875ca02815Sjsg 	if (pll->active_mask)
4388c349dbc7Sjsg 		return;
4389c349dbc7Sjsg 
4390c349dbc7Sjsg 	drm_dbg_kms(&i915->drm,
4391c349dbc7Sjsg 		    "%s enabled but not in use, disabling\n",
4392c349dbc7Sjsg 		    pll->info->name);
4393c349dbc7Sjsg 
4394c349dbc7Sjsg 	pll->info->funcs->disable(i915, pll);
4395c349dbc7Sjsg 	pll->on = false;
4396c349dbc7Sjsg }
4397c349dbc7Sjsg 
4398c349dbc7Sjsg void intel_dpll_sanitize_state(struct drm_i915_private *i915)
4399c349dbc7Sjsg {
4400c349dbc7Sjsg 	int i;
4401c349dbc7Sjsg 
44021bb76ff1Sjsg 	for (i = 0; i < i915->display.dpll.num_shared_dpll; i++)
44031bb76ff1Sjsg 		sanitize_dpll_state(i915, &i915->display.dpll.shared_dplls[i]);
4404c349dbc7Sjsg }
4405c349dbc7Sjsg 
4406c349dbc7Sjsg /**
44075ca02815Sjsg  * intel_dpll_dump_hw_state - write hw_state to dmesg
4408c349dbc7Sjsg  * @dev_priv: i915 drm device
4409c349dbc7Sjsg  * @hw_state: hw state to be written to the log
4410c349dbc7Sjsg  *
4411c349dbc7Sjsg  * Write the relevant values in @hw_state to dmesg using drm_dbg_kms.
4412c349dbc7Sjsg  */
4413c349dbc7Sjsg void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv,
4414c349dbc7Sjsg 			      const struct intel_dpll_hw_state *hw_state)
4415c349dbc7Sjsg {
44161bb76ff1Sjsg 	if (dev_priv->display.dpll.mgr) {
44171bb76ff1Sjsg 		dev_priv->display.dpll.mgr->dump_hw_state(dev_priv, hw_state);
4418c349dbc7Sjsg 	} else {
4419c349dbc7Sjsg 		/* fallback for platforms that don't use the shared dpll
4420c349dbc7Sjsg 		 * infrastructure
4421c349dbc7Sjsg 		 */
4422c349dbc7Sjsg 		drm_dbg_kms(&dev_priv->drm,
4423c349dbc7Sjsg 			    "dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
4424c349dbc7Sjsg 			    "fp0: 0x%x, fp1: 0x%x\n",
4425c349dbc7Sjsg 			    hw_state->dpll,
4426c349dbc7Sjsg 			    hw_state->dpll_md,
4427c349dbc7Sjsg 			    hw_state->fp0,
4428c349dbc7Sjsg 			    hw_state->fp1);
4429c349dbc7Sjsg 	}
4430c349dbc7Sjsg }
44311bb76ff1Sjsg 
44321bb76ff1Sjsg static void
44331bb76ff1Sjsg verify_single_dpll_state(struct drm_i915_private *dev_priv,
44341bb76ff1Sjsg 			 struct intel_shared_dpll *pll,
44351bb76ff1Sjsg 			 struct intel_crtc *crtc,
44361bb76ff1Sjsg 			 struct intel_crtc_state *new_crtc_state)
44371bb76ff1Sjsg {
44381bb76ff1Sjsg 	struct intel_dpll_hw_state dpll_hw_state;
44391bb76ff1Sjsg 	u8 pipe_mask;
44401bb76ff1Sjsg 	bool active;
44411bb76ff1Sjsg 
44421bb76ff1Sjsg 	memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
44431bb76ff1Sjsg 
44441bb76ff1Sjsg 	drm_dbg_kms(&dev_priv->drm, "%s\n", pll->info->name);
44451bb76ff1Sjsg 
44461bb76ff1Sjsg 	active = intel_dpll_get_hw_state(dev_priv, pll, &dpll_hw_state);
44471bb76ff1Sjsg 
44481bb76ff1Sjsg 	if (!(pll->info->flags & INTEL_DPLL_ALWAYS_ON)) {
4449f005ef32Sjsg 		I915_STATE_WARN(dev_priv, !pll->on && pll->active_mask,
44501bb76ff1Sjsg 				"pll in active use but not on in sw tracking\n");
4451f005ef32Sjsg 		I915_STATE_WARN(dev_priv, pll->on && !pll->active_mask,
44521bb76ff1Sjsg 				"pll is on but not used by any active pipe\n");
4453f005ef32Sjsg 		I915_STATE_WARN(dev_priv, pll->on != active,
44541bb76ff1Sjsg 				"pll on state mismatch (expected %i, found %i)\n",
44551bb76ff1Sjsg 				pll->on, active);
44561bb76ff1Sjsg 	}
44571bb76ff1Sjsg 
44581bb76ff1Sjsg 	if (!crtc) {
4459f005ef32Sjsg 		I915_STATE_WARN(dev_priv,
4460f005ef32Sjsg 				pll->active_mask & ~pll->state.pipe_mask,
44611bb76ff1Sjsg 				"more active pll users than references: 0x%x vs 0x%x\n",
44621bb76ff1Sjsg 				pll->active_mask, pll->state.pipe_mask);
44631bb76ff1Sjsg 
44641bb76ff1Sjsg 		return;
44651bb76ff1Sjsg 	}
44661bb76ff1Sjsg 
44671bb76ff1Sjsg 	pipe_mask = BIT(crtc->pipe);
44681bb76ff1Sjsg 
44691bb76ff1Sjsg 	if (new_crtc_state->hw.active)
4470f005ef32Sjsg 		I915_STATE_WARN(dev_priv, !(pll->active_mask & pipe_mask),
44711bb76ff1Sjsg 				"pll active mismatch (expected pipe %c in active mask 0x%x)\n",
44721bb76ff1Sjsg 				pipe_name(crtc->pipe), pll->active_mask);
44731bb76ff1Sjsg 	else
4474f005ef32Sjsg 		I915_STATE_WARN(dev_priv, pll->active_mask & pipe_mask,
44751bb76ff1Sjsg 				"pll active mismatch (didn't expect pipe %c in active mask 0x%x)\n",
44761bb76ff1Sjsg 				pipe_name(crtc->pipe), pll->active_mask);
44771bb76ff1Sjsg 
4478f005ef32Sjsg 	I915_STATE_WARN(dev_priv, !(pll->state.pipe_mask & pipe_mask),
44791bb76ff1Sjsg 			"pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n",
44801bb76ff1Sjsg 			pipe_mask, pll->state.pipe_mask);
44811bb76ff1Sjsg 
4482f005ef32Sjsg 	I915_STATE_WARN(dev_priv,
4483f005ef32Sjsg 			pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state,
44841bb76ff1Sjsg 					  sizeof(dpll_hw_state)),
44851bb76ff1Sjsg 			"pll hw state mismatch\n");
44861bb76ff1Sjsg }
44871bb76ff1Sjsg 
44881bb76ff1Sjsg void intel_shared_dpll_state_verify(struct intel_crtc *crtc,
44891bb76ff1Sjsg 				    struct intel_crtc_state *old_crtc_state,
44901bb76ff1Sjsg 				    struct intel_crtc_state *new_crtc_state)
44911bb76ff1Sjsg {
44921bb76ff1Sjsg 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
44931bb76ff1Sjsg 
44941bb76ff1Sjsg 	if (new_crtc_state->shared_dpll)
44951bb76ff1Sjsg 		verify_single_dpll_state(dev_priv, new_crtc_state->shared_dpll,
44961bb76ff1Sjsg 					 crtc, new_crtc_state);
44971bb76ff1Sjsg 
44981bb76ff1Sjsg 	if (old_crtc_state->shared_dpll &&
44991bb76ff1Sjsg 	    old_crtc_state->shared_dpll != new_crtc_state->shared_dpll) {
45001bb76ff1Sjsg 		u8 pipe_mask = BIT(crtc->pipe);
45011bb76ff1Sjsg 		struct intel_shared_dpll *pll = old_crtc_state->shared_dpll;
45021bb76ff1Sjsg 
4503f005ef32Sjsg 		I915_STATE_WARN(dev_priv, pll->active_mask & pipe_mask,
45041bb76ff1Sjsg 				"pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n",
45051bb76ff1Sjsg 				pipe_name(crtc->pipe), pll->active_mask);
4506f005ef32Sjsg 		I915_STATE_WARN(dev_priv, pll->state.pipe_mask & pipe_mask,
45071bb76ff1Sjsg 				"pll enabled crtcs mismatch (found %x in enabled mask (0x%x))\n",
45081bb76ff1Sjsg 				pipe_name(crtc->pipe), pll->state.pipe_mask);
45091bb76ff1Sjsg 	}
45101bb76ff1Sjsg }
45111bb76ff1Sjsg 
45121bb76ff1Sjsg void intel_shared_dpll_verify_disabled(struct drm_i915_private *i915)
45131bb76ff1Sjsg {
45141bb76ff1Sjsg 	int i;
45151bb76ff1Sjsg 
45161bb76ff1Sjsg 	for (i = 0; i < i915->display.dpll.num_shared_dpll; i++)
45171bb76ff1Sjsg 		verify_single_dpll_state(i915, &i915->display.dpll.shared_dplls[i],
45181bb76ff1Sjsg 					 NULL, NULL);
45191bb76ff1Sjsg }
4520