diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2011-05-20 04:34:16 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-05-20 06:02:21 -0400 |
commit | 8e8e523d865490e95ed7c9d2e173c02648d6be90 (patch) | |
tree | cfab46ff01a706afd4b21558ee879e433b071cbf /drivers/gpu/drm/radeon/atombios_crtc.c | |
parent | df271bec805b42527d864777ed035fcbb42e76c0 (diff) |
drm/radeon/kms: spread spectrum fixes
- properly mask the ss type
- don't enable ss if type is external or percentage is 0
- if ss enabled and type is external, set ref_div_src to ext clock
- prefer ASIC_INTERNAL_SS_ON_DP to LCD_Info SS_Id for eDP
- fix ss amount calculation
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/atombios_crtc.c')
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_crtc.c | 52 |
1 files changed, 36 insertions, 16 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 608b1c20a768..ff0d1cad1012 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
@@ -420,7 +420,7 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc, | |||
420 | 420 | ||
421 | if (ASIC_IS_DCE5(rdev)) { | 421 | if (ASIC_IS_DCE5(rdev)) { |
422 | args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0); | 422 | args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0); |
423 | args.v3.ucSpreadSpectrumType = ss->type; | 423 | args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; |
424 | switch (pll_id) { | 424 | switch (pll_id) { |
425 | case ATOM_PPLL1: | 425 | case ATOM_PPLL1: |
426 | args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; | 426 | args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; |
@@ -441,9 +441,11 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc, | |||
441 | return; | 441 | return; |
442 | } | 442 | } |
443 | args.v2.ucEnable = enable; | 443 | args.v2.ucEnable = enable; |
444 | if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK)) | ||
445 | args.v3.ucEnable = ATOM_DISABLE; | ||
444 | } else if (ASIC_IS_DCE4(rdev)) { | 446 | } else if (ASIC_IS_DCE4(rdev)) { |
445 | args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); | 447 | args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
446 | args.v2.ucSpreadSpectrumType = ss->type; | 448 | args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; |
447 | switch (pll_id) { | 449 | switch (pll_id) { |
448 | case ATOM_PPLL1: | 450 | case ATOM_PPLL1: |
449 | args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; | 451 | args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; |
@@ -464,32 +466,36 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc, | |||
464 | return; | 466 | return; |
465 | } | 467 | } |
466 | args.v2.ucEnable = enable; | 468 | args.v2.ucEnable = enable; |
469 | if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK)) | ||
470 | args.v2.ucEnable = ATOM_DISABLE; | ||
467 | } else if (ASIC_IS_DCE3(rdev)) { | 471 | } else if (ASIC_IS_DCE3(rdev)) { |
468 | args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); | 472 | args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
469 | args.v1.ucSpreadSpectrumType = ss->type; | 473 | args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; |
470 | args.v1.ucSpreadSpectrumStep = ss->step; | 474 | args.v1.ucSpreadSpectrumStep = ss->step; |
471 | args.v1.ucSpreadSpectrumDelay = ss->delay; | 475 | args.v1.ucSpreadSpectrumDelay = ss->delay; |
472 | args.v1.ucSpreadSpectrumRange = ss->range; | 476 | args.v1.ucSpreadSpectrumRange = ss->range; |
473 | args.v1.ucPpll = pll_id; | 477 | args.v1.ucPpll = pll_id; |
474 | args.v1.ucEnable = enable; | 478 | args.v1.ucEnable = enable; |
475 | } else if (ASIC_IS_AVIVO(rdev)) { | 479 | } else if (ASIC_IS_AVIVO(rdev)) { |
476 | if (enable == ATOM_DISABLE) { | 480 | if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || |
481 | (ss->type & ATOM_EXTERNAL_SS_MASK)) { | ||
477 | atombios_disable_ss(crtc); | 482 | atombios_disable_ss(crtc); |
478 | return; | 483 | return; |
479 | } | 484 | } |
480 | args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); | 485 | args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
481 | args.lvds_ss_2.ucSpreadSpectrumType = ss->type; | 486 | args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; |
482 | args.lvds_ss_2.ucSpreadSpectrumStep = ss->step; | 487 | args.lvds_ss_2.ucSpreadSpectrumStep = ss->step; |
483 | args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay; | 488 | args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay; |
484 | args.lvds_ss_2.ucSpreadSpectrumRange = ss->range; | 489 | args.lvds_ss_2.ucSpreadSpectrumRange = ss->range; |
485 | args.lvds_ss_2.ucEnable = enable; | 490 | args.lvds_ss_2.ucEnable = enable; |
486 | } else { | 491 | } else { |
487 | if (enable == ATOM_DISABLE) { | 492 | if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || |
493 | (ss->type & ATOM_EXTERNAL_SS_MASK)) { | ||
488 | atombios_disable_ss(crtc); | 494 | atombios_disable_ss(crtc); |
489 | return; | 495 | return; |
490 | } | 496 | } |
491 | args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); | 497 | args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
492 | args.lvds_ss.ucSpreadSpectrumType = ss->type; | 498 | args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; |
493 | args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2; | 499 | args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2; |
494 | args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4; | 500 | args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4; |
495 | args.lvds_ss.ucEnable = enable; | 501 | args.lvds_ss.ucEnable = enable; |
@@ -615,7 +621,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, | |||
615 | args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); | 621 | args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); |
616 | args.v1.ucTransmitterID = radeon_encoder->encoder_id; | 622 | args.v1.ucTransmitterID = radeon_encoder->encoder_id; |
617 | args.v1.ucEncodeMode = encoder_mode; | 623 | args.v1.ucEncodeMode = encoder_mode; |
618 | if (ss_enabled) | 624 | if (ss_enabled && ss->percentage) |
619 | args.v1.ucConfig |= | 625 | args.v1.ucConfig |= |
620 | ADJUST_DISPLAY_CONFIG_SS_ENABLE; | 626 | ADJUST_DISPLAY_CONFIG_SS_ENABLE; |
621 | 627 | ||
@@ -628,7 +634,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, | |||
628 | args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; | 634 | args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; |
629 | args.v3.sInput.ucEncodeMode = encoder_mode; | 635 | args.v3.sInput.ucEncodeMode = encoder_mode; |
630 | args.v3.sInput.ucDispPllConfig = 0; | 636 | args.v3.sInput.ucDispPllConfig = 0; |
631 | if (ss_enabled) | 637 | if (ss_enabled && ss->percentage) |
632 | args.v3.sInput.ucDispPllConfig |= | 638 | args.v3.sInput.ucDispPllConfig |= |
633 | DISPPLL_CONFIG_SS_ENABLE; | 639 | DISPPLL_CONFIG_SS_ENABLE; |
634 | if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { | 640 | if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { |
@@ -758,7 +764,9 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc, | |||
758 | u32 fb_div, | 764 | u32 fb_div, |
759 | u32 frac_fb_div, | 765 | u32 frac_fb_div, |
760 | u32 post_div, | 766 | u32 post_div, |
761 | int bpc) | 767 | int bpc, |
768 | bool ss_enabled, | ||
769 | struct radeon_atom_ss *ss) | ||
762 | { | 770 | { |
763 | struct drm_device *dev = crtc->dev; | 771 | struct drm_device *dev = crtc->dev; |
764 | struct radeon_device *rdev = dev->dev_private; | 772 | struct radeon_device *rdev = dev->dev_private; |
@@ -816,6 +824,8 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc, | |||
816 | args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); | 824 | args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); |
817 | args.v5.ucPostDiv = post_div; | 825 | args.v5.ucPostDiv = post_div; |
818 | args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ | 826 | args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ |
827 | if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) | ||
828 | args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; | ||
819 | switch (bpc) { | 829 | switch (bpc) { |
820 | case 8: | 830 | case 8: |
821 | default: | 831 | default: |
@@ -837,6 +847,8 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc, | |||
837 | args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); | 847 | args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); |
838 | args.v6.ucPostDiv = post_div; | 848 | args.v6.ucPostDiv = post_div; |
839 | args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ | 849 | args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ |
850 | if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) | ||
851 | args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; | ||
840 | switch (bpc) { | 852 | switch (bpc) { |
841 | case 8: | 853 | case 8: |
842 | default: | 854 | default: |
@@ -927,12 +939,18 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode | |||
927 | /* DP/eDP */ | 939 | /* DP/eDP */ |
928 | dp_clock = dig_connector->dp_clock / 10; | 940 | dp_clock = dig_connector->dp_clock / 10; |
929 | if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { | 941 | if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { |
930 | if (ASIC_IS_DCE4(rdev)) | 942 | if (ASIC_IS_DCE4(rdev)) { |
943 | /* first try ASIC_INTERNAL_SS_ON_DP */ | ||
931 | ss_enabled = | 944 | ss_enabled = |
932 | radeon_atombios_get_asic_ss_info(rdev, &ss, | 945 | radeon_atombios_get_asic_ss_info(rdev, &ss, |
933 | dig->lcd_ss_id, | 946 | ASIC_INTERNAL_SS_ON_DP, |
934 | dp_clock); | 947 | dp_clock); |
935 | else | 948 | if (!ss_enabled) |
949 | ss_enabled = | ||
950 | radeon_atombios_get_asic_ss_info(rdev, &ss, | ||
951 | dig->lcd_ss_id, | ||
952 | dp_clock); | ||
953 | } else | ||
936 | ss_enabled = | 954 | ss_enabled = |
937 | radeon_atombios_get_ppll_ss_info(rdev, &ss, | 955 | radeon_atombios_get_ppll_ss_info(rdev, &ss, |
938 | dig->lcd_ss_id); | 956 | dig->lcd_ss_id); |
@@ -1004,7 +1022,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode | |||
1004 | 1022 | ||
1005 | atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, | 1023 | atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, |
1006 | encoder_mode, radeon_encoder->encoder_id, mode->clock, | 1024 | encoder_mode, radeon_encoder->encoder_id, mode->clock, |
1007 | ref_div, fb_div, frac_fb_div, post_div, bpc); | 1025 | ref_div, fb_div, frac_fb_div, post_div, bpc, ss_enabled, &ss); |
1008 | 1026 | ||
1009 | if (ss_enabled) { | 1027 | if (ss_enabled) { |
1010 | /* calculate ss amount and step size */ | 1028 | /* calculate ss amount and step size */ |
@@ -1012,7 +1030,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode | |||
1012 | u32 step_size; | 1030 | u32 step_size; |
1013 | u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000; | 1031 | u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000; |
1014 | ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; | 1032 | ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; |
1015 | ss.amount |= ((amount - (ss.amount * 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & | 1033 | ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & |
1016 | ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; | 1034 | ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; |
1017 | if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) | 1035 | if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) |
1018 | step_size = (4 * amount * ref_div * (ss.rate * 2048)) / | 1036 | step_size = (4 * amount * ref_div * (ss.rate * 2048)) / |
@@ -1545,6 +1563,8 @@ static void atombios_crtc_commit(struct drm_crtc *crtc) | |||
1545 | static void atombios_crtc_disable(struct drm_crtc *crtc) | 1563 | static void atombios_crtc_disable(struct drm_crtc *crtc) |
1546 | { | 1564 | { |
1547 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | 1565 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
1566 | struct radeon_atom_ss ss; | ||
1567 | |||
1548 | atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | 1568 | atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
1549 | 1569 | ||
1550 | switch (radeon_crtc->pll_id) { | 1570 | switch (radeon_crtc->pll_id) { |
@@ -1552,7 +1572,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) | |||
1552 | case ATOM_PPLL2: | 1572 | case ATOM_PPLL2: |
1553 | /* disable the ppll */ | 1573 | /* disable the ppll */ |
1554 | atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, | 1574 | atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, |
1555 | 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0); | 1575 | 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); |
1556 | break; | 1576 | break; |
1557 | default: | 1577 | default: |
1558 | break; | 1578 | break; |