diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2009-10-16 11:15:25 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-10-25 23:28:22 -0400 |
commit | ebbe1cb936dfc96d809ccf4d64a9755f8ba0c0ff (patch) | |
tree | 42c9ef8b5552c84a2e02b5e35f17bfddc28927b5 | |
parent | c290dadf4cac25cc91529d84004795ab43fc0821 (diff) |
drm/radeon/kms/atom: add support for spread spectrum (v2)
Spread spectrum is a periodic disturbance added
to the feedback divider to change the pixel clock
periodically to reduce interference.
Only enabled on LVDS.
v2: add support for r4xx and fix DCE 3
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/radeon/atombios.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_crtc.c | 68 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 42 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 11 |
4 files changed, 111 insertions, 12 deletions
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index 5d402086bc47..c11ddddfb3b6 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h | |||
@@ -2314,7 +2314,7 @@ typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT { | |||
2314 | UCHAR ucSS_Step; | 2314 | UCHAR ucSS_Step; |
2315 | UCHAR ucSS_Delay; | 2315 | UCHAR ucSS_Delay; |
2316 | UCHAR ucSS_Id; | 2316 | UCHAR ucSS_Id; |
2317 | UCHAR ucRecommandedRef_Div; | 2317 | UCHAR ucRecommendedRef_Div; |
2318 | UCHAR ucSS_Range; /* it was reserved for V11 */ | 2318 | UCHAR ucSS_Range; /* it was reserved for V11 */ |
2319 | } ATOM_SPREAD_SPECTRUM_ASSIGNMENT; | 2319 | } ATOM_SPREAD_SPECTRUM_ASSIGNMENT; |
2320 | 2320 | ||
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 9c26e538a1e0..e5a3c301b7a9 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
@@ -351,6 +351,61 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc, | |||
351 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | 351 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
352 | } | 352 | } |
353 | 353 | ||
354 | static void atombios_set_ss(struct drm_crtc *crtc, int enable) | ||
355 | { | ||
356 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
357 | struct drm_device *dev = crtc->dev; | ||
358 | struct radeon_device *rdev = dev->dev_private; | ||
359 | struct drm_encoder *encoder = NULL; | ||
360 | struct radeon_encoder *radeon_encoder = NULL; | ||
361 | struct radeon_encoder_atom_dig *dig = NULL; | ||
362 | int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); | ||
363 | ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION args; | ||
364 | ENABLE_LVDS_SS_PARAMETERS legacy_args; | ||
365 | uint16_t percentage = 0; | ||
366 | uint8_t type = 0, step = 0, delay = 0, range = 0; | ||
367 | |||
368 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
369 | if (encoder->crtc == crtc) { | ||
370 | radeon_encoder = to_radeon_encoder(encoder); | ||
371 | dig = radeon_encoder->enc_priv; | ||
372 | /* only enable spread spectrum on LVDS */ | ||
373 | if (dig && dig->ss) { | ||
374 | percentage = dig->ss->percentage; | ||
375 | type = dig->ss->type; | ||
376 | step = dig->ss->step; | ||
377 | delay = dig->ss->delay; | ||
378 | range = dig->ss->range; | ||
379 | } else if (enable) | ||
380 | return; | ||
381 | break; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | if (!radeon_encoder) | ||
386 | return; | ||
387 | |||
388 | if (ASIC_IS_AVIVO(rdev)) { | ||
389 | memset(&args, 0, sizeof(args)); | ||
390 | args.usSpreadSpectrumPercentage = percentage; | ||
391 | args.ucSpreadSpectrumType = type; | ||
392 | args.ucSpreadSpectrumStep = step; | ||
393 | args.ucSpreadSpectrumDelay = delay; | ||
394 | args.ucSpreadSpectrumRange = range; | ||
395 | args.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; | ||
396 | args.ucEnable = enable; | ||
397 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | ||
398 | } else { | ||
399 | memset(&legacy_args, 0, sizeof(legacy_args)); | ||
400 | legacy_args.usSpreadSpectrumPercentage = percentage; | ||
401 | legacy_args.ucSpreadSpectrumType = type; | ||
402 | legacy_args.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2; | ||
403 | legacy_args.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4; | ||
404 | legacy_args.ucEnable = enable; | ||
405 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&legacy_args); | ||
406 | } | ||
407 | } | ||
408 | |||
354 | void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) | 409 | void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) |
355 | { | 410 | { |
356 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | 411 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
@@ -373,8 +428,6 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) | |||
373 | memset(&args, 0, sizeof(args)); | 428 | memset(&args, 0, sizeof(args)); |
374 | 429 | ||
375 | if (ASIC_IS_AVIVO(rdev)) { | 430 | if (ASIC_IS_AVIVO(rdev)) { |
376 | uint32_t ss_cntl; | ||
377 | |||
378 | if ((rdev->family == CHIP_RS600) || | 431 | if ((rdev->family == CHIP_RS600) || |
379 | (rdev->family == CHIP_RS690) || | 432 | (rdev->family == CHIP_RS690) || |
380 | (rdev->family == CHIP_RS740)) | 433 | (rdev->family == CHIP_RS740)) |
@@ -385,15 +438,6 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) | |||
385 | pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; | 438 | pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; |
386 | else | 439 | else |
387 | pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; | 440 | pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; |
388 | |||
389 | /* disable spread spectrum clocking for now -- thanks Hedy Lamarr */ | ||
390 | if (radeon_crtc->crtc_id == 0) { | ||
391 | ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); | ||
392 | WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1); | ||
393 | } else { | ||
394 | ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); | ||
395 | WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1); | ||
396 | } | ||
397 | } else { | 441 | } else { |
398 | pll_flags |= RADEON_PLL_LEGACY; | 442 | pll_flags |= RADEON_PLL_LEGACY; |
399 | 443 | ||
@@ -641,7 +685,9 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, | |||
641 | 685 | ||
642 | /* TODO color tiling */ | 686 | /* TODO color tiling */ |
643 | 687 | ||
688 | atombios_set_ss(crtc, 0); | ||
644 | atombios_crtc_set_pll(crtc, adjusted_mode); | 689 | atombios_crtc_set_pll(crtc, adjusted_mode); |
690 | atombios_set_ss(crtc, 1); | ||
645 | atombios_crtc_set_timing(crtc, adjusted_mode); | 691 | atombios_crtc_set_timing(crtc, adjusted_mode); |
646 | 692 | ||
647 | if (ASIC_IS_AVIVO(rdev)) | 693 | if (ASIC_IS_AVIVO(rdev)) |
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index cec67917179f..18729259c2fc 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
@@ -771,6 +771,46 @@ bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder, | |||
771 | return false; | 771 | return false; |
772 | } | 772 | } |
773 | 773 | ||
774 | static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct | ||
775 | radeon_encoder | ||
776 | *encoder, | ||
777 | int id) | ||
778 | { | ||
779 | struct drm_device *dev = encoder->base.dev; | ||
780 | struct radeon_device *rdev = dev->dev_private; | ||
781 | struct radeon_mode_info *mode_info = &rdev->mode_info; | ||
782 | int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info); | ||
783 | uint16_t data_offset; | ||
784 | struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info; | ||
785 | uint8_t frev, crev; | ||
786 | struct radeon_atom_ss *ss = NULL; | ||
787 | |||
788 | if (id > ATOM_MAX_SS_ENTRY) | ||
789 | return NULL; | ||
790 | |||
791 | atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, | ||
792 | &crev, &data_offset); | ||
793 | |||
794 | ss_info = | ||
795 | (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset); | ||
796 | |||
797 | if (ss_info) { | ||
798 | ss = | ||
799 | kzalloc(sizeof(struct radeon_atom_ss), GFP_KERNEL); | ||
800 | |||
801 | if (!ss) | ||
802 | return NULL; | ||
803 | |||
804 | ss->percentage = le16_to_cpu(ss_info->asSS_Info[id].usSpreadSpectrumPercentage); | ||
805 | ss->type = ss_info->asSS_Info[id].ucSpreadSpectrumType; | ||
806 | ss->step = ss_info->asSS_Info[id].ucSS_Step; | ||
807 | ss->delay = ss_info->asSS_Info[id].ucSS_Delay; | ||
808 | ss->range = ss_info->asSS_Info[id].ucSS_Range; | ||
809 | ss->refdiv = ss_info->asSS_Info[id].ucRecommendedRef_Div; | ||
810 | } | ||
811 | return ss; | ||
812 | } | ||
813 | |||
774 | union lvds_info { | 814 | union lvds_info { |
775 | struct _ATOM_LVDS_INFO info; | 815 | struct _ATOM_LVDS_INFO info; |
776 | struct _ATOM_LVDS_INFO_V12 info_12; | 816 | struct _ATOM_LVDS_INFO_V12 info_12; |
@@ -826,6 +866,8 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct | |||
826 | /* set crtc values */ | 866 | /* set crtc values */ |
827 | drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V); | 867 | drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V); |
828 | 868 | ||
869 | lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id); | ||
870 | |||
829 | encoder->native_mode = lvds->native_mode; | 871 | encoder->native_mode = lvds->native_mode; |
830 | } | 872 | } |
831 | return lvds; | 873 | return lvds; |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index b6868fbe7346..2ea5707c018c 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -260,6 +260,16 @@ struct radeon_encoder_int_tmds { | |||
260 | struct radeon_tmds_pll tmds_pll[4]; | 260 | struct radeon_tmds_pll tmds_pll[4]; |
261 | }; | 261 | }; |
262 | 262 | ||
263 | /* spread spectrum */ | ||
264 | struct radeon_atom_ss { | ||
265 | uint16_t percentage; | ||
266 | uint8_t type; | ||
267 | uint8_t step; | ||
268 | uint8_t delay; | ||
269 | uint8_t range; | ||
270 | uint8_t refdiv; | ||
271 | }; | ||
272 | |||
263 | struct radeon_encoder_atom_dig { | 273 | struct radeon_encoder_atom_dig { |
264 | /* atom dig */ | 274 | /* atom dig */ |
265 | bool coherent_mode; | 275 | bool coherent_mode; |
@@ -267,6 +277,7 @@ struct radeon_encoder_atom_dig { | |||
267 | /* atom lvds */ | 277 | /* atom lvds */ |
268 | uint32_t lvds_misc; | 278 | uint32_t lvds_misc; |
269 | uint16_t panel_pwr_delay; | 279 | uint16_t panel_pwr_delay; |
280 | struct radeon_atom_ss *ss; | ||
270 | /* panel mode */ | 281 | /* panel mode */ |
271 | struct drm_display_mode native_mode; | 282 | struct drm_display_mode native_mode; |
272 | }; | 283 | }; |