1 From 244fda9f361b276c5697573b7aef7e89ee06c209 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.
6 Fixes a purple bar on the left side of the screen with my Dell
7 2408WFP. It will also be required for supporting the double-clocked
10 Signed-off-by: Eric Anholt <eric@anholt.net>
12 drivers/gpu/drm/vc4/vc4_hdmi.c | 136 +++++++++++++++++++++++++++++++++++++++--
13 drivers/gpu/drm/vc4/vc4_regs.h | 5 ++
14 2 files changed, 136 insertions(+), 5 deletions(-)
16 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
17 +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
18 @@ -62,6 +62,8 @@ struct vc4_hdmi {
19 struct vc4_hdmi_encoder {
20 struct vc4_encoder base;
22 + bool limited_rgb_range;
23 + bool rgb_range_selectable;
26 static inline struct vc4_hdmi_encoder *
27 @@ -205,6 +207,12 @@ static int vc4_hdmi_connector_get_modes(
30 vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
32 + if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
33 + vc4_encoder->rgb_range_selectable =
34 + drm_rgb_quant_range_selectable(edid);
37 drm_mode_connector_update_edid_property(connector, edid);
38 ret = drm_add_edid_modes(connector, edid);
40 @@ -281,6 +289,117 @@ static const struct drm_encoder_funcs vc
41 .destroy = vc4_hdmi_encoder_destroy,
44 +static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
45 + enum hdmi_infoframe_type type)
47 + struct drm_device *dev = encoder->dev;
48 + struct vc4_dev *vc4 = to_vc4_dev(dev);
49 + u32 packet_id = type - 0x80;
51 + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
52 + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
54 + return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
55 + BIT(packet_id)), 100);
58 +static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
59 + union hdmi_infoframe *frame)
61 + struct drm_device *dev = encoder->dev;
62 + struct vc4_dev *vc4 = to_vc4_dev(dev);
63 + u32 packet_id = frame->any.type - 0x80;
64 + u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id;
65 + uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
69 + WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
70 + VC4_HDMI_RAM_PACKET_ENABLE),
71 + "Packet RAM has to be on to store the packet.");
73 + len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
77 + ret = vc4_hdmi_stop_packet(encoder, frame->any.type);
79 + DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret);
83 + for (i = 0; i < len; i += 7) {
84 + HDMI_WRITE(packet_reg,
85 + buffer[i + 0] << 0 |
86 + buffer[i + 1] << 8 |
87 + buffer[i + 2] << 16);
90 + HDMI_WRITE(packet_reg,
91 + buffer[i + 3] << 0 |
92 + buffer[i + 4] << 8 |
93 + buffer[i + 5] << 16 |
94 + buffer[i + 6] << 24);
98 + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
99 + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
100 + ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
101 + BIT(packet_id)), 100);
103 + DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
106 +static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
108 + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
109 + struct drm_crtc *crtc = encoder->crtc;
110 + const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
111 + union hdmi_infoframe frame;
114 + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
116 + DRM_ERROR("couldn't fill AVI infoframe\n");
120 + if (vc4_encoder->rgb_range_selectable) {
121 + if (vc4_encoder->limited_rgb_range) {
122 + frame.avi.quantization_range =
123 + HDMI_QUANTIZATION_RANGE_LIMITED;
125 + frame.avi.quantization_range =
126 + HDMI_QUANTIZATION_RANGE_FULL;
130 + vc4_hdmi_write_infoframe(encoder, &frame);
133 +static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
135 + union hdmi_infoframe frame;
138 + ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore");
140 + DRM_ERROR("couldn't fill SPD infoframe\n");
144 + frame.spd.sdi = HDMI_SPD_SDI_PC;
146 + vc4_hdmi_write_infoframe(encoder, &frame);
149 +static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
151 + vc4_hdmi_set_avi_infoframe(encoder);
152 + vc4_hdmi_set_spd_infoframe(encoder);
155 static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
156 struct drm_display_mode *unadjusted_mode,
157 struct drm_display_mode *mode)
158 @@ -349,8 +468,9 @@ static void vc4_hdmi_encoder_mode_set(st
160 if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
161 /* CEA VICs other than #1 requre limited range RGB
162 - * output. Apply a colorspace conversion to squash
163 - * 0-255 down to 16-235. The matrix here is:
164 + * output unless overridden by an AVI infoframe.
165 + * Apply a colorspace conversion to squash 0-255 down
166 + * to 16-235. The matrix here is:
170 @@ -368,6 +488,9 @@ static void vc4_hdmi_encoder_mode_set(st
171 HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
172 HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
173 HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
174 + vc4_encoder->limited_rgb_range = true;
176 + vc4_encoder->limited_rgb_range = false;
179 /* The RGB order applies even when CSC is disabled. */
180 @@ -386,6 +509,8 @@ static void vc4_hdmi_encoder_disable(str
181 struct drm_device *dev = encoder->dev;
182 struct vc4_dev *vc4 = to_vc4_dev(dev);
184 + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0);
186 HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
187 HD_WRITE(VC4_HD_VID_CTL,
188 HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
189 @@ -438,9 +563,10 @@ static void vc4_hdmi_encoder_enable(stru
190 HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
191 VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
193 - /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set
194 - * up the infoframe.
196 + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
197 + VC4_HDMI_RAM_PACKET_ENABLE);
199 + vc4_hdmi_set_infoframes(encoder);
201 drift = HDMI_READ(VC4_HDMI_FIFO_CTL);
202 drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
203 --- a/drivers/gpu/drm/vc4/vc4_regs.h
204 +++ b/drivers/gpu/drm/vc4/vc4_regs.h
206 #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0
207 # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16)
209 +#define VC4_HDMI_RAM_PACKET_STATUS 0x0a4
211 #define VC4_HDMI_HORZA 0x0c4
212 # define VC4_HDMI_HORZA_VPOS BIT(14)
213 # define VC4_HDMI_HORZA_HPOS BIT(13)
216 #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0
218 +#define VC4_HDMI_GCP_0 0x400
219 +#define VC4_HDMI_PACKET_STRIDE 0x24
221 #define VC4_HD_M_CTL 0x00c
222 # define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6)
223 # define VC4_HD_M_RAM_STANDBY (3 << 4)