radeon_hd: rework some pll code

* Force fractional feedback divider on APU's
* Spread Spectrum is now probed more correctly
  across multiple encoders and cards
* SS still disabled however.
This commit is contained in:
Alexander von Gluck IV 2012-08-07 13:20:52 -05:00
parent 63624e404b
commit 817c114de7
8 changed files with 100 additions and 37 deletions

View File

@ -255,9 +255,6 @@ radeon_init_accelerant(int device)
// probe firmware information
radeon_gpu_probe();
// disable spread spectrum as it requires lots of extra calculations
radeon_gpu_ss_disable();
// program external pll clock
pll_external_init();

View File

@ -76,6 +76,8 @@ struct accelerant_info {
uint32 displayClockFrequency;
uint32 dpExternalClock;
uint32 lvdsSpreadSpectrumID;
RingQueue* ringQueue[RADEON_QUEUE_MAX]; // Ring buffer command processor
};

View File

@ -200,6 +200,9 @@ connector_read_mode_lvds(uint32 connectorIndex, display_mode* mode)
// Store special lvds flags the encoder setup needs
gConnector[connectorIndex]->lvdsFlags = lvdsInfo->info.ucLVDS_Misc;
// Spread Spectrum ID (in SS table)
gInfo->lvdsSpreadSpectrumID = lvdsInfo->info.ucSS_Id;
uint16 flags = B_LENDIAN_TO_HOST_INT16(
lvdsInfo->info.sLCDTiming.susModeMiscInfo.usAccess);

View File

@ -951,8 +951,7 @@ display_crtc_ss(uint8 crtcID, int 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();
radeon_gpu_ss_control(pll, false);
return;
}
args.lvds_ss_2.usSpreadSpectrumPercentage

View File

@ -16,6 +16,7 @@
#include "accelerant.h"
#include "atom.h"
#include "bios.h"
#include "pll.h"
#include "utility.h"
@ -715,7 +716,7 @@ radeon_gpu_ring_boot(uint32 ringType)
status_t
radeon_gpu_ss_disable()
radeon_gpu_ss_control(pll_info* pll, bool enable)
{
TRACE("%s called\n", __func__);
@ -723,25 +724,52 @@ radeon_gpu_ss_disable()
uint32 ssControl;
if (info.chipsetID >= RADEON_CEDAR) {
// PLL1
ssControl = Read32(OUT, EVERGREEN_P1PLL_SS_CNTL);
ssControl &= ~EVERGREEN_PxPLL_SS_EN;
Write32(OUT, EVERGREEN_P1PLL_SS_CNTL, ssControl);
// PLL2
ssControl = Read32(OUT, EVERGREEN_P2PLL_SS_CNTL);
ssControl &= ~EVERGREEN_PxPLL_SS_EN;
Write32(OUT, EVERGREEN_P2PLL_SS_CNTL, ssControl);
switch (pll->id) {
case ATOM_PPLL1:
// PLL1
ssControl = Read32(OUT, EVERGREEN_P1PLL_SS_CNTL);
if (enable)
ssControl |= EVERGREEN_PxPLL_SS_EN;
else
ssControl &= ~EVERGREEN_PxPLL_SS_EN;
Write32(OUT, EVERGREEN_P1PLL_SS_CNTL, ssControl);
break;
case ATOM_PPLL2:
// PLL2
ssControl = Read32(OUT, EVERGREEN_P2PLL_SS_CNTL);
if (enable)
ssControl |= EVERGREEN_PxPLL_SS_EN;
else
ssControl &= ~EVERGREEN_PxPLL_SS_EN;
Write32(OUT, EVERGREEN_P2PLL_SS_CNTL, ssControl);
break;
}
// DCPLL, no action
return B_OK;
} else if (info.chipsetID >= RADEON_RS600) {
// PLL1
ssControl = Read32(OUT, AVIVO_P1PLL_INT_SS_CNTL);
ssControl &= ~1;
Write32(OUT, AVIVO_P1PLL_INT_SS_CNTL, ssControl);
// PLL2
ssControl = Read32(OUT, AVIVO_P2PLL_INT_SS_CNTL);
ssControl &= ~1;
Write32(OUT, AVIVO_P2PLL_INT_SS_CNTL, ssControl);
} else
return B_ERROR;
switch (pll->id) {
case ATOM_PPLL1:
// PLL1
ssControl = Read32(OUT, AVIVO_P1PLL_INT_SS_CNTL);
if (enable)
ssControl |= 1;
else
ssControl &= ~1;
Write32(OUT, AVIVO_P1PLL_INT_SS_CNTL, ssControl);
break;
case ATOM_PPLL2:
// PLL2
ssControl = Read32(OUT, AVIVO_P2PLL_INT_SS_CNTL);
if (enable)
ssControl |= 1;
else
ssControl &= ~1;
Write32(OUT, AVIVO_P2PLL_INT_SS_CNTL, ssControl);
break;
}
// DCPLL, no action
return B_OK;
}
return B_OK;
return B_ERROR;
}

View File

@ -13,6 +13,8 @@
#include <video_configuration.h>
#include "pll.h"
// GPU Control registers. These are combined as
// the registers exist on all models, some flags
@ -172,7 +174,8 @@ status_t radeon_gpu_mc_idlewait();
status_t radeon_gpu_mc_setup();
status_t radeon_gpu_ring_setup();
status_t radeon_gpu_ring_boot(uint32 ringType);
status_t radeon_gpu_ss_disable();
status_t radeon_gpu_ss_control(pll_info* pll, bool enable);
#endif

View File

@ -128,7 +128,7 @@ pll_limit_probe(pll_info* pll)
status_t
pll_dp_ss_probe(pll_info* pll)
pll_ppll_ss_probe(pll_info* pll, uint32 ssID)
{
uint8 tableMajor;
uint8 tableMinor;
@ -151,7 +151,7 @@ pll_dp_ss_probe(pll_info* pll)
int i;
for (i = 0; i < indices; i++) {
if (ss_info->asSS_Info[i].ucSS_Id == pll->id) {
if (ss_info->asSS_Info[i].ucSS_Id == ssID) {
pll->ssPercentage = B_LENDIAN_TO_HOST_INT16(
ss_info->asSS_Info[i].usSpreadSpectrumPercentage);
pll->ssType = ss_info->asSS_Info[i].ucSpreadSpectrumType;
@ -175,7 +175,7 @@ pll_dp_ss_probe(pll_info* pll)
status_t
pll_asic_ss_probe(pll_info* pll)
pll_asic_ss_probe(pll_info* pll, uint32 ssID)
{
uint8 tableMajor;
uint8 tableMinor;
@ -207,7 +207,7 @@ pll_asic_ss_probe(pll_info* pll)
for (i = 0; i < indices; i++) {
if (ss_info->info.asSpreadSpectrum[i].ucClockIndication
!= pll->id) {
!= ssID) {
continue;
}
TRACE("%s: ss match found\n", __func__);
@ -234,7 +234,7 @@ pll_asic_ss_probe(pll_info* pll)
for (i = 0; i < indices; i++) {
if (ss_info->info_2.asSpreadSpectrum[i].ucClockIndication
!= pll->id) {
!= ssID) {
continue;
}
TRACE("%s: ss match found\n", __func__);
@ -262,7 +262,7 @@ pll_asic_ss_probe(pll_info* pll)
for (i = 0; i < indices; i++) {
if (ss_info->info_3.asSpreadSpectrum[i].ucClockIndication
!= pll->id) {
!= ssID) {
continue;
}
TRACE("%s: ss match found\n", __func__);
@ -492,6 +492,11 @@ pll_setup_flags(pll_info* pll, uint8 crtcID)
if ((encoderFlags & ATOM_DEVICE_TV_SUPPORT) != 0)
pll->flags |= PLL_PREFER_CLOSEST_LOWER;
if ((info.chipsetFlags & CHIP_APU) != 0) {
// Use fractional feedback on APU's
pll->flags |= PLL_USE_FRAC_FB_DIV;
}
}
@ -657,12 +662,38 @@ pll_set(display_mode* mode, uint8 crtcID)
pll_compute(pll);
// compute dividers
pll_asic_ss_probe(pll);
// probe spread spectrum metrics (TODO: pll_dp_ss_probe)
radeon_shared_info &info = *gInfo->shared_info;
pll->ssType = 0;
switch (display_get_encoder_mode(connectorIndex)) {
case ATOM_ENCODER_MODE_DP_MST:
case ATOM_ENCODER_MODE_DP:
if (info.dceMajor >= 4)
pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_DP);
else {
// TODO: DP Clock == 1.62Ghz?
pll_ppll_ss_probe(pll, ATOM_DP_SS_ID1);
}
break;
case ATOM_ENCODER_MODE_LVDS:
if (info.dceMajor >= 4)
pll_asic_ss_probe(pll, gInfo->lvdsSpreadSpectrumID);
else
pll_ppll_ss_probe(pll, gInfo->lvdsSpreadSpectrumID);
break;
case ATOM_ENCODER_MODE_DVI:
if (info.dceMajor >= 4)
pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_TMDS);
break;
case ATOM_ENCODER_MODE_HDMI:
if (info.dceMajor >= 4)
pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_HDMI);
break;
}
display_crtc_ss(crtcID, ATOM_DISABLE);
// disable ss
uint8 tableMajor;
uint8 tableMinor;

View File

@ -103,8 +103,8 @@ status_t pll_adjust(pll_info* pll, display_mode* mode, uint8 crtcID);
status_t pll_compute(pll_info* pll);
void pll_setup_flags(pll_info* pll, uint8 crtcID);
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_ppll_ss_probe(pll_info* pll, uint32 ssID);
status_t pll_asic_ss_probe(pll_info* pll, uint32 ssID);
status_t pll_set(display_mode* mode, uint8 crtcID);
status_t pll_pick(uint32 connectorIndex);