aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/atombios_crtc.c
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2010-10-04 17:13:01 -0400
committerDave Airlie <airlied@redhat.com>2010-10-05 21:46:26 -0400
commitba032a58d1f320039e7850fb6e8651695c1aa571 (patch)
treef883a015e10d00b79505d16682d504e6914118e8 /drivers/gpu/drm/radeon/atombios_crtc.c
parent48dfaaeb6637240af3089bf9b7a00a6cf24e0182 (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/drm/radeon/atombios_crtc.c')
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c255
1 files changed, 191 insertions, 64 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
400union atom_enable_ss { 400union 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
405static void atombios_enable_ss(struct drm_crtc *crtc) 407static 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
469static u32 atombios_adjust_pll(struct drm_crtc *crtc, 480static 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
815static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, 935static 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);