logicvc_interface.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2019-2022 Bootlin
  4. * Author: Paul Kocialkowski <[email protected]>
  5. */
  6. #include <linux/types.h>
  7. #include <drm/drm_atomic_helper.h>
  8. #include <drm/drm_bridge.h>
  9. #include <drm/drm_connector.h>
  10. #include <drm/drm_crtc_helper.h>
  11. #include <drm/drm_drv.h>
  12. #include <drm/drm_encoder.h>
  13. #include <drm/drm_gem_dma_helper.h>
  14. #include <drm/drm_modeset_helper_vtables.h>
  15. #include <drm/drm_of.h>
  16. #include <drm/drm_panel.h>
  17. #include <drm/drm_print.h>
  18. #include <drm/drm_probe_helper.h>
  19. #include "logicvc_crtc.h"
  20. #include "logicvc_drm.h"
  21. #include "logicvc_interface.h"
  22. #include "logicvc_regs.h"
  23. #define logicvc_interface_from_drm_encoder(c) \
  24. container_of(c, struct logicvc_interface, drm_encoder)
  25. #define logicvc_interface_from_drm_connector(c) \
  26. container_of(c, struct logicvc_interface, drm_connector)
  27. static void logicvc_encoder_enable(struct drm_encoder *drm_encoder)
  28. {
  29. struct logicvc_drm *logicvc = logicvc_drm(drm_encoder->dev);
  30. struct logicvc_interface *interface =
  31. logicvc_interface_from_drm_encoder(drm_encoder);
  32. regmap_update_bits(logicvc->regmap, LOGICVC_POWER_CTRL_REG,
  33. LOGICVC_POWER_CTRL_VIDEO_ENABLE,
  34. LOGICVC_POWER_CTRL_VIDEO_ENABLE);
  35. if (interface->drm_panel) {
  36. drm_panel_prepare(interface->drm_panel);
  37. drm_panel_enable(interface->drm_panel);
  38. }
  39. }
  40. static void logicvc_encoder_disable(struct drm_encoder *drm_encoder)
  41. {
  42. struct logicvc_interface *interface =
  43. logicvc_interface_from_drm_encoder(drm_encoder);
  44. if (interface->drm_panel) {
  45. drm_panel_disable(interface->drm_panel);
  46. drm_panel_unprepare(interface->drm_panel);
  47. }
  48. }
  49. static const struct drm_encoder_helper_funcs logicvc_encoder_helper_funcs = {
  50. .enable = logicvc_encoder_enable,
  51. .disable = logicvc_encoder_disable,
  52. };
  53. static const struct drm_encoder_funcs logicvc_encoder_funcs = {
  54. .destroy = drm_encoder_cleanup,
  55. };
  56. static int logicvc_connector_get_modes(struct drm_connector *drm_connector)
  57. {
  58. struct logicvc_interface *interface =
  59. logicvc_interface_from_drm_connector(drm_connector);
  60. if (interface->drm_panel)
  61. return drm_panel_get_modes(interface->drm_panel, drm_connector);
  62. WARN_ONCE(1, "Retrieving modes from a native connector is not implemented.");
  63. return 0;
  64. }
  65. static const struct drm_connector_helper_funcs logicvc_connector_helper_funcs = {
  66. .get_modes = logicvc_connector_get_modes,
  67. };
  68. static const struct drm_connector_funcs logicvc_connector_funcs = {
  69. .reset = drm_atomic_helper_connector_reset,
  70. .fill_modes = drm_helper_probe_single_connector_modes,
  71. .destroy = drm_connector_cleanup,
  72. .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
  73. .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
  74. };
  75. static int logicvc_interface_encoder_type(struct logicvc_drm *logicvc)
  76. {
  77. switch (logicvc->config.display_interface) {
  78. case LOGICVC_DISPLAY_INTERFACE_LVDS_4BITS:
  79. case LOGICVC_DISPLAY_INTERFACE_LVDS_4BITS_CAMERA:
  80. case LOGICVC_DISPLAY_INTERFACE_LVDS_3BITS:
  81. return DRM_MODE_ENCODER_LVDS;
  82. case LOGICVC_DISPLAY_INTERFACE_DVI:
  83. return DRM_MODE_ENCODER_TMDS;
  84. case LOGICVC_DISPLAY_INTERFACE_RGB:
  85. return DRM_MODE_ENCODER_DPI;
  86. default:
  87. return DRM_MODE_ENCODER_NONE;
  88. }
  89. }
  90. static int logicvc_interface_connector_type(struct logicvc_drm *logicvc)
  91. {
  92. switch (logicvc->config.display_interface) {
  93. case LOGICVC_DISPLAY_INTERFACE_LVDS_4BITS:
  94. case LOGICVC_DISPLAY_INTERFACE_LVDS_4BITS_CAMERA:
  95. case LOGICVC_DISPLAY_INTERFACE_LVDS_3BITS:
  96. return DRM_MODE_CONNECTOR_LVDS;
  97. case LOGICVC_DISPLAY_INTERFACE_DVI:
  98. return DRM_MODE_CONNECTOR_DVID;
  99. case LOGICVC_DISPLAY_INTERFACE_RGB:
  100. return DRM_MODE_CONNECTOR_DPI;
  101. default:
  102. return DRM_MODE_CONNECTOR_Unknown;
  103. }
  104. }
  105. static bool logicvc_interface_native_connector(struct logicvc_drm *logicvc)
  106. {
  107. switch (logicvc->config.display_interface) {
  108. case LOGICVC_DISPLAY_INTERFACE_DVI:
  109. return true;
  110. default:
  111. return false;
  112. }
  113. }
  114. void logicvc_interface_attach_crtc(struct logicvc_drm *logicvc)
  115. {
  116. uint32_t possible_crtcs = drm_crtc_mask(&logicvc->crtc->drm_crtc);
  117. logicvc->interface->drm_encoder.possible_crtcs = possible_crtcs;
  118. }
  119. int logicvc_interface_init(struct logicvc_drm *logicvc)
  120. {
  121. struct logicvc_interface *interface;
  122. struct drm_device *drm_dev = &logicvc->drm_dev;
  123. struct device *dev = drm_dev->dev;
  124. struct device_node *of_node = dev->of_node;
  125. int encoder_type = logicvc_interface_encoder_type(logicvc);
  126. int connector_type = logicvc_interface_connector_type(logicvc);
  127. bool native_connector = logicvc_interface_native_connector(logicvc);
  128. int ret;
  129. interface = devm_kzalloc(dev, sizeof(*interface), GFP_KERNEL);
  130. if (!interface) {
  131. ret = -ENOMEM;
  132. goto error_early;
  133. }
  134. ret = drm_of_find_panel_or_bridge(of_node, 0, 0, &interface->drm_panel,
  135. &interface->drm_bridge);
  136. if (ret == -EPROBE_DEFER)
  137. goto error_early;
  138. ret = drm_encoder_init(drm_dev, &interface->drm_encoder,
  139. &logicvc_encoder_funcs, encoder_type, NULL);
  140. if (ret) {
  141. drm_err(drm_dev, "Failed to initialize encoder\n");
  142. goto error_early;
  143. }
  144. drm_encoder_helper_add(&interface->drm_encoder,
  145. &logicvc_encoder_helper_funcs);
  146. if (native_connector || interface->drm_panel) {
  147. ret = drm_connector_init(drm_dev, &interface->drm_connector,
  148. &logicvc_connector_funcs,
  149. connector_type);
  150. if (ret) {
  151. drm_err(drm_dev, "Failed to initialize connector\n");
  152. goto error_encoder;
  153. }
  154. drm_connector_helper_add(&interface->drm_connector,
  155. &logicvc_connector_helper_funcs);
  156. ret = drm_connector_attach_encoder(&interface->drm_connector,
  157. &interface->drm_encoder);
  158. if (ret) {
  159. drm_err(drm_dev,
  160. "Failed to attach connector to encoder\n");
  161. goto error_encoder;
  162. }
  163. }
  164. if (interface->drm_bridge) {
  165. ret = drm_bridge_attach(&interface->drm_encoder,
  166. interface->drm_bridge, NULL, 0);
  167. if (ret) {
  168. drm_err(drm_dev,
  169. "Failed to attach bridge to encoder\n");
  170. goto error_encoder;
  171. }
  172. }
  173. logicvc->interface = interface;
  174. return 0;
  175. error_encoder:
  176. drm_encoder_cleanup(&interface->drm_encoder);
  177. error_early:
  178. return ret;
  179. }