119df918dSFrançois Tigeot /* 219df918dSFrançois Tigeot * Copyright © 2012 Intel Corporation 319df918dSFrançois Tigeot * 419df918dSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 519df918dSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 619df918dSFrançois Tigeot * to deal in the Software without restriction, including without limitation 719df918dSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 819df918dSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 919df918dSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 1019df918dSFrançois Tigeot * 1119df918dSFrançois Tigeot * The above copyright notice and this permission notice (including the next 1219df918dSFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the 1319df918dSFrançois Tigeot * Software. 1419df918dSFrançois Tigeot * 1519df918dSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1619df918dSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1719df918dSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1819df918dSFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1919df918dSFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2019df918dSFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2119df918dSFrançois Tigeot * IN THE SOFTWARE. 2219df918dSFrançois Tigeot * 2319df918dSFrançois Tigeot * Authors: 2419df918dSFrançois Tigeot * Eugeni Dodonov <eugeni.dodonov@intel.com> 2519df918dSFrançois Tigeot * 2619df918dSFrançois Tigeot */ 2719df918dSFrançois Tigeot 2819df918dSFrançois Tigeot #include "i915_drv.h" 2919df918dSFrançois Tigeot #include "intel_drv.h" 301b13d190SFrançois Tigeot #include <asm/int-ll64.h> 311b13d190SFrançois Tigeot 321b13d190SFrançois Tigeot struct ddi_buf_trans { 331b13d190SFrançois Tigeot u32 trans1; /* balance leg enable, de-emph level */ 341b13d190SFrançois Tigeot u32 trans2; /* vref sel, vswing */ 351b13d190SFrançois Tigeot }; 3619df918dSFrançois Tigeot 3719df918dSFrançois Tigeot /* HDMI/DVI modes ignore everything but the last 2 items. So we share 3819df918dSFrançois Tigeot * them for both DP and FDI transports, allowing those ports to 3919df918dSFrançois Tigeot * automatically adapt to HDMI connections as well 4019df918dSFrançois Tigeot */ 411b13d190SFrançois Tigeot static const struct ddi_buf_trans hsw_ddi_translations_dp[] = { 421b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0006000E }, 431b13d190SFrançois Tigeot { 0x00D75FFF, 0x0005000A }, 441b13d190SFrançois Tigeot { 0x00C30FFF, 0x00040006 }, 451b13d190SFrançois Tigeot { 0x80AAAFFF, 0x000B0000 }, 461b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0005000A }, 471b13d190SFrançois Tigeot { 0x00D75FFF, 0x000C0004 }, 481b13d190SFrançois Tigeot { 0x80C30FFF, 0x000B0000 }, 491b13d190SFrançois Tigeot { 0x00FFFFFF, 0x00040006 }, 501b13d190SFrançois Tigeot { 0x80D75FFF, 0x000B0000 }, 5119df918dSFrançois Tigeot }; 5219df918dSFrançois Tigeot 531b13d190SFrançois Tigeot static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = { 541b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0007000E }, 551b13d190SFrançois Tigeot { 0x00D75FFF, 0x000F000A }, 561b13d190SFrançois Tigeot { 0x00C30FFF, 0x00060006 }, 571b13d190SFrançois Tigeot { 0x00AAAFFF, 0x001E0000 }, 581b13d190SFrançois Tigeot { 0x00FFFFFF, 0x000F000A }, 591b13d190SFrançois Tigeot { 0x00D75FFF, 0x00160004 }, 601b13d190SFrançois Tigeot { 0x00C30FFF, 0x001E0000 }, 611b13d190SFrançois Tigeot { 0x00FFFFFF, 0x00060006 }, 621b13d190SFrançois Tigeot { 0x00D75FFF, 0x001E0000 }, 6319df918dSFrançois Tigeot }; 6419df918dSFrançois Tigeot 651b13d190SFrançois Tigeot static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = { 661b13d190SFrançois Tigeot /* Idx NT mV d T mV d db */ 671b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0006000E }, /* 0: 400 400 0 */ 681b13d190SFrançois Tigeot { 0x00E79FFF, 0x000E000C }, /* 1: 400 500 2 */ 691b13d190SFrançois Tigeot { 0x00D75FFF, 0x0005000A }, /* 2: 400 600 3.5 */ 701b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0005000A }, /* 3: 600 600 0 */ 711b13d190SFrançois Tigeot { 0x00E79FFF, 0x001D0007 }, /* 4: 600 750 2 */ 721b13d190SFrançois Tigeot { 0x00D75FFF, 0x000C0004 }, /* 5: 600 900 3.5 */ 731b13d190SFrançois Tigeot { 0x00FFFFFF, 0x00040006 }, /* 6: 800 800 0 */ 741b13d190SFrançois Tigeot { 0x80E79FFF, 0x00030002 }, /* 7: 800 1000 2 */ 751b13d190SFrançois Tigeot { 0x00FFFFFF, 0x00140005 }, /* 8: 850 850 0 */ 761b13d190SFrançois Tigeot { 0x00FFFFFF, 0x000C0004 }, /* 9: 900 900 0 */ 771b13d190SFrançois Tigeot { 0x00FFFFFF, 0x001C0003 }, /* 10: 950 950 0 */ 781b13d190SFrançois Tigeot { 0x80FFFFFF, 0x00030002 }, /* 11: 1000 1000 0 */ 799edbd4a0SFrançois Tigeot }; 809edbd4a0SFrançois Tigeot 811b13d190SFrançois Tigeot static const struct ddi_buf_trans bdw_ddi_translations_edp[] = { 821b13d190SFrançois Tigeot { 0x00FFFFFF, 0x00000012 }, 831b13d190SFrançois Tigeot { 0x00EBAFFF, 0x00020011 }, 841b13d190SFrançois Tigeot { 0x00C71FFF, 0x0006000F }, 851b13d190SFrançois Tigeot { 0x00AAAFFF, 0x000E000A }, 861b13d190SFrançois Tigeot { 0x00FFFFFF, 0x00020011 }, 871b13d190SFrançois Tigeot { 0x00DB6FFF, 0x0005000F }, 881b13d190SFrançois Tigeot { 0x00BEEFFF, 0x000A000C }, 891b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0005000F }, 901b13d190SFrançois Tigeot { 0x00DB6FFF, 0x000A000C }, 919edbd4a0SFrançois Tigeot }; 929edbd4a0SFrançois Tigeot 931b13d190SFrançois Tigeot static const struct ddi_buf_trans bdw_ddi_translations_dp[] = { 941b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0007000E }, 951b13d190SFrançois Tigeot { 0x00D75FFF, 0x000E000A }, 961b13d190SFrançois Tigeot { 0x00BEFFFF, 0x00140006 }, 971b13d190SFrançois Tigeot { 0x80B2CFFF, 0x001B0002 }, 981b13d190SFrançois Tigeot { 0x00FFFFFF, 0x000E000A }, 992c9916cdSFrançois Tigeot { 0x00DB6FFF, 0x00160005 }, 1002c9916cdSFrançois Tigeot { 0x80C71FFF, 0x001A0002 }, 1011b13d190SFrançois Tigeot { 0x00F7DFFF, 0x00180004 }, 1021b13d190SFrançois Tigeot { 0x80D75FFF, 0x001B0002 }, 1039edbd4a0SFrançois Tigeot }; 1049edbd4a0SFrançois Tigeot 1051b13d190SFrançois Tigeot static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = { 1061b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0001000E }, 1071b13d190SFrançois Tigeot { 0x00D75FFF, 0x0004000A }, 1081b13d190SFrançois Tigeot { 0x00C30FFF, 0x00070006 }, 1091b13d190SFrançois Tigeot { 0x00AAAFFF, 0x000C0000 }, 1101b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0004000A }, 1111b13d190SFrançois Tigeot { 0x00D75FFF, 0x00090004 }, 1121b13d190SFrançois Tigeot { 0x00C30FFF, 0x000C0000 }, 1131b13d190SFrançois Tigeot { 0x00FFFFFF, 0x00070006 }, 1141b13d190SFrançois Tigeot { 0x00D75FFF, 0x000C0000 }, 1151b13d190SFrançois Tigeot }; 1161b13d190SFrançois Tigeot 1171b13d190SFrançois Tigeot static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = { 1181b13d190SFrançois Tigeot /* Idx NT mV d T mV df db */ 1191b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0007000E }, /* 0: 400 400 0 */ 1201b13d190SFrançois Tigeot { 0x00D75FFF, 0x000E000A }, /* 1: 400 600 3.5 */ 1211b13d190SFrançois Tigeot { 0x00BEFFFF, 0x00140006 }, /* 2: 400 800 6 */ 1221b13d190SFrançois Tigeot { 0x00FFFFFF, 0x0009000D }, /* 3: 450 450 0 */ 1231b13d190SFrançois Tigeot { 0x00FFFFFF, 0x000E000A }, /* 4: 600 600 0 */ 1241b13d190SFrançois Tigeot { 0x00D7FFFF, 0x00140006 }, /* 5: 600 800 2.5 */ 1251b13d190SFrançois Tigeot { 0x80CB2FFF, 0x001B0002 }, /* 6: 600 1000 4.5 */ 1261b13d190SFrançois Tigeot { 0x00FFFFFF, 0x00140006 }, /* 7: 800 800 0 */ 1271b13d190SFrançois Tigeot { 0x80E79FFF, 0x001B0002 }, /* 8: 800 1000 2 */ 1281b13d190SFrançois Tigeot { 0x80FFFFFF, 0x001B0002 }, /* 9: 1000 1000 0 */ 1299edbd4a0SFrançois Tigeot }; 1309edbd4a0SFrançois Tigeot 1312c9916cdSFrançois Tigeot static const struct ddi_buf_trans skl_ddi_translations_dp[] = { 1322c9916cdSFrançois Tigeot { 0x00000018, 0x000000a2 }, 1332c9916cdSFrançois Tigeot { 0x00004014, 0x0000009B }, 1342c9916cdSFrançois Tigeot { 0x00006012, 0x00000088 }, 1352c9916cdSFrançois Tigeot { 0x00008010, 0x00000087 }, 1362c9916cdSFrançois Tigeot { 0x00000018, 0x0000009B }, 1372c9916cdSFrançois Tigeot { 0x00004014, 0x00000088 }, 1382c9916cdSFrançois Tigeot { 0x00006012, 0x00000087 }, 1392c9916cdSFrançois Tigeot { 0x00000018, 0x00000088 }, 1402c9916cdSFrançois Tigeot { 0x00004014, 0x00000087 }, 1412c9916cdSFrançois Tigeot }; 1422c9916cdSFrançois Tigeot 143*477eb7f9SFrançois Tigeot /* eDP 1.4 low vswing translation parameters */ 144*477eb7f9SFrançois Tigeot static const struct ddi_buf_trans skl_ddi_translations_edp[] = { 145*477eb7f9SFrançois Tigeot { 0x00000018, 0x000000a8 }, 146*477eb7f9SFrançois Tigeot { 0x00002016, 0x000000ab }, 147*477eb7f9SFrançois Tigeot { 0x00006012, 0x000000a2 }, 148*477eb7f9SFrançois Tigeot { 0x00008010, 0x00000088 }, 149*477eb7f9SFrançois Tigeot { 0x00000018, 0x000000ab }, 150*477eb7f9SFrançois Tigeot { 0x00004014, 0x000000a2 }, 151*477eb7f9SFrançois Tigeot { 0x00006012, 0x000000a6 }, 152*477eb7f9SFrançois Tigeot { 0x00000018, 0x000000a2 }, 153*477eb7f9SFrançois Tigeot { 0x00005013, 0x0000009c }, 154*477eb7f9SFrançois Tigeot { 0x00000018, 0x00000088 }, 155*477eb7f9SFrançois Tigeot }; 156*477eb7f9SFrançois Tigeot 157*477eb7f9SFrançois Tigeot 1582c9916cdSFrançois Tigeot static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { 1592c9916cdSFrançois Tigeot /* Idx NT mV T mV db */ 160*477eb7f9SFrançois Tigeot { 0x00004014, 0x00000087 }, /* 0: 800 1000 2 */ 1612c9916cdSFrançois Tigeot }; 1622c9916cdSFrançois Tigeot 1639edbd4a0SFrançois Tigeot enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) 16419df918dSFrançois Tigeot { 16519df918dSFrançois Tigeot struct drm_encoder *encoder = &intel_encoder->base; 16619df918dSFrançois Tigeot int type = intel_encoder->type; 16719df918dSFrançois Tigeot 1682c9916cdSFrançois Tigeot if (type == INTEL_OUTPUT_DP_MST) { 1692c9916cdSFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_mst(encoder)->primary; 1702c9916cdSFrançois Tigeot return intel_dig_port->port; 1712c9916cdSFrançois Tigeot } else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || 17219df918dSFrançois Tigeot type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) { 17319df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = 17419df918dSFrançois Tigeot enc_to_dig_port(encoder); 17519df918dSFrançois Tigeot return intel_dig_port->port; 17619df918dSFrançois Tigeot 17719df918dSFrançois Tigeot } else if (type == INTEL_OUTPUT_ANALOG) { 17819df918dSFrançois Tigeot return PORT_E; 17919df918dSFrançois Tigeot 18019df918dSFrançois Tigeot } else { 18119df918dSFrançois Tigeot DRM_ERROR("Invalid DDI encoder type %d\n", type); 18219df918dSFrançois Tigeot BUG(); 18319df918dSFrançois Tigeot } 18419df918dSFrançois Tigeot } 18519df918dSFrançois Tigeot 1869edbd4a0SFrançois Tigeot /* 1879edbd4a0SFrançois Tigeot * Starting with Haswell, DDI port buffers must be programmed with correct 1889edbd4a0SFrançois Tigeot * values in advance. The buffer values are different for FDI and DP modes, 18919df918dSFrançois Tigeot * but the HDMI/DVI fields are shared among those. So we program the DDI 19019df918dSFrançois Tigeot * in either FDI or DP modes only, as HDMI connections will work with both 19119df918dSFrançois Tigeot * of those 19219df918dSFrançois Tigeot */ 1939edbd4a0SFrançois Tigeot static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) 19419df918dSFrançois Tigeot { 19519df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 19619df918dSFrançois Tigeot u32 reg; 197*477eb7f9SFrançois Tigeot int i, n_hdmi_entries, n_dp_entries, n_edp_entries, hdmi_default_entry, 198*477eb7f9SFrançois Tigeot size; 1999edbd4a0SFrançois Tigeot int hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift; 2001b13d190SFrançois Tigeot const struct ddi_buf_trans *ddi_translations_fdi; 2011b13d190SFrançois Tigeot const struct ddi_buf_trans *ddi_translations_dp; 2021b13d190SFrançois Tigeot const struct ddi_buf_trans *ddi_translations_edp; 2031b13d190SFrançois Tigeot const struct ddi_buf_trans *ddi_translations_hdmi; 2041b13d190SFrançois Tigeot const struct ddi_buf_trans *ddi_translations; 20519df918dSFrançois Tigeot 2062c9916cdSFrançois Tigeot if (IS_SKYLAKE(dev)) { 2072c9916cdSFrançois Tigeot ddi_translations_fdi = NULL; 2082c9916cdSFrançois Tigeot ddi_translations_dp = skl_ddi_translations_dp; 209*477eb7f9SFrançois Tigeot n_dp_entries = ARRAY_SIZE(skl_ddi_translations_dp); 210*477eb7f9SFrançois Tigeot if (dev_priv->vbt.edp_low_vswing) { 211*477eb7f9SFrançois Tigeot ddi_translations_edp = skl_ddi_translations_edp; 212*477eb7f9SFrançois Tigeot n_edp_entries = ARRAY_SIZE(skl_ddi_translations_edp); 213*477eb7f9SFrançois Tigeot } else { 2142c9916cdSFrançois Tigeot ddi_translations_edp = skl_ddi_translations_dp; 215*477eb7f9SFrançois Tigeot n_edp_entries = ARRAY_SIZE(skl_ddi_translations_dp); 216*477eb7f9SFrançois Tigeot } 217*477eb7f9SFrançois Tigeot 218*477eb7f9SFrançois Tigeot /* 219*477eb7f9SFrançois Tigeot * On SKL, the recommendation from the hw team is to always use 220*477eb7f9SFrançois Tigeot * a certain type of level shifter (and thus the corresponding 221*477eb7f9SFrançois Tigeot * 800mV+2dB entry). Given that's the only validated entry, we 222*477eb7f9SFrançois Tigeot * override what is in the VBT, at least until further notice. 223*477eb7f9SFrançois Tigeot */ 224*477eb7f9SFrançois Tigeot hdmi_level = 0; 2252c9916cdSFrançois Tigeot ddi_translations_hdmi = skl_ddi_translations_hdmi; 2262c9916cdSFrançois Tigeot n_hdmi_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); 227*477eb7f9SFrançois Tigeot hdmi_default_entry = 0; 2282c9916cdSFrançois Tigeot } else if (IS_BROADWELL(dev)) { 2299edbd4a0SFrançois Tigeot ddi_translations_fdi = bdw_ddi_translations_fdi; 2309edbd4a0SFrançois Tigeot ddi_translations_dp = bdw_ddi_translations_dp; 2319edbd4a0SFrançois Tigeot ddi_translations_edp = bdw_ddi_translations_edp; 2321b13d190SFrançois Tigeot ddi_translations_hdmi = bdw_ddi_translations_hdmi; 233*477eb7f9SFrançois Tigeot n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp); 234*477eb7f9SFrançois Tigeot n_dp_entries = ARRAY_SIZE(bdw_ddi_translations_dp); 2351b13d190SFrançois Tigeot n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); 236*477eb7f9SFrançois Tigeot hdmi_default_entry = 7; 2379edbd4a0SFrançois Tigeot } else if (IS_HASWELL(dev)) { 2389edbd4a0SFrançois Tigeot ddi_translations_fdi = hsw_ddi_translations_fdi; 2399edbd4a0SFrançois Tigeot ddi_translations_dp = hsw_ddi_translations_dp; 2409edbd4a0SFrançois Tigeot ddi_translations_edp = hsw_ddi_translations_dp; 2411b13d190SFrançois Tigeot ddi_translations_hdmi = hsw_ddi_translations_hdmi; 242*477eb7f9SFrançois Tigeot n_dp_entries = n_edp_entries = ARRAY_SIZE(hsw_ddi_translations_dp); 2431b13d190SFrançois Tigeot n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); 244*477eb7f9SFrançois Tigeot hdmi_default_entry = 6; 2459edbd4a0SFrançois Tigeot } else { 2469edbd4a0SFrançois Tigeot WARN(1, "ddi translation table missing\n"); 2479edbd4a0SFrançois Tigeot ddi_translations_edp = bdw_ddi_translations_dp; 2489edbd4a0SFrançois Tigeot ddi_translations_fdi = bdw_ddi_translations_fdi; 2499edbd4a0SFrançois Tigeot ddi_translations_dp = bdw_ddi_translations_dp; 2501b13d190SFrançois Tigeot ddi_translations_hdmi = bdw_ddi_translations_hdmi; 251*477eb7f9SFrançois Tigeot n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp); 252*477eb7f9SFrançois Tigeot n_dp_entries = ARRAY_SIZE(bdw_ddi_translations_dp); 2531b13d190SFrançois Tigeot n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); 254*477eb7f9SFrançois Tigeot hdmi_default_entry = 7; 2559edbd4a0SFrançois Tigeot } 25619df918dSFrançois Tigeot 2579edbd4a0SFrançois Tigeot switch (port) { 2589edbd4a0SFrançois Tigeot case PORT_A: 2599edbd4a0SFrançois Tigeot ddi_translations = ddi_translations_edp; 260*477eb7f9SFrançois Tigeot size = n_edp_entries; 2619edbd4a0SFrançois Tigeot break; 2629edbd4a0SFrançois Tigeot case PORT_B: 2639edbd4a0SFrançois Tigeot case PORT_C: 2649edbd4a0SFrançois Tigeot ddi_translations = ddi_translations_dp; 265*477eb7f9SFrançois Tigeot size = n_dp_entries; 2669edbd4a0SFrançois Tigeot break; 2679edbd4a0SFrançois Tigeot case PORT_D: 268*477eb7f9SFrançois Tigeot if (intel_dp_is_edp(dev, PORT_D)) { 2699edbd4a0SFrançois Tigeot ddi_translations = ddi_translations_edp; 270*477eb7f9SFrançois Tigeot size = n_edp_entries; 271*477eb7f9SFrançois Tigeot } else { 2729edbd4a0SFrançois Tigeot ddi_translations = ddi_translations_dp; 273*477eb7f9SFrançois Tigeot size = n_dp_entries; 274*477eb7f9SFrançois Tigeot } 2759edbd4a0SFrançois Tigeot break; 2769edbd4a0SFrançois Tigeot case PORT_E: 2772c9916cdSFrançois Tigeot if (ddi_translations_fdi) 2789edbd4a0SFrançois Tigeot ddi_translations = ddi_translations_fdi; 2792c9916cdSFrançois Tigeot else 2802c9916cdSFrançois Tigeot ddi_translations = ddi_translations_dp; 281*477eb7f9SFrançois Tigeot size = n_dp_entries; 2829edbd4a0SFrançois Tigeot break; 2839edbd4a0SFrançois Tigeot default: 2849edbd4a0SFrançois Tigeot BUG(); 2859edbd4a0SFrançois Tigeot } 28619df918dSFrançois Tigeot 287*477eb7f9SFrançois Tigeot for (i = 0, reg = DDI_BUF_TRANS(port); i < size; i++) { 2881b13d190SFrançois Tigeot I915_WRITE(reg, ddi_translations[i].trans1); 2891b13d190SFrançois Tigeot reg += 4; 2901b13d190SFrançois Tigeot I915_WRITE(reg, ddi_translations[i].trans2); 29119df918dSFrançois Tigeot reg += 4; 29219df918dSFrançois Tigeot } 2931b13d190SFrançois Tigeot 2941b13d190SFrançois Tigeot /* Choose a good default if VBT is badly populated */ 2951b13d190SFrançois Tigeot if (hdmi_level == HDMI_LEVEL_SHIFT_UNKNOWN || 2961b13d190SFrançois Tigeot hdmi_level >= n_hdmi_entries) 297*477eb7f9SFrançois Tigeot hdmi_level = hdmi_default_entry; 2981b13d190SFrançois Tigeot 2999edbd4a0SFrançois Tigeot /* Entry 9 is for HDMI: */ 3001b13d190SFrançois Tigeot I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans1); 3019edbd4a0SFrançois Tigeot reg += 4; 3021b13d190SFrançois Tigeot I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans2); 3031b13d190SFrançois Tigeot reg += 4; 30419df918dSFrançois Tigeot } 30519df918dSFrançois Tigeot 30619df918dSFrançois Tigeot /* Program DDI buffers translations for DP. By default, program ports A-D in DP 30719df918dSFrançois Tigeot * mode and port E for FDI. 30819df918dSFrançois Tigeot */ 30919df918dSFrançois Tigeot void intel_prepare_ddi(struct drm_device *dev) 31019df918dSFrançois Tigeot { 31119df918dSFrançois Tigeot int port; 31219df918dSFrançois Tigeot 313a2fdbec6SFrançois Tigeot if (!HAS_DDI(dev)) 314a2fdbec6SFrançois Tigeot return; 315a2fdbec6SFrançois Tigeot 3169edbd4a0SFrançois Tigeot for (port = PORT_A; port <= PORT_E; port++) 3179edbd4a0SFrançois Tigeot intel_prepare_ddi_buffers(dev, port); 31819df918dSFrançois Tigeot } 31919df918dSFrançois Tigeot 32019df918dSFrançois Tigeot static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, 32119df918dSFrançois Tigeot enum port port) 32219df918dSFrançois Tigeot { 32319df918dSFrançois Tigeot uint32_t reg = DDI_BUF_CTL(port); 32419df918dSFrançois Tigeot int i; 32519df918dSFrançois Tigeot 32619df918dSFrançois Tigeot for (i = 0; i < 8; i++) { 32719df918dSFrançois Tigeot udelay(1); 32819df918dSFrançois Tigeot if (I915_READ(reg) & DDI_BUF_IS_IDLE) 32919df918dSFrançois Tigeot return; 33019df918dSFrançois Tigeot } 33119df918dSFrançois Tigeot DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port)); 33219df918dSFrançois Tigeot } 33319df918dSFrançois Tigeot 33419df918dSFrançois Tigeot /* Starting with Haswell, different DDI ports can work in FDI mode for 33519df918dSFrançois Tigeot * connection to the PCH-located connectors. For this, it is necessary to train 33619df918dSFrançois Tigeot * both the DDI port and PCH receiver for the desired DDI buffer settings. 33719df918dSFrançois Tigeot * 33819df918dSFrançois Tigeot * The recommended port to work in FDI mode is DDI E, which we use here. Also, 33919df918dSFrançois Tigeot * please note that when FDI mode is active on DDI E, it shares 2 lines with 34019df918dSFrançois Tigeot * DDI A (which is used for eDP) 34119df918dSFrançois Tigeot */ 34219df918dSFrançois Tigeot 34319df918dSFrançois Tigeot void hsw_fdi_link_train(struct drm_crtc *crtc) 34419df918dSFrançois Tigeot { 34519df918dSFrançois Tigeot struct drm_device *dev = crtc->dev; 34619df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 34719df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 34819df918dSFrançois Tigeot u32 temp, i, rx_ctl_val; 34919df918dSFrançois Tigeot 35019df918dSFrançois Tigeot /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the 35119df918dSFrançois Tigeot * mode set "sequence for CRT port" document: 35219df918dSFrançois Tigeot * - TP1 to TP2 time with the default value 35319df918dSFrançois Tigeot * - FDI delay to 90h 3545d0b1887SFrançois Tigeot * 3555d0b1887SFrançois Tigeot * WaFDIAutoLinkSetTimingOverrride:hsw 35619df918dSFrançois Tigeot */ 35719df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) | 35819df918dSFrançois Tigeot FDI_RX_PWRDN_LANE0_VAL(2) | 35919df918dSFrançois Tigeot FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); 36019df918dSFrançois Tigeot 36119df918dSFrançois Tigeot /* Enable the PCH Receiver FDI PLL */ 36219df918dSFrançois Tigeot rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | 3635d0b1887SFrançois Tigeot FDI_RX_PLL_ENABLE | 3642c9916cdSFrançois Tigeot FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes); 36519df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); 36619df918dSFrançois Tigeot POSTING_READ(_FDI_RXA_CTL); 36719df918dSFrançois Tigeot udelay(220); 36819df918dSFrançois Tigeot 36919df918dSFrançois Tigeot /* Switch from Rawclk to PCDclk */ 37019df918dSFrançois Tigeot rx_ctl_val |= FDI_PCDCLK; 37119df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); 37219df918dSFrançois Tigeot 37319df918dSFrançois Tigeot /* Configure Port Clock Select */ 3742c9916cdSFrançois Tigeot I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel); 3752c9916cdSFrançois Tigeot WARN_ON(intel_crtc->config->ddi_pll_sel != PORT_CLK_SEL_SPLL); 37619df918dSFrançois Tigeot 37719df918dSFrançois Tigeot /* Start the training iterating through available voltages and emphasis, 37819df918dSFrançois Tigeot * testing each value twice. */ 3791b13d190SFrançois Tigeot for (i = 0; i < ARRAY_SIZE(hsw_ddi_translations_fdi) * 2; i++) { 38019df918dSFrançois Tigeot /* Configure DP_TP_CTL with auto-training */ 38119df918dSFrançois Tigeot I915_WRITE(DP_TP_CTL(PORT_E), 38219df918dSFrançois Tigeot DP_TP_CTL_FDI_AUTOTRAIN | 38319df918dSFrançois Tigeot DP_TP_CTL_ENHANCED_FRAME_ENABLE | 38419df918dSFrançois Tigeot DP_TP_CTL_LINK_TRAIN_PAT1 | 38519df918dSFrançois Tigeot DP_TP_CTL_ENABLE); 38619df918dSFrançois Tigeot 38719df918dSFrançois Tigeot /* Configure and enable DDI_BUF_CTL for DDI E with next voltage. 38819df918dSFrançois Tigeot * DDI E does not support port reversal, the functionality is 38919df918dSFrançois Tigeot * achieved on the PCH side in FDI_RX_CTL, so no need to set the 39019df918dSFrançois Tigeot * port reversal bit */ 39119df918dSFrançois Tigeot I915_WRITE(DDI_BUF_CTL(PORT_E), 39219df918dSFrançois Tigeot DDI_BUF_CTL_ENABLE | 3932c9916cdSFrançois Tigeot ((intel_crtc->config->fdi_lanes - 1) << 1) | 3941b13d190SFrançois Tigeot DDI_BUF_TRANS_SELECT(i / 2)); 39519df918dSFrançois Tigeot POSTING_READ(DDI_BUF_CTL(PORT_E)); 39619df918dSFrançois Tigeot 39719df918dSFrançois Tigeot udelay(600); 39819df918dSFrançois Tigeot 39919df918dSFrançois Tigeot /* Program PCH FDI Receiver TU */ 40019df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_TUSIZE1, TU_SIZE(64)); 40119df918dSFrançois Tigeot 40219df918dSFrançois Tigeot /* Enable PCH FDI Receiver with auto-training */ 40319df918dSFrançois Tigeot rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO; 40419df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); 40519df918dSFrançois Tigeot POSTING_READ(_FDI_RXA_CTL); 40619df918dSFrançois Tigeot 40719df918dSFrançois Tigeot /* Wait for FDI receiver lane calibration */ 40819df918dSFrançois Tigeot udelay(30); 40919df918dSFrançois Tigeot 41019df918dSFrançois Tigeot /* Unset FDI_RX_MISC pwrdn lanes */ 41119df918dSFrançois Tigeot temp = I915_READ(_FDI_RXA_MISC); 41219df918dSFrançois Tigeot temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); 41319df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_MISC, temp); 41419df918dSFrançois Tigeot POSTING_READ(_FDI_RXA_MISC); 41519df918dSFrançois Tigeot 41619df918dSFrançois Tigeot /* Wait for FDI auto training time */ 41719df918dSFrançois Tigeot udelay(5); 41819df918dSFrançois Tigeot 41919df918dSFrançois Tigeot temp = I915_READ(DP_TP_STATUS(PORT_E)); 42019df918dSFrançois Tigeot if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) { 42119df918dSFrançois Tigeot DRM_DEBUG_KMS("FDI link training done on step %d\n", i); 42219df918dSFrançois Tigeot 42319df918dSFrançois Tigeot /* Enable normal pixel sending for FDI */ 42419df918dSFrançois Tigeot I915_WRITE(DP_TP_CTL(PORT_E), 42519df918dSFrançois Tigeot DP_TP_CTL_FDI_AUTOTRAIN | 42619df918dSFrançois Tigeot DP_TP_CTL_LINK_TRAIN_NORMAL | 42719df918dSFrançois Tigeot DP_TP_CTL_ENHANCED_FRAME_ENABLE | 42819df918dSFrançois Tigeot DP_TP_CTL_ENABLE); 42919df918dSFrançois Tigeot 43019df918dSFrançois Tigeot return; 43119df918dSFrançois Tigeot } 43219df918dSFrançois Tigeot 43319df918dSFrançois Tigeot temp = I915_READ(DDI_BUF_CTL(PORT_E)); 43419df918dSFrançois Tigeot temp &= ~DDI_BUF_CTL_ENABLE; 43519df918dSFrançois Tigeot I915_WRITE(DDI_BUF_CTL(PORT_E), temp); 43619df918dSFrançois Tigeot POSTING_READ(DDI_BUF_CTL(PORT_E)); 43719df918dSFrançois Tigeot 43819df918dSFrançois Tigeot /* Disable DP_TP_CTL and FDI_RX_CTL and retry */ 43919df918dSFrançois Tigeot temp = I915_READ(DP_TP_CTL(PORT_E)); 44019df918dSFrançois Tigeot temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); 44119df918dSFrançois Tigeot temp |= DP_TP_CTL_LINK_TRAIN_PAT1; 44219df918dSFrançois Tigeot I915_WRITE(DP_TP_CTL(PORT_E), temp); 44319df918dSFrançois Tigeot POSTING_READ(DP_TP_CTL(PORT_E)); 44419df918dSFrançois Tigeot 44519df918dSFrançois Tigeot intel_wait_ddi_buf_idle(dev_priv, PORT_E); 44619df918dSFrançois Tigeot 44719df918dSFrançois Tigeot rx_ctl_val &= ~FDI_RX_ENABLE; 44819df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); 44919df918dSFrançois Tigeot POSTING_READ(_FDI_RXA_CTL); 45019df918dSFrançois Tigeot 45119df918dSFrançois Tigeot /* Reset FDI_RX_MISC pwrdn lanes */ 45219df918dSFrançois Tigeot temp = I915_READ(_FDI_RXA_MISC); 45319df918dSFrançois Tigeot temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); 45419df918dSFrançois Tigeot temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); 45519df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_MISC, temp); 45619df918dSFrançois Tigeot POSTING_READ(_FDI_RXA_MISC); 45719df918dSFrançois Tigeot } 45819df918dSFrançois Tigeot 45919df918dSFrançois Tigeot DRM_ERROR("FDI link training failed!\n"); 46019df918dSFrançois Tigeot } 46119df918dSFrançois Tigeot 4621b13d190SFrançois Tigeot void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder) 4631b13d190SFrançois Tigeot { 4641b13d190SFrançois Tigeot struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); 4651b13d190SFrançois Tigeot struct intel_digital_port *intel_dig_port = 4661b13d190SFrançois Tigeot enc_to_dig_port(&encoder->base); 4671b13d190SFrançois Tigeot 4681b13d190SFrançois Tigeot intel_dp->DP = intel_dig_port->saved_port_bits | 4691b13d190SFrançois Tigeot DDI_BUF_CTL_ENABLE | DDI_BUF_TRANS_SELECT(0); 4701b13d190SFrançois Tigeot intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count); 4711b13d190SFrançois Tigeot 4721b13d190SFrançois Tigeot } 4731b13d190SFrançois Tigeot 47419df918dSFrançois Tigeot static struct intel_encoder * 47519df918dSFrançois Tigeot intel_ddi_get_crtc_encoder(struct drm_crtc *crtc) 47619df918dSFrançois Tigeot { 47719df918dSFrançois Tigeot struct drm_device *dev = crtc->dev; 47819df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 47919df918dSFrançois Tigeot struct intel_encoder *intel_encoder, *ret = NULL; 48019df918dSFrançois Tigeot int num_encoders = 0; 48119df918dSFrançois Tigeot 48219df918dSFrançois Tigeot for_each_encoder_on_crtc(dev, crtc, intel_encoder) { 48319df918dSFrançois Tigeot ret = intel_encoder; 48419df918dSFrançois Tigeot num_encoders++; 48519df918dSFrançois Tigeot } 48619df918dSFrançois Tigeot 48719df918dSFrançois Tigeot if (num_encoders != 1) 4885d0b1887SFrançois Tigeot WARN(1, "%d encoders on crtc for pipe %c\n", num_encoders, 4895d0b1887SFrançois Tigeot pipe_name(intel_crtc->pipe)); 49019df918dSFrançois Tigeot 49119df918dSFrançois Tigeot BUG_ON(ret == NULL); 49219df918dSFrançois Tigeot return ret; 49319df918dSFrançois Tigeot } 49419df918dSFrançois Tigeot 4952c9916cdSFrançois Tigeot static struct intel_encoder * 496*477eb7f9SFrançois Tigeot intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state) 4972c9916cdSFrançois Tigeot { 498*477eb7f9SFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); 499*477eb7f9SFrançois Tigeot struct intel_encoder *ret = NULL; 500*477eb7f9SFrançois Tigeot struct drm_atomic_state *state; 5012c9916cdSFrançois Tigeot int num_encoders = 0; 502*477eb7f9SFrançois Tigeot int i; 5032c9916cdSFrançois Tigeot 504*477eb7f9SFrançois Tigeot state = crtc_state->base.state; 505*477eb7f9SFrançois Tigeot 506*477eb7f9SFrançois Tigeot for (i = 0; i < state->num_connector; i++) { 507*477eb7f9SFrançois Tigeot if (!state->connectors[i] || 508*477eb7f9SFrançois Tigeot state->connector_states[i]->crtc != crtc_state->base.crtc) 509*477eb7f9SFrançois Tigeot continue; 510*477eb7f9SFrançois Tigeot 511*477eb7f9SFrançois Tigeot ret = to_intel_encoder(state->connector_states[i]->best_encoder); 5122c9916cdSFrançois Tigeot num_encoders++; 5132c9916cdSFrançois Tigeot } 5142c9916cdSFrançois Tigeot 5152c9916cdSFrançois Tigeot WARN(num_encoders != 1, "%d encoders on crtc for pipe %c\n", num_encoders, 5162c9916cdSFrançois Tigeot pipe_name(crtc->pipe)); 5172c9916cdSFrançois Tigeot 5182c9916cdSFrançois Tigeot BUG_ON(ret == NULL); 5192c9916cdSFrançois Tigeot return ret; 5202c9916cdSFrançois Tigeot } 5212c9916cdSFrançois Tigeot 5225d0b1887SFrançois Tigeot #define LC_FREQ 2700 5231b13d190SFrançois Tigeot #define LC_FREQ_2K U64_C(LC_FREQ * 2000) 5245d0b1887SFrançois Tigeot 5255d0b1887SFrançois Tigeot #define P_MIN 2 5265d0b1887SFrançois Tigeot #define P_MAX 64 5275d0b1887SFrançois Tigeot #define P_INC 2 5285d0b1887SFrançois Tigeot 5295d0b1887SFrançois Tigeot /* Constraints for PLL good behavior */ 5305d0b1887SFrançois Tigeot #define REF_MIN 48 5315d0b1887SFrançois Tigeot #define REF_MAX 400 5325d0b1887SFrançois Tigeot #define VCO_MIN 2400 5335d0b1887SFrançois Tigeot #define VCO_MAX 4800 5345d0b1887SFrançois Tigeot 5351b13d190SFrançois Tigeot #define abs_diff(a, b) ({ \ 5361b13d190SFrançois Tigeot typeof(a) __a = (a); \ 5371b13d190SFrançois Tigeot typeof(b) __b = (b); \ 5381b13d190SFrançois Tigeot (void) (&__a == &__b); \ 5391b13d190SFrançois Tigeot __a > __b ? (__a - __b) : (__b - __a); }) 5405d0b1887SFrançois Tigeot 5415d0b1887SFrançois Tigeot struct wrpll_rnp { 5425d0b1887SFrançois Tigeot unsigned p, n2, r2; 5435d0b1887SFrançois Tigeot }; 5445d0b1887SFrançois Tigeot 5455d0b1887SFrançois Tigeot static unsigned wrpll_get_budget_for_freq(int clock) 54619df918dSFrançois Tigeot { 5475d0b1887SFrançois Tigeot unsigned budget; 54819df918dSFrançois Tigeot 5495d0b1887SFrançois Tigeot switch (clock) { 5505d0b1887SFrançois Tigeot case 25175000: 5515d0b1887SFrançois Tigeot case 25200000: 5525d0b1887SFrançois Tigeot case 27000000: 5535d0b1887SFrançois Tigeot case 27027000: 5545d0b1887SFrançois Tigeot case 37762500: 5555d0b1887SFrançois Tigeot case 37800000: 5565d0b1887SFrançois Tigeot case 40500000: 5575d0b1887SFrançois Tigeot case 40541000: 5585d0b1887SFrançois Tigeot case 54000000: 5595d0b1887SFrançois Tigeot case 54054000: 5605d0b1887SFrançois Tigeot case 59341000: 5615d0b1887SFrançois Tigeot case 59400000: 5625d0b1887SFrançois Tigeot case 72000000: 5635d0b1887SFrançois Tigeot case 74176000: 5645d0b1887SFrançois Tigeot case 74250000: 5655d0b1887SFrançois Tigeot case 81000000: 5665d0b1887SFrançois Tigeot case 81081000: 5675d0b1887SFrançois Tigeot case 89012000: 5685d0b1887SFrançois Tigeot case 89100000: 5695d0b1887SFrançois Tigeot case 108000000: 5705d0b1887SFrançois Tigeot case 108108000: 5715d0b1887SFrançois Tigeot case 111264000: 5725d0b1887SFrançois Tigeot case 111375000: 5735d0b1887SFrançois Tigeot case 148352000: 5745d0b1887SFrançois Tigeot case 148500000: 5755d0b1887SFrançois Tigeot case 162000000: 5765d0b1887SFrançois Tigeot case 162162000: 5775d0b1887SFrançois Tigeot case 222525000: 5785d0b1887SFrançois Tigeot case 222750000: 5795d0b1887SFrançois Tigeot case 296703000: 5805d0b1887SFrançois Tigeot case 297000000: 5815d0b1887SFrançois Tigeot budget = 0; 58219df918dSFrançois Tigeot break; 5835d0b1887SFrançois Tigeot case 233500000: 5845d0b1887SFrançois Tigeot case 245250000: 5855d0b1887SFrançois Tigeot case 247750000: 5865d0b1887SFrançois Tigeot case 253250000: 5875d0b1887SFrançois Tigeot case 298000000: 5885d0b1887SFrançois Tigeot budget = 1500; 5895d0b1887SFrançois Tigeot break; 5905d0b1887SFrançois Tigeot case 169128000: 5915d0b1887SFrançois Tigeot case 169500000: 5925d0b1887SFrançois Tigeot case 179500000: 5935d0b1887SFrançois Tigeot case 202000000: 5945d0b1887SFrançois Tigeot budget = 2000; 5955d0b1887SFrançois Tigeot break; 5965d0b1887SFrançois Tigeot case 256250000: 5975d0b1887SFrançois Tigeot case 262500000: 5985d0b1887SFrançois Tigeot case 270000000: 5995d0b1887SFrançois Tigeot case 272500000: 6005d0b1887SFrançois Tigeot case 273750000: 6015d0b1887SFrançois Tigeot case 280750000: 6025d0b1887SFrançois Tigeot case 281250000: 6035d0b1887SFrançois Tigeot case 286000000: 6045d0b1887SFrançois Tigeot case 291750000: 6055d0b1887SFrançois Tigeot budget = 4000; 6065d0b1887SFrançois Tigeot break; 6075d0b1887SFrançois Tigeot case 267250000: 6085d0b1887SFrançois Tigeot case 268500000: 6095d0b1887SFrançois Tigeot budget = 5000; 6105d0b1887SFrançois Tigeot break; 6115d0b1887SFrançois Tigeot default: 6125d0b1887SFrançois Tigeot budget = 1000; 6135d0b1887SFrançois Tigeot break; 61419df918dSFrançois Tigeot } 61519df918dSFrançois Tigeot 6165d0b1887SFrançois Tigeot return budget; 6175d0b1887SFrançois Tigeot } 6185d0b1887SFrançois Tigeot 6195d0b1887SFrançois Tigeot static void wrpll_update_rnp(uint64_t freq2k, unsigned budget, 6205d0b1887SFrançois Tigeot unsigned r2, unsigned n2, unsigned p, 6215d0b1887SFrançois Tigeot struct wrpll_rnp *best) 6225d0b1887SFrançois Tigeot { 6235d0b1887SFrançois Tigeot uint64_t a, b, c, d, diff, diff_best; 6245d0b1887SFrançois Tigeot 6255d0b1887SFrançois Tigeot /* No best (r,n,p) yet */ 6265d0b1887SFrançois Tigeot if (best->p == 0) { 6275d0b1887SFrançois Tigeot best->p = p; 6285d0b1887SFrançois Tigeot best->n2 = n2; 6295d0b1887SFrançois Tigeot best->r2 = r2; 6305d0b1887SFrançois Tigeot return; 6315d0b1887SFrançois Tigeot } 6325d0b1887SFrançois Tigeot 6335d0b1887SFrançois Tigeot /* 6345d0b1887SFrançois Tigeot * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to 6355d0b1887SFrançois Tigeot * freq2k. 6365d0b1887SFrançois Tigeot * 6375d0b1887SFrançois Tigeot * delta = 1e6 * 6385d0b1887SFrançois Tigeot * abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) / 6395d0b1887SFrançois Tigeot * freq2k; 6405d0b1887SFrançois Tigeot * 6415d0b1887SFrançois Tigeot * and we would like delta <= budget. 6425d0b1887SFrançois Tigeot * 6435d0b1887SFrançois Tigeot * If the discrepancy is above the PPM-based budget, always prefer to 6445d0b1887SFrançois Tigeot * improve upon the previous solution. However, if you're within the 6455d0b1887SFrançois Tigeot * budget, try to maximize Ref * VCO, that is N / (P * R^2). 6465d0b1887SFrançois Tigeot */ 6475d0b1887SFrançois Tigeot a = freq2k * budget * p * r2; 6485d0b1887SFrançois Tigeot b = freq2k * budget * best->p * best->r2; 6491b13d190SFrançois Tigeot diff = abs_diff(freq2k * p * r2, LC_FREQ_2K * n2); 6501b13d190SFrançois Tigeot diff_best = abs_diff(freq2k * best->p * best->r2, 6511b13d190SFrançois Tigeot LC_FREQ_2K * best->n2); 6525d0b1887SFrançois Tigeot c = 1000000 * diff; 6535d0b1887SFrançois Tigeot d = 1000000 * diff_best; 6545d0b1887SFrançois Tigeot 6555d0b1887SFrançois Tigeot if (a < c && b < d) { 6565d0b1887SFrançois Tigeot /* If both are above the budget, pick the closer */ 6575d0b1887SFrançois Tigeot if (best->p * best->r2 * diff < p * r2 * diff_best) { 6585d0b1887SFrançois Tigeot best->p = p; 6595d0b1887SFrançois Tigeot best->n2 = n2; 6605d0b1887SFrançois Tigeot best->r2 = r2; 6615d0b1887SFrançois Tigeot } 6625d0b1887SFrançois Tigeot } else if (a >= c && b < d) { 6635d0b1887SFrançois Tigeot /* If A is below the threshold but B is above it? Update. */ 6645d0b1887SFrançois Tigeot best->p = p; 6655d0b1887SFrançois Tigeot best->n2 = n2; 6665d0b1887SFrançois Tigeot best->r2 = r2; 6675d0b1887SFrançois Tigeot } else if (a >= c && b >= d) { 6685d0b1887SFrançois Tigeot /* Both are below the limit, so pick the higher n2/(r2*r2) */ 6695d0b1887SFrançois Tigeot if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) { 6705d0b1887SFrançois Tigeot best->p = p; 6715d0b1887SFrançois Tigeot best->n2 = n2; 6725d0b1887SFrançois Tigeot best->r2 = r2; 6735d0b1887SFrançois Tigeot } 6745d0b1887SFrançois Tigeot } 6755d0b1887SFrançois Tigeot /* Otherwise a < c && b >= d, do nothing */ 6765d0b1887SFrançois Tigeot } 6775d0b1887SFrançois Tigeot 678ba55f2f5SFrançois Tigeot static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, 679ba55f2f5SFrançois Tigeot int reg) 680ba55f2f5SFrançois Tigeot { 681ba55f2f5SFrançois Tigeot int refclk = LC_FREQ; 682ba55f2f5SFrançois Tigeot int n, p, r; 683ba55f2f5SFrançois Tigeot u32 wrpll; 684ba55f2f5SFrançois Tigeot 685ba55f2f5SFrançois Tigeot wrpll = I915_READ(reg); 68624edb884SFrançois Tigeot switch (wrpll & WRPLL_PLL_REF_MASK) { 68724edb884SFrançois Tigeot case WRPLL_PLL_SSC: 68824edb884SFrançois Tigeot case WRPLL_PLL_NON_SSC: 689ba55f2f5SFrançois Tigeot /* 690ba55f2f5SFrançois Tigeot * We could calculate spread here, but our checking 691ba55f2f5SFrançois Tigeot * code only cares about 5% accuracy, and spread is a max of 692ba55f2f5SFrançois Tigeot * 0.5% downspread. 693ba55f2f5SFrançois Tigeot */ 694ba55f2f5SFrançois Tigeot refclk = 135; 695ba55f2f5SFrançois Tigeot break; 69624edb884SFrançois Tigeot case WRPLL_PLL_LCPLL: 697ba55f2f5SFrançois Tigeot refclk = LC_FREQ; 698ba55f2f5SFrançois Tigeot break; 699ba55f2f5SFrançois Tigeot default: 700ba55f2f5SFrançois Tigeot WARN(1, "bad wrpll refclk\n"); 701ba55f2f5SFrançois Tigeot return 0; 702ba55f2f5SFrançois Tigeot } 703ba55f2f5SFrançois Tigeot 704ba55f2f5SFrançois Tigeot r = wrpll & WRPLL_DIVIDER_REF_MASK; 705ba55f2f5SFrançois Tigeot p = (wrpll & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT; 706ba55f2f5SFrançois Tigeot n = (wrpll & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT; 707ba55f2f5SFrançois Tigeot 708ba55f2f5SFrançois Tigeot /* Convert to KHz, p & r have a fixed point portion */ 709ba55f2f5SFrançois Tigeot return (refclk * n * 100) / (p * r); 710ba55f2f5SFrançois Tigeot } 711ba55f2f5SFrançois Tigeot 7122c9916cdSFrançois Tigeot static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv, 7132c9916cdSFrançois Tigeot uint32_t dpll) 7142c9916cdSFrançois Tigeot { 7152c9916cdSFrançois Tigeot uint32_t cfgcr1_reg, cfgcr2_reg; 7162c9916cdSFrançois Tigeot uint32_t cfgcr1_val, cfgcr2_val; 7172c9916cdSFrançois Tigeot uint32_t p0, p1, p2, dco_freq; 7182c9916cdSFrançois Tigeot 7192c9916cdSFrançois Tigeot cfgcr1_reg = GET_CFG_CR1_REG(dpll); 7202c9916cdSFrançois Tigeot cfgcr2_reg = GET_CFG_CR2_REG(dpll); 7212c9916cdSFrançois Tigeot 7222c9916cdSFrançois Tigeot cfgcr1_val = I915_READ(cfgcr1_reg); 7232c9916cdSFrançois Tigeot cfgcr2_val = I915_READ(cfgcr2_reg); 7242c9916cdSFrançois Tigeot 7252c9916cdSFrançois Tigeot p0 = cfgcr2_val & DPLL_CFGCR2_PDIV_MASK; 7262c9916cdSFrançois Tigeot p2 = cfgcr2_val & DPLL_CFGCR2_KDIV_MASK; 7272c9916cdSFrançois Tigeot 7282c9916cdSFrançois Tigeot if (cfgcr2_val & DPLL_CFGCR2_QDIV_MODE(1)) 7292c9916cdSFrançois Tigeot p1 = (cfgcr2_val & DPLL_CFGCR2_QDIV_RATIO_MASK) >> 8; 7302c9916cdSFrançois Tigeot else 7312c9916cdSFrançois Tigeot p1 = 1; 7322c9916cdSFrançois Tigeot 7332c9916cdSFrançois Tigeot 7342c9916cdSFrançois Tigeot switch (p0) { 7352c9916cdSFrançois Tigeot case DPLL_CFGCR2_PDIV_1: 7362c9916cdSFrançois Tigeot p0 = 1; 7372c9916cdSFrançois Tigeot break; 7382c9916cdSFrançois Tigeot case DPLL_CFGCR2_PDIV_2: 7392c9916cdSFrançois Tigeot p0 = 2; 7402c9916cdSFrançois Tigeot break; 7412c9916cdSFrançois Tigeot case DPLL_CFGCR2_PDIV_3: 7422c9916cdSFrançois Tigeot p0 = 3; 7432c9916cdSFrançois Tigeot break; 7442c9916cdSFrançois Tigeot case DPLL_CFGCR2_PDIV_7: 7452c9916cdSFrançois Tigeot p0 = 7; 7462c9916cdSFrançois Tigeot break; 7472c9916cdSFrançois Tigeot } 7482c9916cdSFrançois Tigeot 7492c9916cdSFrançois Tigeot switch (p2) { 7502c9916cdSFrançois Tigeot case DPLL_CFGCR2_KDIV_5: 7512c9916cdSFrançois Tigeot p2 = 5; 7522c9916cdSFrançois Tigeot break; 7532c9916cdSFrançois Tigeot case DPLL_CFGCR2_KDIV_2: 7542c9916cdSFrançois Tigeot p2 = 2; 7552c9916cdSFrançois Tigeot break; 7562c9916cdSFrançois Tigeot case DPLL_CFGCR2_KDIV_3: 7572c9916cdSFrançois Tigeot p2 = 3; 7582c9916cdSFrançois Tigeot break; 7592c9916cdSFrançois Tigeot case DPLL_CFGCR2_KDIV_1: 7602c9916cdSFrançois Tigeot p2 = 1; 7612c9916cdSFrançois Tigeot break; 7622c9916cdSFrançois Tigeot } 7632c9916cdSFrançois Tigeot 7642c9916cdSFrançois Tigeot dco_freq = (cfgcr1_val & DPLL_CFGCR1_DCO_INTEGER_MASK) * 24 * 1000; 7652c9916cdSFrançois Tigeot 7662c9916cdSFrançois Tigeot dco_freq += (((cfgcr1_val & DPLL_CFGCR1_DCO_FRACTION_MASK) >> 9) * 24 * 7672c9916cdSFrançois Tigeot 1000) / 0x8000; 7682c9916cdSFrançois Tigeot 7692c9916cdSFrançois Tigeot return dco_freq / (p0 * p1 * p2 * 5); 7702c9916cdSFrançois Tigeot } 7712c9916cdSFrançois Tigeot 7722c9916cdSFrançois Tigeot 7732c9916cdSFrançois Tigeot static void skl_ddi_clock_get(struct intel_encoder *encoder, 7742c9916cdSFrançois Tigeot struct intel_crtc_state *pipe_config) 7752c9916cdSFrançois Tigeot { 7762c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 7772c9916cdSFrançois Tigeot int link_clock = 0; 7782c9916cdSFrançois Tigeot uint32_t dpll_ctl1, dpll; 7792c9916cdSFrançois Tigeot 7802c9916cdSFrançois Tigeot dpll = pipe_config->ddi_pll_sel; 7812c9916cdSFrançois Tigeot 7822c9916cdSFrançois Tigeot dpll_ctl1 = I915_READ(DPLL_CTRL1); 7832c9916cdSFrançois Tigeot 7842c9916cdSFrançois Tigeot if (dpll_ctl1 & DPLL_CTRL1_HDMI_MODE(dpll)) { 7852c9916cdSFrançois Tigeot link_clock = skl_calc_wrpll_link(dev_priv, dpll); 7862c9916cdSFrançois Tigeot } else { 7872c9916cdSFrançois Tigeot link_clock = dpll_ctl1 & DPLL_CRTL1_LINK_RATE_MASK(dpll); 7882c9916cdSFrançois Tigeot link_clock >>= DPLL_CRTL1_LINK_RATE_SHIFT(dpll); 7892c9916cdSFrançois Tigeot 7902c9916cdSFrançois Tigeot switch (link_clock) { 7912c9916cdSFrançois Tigeot case DPLL_CRTL1_LINK_RATE_810: 7922c9916cdSFrançois Tigeot link_clock = 81000; 7932c9916cdSFrançois Tigeot break; 794*477eb7f9SFrançois Tigeot case DPLL_CRTL1_LINK_RATE_1080: 795*477eb7f9SFrançois Tigeot link_clock = 108000; 796*477eb7f9SFrançois Tigeot break; 7972c9916cdSFrançois Tigeot case DPLL_CRTL1_LINK_RATE_1350: 7982c9916cdSFrançois Tigeot link_clock = 135000; 7992c9916cdSFrançois Tigeot break; 800*477eb7f9SFrançois Tigeot case DPLL_CRTL1_LINK_RATE_1620: 801*477eb7f9SFrançois Tigeot link_clock = 162000; 802*477eb7f9SFrançois Tigeot break; 803*477eb7f9SFrançois Tigeot case DPLL_CRTL1_LINK_RATE_2160: 804*477eb7f9SFrançois Tigeot link_clock = 216000; 805*477eb7f9SFrançois Tigeot break; 8062c9916cdSFrançois Tigeot case DPLL_CRTL1_LINK_RATE_2700: 8072c9916cdSFrançois Tigeot link_clock = 270000; 8082c9916cdSFrançois Tigeot break; 8092c9916cdSFrançois Tigeot default: 8102c9916cdSFrançois Tigeot WARN(1, "Unsupported link rate\n"); 8112c9916cdSFrançois Tigeot break; 8122c9916cdSFrançois Tigeot } 8132c9916cdSFrançois Tigeot link_clock *= 2; 8142c9916cdSFrançois Tigeot } 8152c9916cdSFrançois Tigeot 8162c9916cdSFrançois Tigeot pipe_config->port_clock = link_clock; 8172c9916cdSFrançois Tigeot 8182c9916cdSFrançois Tigeot if (pipe_config->has_dp_encoder) 8192c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.crtc_clock = 8202c9916cdSFrançois Tigeot intel_dotclock_calculate(pipe_config->port_clock, 8212c9916cdSFrançois Tigeot &pipe_config->dp_m_n); 8222c9916cdSFrançois Tigeot else 8232c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; 8242c9916cdSFrançois Tigeot } 8252c9916cdSFrançois Tigeot 8261b13d190SFrançois Tigeot static void hsw_ddi_clock_get(struct intel_encoder *encoder, 8272c9916cdSFrançois Tigeot struct intel_crtc_state *pipe_config) 828ba55f2f5SFrançois Tigeot { 829ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 830ba55f2f5SFrançois Tigeot int link_clock = 0; 831ba55f2f5SFrançois Tigeot u32 val, pll; 832ba55f2f5SFrançois Tigeot 83324edb884SFrançois Tigeot val = pipe_config->ddi_pll_sel; 834ba55f2f5SFrançois Tigeot switch (val & PORT_CLK_SEL_MASK) { 835ba55f2f5SFrançois Tigeot case PORT_CLK_SEL_LCPLL_810: 836ba55f2f5SFrançois Tigeot link_clock = 81000; 837ba55f2f5SFrançois Tigeot break; 838ba55f2f5SFrançois Tigeot case PORT_CLK_SEL_LCPLL_1350: 839ba55f2f5SFrançois Tigeot link_clock = 135000; 840ba55f2f5SFrançois Tigeot break; 841ba55f2f5SFrançois Tigeot case PORT_CLK_SEL_LCPLL_2700: 842ba55f2f5SFrançois Tigeot link_clock = 270000; 843ba55f2f5SFrançois Tigeot break; 844ba55f2f5SFrançois Tigeot case PORT_CLK_SEL_WRPLL1: 845ba55f2f5SFrançois Tigeot link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1); 846ba55f2f5SFrançois Tigeot break; 847ba55f2f5SFrançois Tigeot case PORT_CLK_SEL_WRPLL2: 848ba55f2f5SFrançois Tigeot link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2); 849ba55f2f5SFrançois Tigeot break; 850ba55f2f5SFrançois Tigeot case PORT_CLK_SEL_SPLL: 851ba55f2f5SFrançois Tigeot pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK; 852ba55f2f5SFrançois Tigeot if (pll == SPLL_PLL_FREQ_810MHz) 853ba55f2f5SFrançois Tigeot link_clock = 81000; 854ba55f2f5SFrançois Tigeot else if (pll == SPLL_PLL_FREQ_1350MHz) 855ba55f2f5SFrançois Tigeot link_clock = 135000; 856ba55f2f5SFrançois Tigeot else if (pll == SPLL_PLL_FREQ_2700MHz) 857ba55f2f5SFrançois Tigeot link_clock = 270000; 858ba55f2f5SFrançois Tigeot else { 859ba55f2f5SFrançois Tigeot WARN(1, "bad spll freq\n"); 860ba55f2f5SFrançois Tigeot return; 861ba55f2f5SFrançois Tigeot } 862ba55f2f5SFrançois Tigeot break; 863ba55f2f5SFrançois Tigeot default: 864ba55f2f5SFrançois Tigeot WARN(1, "bad port clock sel\n"); 865ba55f2f5SFrançois Tigeot return; 866ba55f2f5SFrançois Tigeot } 867ba55f2f5SFrançois Tigeot 868ba55f2f5SFrançois Tigeot pipe_config->port_clock = link_clock * 2; 869ba55f2f5SFrançois Tigeot 870ba55f2f5SFrançois Tigeot if (pipe_config->has_pch_encoder) 8712c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.crtc_clock = 872ba55f2f5SFrançois Tigeot intel_dotclock_calculate(pipe_config->port_clock, 873ba55f2f5SFrançois Tigeot &pipe_config->fdi_m_n); 874ba55f2f5SFrançois Tigeot else if (pipe_config->has_dp_encoder) 8752c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.crtc_clock = 876ba55f2f5SFrançois Tigeot intel_dotclock_calculate(pipe_config->port_clock, 877ba55f2f5SFrançois Tigeot &pipe_config->dp_m_n); 878ba55f2f5SFrançois Tigeot else 8792c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; 880ba55f2f5SFrançois Tigeot } 881ba55f2f5SFrançois Tigeot 8821b13d190SFrançois Tigeot void intel_ddi_clock_get(struct intel_encoder *encoder, 8832c9916cdSFrançois Tigeot struct intel_crtc_state *pipe_config) 8841b13d190SFrançois Tigeot { 8852c9916cdSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 8862c9916cdSFrançois Tigeot 8872c9916cdSFrançois Tigeot if (INTEL_INFO(dev)->gen <= 8) 8881b13d190SFrançois Tigeot hsw_ddi_clock_get(encoder, pipe_config); 8892c9916cdSFrançois Tigeot else 8902c9916cdSFrançois Tigeot skl_ddi_clock_get(encoder, pipe_config); 8911b13d190SFrançois Tigeot } 8921b13d190SFrançois Tigeot 8935d0b1887SFrançois Tigeot static void 8941b13d190SFrançois Tigeot hsw_ddi_calculate_wrpll(int clock /* in Hz */, 8955d0b1887SFrançois Tigeot unsigned *r2_out, unsigned *n2_out, unsigned *p_out) 8965d0b1887SFrançois Tigeot { 8975d0b1887SFrançois Tigeot uint64_t freq2k; 8985d0b1887SFrançois Tigeot unsigned p, n2, r2; 8995d0b1887SFrançois Tigeot struct wrpll_rnp best = { 0, 0, 0 }; 9005d0b1887SFrançois Tigeot unsigned budget; 9015d0b1887SFrançois Tigeot 9025d0b1887SFrançois Tigeot freq2k = clock / 100; 9035d0b1887SFrançois Tigeot 9045d0b1887SFrançois Tigeot budget = wrpll_get_budget_for_freq(clock); 9055d0b1887SFrançois Tigeot 9065d0b1887SFrançois Tigeot /* Special case handling for 540 pixel clock: bypass WR PLL entirely 9075d0b1887SFrançois Tigeot * and directly pass the LC PLL to it. */ 9085d0b1887SFrançois Tigeot if (freq2k == 5400000) { 9095d0b1887SFrançois Tigeot *n2_out = 2; 9105d0b1887SFrançois Tigeot *p_out = 1; 9115d0b1887SFrançois Tigeot *r2_out = 2; 9125d0b1887SFrançois Tigeot return; 9135d0b1887SFrançois Tigeot } 9145d0b1887SFrançois Tigeot 9155d0b1887SFrançois Tigeot /* 9165d0b1887SFrançois Tigeot * Ref = LC_FREQ / R, where Ref is the actual reference input seen by 9175d0b1887SFrançois Tigeot * the WR PLL. 9185d0b1887SFrançois Tigeot * 9195d0b1887SFrançois Tigeot * We want R so that REF_MIN <= Ref <= REF_MAX. 9205d0b1887SFrançois Tigeot * Injecting R2 = 2 * R gives: 9215d0b1887SFrançois Tigeot * REF_MAX * r2 > LC_FREQ * 2 and 9225d0b1887SFrançois Tigeot * REF_MIN * r2 < LC_FREQ * 2 9235d0b1887SFrançois Tigeot * 9245d0b1887SFrançois Tigeot * Which means the desired boundaries for r2 are: 9255d0b1887SFrançois Tigeot * LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN 9265d0b1887SFrançois Tigeot * 9275d0b1887SFrançois Tigeot */ 9285d0b1887SFrançois Tigeot for (r2 = LC_FREQ * 2 / REF_MAX + 1; 9295d0b1887SFrançois Tigeot r2 <= LC_FREQ * 2 / REF_MIN; 9305d0b1887SFrançois Tigeot r2++) { 9315d0b1887SFrançois Tigeot 9325d0b1887SFrançois Tigeot /* 9335d0b1887SFrançois Tigeot * VCO = N * Ref, that is: VCO = N * LC_FREQ / R 9345d0b1887SFrançois Tigeot * 9355d0b1887SFrançois Tigeot * Once again we want VCO_MIN <= VCO <= VCO_MAX. 9365d0b1887SFrançois Tigeot * Injecting R2 = 2 * R and N2 = 2 * N, we get: 9375d0b1887SFrançois Tigeot * VCO_MAX * r2 > n2 * LC_FREQ and 9385d0b1887SFrançois Tigeot * VCO_MIN * r2 < n2 * LC_FREQ) 9395d0b1887SFrançois Tigeot * 9405d0b1887SFrançois Tigeot * Which means the desired boundaries for n2 are: 9415d0b1887SFrançois Tigeot * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ 9425d0b1887SFrançois Tigeot */ 9435d0b1887SFrançois Tigeot for (n2 = VCO_MIN * r2 / LC_FREQ + 1; 9445d0b1887SFrançois Tigeot n2 <= VCO_MAX * r2 / LC_FREQ; 9455d0b1887SFrançois Tigeot n2++) { 9465d0b1887SFrançois Tigeot 9475d0b1887SFrançois Tigeot for (p = P_MIN; p <= P_MAX; p += P_INC) 9485d0b1887SFrançois Tigeot wrpll_update_rnp(freq2k, budget, 9495d0b1887SFrançois Tigeot r2, n2, p, &best); 9505d0b1887SFrançois Tigeot } 9515d0b1887SFrançois Tigeot } 9525d0b1887SFrançois Tigeot 9535d0b1887SFrançois Tigeot *n2_out = best.n2; 9545d0b1887SFrançois Tigeot *p_out = best.p; 9555d0b1887SFrançois Tigeot *r2_out = best.r2; 9565d0b1887SFrançois Tigeot } 9575d0b1887SFrançois Tigeot 9581b13d190SFrançois Tigeot static bool 9591b13d190SFrançois Tigeot hsw_ddi_pll_select(struct intel_crtc *intel_crtc, 9602c9916cdSFrançois Tigeot struct intel_crtc_state *crtc_state, 9611b13d190SFrançois Tigeot struct intel_encoder *intel_encoder, 9621b13d190SFrançois Tigeot int clock) 96319df918dSFrançois Tigeot { 9641b13d190SFrançois Tigeot if (intel_encoder->type == INTEL_OUTPUT_HDMI) { 96524edb884SFrançois Tigeot struct intel_shared_dpll *pll; 96624edb884SFrançois Tigeot uint32_t val; 9675d0b1887SFrançois Tigeot unsigned p, n2, r2; 96819df918dSFrançois Tigeot 9691b13d190SFrançois Tigeot hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); 97019df918dSFrançois Tigeot 97124edb884SFrançois Tigeot val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL | 97219df918dSFrançois Tigeot WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | 97319df918dSFrançois Tigeot WRPLL_DIVIDER_POST(p); 97419df918dSFrançois Tigeot 9752c9916cdSFrançois Tigeot crtc_state->dpll_hw_state.wrpll = val; 97624edb884SFrançois Tigeot 9772c9916cdSFrançois Tigeot pll = intel_get_shared_dpll(intel_crtc, crtc_state); 97824edb884SFrançois Tigeot if (pll == NULL) { 97924edb884SFrançois Tigeot DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", 98024edb884SFrançois Tigeot pipe_name(intel_crtc->pipe)); 9819edbd4a0SFrançois Tigeot return false; 9829edbd4a0SFrançois Tigeot } 9839edbd4a0SFrançois Tigeot 9842c9916cdSFrançois Tigeot crtc_state->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id); 98519df918dSFrançois Tigeot } 98619df918dSFrançois Tigeot 98719df918dSFrançois Tigeot return true; 98819df918dSFrançois Tigeot } 98919df918dSFrançois Tigeot 9902c9916cdSFrançois Tigeot struct skl_wrpll_params { 9912c9916cdSFrançois Tigeot uint32_t dco_fraction; 9922c9916cdSFrançois Tigeot uint32_t dco_integer; 9932c9916cdSFrançois Tigeot uint32_t qdiv_ratio; 9942c9916cdSFrançois Tigeot uint32_t qdiv_mode; 9952c9916cdSFrançois Tigeot uint32_t kdiv; 9962c9916cdSFrançois Tigeot uint32_t pdiv; 9972c9916cdSFrançois Tigeot uint32_t central_freq; 9982c9916cdSFrançois Tigeot }; 9992c9916cdSFrançois Tigeot 10002c9916cdSFrançois Tigeot static void 10012c9916cdSFrançois Tigeot skl_ddi_calculate_wrpll(int clock /* in Hz */, 10022c9916cdSFrançois Tigeot struct skl_wrpll_params *wrpll_params) 10032c9916cdSFrançois Tigeot { 10042c9916cdSFrançois Tigeot uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ 10052c9916cdSFrançois Tigeot uint64_t dco_central_freq[3] = {8400000000ULL, 10062c9916cdSFrançois Tigeot 9000000000ULL, 10072c9916cdSFrançois Tigeot 9600000000ULL}; 10082c9916cdSFrançois Tigeot uint32_t min_dco_deviation = 400; 10092c9916cdSFrançois Tigeot uint32_t min_dco_index = 3; 10102c9916cdSFrançois Tigeot uint32_t P0[4] = {1, 2, 3, 7}; 10112c9916cdSFrançois Tigeot uint32_t P2[4] = {1, 2, 3, 5}; 10122c9916cdSFrançois Tigeot bool found = false; 10132c9916cdSFrançois Tigeot uint32_t candidate_p = 0; 10142c9916cdSFrançois Tigeot uint32_t candidate_p0[3] = {0}, candidate_p1[3] = {0}; 10152c9916cdSFrançois Tigeot uint32_t candidate_p2[3] = {0}; 10162c9916cdSFrançois Tigeot uint32_t dco_central_freq_deviation[3]; 10172c9916cdSFrançois Tigeot uint32_t i, P1, k, dco_count; 10182c9916cdSFrançois Tigeot bool retry_with_odd = false; 10192c9916cdSFrançois Tigeot uint64_t dco_freq; 10202c9916cdSFrançois Tigeot 10212c9916cdSFrançois Tigeot /* Determine P0, P1 or P2 */ 10222c9916cdSFrançois Tigeot for (dco_count = 0; dco_count < 3; dco_count++) { 10232c9916cdSFrançois Tigeot found = false; 10242c9916cdSFrançois Tigeot candidate_p = 10252c9916cdSFrançois Tigeot div64_u64(dco_central_freq[dco_count], afe_clock); 10262c9916cdSFrançois Tigeot if (retry_with_odd == false) 10272c9916cdSFrançois Tigeot candidate_p = (candidate_p % 2 == 0 ? 10282c9916cdSFrançois Tigeot candidate_p : candidate_p + 1); 10292c9916cdSFrançois Tigeot 10302c9916cdSFrançois Tigeot for (P1 = 1; P1 < candidate_p; P1++) { 10312c9916cdSFrançois Tigeot for (i = 0; i < 4; i++) { 10322c9916cdSFrançois Tigeot if (!(P0[i] != 1 || P1 == 1)) 10332c9916cdSFrançois Tigeot continue; 10342c9916cdSFrançois Tigeot 10352c9916cdSFrançois Tigeot for (k = 0; k < 4; k++) { 10362c9916cdSFrançois Tigeot if (P1 != 1 && P2[k] != 2) 10372c9916cdSFrançois Tigeot continue; 10382c9916cdSFrançois Tigeot 10392c9916cdSFrançois Tigeot if (candidate_p == P0[i] * P1 * P2[k]) { 10402c9916cdSFrançois Tigeot /* Found possible P0, P1, P2 */ 10412c9916cdSFrançois Tigeot found = true; 10422c9916cdSFrançois Tigeot candidate_p0[dco_count] = P0[i]; 10432c9916cdSFrançois Tigeot candidate_p1[dco_count] = P1; 10442c9916cdSFrançois Tigeot candidate_p2[dco_count] = P2[k]; 10452c9916cdSFrançois Tigeot goto found; 10462c9916cdSFrançois Tigeot } 10472c9916cdSFrançois Tigeot 10482c9916cdSFrançois Tigeot } 10492c9916cdSFrançois Tigeot } 10502c9916cdSFrançois Tigeot } 10512c9916cdSFrançois Tigeot 10522c9916cdSFrançois Tigeot found: 10532c9916cdSFrançois Tigeot if (found) { 10542c9916cdSFrançois Tigeot dco_central_freq_deviation[dco_count] = 10552c9916cdSFrançois Tigeot div64_u64(10000 * 10562c9916cdSFrançois Tigeot abs_diff((candidate_p * afe_clock), 10572c9916cdSFrançois Tigeot dco_central_freq[dco_count]), 10582c9916cdSFrançois Tigeot dco_central_freq[dco_count]); 10592c9916cdSFrançois Tigeot 10602c9916cdSFrançois Tigeot if (dco_central_freq_deviation[dco_count] < 10612c9916cdSFrançois Tigeot min_dco_deviation) { 10622c9916cdSFrançois Tigeot min_dco_deviation = 10632c9916cdSFrançois Tigeot dco_central_freq_deviation[dco_count]; 10642c9916cdSFrançois Tigeot min_dco_index = dco_count; 10652c9916cdSFrançois Tigeot } 10662c9916cdSFrançois Tigeot } 10672c9916cdSFrançois Tigeot 10682c9916cdSFrançois Tigeot if (min_dco_index > 2 && dco_count == 2) { 10692c9916cdSFrançois Tigeot retry_with_odd = true; 10702c9916cdSFrançois Tigeot dco_count = 0; 10712c9916cdSFrançois Tigeot } 10722c9916cdSFrançois Tigeot } 10732c9916cdSFrançois Tigeot 10742c9916cdSFrançois Tigeot if (min_dco_index > 2) { 10752c9916cdSFrançois Tigeot WARN(1, "No valid values found for the given pixel clock\n"); 10762c9916cdSFrançois Tigeot } else { 10772c9916cdSFrançois Tigeot wrpll_params->central_freq = dco_central_freq[min_dco_index]; 10782c9916cdSFrançois Tigeot 10792c9916cdSFrançois Tigeot switch (dco_central_freq[min_dco_index]) { 10802c9916cdSFrançois Tigeot case 9600000000ULL: 10812c9916cdSFrançois Tigeot wrpll_params->central_freq = 0; 10822c9916cdSFrançois Tigeot break; 10832c9916cdSFrançois Tigeot case 9000000000ULL: 10842c9916cdSFrançois Tigeot wrpll_params->central_freq = 1; 10852c9916cdSFrançois Tigeot break; 10862c9916cdSFrançois Tigeot case 8400000000ULL: 10872c9916cdSFrançois Tigeot wrpll_params->central_freq = 3; 10882c9916cdSFrançois Tigeot } 10892c9916cdSFrançois Tigeot 10902c9916cdSFrançois Tigeot switch (candidate_p0[min_dco_index]) { 10912c9916cdSFrançois Tigeot case 1: 10922c9916cdSFrançois Tigeot wrpll_params->pdiv = 0; 10932c9916cdSFrançois Tigeot break; 10942c9916cdSFrançois Tigeot case 2: 10952c9916cdSFrançois Tigeot wrpll_params->pdiv = 1; 10962c9916cdSFrançois Tigeot break; 10972c9916cdSFrançois Tigeot case 3: 10982c9916cdSFrançois Tigeot wrpll_params->pdiv = 2; 10992c9916cdSFrançois Tigeot break; 11002c9916cdSFrançois Tigeot case 7: 11012c9916cdSFrançois Tigeot wrpll_params->pdiv = 4; 11022c9916cdSFrançois Tigeot break; 11032c9916cdSFrançois Tigeot default: 11042c9916cdSFrançois Tigeot WARN(1, "Incorrect PDiv\n"); 11052c9916cdSFrançois Tigeot } 11062c9916cdSFrançois Tigeot 11072c9916cdSFrançois Tigeot switch (candidate_p2[min_dco_index]) { 11082c9916cdSFrançois Tigeot case 5: 11092c9916cdSFrançois Tigeot wrpll_params->kdiv = 0; 11102c9916cdSFrançois Tigeot break; 11112c9916cdSFrançois Tigeot case 2: 11122c9916cdSFrançois Tigeot wrpll_params->kdiv = 1; 11132c9916cdSFrançois Tigeot break; 11142c9916cdSFrançois Tigeot case 3: 11152c9916cdSFrançois Tigeot wrpll_params->kdiv = 2; 11162c9916cdSFrançois Tigeot break; 11172c9916cdSFrançois Tigeot case 1: 11182c9916cdSFrançois Tigeot wrpll_params->kdiv = 3; 11192c9916cdSFrançois Tigeot break; 11202c9916cdSFrançois Tigeot default: 11212c9916cdSFrançois Tigeot WARN(1, "Incorrect KDiv\n"); 11222c9916cdSFrançois Tigeot } 11232c9916cdSFrançois Tigeot 11242c9916cdSFrançois Tigeot wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; 11252c9916cdSFrançois Tigeot wrpll_params->qdiv_mode = 11262c9916cdSFrançois Tigeot (wrpll_params->qdiv_ratio == 1) ? 0 : 1; 11272c9916cdSFrançois Tigeot 11282c9916cdSFrançois Tigeot dco_freq = candidate_p0[min_dco_index] * 11292c9916cdSFrançois Tigeot candidate_p1[min_dco_index] * 11302c9916cdSFrançois Tigeot candidate_p2[min_dco_index] * afe_clock; 11312c9916cdSFrançois Tigeot 11322c9916cdSFrançois Tigeot /* 11332c9916cdSFrançois Tigeot * Intermediate values are in Hz. 11342c9916cdSFrançois Tigeot * Divide by MHz to match bsepc 11352c9916cdSFrançois Tigeot */ 11362c9916cdSFrançois Tigeot wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); 11372c9916cdSFrançois Tigeot wrpll_params->dco_fraction = 11382c9916cdSFrançois Tigeot div_u64(((div_u64(dco_freq, 24) - 11392c9916cdSFrançois Tigeot wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); 11402c9916cdSFrançois Tigeot 11412c9916cdSFrançois Tigeot } 11422c9916cdSFrançois Tigeot } 11432c9916cdSFrançois Tigeot 11442c9916cdSFrançois Tigeot 11452c9916cdSFrançois Tigeot static bool 11462c9916cdSFrançois Tigeot skl_ddi_pll_select(struct intel_crtc *intel_crtc, 11472c9916cdSFrançois Tigeot struct intel_crtc_state *crtc_state, 11482c9916cdSFrançois Tigeot struct intel_encoder *intel_encoder, 11492c9916cdSFrançois Tigeot int clock) 11502c9916cdSFrançois Tigeot { 11512c9916cdSFrançois Tigeot struct intel_shared_dpll *pll; 11522c9916cdSFrançois Tigeot uint32_t ctrl1, cfgcr1, cfgcr2; 11532c9916cdSFrançois Tigeot 11542c9916cdSFrançois Tigeot /* 11552c9916cdSFrançois Tigeot * See comment in intel_dpll_hw_state to understand why we always use 0 11562c9916cdSFrançois Tigeot * as the DPLL id in this function. 11572c9916cdSFrançois Tigeot */ 11582c9916cdSFrançois Tigeot 11592c9916cdSFrançois Tigeot ctrl1 = DPLL_CTRL1_OVERRIDE(0); 11602c9916cdSFrançois Tigeot 11612c9916cdSFrançois Tigeot if (intel_encoder->type == INTEL_OUTPUT_HDMI) { 11622c9916cdSFrançois Tigeot struct skl_wrpll_params wrpll_params = { 0, }; 11632c9916cdSFrançois Tigeot 11642c9916cdSFrançois Tigeot ctrl1 |= DPLL_CTRL1_HDMI_MODE(0); 11652c9916cdSFrançois Tigeot 11662c9916cdSFrançois Tigeot skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params); 11672c9916cdSFrançois Tigeot 11682c9916cdSFrançois Tigeot cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE | 11692c9916cdSFrançois Tigeot DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) | 11702c9916cdSFrançois Tigeot wrpll_params.dco_integer; 11712c9916cdSFrançois Tigeot 11722c9916cdSFrançois Tigeot cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) | 11732c9916cdSFrançois Tigeot DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) | 11742c9916cdSFrançois Tigeot DPLL_CFGCR2_KDIV(wrpll_params.kdiv) | 11752c9916cdSFrançois Tigeot DPLL_CFGCR2_PDIV(wrpll_params.pdiv) | 11762c9916cdSFrançois Tigeot wrpll_params.central_freq; 11772c9916cdSFrançois Tigeot } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { 11782c9916cdSFrançois Tigeot struct drm_encoder *encoder = &intel_encoder->base; 11792c9916cdSFrançois Tigeot struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 11802c9916cdSFrançois Tigeot 11812c9916cdSFrançois Tigeot switch (intel_dp->link_bw) { 11822c9916cdSFrançois Tigeot case DP_LINK_BW_1_62: 11832c9916cdSFrançois Tigeot ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_810, 0); 11842c9916cdSFrançois Tigeot break; 11852c9916cdSFrançois Tigeot case DP_LINK_BW_2_7: 11862c9916cdSFrançois Tigeot ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1350, 0); 11872c9916cdSFrançois Tigeot break; 11882c9916cdSFrançois Tigeot case DP_LINK_BW_5_4: 11892c9916cdSFrançois Tigeot ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2700, 0); 11902c9916cdSFrançois Tigeot break; 11912c9916cdSFrançois Tigeot } 11922c9916cdSFrançois Tigeot 11932c9916cdSFrançois Tigeot cfgcr1 = cfgcr2 = 0; 11942c9916cdSFrançois Tigeot } else /* eDP */ 11952c9916cdSFrançois Tigeot return true; 11962c9916cdSFrançois Tigeot 11972c9916cdSFrançois Tigeot crtc_state->dpll_hw_state.ctrl1 = ctrl1; 11982c9916cdSFrançois Tigeot crtc_state->dpll_hw_state.cfgcr1 = cfgcr1; 11992c9916cdSFrançois Tigeot crtc_state->dpll_hw_state.cfgcr2 = cfgcr2; 12002c9916cdSFrançois Tigeot 12012c9916cdSFrançois Tigeot pll = intel_get_shared_dpll(intel_crtc, crtc_state); 12022c9916cdSFrançois Tigeot if (pll == NULL) { 12032c9916cdSFrançois Tigeot DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", 12042c9916cdSFrançois Tigeot pipe_name(intel_crtc->pipe)); 12052c9916cdSFrançois Tigeot return false; 12062c9916cdSFrançois Tigeot } 12072c9916cdSFrançois Tigeot 12082c9916cdSFrançois Tigeot /* shared DPLL id 0 is DPLL 1 */ 12092c9916cdSFrançois Tigeot crtc_state->ddi_pll_sel = pll->id + 1; 12102c9916cdSFrançois Tigeot 12112c9916cdSFrançois Tigeot return true; 12122c9916cdSFrançois Tigeot } 12131b13d190SFrançois Tigeot 12141b13d190SFrançois Tigeot /* 12151b13d190SFrançois Tigeot * Tries to find a *shared* PLL for the CRTC and store it in 12161b13d190SFrançois Tigeot * intel_crtc->ddi_pll_sel. 12171b13d190SFrançois Tigeot * 12181b13d190SFrançois Tigeot * For private DPLLs, compute_config() should do the selection for us. This 12191b13d190SFrançois Tigeot * function should be folded into compute_config() eventually. 12201b13d190SFrançois Tigeot */ 12212c9916cdSFrançois Tigeot bool intel_ddi_pll_select(struct intel_crtc *intel_crtc, 12222c9916cdSFrançois Tigeot struct intel_crtc_state *crtc_state) 12231b13d190SFrançois Tigeot { 12242c9916cdSFrançois Tigeot struct drm_device *dev = intel_crtc->base.dev; 12252c9916cdSFrançois Tigeot struct intel_encoder *intel_encoder = 1226*477eb7f9SFrançois Tigeot intel_ddi_get_crtc_new_encoder(crtc_state); 12272c9916cdSFrançois Tigeot int clock = crtc_state->port_clock; 12281b13d190SFrançois Tigeot 12292c9916cdSFrançois Tigeot if (IS_SKYLAKE(dev)) 12302c9916cdSFrançois Tigeot return skl_ddi_pll_select(intel_crtc, crtc_state, 12312c9916cdSFrançois Tigeot intel_encoder, clock); 12322c9916cdSFrançois Tigeot else 12332c9916cdSFrançois Tigeot return hsw_ddi_pll_select(intel_crtc, crtc_state, 12342c9916cdSFrançois Tigeot intel_encoder, clock); 12351b13d190SFrançois Tigeot } 12361b13d190SFrançois Tigeot 123719df918dSFrançois Tigeot void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) 123819df918dSFrançois Tigeot { 123919df918dSFrançois Tigeot struct drm_i915_private *dev_priv = crtc->dev->dev_private; 124019df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 124119df918dSFrançois Tigeot struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); 12422c9916cdSFrançois Tigeot enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; 124319df918dSFrançois Tigeot int type = intel_encoder->type; 124419df918dSFrançois Tigeot uint32_t temp; 124519df918dSFrançois Tigeot 12462c9916cdSFrançois Tigeot if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) { 124719df918dSFrançois Tigeot temp = TRANS_MSA_SYNC_CLK; 12482c9916cdSFrançois Tigeot switch (intel_crtc->config->pipe_bpp) { 124919df918dSFrançois Tigeot case 18: 125019df918dSFrançois Tigeot temp |= TRANS_MSA_6_BPC; 125119df918dSFrançois Tigeot break; 125219df918dSFrançois Tigeot case 24: 125319df918dSFrançois Tigeot temp |= TRANS_MSA_8_BPC; 125419df918dSFrançois Tigeot break; 125519df918dSFrançois Tigeot case 30: 125619df918dSFrançois Tigeot temp |= TRANS_MSA_10_BPC; 125719df918dSFrançois Tigeot break; 125819df918dSFrançois Tigeot case 36: 125919df918dSFrançois Tigeot temp |= TRANS_MSA_12_BPC; 126019df918dSFrançois Tigeot break; 126119df918dSFrançois Tigeot default: 12628e26cdf6SFrançois Tigeot BUG(); 126319df918dSFrançois Tigeot } 126419df918dSFrançois Tigeot I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp); 126519df918dSFrançois Tigeot } 126619df918dSFrançois Tigeot } 126719df918dSFrançois Tigeot 12681b13d190SFrançois Tigeot void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state) 12691b13d190SFrançois Tigeot { 12701b13d190SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 12711b13d190SFrançois Tigeot struct drm_device *dev = crtc->dev; 12721b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 12732c9916cdSFrançois Tigeot enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; 12741b13d190SFrançois Tigeot uint32_t temp; 12751b13d190SFrançois Tigeot temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); 12761b13d190SFrançois Tigeot if (state == true) 12771b13d190SFrançois Tigeot temp |= TRANS_DDI_DP_VC_PAYLOAD_ALLOC; 12781b13d190SFrançois Tigeot else 12791b13d190SFrançois Tigeot temp &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC; 12801b13d190SFrançois Tigeot I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp); 12811b13d190SFrançois Tigeot } 12821b13d190SFrançois Tigeot 12838e26cdf6SFrançois Tigeot void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) 128419df918dSFrançois Tigeot { 128519df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 128619df918dSFrançois Tigeot struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); 128719df918dSFrançois Tigeot struct drm_encoder *encoder = &intel_encoder->base; 12889edbd4a0SFrançois Tigeot struct drm_device *dev = crtc->dev; 12899edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 129019df918dSFrançois Tigeot enum i915_pipe pipe = intel_crtc->pipe; 12912c9916cdSFrançois Tigeot enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; 129219df918dSFrançois Tigeot enum port port = intel_ddi_get_encoder_port(intel_encoder); 129319df918dSFrançois Tigeot int type = intel_encoder->type; 129419df918dSFrançois Tigeot uint32_t temp; 129519df918dSFrançois Tigeot 129619df918dSFrançois Tigeot /* Enable TRANS_DDI_FUNC_CTL for the pipe to work in HDMI mode */ 129719df918dSFrançois Tigeot temp = TRANS_DDI_FUNC_ENABLE; 129819df918dSFrançois Tigeot temp |= TRANS_DDI_SELECT_PORT(port); 129919df918dSFrançois Tigeot 13002c9916cdSFrançois Tigeot switch (intel_crtc->config->pipe_bpp) { 130119df918dSFrançois Tigeot case 18: 130219df918dSFrançois Tigeot temp |= TRANS_DDI_BPC_6; 130319df918dSFrançois Tigeot break; 130419df918dSFrançois Tigeot case 24: 130519df918dSFrançois Tigeot temp |= TRANS_DDI_BPC_8; 130619df918dSFrançois Tigeot break; 130719df918dSFrançois Tigeot case 30: 130819df918dSFrançois Tigeot temp |= TRANS_DDI_BPC_10; 130919df918dSFrançois Tigeot break; 131019df918dSFrançois Tigeot case 36: 131119df918dSFrançois Tigeot temp |= TRANS_DDI_BPC_12; 131219df918dSFrançois Tigeot break; 131319df918dSFrançois Tigeot default: 13148e26cdf6SFrançois Tigeot BUG(); 131519df918dSFrançois Tigeot } 131619df918dSFrançois Tigeot 13172c9916cdSFrançois Tigeot if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_PVSYNC) 131819df918dSFrançois Tigeot temp |= TRANS_DDI_PVSYNC; 13192c9916cdSFrançois Tigeot if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_PHSYNC) 132019df918dSFrançois Tigeot temp |= TRANS_DDI_PHSYNC; 132119df918dSFrançois Tigeot 132219df918dSFrançois Tigeot if (cpu_transcoder == TRANSCODER_EDP) { 132319df918dSFrançois Tigeot switch (pipe) { 132419df918dSFrançois Tigeot case PIPE_A: 13259edbd4a0SFrançois Tigeot /* On Haswell, can only use the always-on power well for 13269edbd4a0SFrançois Tigeot * eDP when not using the panel fitter, and when not 13279edbd4a0SFrançois Tigeot * using motion blur mitigation (which we don't 13289edbd4a0SFrançois Tigeot * support). */ 132924edb884SFrançois Tigeot if (IS_HASWELL(dev) && 13302c9916cdSFrançois Tigeot (intel_crtc->config->pch_pfit.enabled || 13312c9916cdSFrançois Tigeot intel_crtc->config->pch_pfit.force_thru)) 133219df918dSFrançois Tigeot temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; 1333a2fdbec6SFrançois Tigeot else 1334a2fdbec6SFrançois Tigeot temp |= TRANS_DDI_EDP_INPUT_A_ON; 133519df918dSFrançois Tigeot break; 133619df918dSFrançois Tigeot case PIPE_B: 133719df918dSFrançois Tigeot temp |= TRANS_DDI_EDP_INPUT_B_ONOFF; 133819df918dSFrançois Tigeot break; 133919df918dSFrançois Tigeot case PIPE_C: 134019df918dSFrançois Tigeot temp |= TRANS_DDI_EDP_INPUT_C_ONOFF; 134119df918dSFrançois Tigeot break; 134219df918dSFrançois Tigeot default: 134319df918dSFrançois Tigeot BUG(); 134419df918dSFrançois Tigeot break; 134519df918dSFrançois Tigeot } 134619df918dSFrançois Tigeot } 134719df918dSFrançois Tigeot 134819df918dSFrançois Tigeot if (type == INTEL_OUTPUT_HDMI) { 13492c9916cdSFrançois Tigeot if (intel_crtc->config->has_hdmi_sink) 135019df918dSFrançois Tigeot temp |= TRANS_DDI_MODE_SELECT_HDMI; 135119df918dSFrançois Tigeot else 135219df918dSFrançois Tigeot temp |= TRANS_DDI_MODE_SELECT_DVI; 135319df918dSFrançois Tigeot 135419df918dSFrançois Tigeot } else if (type == INTEL_OUTPUT_ANALOG) { 135519df918dSFrançois Tigeot temp |= TRANS_DDI_MODE_SELECT_FDI; 13562c9916cdSFrançois Tigeot temp |= (intel_crtc->config->fdi_lanes - 1) << 1; 135719df918dSFrançois Tigeot 135819df918dSFrançois Tigeot } else if (type == INTEL_OUTPUT_DISPLAYPORT || 135919df918dSFrançois Tigeot type == INTEL_OUTPUT_EDP) { 136019df918dSFrançois Tigeot struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 136119df918dSFrançois Tigeot 13622c9916cdSFrançois Tigeot if (intel_dp->is_mst) { 13632c9916cdSFrançois Tigeot temp |= TRANS_DDI_MODE_SELECT_DP_MST; 13642c9916cdSFrançois Tigeot } else 13652c9916cdSFrançois Tigeot temp |= TRANS_DDI_MODE_SELECT_DP_SST; 13662c9916cdSFrançois Tigeot 13672c9916cdSFrançois Tigeot temp |= DDI_PORT_WIDTH(intel_dp->lane_count); 13682c9916cdSFrançois Tigeot } else if (type == INTEL_OUTPUT_DP_MST) { 13692c9916cdSFrançois Tigeot struct intel_dp *intel_dp = &enc_to_mst(encoder)->primary->dp; 13702c9916cdSFrançois Tigeot 13712c9916cdSFrançois Tigeot if (intel_dp->is_mst) { 13722c9916cdSFrançois Tigeot temp |= TRANS_DDI_MODE_SELECT_DP_MST; 13732c9916cdSFrançois Tigeot } else 137419df918dSFrançois Tigeot temp |= TRANS_DDI_MODE_SELECT_DP_SST; 137519df918dSFrançois Tigeot 13765d0b1887SFrançois Tigeot temp |= DDI_PORT_WIDTH(intel_dp->lane_count); 137719df918dSFrançois Tigeot } else { 13785d0b1887SFrançois Tigeot WARN(1, "Invalid encoder type %d for pipe %c\n", 13795d0b1887SFrançois Tigeot intel_encoder->type, pipe_name(pipe)); 138019df918dSFrançois Tigeot } 138119df918dSFrançois Tigeot 138219df918dSFrançois Tigeot I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp); 138319df918dSFrançois Tigeot } 138419df918dSFrançois Tigeot 138519df918dSFrançois Tigeot void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, 138619df918dSFrançois Tigeot enum transcoder cpu_transcoder) 138719df918dSFrançois Tigeot { 138819df918dSFrançois Tigeot uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); 138919df918dSFrançois Tigeot uint32_t val = I915_READ(reg); 139019df918dSFrançois Tigeot 13912c9916cdSFrançois Tigeot val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC); 139219df918dSFrançois Tigeot val |= TRANS_DDI_PORT_NONE; 139319df918dSFrançois Tigeot I915_WRITE(reg, val); 139419df918dSFrançois Tigeot } 139519df918dSFrançois Tigeot 139619df918dSFrançois Tigeot bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) 139719df918dSFrançois Tigeot { 139819df918dSFrançois Tigeot struct drm_device *dev = intel_connector->base.dev; 139919df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 140019df918dSFrançois Tigeot struct intel_encoder *intel_encoder = intel_connector->encoder; 140119df918dSFrançois Tigeot int type = intel_connector->base.connector_type; 140219df918dSFrançois Tigeot enum port port = intel_ddi_get_encoder_port(intel_encoder); 140319df918dSFrançois Tigeot enum i915_pipe pipe = 0; 140419df918dSFrançois Tigeot enum transcoder cpu_transcoder; 1405ba55f2f5SFrançois Tigeot enum intel_display_power_domain power_domain; 140619df918dSFrançois Tigeot uint32_t tmp; 140719df918dSFrançois Tigeot 1408ba55f2f5SFrançois Tigeot power_domain = intel_display_port_power_domain(intel_encoder); 14092c9916cdSFrançois Tigeot if (!intel_display_power_is_enabled(dev_priv, power_domain)) 1410ba55f2f5SFrançois Tigeot return false; 1411ba55f2f5SFrançois Tigeot 141219df918dSFrançois Tigeot if (!intel_encoder->get_hw_state(intel_encoder, &pipe)) 141319df918dSFrançois Tigeot return false; 141419df918dSFrançois Tigeot 141519df918dSFrançois Tigeot if (port == PORT_A) 141619df918dSFrançois Tigeot cpu_transcoder = TRANSCODER_EDP; 141719df918dSFrançois Tigeot else 1418a2fdbec6SFrançois Tigeot cpu_transcoder = (enum transcoder) pipe; 141919df918dSFrançois Tigeot 142019df918dSFrançois Tigeot tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); 142119df918dSFrançois Tigeot 142219df918dSFrançois Tigeot switch (tmp & TRANS_DDI_MODE_SELECT_MASK) { 142319df918dSFrançois Tigeot case TRANS_DDI_MODE_SELECT_HDMI: 142419df918dSFrançois Tigeot case TRANS_DDI_MODE_SELECT_DVI: 142519df918dSFrançois Tigeot return (type == DRM_MODE_CONNECTOR_HDMIA); 142619df918dSFrançois Tigeot 142719df918dSFrançois Tigeot case TRANS_DDI_MODE_SELECT_DP_SST: 142819df918dSFrançois Tigeot if (type == DRM_MODE_CONNECTOR_eDP) 142919df918dSFrançois Tigeot return true; 143019df918dSFrançois Tigeot return (type == DRM_MODE_CONNECTOR_DisplayPort); 14312c9916cdSFrançois Tigeot case TRANS_DDI_MODE_SELECT_DP_MST: 14322c9916cdSFrançois Tigeot /* if the transcoder is in MST state then 14332c9916cdSFrançois Tigeot * connector isn't connected */ 14342c9916cdSFrançois Tigeot return false; 143519df918dSFrançois Tigeot 143619df918dSFrançois Tigeot case TRANS_DDI_MODE_SELECT_FDI: 143719df918dSFrançois Tigeot return (type == DRM_MODE_CONNECTOR_VGA); 143819df918dSFrançois Tigeot 143919df918dSFrançois Tigeot default: 144019df918dSFrançois Tigeot return false; 144119df918dSFrançois Tigeot } 144219df918dSFrançois Tigeot } 144319df918dSFrançois Tigeot 144419df918dSFrançois Tigeot bool intel_ddi_get_hw_state(struct intel_encoder *encoder, 144519df918dSFrançois Tigeot enum i915_pipe *pipe) 144619df918dSFrançois Tigeot { 144719df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 144819df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 144919df918dSFrançois Tigeot enum port port = intel_ddi_get_encoder_port(encoder); 1450ba55f2f5SFrançois Tigeot enum intel_display_power_domain power_domain; 145119df918dSFrançois Tigeot u32 tmp; 145219df918dSFrançois Tigeot int i; 145319df918dSFrançois Tigeot 1454ba55f2f5SFrançois Tigeot power_domain = intel_display_port_power_domain(encoder); 14552c9916cdSFrançois Tigeot if (!intel_display_power_is_enabled(dev_priv, power_domain)) 1456ba55f2f5SFrançois Tigeot return false; 1457ba55f2f5SFrançois Tigeot 145819df918dSFrançois Tigeot tmp = I915_READ(DDI_BUF_CTL(port)); 145919df918dSFrançois Tigeot 146019df918dSFrançois Tigeot if (!(tmp & DDI_BUF_CTL_ENABLE)) 146119df918dSFrançois Tigeot return false; 146219df918dSFrançois Tigeot 146319df918dSFrançois Tigeot if (port == PORT_A) { 146419df918dSFrançois Tigeot tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); 146519df918dSFrançois Tigeot 146619df918dSFrançois Tigeot switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { 146719df918dSFrançois Tigeot case TRANS_DDI_EDP_INPUT_A_ON: 146819df918dSFrançois Tigeot case TRANS_DDI_EDP_INPUT_A_ONOFF: 146919df918dSFrançois Tigeot *pipe = PIPE_A; 147019df918dSFrançois Tigeot break; 147119df918dSFrançois Tigeot case TRANS_DDI_EDP_INPUT_B_ONOFF: 147219df918dSFrançois Tigeot *pipe = PIPE_B; 147319df918dSFrançois Tigeot break; 147419df918dSFrançois Tigeot case TRANS_DDI_EDP_INPUT_C_ONOFF: 147519df918dSFrançois Tigeot *pipe = PIPE_C; 147619df918dSFrançois Tigeot break; 147719df918dSFrançois Tigeot } 147819df918dSFrançois Tigeot 147919df918dSFrançois Tigeot return true; 148019df918dSFrançois Tigeot } else { 148119df918dSFrançois Tigeot for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) { 148219df918dSFrançois Tigeot tmp = I915_READ(TRANS_DDI_FUNC_CTL(i)); 148319df918dSFrançois Tigeot 148419df918dSFrançois Tigeot if ((tmp & TRANS_DDI_PORT_MASK) 148519df918dSFrançois Tigeot == TRANS_DDI_SELECT_PORT(port)) { 14862c9916cdSFrançois Tigeot if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == TRANS_DDI_MODE_SELECT_DP_MST) 14872c9916cdSFrançois Tigeot return false; 14882c9916cdSFrançois Tigeot 148919df918dSFrançois Tigeot *pipe = i; 149019df918dSFrançois Tigeot return true; 149119df918dSFrançois Tigeot } 149219df918dSFrançois Tigeot } 149319df918dSFrançois Tigeot } 149419df918dSFrançois Tigeot 14955d0b1887SFrançois Tigeot DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port)); 149619df918dSFrançois Tigeot 14978e26cdf6SFrançois Tigeot return false; 149819df918dSFrançois Tigeot } 149919df918dSFrançois Tigeot 150019df918dSFrançois Tigeot void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) 150119df918dSFrançois Tigeot { 150219df918dSFrançois Tigeot struct drm_crtc *crtc = &intel_crtc->base; 150319df918dSFrançois Tigeot struct drm_i915_private *dev_priv = crtc->dev->dev_private; 150419df918dSFrançois Tigeot struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); 150519df918dSFrançois Tigeot enum port port = intel_ddi_get_encoder_port(intel_encoder); 15062c9916cdSFrançois Tigeot enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; 150719df918dSFrançois Tigeot 150819df918dSFrançois Tigeot if (cpu_transcoder != TRANSCODER_EDP) 150919df918dSFrançois Tigeot I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), 151019df918dSFrançois Tigeot TRANS_CLK_SEL_PORT(port)); 151119df918dSFrançois Tigeot } 151219df918dSFrançois Tigeot 151319df918dSFrançois Tigeot void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) 151419df918dSFrançois Tigeot { 151519df918dSFrançois Tigeot struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; 15162c9916cdSFrançois Tigeot enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; 151719df918dSFrançois Tigeot 151819df918dSFrançois Tigeot if (cpu_transcoder != TRANSCODER_EDP) 151919df918dSFrançois Tigeot I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), 152019df918dSFrançois Tigeot TRANS_CLK_SEL_DISABLED); 152119df918dSFrançois Tigeot } 152219df918dSFrançois Tigeot 152319df918dSFrançois Tigeot static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) 152419df918dSFrançois Tigeot { 152519df918dSFrançois Tigeot struct drm_encoder *encoder = &intel_encoder->base; 15262c9916cdSFrançois Tigeot struct drm_device *dev = encoder->dev; 15272c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1528ba55f2f5SFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); 152919df918dSFrançois Tigeot enum port port = intel_ddi_get_encoder_port(intel_encoder); 153019df918dSFrançois Tigeot int type = intel_encoder->type; 153119df918dSFrançois Tigeot 1532ba55f2f5SFrançois Tigeot if (type == INTEL_OUTPUT_EDP) { 1533ba55f2f5SFrançois Tigeot struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 1534ba55f2f5SFrançois Tigeot intel_edp_panel_on(intel_dp); 1535ba55f2f5SFrançois Tigeot } 1536ba55f2f5SFrançois Tigeot 15372c9916cdSFrançois Tigeot if (IS_SKYLAKE(dev)) { 15382c9916cdSFrançois Tigeot uint32_t dpll = crtc->config->ddi_pll_sel; 15392c9916cdSFrançois Tigeot uint32_t val; 15402c9916cdSFrançois Tigeot 15412c9916cdSFrançois Tigeot /* 15422c9916cdSFrançois Tigeot * DPLL0 is used for eDP and is the only "private" DPLL (as 15432c9916cdSFrançois Tigeot * opposed to shared) on SKL 15442c9916cdSFrançois Tigeot */ 15452c9916cdSFrançois Tigeot if (type == INTEL_OUTPUT_EDP) { 15462c9916cdSFrançois Tigeot WARN_ON(dpll != SKL_DPLL0); 15472c9916cdSFrançois Tigeot 15482c9916cdSFrançois Tigeot val = I915_READ(DPLL_CTRL1); 15492c9916cdSFrançois Tigeot 15502c9916cdSFrançois Tigeot val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | 15512c9916cdSFrançois Tigeot DPLL_CTRL1_SSC(dpll) | 15522c9916cdSFrançois Tigeot DPLL_CRTL1_LINK_RATE_MASK(dpll)); 15532c9916cdSFrançois Tigeot val |= crtc->config->dpll_hw_state.ctrl1 << (dpll * 6); 15542c9916cdSFrançois Tigeot 15552c9916cdSFrançois Tigeot I915_WRITE(DPLL_CTRL1, val); 15562c9916cdSFrançois Tigeot POSTING_READ(DPLL_CTRL1); 15572c9916cdSFrançois Tigeot } 15582c9916cdSFrançois Tigeot 15592c9916cdSFrançois Tigeot /* DDI -> PLL mapping */ 15602c9916cdSFrançois Tigeot val = I915_READ(DPLL_CTRL2); 15612c9916cdSFrançois Tigeot 15622c9916cdSFrançois Tigeot val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) | 15632c9916cdSFrançois Tigeot DPLL_CTRL2_DDI_CLK_SEL_MASK(port)); 15642c9916cdSFrançois Tigeot val |= (DPLL_CTRL2_DDI_CLK_SEL(dpll, port) | 15652c9916cdSFrançois Tigeot DPLL_CTRL2_DDI_SEL_OVERRIDE(port)); 15662c9916cdSFrançois Tigeot 15672c9916cdSFrançois Tigeot I915_WRITE(DPLL_CTRL2, val); 15682c9916cdSFrançois Tigeot 15692c9916cdSFrançois Tigeot } else { 15702c9916cdSFrançois Tigeot WARN_ON(crtc->config->ddi_pll_sel == PORT_CLK_SEL_NONE); 15712c9916cdSFrançois Tigeot I915_WRITE(PORT_CLK_SEL(port), crtc->config->ddi_pll_sel); 15722c9916cdSFrançois Tigeot } 157319df918dSFrançois Tigeot 157419df918dSFrançois Tigeot if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { 157519df918dSFrançois Tigeot struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 1576ba55f2f5SFrançois Tigeot 15771b13d190SFrançois Tigeot intel_ddi_init_dp_buf_reg(intel_encoder); 157819df918dSFrançois Tigeot 157919df918dSFrançois Tigeot intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); 158019df918dSFrançois Tigeot intel_dp_start_link_train(intel_dp); 158119df918dSFrançois Tigeot intel_dp_complete_link_train(intel_dp); 15822c9916cdSFrançois Tigeot if (port != PORT_A || INTEL_INFO(dev)->gen >= 9) 15838e26cdf6SFrançois Tigeot intel_dp_stop_link_train(intel_dp); 1584ba55f2f5SFrançois Tigeot } else if (type == INTEL_OUTPUT_HDMI) { 1585ba55f2f5SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 1586ba55f2f5SFrançois Tigeot 1587ba55f2f5SFrançois Tigeot intel_hdmi->set_infoframes(encoder, 15882c9916cdSFrançois Tigeot crtc->config->has_hdmi_sink, 15892c9916cdSFrançois Tigeot &crtc->config->base.adjusted_mode); 159019df918dSFrançois Tigeot } 159119df918dSFrançois Tigeot } 159219df918dSFrançois Tigeot 159319df918dSFrançois Tigeot static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) 159419df918dSFrançois Tigeot { 159519df918dSFrançois Tigeot struct drm_encoder *encoder = &intel_encoder->base; 15962c9916cdSFrançois Tigeot struct drm_device *dev = encoder->dev; 15972c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 159819df918dSFrançois Tigeot enum port port = intel_ddi_get_encoder_port(intel_encoder); 159919df918dSFrançois Tigeot int type = intel_encoder->type; 160019df918dSFrançois Tigeot uint32_t val; 160119df918dSFrançois Tigeot bool wait = false; 160219df918dSFrançois Tigeot 160319df918dSFrançois Tigeot val = I915_READ(DDI_BUF_CTL(port)); 160419df918dSFrançois Tigeot if (val & DDI_BUF_CTL_ENABLE) { 160519df918dSFrançois Tigeot val &= ~DDI_BUF_CTL_ENABLE; 160619df918dSFrançois Tigeot I915_WRITE(DDI_BUF_CTL(port), val); 160719df918dSFrançois Tigeot wait = true; 160819df918dSFrançois Tigeot } 160919df918dSFrançois Tigeot 161019df918dSFrançois Tigeot val = I915_READ(DP_TP_CTL(port)); 161119df918dSFrançois Tigeot val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); 161219df918dSFrançois Tigeot val |= DP_TP_CTL_LINK_TRAIN_PAT1; 161319df918dSFrançois Tigeot I915_WRITE(DP_TP_CTL(port), val); 161419df918dSFrançois Tigeot 161519df918dSFrançois Tigeot if (wait) 161619df918dSFrançois Tigeot intel_wait_ddi_buf_idle(dev_priv, port); 161719df918dSFrançois Tigeot 16189edbd4a0SFrançois Tigeot if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { 161919df918dSFrançois Tigeot struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 16209edbd4a0SFrançois Tigeot intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); 1621ba55f2f5SFrançois Tigeot intel_edp_panel_vdd_on(intel_dp); 1622ba55f2f5SFrançois Tigeot intel_edp_panel_off(intel_dp); 162319df918dSFrançois Tigeot } 162419df918dSFrançois Tigeot 16252c9916cdSFrançois Tigeot if (IS_SKYLAKE(dev)) 16262c9916cdSFrançois Tigeot I915_WRITE(DPLL_CTRL2, (I915_READ(DPLL_CTRL2) | 16272c9916cdSFrançois Tigeot DPLL_CTRL2_DDI_CLK_OFF(port))); 16282c9916cdSFrançois Tigeot else 162919df918dSFrançois Tigeot I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); 163019df918dSFrançois Tigeot } 163119df918dSFrançois Tigeot 163219df918dSFrançois Tigeot static void intel_enable_ddi(struct intel_encoder *intel_encoder) 163319df918dSFrançois Tigeot { 163419df918dSFrançois Tigeot struct drm_encoder *encoder = &intel_encoder->base; 1635a2fdbec6SFrançois Tigeot struct drm_crtc *crtc = encoder->crtc; 1636a2fdbec6SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 163719df918dSFrançois Tigeot struct drm_device *dev = encoder->dev; 163819df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 163919df918dSFrançois Tigeot enum port port = intel_ddi_get_encoder_port(intel_encoder); 164019df918dSFrançois Tigeot int type = intel_encoder->type; 164119df918dSFrançois Tigeot 164219df918dSFrançois Tigeot if (type == INTEL_OUTPUT_HDMI) { 164319df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = 164419df918dSFrançois Tigeot enc_to_dig_port(encoder); 164519df918dSFrançois Tigeot 164619df918dSFrançois Tigeot /* In HDMI/DVI mode, the port width, and swing/emphasis values 164719df918dSFrançois Tigeot * are ignored so nothing special needs to be done besides 164819df918dSFrançois Tigeot * enabling the port. 164919df918dSFrançois Tigeot */ 165019df918dSFrançois Tigeot I915_WRITE(DDI_BUF_CTL(port), 16515d0b1887SFrançois Tigeot intel_dig_port->saved_port_bits | 16525d0b1887SFrançois Tigeot DDI_BUF_CTL_ENABLE); 165319df918dSFrançois Tigeot } else if (type == INTEL_OUTPUT_EDP) { 165419df918dSFrançois Tigeot struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 165519df918dSFrançois Tigeot 16562c9916cdSFrançois Tigeot if (port == PORT_A && INTEL_INFO(dev)->gen < 9) 16578e26cdf6SFrançois Tigeot intel_dp_stop_link_train(intel_dp); 16588e26cdf6SFrançois Tigeot 1659ba55f2f5SFrançois Tigeot intel_edp_backlight_on(intel_dp); 16602c9916cdSFrançois Tigeot intel_psr_enable(intel_dp); 16612c9916cdSFrançois Tigeot intel_edp_drrs_enable(intel_dp); 166219df918dSFrançois Tigeot } 1663a2fdbec6SFrançois Tigeot 16642c9916cdSFrançois Tigeot if (intel_crtc->config->has_audio) { 1665ba55f2f5SFrançois Tigeot intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); 16662c9916cdSFrançois Tigeot intel_audio_codec_enable(intel_encoder); 1667a2fdbec6SFrançois Tigeot } 166819df918dSFrançois Tigeot } 166919df918dSFrançois Tigeot 167019df918dSFrançois Tigeot static void intel_disable_ddi(struct intel_encoder *intel_encoder) 167119df918dSFrançois Tigeot { 167219df918dSFrançois Tigeot struct drm_encoder *encoder = &intel_encoder->base; 1673a2fdbec6SFrançois Tigeot struct drm_crtc *crtc = encoder->crtc; 1674a2fdbec6SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 167519df918dSFrançois Tigeot int type = intel_encoder->type; 1676a2fdbec6SFrançois Tigeot struct drm_device *dev = encoder->dev; 1677a2fdbec6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 167819df918dSFrançois Tigeot 16792c9916cdSFrançois Tigeot if (intel_crtc->config->has_audio) { 16802c9916cdSFrançois Tigeot intel_audio_codec_disable(intel_encoder); 1681ba55f2f5SFrançois Tigeot intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); 16825d0b1887SFrançois Tigeot } 16838e26cdf6SFrançois Tigeot 168419df918dSFrançois Tigeot if (type == INTEL_OUTPUT_EDP) { 168519df918dSFrançois Tigeot struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 168619df918dSFrançois Tigeot 16872c9916cdSFrançois Tigeot intel_edp_drrs_disable(intel_dp); 16882c9916cdSFrançois Tigeot intel_psr_disable(intel_dp); 1689ba55f2f5SFrançois Tigeot intel_edp_backlight_off(intel_dp); 169019df918dSFrançois Tigeot } 169119df918dSFrançois Tigeot } 169219df918dSFrançois Tigeot 16932c9916cdSFrançois Tigeot static int skl_get_cdclk_freq(struct drm_i915_private *dev_priv) 16942c9916cdSFrançois Tigeot { 16952c9916cdSFrançois Tigeot uint32_t lcpll1 = I915_READ(LCPLL1_CTL); 16962c9916cdSFrançois Tigeot uint32_t cdctl = I915_READ(CDCLK_CTL); 16972c9916cdSFrançois Tigeot uint32_t linkrate; 16982c9916cdSFrançois Tigeot 16992c9916cdSFrançois Tigeot if (!(lcpll1 & LCPLL_PLL_ENABLE)) { 17002c9916cdSFrançois Tigeot WARN(1, "LCPLL1 not enabled\n"); 17012c9916cdSFrançois Tigeot return 24000; /* 24MHz is the cd freq with NSSC ref */ 17022c9916cdSFrançois Tigeot } 17032c9916cdSFrançois Tigeot 17042c9916cdSFrançois Tigeot if ((cdctl & CDCLK_FREQ_SEL_MASK) == CDCLK_FREQ_540) 17052c9916cdSFrançois Tigeot return 540000; 17062c9916cdSFrançois Tigeot 17072c9916cdSFrançois Tigeot linkrate = (I915_READ(DPLL_CTRL1) & 17082c9916cdSFrançois Tigeot DPLL_CRTL1_LINK_RATE_MASK(SKL_DPLL0)) >> 1; 17092c9916cdSFrançois Tigeot 17102c9916cdSFrançois Tigeot if (linkrate == DPLL_CRTL1_LINK_RATE_2160 || 17112c9916cdSFrançois Tigeot linkrate == DPLL_CRTL1_LINK_RATE_1080) { 17122c9916cdSFrançois Tigeot /* vco 8640 */ 17132c9916cdSFrançois Tigeot switch (cdctl & CDCLK_FREQ_SEL_MASK) { 17142c9916cdSFrançois Tigeot case CDCLK_FREQ_450_432: 17152c9916cdSFrançois Tigeot return 432000; 17162c9916cdSFrançois Tigeot case CDCLK_FREQ_337_308: 17172c9916cdSFrançois Tigeot return 308570; 17182c9916cdSFrançois Tigeot case CDCLK_FREQ_675_617: 17192c9916cdSFrançois Tigeot return 617140; 17202c9916cdSFrançois Tigeot default: 17212c9916cdSFrançois Tigeot WARN(1, "Unknown cd freq selection\n"); 17222c9916cdSFrançois Tigeot } 17232c9916cdSFrançois Tigeot } else { 17242c9916cdSFrançois Tigeot /* vco 8100 */ 17252c9916cdSFrançois Tigeot switch (cdctl & CDCLK_FREQ_SEL_MASK) { 17262c9916cdSFrançois Tigeot case CDCLK_FREQ_450_432: 17272c9916cdSFrançois Tigeot return 450000; 17282c9916cdSFrançois Tigeot case CDCLK_FREQ_337_308: 17292c9916cdSFrançois Tigeot return 337500; 17302c9916cdSFrançois Tigeot case CDCLK_FREQ_675_617: 17312c9916cdSFrançois Tigeot return 675000; 17322c9916cdSFrançois Tigeot default: 17332c9916cdSFrançois Tigeot WARN(1, "Unknown cd freq selection\n"); 17342c9916cdSFrançois Tigeot } 17352c9916cdSFrançois Tigeot } 17362c9916cdSFrançois Tigeot 17372c9916cdSFrançois Tigeot /* error case, do as if DPLL0 isn't enabled */ 17382c9916cdSFrançois Tigeot return 24000; 17392c9916cdSFrançois Tigeot } 17402c9916cdSFrançois Tigeot 17411b13d190SFrançois Tigeot static int bdw_get_cdclk_freq(struct drm_i915_private *dev_priv) 174219df918dSFrançois Tigeot { 17439edbd4a0SFrançois Tigeot uint32_t lcpll = I915_READ(LCPLL_CTL); 17449edbd4a0SFrançois Tigeot uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK; 17459edbd4a0SFrançois Tigeot 17461b13d190SFrançois Tigeot if (lcpll & LCPLL_CD_SOURCE_FCLK) 17479edbd4a0SFrançois Tigeot return 800000; 17481b13d190SFrançois Tigeot else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) 17495d0b1887SFrançois Tigeot return 450000; 17501b13d190SFrançois Tigeot else if (freq == LCPLL_CLK_FREQ_450) 17515d0b1887SFrançois Tigeot return 450000; 17521b13d190SFrançois Tigeot else if (freq == LCPLL_CLK_FREQ_54O_BDW) 17539edbd4a0SFrançois Tigeot return 540000; 17549edbd4a0SFrançois Tigeot else if (freq == LCPLL_CLK_FREQ_337_5_BDW) 17559edbd4a0SFrançois Tigeot return 337500; 17569edbd4a0SFrançois Tigeot else 17579edbd4a0SFrançois Tigeot return 675000; 17589edbd4a0SFrançois Tigeot } 17591b13d190SFrançois Tigeot 17601b13d190SFrançois Tigeot static int hsw_get_cdclk_freq(struct drm_i915_private *dev_priv) 17611b13d190SFrançois Tigeot { 17621b13d190SFrançois Tigeot struct drm_device *dev = dev_priv->dev; 17631b13d190SFrançois Tigeot uint32_t lcpll = I915_READ(LCPLL_CTL); 17641b13d190SFrançois Tigeot uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK; 17651b13d190SFrançois Tigeot 17661b13d190SFrançois Tigeot if (lcpll & LCPLL_CD_SOURCE_FCLK) 17671b13d190SFrançois Tigeot return 800000; 17681b13d190SFrançois Tigeot else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) 17691b13d190SFrançois Tigeot return 450000; 17701b13d190SFrançois Tigeot else if (freq == LCPLL_CLK_FREQ_450) 17711b13d190SFrançois Tigeot return 450000; 17722c9916cdSFrançois Tigeot else if (IS_HSW_ULT(dev)) 17731b13d190SFrançois Tigeot return 337500; 17741b13d190SFrançois Tigeot else 17751b13d190SFrançois Tigeot return 540000; 17761b13d190SFrançois Tigeot } 17771b13d190SFrançois Tigeot 17781b13d190SFrançois Tigeot int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) 17791b13d190SFrançois Tigeot { 17801b13d190SFrançois Tigeot struct drm_device *dev = dev_priv->dev; 17811b13d190SFrançois Tigeot 17822c9916cdSFrançois Tigeot if (IS_SKYLAKE(dev)) 17832c9916cdSFrançois Tigeot return skl_get_cdclk_freq(dev_priv); 17842c9916cdSFrançois Tigeot 17851b13d190SFrançois Tigeot if (IS_BROADWELL(dev)) 17861b13d190SFrançois Tigeot return bdw_get_cdclk_freq(dev_priv); 17871b13d190SFrançois Tigeot 17881b13d190SFrançois Tigeot /* Haswell */ 17891b13d190SFrançois Tigeot return hsw_get_cdclk_freq(dev_priv); 179019df918dSFrançois Tigeot } 179119df918dSFrançois Tigeot 179224edb884SFrançois Tigeot static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv, 179324edb884SFrançois Tigeot struct intel_shared_dpll *pll) 179424edb884SFrançois Tigeot { 17952c9916cdSFrançois Tigeot I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll); 179624edb884SFrançois Tigeot POSTING_READ(WRPLL_CTL(pll->id)); 179724edb884SFrançois Tigeot udelay(20); 179824edb884SFrançois Tigeot } 179924edb884SFrançois Tigeot 180024edb884SFrançois Tigeot static void hsw_ddi_pll_disable(struct drm_i915_private *dev_priv, 180124edb884SFrançois Tigeot struct intel_shared_dpll *pll) 180224edb884SFrançois Tigeot { 180324edb884SFrançois Tigeot uint32_t val; 180424edb884SFrançois Tigeot 180524edb884SFrançois Tigeot val = I915_READ(WRPLL_CTL(pll->id)); 180624edb884SFrançois Tigeot I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE); 180724edb884SFrançois Tigeot POSTING_READ(WRPLL_CTL(pll->id)); 180824edb884SFrançois Tigeot } 180924edb884SFrançois Tigeot 181024edb884SFrançois Tigeot static bool hsw_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, 181124edb884SFrançois Tigeot struct intel_shared_dpll *pll, 181224edb884SFrançois Tigeot struct intel_dpll_hw_state *hw_state) 181324edb884SFrançois Tigeot { 181424edb884SFrançois Tigeot uint32_t val; 181524edb884SFrançois Tigeot 18162c9916cdSFrançois Tigeot if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS)) 181724edb884SFrançois Tigeot return false; 181824edb884SFrançois Tigeot 181924edb884SFrançois Tigeot val = I915_READ(WRPLL_CTL(pll->id)); 182024edb884SFrançois Tigeot hw_state->wrpll = val; 182124edb884SFrançois Tigeot 182224edb884SFrançois Tigeot return val & WRPLL_PLL_ENABLE; 182324edb884SFrançois Tigeot } 182424edb884SFrançois Tigeot 182524edb884SFrançois Tigeot static const char * const hsw_ddi_pll_names[] = { 182624edb884SFrançois Tigeot "WRPLL 1", 182724edb884SFrançois Tigeot "WRPLL 2", 182824edb884SFrançois Tigeot }; 182924edb884SFrançois Tigeot 18301b13d190SFrançois Tigeot static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv) 183119df918dSFrançois Tigeot { 183224edb884SFrançois Tigeot int i; 183324edb884SFrançois Tigeot 183424edb884SFrançois Tigeot dev_priv->num_shared_dpll = 2; 183524edb884SFrançois Tigeot 183624edb884SFrançois Tigeot for (i = 0; i < dev_priv->num_shared_dpll; i++) { 183724edb884SFrançois Tigeot dev_priv->shared_dplls[i].id = i; 183824edb884SFrançois Tigeot dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i]; 183924edb884SFrançois Tigeot dev_priv->shared_dplls[i].disable = hsw_ddi_pll_disable; 184024edb884SFrançois Tigeot dev_priv->shared_dplls[i].enable = hsw_ddi_pll_enable; 184124edb884SFrançois Tigeot dev_priv->shared_dplls[i].get_hw_state = 184224edb884SFrançois Tigeot hsw_ddi_pll_get_hw_state; 184324edb884SFrançois Tigeot } 18441b13d190SFrançois Tigeot } 18451b13d190SFrançois Tigeot 18462c9916cdSFrançois Tigeot static const char * const skl_ddi_pll_names[] = { 18472c9916cdSFrançois Tigeot "DPLL 1", 18482c9916cdSFrançois Tigeot "DPLL 2", 18492c9916cdSFrançois Tigeot "DPLL 3", 18502c9916cdSFrançois Tigeot }; 18512c9916cdSFrançois Tigeot 18522c9916cdSFrançois Tigeot struct skl_dpll_regs { 18532c9916cdSFrançois Tigeot u32 ctl, cfgcr1, cfgcr2; 18542c9916cdSFrançois Tigeot }; 18552c9916cdSFrançois Tigeot 18562c9916cdSFrançois Tigeot /* this array is indexed by the *shared* pll id */ 18572c9916cdSFrançois Tigeot static const struct skl_dpll_regs skl_dpll_regs[3] = { 18582c9916cdSFrançois Tigeot { 18592c9916cdSFrançois Tigeot /* DPLL 1 */ 18602c9916cdSFrançois Tigeot .ctl = LCPLL2_CTL, 18612c9916cdSFrançois Tigeot .cfgcr1 = DPLL1_CFGCR1, 18622c9916cdSFrançois Tigeot .cfgcr2 = DPLL1_CFGCR2, 18632c9916cdSFrançois Tigeot }, 18642c9916cdSFrançois Tigeot { 18652c9916cdSFrançois Tigeot /* DPLL 2 */ 18662c9916cdSFrançois Tigeot .ctl = WRPLL_CTL1, 18672c9916cdSFrançois Tigeot .cfgcr1 = DPLL2_CFGCR1, 18682c9916cdSFrançois Tigeot .cfgcr2 = DPLL2_CFGCR2, 18692c9916cdSFrançois Tigeot }, 18702c9916cdSFrançois Tigeot { 18712c9916cdSFrançois Tigeot /* DPLL 3 */ 18722c9916cdSFrançois Tigeot .ctl = WRPLL_CTL2, 18732c9916cdSFrançois Tigeot .cfgcr1 = DPLL3_CFGCR1, 18742c9916cdSFrançois Tigeot .cfgcr2 = DPLL3_CFGCR2, 18752c9916cdSFrançois Tigeot }, 18762c9916cdSFrançois Tigeot }; 18772c9916cdSFrançois Tigeot 18782c9916cdSFrançois Tigeot static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv, 18792c9916cdSFrançois Tigeot struct intel_shared_dpll *pll) 18802c9916cdSFrançois Tigeot { 18812c9916cdSFrançois Tigeot uint32_t val; 18822c9916cdSFrançois Tigeot unsigned int dpll; 18832c9916cdSFrançois Tigeot const struct skl_dpll_regs *regs = skl_dpll_regs; 18842c9916cdSFrançois Tigeot 18852c9916cdSFrançois Tigeot /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */ 18862c9916cdSFrançois Tigeot dpll = pll->id + 1; 18872c9916cdSFrançois Tigeot 18882c9916cdSFrançois Tigeot val = I915_READ(DPLL_CTRL1); 18892c9916cdSFrançois Tigeot 18902c9916cdSFrançois Tigeot val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) | 18912c9916cdSFrançois Tigeot DPLL_CRTL1_LINK_RATE_MASK(dpll)); 18922c9916cdSFrançois Tigeot val |= pll->config.hw_state.ctrl1 << (dpll * 6); 18932c9916cdSFrançois Tigeot 18942c9916cdSFrançois Tigeot I915_WRITE(DPLL_CTRL1, val); 18952c9916cdSFrançois Tigeot POSTING_READ(DPLL_CTRL1); 18962c9916cdSFrançois Tigeot 18972c9916cdSFrançois Tigeot I915_WRITE(regs[pll->id].cfgcr1, pll->config.hw_state.cfgcr1); 18982c9916cdSFrançois Tigeot I915_WRITE(regs[pll->id].cfgcr2, pll->config.hw_state.cfgcr2); 18992c9916cdSFrançois Tigeot POSTING_READ(regs[pll->id].cfgcr1); 19002c9916cdSFrançois Tigeot POSTING_READ(regs[pll->id].cfgcr2); 19012c9916cdSFrançois Tigeot 19022c9916cdSFrançois Tigeot /* the enable bit is always bit 31 */ 19032c9916cdSFrançois Tigeot I915_WRITE(regs[pll->id].ctl, 19042c9916cdSFrançois Tigeot I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE); 19052c9916cdSFrançois Tigeot 19062c9916cdSFrançois Tigeot if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(dpll), 5)) 19072c9916cdSFrançois Tigeot DRM_ERROR("DPLL %d not locked\n", dpll); 19082c9916cdSFrançois Tigeot } 19092c9916cdSFrançois Tigeot 19102c9916cdSFrançois Tigeot static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv, 19112c9916cdSFrançois Tigeot struct intel_shared_dpll *pll) 19122c9916cdSFrançois Tigeot { 19132c9916cdSFrançois Tigeot const struct skl_dpll_regs *regs = skl_dpll_regs; 19142c9916cdSFrançois Tigeot 19152c9916cdSFrançois Tigeot /* the enable bit is always bit 31 */ 19162c9916cdSFrançois Tigeot I915_WRITE(regs[pll->id].ctl, 19172c9916cdSFrançois Tigeot I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE); 19182c9916cdSFrançois Tigeot POSTING_READ(regs[pll->id].ctl); 19192c9916cdSFrançois Tigeot } 19202c9916cdSFrançois Tigeot 19212c9916cdSFrançois Tigeot static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, 19222c9916cdSFrançois Tigeot struct intel_shared_dpll *pll, 19232c9916cdSFrançois Tigeot struct intel_dpll_hw_state *hw_state) 19242c9916cdSFrançois Tigeot { 19252c9916cdSFrançois Tigeot uint32_t val; 19262c9916cdSFrançois Tigeot unsigned int dpll; 19272c9916cdSFrançois Tigeot const struct skl_dpll_regs *regs = skl_dpll_regs; 19282c9916cdSFrançois Tigeot 19292c9916cdSFrançois Tigeot if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS)) 19302c9916cdSFrançois Tigeot return false; 19312c9916cdSFrançois Tigeot 19322c9916cdSFrançois Tigeot /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */ 19332c9916cdSFrançois Tigeot dpll = pll->id + 1; 19342c9916cdSFrançois Tigeot 19352c9916cdSFrançois Tigeot val = I915_READ(regs[pll->id].ctl); 19362c9916cdSFrançois Tigeot if (!(val & LCPLL_PLL_ENABLE)) 19372c9916cdSFrançois Tigeot return false; 19382c9916cdSFrançois Tigeot 19392c9916cdSFrançois Tigeot val = I915_READ(DPLL_CTRL1); 19402c9916cdSFrançois Tigeot hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f; 19412c9916cdSFrançois Tigeot 19422c9916cdSFrançois Tigeot /* avoid reading back stale values if HDMI mode is not enabled */ 19432c9916cdSFrançois Tigeot if (val & DPLL_CTRL1_HDMI_MODE(dpll)) { 19442c9916cdSFrançois Tigeot hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1); 19452c9916cdSFrançois Tigeot hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2); 19462c9916cdSFrançois Tigeot } 19472c9916cdSFrançois Tigeot 19482c9916cdSFrançois Tigeot return true; 19492c9916cdSFrançois Tigeot } 19502c9916cdSFrançois Tigeot 19512c9916cdSFrançois Tigeot static void skl_shared_dplls_init(struct drm_i915_private *dev_priv) 19522c9916cdSFrançois Tigeot { 19532c9916cdSFrançois Tigeot int i; 19542c9916cdSFrançois Tigeot 19552c9916cdSFrançois Tigeot dev_priv->num_shared_dpll = 3; 19562c9916cdSFrançois Tigeot 19572c9916cdSFrançois Tigeot for (i = 0; i < dev_priv->num_shared_dpll; i++) { 19582c9916cdSFrançois Tigeot dev_priv->shared_dplls[i].id = i; 19592c9916cdSFrançois Tigeot dev_priv->shared_dplls[i].name = skl_ddi_pll_names[i]; 19602c9916cdSFrançois Tigeot dev_priv->shared_dplls[i].disable = skl_ddi_pll_disable; 19612c9916cdSFrançois Tigeot dev_priv->shared_dplls[i].enable = skl_ddi_pll_enable; 19622c9916cdSFrançois Tigeot dev_priv->shared_dplls[i].get_hw_state = 19632c9916cdSFrançois Tigeot skl_ddi_pll_get_hw_state; 19642c9916cdSFrançois Tigeot } 19652c9916cdSFrançois Tigeot } 19662c9916cdSFrançois Tigeot 19671b13d190SFrançois Tigeot void intel_ddi_pll_init(struct drm_device *dev) 19681b13d190SFrançois Tigeot { 19691b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 19701b13d190SFrançois Tigeot uint32_t val = I915_READ(LCPLL_CTL); 19711b13d190SFrançois Tigeot 19722c9916cdSFrançois Tigeot if (IS_SKYLAKE(dev)) 19732c9916cdSFrançois Tigeot skl_shared_dplls_init(dev_priv); 19742c9916cdSFrançois Tigeot else 19751b13d190SFrançois Tigeot hsw_shared_dplls_init(dev_priv); 197619df918dSFrançois Tigeot 19775d0b1887SFrançois Tigeot DRM_DEBUG_KMS("CDCLK running at %dKHz\n", 197819df918dSFrançois Tigeot intel_ddi_get_cdclk_freq(dev_priv)); 197919df918dSFrançois Tigeot 19802c9916cdSFrançois Tigeot if (IS_SKYLAKE(dev)) { 19812c9916cdSFrançois Tigeot if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) 19822c9916cdSFrançois Tigeot DRM_ERROR("LCPLL1 is disabled\n"); 19832c9916cdSFrançois Tigeot } else { 19842c9916cdSFrançois Tigeot /* 19852c9916cdSFrançois Tigeot * The LCPLL register should be turned on by the BIOS. For now 19862c9916cdSFrançois Tigeot * let's just check its state and print errors in case 19872c9916cdSFrançois Tigeot * something is wrong. Don't even try to turn it on. 19882c9916cdSFrançois Tigeot */ 19892c9916cdSFrançois Tigeot 199019df918dSFrançois Tigeot if (val & LCPLL_CD_SOURCE_FCLK) 199119df918dSFrançois Tigeot DRM_ERROR("CDCLK source is not LCPLL\n"); 199219df918dSFrançois Tigeot 199319df918dSFrançois Tigeot if (val & LCPLL_PLL_DISABLE) 199419df918dSFrançois Tigeot DRM_ERROR("LCPLL is disabled\n"); 199519df918dSFrançois Tigeot } 19962c9916cdSFrançois Tigeot } 199719df918dSFrançois Tigeot 199819df918dSFrançois Tigeot void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) 199919df918dSFrançois Tigeot { 200019df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 200119df918dSFrançois Tigeot struct intel_dp *intel_dp = &intel_dig_port->dp; 200219df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 200319df918dSFrançois Tigeot enum port port = intel_dig_port->port; 200419df918dSFrançois Tigeot uint32_t val; 2005a2fdbec6SFrançois Tigeot bool wait = false; 200619df918dSFrançois Tigeot 200719df918dSFrançois Tigeot if (I915_READ(DP_TP_CTL(port)) & DP_TP_CTL_ENABLE) { 200819df918dSFrançois Tigeot val = I915_READ(DDI_BUF_CTL(port)); 200919df918dSFrançois Tigeot if (val & DDI_BUF_CTL_ENABLE) { 201019df918dSFrançois Tigeot val &= ~DDI_BUF_CTL_ENABLE; 201119df918dSFrançois Tigeot I915_WRITE(DDI_BUF_CTL(port), val); 201219df918dSFrançois Tigeot wait = true; 201319df918dSFrançois Tigeot } 201419df918dSFrançois Tigeot 201519df918dSFrançois Tigeot val = I915_READ(DP_TP_CTL(port)); 201619df918dSFrançois Tigeot val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); 201719df918dSFrançois Tigeot val |= DP_TP_CTL_LINK_TRAIN_PAT1; 201819df918dSFrançois Tigeot I915_WRITE(DP_TP_CTL(port), val); 201919df918dSFrançois Tigeot POSTING_READ(DP_TP_CTL(port)); 202019df918dSFrançois Tigeot 202119df918dSFrançois Tigeot if (wait) 202219df918dSFrançois Tigeot intel_wait_ddi_buf_idle(dev_priv, port); 202319df918dSFrançois Tigeot } 202419df918dSFrançois Tigeot 20252c9916cdSFrançois Tigeot val = DP_TP_CTL_ENABLE | 202619df918dSFrançois Tigeot DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE; 20272c9916cdSFrançois Tigeot if (intel_dp->is_mst) 20282c9916cdSFrançois Tigeot val |= DP_TP_CTL_MODE_MST; 20292c9916cdSFrançois Tigeot else { 20302c9916cdSFrançois Tigeot val |= DP_TP_CTL_MODE_SST; 20319edbd4a0SFrançois Tigeot if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) 203219df918dSFrançois Tigeot val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; 20332c9916cdSFrançois Tigeot } 203419df918dSFrançois Tigeot I915_WRITE(DP_TP_CTL(port), val); 203519df918dSFrançois Tigeot POSTING_READ(DP_TP_CTL(port)); 203619df918dSFrançois Tigeot 203719df918dSFrançois Tigeot intel_dp->DP |= DDI_BUF_CTL_ENABLE; 203819df918dSFrançois Tigeot I915_WRITE(DDI_BUF_CTL(port), intel_dp->DP); 203919df918dSFrançois Tigeot POSTING_READ(DDI_BUF_CTL(port)); 204019df918dSFrançois Tigeot 204119df918dSFrançois Tigeot udelay(600); 204219df918dSFrançois Tigeot } 204319df918dSFrançois Tigeot 204419df918dSFrançois Tigeot void intel_ddi_fdi_disable(struct drm_crtc *crtc) 204519df918dSFrançois Tigeot { 204619df918dSFrançois Tigeot struct drm_i915_private *dev_priv = crtc->dev->dev_private; 204719df918dSFrançois Tigeot struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); 204819df918dSFrançois Tigeot uint32_t val; 204919df918dSFrançois Tigeot 205019df918dSFrançois Tigeot intel_ddi_post_disable(intel_encoder); 205119df918dSFrançois Tigeot 205219df918dSFrançois Tigeot val = I915_READ(_FDI_RXA_CTL); 205319df918dSFrançois Tigeot val &= ~FDI_RX_ENABLE; 205419df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_CTL, val); 205519df918dSFrançois Tigeot 205619df918dSFrançois Tigeot val = I915_READ(_FDI_RXA_MISC); 205719df918dSFrançois Tigeot val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); 205819df918dSFrançois Tigeot val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); 205919df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_MISC, val); 206019df918dSFrançois Tigeot 206119df918dSFrançois Tigeot val = I915_READ(_FDI_RXA_CTL); 206219df918dSFrançois Tigeot val &= ~FDI_PCDCLK; 206319df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_CTL, val); 206419df918dSFrançois Tigeot 206519df918dSFrançois Tigeot val = I915_READ(_FDI_RXA_CTL); 206619df918dSFrançois Tigeot val &= ~FDI_RX_PLL_ENABLE; 206719df918dSFrançois Tigeot I915_WRITE(_FDI_RXA_CTL, val); 206819df918dSFrançois Tigeot } 206919df918dSFrançois Tigeot 207019df918dSFrançois Tigeot static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) 207119df918dSFrançois Tigeot { 20722c9916cdSFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(&intel_encoder->base); 20732c9916cdSFrançois Tigeot int type = intel_dig_port->base.type; 207419df918dSFrançois Tigeot 20752c9916cdSFrançois Tigeot if (type != INTEL_OUTPUT_DISPLAYPORT && 20762c9916cdSFrançois Tigeot type != INTEL_OUTPUT_EDP && 20772c9916cdSFrançois Tigeot type != INTEL_OUTPUT_UNKNOWN) { 20782c9916cdSFrançois Tigeot return; 20792c9916cdSFrançois Tigeot } 20802c9916cdSFrançois Tigeot 20812c9916cdSFrançois Tigeot intel_dp_hot_plug(intel_encoder); 208219df918dSFrançois Tigeot } 208319df918dSFrançois Tigeot 20849edbd4a0SFrançois Tigeot void intel_ddi_get_config(struct intel_encoder *encoder, 20852c9916cdSFrançois Tigeot struct intel_crtc_state *pipe_config) 20865d0b1887SFrançois Tigeot { 20875d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 20885d0b1887SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); 20892c9916cdSFrançois Tigeot enum transcoder cpu_transcoder = pipe_config->cpu_transcoder; 20902c9916cdSFrançois Tigeot struct intel_hdmi *intel_hdmi; 20915d0b1887SFrançois Tigeot u32 temp, flags = 0; 20925d0b1887SFrançois Tigeot 20935d0b1887SFrançois Tigeot temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); 20945d0b1887SFrançois Tigeot if (temp & TRANS_DDI_PHSYNC) 20955d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PHSYNC; 20965d0b1887SFrançois Tigeot else 20975d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NHSYNC; 20985d0b1887SFrançois Tigeot if (temp & TRANS_DDI_PVSYNC) 20995d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PVSYNC; 21005d0b1887SFrançois Tigeot else 21015d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NVSYNC; 21025d0b1887SFrançois Tigeot 21032c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.flags |= flags; 21049edbd4a0SFrançois Tigeot 21059edbd4a0SFrançois Tigeot switch (temp & TRANS_DDI_BPC_MASK) { 21069edbd4a0SFrançois Tigeot case TRANS_DDI_BPC_6: 21079edbd4a0SFrançois Tigeot pipe_config->pipe_bpp = 18; 21089edbd4a0SFrançois Tigeot break; 21099edbd4a0SFrançois Tigeot case TRANS_DDI_BPC_8: 21109edbd4a0SFrançois Tigeot pipe_config->pipe_bpp = 24; 21119edbd4a0SFrançois Tigeot break; 21129edbd4a0SFrançois Tigeot case TRANS_DDI_BPC_10: 21139edbd4a0SFrançois Tigeot pipe_config->pipe_bpp = 30; 21149edbd4a0SFrançois Tigeot break; 21159edbd4a0SFrançois Tigeot case TRANS_DDI_BPC_12: 21169edbd4a0SFrançois Tigeot pipe_config->pipe_bpp = 36; 21179edbd4a0SFrançois Tigeot break; 21189edbd4a0SFrançois Tigeot default: 21199edbd4a0SFrançois Tigeot break; 21209edbd4a0SFrançois Tigeot } 21219edbd4a0SFrançois Tigeot 21229edbd4a0SFrançois Tigeot switch (temp & TRANS_DDI_MODE_SELECT_MASK) { 21239edbd4a0SFrançois Tigeot case TRANS_DDI_MODE_SELECT_HDMI: 2124ba55f2f5SFrançois Tigeot pipe_config->has_hdmi_sink = true; 21252c9916cdSFrançois Tigeot intel_hdmi = enc_to_intel_hdmi(&encoder->base); 21262c9916cdSFrançois Tigeot 21272c9916cdSFrançois Tigeot if (intel_hdmi->infoframe_enabled(&encoder->base)) 21282c9916cdSFrançois Tigeot pipe_config->has_infoframe = true; 21292c9916cdSFrançois Tigeot break; 21309edbd4a0SFrançois Tigeot case TRANS_DDI_MODE_SELECT_DVI: 21319edbd4a0SFrançois Tigeot case TRANS_DDI_MODE_SELECT_FDI: 21329edbd4a0SFrançois Tigeot break; 21339edbd4a0SFrançois Tigeot case TRANS_DDI_MODE_SELECT_DP_SST: 21349edbd4a0SFrançois Tigeot case TRANS_DDI_MODE_SELECT_DP_MST: 21359edbd4a0SFrançois Tigeot pipe_config->has_dp_encoder = true; 21369edbd4a0SFrançois Tigeot intel_dp_get_m_n(intel_crtc, pipe_config); 21379edbd4a0SFrançois Tigeot break; 21389edbd4a0SFrançois Tigeot default: 21399edbd4a0SFrançois Tigeot break; 21409edbd4a0SFrançois Tigeot } 21419edbd4a0SFrançois Tigeot 21422c9916cdSFrançois Tigeot if (intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_AUDIO)) { 2143ba55f2f5SFrançois Tigeot temp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); 21442c9916cdSFrançois Tigeot if (temp & AUDIO_OUTPUT_ENABLE(intel_crtc->pipe)) 2145ba55f2f5SFrançois Tigeot pipe_config->has_audio = true; 2146ba55f2f5SFrançois Tigeot } 2147ba55f2f5SFrançois Tigeot 21489edbd4a0SFrançois Tigeot if (encoder->type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp_bpp && 21499edbd4a0SFrançois Tigeot pipe_config->pipe_bpp > dev_priv->vbt.edp_bpp) { 21509edbd4a0SFrançois Tigeot /* 21519edbd4a0SFrançois Tigeot * This is a big fat ugly hack. 21529edbd4a0SFrançois Tigeot * 21539edbd4a0SFrançois Tigeot * Some machines in UEFI boot mode provide us a VBT that has 18 21549edbd4a0SFrançois Tigeot * bpp and 1.62 GHz link bandwidth for eDP, which for reasons 21559edbd4a0SFrançois Tigeot * unknown we fail to light up. Yet the same BIOS boots up with 21569edbd4a0SFrançois Tigeot * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as 21579edbd4a0SFrançois Tigeot * max, not what it tells us to use. 21589edbd4a0SFrançois Tigeot * 21599edbd4a0SFrançois Tigeot * Note: This will still be broken if the eDP panel is not lit 21609edbd4a0SFrançois Tigeot * up by the BIOS, and thus we can't get the mode at module 21619edbd4a0SFrançois Tigeot * load. 21629edbd4a0SFrançois Tigeot */ 21639edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n", 21649edbd4a0SFrançois Tigeot pipe_config->pipe_bpp, dev_priv->vbt.edp_bpp); 21659edbd4a0SFrançois Tigeot dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp; 21669edbd4a0SFrançois Tigeot } 2167ba55f2f5SFrançois Tigeot 21682c9916cdSFrançois Tigeot intel_ddi_clock_get(encoder, pipe_config); 21695d0b1887SFrançois Tigeot } 21705d0b1887SFrançois Tigeot 217119df918dSFrançois Tigeot static void intel_ddi_destroy(struct drm_encoder *encoder) 217219df918dSFrançois Tigeot { 217319df918dSFrançois Tigeot /* HDMI has nothing special to destroy, so we can go with this. */ 217419df918dSFrançois Tigeot intel_dp_encoder_destroy(encoder); 217519df918dSFrançois Tigeot } 217619df918dSFrançois Tigeot 21778e26cdf6SFrançois Tigeot static bool intel_ddi_compute_config(struct intel_encoder *encoder, 21782c9916cdSFrançois Tigeot struct intel_crtc_state *pipe_config) 217919df918dSFrançois Tigeot { 21808e26cdf6SFrançois Tigeot int type = encoder->type; 21815d0b1887SFrançois Tigeot int port = intel_ddi_get_encoder_port(encoder); 218219df918dSFrançois Tigeot 21838e26cdf6SFrançois Tigeot WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n"); 218419df918dSFrançois Tigeot 21855d0b1887SFrançois Tigeot if (port == PORT_A) 21865d0b1887SFrançois Tigeot pipe_config->cpu_transcoder = TRANSCODER_EDP; 21875d0b1887SFrançois Tigeot 218819df918dSFrançois Tigeot if (type == INTEL_OUTPUT_HDMI) 21898e26cdf6SFrançois Tigeot return intel_hdmi_compute_config(encoder, pipe_config); 219019df918dSFrançois Tigeot else 21918e26cdf6SFrançois Tigeot return intel_dp_compute_config(encoder, pipe_config); 219219df918dSFrançois Tigeot } 219319df918dSFrançois Tigeot 219419df918dSFrançois Tigeot static const struct drm_encoder_funcs intel_ddi_funcs = { 219519df918dSFrançois Tigeot .destroy = intel_ddi_destroy, 219619df918dSFrançois Tigeot }; 219719df918dSFrançois Tigeot 21989edbd4a0SFrançois Tigeot static struct intel_connector * 21999edbd4a0SFrançois Tigeot intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port) 22009edbd4a0SFrançois Tigeot { 22019edbd4a0SFrançois Tigeot struct intel_connector *connector; 22029edbd4a0SFrançois Tigeot enum port port = intel_dig_port->port; 22039edbd4a0SFrançois Tigeot 2204*477eb7f9SFrançois Tigeot connector = intel_connector_alloc(); 22059edbd4a0SFrançois Tigeot if (!connector) 22069edbd4a0SFrançois Tigeot return NULL; 22079edbd4a0SFrançois Tigeot 22089edbd4a0SFrançois Tigeot intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); 22099edbd4a0SFrançois Tigeot if (!intel_dp_init_connector(intel_dig_port, connector)) { 22109edbd4a0SFrançois Tigeot kfree(connector); 22119edbd4a0SFrançois Tigeot return NULL; 22129edbd4a0SFrançois Tigeot } 22139edbd4a0SFrançois Tigeot 22149edbd4a0SFrançois Tigeot return connector; 22159edbd4a0SFrançois Tigeot } 22169edbd4a0SFrançois Tigeot 22179edbd4a0SFrançois Tigeot static struct intel_connector * 22189edbd4a0SFrançois Tigeot intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port) 22199edbd4a0SFrançois Tigeot { 22209edbd4a0SFrançois Tigeot struct intel_connector *connector; 22219edbd4a0SFrançois Tigeot enum port port = intel_dig_port->port; 22229edbd4a0SFrançois Tigeot 2223*477eb7f9SFrançois Tigeot connector = intel_connector_alloc(); 22249edbd4a0SFrançois Tigeot if (!connector) 22259edbd4a0SFrançois Tigeot return NULL; 22269edbd4a0SFrançois Tigeot 22279edbd4a0SFrançois Tigeot intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); 22289edbd4a0SFrançois Tigeot intel_hdmi_init_connector(intel_dig_port, connector); 22299edbd4a0SFrançois Tigeot 22309edbd4a0SFrançois Tigeot return connector; 22319edbd4a0SFrançois Tigeot } 223219df918dSFrançois Tigeot 223319df918dSFrançois Tigeot void intel_ddi_init(struct drm_device *dev, enum port port) 223419df918dSFrançois Tigeot { 223519df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 223619df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port; 223719df918dSFrançois Tigeot struct intel_encoder *intel_encoder; 223819df918dSFrançois Tigeot struct drm_encoder *encoder; 22399edbd4a0SFrançois Tigeot bool init_hdmi, init_dp; 224019df918dSFrançois Tigeot 22419edbd4a0SFrançois Tigeot init_hdmi = (dev_priv->vbt.ddi_port_info[port].supports_dvi || 22429edbd4a0SFrançois Tigeot dev_priv->vbt.ddi_port_info[port].supports_hdmi); 22439edbd4a0SFrançois Tigeot init_dp = dev_priv->vbt.ddi_port_info[port].supports_dp; 22449edbd4a0SFrançois Tigeot if (!init_dp && !init_hdmi) { 224524edb884SFrançois Tigeot DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible, assuming it is\n", 22469edbd4a0SFrançois Tigeot port_name(port)); 22479edbd4a0SFrançois Tigeot init_hdmi = true; 22489edbd4a0SFrançois Tigeot init_dp = true; 22499edbd4a0SFrançois Tigeot } 22509edbd4a0SFrançois Tigeot 22519edbd4a0SFrançois Tigeot intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL); 225219df918dSFrançois Tigeot if (!intel_dig_port) 225319df918dSFrançois Tigeot return; 225419df918dSFrançois Tigeot 225519df918dSFrançois Tigeot intel_encoder = &intel_dig_port->base; 225619df918dSFrançois Tigeot encoder = &intel_encoder->base; 225719df918dSFrançois Tigeot 225819df918dSFrançois Tigeot drm_encoder_init(dev, encoder, &intel_ddi_funcs, 225919df918dSFrançois Tigeot DRM_MODE_ENCODER_TMDS); 226019df918dSFrançois Tigeot 22618e26cdf6SFrançois Tigeot intel_encoder->compute_config = intel_ddi_compute_config; 226219df918dSFrançois Tigeot intel_encoder->enable = intel_enable_ddi; 226319df918dSFrançois Tigeot intel_encoder->pre_enable = intel_ddi_pre_enable; 226419df918dSFrançois Tigeot intel_encoder->disable = intel_disable_ddi; 226519df918dSFrançois Tigeot intel_encoder->post_disable = intel_ddi_post_disable; 226619df918dSFrançois Tigeot intel_encoder->get_hw_state = intel_ddi_get_hw_state; 22675d0b1887SFrançois Tigeot intel_encoder->get_config = intel_ddi_get_config; 226819df918dSFrançois Tigeot 226919df918dSFrançois Tigeot intel_dig_port->port = port; 22705d0b1887SFrançois Tigeot intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & 22715d0b1887SFrançois Tigeot (DDI_BUF_PORT_REVERSAL | 22725d0b1887SFrançois Tigeot DDI_A_4_LANES); 227319df918dSFrançois Tigeot 227419df918dSFrançois Tigeot intel_encoder->type = INTEL_OUTPUT_UNKNOWN; 227519df918dSFrançois Tigeot intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); 2276ba55f2f5SFrançois Tigeot intel_encoder->cloneable = 0; 227719df918dSFrançois Tigeot intel_encoder->hot_plug = intel_ddi_hot_plug; 227819df918dSFrançois Tigeot 227924edb884SFrançois Tigeot if (init_dp) { 228024edb884SFrançois Tigeot if (!intel_ddi_init_dp_connector(intel_dig_port)) 228124edb884SFrançois Tigeot goto err; 228224edb884SFrançois Tigeot 228324edb884SFrançois Tigeot intel_dig_port->hpd_pulse = intel_dp_hpd_pulse; 228424edb884SFrançois Tigeot dev_priv->hpd_irq_port[port] = intel_dig_port; 228524edb884SFrançois Tigeot } 22869edbd4a0SFrançois Tigeot 22879edbd4a0SFrançois Tigeot /* In theory we don't need the encoder->type check, but leave it just in 22889edbd4a0SFrançois Tigeot * case we have some really bad VBTs... */ 228924edb884SFrançois Tigeot if (intel_encoder->type != INTEL_OUTPUT_EDP && init_hdmi) { 229024edb884SFrançois Tigeot if (!intel_ddi_init_hdmi_connector(intel_dig_port)) 229124edb884SFrançois Tigeot goto err; 229224edb884SFrançois Tigeot } 22939edbd4a0SFrançois Tigeot 229424edb884SFrançois Tigeot return; 229524edb884SFrançois Tigeot 229624edb884SFrançois Tigeot err: 22975d0b1887SFrançois Tigeot drm_encoder_cleanup(encoder); 22985d0b1887SFrançois Tigeot kfree(intel_dig_port); 22995d0b1887SFrançois Tigeot } 2300