diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2010-10-04 17:13:01 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-10-05 21:46:26 -0400 |
commit | ba032a58d1f320039e7850fb6e8651695c1aa571 (patch) | |
tree | f883a015e10d00b79505d16682d504e6914118e8 /drivers/gpu | |
parent | 48dfaaeb6637240af3089bf9b7a00a6cf24e0182 (diff) |
drm/radeon/kms: rework spread spectrum handling
This patch reworks spread spectrum handling to enable it
properly on lvds and DP/eDP links. It also fixes several
bugs in the old spread spectrum code.
- Use the ss recommended reference divider if available
when calculating the pll
- Use the proper ss command tables on pre-DCE3 asics
- Avoid reading past the end of the ss info tables
- Enable ss on evergreen asics (lvds, dp, tmds)
- Enable ss on DP/eDP links
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_crtc.c | 255 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 114 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_encoders.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 20 |
4 files changed, 305 insertions, 100 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 89600e344230..7238f3f54aa6 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
@@ -398,65 +398,76 @@ static void atombios_disable_ss(struct drm_crtc *crtc) | |||
398 | 398 | ||
399 | 399 | ||
400 | union atom_enable_ss { | 400 | union atom_enable_ss { |
401 | ENABLE_LVDS_SS_PARAMETERS legacy; | 401 | ENABLE_LVDS_SS_PARAMETERS lvds_ss; |
402 | ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2; | ||
402 | ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; | 403 | ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; |
404 | ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2; | ||
403 | }; | 405 | }; |
404 | 406 | ||
405 | static void atombios_enable_ss(struct drm_crtc *crtc) | 407 | static void atombios_crtc_program_ss(struct drm_crtc *crtc, |
408 | int enable, | ||
409 | int pll_id, | ||
410 | struct radeon_atom_ss *ss) | ||
406 | { | 411 | { |
407 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
408 | struct drm_device *dev = crtc->dev; | 412 | struct drm_device *dev = crtc->dev; |
409 | struct radeon_device *rdev = dev->dev_private; | 413 | struct radeon_device *rdev = dev->dev_private; |
410 | struct drm_encoder *encoder = NULL; | ||
411 | struct radeon_encoder *radeon_encoder = NULL; | ||
412 | struct radeon_encoder_atom_dig *dig = NULL; | ||
413 | int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); | 414 | int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); |
414 | union atom_enable_ss args; | 415 | union atom_enable_ss args; |
415 | uint16_t percentage = 0; | ||
416 | uint8_t type = 0, step = 0, delay = 0, range = 0; | ||
417 | 416 | ||
418 | /* XXX add ss support for DCE4 */ | 417 | memset(&args, 0, sizeof(args)); |
419 | if (ASIC_IS_DCE4(rdev)) | ||
420 | return; | ||
421 | 418 | ||
422 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | 419 | if (ASIC_IS_DCE4(rdev)) { |
423 | if (encoder->crtc == crtc) { | 420 | args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
424 | radeon_encoder = to_radeon_encoder(encoder); | 421 | args.v2.ucSpreadSpectrumType = ss->type; |
425 | /* only enable spread spectrum on LVDS */ | 422 | switch (pll_id) { |
426 | if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { | 423 | case ATOM_PPLL1: |
427 | dig = radeon_encoder->enc_priv; | 424 | args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; |
428 | if (dig && dig->ss) { | 425 | args.v2.usSpreadSpectrumAmount = ss->amount; |
429 | percentage = dig->ss->percentage; | 426 | args.v2.usSpreadSpectrumStep = ss->step; |
430 | type = dig->ss->type; | 427 | break; |
431 | step = dig->ss->step; | 428 | case ATOM_PPLL2: |
432 | delay = dig->ss->delay; | 429 | args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL; |
433 | range = dig->ss->range; | 430 | args.v2.usSpreadSpectrumAmount = ss->amount; |
434 | } else | 431 | args.v2.usSpreadSpectrumStep = ss->step; |
435 | return; | ||
436 | } else | ||
437 | return; | ||
438 | break; | 432 | break; |
433 | case ATOM_DCPLL: | ||
434 | args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL; | ||
435 | args.v2.usSpreadSpectrumAmount = 0; | ||
436 | args.v2.usSpreadSpectrumStep = 0; | ||
437 | break; | ||
438 | case ATOM_PPLL_INVALID: | ||
439 | return; | ||
439 | } | 440 | } |
440 | } | 441 | args.v2.ucEnable = enable; |
441 | 442 | } else if (ASIC_IS_DCE3(rdev)) { | |
442 | if (!radeon_encoder) | 443 | args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
443 | return; | 444 | args.v1.ucSpreadSpectrumType = ss->type; |
444 | 445 | args.v1.ucSpreadSpectrumStep = ss->step; | |
445 | memset(&args, 0, sizeof(args)); | 446 | args.v1.ucSpreadSpectrumDelay = ss->delay; |
446 | if (ASIC_IS_AVIVO(rdev)) { | 447 | args.v1.ucSpreadSpectrumRange = ss->range; |
447 | args.v1.usSpreadSpectrumPercentage = cpu_to_le16(percentage); | 448 | args.v1.ucPpll = pll_id; |
448 | args.v1.ucSpreadSpectrumType = type; | 449 | args.v1.ucEnable = enable; |
449 | args.v1.ucSpreadSpectrumStep = step; | 450 | } else if (ASIC_IS_AVIVO(rdev)) { |
450 | args.v1.ucSpreadSpectrumDelay = delay; | 451 | if (enable == ATOM_DISABLE) { |
451 | args.v1.ucSpreadSpectrumRange = range; | 452 | atombios_disable_ss(crtc); |
452 | args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; | 453 | return; |
453 | args.v1.ucEnable = ATOM_ENABLE; | 454 | } |
455 | args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); | ||
456 | args.lvds_ss_2.ucSpreadSpectrumType = ss->type; | ||
457 | args.lvds_ss_2.ucSpreadSpectrumStep = ss->step; | ||
458 | args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay; | ||
459 | args.lvds_ss_2.ucSpreadSpectrumRange = ss->range; | ||
460 | args.lvds_ss_2.ucEnable = enable; | ||
454 | } else { | 461 | } else { |
455 | args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage); | 462 | if (enable == ATOM_DISABLE) { |
456 | args.legacy.ucSpreadSpectrumType = type; | 463 | atombios_disable_ss(crtc); |
457 | args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2; | 464 | return; |
458 | args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4; | 465 | } |
459 | args.legacy.ucEnable = ATOM_ENABLE; | 466 | args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
467 | args.lvds_ss.ucSpreadSpectrumType = ss->type; | ||
468 | args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2; | ||
469 | args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4; | ||
470 | args.lvds_ss.ucEnable = enable; | ||
460 | } | 471 | } |
461 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | 472 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
462 | } | 473 | } |
@@ -468,7 +479,9 @@ union adjust_pixel_clock { | |||
468 | 479 | ||
469 | static u32 atombios_adjust_pll(struct drm_crtc *crtc, | 480 | static u32 atombios_adjust_pll(struct drm_crtc *crtc, |
470 | struct drm_display_mode *mode, | 481 | struct drm_display_mode *mode, |
471 | struct radeon_pll *pll) | 482 | struct radeon_pll *pll, |
483 | bool ss_enabled, | ||
484 | struct radeon_atom_ss *ss) | ||
472 | { | 485 | { |
473 | struct drm_device *dev = crtc->dev; | 486 | struct drm_device *dev = crtc->dev; |
474 | struct radeon_device *rdev = dev->dev_private; | 487 | struct radeon_device *rdev = dev->dev_private; |
@@ -506,6 +519,16 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, | |||
506 | } | 519 | } |
507 | } | 520 | } |
508 | 521 | ||
522 | /* use recommended ref_div for ss */ | ||
523 | if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { | ||
524 | if (ss_enabled) { | ||
525 | if (ss->refdiv) { | ||
526 | pll->flags |= RADEON_PLL_USE_REF_DIV; | ||
527 | pll->reference_div = ss->refdiv; | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | |||
509 | if (ASIC_IS_AVIVO(rdev)) { | 532 | if (ASIC_IS_AVIVO(rdev)) { |
510 | /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ | 533 | /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ |
511 | if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) | 534 | if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) |
@@ -547,9 +570,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, | |||
547 | args.v1.ucTransmitterID = radeon_encoder->encoder_id; | 570 | args.v1.ucTransmitterID = radeon_encoder->encoder_id; |
548 | args.v1.ucEncodeMode = encoder_mode; | 571 | args.v1.ucEncodeMode = encoder_mode; |
549 | if (encoder_mode == ATOM_ENCODER_MODE_DP) { | 572 | if (encoder_mode == ATOM_ENCODER_MODE_DP) { |
550 | /* may want to enable SS on DP eventually */ | 573 | if (ss_enabled) |
551 | /* args.v1.ucConfig |= | 574 | args.v1.ucConfig |= |
552 | ADJUST_DISPLAY_CONFIG_SS_ENABLE;*/ | 575 | ADJUST_DISPLAY_CONFIG_SS_ENABLE; |
553 | } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { | 576 | } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { |
554 | args.v1.ucConfig |= | 577 | args.v1.ucConfig |= |
555 | ADJUST_DISPLAY_CONFIG_SS_ENABLE; | 578 | ADJUST_DISPLAY_CONFIG_SS_ENABLE; |
@@ -566,11 +589,10 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, | |||
566 | args.v3.sInput.ucDispPllConfig = 0; | 589 | args.v3.sInput.ucDispPllConfig = 0; |
567 | if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { | 590 | if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { |
568 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | 591 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
569 | |||
570 | if (encoder_mode == ATOM_ENCODER_MODE_DP) { | 592 | if (encoder_mode == ATOM_ENCODER_MODE_DP) { |
571 | /* may want to enable SS on DP/eDP eventually */ | 593 | if (ss_enabled) |
572 | /*args.v3.sInput.ucDispPllConfig |= | 594 | args.v3.sInput.ucDispPllConfig |= |
573 | DISPPLL_CONFIG_SS_ENABLE;*/ | 595 | DISPPLL_CONFIG_SS_ENABLE; |
574 | args.v3.sInput.ucDispPllConfig |= | 596 | args.v3.sInput.ucDispPllConfig |= |
575 | DISPPLL_CONFIG_COHERENT_MODE; | 597 | DISPPLL_CONFIG_COHERENT_MODE; |
576 | /* 16200 or 27000 */ | 598 | /* 16200 or 27000 */ |
@@ -590,17 +612,17 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, | |||
590 | } | 612 | } |
591 | } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { | 613 | } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
592 | if (encoder_mode == ATOM_ENCODER_MODE_DP) { | 614 | if (encoder_mode == ATOM_ENCODER_MODE_DP) { |
593 | /* may want to enable SS on DP/eDP eventually */ | 615 | if (ss_enabled) |
594 | /*args.v3.sInput.ucDispPllConfig |= | 616 | args.v3.sInput.ucDispPllConfig |= |
595 | DISPPLL_CONFIG_SS_ENABLE;*/ | 617 | DISPPLL_CONFIG_SS_ENABLE; |
596 | args.v3.sInput.ucDispPllConfig |= | 618 | args.v3.sInput.ucDispPllConfig |= |
597 | DISPPLL_CONFIG_COHERENT_MODE; | 619 | DISPPLL_CONFIG_COHERENT_MODE; |
598 | /* 16200 or 27000 */ | 620 | /* 16200 or 27000 */ |
599 | args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); | 621 | args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); |
600 | } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { | 622 | } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { |
601 | /* want to enable SS on LVDS eventually */ | 623 | if (ss_enabled) |
602 | /*args.v3.sInput.ucDispPllConfig |= | 624 | args.v3.sInput.ucDispPllConfig |= |
603 | DISPPLL_CONFIG_SS_ENABLE;*/ | 625 | DISPPLL_CONFIG_SS_ENABLE; |
604 | } else { | 626 | } else { |
605 | if (mode->clock > 165000) | 627 | if (mode->clock > 165000) |
606 | args.v3.sInput.ucDispPllConfig |= | 628 | args.v3.sInput.ucDispPllConfig |= |
@@ -774,6 +796,8 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode | |||
774 | struct radeon_pll *pll; | 796 | struct radeon_pll *pll; |
775 | u32 adjusted_clock; | 797 | u32 adjusted_clock; |
776 | int encoder_mode = 0; | 798 | int encoder_mode = 0; |
799 | struct radeon_atom_ss ss; | ||
800 | bool ss_enabled = false; | ||
777 | 801 | ||
778 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | 802 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
779 | if (encoder->crtc == crtc) { | 803 | if (encoder->crtc == crtc) { |
@@ -800,16 +824,112 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode | |||
800 | break; | 824 | break; |
801 | } | 825 | } |
802 | 826 | ||
827 | if (radeon_encoder->active_device & | ||
828 | (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { | ||
829 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
830 | struct drm_connector *connector = | ||
831 | radeon_get_connector_for_encoder(encoder); | ||
832 | struct radeon_connector *radeon_connector = | ||
833 | to_radeon_connector(connector); | ||
834 | struct radeon_connector_atom_dig *dig_connector = | ||
835 | radeon_connector->con_priv; | ||
836 | int dp_clock; | ||
837 | |||
838 | switch (encoder_mode) { | ||
839 | case ATOM_ENCODER_MODE_DP: | ||
840 | /* DP/eDP */ | ||
841 | dp_clock = dig_connector->dp_clock / 10; | ||
842 | if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { | ||
843 | if (ASIC_IS_DCE4(rdev)) | ||
844 | ss_enabled = | ||
845 | radeon_atombios_get_asic_ss_info(rdev, &ss, | ||
846 | dig->lcd_ss_id, | ||
847 | dp_clock); | ||
848 | else | ||
849 | ss_enabled = | ||
850 | radeon_atombios_get_ppll_ss_info(rdev, &ss, | ||
851 | dig->lcd_ss_id); | ||
852 | } else { | ||
853 | if (ASIC_IS_DCE4(rdev)) | ||
854 | ss_enabled = | ||
855 | radeon_atombios_get_asic_ss_info(rdev, &ss, | ||
856 | ASIC_INTERNAL_SS_ON_DP, | ||
857 | dp_clock); | ||
858 | else { | ||
859 | if (dp_clock == 16200) { | ||
860 | ss_enabled = | ||
861 | radeon_atombios_get_ppll_ss_info(rdev, &ss, | ||
862 | ATOM_DP_SS_ID2); | ||
863 | if (!ss_enabled) | ||
864 | ss_enabled = | ||
865 | radeon_atombios_get_ppll_ss_info(rdev, &ss, | ||
866 | ATOM_DP_SS_ID1); | ||
867 | } else | ||
868 | ss_enabled = | ||
869 | radeon_atombios_get_ppll_ss_info(rdev, &ss, | ||
870 | ATOM_DP_SS_ID1); | ||
871 | } | ||
872 | } | ||
873 | break; | ||
874 | case ATOM_ENCODER_MODE_LVDS: | ||
875 | if (ASIC_IS_DCE4(rdev)) | ||
876 | ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, | ||
877 | dig->lcd_ss_id, | ||
878 | mode->clock / 10); | ||
879 | else | ||
880 | ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &ss, | ||
881 | dig->lcd_ss_id); | ||
882 | break; | ||
883 | case ATOM_ENCODER_MODE_DVI: | ||
884 | if (ASIC_IS_DCE4(rdev)) | ||
885 | ss_enabled = | ||
886 | radeon_atombios_get_asic_ss_info(rdev, &ss, | ||
887 | ASIC_INTERNAL_SS_ON_TMDS, | ||
888 | mode->clock / 10); | ||
889 | break; | ||
890 | case ATOM_ENCODER_MODE_HDMI: | ||
891 | if (ASIC_IS_DCE4(rdev)) | ||
892 | ss_enabled = | ||
893 | radeon_atombios_get_asic_ss_info(rdev, &ss, | ||
894 | ASIC_INTERNAL_SS_ON_HDMI, | ||
895 | mode->clock / 10); | ||
896 | break; | ||
897 | default: | ||
898 | break; | ||
899 | } | ||
900 | } | ||
901 | |||
803 | /* adjust pixel clock as needed */ | 902 | /* adjust pixel clock as needed */ |
804 | adjusted_clock = atombios_adjust_pll(crtc, mode, pll); | 903 | adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); |
805 | 904 | ||
806 | radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, | 905 | radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, |
807 | &ref_div, &post_div); | 906 | &ref_div, &post_div); |
808 | 907 | ||
908 | atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss); | ||
909 | |||
809 | atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, | 910 | atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, |
810 | encoder_mode, radeon_encoder->encoder_id, mode->clock, | 911 | encoder_mode, radeon_encoder->encoder_id, mode->clock, |
811 | ref_div, fb_div, frac_fb_div, post_div); | 912 | ref_div, fb_div, frac_fb_div, post_div); |
812 | 913 | ||
914 | if (ss_enabled) { | ||
915 | /* calculate ss amount and step size */ | ||
916 | if (ASIC_IS_DCE4(rdev)) { | ||
917 | u32 step_size; | ||
918 | u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000; | ||
919 | ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; | ||
920 | ss.amount |= ((amount - (ss.amount * 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & | ||
921 | ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; | ||
922 | if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) | ||
923 | step_size = (4 * amount * ref_div * (ss.rate * 2048)) / | ||
924 | (125 * 25 * pll->reference_freq / 100); | ||
925 | else | ||
926 | step_size = (2 * amount * ref_div * (ss.rate * 2048)) / | ||
927 | (125 * 25 * pll->reference_freq / 100); | ||
928 | ss.step = step_size; | ||
929 | } | ||
930 | |||
931 | atombios_crtc_program_ss(crtc, ATOM_ENABLE, radeon_crtc->pll_id, &ss); | ||
932 | } | ||
813 | } | 933 | } |
814 | 934 | ||
815 | static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, | 935 | static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, |
@@ -1188,12 +1308,19 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, | |||
1188 | } | 1308 | } |
1189 | } | 1309 | } |
1190 | 1310 | ||
1191 | atombios_disable_ss(crtc); | ||
1192 | /* always set DCPLL */ | 1311 | /* always set DCPLL */ |
1193 | if (ASIC_IS_DCE4(rdev)) | 1312 | if (ASIC_IS_DCE4(rdev)) { |
1313 | struct radeon_atom_ss ss; | ||
1314 | bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, | ||
1315 | ASIC_INTERNAL_SS_ON_DCPLL, | ||
1316 | rdev->clock.default_dispclk); | ||
1317 | if (ss_enabled) | ||
1318 | atombios_crtc_program_ss(crtc, ATOM_DISABLE, ATOM_DCPLL, &ss); | ||
1194 | atombios_crtc_set_dcpll(crtc); | 1319 | atombios_crtc_set_dcpll(crtc); |
1320 | if (ss_enabled) | ||
1321 | atombios_crtc_program_ss(crtc, ATOM_ENABLE, ATOM_DCPLL, &ss); | ||
1322 | } | ||
1195 | atombios_crtc_set_pll(crtc, adjusted_mode); | 1323 | atombios_crtc_set_pll(crtc, adjusted_mode); |
1196 | atombios_enable_ss(crtc); | ||
1197 | 1324 | ||
1198 | if (ASIC_IS_DCE4(rdev)) | 1325 | if (ASIC_IS_DCE4(rdev)) |
1199 | atombios_set_crtc_dtd_timing(crtc, adjusted_mode); | 1326 | atombios_set_crtc_dtd_timing(crtc, adjusted_mode); |
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 89ce9b6d89d9..2b44cbcb031b 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
@@ -1276,36 +1276,27 @@ bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder, | |||
1276 | return false; | 1276 | return false; |
1277 | } | 1277 | } |
1278 | 1278 | ||
1279 | static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct | 1279 | bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev, |
1280 | radeon_encoder | 1280 | struct radeon_atom_ss *ss, |
1281 | *encoder, | 1281 | int id) |
1282 | int id) | ||
1283 | { | 1282 | { |
1284 | struct drm_device *dev = encoder->base.dev; | ||
1285 | struct radeon_device *rdev = dev->dev_private; | ||
1286 | struct radeon_mode_info *mode_info = &rdev->mode_info; | 1283 | struct radeon_mode_info *mode_info = &rdev->mode_info; |
1287 | int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info); | 1284 | int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info); |
1288 | uint16_t data_offset; | 1285 | uint16_t data_offset, size; |
1289 | struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info; | 1286 | struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info; |
1290 | uint8_t frev, crev; | 1287 | uint8_t frev, crev; |
1291 | struct radeon_atom_ss *ss = NULL; | 1288 | int i, num_indices; |
1292 | int i; | ||
1293 | |||
1294 | if (id > ATOM_MAX_SS_ENTRY) | ||
1295 | return NULL; | ||
1296 | 1289 | ||
1297 | if (atom_parse_data_header(mode_info->atom_context, index, NULL, | 1290 | memset(ss, 0, sizeof(struct radeon_atom_ss)); |
1291 | if (atom_parse_data_header(mode_info->atom_context, index, &size, | ||
1298 | &frev, &crev, &data_offset)) { | 1292 | &frev, &crev, &data_offset)) { |
1299 | ss_info = | 1293 | ss_info = |
1300 | (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset); | 1294 | (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset); |
1301 | 1295 | ||
1302 | ss = | 1296 | num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / |
1303 | kzalloc(sizeof(struct radeon_atom_ss), GFP_KERNEL); | 1297 | sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT); |
1304 | |||
1305 | if (!ss) | ||
1306 | return NULL; | ||
1307 | 1298 | ||
1308 | for (i = 0; i < ATOM_MAX_SS_ENTRY; i++) { | 1299 | for (i = 0; i < num_indices; i++) { |
1309 | if (ss_info->asSS_Info[i].ucSS_Id == id) { | 1300 | if (ss_info->asSS_Info[i].ucSS_Id == id) { |
1310 | ss->percentage = | 1301 | ss->percentage = |
1311 | le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage); | 1302 | le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage); |
@@ -1314,11 +1305,88 @@ static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct | |||
1314 | ss->delay = ss_info->asSS_Info[i].ucSS_Delay; | 1305 | ss->delay = ss_info->asSS_Info[i].ucSS_Delay; |
1315 | ss->range = ss_info->asSS_Info[i].ucSS_Range; | 1306 | ss->range = ss_info->asSS_Info[i].ucSS_Range; |
1316 | ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div; | 1307 | ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div; |
1317 | break; | 1308 | return true; |
1309 | } | ||
1310 | } | ||
1311 | } | ||
1312 | return false; | ||
1313 | } | ||
1314 | |||
1315 | union asic_ss_info { | ||
1316 | struct _ATOM_ASIC_INTERNAL_SS_INFO info; | ||
1317 | struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2; | ||
1318 | struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3; | ||
1319 | }; | ||
1320 | |||
1321 | bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, | ||
1322 | struct radeon_atom_ss *ss, | ||
1323 | int id, u32 clock) | ||
1324 | { | ||
1325 | struct radeon_mode_info *mode_info = &rdev->mode_info; | ||
1326 | int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); | ||
1327 | uint16_t data_offset, size; | ||
1328 | union asic_ss_info *ss_info; | ||
1329 | uint8_t frev, crev; | ||
1330 | int i, num_indices; | ||
1331 | |||
1332 | memset(ss, 0, sizeof(struct radeon_atom_ss)); | ||
1333 | if (atom_parse_data_header(mode_info->atom_context, index, &size, | ||
1334 | &frev, &crev, &data_offset)) { | ||
1335 | |||
1336 | ss_info = | ||
1337 | (union asic_ss_info *)(mode_info->atom_context->bios + data_offset); | ||
1338 | |||
1339 | switch (frev) { | ||
1340 | case 1: | ||
1341 | num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / | ||
1342 | sizeof(ATOM_ASIC_SS_ASSIGNMENT); | ||
1343 | |||
1344 | for (i = 0; i < num_indices; i++) { | ||
1345 | if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) && | ||
1346 | (clock <= ss_info->info.asSpreadSpectrum[i].ulTargetClockRange)) { | ||
1347 | ss->percentage = | ||
1348 | le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage); | ||
1349 | ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode; | ||
1350 | ss->rate = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz); | ||
1351 | return true; | ||
1352 | } | ||
1318 | } | 1353 | } |
1354 | break; | ||
1355 | case 2: | ||
1356 | num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / | ||
1357 | sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2); | ||
1358 | for (i = 0; i < num_indices; i++) { | ||
1359 | if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) && | ||
1360 | (clock <= ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange)) { | ||
1361 | ss->percentage = | ||
1362 | le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage); | ||
1363 | ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode; | ||
1364 | ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz); | ||
1365 | return true; | ||
1366 | } | ||
1367 | } | ||
1368 | break; | ||
1369 | case 3: | ||
1370 | num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / | ||
1371 | sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3); | ||
1372 | for (i = 0; i < num_indices; i++) { | ||
1373 | if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) && | ||
1374 | (clock <= ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange)) { | ||
1375 | ss->percentage = | ||
1376 | le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage); | ||
1377 | ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode; | ||
1378 | ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz); | ||
1379 | return true; | ||
1380 | } | ||
1381 | } | ||
1382 | break; | ||
1383 | default: | ||
1384 | DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev); | ||
1385 | break; | ||
1319 | } | 1386 | } |
1387 | |||
1320 | } | 1388 | } |
1321 | return ss; | 1389 | return false; |
1322 | } | 1390 | } |
1323 | 1391 | ||
1324 | union lvds_info { | 1392 | union lvds_info { |
@@ -1370,7 +1438,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct | |||
1370 | le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); | 1438 | le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); |
1371 | lvds->panel_pwr_delay = | 1439 | lvds->panel_pwr_delay = |
1372 | le16_to_cpu(lvds_info->info.usOffDelayInMs); | 1440 | le16_to_cpu(lvds_info->info.usOffDelayInMs); |
1373 | lvds->lvds_misc = lvds_info->info.ucLVDS_Misc; | 1441 | lvds->lcd_misc = lvds_info->info.ucLVDS_Misc; |
1374 | 1442 | ||
1375 | misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess); | 1443 | misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess); |
1376 | if (misc & ATOM_VSYNC_POLARITY) | 1444 | if (misc & ATOM_VSYNC_POLARITY) |
@@ -1387,7 +1455,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct | |||
1387 | /* set crtc values */ | 1455 | /* set crtc values */ |
1388 | drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V); | 1456 | drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V); |
1389 | 1457 | ||
1390 | lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id); | 1458 | lvds->lcd_ss_id = lvds_info->info.ucSS_Id; |
1391 | 1459 | ||
1392 | encoder->native_mode = lvds->native_mode; | 1460 | encoder->native_mode = lvds->native_mode; |
1393 | 1461 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 2c293e8304d6..ae58b6849a2e 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c | |||
@@ -529,9 +529,9 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) | |||
529 | args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; | 529 | args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; |
530 | args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); | 530 | args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); |
531 | if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { | 531 | if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
532 | if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL) | 532 | if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) |
533 | args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; | 533 | args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; |
534 | if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB) | 534 | if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) |
535 | args.v1.ucMisc |= (1 << 1); | 535 | args.v1.ucMisc |= (1 << 1); |
536 | } else { | 536 | } else { |
537 | if (dig->linkb) | 537 | if (dig->linkb) |
@@ -558,18 +558,18 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) | |||
558 | args.v2.ucTemporal = 0; | 558 | args.v2.ucTemporal = 0; |
559 | args.v2.ucFRC = 0; | 559 | args.v2.ucFRC = 0; |
560 | if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { | 560 | if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
561 | if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL) | 561 | if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) |
562 | args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; | 562 | args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; |
563 | if (dig->lvds_misc & ATOM_PANEL_MISC_SPATIAL) { | 563 | if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) { |
564 | args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; | 564 | args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; |
565 | if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB) | 565 | if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) |
566 | args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; | 566 | args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; |
567 | } | 567 | } |
568 | if (dig->lvds_misc & ATOM_PANEL_MISC_TEMPORAL) { | 568 | if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) { |
569 | args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; | 569 | args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; |
570 | if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB) | 570 | if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) |
571 | args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; | 571 | args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; |
572 | if (((dig->lvds_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2) | 572 | if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2) |
573 | args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; | 573 | args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; |
574 | } | 574 | } |
575 | } else { | 575 | } else { |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 29f551769aaf..d25cf093c84d 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -324,21 +324,24 @@ struct radeon_encoder_ext_tmds { | |||
324 | struct radeon_atom_ss { | 324 | struct radeon_atom_ss { |
325 | uint16_t percentage; | 325 | uint16_t percentage; |
326 | uint8_t type; | 326 | uint8_t type; |
327 | uint8_t step; | 327 | uint16_t step; |
328 | uint8_t delay; | 328 | uint8_t delay; |
329 | uint8_t range; | 329 | uint8_t range; |
330 | uint8_t refdiv; | 330 | uint8_t refdiv; |
331 | /* asic_ss */ | ||
332 | uint16_t rate; | ||
333 | uint16_t amount; | ||
331 | }; | 334 | }; |
332 | 335 | ||
333 | struct radeon_encoder_atom_dig { | 336 | struct radeon_encoder_atom_dig { |
334 | bool linkb; | 337 | bool linkb; |
335 | /* atom dig */ | 338 | /* atom dig */ |
336 | bool coherent_mode; | 339 | bool coherent_mode; |
337 | int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB */ | 340 | int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB, etc. */ |
338 | /* atom lvds */ | 341 | /* atom lvds/edp */ |
339 | uint32_t lvds_misc; | 342 | uint32_t lcd_misc; |
340 | uint16_t panel_pwr_delay; | 343 | uint16_t panel_pwr_delay; |
341 | struct radeon_atom_ss *ss; | 344 | uint32_t lcd_ss_id; |
342 | /* panel mode */ | 345 | /* panel mode */ |
343 | struct drm_display_mode native_mode; | 346 | struct drm_display_mode native_mode; |
344 | }; | 347 | }; |
@@ -480,6 +483,13 @@ extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); | |||
480 | 483 | ||
481 | extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); | 484 | extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); |
482 | 485 | ||
486 | extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev, | ||
487 | struct radeon_atom_ss *ss, | ||
488 | int id); | ||
489 | extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, | ||
490 | struct radeon_atom_ss *ss, | ||
491 | int id, u32 clock); | ||
492 | |||
483 | extern void radeon_compute_pll(struct radeon_pll *pll, | 493 | extern void radeon_compute_pll(struct radeon_pll *pll, |
484 | uint64_t freq, | 494 | uint64_t freq, |
485 | uint32_t *dot_clock_p, | 495 | uint32_t *dot_clock_p, |