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>
This commit is contained in:
Родитель
c290dadf4c
Коммит
ebbe1cb936
|
@ -2314,7 +2314,7 @@ typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT {
|
||||||
UCHAR ucSS_Step;
|
UCHAR ucSS_Step;
|
||||||
UCHAR ucSS_Delay;
|
UCHAR ucSS_Delay;
|
||||||
UCHAR ucSS_Id;
|
UCHAR ucSS_Id;
|
||||||
UCHAR ucRecommandedRef_Div;
|
UCHAR ucRecommendedRef_Div;
|
||||||
UCHAR ucSS_Range; /* it was reserved for V11 */
|
UCHAR ucSS_Range; /* it was reserved for V11 */
|
||||||
} ATOM_SPREAD_SPECTRUM_ASSIGNMENT;
|
} ATOM_SPREAD_SPECTRUM_ASSIGNMENT;
|
||||||
|
|
||||||
|
|
|
@ -351,6 +351,61 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc,
|
||||||
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void atombios_set_ss(struct drm_crtc *crtc, int enable)
|
||||||
|
{
|
||||||
|
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
|
||||||
|
struct drm_device *dev = crtc->dev;
|
||||||
|
struct radeon_device *rdev = dev->dev_private;
|
||||||
|
struct drm_encoder *encoder = NULL;
|
||||||
|
struct radeon_encoder *radeon_encoder = NULL;
|
||||||
|
struct radeon_encoder_atom_dig *dig = NULL;
|
||||||
|
int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
|
||||||
|
ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION args;
|
||||||
|
ENABLE_LVDS_SS_PARAMETERS legacy_args;
|
||||||
|
uint16_t percentage = 0;
|
||||||
|
uint8_t type = 0, step = 0, delay = 0, range = 0;
|
||||||
|
|
||||||
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||||
|
if (encoder->crtc == crtc) {
|
||||||
|
radeon_encoder = to_radeon_encoder(encoder);
|
||||||
|
dig = radeon_encoder->enc_priv;
|
||||||
|
/* only enable spread spectrum on LVDS */
|
||||||
|
if (dig && dig->ss) {
|
||||||
|
percentage = dig->ss->percentage;
|
||||||
|
type = dig->ss->type;
|
||||||
|
step = dig->ss->step;
|
||||||
|
delay = dig->ss->delay;
|
||||||
|
range = dig->ss->range;
|
||||||
|
} else if (enable)
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!radeon_encoder)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ASIC_IS_AVIVO(rdev)) {
|
||||||
|
memset(&args, 0, sizeof(args));
|
||||||
|
args.usSpreadSpectrumPercentage = percentage;
|
||||||
|
args.ucSpreadSpectrumType = type;
|
||||||
|
args.ucSpreadSpectrumStep = step;
|
||||||
|
args.ucSpreadSpectrumDelay = delay;
|
||||||
|
args.ucSpreadSpectrumRange = range;
|
||||||
|
args.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
|
||||||
|
args.ucEnable = enable;
|
||||||
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||||
|
} else {
|
||||||
|
memset(&legacy_args, 0, sizeof(legacy_args));
|
||||||
|
legacy_args.usSpreadSpectrumPercentage = percentage;
|
||||||
|
legacy_args.ucSpreadSpectrumType = type;
|
||||||
|
legacy_args.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
|
||||||
|
legacy_args.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
|
||||||
|
legacy_args.ucEnable = enable;
|
||||||
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&legacy_args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
|
void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
|
||||||
{
|
{
|
||||||
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
|
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)
|
||||||
memset(&args, 0, sizeof(args));
|
memset(&args, 0, sizeof(args));
|
||||||
|
|
||||||
if (ASIC_IS_AVIVO(rdev)) {
|
if (ASIC_IS_AVIVO(rdev)) {
|
||||||
uint32_t ss_cntl;
|
|
||||||
|
|
||||||
if ((rdev->family == CHIP_RS600) ||
|
if ((rdev->family == CHIP_RS600) ||
|
||||||
(rdev->family == CHIP_RS690) ||
|
(rdev->family == CHIP_RS690) ||
|
||||||
(rdev->family == CHIP_RS740))
|
(rdev->family == CHIP_RS740))
|
||||||
|
@ -385,15 +438,6 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
|
||||||
pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
|
pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
|
||||||
else
|
else
|
||||||
pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
|
pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
|
||||||
|
|
||||||
/* disable spread spectrum clocking for now -- thanks Hedy Lamarr */
|
|
||||||
if (radeon_crtc->crtc_id == 0) {
|
|
||||||
ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL);
|
|
||||||
WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1);
|
|
||||||
} else {
|
|
||||||
ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL);
|
|
||||||
WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
pll_flags |= RADEON_PLL_LEGACY;
|
pll_flags |= RADEON_PLL_LEGACY;
|
||||||
|
|
||||||
|
@ -641,7 +685,9 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
|
||||||
|
|
||||||
/* TODO color tiling */
|
/* TODO color tiling */
|
||||||
|
|
||||||
|
atombios_set_ss(crtc, 0);
|
||||||
atombios_crtc_set_pll(crtc, adjusted_mode);
|
atombios_crtc_set_pll(crtc, adjusted_mode);
|
||||||
|
atombios_set_ss(crtc, 1);
|
||||||
atombios_crtc_set_timing(crtc, adjusted_mode);
|
atombios_crtc_set_timing(crtc, adjusted_mode);
|
||||||
|
|
||||||
if (ASIC_IS_AVIVO(rdev))
|
if (ASIC_IS_AVIVO(rdev))
|
||||||
|
|
|
@ -771,6 +771,46 @@ bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct
|
||||||
|
radeon_encoder
|
||||||
|
*encoder,
|
||||||
|
int id)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = encoder->base.dev;
|
||||||
|
struct radeon_device *rdev = dev->dev_private;
|
||||||
|
struct radeon_mode_info *mode_info = &rdev->mode_info;
|
||||||
|
int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info);
|
||||||
|
uint16_t data_offset;
|
||||||
|
struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info;
|
||||||
|
uint8_t frev, crev;
|
||||||
|
struct radeon_atom_ss *ss = NULL;
|
||||||
|
|
||||||
|
if (id > ATOM_MAX_SS_ENTRY)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
atom_parse_data_header(mode_info->atom_context, index, NULL, &frev,
|
||||||
|
&crev, &data_offset);
|
||||||
|
|
||||||
|
ss_info =
|
||||||
|
(struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset);
|
||||||
|
|
||||||
|
if (ss_info) {
|
||||||
|
ss =
|
||||||
|
kzalloc(sizeof(struct radeon_atom_ss), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!ss)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ss->percentage = le16_to_cpu(ss_info->asSS_Info[id].usSpreadSpectrumPercentage);
|
||||||
|
ss->type = ss_info->asSS_Info[id].ucSpreadSpectrumType;
|
||||||
|
ss->step = ss_info->asSS_Info[id].ucSS_Step;
|
||||||
|
ss->delay = ss_info->asSS_Info[id].ucSS_Delay;
|
||||||
|
ss->range = ss_info->asSS_Info[id].ucSS_Range;
|
||||||
|
ss->refdiv = ss_info->asSS_Info[id].ucRecommendedRef_Div;
|
||||||
|
}
|
||||||
|
return ss;
|
||||||
|
}
|
||||||
|
|
||||||
union lvds_info {
|
union lvds_info {
|
||||||
struct _ATOM_LVDS_INFO info;
|
struct _ATOM_LVDS_INFO info;
|
||||||
struct _ATOM_LVDS_INFO_V12 info_12;
|
struct _ATOM_LVDS_INFO_V12 info_12;
|
||||||
|
@ -826,6 +866,8 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
|
||||||
/* set crtc values */
|
/* set crtc values */
|
||||||
drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
|
drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
|
||||||
|
|
||||||
|
lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id);
|
||||||
|
|
||||||
encoder->native_mode = lvds->native_mode;
|
encoder->native_mode = lvds->native_mode;
|
||||||
}
|
}
|
||||||
return lvds;
|
return lvds;
|
||||||
|
|
|
@ -260,6 +260,16 @@ struct radeon_encoder_int_tmds {
|
||||||
struct radeon_tmds_pll tmds_pll[4];
|
struct radeon_tmds_pll tmds_pll[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* spread spectrum */
|
||||||
|
struct radeon_atom_ss {
|
||||||
|
uint16_t percentage;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t step;
|
||||||
|
uint8_t delay;
|
||||||
|
uint8_t range;
|
||||||
|
uint8_t refdiv;
|
||||||
|
};
|
||||||
|
|
||||||
struct radeon_encoder_atom_dig {
|
struct radeon_encoder_atom_dig {
|
||||||
/* atom dig */
|
/* atom dig */
|
||||||
bool coherent_mode;
|
bool coherent_mode;
|
||||||
|
@ -267,6 +277,7 @@ struct radeon_encoder_atom_dig {
|
||||||
/* atom lvds */
|
/* atom lvds */
|
||||||
uint32_t lvds_misc;
|
uint32_t lvds_misc;
|
||||||
uint16_t panel_pwr_delay;
|
uint16_t panel_pwr_delay;
|
||||||
|
struct radeon_atom_ss *ss;
|
||||||
/* panel mode */
|
/* panel mode */
|
||||||
struct drm_display_mode native_mode;
|
struct drm_display_mode native_mode;
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче