0522-drm-vc4-Set-up-the-AVI-and-SPD-infoframes.patch 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. From 76359522fa9c449fb715d1933523c153cc1871f3 Mon Sep 17 00:00:00 2001
  2. From: Eric Anholt <eric@anholt.net>
  3. Date: Thu, 29 Sep 2016 10:34:21 -0700
  4. Subject: [PATCH] drm/vc4: Set up the AVI and SPD infoframes.
  5. Fixes a purple bar on the left side of the screen with my Dell
  6. 2408WFP. It will also be required for supporting the double-clocked
  7. video modes.
  8. Signed-off-by: Eric Anholt <eric@anholt.net>
  9. ---
  10. drivers/gpu/drm/vc4/vc4_hdmi.c | 136 +++++++++++++++++++++++++++++++++++++++--
  11. drivers/gpu/drm/vc4/vc4_regs.h | 5 ++
  12. 2 files changed, 136 insertions(+), 5 deletions(-)
  13. --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
  14. +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
  15. @@ -62,6 +62,8 @@ struct vc4_hdmi {
  16. struct vc4_hdmi_encoder {
  17. struct vc4_encoder base;
  18. bool hdmi_monitor;
  19. + bool limited_rgb_range;
  20. + bool rgb_range_selectable;
  21. };
  22. static inline struct vc4_hdmi_encoder *
  23. @@ -205,6 +207,12 @@ static int vc4_hdmi_connector_get_modes(
  24. return -ENODEV;
  25. vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
  26. +
  27. + if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
  28. + vc4_encoder->rgb_range_selectable =
  29. + drm_rgb_quant_range_selectable(edid);
  30. + }
  31. +
  32. drm_mode_connector_update_edid_property(connector, edid);
  33. ret = drm_add_edid_modes(connector, edid);
  34. @@ -281,6 +289,117 @@ static const struct drm_encoder_funcs vc
  35. .destroy = vc4_hdmi_encoder_destroy,
  36. };
  37. +static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
  38. + enum hdmi_infoframe_type type)
  39. +{
  40. + struct drm_device *dev = encoder->dev;
  41. + struct vc4_dev *vc4 = to_vc4_dev(dev);
  42. + u32 packet_id = type - 0x80;
  43. +
  44. + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
  45. + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
  46. +
  47. + return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
  48. + BIT(packet_id)), 100);
  49. +}
  50. +
  51. +static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
  52. + union hdmi_infoframe *frame)
  53. +{
  54. + struct drm_device *dev = encoder->dev;
  55. + struct vc4_dev *vc4 = to_vc4_dev(dev);
  56. + u32 packet_id = frame->any.type - 0x80;
  57. + u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id;
  58. + uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
  59. + ssize_t len, i;
  60. + int ret;
  61. +
  62. + WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
  63. + VC4_HDMI_RAM_PACKET_ENABLE),
  64. + "Packet RAM has to be on to store the packet.");
  65. +
  66. + len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
  67. + if (len < 0)
  68. + return;
  69. +
  70. + ret = vc4_hdmi_stop_packet(encoder, frame->any.type);
  71. + if (ret) {
  72. + DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret);
  73. + return;
  74. + }
  75. +
  76. + for (i = 0; i < len; i += 7) {
  77. + HDMI_WRITE(packet_reg,
  78. + buffer[i + 0] << 0 |
  79. + buffer[i + 1] << 8 |
  80. + buffer[i + 2] << 16);
  81. + packet_reg += 4;
  82. +
  83. + HDMI_WRITE(packet_reg,
  84. + buffer[i + 3] << 0 |
  85. + buffer[i + 4] << 8 |
  86. + buffer[i + 5] << 16 |
  87. + buffer[i + 6] << 24);
  88. + packet_reg += 4;
  89. + }
  90. +
  91. + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
  92. + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
  93. + ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
  94. + BIT(packet_id)), 100);
  95. + if (ret)
  96. + DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
  97. +}
  98. +
  99. +static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
  100. +{
  101. + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
  102. + struct drm_crtc *crtc = encoder->crtc;
  103. + const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
  104. + union hdmi_infoframe frame;
  105. + int ret;
  106. +
  107. + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
  108. + if (ret < 0) {
  109. + DRM_ERROR("couldn't fill AVI infoframe\n");
  110. + return;
  111. + }
  112. +
  113. + if (vc4_encoder->rgb_range_selectable) {
  114. + if (vc4_encoder->limited_rgb_range) {
  115. + frame.avi.quantization_range =
  116. + HDMI_QUANTIZATION_RANGE_LIMITED;
  117. + } else {
  118. + frame.avi.quantization_range =
  119. + HDMI_QUANTIZATION_RANGE_FULL;
  120. + }
  121. + }
  122. +
  123. + vc4_hdmi_write_infoframe(encoder, &frame);
  124. +}
  125. +
  126. +static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
  127. +{
  128. + union hdmi_infoframe frame;
  129. + int ret;
  130. +
  131. + ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore");
  132. + if (ret < 0) {
  133. + DRM_ERROR("couldn't fill SPD infoframe\n");
  134. + return;
  135. + }
  136. +
  137. + frame.spd.sdi = HDMI_SPD_SDI_PC;
  138. +
  139. + vc4_hdmi_write_infoframe(encoder, &frame);
  140. +}
  141. +
  142. +static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
  143. +{
  144. + vc4_hdmi_set_avi_infoframe(encoder);
  145. + vc4_hdmi_set_spd_infoframe(encoder);
  146. +}
  147. +
  148. static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
  149. struct drm_display_mode *unadjusted_mode,
  150. struct drm_display_mode *mode)
  151. @@ -349,8 +468,9 @@ static void vc4_hdmi_encoder_mode_set(st
  152. if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
  153. /* CEA VICs other than #1 requre limited range RGB
  154. - * output. Apply a colorspace conversion to squash
  155. - * 0-255 down to 16-235. The matrix here is:
  156. + * output unless overridden by an AVI infoframe.
  157. + * Apply a colorspace conversion to squash 0-255 down
  158. + * to 16-235. The matrix here is:
  159. *
  160. * [ 0 0 0.8594 16]
  161. * [ 0 0.8594 0 16]
  162. @@ -368,6 +488,9 @@ static void vc4_hdmi_encoder_mode_set(st
  163. HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
  164. HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
  165. HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
  166. + vc4_encoder->limited_rgb_range = true;
  167. + } else {
  168. + vc4_encoder->limited_rgb_range = false;
  169. }
  170. /* The RGB order applies even when CSC is disabled. */
  171. @@ -386,6 +509,8 @@ static void vc4_hdmi_encoder_disable(str
  172. struct drm_device *dev = encoder->dev;
  173. struct vc4_dev *vc4 = to_vc4_dev(dev);
  174. + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0);
  175. +
  176. HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
  177. HD_WRITE(VC4_HD_VID_CTL,
  178. HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
  179. @@ -438,9 +563,10 @@ static void vc4_hdmi_encoder_enable(stru
  180. HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
  181. VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
  182. - /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set
  183. - * up the infoframe.
  184. - */
  185. + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
  186. + VC4_HDMI_RAM_PACKET_ENABLE);
  187. +
  188. + vc4_hdmi_set_infoframes(encoder);
  189. drift = HDMI_READ(VC4_HDMI_FIFO_CTL);
  190. drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
  191. --- a/drivers/gpu/drm/vc4/vc4_regs.h
  192. +++ b/drivers/gpu/drm/vc4/vc4_regs.h
  193. @@ -443,6 +443,8 @@
  194. #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0
  195. # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16)
  196. +#define VC4_HDMI_RAM_PACKET_STATUS 0x0a4
  197. +
  198. #define VC4_HDMI_HORZA 0x0c4
  199. # define VC4_HDMI_HORZA_VPOS BIT(14)
  200. # define VC4_HDMI_HORZA_HPOS BIT(13)
  201. @@ -504,6 +506,9 @@
  202. #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0
  203. +#define VC4_HDMI_GCP_0 0x400
  204. +#define VC4_HDMI_PACKET_STRIDE 0x24
  205. +
  206. #define VC4_HD_M_CTL 0x00c
  207. # define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6)
  208. # define VC4_HD_M_RAM_STANDBY (3 << 4)