hdmi_phy.c 4.9 KB

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