diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.cpp b/src/add-ons/accelerants/radeon_hd/accelerant.cpp index cf6bb2eca0..fa6b9c4beb 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.cpp +++ b/src/add-ons/accelerants/radeon_hd/accelerant.cpp @@ -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(); diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.h b/src/add-ons/accelerants/radeon_hd/accelerant.h index 05aa0b2120..6b3d720ace 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.h +++ b/src/add-ons/accelerants/radeon_hd/accelerant.h @@ -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 }; diff --git a/src/add-ons/accelerants/radeon_hd/encoder.cpp b/src/add-ons/accelerants/radeon_hd/encoder.cpp index 9a0d0b418b..bccae25cd3 100644 --- a/src/add-ons/accelerants/radeon_hd/encoder.cpp +++ b/src/add-ons/accelerants/radeon_hd/encoder.cpp @@ -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 { diff --git a/src/add-ons/accelerants/radeon_hd/gpu.cpp b/src/add-ons/accelerants/radeon_hd/gpu.cpp index b835d2e671..85c50cac53 100644 --- a/src/add-ons/accelerants/radeon_hd/gpu.cpp +++ b/src/add-ons/accelerants/radeon_hd/gpu.cpp @@ -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() { diff --git a/src/add-ons/accelerants/radeon_hd/gpu.h b/src/add-ons/accelerants/radeon_hd/gpu.h index d9586c9ae1..f0c0fb687b 100644 --- a/src/add-ons/accelerants/radeon_hd/gpu.h +++ b/src/add-ons/accelerants/radeon_hd/gpu.h @@ -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); diff --git a/src/add-ons/accelerants/radeon_hd/pll.cpp b/src/add-ons/accelerants/radeon_hd/pll.cpp index 3ea25775e6..79b0cb7c54 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.cpp +++ b/src/add-ons/accelerants/radeon_hd/pll.cpp @@ -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; } diff --git a/src/add-ons/accelerants/radeon_hd/pll.h b/src/add-ons/accelerants/radeon_hd/pll.h index 2be6e977c1..c04f042597 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.h +++ b/src/add-ons/accelerants/radeon_hd/pll.h @@ -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);