hdmi_phy.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * HDMI PHY
  3. *
  4. * Copyright (C) 2013 Texas Instruments Incorporated
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 as published by
  8. * the Free Software Foundation.
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/err.h>
  12. #include <linux/io.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/slab.h>
  15. #include <video/omapdss.h>
  16. #include "dss.h"
  17. #include "hdmi.h"
  18. struct hdmi_phy_features {
  19. bool bist_ctrl;
  20. bool calc_freqout;
  21. bool ldo_voltage;
  22. unsigned long dcofreq_min;
  23. unsigned long max_phy;
  24. };
  25. static const struct hdmi_phy_features *phy_feat;
  26. void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s)
  27. {
  28. #define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\
  29. hdmi_read_reg(phy->base, r))
  30. DUMPPHY(HDMI_TXPHY_TX_CTRL);
  31. DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL);
  32. DUMPPHY(HDMI_TXPHY_POWER_CTRL);
  33. DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL);
  34. if (phy_feat->bist_ctrl)
  35. DUMPPHY(HDMI_TXPHY_BIST_CONTROL);
  36. }
  37. int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes)
  38. {
  39. int i;
  40. for (i = 0; i < 8; i += 2) {
  41. u8 lane, pol;
  42. int dx, dy;
  43. dx = lanes[i];
  44. dy = lanes[i + 1];
  45. if (dx < 0 || dx >= 8)
  46. return -EINVAL;
  47. if (dy < 0 || dy >= 8)
  48. return -EINVAL;
  49. if (dx & 1) {
  50. if (dy != dx - 1)
  51. return -EINVAL;
  52. pol = 1;
  53. } else {
  54. if (dy != dx + 1)
  55. return -EINVAL;
  56. pol = 0;
  57. }
  58. lane = dx / 2;
  59. phy->lane_function[lane] = i / 2;
  60. phy->lane_polarity[lane] = pol;
  61. }
  62. return 0;
  63. }
  64. static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy)
  65. {
  66. static const u16 pad_cfg_list[] = {
  67. 0x0123,
  68. 0x0132,
  69. 0x0312,
  70. 0x0321,
  71. 0x0231,
  72. 0x0213,
  73. 0x1023,
  74. 0x1032,
  75. 0x3012,
  76. 0x3021,
  77. 0x2031,
  78. 0x2013,
  79. 0x1203,
  80. 0x1302,
  81. 0x3102,
  82. 0x3201,
  83. 0x2301,
  84. 0x2103,
  85. 0x1230,
  86. 0x1320,
  87. 0x3120,
  88. 0x3210,
  89. 0x2310,
  90. 0x2130,
  91. };
  92. u16 lane_cfg = 0;
  93. int i;
  94. unsigned lane_cfg_val;
  95. u16 pol_val = 0;
  96. for (i = 0; i < 4; ++i)
  97. lane_cfg |= phy->lane_function[i] << ((3 - i) * 4);
  98. pol_val |= phy->lane_polarity[0] << 0;
  99. pol_val |= phy->lane_polarity[1] << 3;
  100. pol_val |= phy->lane_polarity[2] << 2;
  101. pol_val |= phy->lane_polarity[3] << 1;
  102. for (i = 0; i < ARRAY_SIZE(pad_cfg_list); ++i)
  103. if (pad_cfg_list[i] == lane_cfg)
  104. break;
  105. if (WARN_ON(i == ARRAY_SIZE(pad_cfg_list)))
  106. i = 0;
  107. lane_cfg_val = i;
  108. REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, lane_cfg_val, 26, 22);
  109. REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27);
  110. }
  111. int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
  112. {
  113. u8 freqout;
  114. /*
  115. * Read address 0 in order to get the SCP reset done completed
  116. * Dummy access performed to make sure reset is done
  117. */
  118. hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);
  119. /*
  120. * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the
  121. * HDMI_PHYPWRCMD_LDOON command.
  122. */
  123. if (phy_feat->bist_ctrl)
  124. REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
  125. if (phy_feat->calc_freqout) {
  126. /* DCOCLK/10 is pixel clock, compare pclk with DCOCLK_MIN/10 */
  127. u32 dco_min = phy_feat->dcofreq_min / 10;
  128. u32 pclk = cfg->timings.pixelclock;
  129. if (pclk < dco_min)
  130. freqout = 0;
  131. else if ((pclk >= dco_min) && (pclk < phy_feat->max_phy))
  132. freqout = 1;
  133. else
  134. freqout = 2;
  135. } else {
  136. freqout = 1;
  137. }
  138. /*
  139. * Write to phy address 0 to configure the clock
  140. * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
  141. */
  142. REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30);
  143. /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
  144. hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
  145. /* Setup max LDO voltage */
  146. if (phy_feat->ldo_voltage)
  147. REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
  148. hdmi_phy_configure_lanes(phy);
  149. return 0;
  150. }
  151. static const struct hdmi_phy_features omap44xx_phy_feats = {
  152. .bist_ctrl = false,
  153. .calc_freqout = false,
  154. .ldo_voltage = true,
  155. .dcofreq_min = 500000000,
  156. .max_phy = 185675000,
  157. };
  158. static const struct hdmi_phy_features omap54xx_phy_feats = {
  159. .bist_ctrl = true,
  160. .calc_freqout = true,
  161. .ldo_voltage = false,
  162. .dcofreq_min = 750000000,
  163. .max_phy = 186000000,
  164. };
  165. static int hdmi_phy_init_features(struct platform_device *pdev)
  166. {
  167. struct hdmi_phy_features *dst;
  168. const struct hdmi_phy_features *src;
  169. dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
  170. if (!dst) {
  171. dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
  172. return -ENOMEM;
  173. }
  174. switch (omapdss_get_version()) {
  175. case OMAPDSS_VER_OMAP4430_ES1:
  176. case OMAPDSS_VER_OMAP4430_ES2:
  177. case OMAPDSS_VER_OMAP4:
  178. src = &omap44xx_phy_feats;
  179. break;
  180. case OMAPDSS_VER_OMAP5:
  181. src = &omap54xx_phy_feats;
  182. break;
  183. default:
  184. return -ENODEV;
  185. }
  186. memcpy(dst, src, sizeof(*dst));
  187. phy_feat = dst;
  188. return 0;
  189. }
  190. int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy)
  191. {
  192. int r;
  193. struct resource *res;
  194. r = hdmi_phy_init_features(pdev);
  195. if (r)
  196. return r;
  197. res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
  198. if (!res) {
  199. DSSERR("can't get PHY mem resource\n");
  200. return -EINVAL;
  201. }
  202. phy->base = devm_ioremap_resource(&pdev->dev, res);
  203. if (IS_ERR(phy->base)) {
  204. DSSERR("can't ioremap TX PHY\n");
  205. return PTR_ERR(phy->base);
  206. }
  207. return 0;
  208. }