hdmi_phy.c 4.9 KB

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