rcar_du_encoder.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * rcar_du_encoder.c -- R-Car Display Unit Encoder
  3. *
  4. * Copyright (C) 2013-2014 Renesas Electronics Corporation
  5. *
  6. * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. */
  13. #include <linux/export.h>
  14. #include <drm/drmP.h>
  15. #include <drm/drm_crtc.h>
  16. #include <drm/drm_crtc_helper.h>
  17. #include <drm/drm_panel.h>
  18. #include "rcar_du_drv.h"
  19. #include "rcar_du_encoder.h"
  20. #include "rcar_du_kms.h"
  21. #include "rcar_du_lvdscon.h"
  22. #include "rcar_du_lvdsenc.h"
  23. /* -----------------------------------------------------------------------------
  24. * Encoder
  25. */
  26. static void rcar_du_encoder_disable(struct drm_encoder *encoder)
  27. {
  28. struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
  29. if (renc->connector && renc->connector->panel) {
  30. drm_panel_disable(renc->connector->panel);
  31. drm_panel_unprepare(renc->connector->panel);
  32. }
  33. if (renc->lvds)
  34. rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, false);
  35. }
  36. static void rcar_du_encoder_enable(struct drm_encoder *encoder)
  37. {
  38. struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
  39. if (renc->lvds)
  40. rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, true);
  41. if (renc->connector && renc->connector->panel) {
  42. drm_panel_prepare(renc->connector->panel);
  43. drm_panel_enable(renc->connector->panel);
  44. }
  45. }
  46. static int rcar_du_encoder_atomic_check(struct drm_encoder *encoder,
  47. struct drm_crtc_state *crtc_state,
  48. struct drm_connector_state *conn_state)
  49. {
  50. struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
  51. struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
  52. const struct drm_display_mode *mode = &crtc_state->mode;
  53. struct drm_connector *connector = conn_state->connector;
  54. struct drm_device *dev = encoder->dev;
  55. /*
  56. * Only panel-related encoder types require validation here, everything
  57. * else is handled by the bridge drivers.
  58. */
  59. if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
  60. const struct drm_display_mode *panel_mode;
  61. if (list_empty(&connector->modes)) {
  62. dev_dbg(dev->dev, "encoder: empty modes list\n");
  63. return -EINVAL;
  64. }
  65. panel_mode = list_first_entry(&connector->modes,
  66. struct drm_display_mode, head);
  67. /* We're not allowed to modify the resolution. */
  68. if (mode->hdisplay != panel_mode->hdisplay ||
  69. mode->vdisplay != panel_mode->vdisplay)
  70. return -EINVAL;
  71. /*
  72. * The flat panel mode is fixed, just copy it to the adjusted
  73. * mode.
  74. */
  75. drm_mode_copy(adjusted_mode, panel_mode);
  76. }
  77. if (renc->lvds)
  78. rcar_du_lvdsenc_atomic_check(renc->lvds, adjusted_mode);
  79. return 0;
  80. }
  81. static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
  82. struct drm_crtc_state *crtc_state,
  83. struct drm_connector_state *conn_state)
  84. {
  85. struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
  86. struct drm_display_info *info = &conn_state->connector->display_info;
  87. enum rcar_lvds_mode mode;
  88. rcar_du_crtc_route_output(crtc_state->crtc, renc->output);
  89. if (!renc->lvds) {
  90. /*
  91. * The DU driver creates connectors only for the outputs of the
  92. * internal LVDS encoders.
  93. */
  94. renc->connector = NULL;
  95. return;
  96. }
  97. renc->connector = to_rcar_connector(conn_state->connector);
  98. if (!info->num_bus_formats || !info->bus_formats) {
  99. dev_err(encoder->dev->dev, "no LVDS bus format reported\n");
  100. return;
  101. }
  102. switch (info->bus_formats[0]) {
  103. case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
  104. case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
  105. mode = RCAR_LVDS_MODE_JEIDA;
  106. break;
  107. case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
  108. mode = RCAR_LVDS_MODE_VESA;
  109. break;
  110. default:
  111. dev_err(encoder->dev->dev,
  112. "unsupported LVDS bus format 0x%04x\n",
  113. info->bus_formats[0]);
  114. return;
  115. }
  116. if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB)
  117. mode |= RCAR_LVDS_MODE_MIRROR;
  118. rcar_du_lvdsenc_set_mode(renc->lvds, mode);
  119. }
  120. static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
  121. .atomic_mode_set = rcar_du_encoder_mode_set,
  122. .disable = rcar_du_encoder_disable,
  123. .enable = rcar_du_encoder_enable,
  124. .atomic_check = rcar_du_encoder_atomic_check,
  125. };
  126. static const struct drm_encoder_funcs encoder_funcs = {
  127. .destroy = drm_encoder_cleanup,
  128. };
  129. int rcar_du_encoder_init(struct rcar_du_device *rcdu,
  130. enum rcar_du_output output,
  131. struct device_node *enc_node,
  132. struct device_node *con_node)
  133. {
  134. struct rcar_du_encoder *renc;
  135. struct drm_encoder *encoder;
  136. struct drm_bridge *bridge = NULL;
  137. int ret;
  138. renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
  139. if (renc == NULL)
  140. return -ENOMEM;
  141. renc->output = output;
  142. encoder = rcar_encoder_to_drm_encoder(renc);
  143. switch (output) {
  144. case RCAR_DU_OUTPUT_LVDS0:
  145. renc->lvds = rcdu->lvds[0];
  146. break;
  147. case RCAR_DU_OUTPUT_LVDS1:
  148. renc->lvds = rcdu->lvds[1];
  149. break;
  150. default:
  151. break;
  152. }
  153. if (enc_node) {
  154. dev_dbg(rcdu->dev, "initializing encoder %s for output %u\n",
  155. of_node_full_name(enc_node), output);
  156. /* Locate the DRM bridge from the encoder DT node. */
  157. bridge = of_drm_find_bridge(enc_node);
  158. if (!bridge) {
  159. ret = -EPROBE_DEFER;
  160. goto done;
  161. }
  162. } else {
  163. dev_dbg(rcdu->dev,
  164. "initializing internal encoder for output %u\n",
  165. output);
  166. }
  167. ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
  168. DRM_MODE_ENCODER_NONE, NULL);
  169. if (ret < 0)
  170. goto done;
  171. drm_encoder_helper_add(encoder, &encoder_helper_funcs);
  172. if (bridge) {
  173. /*
  174. * Attach the bridge to the encoder. The bridge will create the
  175. * connector.
  176. */
  177. ret = drm_bridge_attach(encoder, bridge, NULL);
  178. if (ret) {
  179. drm_encoder_cleanup(encoder);
  180. return ret;
  181. }
  182. } else {
  183. /* There's no bridge, create the connector manually. */
  184. switch (output) {
  185. case RCAR_DU_OUTPUT_LVDS0:
  186. case RCAR_DU_OUTPUT_LVDS1:
  187. ret = rcar_du_lvds_connector_init(rcdu, renc, con_node);
  188. break;
  189. default:
  190. ret = -EINVAL;
  191. break;
  192. }
  193. }
  194. done:
  195. if (ret < 0) {
  196. if (encoder->name)
  197. encoder->funcs->destroy(encoder);
  198. devm_kfree(rcdu->dev, renc);
  199. }
  200. return ret;
  201. }