sti_hdmi_tx3g0c55phy.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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_tx3g0c55phy.h"
  7. #define HDMI_SRZ_PLL_CFG 0x0504
  8. #define HDMI_SRZ_TAP_1 0x0508
  9. #define HDMI_SRZ_TAP_2 0x050C
  10. #define HDMI_SRZ_TAP_3 0x0510
  11. #define HDMI_SRZ_CTRL 0x0514
  12. #define HDMI_SRZ_PLL_CFG_POWER_DOWN BIT(0)
  13. #define HDMI_SRZ_PLL_CFG_VCOR_SHIFT 1
  14. #define HDMI_SRZ_PLL_CFG_VCOR_425MHZ 0
  15. #define HDMI_SRZ_PLL_CFG_VCOR_850MHZ 1
  16. #define HDMI_SRZ_PLL_CFG_VCOR_1700MHZ 2
  17. #define HDMI_SRZ_PLL_CFG_VCOR_3000MHZ 3
  18. #define HDMI_SRZ_PLL_CFG_VCOR_MASK 3
  19. #define HDMI_SRZ_PLL_CFG_VCOR(x) (x << HDMI_SRZ_PLL_CFG_VCOR_SHIFT)
  20. #define HDMI_SRZ_PLL_CFG_NDIV_SHIFT 8
  21. #define HDMI_SRZ_PLL_CFG_NDIV_MASK (0x1F << HDMI_SRZ_PLL_CFG_NDIV_SHIFT)
  22. #define HDMI_SRZ_PLL_CFG_MODE_SHIFT 16
  23. #define HDMI_SRZ_PLL_CFG_MODE_13_5_MHZ 0x1
  24. #define HDMI_SRZ_PLL_CFG_MODE_25_2_MHZ 0x4
  25. #define HDMI_SRZ_PLL_CFG_MODE_27_MHZ 0x5
  26. #define HDMI_SRZ_PLL_CFG_MODE_33_75_MHZ 0x6
  27. #define HDMI_SRZ_PLL_CFG_MODE_40_5_MHZ 0x7
  28. #define HDMI_SRZ_PLL_CFG_MODE_54_MHZ 0x8
  29. #define HDMI_SRZ_PLL_CFG_MODE_67_5_MHZ 0x9
  30. #define HDMI_SRZ_PLL_CFG_MODE_74_25_MHZ 0xA
  31. #define HDMI_SRZ_PLL_CFG_MODE_81_MHZ 0xB
  32. #define HDMI_SRZ_PLL_CFG_MODE_82_5_MHZ 0xC
  33. #define HDMI_SRZ_PLL_CFG_MODE_108_MHZ 0xD
  34. #define HDMI_SRZ_PLL_CFG_MODE_148_5_MHZ 0xE
  35. #define HDMI_SRZ_PLL_CFG_MODE_165_MHZ 0xF
  36. #define HDMI_SRZ_PLL_CFG_MODE_MASK 0xF
  37. #define HDMI_SRZ_PLL_CFG_MODE(x) (x << HDMI_SRZ_PLL_CFG_MODE_SHIFT)
  38. #define HDMI_SRZ_CTRL_POWER_DOWN (1 << 0)
  39. #define HDMI_SRZ_CTRL_EXTERNAL_DATA_EN (1 << 1)
  40. /* sysconf registers */
  41. #define HDMI_REJECTION_PLL_CONFIGURATION 0x0858 /* SYSTEM_CONFIG2534 */
  42. #define HDMI_REJECTION_PLL_STATUS 0x0948 /* SYSTEM_CONFIG2594 */
  43. #define REJECTION_PLL_HDMI_ENABLE_SHIFT 0
  44. #define REJECTION_PLL_HDMI_ENABLE_MASK (0x1 << REJECTION_PLL_HDMI_ENABLE_SHIFT)
  45. #define REJECTION_PLL_HDMI_PDIV_SHIFT 24
  46. #define REJECTION_PLL_HDMI_PDIV_MASK (0x7 << REJECTION_PLL_HDMI_PDIV_SHIFT)
  47. #define REJECTION_PLL_HDMI_NDIV_SHIFT 16
  48. #define REJECTION_PLL_HDMI_NDIV_MASK (0xFF << REJECTION_PLL_HDMI_NDIV_SHIFT)
  49. #define REJECTION_PLL_HDMI_MDIV_SHIFT 8
  50. #define REJECTION_PLL_HDMI_MDIV_MASK (0xFF << REJECTION_PLL_HDMI_MDIV_SHIFT)
  51. #define REJECTION_PLL_HDMI_REJ_PLL_LOCK BIT(0)
  52. #define HDMI_TIMEOUT_PLL_LOCK 50 /*milliseconds */
  53. /**
  54. * pll mode structure
  55. *
  56. * A pointer to an array of these structures is passed to a TMDS (HDMI) output
  57. * via the control interface to provide board and SoC specific
  58. * configurations of the HDMI PHY. Each entry in the array specifies a hardware
  59. * specific configuration for a given TMDS clock frequency range. The array
  60. * should be terminated with an entry that has all fields set to zero.
  61. *
  62. * @min: Lower bound of TMDS clock frequency this entry applies to
  63. * @max: Upper bound of TMDS clock frequency this entry applies to
  64. * @mode: SoC specific register configuration
  65. */
  66. struct pllmode {
  67. u32 min;
  68. u32 max;
  69. u32 mode;
  70. };
  71. #define NB_PLL_MODE 7
  72. static struct pllmode pllmodes[NB_PLL_MODE] = {
  73. {13500000, 13513500, HDMI_SRZ_PLL_CFG_MODE_13_5_MHZ},
  74. {25174800, 25200000, HDMI_SRZ_PLL_CFG_MODE_25_2_MHZ},
  75. {27000000, 27027000, HDMI_SRZ_PLL_CFG_MODE_27_MHZ},
  76. {54000000, 54054000, HDMI_SRZ_PLL_CFG_MODE_54_MHZ},
  77. {72000000, 74250000, HDMI_SRZ_PLL_CFG_MODE_74_25_MHZ},
  78. {108000000, 108108000, HDMI_SRZ_PLL_CFG_MODE_108_MHZ},
  79. {148351648, 297000000, HDMI_SRZ_PLL_CFG_MODE_148_5_MHZ}
  80. };
  81. #define NB_HDMI_PHY_CONFIG 5
  82. static struct hdmi_phy_config hdmiphy_config[NB_HDMI_PHY_CONFIG] = {
  83. {0, 40000000, {0x00101010, 0x00101010, 0x00101010, 0x02} },
  84. {40000000, 140000000, {0x00111111, 0x00111111, 0x00111111, 0x02} },
  85. {140000000, 160000000, {0x00131313, 0x00101010, 0x00101010, 0x02} },
  86. {160000000, 250000000, {0x00131313, 0x00111111, 0x00111111, 0x03FE} },
  87. {250000000, 300000000, {0x00151515, 0x00101010, 0x00101010, 0x03FE} },
  88. };
  89. #define PLL_CHANGE_DELAY 1 /* ms */
  90. /**
  91. * Disable the pll rejection
  92. *
  93. * @hdmi: pointer on the hdmi internal structure
  94. *
  95. * return true if the pll has been disabled
  96. */
  97. static bool disable_pll_rejection(struct sti_hdmi *hdmi)
  98. {
  99. u32 val;
  100. DRM_DEBUG_DRIVER("\n");
  101. val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
  102. val &= ~REJECTION_PLL_HDMI_ENABLE_MASK;
  103. writel(val, hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
  104. msleep(PLL_CHANGE_DELAY);
  105. val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_STATUS);
  106. return !(val & REJECTION_PLL_HDMI_REJ_PLL_LOCK);
  107. }
  108. /**
  109. * Enable the old BCH/rejection PLL is now reused to provide the CLKPXPLL
  110. * clock input to the new PHY PLL that generates the serializer clock
  111. * (TMDS*10) and the TMDS clock which is now fed back into the HDMI
  112. * formatter instead of the TMDS clock line from ClockGenB.
  113. *
  114. * @hdmi: pointer on the hdmi internal structure
  115. *
  116. * return true if pll has been correctly set
  117. */
  118. static bool enable_pll_rejection(struct sti_hdmi *hdmi)
  119. {
  120. unsigned int inputclock;
  121. u32 mdiv, ndiv, pdiv, val;
  122. DRM_DEBUG_DRIVER("\n");
  123. if (!disable_pll_rejection(hdmi))
  124. return false;
  125. inputclock = hdmi->mode.clock * 1000;
  126. DRM_DEBUG_DRIVER("hdmi rejection pll input clock = %dHz\n", inputclock);
  127. /* Power up the HDMI rejection PLL
  128. * Note: On this SoC (stiH416) we are forced to have the input clock
  129. * be equal to the HDMI pixel clock.
  130. *
  131. * The values here have been suggested by validation however they are
  132. * still provisional and subject to change.
  133. *
  134. * PLLout = (Fin*Mdiv) / ((2 * Ndiv) / 2^Pdiv)
  135. */
  136. if (inputclock < 50000000) {
  137. /*
  138. * For slower clocks we need to multiply more to keep the
  139. * internal VCO frequency within the physical specification
  140. * of the PLL.
  141. */
  142. pdiv = 4;
  143. ndiv = 240;
  144. mdiv = 30;
  145. } else {
  146. pdiv = 2;
  147. ndiv = 60;
  148. mdiv = 30;
  149. }
  150. val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
  151. val &= ~(REJECTION_PLL_HDMI_PDIV_MASK |
  152. REJECTION_PLL_HDMI_NDIV_MASK |
  153. REJECTION_PLL_HDMI_MDIV_MASK |
  154. REJECTION_PLL_HDMI_ENABLE_MASK);
  155. val |= (pdiv << REJECTION_PLL_HDMI_PDIV_SHIFT) |
  156. (ndiv << REJECTION_PLL_HDMI_NDIV_SHIFT) |
  157. (mdiv << REJECTION_PLL_HDMI_MDIV_SHIFT) |
  158. (0x1 << REJECTION_PLL_HDMI_ENABLE_SHIFT);
  159. writel(val, hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
  160. msleep(PLL_CHANGE_DELAY);
  161. val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_STATUS);
  162. return (val & REJECTION_PLL_HDMI_REJ_PLL_LOCK);
  163. }
  164. /**
  165. * Start hdmi phy macro cell tx3g0c55
  166. *
  167. * @hdmi: pointer on the hdmi internal structure
  168. *
  169. * Return false if an error occur
  170. */
  171. static bool sti_hdmi_tx3g0c55phy_start(struct sti_hdmi *hdmi)
  172. {
  173. u32 ckpxpll = hdmi->mode.clock * 1000;
  174. u32 val, tmdsck, freqvco, pllctrl = 0;
  175. unsigned int i;
  176. if (!enable_pll_rejection(hdmi))
  177. return false;
  178. DRM_DEBUG_DRIVER("ckpxpll = %dHz\n", ckpxpll);
  179. /* Assuming no pixel repetition and 24bits color */
  180. tmdsck = ckpxpll;
  181. pllctrl = 2 << HDMI_SRZ_PLL_CFG_NDIV_SHIFT;
  182. /*
  183. * Setup the PLL mode parameter based on the ckpxpll. If we haven't got
  184. * a clock frequency supported by one of the specific PLL modes then we
  185. * will end up using the generic mode (0) which only supports a 10x
  186. * multiplier, hence only 24bit color.
  187. */
  188. for (i = 0; i < NB_PLL_MODE; i++) {
  189. if (ckpxpll >= pllmodes[i].min && ckpxpll <= pllmodes[i].max)
  190. pllctrl |= HDMI_SRZ_PLL_CFG_MODE(pllmodes[i].mode);
  191. }
  192. freqvco = tmdsck * 10;
  193. if (freqvco <= 425000000UL)
  194. pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_425MHZ);
  195. else if (freqvco <= 850000000UL)
  196. pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_850MHZ);
  197. else if (freqvco <= 1700000000UL)
  198. pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_1700MHZ);
  199. else if (freqvco <= 2970000000UL)
  200. pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_3000MHZ);
  201. else {
  202. DRM_ERROR("PHY serializer clock out of range\n");
  203. goto err;
  204. }
  205. /*
  206. * Configure and power up the PHY PLL
  207. */
  208. hdmi->event_received = false;
  209. DRM_DEBUG_DRIVER("pllctrl = 0x%x\n", pllctrl);
  210. hdmi_write(hdmi, pllctrl, HDMI_SRZ_PLL_CFG);
  211. /* wait PLL interrupt */
  212. wait_event_interruptible_timeout(hdmi->wait_event,
  213. hdmi->event_received == true,
  214. msecs_to_jiffies
  215. (HDMI_TIMEOUT_PLL_LOCK));
  216. if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK) == 0) {
  217. DRM_ERROR("hdmi phy pll not locked\n");
  218. goto err;
  219. }
  220. DRM_DEBUG_DRIVER("got PHY PLL Lock\n");
  221. /*
  222. * To configure the source termination and pre-emphasis appropriately
  223. * for different high speed TMDS clock frequencies a phy configuration
  224. * table must be provided, tailored to the SoC and board combination.
  225. */
  226. for (i = 0; i < NB_HDMI_PHY_CONFIG; i++) {
  227. if ((hdmiphy_config[i].min_tmds_freq <= tmdsck) &&
  228. (hdmiphy_config[i].max_tmds_freq >= tmdsck)) {
  229. val = hdmiphy_config[i].config[0];
  230. hdmi_write(hdmi, val, HDMI_SRZ_TAP_1);
  231. val = hdmiphy_config[i].config[1];
  232. hdmi_write(hdmi, val, HDMI_SRZ_TAP_2);
  233. val = hdmiphy_config[i].config[2];
  234. hdmi_write(hdmi, val, HDMI_SRZ_TAP_3);
  235. val = hdmiphy_config[i].config[3];
  236. val |= HDMI_SRZ_CTRL_EXTERNAL_DATA_EN;
  237. val &= ~HDMI_SRZ_CTRL_POWER_DOWN;
  238. hdmi_write(hdmi, val, HDMI_SRZ_CTRL);
  239. DRM_DEBUG_DRIVER("serializer cfg 0x%x 0x%x 0x%x 0x%x\n",
  240. hdmiphy_config[i].config[0],
  241. hdmiphy_config[i].config[1],
  242. hdmiphy_config[i].config[2],
  243. hdmiphy_config[i].config[3]);
  244. return true;
  245. }
  246. }
  247. /*
  248. * Default, power up the serializer with no pre-emphasis or source
  249. * termination.
  250. */
  251. hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_1);
  252. hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_2);
  253. hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_3);
  254. hdmi_write(hdmi, HDMI_SRZ_CTRL_EXTERNAL_DATA_EN, HDMI_SRZ_CTRL);
  255. return true;
  256. err:
  257. disable_pll_rejection(hdmi);
  258. return false;
  259. }
  260. /**
  261. * Stop hdmi phy macro cell tx3g0c55
  262. *
  263. * @hdmi: pointer on the hdmi internal structure
  264. */
  265. static void sti_hdmi_tx3g0c55phy_stop(struct sti_hdmi *hdmi)
  266. {
  267. DRM_DEBUG_DRIVER("\n");
  268. hdmi->event_received = false;
  269. hdmi_write(hdmi, HDMI_SRZ_CTRL_POWER_DOWN, HDMI_SRZ_CTRL);
  270. hdmi_write(hdmi, HDMI_SRZ_PLL_CFG_POWER_DOWN, HDMI_SRZ_PLL_CFG);
  271. /* wait PLL interrupt */
  272. wait_event_interruptible_timeout(hdmi->wait_event,
  273. hdmi->event_received == true,
  274. msecs_to_jiffies
  275. (HDMI_TIMEOUT_PLL_LOCK));
  276. if (hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK)
  277. DRM_ERROR("hdmi phy pll not well disabled\n");
  278. disable_pll_rejection(hdmi);
  279. }
  280. struct hdmi_phy_ops tx3g0c55phy_ops = {
  281. .start = sti_hdmi_tx3g0c55phy_start,
  282. .stop = sti_hdmi_tx3g0c55phy_stop,
  283. };