radeon_hd: reorganize some pll code

* Move DisplayPort external pixel clock out of pll
  as this frequency is card-wide.
* Add new function to pull display clock frequency
  and other card-wide settings.
* Set displayDefault frequency card-wide
* My DisplayPort LVDS bridge laptop now kind of works
  (a clock somewhere seems a little off though)
This commit is contained in:
Alexander von Gluck IV 2012-08-07 08:53:34 -05:00
parent 5f44fcce9f
commit 63624e404b
7 changed files with 153 additions and 14 deletions

View File

@ -252,9 +252,15 @@ radeon_init_accelerant(int device)
radeon_init_bios(gInfo->rom);
// 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();
// find GPIO pins from AtomBIOS
gpio_probe();

View File

@ -72,6 +72,10 @@ struct accelerant_info {
volatile uint32 dpms_mode; // current driver dpms mode
uint16 maximumPixelClock;
uint32 displayClockFrequency;
uint32 dpExternalClock;
RingQueue* ringQueue[RADEON_QUEUE_MAX]; // Ring buffer command processor
};

View File

@ -1351,7 +1351,7 @@ transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock,
// Select the PLL for the PHY
// DP PHY to be clocked from external src if possible
if (isDP && pll->dpExternalClock) {
if (isDP && gInfo->dpExternalClock) {
// use external clock source
args.v3.acConfig.ucRefClkSource = ATOM_DCPLL;
} else
@ -1418,7 +1418,7 @@ transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock,
// Select the PLL for the PHY
// DP PHY to be clocked from external src if possible
if (isDP) {
if (pll->dpExternalClock > 0) {
if (gInfo->dpExternalClock > 0) {
args.v4.acConfig.ucRefClkSource
= ENCODER_REFCLK_SRC_EXTCLK;
} else {

View File

@ -14,6 +14,7 @@
#include "accelerant_protos.h"
#include "accelerant.h"
#include "atom.h"
#include "bios.h"
#include "utility.h"
@ -30,6 +31,62 @@
#define ERROR(x...) _sPrintf("radeon_hd: " x)
status_t
radeon_gpu_probe()
{
uint8 tableMajor;
uint8 tableMinor;
uint16 tableOffset;
gInfo->displayClockFrequency = 0;
gInfo->dpExternalClock = 0;
int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
if (atom_parse_data_header(gAtomContext, index, NULL,
&tableMajor, &tableMinor, &tableOffset) != B_OK) {
ERROR("%s: Couldn't parse data header\n", __func__);
return B_ERROR;
}
TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
tableMajor, tableMinor);
union atomFirmwareInfo {
ATOM_FIRMWARE_INFO info;
ATOM_FIRMWARE_INFO_V1_2 info_12;
ATOM_FIRMWARE_INFO_V1_3 info_13;
ATOM_FIRMWARE_INFO_V1_4 info_14;
ATOM_FIRMWARE_INFO_V2_1 info_21;
ATOM_FIRMWARE_INFO_V2_2 info_22;
};
union atomFirmwareInfo* firmwareInfo
= (union atomFirmwareInfo*)(gAtomContext->bios + tableOffset);
radeon_shared_info &info = *gInfo->shared_info;
if (info.dceMajor >= 4) {
gInfo->displayClockFrequency = B_LENDIAN_TO_HOST_INT32(
firmwareInfo->info_21.ulDefaultDispEngineClkFreq);
if (gInfo->displayClockFrequency == 0) {
if (info.dceMajor >= 5)
gInfo->displayClockFrequency = 54000;
else
gInfo->displayClockFrequency = 60000;
}
gInfo->dpExternalClock = B_LENDIAN_TO_HOST_INT16(
firmwareInfo->info_21.usUniphyDPModeExtClkFreq);
}
gInfo->maximumPixelClock = B_LENDIAN_TO_HOST_INT16(
firmwareInfo->info.usMaxPixelClock);
if (gInfo->maximumPixelClock == 0)
gInfo->maximumPixelClock = 40000;
return B_OK;
}
status_t
radeon_gpu_reset()
{

View File

@ -164,6 +164,7 @@
#define SOFT_RESET_IA (1 << 15)
status_t radeon_gpu_probe();
status_t radeon_gpu_reset();
void radeon_gpu_mc_halt(struct gpu_state *gpuState);
void radeon_gpu_mc_resume(struct gpu_state *gpuState);

View File

@ -38,8 +38,6 @@ extern "C" void _sPrintf(const char* format, ...);
status_t
pll_limit_probe(pll_info* pll)
{
radeon_shared_info &info = *gInfo->shared_info;
uint8 tableMajor;
uint8 tableMinor;
uint16 tableOffset;
@ -120,12 +118,6 @@ pll_limit_probe(pll_info* pll)
pll->pllInMax = B_LENDIAN_TO_HOST_INT16(
firmwareInfo->info.usMaxPixelClockPLL_Input) * 10;
if (info.dceMajor >= 4) {
pll->dpExternalClock = B_LENDIAN_TO_HOST_INT16(
firmwareInfo->info_21.usUniphyDPModeExtClkFreq);
} else
pll->dpExternalClock = 0;
TRACE("%s: referenceFreq: %" B_PRIu16 "; pllOutMin: %" B_PRIu16 "; "
" pllOutMax: %" B_PRIu16 "; pllInMin: %" B_PRIu16 ";"
"pllInMax: %" B_PRIu16 "\n", __func__, pll->referenceFreq,
@ -810,6 +802,86 @@ pll_set(display_mode* mode, uint8 crtcID)
}
status_t
pll_external_set(uint32 clock)
{
TRACE("%s: set external pll clock to %" B_PRIu32 "\n", __func__, clock);
if (clock == 0)
ERROR("%s: Warning: default display clock is 0?\n", __func__);
// also known as PLL display engineering
uint8 tableMajor;
uint8 tableMinor;
int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor);
TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
tableMajor, tableMinor);
union setPixelClock {
SET_PIXEL_CLOCK_PS_ALLOCATION base;
PIXEL_CLOCK_PARAMETERS v1;
PIXEL_CLOCK_PARAMETERS_V2 v2;
PIXEL_CLOCK_PARAMETERS_V3 v3;
PIXEL_CLOCK_PARAMETERS_V5 v5;
PIXEL_CLOCK_PARAMETERS_V6 v6;
};
union setPixelClock args;
memset(&args, 0, sizeof(args));
radeon_shared_info &info = *gInfo->shared_info;
uint32 dceVersion = (info.dceMajor * 100) + info.dceMinor;
switch (tableMajor) {
case 1:
switch(tableMinor) {
case 5:
// If the default DC PLL clock is specified,
// SetPixelClock provides the dividers.
args.v5.ucCRTC = ATOM_CRTC_INVALID;
args.v5.usPixelClock = B_HOST_TO_LENDIAN_INT16(clock);
args.v5.ucPpll = ATOM_DCPLL;
break;
case 6:
// If the default DC PLL clock is specified,
// SetPixelClock provides the dividers.
args.v6.ulDispEngClkFreq = B_HOST_TO_LENDIAN_INT32(clock);
if (dceVersion == 601)
args.v6.ucPpll = ATOM_EXT_PLL1;
else if (dceVersion >= 600)
args.v6.ucPpll = ATOM_PPLL0;
else
args.v6.ucPpll = ATOM_DCPLL;
break;
default:
ERROR("%s: Unknown table version %" B_PRIu8
".%" B_PRIu8 "\n", __func__, tableMajor, tableMinor);
}
break;
default:
ERROR("%s: Unknown table version %" B_PRIu8
".%" B_PRIu8 "\n", __func__, tableMajor, tableMinor);
}
return B_OK;
}
void
pll_external_init()
{
radeon_shared_info &info = *gInfo->shared_info;
if (info.dceMajor >= 6) {
pll_external_set(gInfo->displayClockFrequency);
} else if (info.dceMajor >= 4) {
// TODO: SS enabled? disable
pll_external_set(gInfo->displayClockFrequency);
// TODO: SS enabled? enable
}
}
status_t
pll_pick(uint32 connectorIndex)
{
@ -837,7 +909,7 @@ pll_pick(uint32 connectorIndex)
} else if (info.dceMajor >= 5) {
pll->id = ATOM_DCPLL;
return B_OK;
} else if (pll->dpExternalClock) {
} else if (gInfo->dpExternalClock) {
pll->id = ATOM_PPLL_INVALID;
return B_OK;
}

View File

@ -49,9 +49,6 @@ struct pll_info {
/* pixel clock to be programmed (kHz)*/
uint32 pixelClock;
/* external DisplayPort clock freq */
uint32 dpExternalClock;
/* flags for the current clock */
uint32 flags;
@ -100,6 +97,8 @@ struct pll_info {
};
void pll_external_init();
status_t pll_external_set(uint32 clock);
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);