hdmi_connector.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * Copyright (C) 2013 Red Hat
  3. * Author: Rob Clark <robdclark@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 as published by
  7. * the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with
  15. * this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <linux/gpio.h>
  18. #include "hdmi.h"
  19. struct hdmi_connector {
  20. struct drm_connector base;
  21. struct hdmi *hdmi;
  22. };
  23. #define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
  24. static int gpio_config(struct hdmi *hdmi, bool on)
  25. {
  26. struct drm_device *dev = hdmi->dev;
  27. struct hdmi_platform_config *config =
  28. hdmi->pdev->dev.platform_data;
  29. int ret;
  30. if (on) {
  31. ret = gpio_request(config->ddc_clk_gpio, "HDMI_DDC_CLK");
  32. if (ret) {
  33. dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
  34. "HDMI_DDC_CLK", config->ddc_clk_gpio, ret);
  35. goto error1;
  36. }
  37. ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
  38. if (ret) {
  39. dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
  40. "HDMI_DDC_DATA", config->ddc_data_gpio, ret);
  41. goto error2;
  42. }
  43. ret = gpio_request(config->hpd_gpio, "HDMI_HPD");
  44. if (ret) {
  45. dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
  46. "HDMI_HPD", config->hpd_gpio, ret);
  47. goto error3;
  48. }
  49. if (config->pmic_gpio != -1) {
  50. ret = gpio_request(config->pmic_gpio, "PMIC_HDMI_MUX_SEL");
  51. if (ret) {
  52. dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
  53. "PMIC_HDMI_MUX_SEL", config->pmic_gpio, ret);
  54. goto error4;
  55. }
  56. gpio_set_value_cansleep(config->pmic_gpio, 0);
  57. }
  58. DBG("gpio on");
  59. } else {
  60. gpio_free(config->ddc_clk_gpio);
  61. gpio_free(config->ddc_data_gpio);
  62. gpio_free(config->hpd_gpio);
  63. if (config->pmic_gpio != -1) {
  64. gpio_set_value_cansleep(config->pmic_gpio, 1);
  65. gpio_free(config->pmic_gpio);
  66. }
  67. DBG("gpio off");
  68. }
  69. return 0;
  70. error4:
  71. gpio_free(config->hpd_gpio);
  72. error3:
  73. gpio_free(config->ddc_data_gpio);
  74. error2:
  75. gpio_free(config->ddc_clk_gpio);
  76. error1:
  77. return ret;
  78. }
  79. static int hpd_enable(struct hdmi_connector *hdmi_connector)
  80. {
  81. struct hdmi *hdmi = hdmi_connector->hdmi;
  82. struct drm_device *dev = hdmi_connector->base.dev;
  83. struct hdmi_phy *phy = hdmi->phy;
  84. uint32_t hpd_ctrl;
  85. int ret;
  86. ret = gpio_config(hdmi, true);
  87. if (ret) {
  88. dev_err(dev->dev, "failed to configure GPIOs: %d\n", ret);
  89. goto fail;
  90. }
  91. ret = clk_prepare_enable(hdmi->clk);
  92. if (ret) {
  93. dev_err(dev->dev, "failed to enable 'clk': %d\n", ret);
  94. goto fail;
  95. }
  96. ret = clk_prepare_enable(hdmi->m_pclk);
  97. if (ret) {
  98. dev_err(dev->dev, "failed to enable 'm_pclk': %d\n", ret);
  99. goto fail;
  100. }
  101. ret = clk_prepare_enable(hdmi->s_pclk);
  102. if (ret) {
  103. dev_err(dev->dev, "failed to enable 's_pclk': %d\n", ret);
  104. goto fail;
  105. }
  106. if (hdmi->mpp0)
  107. ret = regulator_enable(hdmi->mpp0);
  108. if (!ret)
  109. ret = regulator_enable(hdmi->mvs);
  110. if (ret) {
  111. dev_err(dev->dev, "failed to enable regulators: %d\n", ret);
  112. goto fail;
  113. }
  114. hdmi_set_mode(hdmi, false);
  115. phy->funcs->reset(phy);
  116. hdmi_set_mode(hdmi, true);
  117. hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b);
  118. /* enable HPD events: */
  119. hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
  120. HDMI_HPD_INT_CTRL_INT_CONNECT |
  121. HDMI_HPD_INT_CTRL_INT_EN);
  122. /* set timeout to 4.1ms (max) for hardware debounce */
  123. hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
  124. hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff);
  125. /* Toggle HPD circuit to trigger HPD sense */
  126. hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
  127. ~HDMI_HPD_CTRL_ENABLE & hpd_ctrl);
  128. hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
  129. HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
  130. return 0;
  131. fail:
  132. return ret;
  133. }
  134. static int hdp_disable(struct hdmi_connector *hdmi_connector)
  135. {
  136. struct hdmi *hdmi = hdmi_connector->hdmi;
  137. struct drm_device *dev = hdmi_connector->base.dev;
  138. int ret = 0;
  139. /* Disable HPD interrupt */
  140. hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
  141. hdmi_set_mode(hdmi, false);
  142. if (hdmi->mpp0)
  143. ret = regulator_disable(hdmi->mpp0);
  144. if (!ret)
  145. ret = regulator_disable(hdmi->mvs);
  146. if (ret) {
  147. dev_err(dev->dev, "failed to enable regulators: %d\n", ret);
  148. goto fail;
  149. }
  150. clk_disable_unprepare(hdmi->clk);
  151. clk_disable_unprepare(hdmi->m_pclk);
  152. clk_disable_unprepare(hdmi->s_pclk);
  153. ret = gpio_config(hdmi, false);
  154. if (ret) {
  155. dev_err(dev->dev, "failed to unconfigure GPIOs: %d\n", ret);
  156. goto fail;
  157. }
  158. return 0;
  159. fail:
  160. return ret;
  161. }
  162. void hdmi_connector_irq(struct drm_connector *connector)
  163. {
  164. struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
  165. struct hdmi *hdmi = hdmi_connector->hdmi;
  166. uint32_t hpd_int_status, hpd_int_ctrl;
  167. /* Process HPD: */
  168. hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
  169. hpd_int_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL);
  170. if ((hpd_int_ctrl & HDMI_HPD_INT_CTRL_INT_EN) &&
  171. (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) {
  172. bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED);
  173. DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
  174. /* ack the irq: */
  175. hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
  176. hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK);
  177. drm_helper_hpd_irq_event(connector->dev);
  178. /* detect disconnect if we are connected or visa versa: */
  179. hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
  180. if (!detected)
  181. hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
  182. hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
  183. }
  184. }
  185. static enum drm_connector_status hdmi_connector_detect(
  186. struct drm_connector *connector, bool force)
  187. {
  188. struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
  189. struct hdmi *hdmi = hdmi_connector->hdmi;
  190. uint32_t hpd_int_status;
  191. int retry = 20;
  192. hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
  193. /* sense seems to in some cases be momentarily de-asserted, don't
  194. * let that trick us into thinking the monitor is gone:
  195. */
  196. while (retry-- && !(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED)) {
  197. mdelay(10);
  198. hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
  199. DBG("status=%08x", hpd_int_status);
  200. }
  201. return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ?
  202. connector_status_connected : connector_status_disconnected;
  203. }
  204. static void hdmi_connector_destroy(struct drm_connector *connector)
  205. {
  206. struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
  207. hdp_disable(hdmi_connector);
  208. drm_sysfs_connector_remove(connector);
  209. drm_connector_cleanup(connector);
  210. hdmi_unreference(hdmi_connector->hdmi);
  211. kfree(hdmi_connector);
  212. }
  213. static int hdmi_connector_get_modes(struct drm_connector *connector)
  214. {
  215. struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
  216. struct hdmi *hdmi = hdmi_connector->hdmi;
  217. struct edid *edid;
  218. uint32_t hdmi_ctrl;
  219. int ret = 0;
  220. hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
  221. hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
  222. edid = drm_get_edid(connector, hdmi->i2c);
  223. hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
  224. drm_mode_connector_update_edid_property(connector, edid);
  225. if (edid) {
  226. ret = drm_add_edid_modes(connector, edid);
  227. kfree(edid);
  228. }
  229. return ret;
  230. }
  231. static int hdmi_connector_mode_valid(struct drm_connector *connector,
  232. struct drm_display_mode *mode)
  233. {
  234. struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
  235. struct msm_drm_private *priv = connector->dev->dev_private;
  236. struct msm_kms *kms = priv->kms;
  237. long actual, requested;
  238. requested = 1000 * mode->clock;
  239. actual = kms->funcs->round_pixclk(kms,
  240. requested, hdmi_connector->hdmi->encoder);
  241. DBG("requested=%ld, actual=%ld", requested, actual);
  242. if (actual != requested)
  243. return MODE_CLOCK_RANGE;
  244. return 0;
  245. }
  246. static struct drm_encoder *
  247. hdmi_connector_best_encoder(struct drm_connector *connector)
  248. {
  249. struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
  250. return hdmi_connector->hdmi->encoder;
  251. }
  252. static const struct drm_connector_funcs hdmi_connector_funcs = {
  253. .dpms = drm_helper_connector_dpms,
  254. .detect = hdmi_connector_detect,
  255. .fill_modes = drm_helper_probe_single_connector_modes,
  256. .destroy = hdmi_connector_destroy,
  257. };
  258. static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
  259. .get_modes = hdmi_connector_get_modes,
  260. .mode_valid = hdmi_connector_mode_valid,
  261. .best_encoder = hdmi_connector_best_encoder,
  262. };
  263. /* initialize connector */
  264. struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
  265. {
  266. struct drm_connector *connector = NULL;
  267. struct hdmi_connector *hdmi_connector;
  268. int ret;
  269. hdmi_connector = kzalloc(sizeof(*hdmi_connector), GFP_KERNEL);
  270. if (!hdmi_connector) {
  271. ret = -ENOMEM;
  272. goto fail;
  273. }
  274. hdmi_connector->hdmi = hdmi_reference(hdmi);
  275. connector = &hdmi_connector->base;
  276. drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs,
  277. DRM_MODE_CONNECTOR_HDMIA);
  278. drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
  279. connector->polled = DRM_CONNECTOR_POLL_HPD;
  280. connector->interlace_allowed = 1;
  281. connector->doublescan_allowed = 0;
  282. drm_sysfs_connector_add(connector);
  283. ret = hpd_enable(hdmi_connector);
  284. if (ret) {
  285. dev_err(hdmi->dev->dev, "failed to enable HPD: %d\n", ret);
  286. goto fail;
  287. }
  288. drm_mode_connector_attach_encoder(connector, hdmi->encoder);
  289. return connector;
  290. fail:
  291. if (connector)
  292. hdmi_connector_destroy(connector);
  293. return ERR_PTR(ret);
  294. }