diff options
author | Ilia Mirkin <imirkin@alum.mit.edu> | 2018-09-03 20:57:36 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2018-10-10 19:54:10 -0400 |
commit | 7a406f8a62ff0a3647f96f0cfdb518a99a01bf3f (patch) | |
tree | 1a2ec8e52b52e6d15645cbcc04313b9b4b201953 /drivers/gpu | |
parent | a971558c298755d2c07bc5508c65d689471763c8 (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.c | 40 |
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) | |||
531 | static void | 532 | static void |
532 | nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) | 533 | nv50_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 | /****************************************************************************** |