aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorIlia Mirkin <imirkin@alum.mit.edu>2018-09-03 20:57:36 -0400
committerBen Skeggs <bskeggs@redhat.com>2018-10-10 19:54:10 -0400
commit7a406f8a62ff0a3647f96f0cfdb518a99a01bf3f (patch)
tree1a2ec8e52b52e6d15645cbcc04313b9b4b201953 /drivers/gpu
parenta971558c298755d2c07bc5508c65d689471763c8 (diff)
drm/nouveau/disp: add support for setting scdc parameters for high modes
When SCDC is supported, make sure that we configure the GPU and monitor to the same parameters. Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 1dbd1dcdcf15..5f163a025e89 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -36,6 +36,7 @@
36#include <drm/drm_dp_helper.h> 36#include <drm/drm_dp_helper.h>
37#include <drm/drm_fb_helper.h> 37#include <drm/drm_fb_helper.h>
38#include <drm/drm_plane_helper.h> 38#include <drm/drm_plane_helper.h>
39#include <drm/drm_scdc_helper.h>
39#include <drm/drm_edid.h> 40#include <drm/drm_edid.h>
40 41
41#include <nvif/class.h> 42#include <nvif/class.h>
@@ -531,6 +532,7 @@ nv50_hdmi_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
531static void 532static void
532nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) 533nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode)
533{ 534{
535 struct nouveau_drm *drm = nouveau_drm(encoder->dev);
534 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 536 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
535 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); 537 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
536 struct nv50_disp *disp = nv50_disp(encoder->dev); 538 struct nv50_disp *disp = nv50_disp(encoder->dev);
@@ -548,9 +550,12 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode)
548 .pwr.rekey = 56, /* binary driver, and tegra, constant */ 550 .pwr.rekey = 56, /* binary driver, and tegra, constant */
549 }; 551 };
550 struct nouveau_connector *nv_connector; 552 struct nouveau_connector *nv_connector;
553 struct drm_hdmi_info *hdmi;
551 u32 max_ac_packet; 554 u32 max_ac_packet;
552 union hdmi_infoframe avi_frame; 555 union hdmi_infoframe avi_frame;
553 union hdmi_infoframe vendor_frame; 556 union hdmi_infoframe vendor_frame;
557 bool scdc_supported, high_tmds_clock_ratio = false, scrambling = false;
558 u8 config;
554 int ret; 559 int ret;
555 int size; 560 int size;
556 561
@@ -558,8 +563,11 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode)
558 if (!drm_detect_hdmi_monitor(nv_connector->edid)) 563 if (!drm_detect_hdmi_monitor(nv_connector->edid))
559 return; 564 return;
560 565
566 hdmi = &nv_connector->base.display_info.hdmi;
567 scdc_supported = hdmi->scdc.supported;
568
561 ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode, 569 ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode,
562 false); 570 scdc_supported);
563 if (!ret) { 571 if (!ret) {
564 /* We have an AVI InfoFrame, populate it to the display */ 572 /* We have an AVI InfoFrame, populate it to the display */
565 args.pwr.avi_infoframe_length 573 args.pwr.avi_infoframe_length
@@ -582,12 +590,42 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode)
582 max_ac_packet -= 18; /* constant from tegra */ 590 max_ac_packet -= 18; /* constant from tegra */
583 args.pwr.max_ac_packet = max_ac_packet / 32; 591 args.pwr.max_ac_packet = max_ac_packet / 32;
584 592
593 if (hdmi->scdc.scrambling.supported) {
594 high_tmds_clock_ratio = mode->clock > 340000;
595 scrambling = high_tmds_clock_ratio ||
596 hdmi->scdc.scrambling.low_rates;
597 }
598
599 args.pwr.scdc =
600 NV50_DISP_SOR_HDMI_PWR_V0_SCDC_SCRAMBLE * scrambling |
601 NV50_DISP_SOR_HDMI_PWR_V0_SCDC_DIV_BY_4 * high_tmds_clock_ratio;
602
585 size = sizeof(args.base) 603 size = sizeof(args.base)
586 + sizeof(args.pwr) 604 + sizeof(args.pwr)
587 + args.pwr.avi_infoframe_length 605 + args.pwr.avi_infoframe_length
588 + args.pwr.vendor_infoframe_length; 606 + args.pwr.vendor_infoframe_length;
589 nvif_mthd(&disp->disp->object, 0, &args, size); 607 nvif_mthd(&disp->disp->object, 0, &args, size);
608
590 nv50_audio_enable(encoder, mode); 609 nv50_audio_enable(encoder, mode);
610
611 /* If SCDC is supported by the downstream monitor, update
612 * divider / scrambling settings to what we programmed above.
613 */
614 if (!hdmi->scdc.scrambling.supported)
615 return;
616
617 ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &config);
618 if (ret < 0) {
619 NV_ERROR(drm, "Failure to read SCDC_TMDS_CONFIG: %d\n", ret);
620 return;
621 }
622 config &= ~(SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE);
623 config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 * high_tmds_clock_ratio;
624 config |= SCDC_SCRAMBLING_ENABLE * scrambling;
625 ret = drm_scdc_writeb(nv_encoder->i2c, SCDC_TMDS_CONFIG, config);
626 if (ret < 0)
627 NV_ERROR(drm, "Failure to write SCDC_TMDS_CONFIG = 0x%02x: %d\n",
628 config, ret);
591} 629}
592 630
593/****************************************************************************** 631/******************************************************************************