meson_encoder_cvbs.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2016 BayLibre, SAS
  4. * Author: Neil Armstrong <narmstrong@baylibre.com>
  5. * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
  6. * Copyright (C) 2014 Endless Mobile
  7. *
  8. * Written by:
  9. * Jasper St. Pierre <jstpierre@mecheye.net>
  10. */
  11. #include <linux/export.h>
  12. #include <linux/of_graph.h>
  13. #include <drm/drm_atomic_helper.h>
  14. #include <drm/drm_bridge.h>
  15. #include <drm/drm_bridge_connector.h>
  16. #include <drm/drm_device.h>
  17. #include <drm/drm_edid.h>
  18. #include <drm/drm_probe_helper.h>
  19. #include <drm/drm_simple_kms_helper.h>
  20. #include "meson_registers.h"
  21. #include "meson_vclk.h"
  22. #include "meson_encoder_cvbs.h"
  23. /* HHI VDAC Registers */
  24. #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
  25. #define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */
  26. #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
  27. #define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */
  28. struct meson_encoder_cvbs {
  29. struct drm_encoder encoder;
  30. struct drm_bridge bridge;
  31. struct drm_bridge *next_bridge;
  32. struct meson_drm *priv;
  33. };
  34. #define bridge_to_meson_encoder_cvbs(x) \
  35. container_of(x, struct meson_encoder_cvbs, bridge)
  36. /* Supported Modes */
  37. struct meson_cvbs_mode meson_cvbs_modes[MESON_CVBS_MODES_COUNT] = {
  38. { /* PAL */
  39. .enci = &meson_cvbs_enci_pal,
  40. .mode = {
  41. DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500,
  42. 720, 732, 795, 864, 0, 576, 580, 586, 625, 0,
  43. DRM_MODE_FLAG_INTERLACE),
  44. .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3,
  45. },
  46. },
  47. { /* NTSC */
  48. .enci = &meson_cvbs_enci_ntsc,
  49. .mode = {
  50. DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500,
  51. 720, 739, 801, 858, 0, 480, 488, 494, 525, 0,
  52. DRM_MODE_FLAG_INTERLACE),
  53. .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3,
  54. },
  55. },
  56. };
  57. static const struct meson_cvbs_mode *
  58. meson_cvbs_get_mode(const struct drm_display_mode *req_mode)
  59. {
  60. int i;
  61. for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
  62. struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
  63. if (drm_mode_match(req_mode, &meson_mode->mode,
  64. DRM_MODE_MATCH_TIMINGS |
  65. DRM_MODE_MATCH_CLOCK |
  66. DRM_MODE_MATCH_FLAGS |
  67. DRM_MODE_MATCH_3D_FLAGS))
  68. return meson_mode;
  69. }
  70. return NULL;
  71. }
  72. static int meson_encoder_cvbs_attach(struct drm_bridge *bridge,
  73. enum drm_bridge_attach_flags flags)
  74. {
  75. struct meson_encoder_cvbs *meson_encoder_cvbs =
  76. bridge_to_meson_encoder_cvbs(bridge);
  77. return drm_bridge_attach(bridge->encoder, meson_encoder_cvbs->next_bridge,
  78. &meson_encoder_cvbs->bridge, flags);
  79. }
  80. static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
  81. struct drm_connector *connector)
  82. {
  83. struct meson_encoder_cvbs *meson_encoder_cvbs =
  84. bridge_to_meson_encoder_cvbs(bridge);
  85. struct meson_drm *priv = meson_encoder_cvbs->priv;
  86. struct drm_display_mode *mode;
  87. int i;
  88. for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
  89. struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
  90. mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
  91. if (!mode) {
  92. dev_err(priv->dev, "Failed to create a new display mode\n");
  93. return 0;
  94. }
  95. drm_mode_probed_add(connector, mode);
  96. }
  97. return i;
  98. }
  99. static enum drm_mode_status
  100. meson_encoder_cvbs_mode_valid(struct drm_bridge *bridge,
  101. const struct drm_display_info *display_info,
  102. const struct drm_display_mode *mode)
  103. {
  104. if (meson_cvbs_get_mode(mode))
  105. return MODE_OK;
  106. return MODE_BAD;
  107. }
  108. static int meson_encoder_cvbs_atomic_check(struct drm_bridge *bridge,
  109. struct drm_bridge_state *bridge_state,
  110. struct drm_crtc_state *crtc_state,
  111. struct drm_connector_state *conn_state)
  112. {
  113. if (meson_cvbs_get_mode(&crtc_state->mode))
  114. return 0;
  115. return -EINVAL;
  116. }
  117. static void meson_encoder_cvbs_atomic_enable(struct drm_bridge *bridge,
  118. struct drm_bridge_state *bridge_state)
  119. {
  120. struct meson_encoder_cvbs *encoder_cvbs = bridge_to_meson_encoder_cvbs(bridge);
  121. struct drm_atomic_state *state = bridge_state->base.state;
  122. struct meson_drm *priv = encoder_cvbs->priv;
  123. const struct meson_cvbs_mode *meson_mode;
  124. struct drm_connector_state *conn_state;
  125. struct drm_crtc_state *crtc_state;
  126. struct drm_connector *connector;
  127. connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
  128. if (WARN_ON(!connector))
  129. return;
  130. conn_state = drm_atomic_get_new_connector_state(state, connector);
  131. if (WARN_ON(!conn_state))
  132. return;
  133. crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
  134. if (WARN_ON(!crtc_state))
  135. return;
  136. meson_mode = meson_cvbs_get_mode(&crtc_state->adjusted_mode);
  137. if (WARN_ON(!meson_mode))
  138. return;
  139. meson_venci_cvbs_mode_set(priv, meson_mode->enci);
  140. /* Setup 27MHz vclk2 for ENCI and VDAC */
  141. meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
  142. MESON_VCLK_CVBS, MESON_VCLK_CVBS,
  143. MESON_VCLK_CVBS, MESON_VCLK_CVBS,
  144. true);
  145. /* VDAC0 source is not from ATV */
  146. writel_bits_relaxed(VENC_VDAC_SEL_ATV_DMD, 0,
  147. priv->io_base + _REG(VENC_VDAC_DACSEL0));
  148. if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
  149. regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1);
  150. regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
  151. } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
  152. meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
  153. regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001);
  154. regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
  155. } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
  156. regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0x906001);
  157. regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
  158. }
  159. }
  160. static void meson_encoder_cvbs_atomic_disable(struct drm_bridge *bridge,
  161. struct drm_bridge_state *bridge_state)
  162. {
  163. struct meson_encoder_cvbs *meson_encoder_cvbs =
  164. bridge_to_meson_encoder_cvbs(bridge);
  165. struct meson_drm *priv = meson_encoder_cvbs->priv;
  166. /* Disable CVBS VDAC */
  167. if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
  168. regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0);
  169. regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
  170. } else {
  171. regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
  172. regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
  173. }
  174. }
  175. static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
  176. .attach = meson_encoder_cvbs_attach,
  177. .mode_valid = meson_encoder_cvbs_mode_valid,
  178. .get_modes = meson_encoder_cvbs_get_modes,
  179. .atomic_enable = meson_encoder_cvbs_atomic_enable,
  180. .atomic_disable = meson_encoder_cvbs_atomic_disable,
  181. .atomic_check = meson_encoder_cvbs_atomic_check,
  182. .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
  183. .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
  184. .atomic_reset = drm_atomic_helper_bridge_reset,
  185. };
  186. int meson_encoder_cvbs_probe(struct meson_drm *priv)
  187. {
  188. struct drm_device *drm = priv->drm;
  189. struct meson_encoder_cvbs *meson_encoder_cvbs;
  190. struct drm_connector *connector;
  191. struct device_node *remote;
  192. int ret;
  193. meson_encoder_cvbs = devm_kzalloc(priv->dev, sizeof(*meson_encoder_cvbs), GFP_KERNEL);
  194. if (!meson_encoder_cvbs)
  195. return -ENOMEM;
  196. /* CVBS Connector Bridge */
  197. remote = of_graph_get_remote_node(priv->dev->of_node, 0, 0);
  198. if (!remote) {
  199. dev_info(drm->dev, "CVBS Output connector not available\n");
  200. return 0;
  201. }
  202. meson_encoder_cvbs->next_bridge = of_drm_find_bridge(remote);
  203. of_node_put(remote);
  204. if (!meson_encoder_cvbs->next_bridge)
  205. return dev_err_probe(priv->dev, -EPROBE_DEFER,
  206. "Failed to find CVBS Connector bridge\n");
  207. /* CVBS Encoder Bridge */
  208. meson_encoder_cvbs->bridge.funcs = &meson_encoder_cvbs_bridge_funcs;
  209. meson_encoder_cvbs->bridge.of_node = priv->dev->of_node;
  210. meson_encoder_cvbs->bridge.type = DRM_MODE_CONNECTOR_Composite;
  211. meson_encoder_cvbs->bridge.ops = DRM_BRIDGE_OP_MODES;
  212. meson_encoder_cvbs->bridge.interlace_allowed = true;
  213. drm_bridge_add(&meson_encoder_cvbs->bridge);
  214. meson_encoder_cvbs->priv = priv;
  215. /* Encoder */
  216. ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
  217. DRM_MODE_ENCODER_TVDAC);
  218. if (ret)
  219. return dev_err_probe(priv->dev, ret,
  220. "Failed to init CVBS encoder\n");
  221. meson_encoder_cvbs->encoder.possible_crtcs = BIT(0);
  222. /* Attach CVBS Encoder Bridge to Encoder */
  223. ret = drm_bridge_attach(&meson_encoder_cvbs->encoder, &meson_encoder_cvbs->bridge, NULL,
  224. DRM_BRIDGE_ATTACH_NO_CONNECTOR);
  225. if (ret) {
  226. dev_err(priv->dev, "Failed to attach bridge: %d\n", ret);
  227. return ret;
  228. }
  229. /* Initialize & attach Bridge Connector */
  230. connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
  231. if (IS_ERR(connector))
  232. return dev_err_probe(priv->dev, PTR_ERR(connector),
  233. "Unable to create CVBS bridge connector\n");
  234. drm_connector_attach_encoder(connector, &meson_encoder_cvbs->encoder);
  235. priv->encoders[MESON_ENC_CVBS] = meson_encoder_cvbs;
  236. return 0;
  237. }
  238. void meson_encoder_cvbs_remove(struct meson_drm *priv)
  239. {
  240. struct meson_encoder_cvbs *meson_encoder_cvbs;
  241. if (priv->encoders[MESON_ENC_CVBS]) {
  242. meson_encoder_cvbs = priv->encoders[MESON_ENC_CVBS];
  243. drm_bridge_remove(&meson_encoder_cvbs->bridge);
  244. }
  245. }