sti_hdmi_tx3g4c28phy.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Copyright (C) STMicroelectronics SA 2014
  3. * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
  4. * License terms: GNU General Public License (GPL), version 2
  5. */
  6. #include "sti_hdmi_tx3g4c28phy.h"
  7. #define HDMI_SRZ_CFG 0x504
  8. #define HDMI_SRZ_PLL_CFG 0x510
  9. #define HDMI_SRZ_ICNTL 0x518
  10. #define HDMI_SRZ_CALCODE_EXT 0x520
  11. #define HDMI_SRZ_CFG_EN BIT(0)
  12. #define HDMI_SRZ_CFG_DISABLE_BYPASS_SINK_CURRENT BIT(1)
  13. #define HDMI_SRZ_CFG_EXTERNAL_DATA BIT(16)
  14. #define HDMI_SRZ_CFG_RBIAS_EXT BIT(17)
  15. #define HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION BIT(18)
  16. #define HDMI_SRZ_CFG_EN_BIASRES_DETECTION BIT(19)
  17. #define HDMI_SRZ_CFG_EN_SRC_TERMINATION BIT(24)
  18. #define HDMI_SRZ_CFG_INTERNAL_MASK (HDMI_SRZ_CFG_EN | \
  19. HDMI_SRZ_CFG_DISABLE_BYPASS_SINK_CURRENT | \
  20. HDMI_SRZ_CFG_EXTERNAL_DATA | \
  21. HDMI_SRZ_CFG_RBIAS_EXT | \
  22. HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION | \
  23. HDMI_SRZ_CFG_EN_BIASRES_DETECTION | \
  24. HDMI_SRZ_CFG_EN_SRC_TERMINATION)
  25. #define PLL_CFG_EN BIT(0)
  26. #define PLL_CFG_NDIV_SHIFT (8)
  27. #define PLL_CFG_IDF_SHIFT (16)
  28. #define PLL_CFG_ODF_SHIFT (24)
  29. #define ODF_DIV_1 (0)
  30. #define ODF_DIV_2 (1)
  31. #define ODF_DIV_4 (2)
  32. #define ODF_DIV_8 (3)
  33. #define HDMI_TIMEOUT_PLL_LOCK 50 /*milliseconds */
  34. struct plldividers_s {
  35. uint32_t min;
  36. uint32_t max;
  37. uint32_t idf;
  38. uint32_t odf;
  39. };
  40. /*
  41. * Functional specification recommended values
  42. */
  43. #define NB_PLL_MODE 5
  44. static struct plldividers_s plldividers[NB_PLL_MODE] = {
  45. {0, 20000000, 1, ODF_DIV_8},
  46. {20000000, 42500000, 2, ODF_DIV_8},
  47. {42500000, 85000000, 4, ODF_DIV_4},
  48. {85000000, 170000000, 8, ODF_DIV_2},
  49. {170000000, 340000000, 16, ODF_DIV_1}
  50. };
  51. #define NB_HDMI_PHY_CONFIG 2
  52. static struct hdmi_phy_config hdmiphy_config[NB_HDMI_PHY_CONFIG] = {
  53. {0, 250000000, {0x0, 0x0, 0x0, 0x0} },
  54. {250000000, 300000000, {0x1110, 0x0, 0x0, 0x0} },
  55. };
  56. /**
  57. * Start hdmi phy macro cell tx3g4c28
  58. *
  59. * @hdmi: pointer on the hdmi internal structure
  60. *
  61. * Return false if an error occur
  62. */
  63. static bool sti_hdmi_tx3g4c28phy_start(struct sti_hdmi *hdmi)
  64. {
  65. u32 ckpxpll = hdmi->mode.clock * 1000;
  66. u32 val, tmdsck, idf, odf, pllctrl = 0;
  67. bool foundplldivides = false;
  68. int i;
  69. DRM_DEBUG_DRIVER("ckpxpll = %dHz\n", ckpxpll);
  70. for (i = 0; i < NB_PLL_MODE; i++) {
  71. if (ckpxpll >= plldividers[i].min &&
  72. ckpxpll < plldividers[i].max) {
  73. idf = plldividers[i].idf;
  74. odf = plldividers[i].odf;
  75. foundplldivides = true;
  76. break;
  77. }
  78. }
  79. if (!foundplldivides) {
  80. DRM_ERROR("input TMDS clock speed (%d) not supported\n",
  81. ckpxpll);
  82. goto err;
  83. }
  84. /* Assuming no pixel repetition and 24bits color */
  85. tmdsck = ckpxpll;
  86. pllctrl |= 40 << PLL_CFG_NDIV_SHIFT;
  87. if (tmdsck > 340000000) {
  88. DRM_ERROR("output TMDS clock (%d) out of range\n", tmdsck);
  89. goto err;
  90. }
  91. pllctrl |= idf << PLL_CFG_IDF_SHIFT;
  92. pllctrl |= odf << PLL_CFG_ODF_SHIFT;
  93. /*
  94. * Configure and power up the PHY PLL
  95. */
  96. hdmi->event_received = false;
  97. DRM_DEBUG_DRIVER("pllctrl = 0x%x\n", pllctrl);
  98. hdmi_write(hdmi, (pllctrl | PLL_CFG_EN), HDMI_SRZ_PLL_CFG);
  99. /* wait PLL interrupt */
  100. wait_event_interruptible_timeout(hdmi->wait_event,
  101. hdmi->event_received == true,
  102. msecs_to_jiffies
  103. (HDMI_TIMEOUT_PLL_LOCK));
  104. if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK) == 0) {
  105. DRM_ERROR("hdmi phy pll not locked\n");
  106. goto err;
  107. }
  108. DRM_DEBUG_DRIVER("got PHY PLL Lock\n");
  109. val = (HDMI_SRZ_CFG_EN |
  110. HDMI_SRZ_CFG_EXTERNAL_DATA |
  111. HDMI_SRZ_CFG_EN_BIASRES_DETECTION |
  112. HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION);
  113. if (tmdsck > 165000000)
  114. val |= HDMI_SRZ_CFG_EN_SRC_TERMINATION;
  115. /*
  116. * To configure the source termination and pre-emphasis appropriately
  117. * for different high speed TMDS clock frequencies a phy configuration
  118. * table must be provided, tailored to the SoC and board combination.
  119. */
  120. for (i = 0; i < NB_HDMI_PHY_CONFIG; i++) {
  121. if ((hdmiphy_config[i].min_tmds_freq <= tmdsck) &&
  122. (hdmiphy_config[i].max_tmds_freq >= tmdsck)) {
  123. val |= (hdmiphy_config[i].config[0]
  124. & ~HDMI_SRZ_CFG_INTERNAL_MASK);
  125. hdmi_write(hdmi, val, HDMI_SRZ_CFG);
  126. val = hdmiphy_config[i].config[1];
  127. hdmi_write(hdmi, val, HDMI_SRZ_ICNTL);
  128. val = hdmiphy_config[i].config[2];
  129. hdmi_write(hdmi, val, HDMI_SRZ_CALCODE_EXT);
  130. DRM_DEBUG_DRIVER("serializer cfg 0x%x 0x%x 0x%x\n",
  131. hdmiphy_config[i].config[0],
  132. hdmiphy_config[i].config[1],
  133. hdmiphy_config[i].config[2]);
  134. return true;
  135. }
  136. }
  137. /*
  138. * Default, power up the serializer with no pre-emphasis or
  139. * output swing correction
  140. */
  141. hdmi_write(hdmi, val, HDMI_SRZ_CFG);
  142. hdmi_write(hdmi, 0x0, HDMI_SRZ_ICNTL);
  143. hdmi_write(hdmi, 0x0, HDMI_SRZ_CALCODE_EXT);
  144. return true;
  145. err:
  146. return false;
  147. }
  148. /**
  149. * Stop hdmi phy macro cell tx3g4c28
  150. *
  151. * @hdmi: pointer on the hdmi internal structure
  152. */
  153. static void sti_hdmi_tx3g4c28phy_stop(struct sti_hdmi *hdmi)
  154. {
  155. int val = 0;
  156. DRM_DEBUG_DRIVER("\n");
  157. hdmi->event_received = false;
  158. val = HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION;
  159. val |= HDMI_SRZ_CFG_EN_BIASRES_DETECTION;
  160. hdmi_write(hdmi, val, HDMI_SRZ_CFG);
  161. hdmi_write(hdmi, 0, HDMI_SRZ_PLL_CFG);
  162. /* wait PLL interrupt */
  163. wait_event_interruptible_timeout(hdmi->wait_event,
  164. hdmi->event_received == true,
  165. msecs_to_jiffies
  166. (HDMI_TIMEOUT_PLL_LOCK));
  167. if (hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK)
  168. DRM_ERROR("hdmi phy pll not well disabled\n");
  169. }
  170. struct hdmi_phy_ops tx3g4c28phy_ops = {
  171. .start = sti_hdmi_tx3g4c28phy_start,
  172. .stop = sti_hdmi_tx3g4c28phy_stop,
  173. };