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 338621f407SFrançois Tigeot static const u16 lfsr_converts[] = { 349edbd4a0SFrançois Tigeot 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 62 - 70 */ 359edbd4a0SFrançois Tigeot 461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */ 36a05eeebfSFrançois Tigeot 106, 53, 282, 397, 454, 227, 113, 56, 284, 142, /* 81 - 90 */ 37a05eeebfSFrançois Tigeot 71, 35, 273, 136, 324, 418, 465, 488, 500, 506 /* 91 - 100 */ 389edbd4a0SFrançois Tigeot }; 399edbd4a0SFrançois Tigeot 409edbd4a0SFrançois Tigeot /* Get DSI clock from pixel clock */ 418621f407SFrançois Tigeot static u32 dsi_clk_from_pclk(u32 pclk, enum mipi_dsi_pixel_format fmt, 428621f407SFrançois Tigeot int lane_count) 439edbd4a0SFrançois Tigeot { 449edbd4a0SFrançois Tigeot u32 dsi_clk_khz; 458621f407SFrançois Tigeot u32 bpp = mipi_dsi_pixel_format_to_bpp(fmt); 469edbd4a0SFrançois Tigeot 479edbd4a0SFrançois Tigeot /* DSI data rate = pixel clock * bits per pixel / lane count 489edbd4a0SFrançois Tigeot pixel clock is converted from KHz to Hz */ 491b13d190SFrançois Tigeot dsi_clk_khz = DIV_ROUND_CLOSEST(pclk * bpp, lane_count); 509edbd4a0SFrançois Tigeot 519edbd4a0SFrançois Tigeot return dsi_clk_khz; 529edbd4a0SFrançois Tigeot } 539edbd4a0SFrançois Tigeot 54a05eeebfSFrançois Tigeot static int dsi_calc_mnp(struct drm_i915_private *dev_priv, 558621f407SFrançois Tigeot struct intel_crtc_state *config, 568621f407SFrançois Tigeot int target_dsi_clk) 579edbd4a0SFrançois Tigeot { 58a05eeebfSFrançois Tigeot unsigned int m_min, m_max, p_min = 2, p_max = 6; 59a05eeebfSFrançois Tigeot unsigned int m, n, p; 60303bf270SFrançois Tigeot unsigned int calc_m, calc_p; 61303bf270SFrançois Tigeot int delta, ref_clk; 629edbd4a0SFrançois Tigeot 6319c468b4SFrançois Tigeot /* target_dsi_clk is expected in kHz */ 6419c468b4SFrançois Tigeot if (target_dsi_clk < 300000 || target_dsi_clk > 1150000) { 659edbd4a0SFrançois Tigeot DRM_ERROR("DSI CLK Out of Range\n"); 669edbd4a0SFrançois Tigeot return -ECHRNG; 679edbd4a0SFrançois Tigeot } 689edbd4a0SFrançois Tigeot 69a05eeebfSFrançois Tigeot if (IS_CHERRYVIEW(dev_priv)) { 70a05eeebfSFrançois Tigeot ref_clk = 100000; 71a05eeebfSFrançois Tigeot n = 4; 72a05eeebfSFrançois Tigeot m_min = 70; 73a05eeebfSFrançois Tigeot m_max = 96; 74a05eeebfSFrançois Tigeot } else { 75a05eeebfSFrançois Tigeot ref_clk = 25000; 76a05eeebfSFrançois Tigeot n = 1; 77a05eeebfSFrançois Tigeot m_min = 62; 78a05eeebfSFrançois Tigeot m_max = 92; 79a05eeebfSFrançois Tigeot } 80a05eeebfSFrançois Tigeot 81303bf270SFrançois Tigeot calc_p = p_min; 82303bf270SFrançois Tigeot calc_m = m_min; 83303bf270SFrançois Tigeot delta = abs(target_dsi_clk - (m_min * ref_clk) / (p_min * n)); 84303bf270SFrançois Tigeot 85a05eeebfSFrançois Tigeot for (m = m_min; m <= m_max && delta; m++) { 86a05eeebfSFrançois Tigeot for (p = p_min; p <= p_max && delta; p++) { 8719c468b4SFrançois Tigeot /* 8819c468b4SFrançois Tigeot * Find the optimal m and p divisors with minimal delta 8919c468b4SFrançois Tigeot * +/- the required clock 9019c468b4SFrançois Tigeot */ 9119c468b4SFrançois Tigeot int calc_dsi_clk = (m * ref_clk) / (p * n); 9219c468b4SFrançois Tigeot int d = abs(target_dsi_clk - calc_dsi_clk); 9319c468b4SFrançois Tigeot if (d < delta) { 9419c468b4SFrançois Tigeot delta = d; 959edbd4a0SFrançois Tigeot calc_m = m; 969edbd4a0SFrançois Tigeot calc_p = p; 979edbd4a0SFrançois Tigeot } 989edbd4a0SFrançois Tigeot } 999edbd4a0SFrançois Tigeot } 1009edbd4a0SFrançois Tigeot 10119c468b4SFrançois Tigeot /* register has log2(N1), this works fine for powers of two */ 1028621f407SFrançois Tigeot config->dsi_pll.ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + calc_p - 2); 103303bf270SFrançois Tigeot config->dsi_pll.div = 104303bf270SFrançois Tigeot (ffs(n) - 1) << DSI_PLL_N1_DIV_SHIFT | 105303bf270SFrançois Tigeot (u32)lfsr_converts[calc_m - 62] << DSI_PLL_M1_DIV_SHIFT; 1069edbd4a0SFrançois Tigeot 1079edbd4a0SFrançois Tigeot return 0; 1089edbd4a0SFrançois Tigeot } 1099edbd4a0SFrançois Tigeot 1109edbd4a0SFrançois Tigeot /* 1119edbd4a0SFrançois Tigeot * XXX: The muxing and gating is hard coded for now. Need to add support for 1129edbd4a0SFrançois Tigeot * sharing PLLs with two DSI outputs. 1139edbd4a0SFrançois Tigeot */ 1148621f407SFrançois Tigeot static int vlv_compute_dsi_pll(struct intel_encoder *encoder, 1158621f407SFrançois Tigeot struct intel_crtc_state *config) 1169edbd4a0SFrançois Tigeot { 117303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 1189edbd4a0SFrançois Tigeot struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); 1199edbd4a0SFrançois Tigeot int ret; 1209edbd4a0SFrançois Tigeot u32 dsi_clk; 1219edbd4a0SFrançois Tigeot 1221b13d190SFrançois Tigeot dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format, 1239edbd4a0SFrançois Tigeot intel_dsi->lane_count); 1249edbd4a0SFrançois Tigeot 1258621f407SFrançois Tigeot ret = dsi_calc_mnp(dev_priv, config, dsi_clk); 1269edbd4a0SFrançois Tigeot if (ret) { 1279edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("dsi_calc_mnp failed\n"); 1288621f407SFrançois Tigeot return ret; 1299edbd4a0SFrançois Tigeot } 1309edbd4a0SFrançois Tigeot 1312c9916cdSFrançois Tigeot if (intel_dsi->ports & (1 << PORT_A)) 1328621f407SFrançois Tigeot config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL; 1339edbd4a0SFrançois Tigeot 1342c9916cdSFrançois Tigeot if (intel_dsi->ports & (1 << PORT_C)) 1358621f407SFrançois Tigeot config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL; 1368621f407SFrançois Tigeot 1378621f407SFrançois Tigeot config->dsi_pll.ctrl |= DSI_PLL_VCO_EN; 1382c9916cdSFrançois Tigeot 1399edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n", 1408621f407SFrançois Tigeot config->dsi_pll.div, config->dsi_pll.ctrl); 1419edbd4a0SFrançois Tigeot 1428621f407SFrançois Tigeot return 0; 1439edbd4a0SFrançois Tigeot } 1449edbd4a0SFrançois Tigeot 1458621f407SFrançois Tigeot static void vlv_enable_dsi_pll(struct intel_encoder *encoder, 1468621f407SFrançois Tigeot const struct intel_crtc_state *config) 1479edbd4a0SFrançois Tigeot { 1488621f407SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 1499edbd4a0SFrançois Tigeot 1509edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("\n"); 1519edbd4a0SFrançois Tigeot 15219c468b4SFrançois Tigeot mutex_lock(&dev_priv->sb_lock); 1539edbd4a0SFrançois Tigeot 1548621f407SFrançois Tigeot vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, 0); 1558621f407SFrançois Tigeot vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_DIVIDER, config->dsi_pll.div); 1568621f407SFrançois Tigeot vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, 1578621f407SFrançois Tigeot config->dsi_pll.ctrl & ~DSI_PLL_VCO_EN); 1589edbd4a0SFrançois Tigeot 1599edbd4a0SFrançois Tigeot /* wait at least 0.5 us after ungating before enabling VCO */ 1609edbd4a0SFrançois Tigeot usleep_range(1, 10); 1619edbd4a0SFrançois Tigeot 1628621f407SFrançois Tigeot vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, config->dsi_pll.ctrl); 1639edbd4a0SFrançois Tigeot 1642c9916cdSFrançois Tigeot if (wait_for(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) & 1652c9916cdSFrançois Tigeot DSI_PLL_LOCK, 20)) { 1669edbd4a0SFrançois Tigeot 16719c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock); 1689edbd4a0SFrançois Tigeot DRM_ERROR("DSI PLL lock failed\n"); 1699edbd4a0SFrançois Tigeot return; 1709edbd4a0SFrançois Tigeot } 17119c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock); 1729edbd4a0SFrançois Tigeot 1739edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("DSI PLL locked\n"); 1749edbd4a0SFrançois Tigeot } 1759edbd4a0SFrançois Tigeot 176352ff8bdSFrançois Tigeot static void vlv_disable_dsi_pll(struct intel_encoder *encoder) 1779edbd4a0SFrançois Tigeot { 1788621f407SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 1799edbd4a0SFrançois Tigeot u32 tmp; 1809edbd4a0SFrançois Tigeot 1819edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("\n"); 1829edbd4a0SFrançois Tigeot 18319c468b4SFrançois Tigeot mutex_lock(&dev_priv->sb_lock); 1849edbd4a0SFrançois Tigeot 1859edbd4a0SFrançois Tigeot tmp = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL); 1869edbd4a0SFrançois Tigeot tmp &= ~DSI_PLL_VCO_EN; 1879edbd4a0SFrançois Tigeot tmp |= DSI_PLL_LDO_GATE; 1889edbd4a0SFrançois Tigeot vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp); 1899edbd4a0SFrançois Tigeot 19019c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock); 1919edbd4a0SFrançois Tigeot } 19224edb884SFrançois Tigeot 1938621f407SFrançois Tigeot static bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv) 1948621f407SFrançois Tigeot { 1958621f407SFrançois Tigeot bool enabled; 1968621f407SFrançois Tigeot u32 val; 1978621f407SFrançois Tigeot u32 mask; 1988621f407SFrançois Tigeot 1998621f407SFrançois Tigeot mask = BXT_DSI_PLL_DO_ENABLE | BXT_DSI_PLL_LOCKED; 2008621f407SFrançois Tigeot val = I915_READ(BXT_DSI_PLL_ENABLE); 2018621f407SFrançois Tigeot enabled = (val & mask) == mask; 2028621f407SFrançois Tigeot 2038621f407SFrançois Tigeot if (!enabled) 2048621f407SFrançois Tigeot return false; 2058621f407SFrançois Tigeot 2068621f407SFrançois Tigeot /* 2078621f407SFrançois Tigeot * Both dividers must be programmed with valid values even if only one 2088621f407SFrançois Tigeot * of the PLL is used, see BSpec/Broxton Clocks. Check this here for 2098621f407SFrançois Tigeot * paranoia, since BIOS is known to misconfigure PLLs in this way at 2108621f407SFrançois Tigeot * times, and since accessing DSI registers with invalid dividers 2118621f407SFrançois Tigeot * causes a system hang. 2128621f407SFrançois Tigeot */ 2138621f407SFrançois Tigeot val = I915_READ(BXT_DSI_PLL_CTL); 2148621f407SFrançois Tigeot if (!(val & BXT_DSIA_16X_MASK) || !(val & BXT_DSIC_16X_MASK)) { 2158621f407SFrançois Tigeot DRM_DEBUG_DRIVER("PLL is enabled with invalid divider settings (%08x)\n", 2168621f407SFrançois Tigeot val); 2178621f407SFrançois Tigeot enabled = false; 2188621f407SFrançois Tigeot } 2198621f407SFrançois Tigeot 2208621f407SFrançois Tigeot return enabled; 2218621f407SFrançois Tigeot } 2228621f407SFrançois Tigeot 223352ff8bdSFrançois Tigeot static void bxt_disable_dsi_pll(struct intel_encoder *encoder) 224352ff8bdSFrançois Tigeot { 2258621f407SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 226352ff8bdSFrançois Tigeot u32 val; 227352ff8bdSFrançois Tigeot 228352ff8bdSFrançois Tigeot DRM_DEBUG_KMS("\n"); 229352ff8bdSFrançois Tigeot 230352ff8bdSFrançois Tigeot val = I915_READ(BXT_DSI_PLL_ENABLE); 231352ff8bdSFrançois Tigeot val &= ~BXT_DSI_PLL_DO_ENABLE; 232352ff8bdSFrançois Tigeot I915_WRITE(BXT_DSI_PLL_ENABLE, val); 233352ff8bdSFrançois Tigeot 234352ff8bdSFrançois Tigeot /* 235352ff8bdSFrançois Tigeot * PLL lock should deassert within 200us. 236352ff8bdSFrançois Tigeot * Wait up to 1ms before timing out. 237352ff8bdSFrançois Tigeot */ 2381487f786SFrançois Tigeot if (intel_wait_for_register(dev_priv, 2391487f786SFrançois Tigeot BXT_DSI_PLL_ENABLE, 2401487f786SFrançois Tigeot BXT_DSI_PLL_LOCKED, 2411487f786SFrançois Tigeot 0, 2421487f786SFrançois Tigeot 1)) 243352ff8bdSFrançois Tigeot DRM_ERROR("Timeout waiting for PLL lock deassertion\n"); 244352ff8bdSFrançois Tigeot } 245352ff8bdSFrançois Tigeot 2468621f407SFrançois Tigeot static void assert_bpp_mismatch(enum mipi_dsi_pixel_format fmt, int pipe_bpp) 24724edb884SFrançois Tigeot { 2488621f407SFrançois Tigeot int bpp = mipi_dsi_pixel_format_to_bpp(fmt); 24924edb884SFrançois Tigeot 25024edb884SFrançois Tigeot WARN(bpp != pipe_bpp, 25124edb884SFrançois Tigeot "bpp match assertion failure (expected %d, current %d)\n", 25224edb884SFrançois Tigeot bpp, pipe_bpp); 25324edb884SFrançois Tigeot } 25424edb884SFrançois Tigeot 2558621f407SFrançois Tigeot static u32 vlv_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, 2568621f407SFrançois Tigeot struct intel_crtc_state *config) 25724edb884SFrançois Tigeot { 2588621f407SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 25924edb884SFrançois Tigeot struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); 26024edb884SFrançois Tigeot u32 dsi_clock, pclk; 26124edb884SFrançois Tigeot u32 pll_ctl, pll_div; 26219c468b4SFrançois Tigeot u32 m = 0, p = 0, n; 2638621f407SFrançois Tigeot int refclk = IS_CHERRYVIEW(dev_priv) ? 100000 : 25000; 26424edb884SFrançois Tigeot int i; 26524edb884SFrançois Tigeot 26624edb884SFrançois Tigeot DRM_DEBUG_KMS("\n"); 26724edb884SFrançois Tigeot 26819c468b4SFrançois Tigeot mutex_lock(&dev_priv->sb_lock); 26924edb884SFrançois Tigeot pll_ctl = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL); 27024edb884SFrançois Tigeot pll_div = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_DIVIDER); 27119c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock); 27224edb884SFrançois Tigeot 2738621f407SFrançois Tigeot config->dsi_pll.ctrl = pll_ctl & ~DSI_PLL_LOCK; 2748621f407SFrançois Tigeot config->dsi_pll.div = pll_div; 2758621f407SFrançois Tigeot 27624edb884SFrançois Tigeot /* mask out other bits and extract the P1 divisor */ 27724edb884SFrançois Tigeot pll_ctl &= DSI_PLL_P1_POST_DIV_MASK; 27824edb884SFrançois Tigeot pll_ctl = pll_ctl >> (DSI_PLL_P1_POST_DIV_SHIFT - 2); 27924edb884SFrançois Tigeot 28019c468b4SFrançois Tigeot /* N1 divisor */ 28119c468b4SFrançois Tigeot n = (pll_div & DSI_PLL_N1_DIV_MASK) >> DSI_PLL_N1_DIV_SHIFT; 28219c468b4SFrançois Tigeot n = 1 << n; /* register has log2(N1) */ 28319c468b4SFrançois Tigeot 28424edb884SFrançois Tigeot /* mask out the other bits and extract the M1 divisor */ 28524edb884SFrançois Tigeot pll_div &= DSI_PLL_M1_DIV_MASK; 28624edb884SFrançois Tigeot pll_div = pll_div >> DSI_PLL_M1_DIV_SHIFT; 28724edb884SFrançois Tigeot 28824edb884SFrançois Tigeot while (pll_ctl) { 28924edb884SFrançois Tigeot pll_ctl = pll_ctl >> 1; 29024edb884SFrançois Tigeot p++; 29124edb884SFrançois Tigeot } 29224edb884SFrançois Tigeot p--; 29324edb884SFrançois Tigeot 29424edb884SFrançois Tigeot if (!p) { 29524edb884SFrançois Tigeot DRM_ERROR("wrong P1 divisor\n"); 29624edb884SFrançois Tigeot return 0; 29724edb884SFrançois Tigeot } 29824edb884SFrançois Tigeot 29924edb884SFrançois Tigeot for (i = 0; i < ARRAY_SIZE(lfsr_converts); i++) { 30024edb884SFrançois Tigeot if (lfsr_converts[i] == pll_div) 30124edb884SFrançois Tigeot break; 30224edb884SFrançois Tigeot } 30324edb884SFrançois Tigeot 30424edb884SFrançois Tigeot if (i == ARRAY_SIZE(lfsr_converts)) { 30524edb884SFrançois Tigeot DRM_ERROR("wrong m_seed programmed\n"); 30624edb884SFrançois Tigeot return 0; 30724edb884SFrançois Tigeot } 30824edb884SFrançois Tigeot 30924edb884SFrançois Tigeot m = i + 62; 31024edb884SFrançois Tigeot 31119c468b4SFrançois Tigeot dsi_clock = (m * refclk) / (p * n); 31224edb884SFrançois Tigeot 31324edb884SFrançois Tigeot /* pixel_format and pipe_bpp should agree */ 31424edb884SFrançois Tigeot assert_bpp_mismatch(intel_dsi->pixel_format, pipe_bpp); 31524edb884SFrançois Tigeot 31624edb884SFrançois Tigeot pclk = DIV_ROUND_CLOSEST(dsi_clock * intel_dsi->lane_count, pipe_bpp); 31724edb884SFrançois Tigeot 31824edb884SFrançois Tigeot return pclk; 31924edb884SFrançois Tigeot } 320352ff8bdSFrançois Tigeot 3218621f407SFrançois Tigeot static u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, 3228621f407SFrançois Tigeot struct intel_crtc_state *config) 323352ff8bdSFrançois Tigeot { 324352ff8bdSFrançois Tigeot u32 pclk; 325352ff8bdSFrançois Tigeot u32 dsi_clk; 326352ff8bdSFrançois Tigeot u32 dsi_ratio; 327352ff8bdSFrançois Tigeot struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); 328303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 329352ff8bdSFrançois Tigeot 330352ff8bdSFrançois Tigeot /* Divide by zero */ 331352ff8bdSFrançois Tigeot if (!pipe_bpp) { 332352ff8bdSFrançois Tigeot DRM_ERROR("Invalid BPP(0)\n"); 333352ff8bdSFrançois Tigeot return 0; 334352ff8bdSFrançois Tigeot } 335352ff8bdSFrançois Tigeot 3368621f407SFrançois Tigeot config->dsi_pll.ctrl = I915_READ(BXT_DSI_PLL_CTL); 337352ff8bdSFrançois Tigeot 3388621f407SFrançois Tigeot dsi_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK; 339352ff8bdSFrançois Tigeot 340352ff8bdSFrançois Tigeot dsi_clk = (dsi_ratio * BXT_REF_CLOCK_KHZ) / 2; 341352ff8bdSFrançois Tigeot 342352ff8bdSFrançois Tigeot /* pixel_format and pipe_bpp should agree */ 343352ff8bdSFrançois Tigeot assert_bpp_mismatch(intel_dsi->pixel_format, pipe_bpp); 344352ff8bdSFrançois Tigeot 345352ff8bdSFrançois Tigeot pclk = DIV_ROUND_CLOSEST(dsi_clk * intel_dsi->lane_count, pipe_bpp); 346352ff8bdSFrançois Tigeot 347352ff8bdSFrançois Tigeot DRM_DEBUG_DRIVER("Calculated pclk=%u\n", pclk); 348352ff8bdSFrançois Tigeot return pclk; 349352ff8bdSFrançois Tigeot } 350352ff8bdSFrançois Tigeot 3518621f407SFrançois Tigeot u32 intel_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, 3528621f407SFrançois Tigeot struct intel_crtc_state *config) 353c0e85e96SFrançois Tigeot { 354*1e12ee3bSFrançois Tigeot if (IS_BROXTON(to_i915(encoder->base.dev))) 3558621f407SFrançois Tigeot return bxt_dsi_get_pclk(encoder, pipe_bpp, config); 356c0e85e96SFrançois Tigeot else 3578621f407SFrançois Tigeot return vlv_dsi_get_pclk(encoder, pipe_bpp, config); 358c0e85e96SFrançois Tigeot } 359c0e85e96SFrançois Tigeot 360352ff8bdSFrançois Tigeot static void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) 361352ff8bdSFrançois Tigeot { 362352ff8bdSFrançois Tigeot u32 temp; 363303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 364352ff8bdSFrançois Tigeot struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); 365352ff8bdSFrançois Tigeot 366352ff8bdSFrançois Tigeot temp = I915_READ(MIPI_CTRL(port)); 367352ff8bdSFrançois Tigeot temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; 368352ff8bdSFrançois Tigeot I915_WRITE(MIPI_CTRL(port), temp | 369352ff8bdSFrançois Tigeot intel_dsi->escape_clk_div << 370352ff8bdSFrançois Tigeot ESCAPE_CLOCK_DIVIDER_SHIFT); 371352ff8bdSFrançois Tigeot } 372352ff8bdSFrançois Tigeot 373352ff8bdSFrançois Tigeot /* Program BXT Mipi clocks and dividers */ 3748621f407SFrançois Tigeot static void bxt_dsi_program_clocks(struct drm_device *dev, enum port port, 3758621f407SFrançois Tigeot const struct intel_crtc_state *config) 376352ff8bdSFrançois Tigeot { 377303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 3788621f407SFrançois Tigeot u32 tmp; 3798621f407SFrançois Tigeot u32 dsi_rate = 0; 3808621f407SFrançois Tigeot u32 pll_ratio = 0; 3818621f407SFrançois Tigeot u32 rx_div; 3828621f407SFrançois Tigeot u32 tx_div; 3838621f407SFrançois Tigeot u32 rx_div_upper; 3848621f407SFrançois Tigeot u32 rx_div_lower; 3858621f407SFrançois Tigeot u32 mipi_8by3_divider; 386352ff8bdSFrançois Tigeot 387352ff8bdSFrançois Tigeot /* Clear old configurations */ 388352ff8bdSFrançois Tigeot tmp = I915_READ(BXT_MIPI_CLOCK_CTL); 389352ff8bdSFrançois Tigeot tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port)); 3908621f407SFrançois Tigeot tmp &= ~(BXT_MIPI_RX_ESCLK_UPPER_FIXDIV_MASK(port)); 3918621f407SFrançois Tigeot tmp &= ~(BXT_MIPI_8X_BY3_DIVIDER_MASK(port)); 3928621f407SFrançois Tigeot tmp &= ~(BXT_MIPI_RX_ESCLK_LOWER_FIXDIV_MASK(port)); 393352ff8bdSFrançois Tigeot 394352ff8bdSFrançois Tigeot /* Get the current DSI rate(actual) */ 3958621f407SFrançois Tigeot pll_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK; 396352ff8bdSFrançois Tigeot dsi_rate = (BXT_REF_CLOCK_KHZ * pll_ratio) / 2; 397352ff8bdSFrançois Tigeot 3988621f407SFrançois Tigeot /* 3998621f407SFrançois Tigeot * tx clock should be <= 20MHz and the div value must be 4008621f407SFrançois Tigeot * subtracted by 1 as per bspec 4018621f407SFrançois Tigeot */ 4028621f407SFrançois Tigeot tx_div = DIV_ROUND_UP(dsi_rate, 20000) - 1; 4038621f407SFrançois Tigeot /* 4048621f407SFrançois Tigeot * rx clock should be <= 150MHz and the div value must be 4058621f407SFrançois Tigeot * subtracted by 1 as per bspec 4068621f407SFrançois Tigeot */ 4078621f407SFrançois Tigeot rx_div = DIV_ROUND_UP(dsi_rate, 150000) - 1; 408352ff8bdSFrançois Tigeot 409352ff8bdSFrançois Tigeot /* 4108621f407SFrançois Tigeot * rx divider value needs to be updated in the 4118621f407SFrançois Tigeot * two differnt bit fields in the register hence splitting the 4128621f407SFrançois Tigeot * rx divider value accordingly 413352ff8bdSFrançois Tigeot */ 4148621f407SFrançois Tigeot rx_div_lower = rx_div & RX_DIVIDER_BIT_1_2; 4158621f407SFrançois Tigeot rx_div_upper = (rx_div & RX_DIVIDER_BIT_3_4) >> 2; 416352ff8bdSFrançois Tigeot 4178621f407SFrançois Tigeot /* As per bpsec program the 8/3X clock divider to the below value */ 4188621f407SFrançois Tigeot if (dev_priv->vbt.dsi.config->is_cmd_mode) 4198621f407SFrançois Tigeot mipi_8by3_divider = 0x2; 4208621f407SFrançois Tigeot else 4218621f407SFrançois Tigeot mipi_8by3_divider = 0x3; 4228621f407SFrançois Tigeot 4238621f407SFrançois Tigeot tmp |= BXT_MIPI_8X_BY3_DIVIDER(port, mipi_8by3_divider); 4248621f407SFrançois Tigeot tmp |= BXT_MIPI_TX_ESCLK_DIVIDER(port, tx_div); 4258621f407SFrançois Tigeot tmp |= BXT_MIPI_RX_ESCLK_LOWER_DIVIDER(port, rx_div_lower); 4268621f407SFrançois Tigeot tmp |= BXT_MIPI_RX_ESCLK_UPPER_DIVIDER(port, rx_div_upper); 427352ff8bdSFrançois Tigeot 428352ff8bdSFrançois Tigeot I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp); 429352ff8bdSFrançois Tigeot } 430352ff8bdSFrançois Tigeot 4318621f407SFrançois Tigeot static int bxt_compute_dsi_pll(struct intel_encoder *encoder, 4328621f407SFrançois Tigeot struct intel_crtc_state *config) 433352ff8bdSFrançois Tigeot { 434352ff8bdSFrançois Tigeot struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); 435352ff8bdSFrançois Tigeot u8 dsi_ratio; 436352ff8bdSFrançois Tigeot u32 dsi_clk; 437352ff8bdSFrançois Tigeot 438352ff8bdSFrançois Tigeot dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format, 439352ff8bdSFrançois Tigeot intel_dsi->lane_count); 440352ff8bdSFrançois Tigeot 441352ff8bdSFrançois Tigeot /* 442352ff8bdSFrançois Tigeot * From clock diagram, to get PLL ratio divider, divide double of DSI 443352ff8bdSFrançois Tigeot * link rate (i.e., 2*8x=16x frequency value) by ref clock. Make sure to 444352ff8bdSFrançois Tigeot * round 'up' the result 445352ff8bdSFrançois Tigeot */ 446352ff8bdSFrançois Tigeot dsi_ratio = DIV_ROUND_UP(dsi_clk * 2, BXT_REF_CLOCK_KHZ); 447352ff8bdSFrançois Tigeot if (dsi_ratio < BXT_DSI_PLL_RATIO_MIN || 448352ff8bdSFrançois Tigeot dsi_ratio > BXT_DSI_PLL_RATIO_MAX) { 449352ff8bdSFrançois Tigeot DRM_ERROR("Cant get a suitable ratio from DSI PLL ratios\n"); 4508621f407SFrançois Tigeot return -ECHRNG; 451352ff8bdSFrançois Tigeot } 452352ff8bdSFrançois Tigeot 453352ff8bdSFrançois Tigeot /* 454352ff8bdSFrançois Tigeot * Program DSI ratio and Select MIPIC and MIPIA PLL output as 8x 455352ff8bdSFrançois Tigeot * Spec says both have to be programmed, even if one is not getting 456352ff8bdSFrançois Tigeot * used. Configure MIPI_CLOCK_CTL dividers in modeset 457352ff8bdSFrançois Tigeot */ 4588621f407SFrançois Tigeot config->dsi_pll.ctrl = dsi_ratio | BXT_DSIA_16X_BY2 | BXT_DSIC_16X_BY2; 459352ff8bdSFrançois Tigeot 460352ff8bdSFrançois Tigeot /* As per recommendation from hardware team, 461352ff8bdSFrançois Tigeot * Prog PVD ratio =1 if dsi ratio <= 50 462352ff8bdSFrançois Tigeot */ 4638621f407SFrançois Tigeot if (dsi_ratio <= 50) 4648621f407SFrançois Tigeot config->dsi_pll.ctrl |= BXT_DSI_PLL_PVD_RATIO_1; 4658621f407SFrançois Tigeot 4668621f407SFrançois Tigeot return 0; 467352ff8bdSFrançois Tigeot } 468352ff8bdSFrançois Tigeot 4698621f407SFrançois Tigeot static void bxt_enable_dsi_pll(struct intel_encoder *encoder, 4708621f407SFrançois Tigeot const struct intel_crtc_state *config) 471352ff8bdSFrançois Tigeot { 472303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 473352ff8bdSFrançois Tigeot struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); 474352ff8bdSFrançois Tigeot enum port port; 475352ff8bdSFrançois Tigeot u32 val; 476352ff8bdSFrançois Tigeot 477352ff8bdSFrançois Tigeot DRM_DEBUG_KMS("\n"); 478352ff8bdSFrançois Tigeot 479352ff8bdSFrançois Tigeot /* Configure PLL vales */ 4808621f407SFrançois Tigeot I915_WRITE(BXT_DSI_PLL_CTL, config->dsi_pll.ctrl); 4818621f407SFrançois Tigeot POSTING_READ(BXT_DSI_PLL_CTL); 482352ff8bdSFrançois Tigeot 483352ff8bdSFrançois Tigeot /* Program TX, RX, Dphy clocks */ 484352ff8bdSFrançois Tigeot for_each_dsi_port(port, intel_dsi->ports) 4858621f407SFrançois Tigeot bxt_dsi_program_clocks(encoder->base.dev, port, config); 486352ff8bdSFrançois Tigeot 487352ff8bdSFrançois Tigeot /* Enable DSI PLL */ 488352ff8bdSFrançois Tigeot val = I915_READ(BXT_DSI_PLL_ENABLE); 489352ff8bdSFrançois Tigeot val |= BXT_DSI_PLL_DO_ENABLE; 490352ff8bdSFrançois Tigeot I915_WRITE(BXT_DSI_PLL_ENABLE, val); 491352ff8bdSFrançois Tigeot 492352ff8bdSFrançois Tigeot /* Timeout and fail if PLL not locked */ 4931487f786SFrançois Tigeot if (intel_wait_for_register(dev_priv, 4941487f786SFrançois Tigeot BXT_DSI_PLL_ENABLE, 4951487f786SFrançois Tigeot BXT_DSI_PLL_LOCKED, 4961487f786SFrançois Tigeot BXT_DSI_PLL_LOCKED, 4971487f786SFrançois Tigeot 1)) { 498352ff8bdSFrançois Tigeot DRM_ERROR("Timed out waiting for DSI PLL to lock\n"); 499352ff8bdSFrançois Tigeot return; 500352ff8bdSFrançois Tigeot } 501352ff8bdSFrançois Tigeot 502352ff8bdSFrançois Tigeot DRM_DEBUG_KMS("DSI PLL locked\n"); 503352ff8bdSFrançois Tigeot } 504352ff8bdSFrançois Tigeot 5058621f407SFrançois Tigeot bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv) 5068621f407SFrançois Tigeot { 5078621f407SFrançois Tigeot if (IS_BROXTON(dev_priv)) 5088621f407SFrançois Tigeot return bxt_dsi_pll_is_enabled(dev_priv); 5098621f407SFrançois Tigeot 5108621f407SFrançois Tigeot MISSING_CASE(INTEL_DEVID(dev_priv)); 5118621f407SFrançois Tigeot 5128621f407SFrançois Tigeot return false; 5138621f407SFrançois Tigeot } 5148621f407SFrançois Tigeot 5158621f407SFrançois Tigeot int intel_compute_dsi_pll(struct intel_encoder *encoder, 5168621f407SFrançois Tigeot struct intel_crtc_state *config) 517352ff8bdSFrançois Tigeot { 518*1e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 519352ff8bdSFrançois Tigeot 520*1e12ee3bSFrançois Tigeot if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) 5218621f407SFrançois Tigeot return vlv_compute_dsi_pll(encoder, config); 522*1e12ee3bSFrançois Tigeot else if (IS_BROXTON(dev_priv)) 5238621f407SFrançois Tigeot return bxt_compute_dsi_pll(encoder, config); 5248621f407SFrançois Tigeot 5258621f407SFrançois Tigeot return -ENODEV; 5268621f407SFrançois Tigeot } 5278621f407SFrançois Tigeot 5288621f407SFrançois Tigeot void intel_enable_dsi_pll(struct intel_encoder *encoder, 5298621f407SFrançois Tigeot const struct intel_crtc_state *config) 5308621f407SFrançois Tigeot { 531*1e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 5328621f407SFrançois Tigeot 533*1e12ee3bSFrançois Tigeot if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) 5348621f407SFrançois Tigeot vlv_enable_dsi_pll(encoder, config); 535*1e12ee3bSFrançois Tigeot else if (IS_BROXTON(dev_priv)) 5368621f407SFrançois Tigeot bxt_enable_dsi_pll(encoder, config); 537352ff8bdSFrançois Tigeot } 538352ff8bdSFrançois Tigeot 539352ff8bdSFrançois Tigeot void intel_disable_dsi_pll(struct intel_encoder *encoder) 540352ff8bdSFrançois Tigeot { 541*1e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 542352ff8bdSFrançois Tigeot 543*1e12ee3bSFrançois Tigeot if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) 544352ff8bdSFrançois Tigeot vlv_disable_dsi_pll(encoder); 545*1e12ee3bSFrançois Tigeot else if (IS_BROXTON(dev_priv)) 546352ff8bdSFrançois Tigeot bxt_disable_dsi_pll(encoder); 547352ff8bdSFrançois Tigeot } 548352ff8bdSFrançois Tigeot 549352ff8bdSFrançois Tigeot static void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) 550352ff8bdSFrançois Tigeot { 551352ff8bdSFrançois Tigeot u32 tmp; 552352ff8bdSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 553303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev); 554352ff8bdSFrançois Tigeot 555352ff8bdSFrançois Tigeot /* Clear old configurations */ 556352ff8bdSFrançois Tigeot tmp = I915_READ(BXT_MIPI_CLOCK_CTL); 557352ff8bdSFrançois Tigeot tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port)); 5588621f407SFrançois Tigeot tmp &= ~(BXT_MIPI_RX_ESCLK_UPPER_FIXDIV_MASK(port)); 5598621f407SFrançois Tigeot tmp &= ~(BXT_MIPI_8X_BY3_DIVIDER_MASK(port)); 5608621f407SFrançois Tigeot tmp &= ~(BXT_MIPI_RX_ESCLK_LOWER_FIXDIV_MASK(port)); 561352ff8bdSFrançois Tigeot I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp); 562352ff8bdSFrançois Tigeot I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); 563352ff8bdSFrançois Tigeot } 564352ff8bdSFrançois Tigeot 565352ff8bdSFrançois Tigeot void intel_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) 566352ff8bdSFrançois Tigeot { 567*1e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 568352ff8bdSFrançois Tigeot 569*1e12ee3bSFrançois Tigeot if (IS_BROXTON(dev_priv)) 570352ff8bdSFrançois Tigeot bxt_dsi_reset_clocks(encoder, port); 571*1e12ee3bSFrançois Tigeot else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) 572352ff8bdSFrançois Tigeot vlv_dsi_reset_clocks(encoder, port); 573352ff8bdSFrançois Tigeot } 574