hdmi_hpd.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2013 Red Hat
  4. * Author: Rob Clark <robdclark@gmail.com>
  5. */
  6. #include <linux/delay.h>
  7. #include <linux/gpio/consumer.h>
  8. #include <linux/pinctrl/consumer.h>
  9. #include "msm_kms.h"
  10. #include "hdmi.h"
  11. static void msm_hdmi_phy_reset(struct hdmi *hdmi)
  12. {
  13. unsigned int val;
  14. val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
  15. if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
  16. /* pull low */
  17. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  18. val & ~HDMI_PHY_CTRL_SW_RESET);
  19. } else {
  20. /* pull high */
  21. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  22. val | HDMI_PHY_CTRL_SW_RESET);
  23. }
  24. if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
  25. /* pull low */
  26. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  27. val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
  28. } else {
  29. /* pull high */
  30. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  31. val | HDMI_PHY_CTRL_SW_RESET_PLL);
  32. }
  33. msleep(100);
  34. if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
  35. /* pull high */
  36. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  37. val | HDMI_PHY_CTRL_SW_RESET);
  38. } else {
  39. /* pull low */
  40. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  41. val & ~HDMI_PHY_CTRL_SW_RESET);
  42. }
  43. if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
  44. /* pull high */
  45. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  46. val | HDMI_PHY_CTRL_SW_RESET_PLL);
  47. } else {
  48. /* pull low */
  49. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  50. val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
  51. }
  52. }
  53. static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
  54. {
  55. const struct hdmi_platform_config *config = hdmi->config;
  56. struct device *dev = &hdmi->pdev->dev;
  57. int i, ret;
  58. if (enable) {
  59. for (i = 0; i < config->hpd_clk_cnt; i++) {
  60. if (config->hpd_freq && config->hpd_freq[i]) {
  61. ret = clk_set_rate(hdmi->hpd_clks[i],
  62. config->hpd_freq[i]);
  63. if (ret)
  64. dev_warn(dev,
  65. "failed to set clk %s (%d)\n",
  66. config->hpd_clk_names[i], ret);
  67. }
  68. ret = clk_prepare_enable(hdmi->hpd_clks[i]);
  69. if (ret) {
  70. DRM_DEV_ERROR(dev,
  71. "failed to enable hpd clk: %s (%d)\n",
  72. config->hpd_clk_names[i], ret);
  73. }
  74. }
  75. } else {
  76. for (i = config->hpd_clk_cnt - 1; i >= 0; i--)
  77. clk_disable_unprepare(hdmi->hpd_clks[i]);
  78. }
  79. }
  80. int msm_hdmi_hpd_enable(struct drm_bridge *bridge)
  81. {
  82. struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
  83. struct hdmi *hdmi = hdmi_bridge->hdmi;
  84. const struct hdmi_platform_config *config = hdmi->config;
  85. struct device *dev = &hdmi->pdev->dev;
  86. uint32_t hpd_ctrl;
  87. int ret;
  88. unsigned long flags;
  89. ret = regulator_bulk_enable(config->hpd_reg_cnt, hdmi->hpd_regs);
  90. if (ret) {
  91. DRM_DEV_ERROR(dev, "failed to enable hpd regulators: %d\n", ret);
  92. goto fail;
  93. }
  94. ret = pinctrl_pm_select_default_state(dev);
  95. if (ret) {
  96. DRM_DEV_ERROR(dev, "pinctrl state chg failed: %d\n", ret);
  97. goto fail;
  98. }
  99. if (hdmi->hpd_gpiod)
  100. gpiod_set_value_cansleep(hdmi->hpd_gpiod, 1);
  101. pm_runtime_get_sync(dev);
  102. enable_hpd_clocks(hdmi, true);
  103. msm_hdmi_set_mode(hdmi, false);
  104. msm_hdmi_phy_reset(hdmi);
  105. msm_hdmi_set_mode(hdmi, true);
  106. hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b);
  107. /* enable HPD events: */
  108. hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
  109. HDMI_HPD_INT_CTRL_INT_CONNECT |
  110. HDMI_HPD_INT_CTRL_INT_EN);
  111. /* set timeout to 4.1ms (max) for hardware debounce */
  112. spin_lock_irqsave(&hdmi->reg_lock, flags);
  113. hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
  114. hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff);
  115. /* Toggle HPD circuit to trigger HPD sense */
  116. hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
  117. ~HDMI_HPD_CTRL_ENABLE & hpd_ctrl);
  118. hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
  119. HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
  120. spin_unlock_irqrestore(&hdmi->reg_lock, flags);
  121. return 0;
  122. fail:
  123. return ret;
  124. }
  125. void msm_hdmi_hpd_disable(struct hdmi *hdmi)
  126. {
  127. const struct hdmi_platform_config *config = hdmi->config;
  128. struct device *dev = &hdmi->pdev->dev;
  129. int ret;
  130. /* Disable HPD interrupt */
  131. hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
  132. msm_hdmi_set_mode(hdmi, false);
  133. enable_hpd_clocks(hdmi, false);
  134. pm_runtime_put(dev);
  135. ret = pinctrl_pm_select_sleep_state(dev);
  136. if (ret)
  137. dev_warn(dev, "pinctrl state chg failed: %d\n", ret);
  138. ret = regulator_bulk_disable(config->hpd_reg_cnt, hdmi->hpd_regs);
  139. if (ret)
  140. dev_warn(dev, "failed to disable hpd regulator: %d\n", ret);
  141. }
  142. void msm_hdmi_hpd_irq(struct drm_bridge *bridge)
  143. {
  144. struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
  145. struct hdmi *hdmi = hdmi_bridge->hdmi;
  146. uint32_t hpd_int_status, hpd_int_ctrl;
  147. /* Process HPD: */
  148. hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
  149. hpd_int_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL);
  150. if ((hpd_int_ctrl & HDMI_HPD_INT_CTRL_INT_EN) &&
  151. (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) {
  152. bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED);
  153. /* ack & disable (temporarily) HPD events: */
  154. hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
  155. HDMI_HPD_INT_CTRL_INT_ACK);
  156. DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
  157. /* detect disconnect if we are connected or visa versa: */
  158. hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
  159. if (!detected)
  160. hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
  161. hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
  162. queue_work(hdmi->workq, &hdmi_bridge->hpd_work);
  163. }
  164. }
  165. static enum drm_connector_status detect_reg(struct hdmi *hdmi)
  166. {
  167. uint32_t hpd_int_status;
  168. pm_runtime_get_sync(&hdmi->pdev->dev);
  169. enable_hpd_clocks(hdmi, true);
  170. hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
  171. enable_hpd_clocks(hdmi, false);
  172. pm_runtime_put(&hdmi->pdev->dev);
  173. return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ?
  174. connector_status_connected : connector_status_disconnected;
  175. }
  176. #define HPD_GPIO_INDEX 2
  177. static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
  178. {
  179. return gpiod_get_value(hdmi->hpd_gpiod) ?
  180. connector_status_connected :
  181. connector_status_disconnected;
  182. }
  183. enum drm_connector_status msm_hdmi_bridge_detect(
  184. struct drm_bridge *bridge)
  185. {
  186. struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
  187. struct hdmi *hdmi = hdmi_bridge->hdmi;
  188. enum drm_connector_status stat_gpio, stat_reg;
  189. int retry = 20;
  190. /*
  191. * some platforms may not have hpd gpio. Rely only on the status
  192. * provided by REG_HDMI_HPD_INT_STATUS in this case.
  193. */
  194. if (!hdmi->hpd_gpiod)
  195. return detect_reg(hdmi);
  196. do {
  197. stat_gpio = detect_gpio(hdmi);
  198. stat_reg = detect_reg(hdmi);
  199. if (stat_gpio == stat_reg)
  200. break;
  201. mdelay(10);
  202. } while (--retry);
  203. /* the status we get from reading gpio seems to be more reliable,
  204. * so trust that one the most if we didn't manage to get hdmi and
  205. * gpio status to agree:
  206. */
  207. if (stat_gpio != stat_reg) {
  208. DBG("HDMI_HPD_INT_STATUS tells us: %d", stat_reg);
  209. DBG("hpd gpio tells us: %d", stat_gpio);
  210. }
  211. return stat_gpio;
  212. }