lsdc_output_7a1000.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2023 Loongson Technology Corporation Limited
  4. */
  5. #include <drm/drm_atomic_helper.h>
  6. #include <drm/drm_edid.h>
  7. #include <drm/drm_print.h>
  8. #include <drm/drm_probe_helper.h>
  9. #include "lsdc_drv.h"
  10. #include "lsdc_output.h"
  11. /*
  12. * The display controller in the LS7A1000 exports two DVO interfaces, thus
  13. * external encoder is required, except connected to the DPI panel directly.
  14. *
  15. * ___________________ _________
  16. * | -------| | |
  17. * | CRTC0 --> | DVO0 ----> Encoder0 ---> Connector0 ---> | Display |
  18. * | _ _ -------| ^ ^ |_________|
  19. * | | | | | +------+ | | |
  20. * | |_| |_| | i2c6 | <--------+-------------+
  21. * | +------+ |
  22. * | |
  23. * | DC in LS7A1000 |
  24. * | |
  25. * | _ _ +------+ |
  26. * | | | | | | i2c7 | <--------+-------------+
  27. * | |_| |_| +------+ | | | _________
  28. * | -------| | | | |
  29. * | CRTC1 --> | DVO1 ----> Encoder1 ---> Connector1 ---> | Panel |
  30. * | -------| |_________|
  31. * |___________________|
  32. *
  33. * Currently, we assume the external encoders connected to the DVO are
  34. * transparent. Loongson's DVO interface can directly drive RGB888 panels.
  35. *
  36. * TODO: Add support for non-transparent encoders
  37. */
  38. static int ls7a1000_dpi_connector_get_modes(struct drm_connector *conn)
  39. {
  40. int num;
  41. if (conn->ddc) {
  42. const struct drm_edid *drm_edid;
  43. drm_edid = drm_edid_read(conn);
  44. drm_edid_connector_update(conn, drm_edid);
  45. num = drm_edid_connector_add_modes(conn);
  46. drm_edid_free(drm_edid);
  47. return num;
  48. }
  49. num = drm_add_modes_noedid(conn, 1920, 1200);
  50. drm_set_preferred_mode(conn, 1024, 768);
  51. return num;
  52. }
  53. static struct drm_encoder *
  54. ls7a1000_dpi_connector_get_best_encoder(struct drm_connector *connector,
  55. struct drm_atomic_state *state)
  56. {
  57. struct lsdc_output *output = connector_to_lsdc_output(connector);
  58. return &output->encoder;
  59. }
  60. static const struct drm_connector_helper_funcs
  61. ls7a1000_dpi_connector_helpers = {
  62. .atomic_best_encoder = ls7a1000_dpi_connector_get_best_encoder,
  63. .get_modes = ls7a1000_dpi_connector_get_modes,
  64. };
  65. static enum drm_connector_status
  66. ls7a1000_dpi_connector_detect(struct drm_connector *connector, bool force)
  67. {
  68. struct i2c_adapter *ddc = connector->ddc;
  69. if (ddc) {
  70. if (drm_probe_ddc(ddc))
  71. return connector_status_connected;
  72. return connector_status_disconnected;
  73. }
  74. return connector_status_unknown;
  75. }
  76. static const struct drm_connector_funcs ls7a1000_dpi_connector_funcs = {
  77. .detect = ls7a1000_dpi_connector_detect,
  78. .fill_modes = drm_helper_probe_single_connector_modes,
  79. .destroy = drm_connector_cleanup,
  80. .reset = drm_atomic_helper_connector_reset,
  81. .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
  82. .atomic_destroy_state = drm_atomic_helper_connector_destroy_state
  83. };
  84. static void ls7a1000_pipe0_encoder_reset(struct drm_encoder *encoder)
  85. {
  86. struct drm_device *ddev = encoder->dev;
  87. struct lsdc_device *ldev = to_lsdc(ddev);
  88. /*
  89. * We need this for S3 support, screen will not lightup if don't set
  90. * this register correctly.
  91. */
  92. lsdc_wreg32(ldev, LSDC_CRTC0_DVO_CONF_REG,
  93. PHY_CLOCK_POL | PHY_CLOCK_EN | PHY_DATA_EN);
  94. }
  95. static void ls7a1000_pipe1_encoder_reset(struct drm_encoder *encoder)
  96. {
  97. struct drm_device *ddev = encoder->dev;
  98. struct lsdc_device *ldev = to_lsdc(ddev);
  99. /*
  100. * We need this for S3 support, screen will not lightup if don't set
  101. * this register correctly.
  102. */
  103. /* DVO */
  104. lsdc_wreg32(ldev, LSDC_CRTC1_DVO_CONF_REG,
  105. BIT(31) | PHY_CLOCK_POL | PHY_CLOCK_EN | PHY_DATA_EN);
  106. }
  107. static const struct drm_encoder_funcs ls7a1000_encoder_funcs[2] = {
  108. {
  109. .reset = ls7a1000_pipe0_encoder_reset,
  110. .destroy = drm_encoder_cleanup,
  111. },
  112. {
  113. .reset = ls7a1000_pipe1_encoder_reset,
  114. .destroy = drm_encoder_cleanup,
  115. },
  116. };
  117. int ls7a1000_output_init(struct drm_device *ddev,
  118. struct lsdc_display_pipe *dispipe,
  119. struct i2c_adapter *ddc,
  120. unsigned int index)
  121. {
  122. struct lsdc_output *output = &dispipe->output;
  123. struct drm_encoder *encoder = &output->encoder;
  124. struct drm_connector *connector = &output->connector;
  125. int ret;
  126. ret = drm_encoder_init(ddev, encoder, &ls7a1000_encoder_funcs[index],
  127. DRM_MODE_ENCODER_TMDS, "encoder-%u", index);
  128. if (ret)
  129. return ret;
  130. encoder->possible_crtcs = BIT(index);
  131. ret = drm_connector_init_with_ddc(ddev, connector,
  132. &ls7a1000_dpi_connector_funcs,
  133. DRM_MODE_CONNECTOR_DPI, ddc);
  134. if (ret)
  135. return ret;
  136. drm_info(ddev, "display pipe-%u has a DVO\n", index);
  137. drm_connector_helper_add(connector, &ls7a1000_dpi_connector_helpers);
  138. drm_connector_attach_encoder(connector, encoder);
  139. connector->polled = DRM_CONNECTOR_POLL_CONNECT |
  140. DRM_CONNECTOR_POLL_DISCONNECT;
  141. connector->interlace_allowed = 0;
  142. connector->doublescan_allowed = 0;
  143. return 0;
  144. }