radeon_hd: Add spread spectrum control functions
* Store SS information with PLL * Probe SS information for PLL * Disable SS more correctly * May resolve mode setting issues on newer cards
This commit is contained in:
parent
67da9f0716
commit
151b499622
@ -631,7 +631,7 @@ connector_probe()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// External encoders are behind DVO or UNIPHY
|
// External encoders are behind DVO or UNIPHY
|
||||||
if(encoder_is_external(encoderID)) {
|
if (encoder_is_external(encoderID)) {
|
||||||
encoder_info* encoder
|
encoder_info* encoder
|
||||||
= &connector->encoderExternal;
|
= &connector->encoderExternal;
|
||||||
encoder->isExternal = true;
|
encoder->isExternal = true;
|
||||||
|
@ -768,6 +768,136 @@ display_crtc_set_dtd(uint8 crtcID, display_mode* mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
display_crtc_ss(uint8 crtcID, int command)
|
||||||
|
{
|
||||||
|
TRACE("%s\n", __func__);
|
||||||
|
radeon_shared_info &info = *gInfo->shared_info;
|
||||||
|
|
||||||
|
int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
|
||||||
|
|
||||||
|
if (command != ATOM_DISABLE) {
|
||||||
|
ERROR("%s: TODO: SS was enabled, however functionality incomplete\n",
|
||||||
|
__func__);
|
||||||
|
command = ATOM_DISABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
union enableSS {
|
||||||
|
ENABLE_LVDS_SS_PARAMETERS lvds_ss;
|
||||||
|
ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2;
|
||||||
|
ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
|
||||||
|
ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
|
||||||
|
ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
|
||||||
|
};
|
||||||
|
|
||||||
|
union enableSS args;
|
||||||
|
memset(&args, 0, sizeof(args));
|
||||||
|
|
||||||
|
uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
|
||||||
|
pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
|
||||||
|
|
||||||
|
if (info.dceMajor >= 5) {
|
||||||
|
args.v3.usSpreadSpectrumAmountFrac = B_HOST_TO_LENDIAN_INT16(0);
|
||||||
|
args.v3.ucSpreadSpectrumType
|
||||||
|
= pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
|
||||||
|
switch (pll->id) {
|
||||||
|
case ATOM_PPLL1:
|
||||||
|
args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
|
||||||
|
args.v3.usSpreadSpectrumAmount
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssAmount);
|
||||||
|
args.v3.usSpreadSpectrumStep
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssStep);
|
||||||
|
break;
|
||||||
|
case ATOM_PPLL2:
|
||||||
|
args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
|
||||||
|
args.v3.usSpreadSpectrumAmount
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssAmount);
|
||||||
|
args.v3.usSpreadSpectrumStep
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssStep);
|
||||||
|
break;
|
||||||
|
case ATOM_DCPLL:
|
||||||
|
args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
|
||||||
|
args.v3.usSpreadSpectrumAmount = B_HOST_TO_LENDIAN_INT16(0);
|
||||||
|
args.v3.usSpreadSpectrumStep = B_HOST_TO_LENDIAN_INT16(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("%s: BUG: Invalid PLL ID!\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pll->ssPercentage == 0
|
||||||
|
|| ((pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0)) {
|
||||||
|
command = ATOM_DISABLE;
|
||||||
|
}
|
||||||
|
args.v3.ucEnable = command;
|
||||||
|
} else if (info.dceMajor >= 4) {
|
||||||
|
args.v2.usSpreadSpectrumPercentage
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssPercentage);
|
||||||
|
args.v2.ucSpreadSpectrumType
|
||||||
|
= pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
|
||||||
|
switch (pll->id) {
|
||||||
|
case ATOM_PPLL1:
|
||||||
|
args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
|
||||||
|
args.v2.usSpreadSpectrumAmount
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssAmount);
|
||||||
|
args.v2.usSpreadSpectrumStep
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssStep);
|
||||||
|
break;
|
||||||
|
case ATOM_PPLL2:
|
||||||
|
args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
|
||||||
|
args.v2.usSpreadSpectrumAmount
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssAmount);
|
||||||
|
args.v2.usSpreadSpectrumStep
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssStep);
|
||||||
|
break;
|
||||||
|
case ATOM_DCPLL:
|
||||||
|
args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
|
||||||
|
args.v2.usSpreadSpectrumAmount = B_HOST_TO_LENDIAN_INT16(0);
|
||||||
|
args.v2.usSpreadSpectrumStep = B_HOST_TO_LENDIAN_INT16(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("%s: BUG: Invalid PLL ID!\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pll->ssPercentage == 0
|
||||||
|
|| ((pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0)
|
||||||
|
|| (info.chipsetFlags & CHIP_APU) != 0 ) {
|
||||||
|
command = ATOM_DISABLE;
|
||||||
|
}
|
||||||
|
args.v2.ucEnable = command;
|
||||||
|
} else if (info.dceMajor >= 3) {
|
||||||
|
args.v1.usSpreadSpectrumPercentage
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssPercentage);
|
||||||
|
args.v1.ucSpreadSpectrumType
|
||||||
|
= pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
|
||||||
|
args.v1.ucSpreadSpectrumStep = pll->ssStep;
|
||||||
|
args.v1.ucSpreadSpectrumDelay = pll->ssDelay;
|
||||||
|
args.v1.ucSpreadSpectrumRange = pll->ssRange;
|
||||||
|
args.v1.ucPpll = pll->id;
|
||||||
|
args.v1.ucEnable = command;
|
||||||
|
} else if (info.dceMajor >= 2) {
|
||||||
|
if ((command == ATOM_DISABLE) || (pll->ssPercentage == 0)
|
||||||
|
|| (pll->ssType & ATOM_EXTERNAL_SS_MASK)) {
|
||||||
|
// TODO: gpu_ss_disable needs pll id
|
||||||
|
radeon_gpu_ss_disable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
args.lvds_ss_2.usSpreadSpectrumPercentage
|
||||||
|
= B_HOST_TO_LENDIAN_INT16(pll->ssPercentage);
|
||||||
|
args.lvds_ss_2.ucSpreadSpectrumType
|
||||||
|
= pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
|
||||||
|
args.lvds_ss_2.ucSpreadSpectrumStep = pll->ssStep;
|
||||||
|
args.lvds_ss_2.ucSpreadSpectrumDelay = pll->ssDelay;
|
||||||
|
args.lvds_ss_2.ucSpreadSpectrumRange = pll->ssRange;
|
||||||
|
args.lvds_ss_2.ucEnable = command;
|
||||||
|
} else {
|
||||||
|
ERROR("%s: TODO: Old card SS control\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
atom_execute_table(gAtomContext, index, (uint32*)&args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
display_crtc_power(uint8 crtcID, int command)
|
display_crtc_power(uint8 crtcID, int command)
|
||||||
{
|
{
|
||||||
|
@ -20,6 +20,7 @@ status_t detect_displays();
|
|||||||
void debug_displays();
|
void debug_displays();
|
||||||
|
|
||||||
uint32 display_get_encoder_mode(uint32 connectorIndex);
|
uint32 display_get_encoder_mode(uint32 connectorIndex);
|
||||||
|
void display_crtc_ss(uint8 crtcID, int command);
|
||||||
void display_crtc_lock(uint8 crtcID, int command);
|
void display_crtc_lock(uint8 crtcID, int command);
|
||||||
void display_crtc_blank(uint8 crtcID, int command);
|
void display_crtc_blank(uint8 crtcID, int command);
|
||||||
void display_crtc_dpms(uint8 crtcID, int mode);
|
void display_crtc_dpms(uint8 crtcID, int mode);
|
||||||
|
@ -134,6 +134,177 @@ pll_limit_probe(pll_info* pll)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
pll_dp_ss_probe(pll_info* pll)
|
||||||
|
{
|
||||||
|
uint8 tableMajor;
|
||||||
|
uint8 tableMinor;
|
||||||
|
uint16 headerOffset;
|
||||||
|
uint16 headerSize;
|
||||||
|
|
||||||
|
int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info);
|
||||||
|
if (atom_parse_data_header(gAtomContext, index, &headerSize,
|
||||||
|
&tableMajor, &tableMinor, &headerOffset) != B_OK) {
|
||||||
|
ERROR("%s: Couldn't parse data header\n", __func__);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info
|
||||||
|
= (struct _ATOM_SPREAD_SPECTRUM_INFO*)((uint16*)gAtomContext->bios
|
||||||
|
+ headerOffset);
|
||||||
|
|
||||||
|
int indices = (headerSize - sizeof(ATOM_COMMON_TABLE_HEADER))
|
||||||
|
/ sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < indices; i++) {
|
||||||
|
if (ss_info->asSS_Info[i].ucSS_Id == pll->id) {
|
||||||
|
pll->ssPercentage = B_LENDIAN_TO_HOST_INT16(
|
||||||
|
ss_info->asSS_Info[i].usSpreadSpectrumPercentage);
|
||||||
|
pll->ssType = ss_info->asSS_Info[i].ucSpreadSpectrumType;
|
||||||
|
pll->ssStep = ss_info->asSS_Info[i].ucSS_Step;
|
||||||
|
pll->ssDelay = ss_info->asSS_Info[i].ucSS_Delay;
|
||||||
|
pll->ssRange = ss_info->asSS_Info[i].ucSS_Range;
|
||||||
|
pll->ssReferenceDiv
|
||||||
|
= ss_info->asSS_Info[i].ucRecommendedRef_Div;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pll->ssPercentage = 0;
|
||||||
|
pll->ssType = 0;
|
||||||
|
pll->ssStep = 0;
|
||||||
|
pll->ssDelay = 0;
|
||||||
|
pll->ssRange = 0;
|
||||||
|
pll->ssReferenceDiv = 0;
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
pll_asic_ss_probe(pll_info* pll)
|
||||||
|
{
|
||||||
|
uint8 tableMajor;
|
||||||
|
uint8 tableMinor;
|
||||||
|
uint16 headerOffset;
|
||||||
|
uint16 headerSize;
|
||||||
|
|
||||||
|
int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
|
||||||
|
if (atom_parse_data_header(gAtomContext, index, &headerSize,
|
||||||
|
&tableMajor, &tableMinor, &headerOffset) != B_OK) {
|
||||||
|
ERROR("%s: Couldn't parse data header\n", __func__);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
union asicSSInfo {
|
||||||
|
struct _ATOM_ASIC_INTERNAL_SS_INFO info;
|
||||||
|
struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;
|
||||||
|
struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;
|
||||||
|
};
|
||||||
|
|
||||||
|
union asicSSInfo *ss_info
|
||||||
|
= (union asicSSInfo*)((uint16*)gAtomContext->bios + headerOffset);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int indices;
|
||||||
|
switch (tableMajor) {
|
||||||
|
case 1:
|
||||||
|
indices = (headerSize - sizeof(ATOM_COMMON_TABLE_HEADER))
|
||||||
|
/ sizeof(ATOM_ASIC_SS_ASSIGNMENT);
|
||||||
|
|
||||||
|
for (i = 0; i < indices; i++) {
|
||||||
|
if (ss_info->info.asSpreadSpectrum[i].ucClockIndication
|
||||||
|
!= pll->id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TRACE("%s: ss match found\n", __func__);
|
||||||
|
if (pll->pixelClock > B_LENDIAN_TO_HOST_INT32(
|
||||||
|
ss_info->info.asSpreadSpectrum[i].ulTargetClockRange)) {
|
||||||
|
TRACE("%s: pixelClock > targetClockRange!\n", __func__);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pll->ssPercentage = B_LENDIAN_TO_HOST_INT16(
|
||||||
|
ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage
|
||||||
|
);
|
||||||
|
|
||||||
|
pll->ssType
|
||||||
|
= ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode;
|
||||||
|
pll->ssRate = B_LENDIAN_TO_HOST_INT16(
|
||||||
|
ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
indices = (headerSize - sizeof(ATOM_COMMON_TABLE_HEADER))
|
||||||
|
/ sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
|
||||||
|
|
||||||
|
for (i = 0; i < indices; i++) {
|
||||||
|
if (ss_info->info_2.asSpreadSpectrum[i].ucClockIndication
|
||||||
|
!= pll->id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TRACE("%s: ss match found\n", __func__);
|
||||||
|
if (pll->pixelClock > B_LENDIAN_TO_HOST_INT32(
|
||||||
|
ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange)) {
|
||||||
|
TRACE("%s: pixelClock > targetClockRange!\n", __func__);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pll->ssPercentage = B_LENDIAN_TO_HOST_INT16(
|
||||||
|
ss_info
|
||||||
|
->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage
|
||||||
|
);
|
||||||
|
|
||||||
|
pll->ssType
|
||||||
|
= ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
|
||||||
|
pll->ssRate = B_LENDIAN_TO_HOST_INT16(
|
||||||
|
ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
indices = (headerSize - sizeof(ATOM_COMMON_TABLE_HEADER))
|
||||||
|
/ sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
|
||||||
|
|
||||||
|
for (i = 0; i < indices; i++) {
|
||||||
|
if (ss_info->info_3.asSpreadSpectrum[i].ucClockIndication
|
||||||
|
!= pll->id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TRACE("%s: ss match found\n", __func__);
|
||||||
|
if (pll->pixelClock > B_LENDIAN_TO_HOST_INT32(
|
||||||
|
ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange)) {
|
||||||
|
TRACE("%s: pixelClock > targetClockRange!\n", __func__);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pll->ssPercentage = B_LENDIAN_TO_HOST_INT16(
|
||||||
|
ss_info
|
||||||
|
->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage
|
||||||
|
);
|
||||||
|
|
||||||
|
pll->ssType
|
||||||
|
= ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
|
||||||
|
pll->ssRate = B_LENDIAN_TO_HOST_INT16(
|
||||||
|
ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("%s: Unknown SS table version!\n", __func__);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pll->ssPercentage = 0;
|
||||||
|
pll->ssType = 0;
|
||||||
|
pll->ssRate = 0;
|
||||||
|
|
||||||
|
ERROR("%s: No potential spread spectrum data found!\n", __func__);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
pll_compute_post_divider(pll_info* pll)
|
pll_compute_post_divider(pll_info* pll)
|
||||||
{
|
{
|
||||||
@ -494,6 +665,12 @@ pll_set(uint8 pllID, uint32 pixelClock, uint8 crtcID)
|
|||||||
pll_compute(pll);
|
pll_compute(pll);
|
||||||
// compute dividers
|
// compute dividers
|
||||||
|
|
||||||
|
pll_asic_ss_probe(pll);
|
||||||
|
// probe spread spectrum metrics (TODO: pll_dp_ss_probe)
|
||||||
|
display_crtc_ss(crtcID, ATOM_DISABLE);
|
||||||
|
// disable ss
|
||||||
|
|
||||||
|
|
||||||
uint8 tableMajor;
|
uint8 tableMajor;
|
||||||
uint8 tableMinor;
|
uint8 tableMinor;
|
||||||
|
|
||||||
@ -624,5 +801,10 @@ pll_set(uint8 pllID, uint32 pixelClock, uint8 crtcID)
|
|||||||
TRACE("%s: set adjusted pixel clock %" B_PRIu32 " (was %" B_PRIu32 ")\n",
|
TRACE("%s: set adjusted pixel clock %" B_PRIu32 " (was %" B_PRIu32 ")\n",
|
||||||
__func__, pll->pixelClock, pixelClock);
|
__func__, pll->pixelClock, pixelClock);
|
||||||
|
|
||||||
return atom_execute_table(gAtomContext, index, (uint32*)&args);
|
status_t result = atom_execute_table(gAtomContext, index, (uint32*)&args);
|
||||||
|
|
||||||
|
//display_crtc_ss(crtcID, ATOM_ENABLE);
|
||||||
|
// Not yet, lets avoid this.
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,18 @@ struct pll_info {
|
|||||||
uint32 maxFeedbackDiv;
|
uint32 maxFeedbackDiv;
|
||||||
uint32 minFeedbackDivFrac;
|
uint32 minFeedbackDivFrac;
|
||||||
uint32 maxFeedbackDivFrac;
|
uint32 maxFeedbackDivFrac;
|
||||||
|
|
||||||
|
/* spread spectrum info */
|
||||||
|
uint8 ssType;
|
||||||
|
uint8 ssDelay;
|
||||||
|
uint8 ssRange;
|
||||||
|
uint8 ssReferenceDiv;
|
||||||
|
uint16 ssPercentage;
|
||||||
|
uint16 ssStep;
|
||||||
|
/* asic spread spectrum */
|
||||||
|
uint16 ssRate;
|
||||||
|
uint16 ssAmount;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -91,6 +103,8 @@ status_t pll_adjust(pll_info* pll, uint8 crtcID);
|
|||||||
status_t pll_compute(pll_info* pll);
|
status_t pll_compute(pll_info* pll);
|
||||||
void pll_setup_flags(pll_info* pll, uint8 crtcID);
|
void pll_setup_flags(pll_info* pll, uint8 crtcID);
|
||||||
status_t pll_limit_probe(pll_info* pll);
|
status_t pll_limit_probe(pll_info* pll);
|
||||||
|
status_t pll_dp_ss_probe(pll_info* pll);
|
||||||
|
status_t pll_asic_ss_probe(pll_info* pll);
|
||||||
status_t pll_set(uint8 pllID, uint32 pixelClock, uint8 crtcID);
|
status_t pll_set(uint8 pllID, uint32 pixelClock, uint8 crtcID);
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user