aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2016-09-29 18:34:43 -0400
committerEric Anholt <eric@anholt.net>2016-10-06 14:58:28 -0400
commit21317b3fba5428c97779cc8a988ac603e82abd8b (patch)
treebd5112275c0eb2253ae44764406d2e67f2ea3317
parent682e62c45406ccf81216481be59c2f7ca5a883d4 (diff)
drm/vc4: Set up the AVI and SPD infoframes.
Fixes a purple bar on the left side of the screen with my Dell 2408WFP. It will also be required for supporting the double-clocked video modes. Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c136
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h5
2 files changed, 136 insertions, 5 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index d94108ca961d..d6b54b905bee 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -62,6 +62,8 @@ struct vc4_hdmi {
62struct vc4_hdmi_encoder { 62struct vc4_hdmi_encoder {
63 struct vc4_encoder base; 63 struct vc4_encoder base;
64 bool hdmi_monitor; 64 bool hdmi_monitor;
65 bool limited_rgb_range;
66 bool rgb_range_selectable;
65}; 67};
66 68
67static inline struct vc4_hdmi_encoder * 69static inline struct vc4_hdmi_encoder *
@@ -205,6 +207,12 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
205 return -ENODEV; 207 return -ENODEV;
206 208
207 vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); 209 vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
210
211 if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
212 vc4_encoder->rgb_range_selectable =
213 drm_rgb_quant_range_selectable(edid);
214 }
215
208 drm_mode_connector_update_edid_property(connector, edid); 216 drm_mode_connector_update_edid_property(connector, edid);
209 ret = drm_add_edid_modes(connector, edid); 217 ret = drm_add_edid_modes(connector, edid);
210 218
@@ -272,6 +280,117 @@ static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = {
272 .destroy = vc4_hdmi_encoder_destroy, 280 .destroy = vc4_hdmi_encoder_destroy,
273}; 281};
274 282
283static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
284 enum hdmi_infoframe_type type)
285{
286 struct drm_device *dev = encoder->dev;
287 struct vc4_dev *vc4 = to_vc4_dev(dev);
288 u32 packet_id = type - 0x80;
289
290 HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
291 HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
292
293 return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
294 BIT(packet_id)), 100);
295}
296
297static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
298 union hdmi_infoframe *frame)
299{
300 struct drm_device *dev = encoder->dev;
301 struct vc4_dev *vc4 = to_vc4_dev(dev);
302 u32 packet_id = frame->any.type - 0x80;
303 u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id;
304 uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
305 ssize_t len, i;
306 int ret;
307
308 WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
309 VC4_HDMI_RAM_PACKET_ENABLE),
310 "Packet RAM has to be on to store the packet.");
311
312 len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
313 if (len < 0)
314 return;
315
316 ret = vc4_hdmi_stop_packet(encoder, frame->any.type);
317 if (ret) {
318 DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret);
319 return;
320 }
321
322 for (i = 0; i < len; i += 7) {
323 HDMI_WRITE(packet_reg,
324 buffer[i + 0] << 0 |
325 buffer[i + 1] << 8 |
326 buffer[i + 2] << 16);
327 packet_reg += 4;
328
329 HDMI_WRITE(packet_reg,
330 buffer[i + 3] << 0 |
331 buffer[i + 4] << 8 |
332 buffer[i + 5] << 16 |
333 buffer[i + 6] << 24);
334 packet_reg += 4;
335 }
336
337 HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
338 HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
339 ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
340 BIT(packet_id)), 100);
341 if (ret)
342 DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
343}
344
345static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
346{
347 struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
348 struct drm_crtc *crtc = encoder->crtc;
349 const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
350 union hdmi_infoframe frame;
351 int ret;
352
353 ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
354 if (ret < 0) {
355 DRM_ERROR("couldn't fill AVI infoframe\n");
356 return;
357 }
358
359 if (vc4_encoder->rgb_range_selectable) {
360 if (vc4_encoder->limited_rgb_range) {
361 frame.avi.quantization_range =
362 HDMI_QUANTIZATION_RANGE_LIMITED;
363 } else {
364 frame.avi.quantization_range =
365 HDMI_QUANTIZATION_RANGE_FULL;
366 }
367 }
368
369 vc4_hdmi_write_infoframe(encoder, &frame);
370}
371
372static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
373{
374 union hdmi_infoframe frame;
375 int ret;
376
377 ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore");
378 if (ret < 0) {
379 DRM_ERROR("couldn't fill SPD infoframe\n");
380 return;
381 }
382
383 frame.spd.sdi = HDMI_SPD_SDI_PC;
384
385 vc4_hdmi_write_infoframe(encoder, &frame);
386}
387
388static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
389{
390 vc4_hdmi_set_avi_infoframe(encoder);
391 vc4_hdmi_set_spd_infoframe(encoder);
392}
393
275static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, 394static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
276 struct drm_display_mode *unadjusted_mode, 395 struct drm_display_mode *unadjusted_mode,
277 struct drm_display_mode *mode) 396 struct drm_display_mode *mode)
@@ -340,8 +459,9 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
340 459
341 if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) { 460 if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
342 /* CEA VICs other than #1 requre limited range RGB 461 /* CEA VICs other than #1 requre limited range RGB
343 * output. Apply a colorspace conversion to squash 462 * output unless overridden by an AVI infoframe.
344 * 0-255 down to 16-235. The matrix here is: 463 * Apply a colorspace conversion to squash 0-255 down
464 * to 16-235. The matrix here is:
345 * 465 *
346 * [ 0 0 0.8594 16] 466 * [ 0 0 0.8594 16]
347 * [ 0 0.8594 0 16] 467 * [ 0 0.8594 0 16]
@@ -359,6 +479,9 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
359 HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000); 479 HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
360 HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0); 480 HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
361 HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000); 481 HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
482 vc4_encoder->limited_rgb_range = true;
483 } else {
484 vc4_encoder->limited_rgb_range = false;
362 } 485 }
363 486
364 /* The RGB order applies even when CSC is disabled. */ 487 /* The RGB order applies even when CSC is disabled. */
@@ -377,6 +500,8 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
377 struct drm_device *dev = encoder->dev; 500 struct drm_device *dev = encoder->dev;
378 struct vc4_dev *vc4 = to_vc4_dev(dev); 501 struct vc4_dev *vc4 = to_vc4_dev(dev);
379 502
503 HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0);
504
380 HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); 505 HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
381 HD_WRITE(VC4_HD_VID_CTL, 506 HD_WRITE(VC4_HD_VID_CTL,
382 HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); 507 HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
@@ -429,9 +554,10 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
429 HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | 554 HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
430 VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT); 555 VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
431 556
432 /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set 557 HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
433 * up the infoframe. 558 VC4_HDMI_RAM_PACKET_ENABLE);
434 */ 559
560 vc4_hdmi_set_infoframes(encoder);
435 561
436 drift = HDMI_READ(VC4_HDMI_FIFO_CTL); 562 drift = HDMI_READ(VC4_HDMI_FIFO_CTL);
437 drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK; 563 drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index c5a423ead86f..0b868aafa8db 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -441,6 +441,8 @@
441#define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 441#define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0
442# define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) 442# define VC4_HDMI_RAM_PACKET_ENABLE BIT(16)
443 443
444#define VC4_HDMI_RAM_PACKET_STATUS 0x0a4
445
444#define VC4_HDMI_HORZA 0x0c4 446#define VC4_HDMI_HORZA 0x0c4
445# define VC4_HDMI_HORZA_VPOS BIT(14) 447# define VC4_HDMI_HORZA_VPOS BIT(14)
446# define VC4_HDMI_HORZA_HPOS BIT(13) 448# define VC4_HDMI_HORZA_HPOS BIT(13)
@@ -502,6 +504,9 @@
502 504
503#define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 505#define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0
504 506
507#define VC4_HDMI_GCP_0 0x400
508#define VC4_HDMI_PACKET_STRIDE 0x24
509
505#define VC4_HD_M_CTL 0x00c 510#define VC4_HD_M_CTL 0x00c
506# define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6) 511# define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6)
507# define VC4_HD_M_RAM_STANDBY (3 << 4) 512# define VC4_HD_M_RAM_STANDBY (3 << 4)