xref: /dflybsd-src/sys/dev/drm/i915/intel_dsi_pll.c (revision c0e85e96994c944a12cb708e4676eac8a306d23a)
19edbd4a0SFrançois Tigeot /*
29edbd4a0SFrançois Tigeot  * Copyright © 2013 Intel Corporation
39edbd4a0SFrançois Tigeot  *
49edbd4a0SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
59edbd4a0SFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
69edbd4a0SFrançois Tigeot  * to deal in the Software without restriction, including without limitation
79edbd4a0SFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
89edbd4a0SFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
99edbd4a0SFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
109edbd4a0SFrançois Tigeot  *
119edbd4a0SFrançois Tigeot  * The above copyright notice and this permission notice (including the next
129edbd4a0SFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
139edbd4a0SFrançois Tigeot  * Software.
149edbd4a0SFrançois Tigeot  *
159edbd4a0SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
169edbd4a0SFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
179edbd4a0SFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
189edbd4a0SFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
199edbd4a0SFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
209edbd4a0SFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
219edbd4a0SFrançois Tigeot  * DEALINGS IN THE SOFTWARE.
229edbd4a0SFrançois Tigeot  *
239edbd4a0SFrançois Tigeot  * Authors:
249edbd4a0SFrançois Tigeot  *	Shobhit Kumar <shobhit.kumar@intel.com>
259edbd4a0SFrançois Tigeot  *	Yogesh Mohan Marimuthu <yogesh.mohan.marimuthu@intel.com>
269edbd4a0SFrançois Tigeot  */
279edbd4a0SFrançois Tigeot 
289edbd4a0SFrançois Tigeot #include <linux/kernel.h>
299edbd4a0SFrançois Tigeot #include "intel_drv.h"
309edbd4a0SFrançois Tigeot #include "i915_drv.h"
319edbd4a0SFrançois Tigeot #include "intel_dsi.h"
329edbd4a0SFrançois Tigeot 
33*c0e85e96SFrançois Tigeot int dsi_pixel_format_bpp(int pixel_format)
34a05eeebfSFrançois Tigeot {
35a05eeebfSFrançois Tigeot 	int bpp;
36a05eeebfSFrançois Tigeot 
37a05eeebfSFrançois Tigeot 	switch (pixel_format) {
38a05eeebfSFrançois Tigeot 	default:
39a05eeebfSFrançois Tigeot 	case VID_MODE_FORMAT_RGB888:
40a05eeebfSFrançois Tigeot 	case VID_MODE_FORMAT_RGB666_LOOSE:
41a05eeebfSFrançois Tigeot 		bpp = 24;
42a05eeebfSFrançois Tigeot 		break;
43a05eeebfSFrançois Tigeot 	case VID_MODE_FORMAT_RGB666:
44a05eeebfSFrançois Tigeot 		bpp = 18;
45a05eeebfSFrançois Tigeot 		break;
46a05eeebfSFrançois Tigeot 	case VID_MODE_FORMAT_RGB565:
47a05eeebfSFrançois Tigeot 		bpp = 16;
48a05eeebfSFrançois Tigeot 		break;
49a05eeebfSFrançois Tigeot 	}
50a05eeebfSFrançois Tigeot 
51a05eeebfSFrançois Tigeot 	return bpp;
52a05eeebfSFrançois Tigeot }
53a05eeebfSFrançois Tigeot 
549edbd4a0SFrançois Tigeot struct dsi_mnp {
559edbd4a0SFrançois Tigeot 	u32 dsi_pll_ctrl;
569edbd4a0SFrançois Tigeot 	u32 dsi_pll_div;
579edbd4a0SFrançois Tigeot };
589edbd4a0SFrançois Tigeot 
599edbd4a0SFrançois Tigeot static const u32 lfsr_converts[] = {
609edbd4a0SFrançois Tigeot 	426, 469, 234, 373, 442, 221, 110, 311, 411,		/* 62 - 70 */
619edbd4a0SFrançois Tigeot 	461, 486, 243, 377, 188, 350, 175, 343, 427, 213,	/* 71 - 80 */
62a05eeebfSFrançois Tigeot 	106, 53, 282, 397, 454, 227, 113, 56, 284, 142,		/* 81 - 90 */
63a05eeebfSFrançois Tigeot 	71, 35, 273, 136, 324, 418, 465, 488, 500, 506		/* 91 - 100 */
649edbd4a0SFrançois Tigeot };
659edbd4a0SFrançois Tigeot 
669edbd4a0SFrançois Tigeot /* Get DSI clock from pixel clock */
671b13d190SFrançois Tigeot static u32 dsi_clk_from_pclk(u32 pclk, int pixel_format, int lane_count)
689edbd4a0SFrançois Tigeot {
699edbd4a0SFrançois Tigeot 	u32 dsi_clk_khz;
70a05eeebfSFrançois Tigeot 	u32 bpp = dsi_pixel_format_bpp(pixel_format);
719edbd4a0SFrançois Tigeot 
729edbd4a0SFrançois Tigeot 	/* DSI data rate = pixel clock * bits per pixel / lane count
739edbd4a0SFrançois Tigeot 	   pixel clock is converted from KHz to Hz */
741b13d190SFrançois Tigeot 	dsi_clk_khz = DIV_ROUND_CLOSEST(pclk * bpp, lane_count);
759edbd4a0SFrançois Tigeot 
769edbd4a0SFrançois Tigeot 	return dsi_clk_khz;
779edbd4a0SFrançois Tigeot }
789edbd4a0SFrançois Tigeot 
79a05eeebfSFrançois Tigeot static int dsi_calc_mnp(struct drm_i915_private *dev_priv,
80a05eeebfSFrançois Tigeot 			struct dsi_mnp *dsi_mnp, int target_dsi_clk)
819edbd4a0SFrançois Tigeot {
8219c468b4SFrançois Tigeot 	unsigned int calc_m = 0, calc_p = 0;
83a05eeebfSFrançois Tigeot 	unsigned int m_min, m_max, p_min = 2, p_max = 6;
84a05eeebfSFrançois Tigeot 	unsigned int m, n, p;
85a05eeebfSFrançois Tigeot 	int ref_clk;
8619c468b4SFrançois Tigeot 	int delta = target_dsi_clk;
879edbd4a0SFrançois Tigeot 	u32 m_seed;
889edbd4a0SFrançois Tigeot 
8919c468b4SFrançois Tigeot 	/* target_dsi_clk is expected in kHz */
9019c468b4SFrançois Tigeot 	if (target_dsi_clk < 300000 || target_dsi_clk > 1150000) {
919edbd4a0SFrançois Tigeot 		DRM_ERROR("DSI CLK Out of Range\n");
929edbd4a0SFrançois Tigeot 		return -ECHRNG;
939edbd4a0SFrançois Tigeot 	}
949edbd4a0SFrançois Tigeot 
95a05eeebfSFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv)) {
96a05eeebfSFrançois Tigeot 		ref_clk = 100000;
97a05eeebfSFrançois Tigeot 		n = 4;
98a05eeebfSFrançois Tigeot 		m_min = 70;
99a05eeebfSFrançois Tigeot 		m_max = 96;
100a05eeebfSFrançois Tigeot 	} else {
101a05eeebfSFrançois Tigeot 		ref_clk = 25000;
102a05eeebfSFrançois Tigeot 		n = 1;
103a05eeebfSFrançois Tigeot 		m_min = 62;
104a05eeebfSFrançois Tigeot 		m_max = 92;
105a05eeebfSFrançois Tigeot 	}
106a05eeebfSFrançois Tigeot 
107a05eeebfSFrançois Tigeot 	for (m = m_min; m <= m_max && delta; m++) {
108a05eeebfSFrançois Tigeot 		for (p = p_min; p <= p_max && delta; p++) {
10919c468b4SFrançois Tigeot 			/*
11019c468b4SFrançois Tigeot 			 * Find the optimal m and p divisors with minimal delta
11119c468b4SFrançois Tigeot 			 * +/- the required clock
11219c468b4SFrançois Tigeot 			 */
11319c468b4SFrançois Tigeot 			int calc_dsi_clk = (m * ref_clk) / (p * n);
11419c468b4SFrançois Tigeot 			int d = abs(target_dsi_clk - calc_dsi_clk);
11519c468b4SFrançois Tigeot 			if (d < delta) {
11619c468b4SFrançois Tigeot 				delta = d;
1179edbd4a0SFrançois Tigeot 				calc_m = m;
1189edbd4a0SFrançois Tigeot 				calc_p = p;
1199edbd4a0SFrançois Tigeot 			}
1209edbd4a0SFrançois Tigeot 		}
1219edbd4a0SFrançois Tigeot 	}
1229edbd4a0SFrançois Tigeot 
12319c468b4SFrançois Tigeot 	/* register has log2(N1), this works fine for powers of two */
12419c468b4SFrançois Tigeot 	n = ffs(n) - 1;
1259edbd4a0SFrançois Tigeot 	m_seed = lfsr_converts[calc_m - 62];
1269edbd4a0SFrançois Tigeot 	dsi_mnp->dsi_pll_ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + calc_p - 2);
12719c468b4SFrançois Tigeot 	dsi_mnp->dsi_pll_div = n << DSI_PLL_N1_DIV_SHIFT |
1289edbd4a0SFrançois Tigeot 		m_seed << DSI_PLL_M1_DIV_SHIFT;
1299edbd4a0SFrançois Tigeot 
1309edbd4a0SFrançois Tigeot 	return 0;
1319edbd4a0SFrançois Tigeot }
1329edbd4a0SFrançois Tigeot 
1339edbd4a0SFrançois Tigeot /*
1349edbd4a0SFrançois Tigeot  * XXX: The muxing and gating is hard coded for now. Need to add support for
1359edbd4a0SFrançois Tigeot  * sharing PLLs with two DSI outputs.
1369edbd4a0SFrançois Tigeot  */
1379edbd4a0SFrançois Tigeot static void vlv_configure_dsi_pll(struct intel_encoder *encoder)
1389edbd4a0SFrançois Tigeot {
1399edbd4a0SFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
1409edbd4a0SFrançois Tigeot 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
1419edbd4a0SFrançois Tigeot 	int ret;
1429edbd4a0SFrançois Tigeot 	struct dsi_mnp dsi_mnp;
1439edbd4a0SFrançois Tigeot 	u32 dsi_clk;
1449edbd4a0SFrançois Tigeot 
1451b13d190SFrançois Tigeot 	dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
1469edbd4a0SFrançois Tigeot 				    intel_dsi->lane_count);
1479edbd4a0SFrançois Tigeot 
148a05eeebfSFrançois Tigeot 	ret = dsi_calc_mnp(dev_priv, &dsi_mnp, dsi_clk);
1499edbd4a0SFrançois Tigeot 	if (ret) {
1509edbd4a0SFrançois Tigeot 		DRM_DEBUG_KMS("dsi_calc_mnp failed\n");
1519edbd4a0SFrançois Tigeot 		return;
1529edbd4a0SFrançois Tigeot 	}
1539edbd4a0SFrançois Tigeot 
1542c9916cdSFrançois Tigeot 	if (intel_dsi->ports & (1 << PORT_A))
1559edbd4a0SFrançois Tigeot 		dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
1569edbd4a0SFrançois Tigeot 
1572c9916cdSFrançois Tigeot 	if (intel_dsi->ports & (1 << PORT_C))
1582c9916cdSFrançois Tigeot 		dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL;
1592c9916cdSFrançois Tigeot 
1609edbd4a0SFrançois Tigeot 	DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n",
1619edbd4a0SFrançois Tigeot 		      dsi_mnp.dsi_pll_div, dsi_mnp.dsi_pll_ctrl);
1629edbd4a0SFrançois Tigeot 
1639edbd4a0SFrançois Tigeot 	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, 0);
1649edbd4a0SFrançois Tigeot 	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_DIVIDER, dsi_mnp.dsi_pll_div);
1659edbd4a0SFrançois Tigeot 	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, dsi_mnp.dsi_pll_ctrl);
1669edbd4a0SFrançois Tigeot }
1679edbd4a0SFrançois Tigeot 
168352ff8bdSFrançois Tigeot static void vlv_enable_dsi_pll(struct intel_encoder *encoder)
1699edbd4a0SFrançois Tigeot {
1709edbd4a0SFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
1719edbd4a0SFrançois Tigeot 	u32 tmp;
1729edbd4a0SFrançois Tigeot 
1739edbd4a0SFrançois Tigeot 	DRM_DEBUG_KMS("\n");
1749edbd4a0SFrançois Tigeot 
17519c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
1769edbd4a0SFrançois Tigeot 
1779edbd4a0SFrançois Tigeot 	vlv_configure_dsi_pll(encoder);
1789edbd4a0SFrançois Tigeot 
1799edbd4a0SFrançois Tigeot 	/* wait at least 0.5 us after ungating before enabling VCO */
1809edbd4a0SFrançois Tigeot 	usleep_range(1, 10);
1819edbd4a0SFrançois Tigeot 
1829edbd4a0SFrançois Tigeot 	tmp = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
1839edbd4a0SFrançois Tigeot 	tmp |= DSI_PLL_VCO_EN;
1849edbd4a0SFrançois Tigeot 	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp);
1859edbd4a0SFrançois Tigeot 
1862c9916cdSFrançois Tigeot 	if (wait_for(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) &
1872c9916cdSFrançois Tigeot 						DSI_PLL_LOCK, 20)) {
1889edbd4a0SFrançois Tigeot 
18919c468b4SFrançois Tigeot 		mutex_unlock(&dev_priv->sb_lock);
1909edbd4a0SFrançois Tigeot 		DRM_ERROR("DSI PLL lock failed\n");
1919edbd4a0SFrançois Tigeot 		return;
1929edbd4a0SFrançois Tigeot 	}
19319c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
1949edbd4a0SFrançois Tigeot 
1959edbd4a0SFrançois Tigeot 	DRM_DEBUG_KMS("DSI PLL locked\n");
1969edbd4a0SFrançois Tigeot }
1979edbd4a0SFrançois Tigeot 
198352ff8bdSFrançois Tigeot static void vlv_disable_dsi_pll(struct intel_encoder *encoder)
1999edbd4a0SFrançois Tigeot {
2009edbd4a0SFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
2019edbd4a0SFrançois Tigeot 	u32 tmp;
2029edbd4a0SFrançois Tigeot 
2039edbd4a0SFrançois Tigeot 	DRM_DEBUG_KMS("\n");
2049edbd4a0SFrançois Tigeot 
20519c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
2069edbd4a0SFrançois Tigeot 
2079edbd4a0SFrançois Tigeot 	tmp = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
2089edbd4a0SFrançois Tigeot 	tmp &= ~DSI_PLL_VCO_EN;
2099edbd4a0SFrançois Tigeot 	tmp |= DSI_PLL_LDO_GATE;
2109edbd4a0SFrançois Tigeot 	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp);
2119edbd4a0SFrançois Tigeot 
21219c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
2139edbd4a0SFrançois Tigeot }
21424edb884SFrançois Tigeot 
215352ff8bdSFrançois Tigeot static void bxt_disable_dsi_pll(struct intel_encoder *encoder)
216352ff8bdSFrançois Tigeot {
217352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
218352ff8bdSFrançois Tigeot 	u32 val;
219352ff8bdSFrançois Tigeot 
220352ff8bdSFrançois Tigeot 	DRM_DEBUG_KMS("\n");
221352ff8bdSFrançois Tigeot 
222352ff8bdSFrançois Tigeot 	val = I915_READ(BXT_DSI_PLL_ENABLE);
223352ff8bdSFrançois Tigeot 	val &= ~BXT_DSI_PLL_DO_ENABLE;
224352ff8bdSFrançois Tigeot 	I915_WRITE(BXT_DSI_PLL_ENABLE, val);
225352ff8bdSFrançois Tigeot 
226352ff8bdSFrançois Tigeot 	/*
227352ff8bdSFrançois Tigeot 	 * PLL lock should deassert within 200us.
228352ff8bdSFrançois Tigeot 	 * Wait up to 1ms before timing out.
229352ff8bdSFrançois Tigeot 	 */
230352ff8bdSFrançois Tigeot 	if (wait_for((I915_READ(BXT_DSI_PLL_ENABLE)
231352ff8bdSFrançois Tigeot 					& BXT_DSI_PLL_LOCKED) == 0, 1))
232352ff8bdSFrançois Tigeot 		DRM_ERROR("Timeout waiting for PLL lock deassertion\n");
233352ff8bdSFrançois Tigeot }
234352ff8bdSFrançois Tigeot 
23524edb884SFrançois Tigeot static void assert_bpp_mismatch(int pixel_format, int pipe_bpp)
23624edb884SFrançois Tigeot {
237a05eeebfSFrançois Tigeot 	int bpp = dsi_pixel_format_bpp(pixel_format);
23824edb884SFrançois Tigeot 
23924edb884SFrançois Tigeot 	WARN(bpp != pipe_bpp,
24024edb884SFrançois Tigeot 	     "bpp match assertion failure (expected %d, current %d)\n",
24124edb884SFrançois Tigeot 	     bpp, pipe_bpp);
24224edb884SFrançois Tigeot }
24324edb884SFrançois Tigeot 
244*c0e85e96SFrançois Tigeot static u32 vlv_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp)
24524edb884SFrançois Tigeot {
24624edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
24724edb884SFrançois Tigeot 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
24824edb884SFrançois Tigeot 	u32 dsi_clock, pclk;
24924edb884SFrançois Tigeot 	u32 pll_ctl, pll_div;
25019c468b4SFrançois Tigeot 	u32 m = 0, p = 0, n;
25124edb884SFrançois Tigeot 	int refclk = 25000;
25224edb884SFrançois Tigeot 	int i;
25324edb884SFrançois Tigeot 
25424edb884SFrançois Tigeot 	DRM_DEBUG_KMS("\n");
25524edb884SFrançois Tigeot 
25619c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
25724edb884SFrançois Tigeot 	pll_ctl = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
25824edb884SFrançois Tigeot 	pll_div = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_DIVIDER);
25919c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
26024edb884SFrançois Tigeot 
26124edb884SFrançois Tigeot 	/* mask out other bits and extract the P1 divisor */
26224edb884SFrançois Tigeot 	pll_ctl &= DSI_PLL_P1_POST_DIV_MASK;
26324edb884SFrançois Tigeot 	pll_ctl = pll_ctl >> (DSI_PLL_P1_POST_DIV_SHIFT - 2);
26424edb884SFrançois Tigeot 
26519c468b4SFrançois Tigeot 	/* N1 divisor */
26619c468b4SFrançois Tigeot 	n = (pll_div & DSI_PLL_N1_DIV_MASK) >> DSI_PLL_N1_DIV_SHIFT;
26719c468b4SFrançois Tigeot 	n = 1 << n; /* register has log2(N1) */
26819c468b4SFrançois Tigeot 
26924edb884SFrançois Tigeot 	/* mask out the other bits and extract the M1 divisor */
27024edb884SFrançois Tigeot 	pll_div &= DSI_PLL_M1_DIV_MASK;
27124edb884SFrançois Tigeot 	pll_div = pll_div >> DSI_PLL_M1_DIV_SHIFT;
27224edb884SFrançois Tigeot 
27324edb884SFrançois Tigeot 	while (pll_ctl) {
27424edb884SFrançois Tigeot 		pll_ctl = pll_ctl >> 1;
27524edb884SFrançois Tigeot 		p++;
27624edb884SFrançois Tigeot 	}
27724edb884SFrançois Tigeot 	p--;
27824edb884SFrançois Tigeot 
27924edb884SFrançois Tigeot 	if (!p) {
28024edb884SFrançois Tigeot 		DRM_ERROR("wrong P1 divisor\n");
28124edb884SFrançois Tigeot 		return 0;
28224edb884SFrançois Tigeot 	}
28324edb884SFrançois Tigeot 
28424edb884SFrançois Tigeot 	for (i = 0; i < ARRAY_SIZE(lfsr_converts); i++) {
28524edb884SFrançois Tigeot 		if (lfsr_converts[i] == pll_div)
28624edb884SFrançois Tigeot 			break;
28724edb884SFrançois Tigeot 	}
28824edb884SFrançois Tigeot 
28924edb884SFrançois Tigeot 	if (i == ARRAY_SIZE(lfsr_converts)) {
29024edb884SFrançois Tigeot 		DRM_ERROR("wrong m_seed programmed\n");
29124edb884SFrançois Tigeot 		return 0;
29224edb884SFrançois Tigeot 	}
29324edb884SFrançois Tigeot 
29424edb884SFrançois Tigeot 	m = i + 62;
29524edb884SFrançois Tigeot 
29619c468b4SFrançois Tigeot 	dsi_clock = (m * refclk) / (p * n);
29724edb884SFrançois Tigeot 
29824edb884SFrançois Tigeot 	/* pixel_format and pipe_bpp should agree */
29924edb884SFrançois Tigeot 	assert_bpp_mismatch(intel_dsi->pixel_format, pipe_bpp);
30024edb884SFrançois Tigeot 
30124edb884SFrançois Tigeot 	pclk = DIV_ROUND_CLOSEST(dsi_clock * intel_dsi->lane_count, pipe_bpp);
30224edb884SFrançois Tigeot 
30324edb884SFrançois Tigeot 	return pclk;
30424edb884SFrançois Tigeot }
305352ff8bdSFrançois Tigeot 
306*c0e85e96SFrançois Tigeot static u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp)
307352ff8bdSFrançois Tigeot {
308352ff8bdSFrançois Tigeot 	u32 pclk;
309352ff8bdSFrançois Tigeot 	u32 dsi_clk;
310352ff8bdSFrançois Tigeot 	u32 dsi_ratio;
311352ff8bdSFrançois Tigeot 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
312352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
313352ff8bdSFrançois Tigeot 
314352ff8bdSFrançois Tigeot 	/* Divide by zero */
315352ff8bdSFrançois Tigeot 	if (!pipe_bpp) {
316352ff8bdSFrançois Tigeot 		DRM_ERROR("Invalid BPP(0)\n");
317352ff8bdSFrançois Tigeot 		return 0;
318352ff8bdSFrançois Tigeot 	}
319352ff8bdSFrançois Tigeot 
320352ff8bdSFrançois Tigeot 	dsi_ratio = I915_READ(BXT_DSI_PLL_CTL) &
321352ff8bdSFrançois Tigeot 				BXT_DSI_PLL_RATIO_MASK;
322352ff8bdSFrançois Tigeot 
323352ff8bdSFrançois Tigeot 	/* Invalid DSI ratio ? */
324352ff8bdSFrançois Tigeot 	if (dsi_ratio < BXT_DSI_PLL_RATIO_MIN ||
325352ff8bdSFrançois Tigeot 			dsi_ratio > BXT_DSI_PLL_RATIO_MAX) {
326352ff8bdSFrançois Tigeot 		DRM_ERROR("Invalid DSI pll ratio(%u) programmed\n", dsi_ratio);
327352ff8bdSFrançois Tigeot 		return 0;
328352ff8bdSFrançois Tigeot 	}
329352ff8bdSFrançois Tigeot 
330352ff8bdSFrançois Tigeot 	dsi_clk = (dsi_ratio * BXT_REF_CLOCK_KHZ) / 2;
331352ff8bdSFrançois Tigeot 
332352ff8bdSFrançois Tigeot 	/* pixel_format and pipe_bpp should agree */
333352ff8bdSFrançois Tigeot 	assert_bpp_mismatch(intel_dsi->pixel_format, pipe_bpp);
334352ff8bdSFrançois Tigeot 
335352ff8bdSFrançois Tigeot 	pclk = DIV_ROUND_CLOSEST(dsi_clk * intel_dsi->lane_count, pipe_bpp);
336352ff8bdSFrançois Tigeot 
337352ff8bdSFrançois Tigeot 	DRM_DEBUG_DRIVER("Calculated pclk=%u\n", pclk);
338352ff8bdSFrançois Tigeot 	return pclk;
339352ff8bdSFrançois Tigeot }
340352ff8bdSFrançois Tigeot 
341*c0e85e96SFrançois Tigeot u32 intel_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp)
342*c0e85e96SFrançois Tigeot {
343*c0e85e96SFrançois Tigeot 	if (IS_BROXTON(encoder->base.dev))
344*c0e85e96SFrançois Tigeot 		return bxt_dsi_get_pclk(encoder, pipe_bpp);
345*c0e85e96SFrançois Tigeot 	else
346*c0e85e96SFrançois Tigeot 		return vlv_dsi_get_pclk(encoder, pipe_bpp);
347*c0e85e96SFrançois Tigeot }
348*c0e85e96SFrançois Tigeot 
349352ff8bdSFrançois Tigeot static void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
350352ff8bdSFrançois Tigeot {
351352ff8bdSFrançois Tigeot 	u32 temp;
352352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
353352ff8bdSFrançois Tigeot 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
354352ff8bdSFrançois Tigeot 
355352ff8bdSFrançois Tigeot 	temp = I915_READ(MIPI_CTRL(port));
356352ff8bdSFrançois Tigeot 	temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
357352ff8bdSFrançois Tigeot 	I915_WRITE(MIPI_CTRL(port), temp |
358352ff8bdSFrançois Tigeot 			intel_dsi->escape_clk_div <<
359352ff8bdSFrançois Tigeot 			ESCAPE_CLOCK_DIVIDER_SHIFT);
360352ff8bdSFrançois Tigeot }
361352ff8bdSFrançois Tigeot 
362352ff8bdSFrançois Tigeot /* Program BXT Mipi clocks and dividers */
363352ff8bdSFrançois Tigeot static void bxt_dsi_program_clocks(struct drm_device *dev, enum port port)
364352ff8bdSFrançois Tigeot {
365352ff8bdSFrançois Tigeot 	u32 tmp;
366352ff8bdSFrançois Tigeot 	u32 divider;
367352ff8bdSFrançois Tigeot 	u32 dsi_rate;
368352ff8bdSFrançois Tigeot 	u32 pll_ratio;
369352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
370352ff8bdSFrançois Tigeot 
371352ff8bdSFrançois Tigeot 	/* Clear old configurations */
372352ff8bdSFrançois Tigeot 	tmp = I915_READ(BXT_MIPI_CLOCK_CTL);
373352ff8bdSFrançois Tigeot 	tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port));
374352ff8bdSFrançois Tigeot 	tmp &= ~(BXT_MIPI_RX_ESCLK_FIXDIV_MASK(port));
375352ff8bdSFrançois Tigeot 	tmp &= ~(BXT_MIPI_ESCLK_VAR_DIV_MASK(port));
376352ff8bdSFrançois Tigeot 	tmp &= ~(BXT_MIPI_DPHY_DIVIDER_MASK(port));
377352ff8bdSFrançois Tigeot 
378352ff8bdSFrançois Tigeot 	/* Get the current DSI rate(actual) */
379352ff8bdSFrançois Tigeot 	pll_ratio = I915_READ(BXT_DSI_PLL_CTL) &
380352ff8bdSFrançois Tigeot 				BXT_DSI_PLL_RATIO_MASK;
381352ff8bdSFrançois Tigeot 	dsi_rate = (BXT_REF_CLOCK_KHZ * pll_ratio) / 2;
382352ff8bdSFrançois Tigeot 
383352ff8bdSFrançois Tigeot 	/* Max possible output of clock is 39.5 MHz, program value -1 */
384352ff8bdSFrançois Tigeot 	divider = (dsi_rate / BXT_MAX_VAR_OUTPUT_KHZ) - 1;
385352ff8bdSFrançois Tigeot 	tmp |= BXT_MIPI_ESCLK_VAR_DIV(port, divider);
386352ff8bdSFrançois Tigeot 
387352ff8bdSFrançois Tigeot 	/*
388352ff8bdSFrançois Tigeot 	 * Tx escape clock must be as close to 20MHz possible, but should
389352ff8bdSFrançois Tigeot 	 * not exceed it. Hence select divide by 2
390352ff8bdSFrançois Tigeot 	 */
391352ff8bdSFrançois Tigeot 	tmp |= BXT_MIPI_TX_ESCLK_8XDIV_BY2(port);
392352ff8bdSFrançois Tigeot 
393352ff8bdSFrançois Tigeot 	tmp |= BXT_MIPI_RX_ESCLK_8X_BY3(port);
394352ff8bdSFrançois Tigeot 
395352ff8bdSFrançois Tigeot 	I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp);
396352ff8bdSFrançois Tigeot }
397352ff8bdSFrançois Tigeot 
398352ff8bdSFrançois Tigeot static bool bxt_configure_dsi_pll(struct intel_encoder *encoder)
399352ff8bdSFrançois Tigeot {
400352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
401352ff8bdSFrançois Tigeot 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
402352ff8bdSFrançois Tigeot 	u8 dsi_ratio;
403352ff8bdSFrançois Tigeot 	u32 dsi_clk;
404352ff8bdSFrançois Tigeot 	u32 val;
405352ff8bdSFrançois Tigeot 
406352ff8bdSFrançois Tigeot 	dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
407352ff8bdSFrançois Tigeot 			intel_dsi->lane_count);
408352ff8bdSFrançois Tigeot 
409352ff8bdSFrançois Tigeot 	/*
410352ff8bdSFrançois Tigeot 	 * From clock diagram, to get PLL ratio divider, divide double of DSI
411352ff8bdSFrançois Tigeot 	 * link rate (i.e., 2*8x=16x frequency value) by ref clock. Make sure to
412352ff8bdSFrançois Tigeot 	 * round 'up' the result
413352ff8bdSFrançois Tigeot 	 */
414352ff8bdSFrançois Tigeot 	dsi_ratio = DIV_ROUND_UP(dsi_clk * 2, BXT_REF_CLOCK_KHZ);
415352ff8bdSFrançois Tigeot 	if (dsi_ratio < BXT_DSI_PLL_RATIO_MIN ||
416352ff8bdSFrançois Tigeot 			dsi_ratio > BXT_DSI_PLL_RATIO_MAX) {
417352ff8bdSFrançois Tigeot 		DRM_ERROR("Cant get a suitable ratio from DSI PLL ratios\n");
418352ff8bdSFrançois Tigeot 		return false;
419352ff8bdSFrançois Tigeot 	}
420352ff8bdSFrançois Tigeot 
421352ff8bdSFrançois Tigeot 	/*
422352ff8bdSFrançois Tigeot 	 * Program DSI ratio and Select MIPIC and MIPIA PLL output as 8x
423352ff8bdSFrançois Tigeot 	 * Spec says both have to be programmed, even if one is not getting
424352ff8bdSFrançois Tigeot 	 * used. Configure MIPI_CLOCK_CTL dividers in modeset
425352ff8bdSFrançois Tigeot 	 */
426352ff8bdSFrançois Tigeot 	val = I915_READ(BXT_DSI_PLL_CTL);
427352ff8bdSFrançois Tigeot 	val &= ~BXT_DSI_PLL_PVD_RATIO_MASK;
428352ff8bdSFrançois Tigeot 	val &= ~BXT_DSI_FREQ_SEL_MASK;
429352ff8bdSFrançois Tigeot 	val &= ~BXT_DSI_PLL_RATIO_MASK;
430352ff8bdSFrançois Tigeot 	val |= (dsi_ratio | BXT_DSIA_16X_BY2 | BXT_DSIC_16X_BY2);
431352ff8bdSFrançois Tigeot 
432352ff8bdSFrançois Tigeot 	/* As per recommendation from hardware team,
433352ff8bdSFrançois Tigeot 	 * Prog PVD ratio =1 if dsi ratio <= 50
434352ff8bdSFrançois Tigeot 	 */
435352ff8bdSFrançois Tigeot 	if (dsi_ratio <= 50) {
436352ff8bdSFrançois Tigeot 		val &= ~BXT_DSI_PLL_PVD_RATIO_MASK;
437352ff8bdSFrançois Tigeot 		val |= BXT_DSI_PLL_PVD_RATIO_1;
438352ff8bdSFrançois Tigeot 	}
439352ff8bdSFrançois Tigeot 
440352ff8bdSFrançois Tigeot 	I915_WRITE(BXT_DSI_PLL_CTL, val);
441352ff8bdSFrançois Tigeot 	POSTING_READ(BXT_DSI_PLL_CTL);
442352ff8bdSFrançois Tigeot 
443352ff8bdSFrançois Tigeot 	return true;
444352ff8bdSFrançois Tigeot }
445352ff8bdSFrançois Tigeot 
446352ff8bdSFrançois Tigeot static void bxt_enable_dsi_pll(struct intel_encoder *encoder)
447352ff8bdSFrançois Tigeot {
448352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
449352ff8bdSFrançois Tigeot 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
450352ff8bdSFrançois Tigeot 	enum port port;
451352ff8bdSFrançois Tigeot 	u32 val;
452352ff8bdSFrançois Tigeot 
453352ff8bdSFrançois Tigeot 	DRM_DEBUG_KMS("\n");
454352ff8bdSFrançois Tigeot 
455352ff8bdSFrançois Tigeot 	val = I915_READ(BXT_DSI_PLL_ENABLE);
456352ff8bdSFrançois Tigeot 
457352ff8bdSFrançois Tigeot 	if (val & BXT_DSI_PLL_DO_ENABLE) {
458352ff8bdSFrançois Tigeot 		WARN(1, "DSI PLL already enabled. Disabling it.\n");
459352ff8bdSFrançois Tigeot 		val &= ~BXT_DSI_PLL_DO_ENABLE;
460352ff8bdSFrançois Tigeot 		I915_WRITE(BXT_DSI_PLL_ENABLE, val);
461352ff8bdSFrançois Tigeot 	}
462352ff8bdSFrançois Tigeot 
463352ff8bdSFrançois Tigeot 	/* Configure PLL vales */
464352ff8bdSFrançois Tigeot 	if (!bxt_configure_dsi_pll(encoder)) {
465352ff8bdSFrançois Tigeot 		DRM_ERROR("Configure DSI PLL failed, abort PLL enable\n");
466352ff8bdSFrançois Tigeot 		return;
467352ff8bdSFrançois Tigeot 	}
468352ff8bdSFrançois Tigeot 
469352ff8bdSFrançois Tigeot 	/* Program TX, RX, Dphy clocks */
470352ff8bdSFrançois Tigeot 	for_each_dsi_port(port, intel_dsi->ports)
471352ff8bdSFrançois Tigeot 		bxt_dsi_program_clocks(encoder->base.dev, port);
472352ff8bdSFrançois Tigeot 
473352ff8bdSFrançois Tigeot 	/* Enable DSI PLL */
474352ff8bdSFrançois Tigeot 	val = I915_READ(BXT_DSI_PLL_ENABLE);
475352ff8bdSFrançois Tigeot 	val |= BXT_DSI_PLL_DO_ENABLE;
476352ff8bdSFrançois Tigeot 	I915_WRITE(BXT_DSI_PLL_ENABLE, val);
477352ff8bdSFrançois Tigeot 
478352ff8bdSFrançois Tigeot 	/* Timeout and fail if PLL not locked */
479352ff8bdSFrançois Tigeot 	if (wait_for(I915_READ(BXT_DSI_PLL_ENABLE) & BXT_DSI_PLL_LOCKED, 1)) {
480352ff8bdSFrançois Tigeot 		DRM_ERROR("Timed out waiting for DSI PLL to lock\n");
481352ff8bdSFrançois Tigeot 		return;
482352ff8bdSFrançois Tigeot 	}
483352ff8bdSFrançois Tigeot 
484352ff8bdSFrançois Tigeot 	DRM_DEBUG_KMS("DSI PLL locked\n");
485352ff8bdSFrançois Tigeot }
486352ff8bdSFrançois Tigeot 
487352ff8bdSFrançois Tigeot void intel_enable_dsi_pll(struct intel_encoder *encoder)
488352ff8bdSFrançois Tigeot {
489352ff8bdSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
490352ff8bdSFrançois Tigeot 
491aee94f86SFrançois Tigeot 	if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
492352ff8bdSFrançois Tigeot 		vlv_enable_dsi_pll(encoder);
493352ff8bdSFrançois Tigeot 	else if (IS_BROXTON(dev))
494352ff8bdSFrançois Tigeot 		bxt_enable_dsi_pll(encoder);
495352ff8bdSFrançois Tigeot }
496352ff8bdSFrançois Tigeot 
497352ff8bdSFrançois Tigeot void intel_disable_dsi_pll(struct intel_encoder *encoder)
498352ff8bdSFrançois Tigeot {
499352ff8bdSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
500352ff8bdSFrançois Tigeot 
501aee94f86SFrançois Tigeot 	if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
502352ff8bdSFrançois Tigeot 		vlv_disable_dsi_pll(encoder);
503352ff8bdSFrançois Tigeot 	else if (IS_BROXTON(dev))
504352ff8bdSFrançois Tigeot 		bxt_disable_dsi_pll(encoder);
505352ff8bdSFrançois Tigeot }
506352ff8bdSFrançois Tigeot 
507352ff8bdSFrançois Tigeot static void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
508352ff8bdSFrançois Tigeot {
509352ff8bdSFrançois Tigeot 	u32 tmp;
510352ff8bdSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
511352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
512352ff8bdSFrançois Tigeot 
513352ff8bdSFrançois Tigeot 	/* Clear old configurations */
514352ff8bdSFrançois Tigeot 	tmp = I915_READ(BXT_MIPI_CLOCK_CTL);
515352ff8bdSFrançois Tigeot 	tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port));
516352ff8bdSFrançois Tigeot 	tmp &= ~(BXT_MIPI_RX_ESCLK_FIXDIV_MASK(port));
517352ff8bdSFrançois Tigeot 	tmp &= ~(BXT_MIPI_ESCLK_VAR_DIV_MASK(port));
518352ff8bdSFrançois Tigeot 	tmp &= ~(BXT_MIPI_DPHY_DIVIDER_MASK(port));
519352ff8bdSFrançois Tigeot 	I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp);
520352ff8bdSFrançois Tigeot 	I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
521352ff8bdSFrançois Tigeot }
522352ff8bdSFrançois Tigeot 
523352ff8bdSFrançois Tigeot void intel_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
524352ff8bdSFrançois Tigeot {
525352ff8bdSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
526352ff8bdSFrançois Tigeot 
527352ff8bdSFrançois Tigeot 	if (IS_BROXTON(dev))
528352ff8bdSFrançois Tigeot 		bxt_dsi_reset_clocks(encoder, port);
529aee94f86SFrançois Tigeot 	else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
530352ff8bdSFrançois Tigeot 		vlv_dsi_reset_clocks(encoder, port);
531352ff8bdSFrançois Tigeot }
532