intel_ddi.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * Copyright © 2012 Intel Corporation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice (including the next
  12. * paragraph) shall be included in all copies or substantial portions of the
  13. * Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. * IN THE SOFTWARE.
  22. *
  23. * Authors:
  24. * Eugeni Dodonov <eugeni.dodonov@intel.com>
  25. *
  26. */
  27. #include "i915_drv.h"
  28. #include "intel_drv.h"
  29. /* HDMI/DVI modes ignore everything but the last 2 items. So we share
  30. * them for both DP and FDI transports, allowing those ports to
  31. * automatically adapt to HDMI connections as well
  32. */
  33. static const u32 hsw_ddi_translations_dp[] = {
  34. 0x00FFFFFF, 0x0006000E, /* DP parameters */
  35. 0x00D75FFF, 0x0005000A,
  36. 0x00C30FFF, 0x00040006,
  37. 0x80AAAFFF, 0x000B0000,
  38. 0x00FFFFFF, 0x0005000A,
  39. 0x00D75FFF, 0x000C0004,
  40. 0x80C30FFF, 0x000B0000,
  41. 0x00FFFFFF, 0x00040006,
  42. 0x80D75FFF, 0x000B0000,
  43. 0x00FFFFFF, 0x00040006 /* HDMI parameters */
  44. };
  45. static const u32 hsw_ddi_translations_fdi[] = {
  46. 0x00FFFFFF, 0x0007000E, /* FDI parameters */
  47. 0x00D75FFF, 0x000F000A,
  48. 0x00C30FFF, 0x00060006,
  49. 0x00AAAFFF, 0x001E0000,
  50. 0x00FFFFFF, 0x000F000A,
  51. 0x00D75FFF, 0x00160004,
  52. 0x00C30FFF, 0x001E0000,
  53. 0x00FFFFFF, 0x00060006,
  54. 0x00D75FFF, 0x001E0000,
  55. 0x00FFFFFF, 0x00040006 /* HDMI parameters */
  56. };
  57. /* On Haswell, DDI port buffers must be programmed with correct values
  58. * in advance. The buffer values are different for FDI and DP modes,
  59. * but the HDMI/DVI fields are shared among those. So we program the DDI
  60. * in either FDI or DP modes only, as HDMI connections will work with both
  61. * of those
  62. */
  63. void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, bool use_fdi_mode)
  64. {
  65. struct drm_i915_private *dev_priv = dev->dev_private;
  66. u32 reg;
  67. int i;
  68. const u32 *ddi_translations = ((use_fdi_mode) ?
  69. hsw_ddi_translations_fdi :
  70. hsw_ddi_translations_dp);
  71. DRM_DEBUG_DRIVER("Initializing DDI buffers for port %c in %s mode\n",
  72. port_name(port),
  73. use_fdi_mode ? "FDI" : "DP");
  74. WARN((use_fdi_mode && (port != PORT_E)),
  75. "Programming port %c in FDI mode, this probably will not work.\n",
  76. port_name(port));
  77. for (i=0, reg=DDI_BUF_TRANS(port); i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) {
  78. I915_WRITE(reg, ddi_translations[i]);
  79. reg += 4;
  80. }
  81. }
  82. /* Program DDI buffers translations for DP. By default, program ports A-D in DP
  83. * mode and port E for FDI.
  84. */
  85. void intel_prepare_ddi(struct drm_device *dev)
  86. {
  87. int port;
  88. if (IS_HASWELL(dev)) {
  89. for (port = PORT_A; port < PORT_E; port++)
  90. intel_prepare_ddi_buffers(dev, port, false);
  91. /* DDI E is the suggested one to work in FDI mode, so program is as such by
  92. * default. It will have to be re-programmed in case a digital DP output
  93. * will be detected on it
  94. */
  95. intel_prepare_ddi_buffers(dev, PORT_E, true);
  96. }
  97. }
  98. static const long hsw_ddi_buf_ctl_values[] = {
  99. DDI_BUF_EMP_400MV_0DB_HSW,
  100. DDI_BUF_EMP_400MV_3_5DB_HSW,
  101. DDI_BUF_EMP_400MV_6DB_HSW,
  102. DDI_BUF_EMP_400MV_9_5DB_HSW,
  103. DDI_BUF_EMP_600MV_0DB_HSW,
  104. DDI_BUF_EMP_600MV_3_5DB_HSW,
  105. DDI_BUF_EMP_600MV_6DB_HSW,
  106. DDI_BUF_EMP_800MV_0DB_HSW,
  107. DDI_BUF_EMP_800MV_3_5DB_HSW
  108. };
  109. /* Starting with Haswell, different DDI ports can work in FDI mode for
  110. * connection to the PCH-located connectors. For this, it is necessary to train
  111. * both the DDI port and PCH receiver for the desired DDI buffer settings.
  112. *
  113. * The recommended port to work in FDI mode is DDI E, which we use here. Also,
  114. * please note that when FDI mode is active on DDI E, it shares 2 lines with
  115. * DDI A (which is used for eDP)
  116. */
  117. void hsw_fdi_link_train(struct drm_crtc *crtc)
  118. {
  119. struct drm_device *dev = crtc->dev;
  120. struct drm_i915_private *dev_priv = dev->dev_private;
  121. struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
  122. int pipe = intel_crtc->pipe;
  123. u32 reg, temp, i;
  124. /* Configure CPU PLL, wait for warmup */
  125. I915_WRITE(SPLL_CTL,
  126. SPLL_PLL_ENABLE |
  127. SPLL_PLL_FREQ_1350MHz |
  128. SPLL_PLL_SCC);
  129. /* Use SPLL to drive the output when in FDI mode */
  130. I915_WRITE(PORT_CLK_SEL(PORT_E),
  131. PORT_CLK_SEL_SPLL);
  132. I915_WRITE(PIPE_CLK_SEL(pipe),
  133. PIPE_CLK_SEL_PORT(PORT_E));
  134. udelay(20);
  135. /* Start the training iterating through available voltages and emphasis */
  136. for (i=0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) {
  137. /* Configure DP_TP_CTL with auto-training */
  138. I915_WRITE(DP_TP_CTL(PORT_E),
  139. DP_TP_CTL_FDI_AUTOTRAIN |
  140. DP_TP_CTL_ENHANCED_FRAME_ENABLE |
  141. DP_TP_CTL_LINK_TRAIN_PAT1 |
  142. DP_TP_CTL_ENABLE);
  143. /* Configure and enable DDI_BUF_CTL for DDI E with next voltage */
  144. temp = I915_READ(DDI_BUF_CTL(PORT_E));
  145. temp = (temp & ~DDI_BUF_EMP_MASK);
  146. I915_WRITE(DDI_BUF_CTL(PORT_E),
  147. temp |
  148. DDI_BUF_CTL_ENABLE |
  149. DDI_PORT_WIDTH_X2 |
  150. hsw_ddi_buf_ctl_values[i]);
  151. udelay(600);
  152. /* Enable CPU FDI Receiver with auto-training */
  153. reg = FDI_RX_CTL(pipe);
  154. I915_WRITE(reg,
  155. I915_READ(reg) |
  156. FDI_LINK_TRAIN_AUTO |
  157. FDI_RX_ENABLE |
  158. FDI_LINK_TRAIN_PATTERN_1_CPT |
  159. FDI_RX_ENHANCE_FRAME_ENABLE |
  160. FDI_PORT_WIDTH_2X_LPT |
  161. FDI_RX_PLL_ENABLE);
  162. POSTING_READ(reg);
  163. udelay(100);
  164. temp = I915_READ(DP_TP_STATUS(PORT_E));
  165. if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) {
  166. DRM_DEBUG_DRIVER("BUF_CTL training done on %d step\n", i);
  167. /* Enable normal pixel sending for FDI */
  168. I915_WRITE(DP_TP_CTL(PORT_E),
  169. DP_TP_CTL_FDI_AUTOTRAIN |
  170. DP_TP_CTL_LINK_TRAIN_NORMAL |
  171. DP_TP_CTL_ENHANCED_FRAME_ENABLE |
  172. DP_TP_CTL_ENABLE);
  173. /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in FDI mode */
  174. temp = I915_READ(DDI_FUNC_CTL(pipe));
  175. temp &= ~PIPE_DDI_PORT_MASK;
  176. temp |= PIPE_DDI_SELECT_PORT(PORT_E) |
  177. PIPE_DDI_MODE_SELECT_FDI |
  178. PIPE_DDI_FUNC_ENABLE |
  179. PIPE_DDI_PORT_WIDTH_X2;
  180. I915_WRITE(DDI_FUNC_CTL(pipe),
  181. temp);
  182. break;
  183. } else {
  184. DRM_ERROR("Error training BUF_CTL %d\n", i);
  185. /* Disable DP_TP_CTL and FDI_RX_CTL) and retry */
  186. I915_WRITE(DP_TP_CTL(PORT_E),
  187. I915_READ(DP_TP_CTL(PORT_E)) &
  188. ~DP_TP_CTL_ENABLE);
  189. I915_WRITE(FDI_RX_CTL(pipe),
  190. I915_READ(FDI_RX_CTL(pipe)) &
  191. ~FDI_RX_PLL_ENABLE);
  192. continue;
  193. }
  194. }
  195. DRM_DEBUG_KMS("FDI train done.\n");
  196. }
  197. /* For DDI connections, it is possible to support different outputs over the
  198. * same DDI port, such as HDMI or DP or even VGA via FDI. So we don't know by
  199. * the time the output is detected what exactly is on the other end of it. This
  200. * function aims at providing support for this detection and proper output
  201. * configuration.
  202. */
  203. void intel_ddi_init(struct drm_device *dev, enum port port)
  204. {
  205. /* For now, we don't do any proper output detection and assume that we
  206. * handle HDMI only */
  207. switch(port){
  208. case PORT_A:
  209. /* We don't handle eDP and DP yet */
  210. DRM_DEBUG_DRIVER("Found digital output on DDI port A\n");
  211. break;
  212. /* Assume that the ports B, C and D are working in HDMI mode for now */
  213. case PORT_B:
  214. case PORT_C:
  215. case PORT_D:
  216. intel_hdmi_init(dev, DDI_BUF_CTL(port));
  217. break;
  218. default:
  219. DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n",
  220. port);
  221. break;
  222. }
  223. }