aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
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
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')
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c255
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c114
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h20
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
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);
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
1279static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct 1279bool 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
1315union 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
1321bool 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
1324union lvds_info { 1392union 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 {
324struct radeon_atom_ss { 324struct 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
333struct radeon_encoder_atom_dig { 336struct 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
481extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); 484extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
482 485
486extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
487 struct radeon_atom_ss *ss,
488 int id);
489extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
490 struct radeon_atom_ss *ss,
491 int id, u32 clock);
492
483extern void radeon_compute_pll(struct radeon_pll *pll, 493extern 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,