| /* $NoKeywords:$ */ |
| /** |
| * @file |
| * |
| * Service procedure to initialize Integrated Info Table |
| * |
| * |
| * |
| * @xrefitem bom "File Content Label" "Release Content" |
| * @e project: AGESA |
| * @e sub-project: GNB |
| * @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $ |
| * |
| */ |
| /* |
| ***************************************************************************** |
| * |
| * Copyright (c) 2008 - 2012, Advanced Micro Devices, Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * * Neither the name of Advanced Micro Devices, Inc. nor the names of |
| * its contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * *************************************************************************** |
| * |
| */ |
| |
| |
| /*---------------------------------------------------------------------------------------- |
| * M O D U L E S U S E D |
| *---------------------------------------------------------------------------------------- |
| */ |
| #include "AGESA.h" |
| #include "Ids.h" |
| #include "amdlib.h" |
| #include "heapManager.h" |
| #include "Gnb.h" |
| #include "GnbFuseTable.h" |
| #include "GnbPcie.h" |
| #include "GnbGfx.h" |
| #include "GnbFuseTable.h" |
| #include "GnbGfxFamServices.h" |
| #include "GnbCommonLib.h" |
| #include "GfxPowerPlayTable.h" |
| #include "Filecode.h" |
| #define FILECODE PROC_GNB_MODULES_GNBGFXINITLIBV1_GFXPOWERPLAYTABLE_FILECODE |
| |
| /*---------------------------------------------------------------------------------------- |
| * D E F I N I T I O N S A N D M A C R O S |
| *---------------------------------------------------------------------------------------- |
| */ |
| |
| /*---------------------------------------------------------------------------------------- |
| * T Y P E D E F S A N D S T R U C T U R E S |
| *---------------------------------------------------------------------------------------- |
| */ |
| /// Software state |
| typedef struct { |
| BOOLEAN Valid; ///< State valid |
| UINT16 Classification; ///< State classification |
| UINT32 CapsAndSettings; ///< State capability and settings |
| UINT16 Classification2; ///< State classification2 |
| UINT32 Vclk; ///< UVD VCLK |
| UINT32 Dclk; ///< UVD DCLK |
| UINT8 NumberOfDpmStates; ///< Number of DPM states |
| UINT8 DpmSatesArray[MAX_NUM_OF_DPM_STATES]; ///< DPM state index array |
| } SW_STATE; |
| |
| /// DPM state |
| typedef struct { |
| BOOLEAN Valid; ///< State valid |
| UINT32 Sclk; ///< Sclk in kHz |
| UINT8 Vid; ///< VID index |
| UINT16 Tdp; ///< Tdp limit |
| } DPM_STATE; |
| |
| typedef struct { |
| GFX_PLATFORM_CONFIG *Gfx; |
| ATOM_PPLIB_POWERPLAYTABLE3 *PpTable; |
| PP_FUSE_ARRAY *PpFuses; |
| SW_STATE SwStateArray [MAX_NUM_OF_SW_STATES]; ///< SW state array |
| DPM_STATE DpmStateArray[MAX_NUM_OF_DPM_STATES]; ///< Sclk DPM state array |
| UINT8 NumOfClockVoltageLimitEnties; /// |
| ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_RECORD VceClockVoltageLimitArray[MAX_NUM_OF_VCE_CLK_STATES]; |
| UINT8 NumOfVceClockEnties; |
| VCECLOCKINFO VceClockInfoArray[MAX_NUM_OF_VCE_CLK_STATES]; |
| UINT8 NumOfVceStateEntries; |
| ATOM_PPLIB_VCE_STATE_RECORD VceStateArray[MAX_NUM_OF_VCE_STATES]; ///< VCE state array |
| } PP_WORKSPACE; |
| /*---------------------------------------------------------------------------------------- |
| * P R O T O T Y P E S O F L O C A L F U N C T I O N S |
| *---------------------------------------------------------------------------------------- |
| */ |
| |
| VOID |
| GfxIntegratedDebugDumpPpTable ( |
| IN ATOM_PPLIB_POWERPLAYTABLE3 *PpTable, |
| IN GFX_PLATFORM_CONFIG *Gfx |
| ); |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Locate existing tdp |
| * |
| * |
| * @param[in ] PpFuses Pointer to PP_FUSE_ARRAY |
| * @param[in] Sclk Sclk in 10kHz |
| * @param[in] StdHeader Standard configuration header |
| * @retval Tdp limit in DPM state array |
| */ |
| |
| STATIC UINT16 |
| GfxPowerPlayLocateTdp ( |
| IN PP_FUSE_ARRAY *PpFuses, |
| IN UINT32 Sclk, |
| IN AMD_CONFIG_PARAMS *StdHeader |
| ) |
| { |
| UINT8 Index; |
| UINT32 DpmIndex; |
| UINT32 DpmSclk; |
| UINT32 DeltaSclk; |
| UINT32 MinDeltaSclk; |
| |
| DpmIndex = 0; |
| MinDeltaSclk = 0xFFFFFFFF; |
| for (Index = 0; Index < MAX_NUM_OF_FUSED_DPM_STATES; Index++) { |
| if (PpFuses->SclkDpmDid[Index] != 0) { |
| DpmSclk = GfxFmCalculateClock (PpFuses->SclkDpmDid[Index], StdHeader); |
| DeltaSclk = (DpmSclk > Sclk) ? (DpmSclk - Sclk) : (Sclk - DpmSclk); |
| if (DeltaSclk < MinDeltaSclk) { |
| MinDeltaSclk = DeltaSclk; |
| DpmIndex = Index; |
| } |
| } |
| } |
| return PpFuses->SclkDpmTdpLimit[DpmIndex]; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Create new software state |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| * @retval Pointer to state entry in SW state array |
| */ |
| |
| STATIC SW_STATE* |
| GfxPowerPlayCreateSwState ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| UINTN Index; |
| for (Index = 0; Index < MAX_NUM_OF_SW_STATES; Index++) { |
| if (PpWorkspace->SwStateArray[Index].Valid == FALSE) { |
| PpWorkspace->SwStateArray[Index].Valid = TRUE; |
| return &(PpWorkspace->SwStateArray[Index]); |
| } |
| } |
| return NULL; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Create new DPM state |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| * @param[in] Sclk SCLK in kHz |
| * @param[in] Vid Vid index |
| * @param[in] Tdp Tdp limit |
| * @retval Index of state entry in DPM state array |
| */ |
| |
| STATIC UINT8 |
| GfxPowerPlayCreateDpmState ( |
| IN OUT PP_WORKSPACE *PpWorkspace, |
| IN UINT32 Sclk, |
| IN UINT8 Vid, |
| IN UINT16 Tdp |
| ) |
| { |
| UINT8 Index; |
| for (Index = 0; Index < MAX_NUM_OF_DPM_STATES; Index++) { |
| if (PpWorkspace->DpmStateArray[Index].Valid == FALSE) { |
| PpWorkspace->DpmStateArray[Index].Sclk = Sclk; |
| PpWorkspace->DpmStateArray[Index].Vid = Vid; |
| PpWorkspace->DpmStateArray[Index].Valid = TRUE; |
| PpWorkspace->DpmStateArray[Index].Tdp = Tdp; |
| return Index; |
| } |
| } |
| return 0; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Locate existing or Create new DPM state |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| * @param[in] Sclk SCLK in kHz |
| * @param[in] Vid Vid index |
| * @param[in] Tdp Tdp limit |
| * @retval Index of state entry in DPM state array |
| */ |
| |
| STATIC UINT8 |
| GfxPowerPlayAddDpmState ( |
| IN OUT PP_WORKSPACE *PpWorkspace, |
| IN UINT32 Sclk, |
| IN UINT8 Vid, |
| IN UINT16 Tdp |
| ) |
| { |
| UINT8 Index; |
| for (Index = 0; Index < MAX_NUM_OF_DPM_STATES; Index++) { |
| if (PpWorkspace->DpmStateArray[Index].Valid && Sclk == PpWorkspace->DpmStateArray[Index].Sclk && Vid == PpWorkspace->DpmStateArray[Index].Vid) { |
| return Index; |
| } |
| } |
| return GfxPowerPlayCreateDpmState (PpWorkspace, Sclk, Vid, Tdp); |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Add reference to DPM state for SW state |
| * |
| * |
| * @param[in, out] SwStateArray Pointer to SW state array |
| * @param[in] DpmStateIndex DPM state index |
| */ |
| |
| STATIC VOID |
| GfxPowerPlayAddDpmStateToSwState ( |
| IN OUT SW_STATE *SwStateArray, |
| IN UINT8 DpmStateIndex |
| ) |
| { |
| SwStateArray->DpmSatesArray[SwStateArray->NumberOfDpmStates++] = DpmStateIndex; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Copy SW state info to PPTable |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| */ |
| STATIC VOID * |
| GfxPowerPlayAttachStateInfoBlock ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| UINT8 Index; |
| UINT8 SwStateIndex; |
| STATE_ARRAY *StateArray; |
| ATOM_PPLIB_STATE_V2 *States; |
| StateArray = (STATE_ARRAY *) ((UINT8 *) PpWorkspace->PpTable + PpWorkspace->PpTable->sHeader.usStructureSize); |
| States = &StateArray->States[0]; |
| SwStateIndex = 0; |
| for (Index = 0; Index < MAX_NUM_OF_SW_STATES; Index++) { |
| if (PpWorkspace->SwStateArray[Index].Valid && PpWorkspace->SwStateArray[Index].NumberOfDpmStates != 0) { |
| States->nonClockInfoIndex = SwStateIndex; |
| States->ucNumDPMLevels = PpWorkspace->SwStateArray[Index].NumberOfDpmStates; |
| LibAmdMemCopy ( |
| &States->ClockInfoIndex[0], |
| PpWorkspace->SwStateArray[Index].DpmSatesArray, |
| PpWorkspace->SwStateArray[Index].NumberOfDpmStates, |
| GnbLibGetHeader (PpWorkspace->Gfx) |
| ); |
| States = (ATOM_PPLIB_STATE_V2*) ((UINT8*) States + sizeof (ATOM_PPLIB_STATE_V2) + sizeof (UINT8) * (States->ucNumDPMLevels - 1)); |
| SwStateIndex++; |
| } |
| } |
| StateArray->ucNumEntries = SwStateIndex; |
| PpWorkspace->PpTable->sHeader.usStructureSize = PpWorkspace->PpTable->sHeader.usStructureSize + (USHORT) ((UINT8 *) States - (UINT8 *) StateArray); |
| return StateArray; |
| } |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Copy clock info to PPTable |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| */ |
| |
| STATIC VOID * |
| GfxPowerPlayAttachClockInfoBlock ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| CLOCK_INFO_ARRAY *ClockInfoArray; |
| UINT8 Index; |
| UINT8 ClkStateIndex; |
| ClkStateIndex = 0; |
| ClockInfoArray = (CLOCK_INFO_ARRAY *) ((UINT8 *) PpWorkspace->PpTable + PpWorkspace->PpTable->sHeader.usStructureSize); |
| for (Index = 0; Index < MAX_NUM_OF_DPM_STATES; Index++) { |
| if (PpWorkspace->DpmStateArray[Index].Valid == TRUE) { |
| ClockInfoArray->ClockInfo[ClkStateIndex].ucEngineClockHigh = (UINT8) (PpWorkspace->DpmStateArray[Index].Sclk >> 16); |
| ClockInfoArray->ClockInfo[ClkStateIndex].usEngineClockLow = (UINT16) (PpWorkspace->DpmStateArray[Index].Sclk); |
| ClockInfoArray->ClockInfo[ClkStateIndex].vddcIndex = PpWorkspace->DpmStateArray[Index].Vid; |
| ClockInfoArray->ClockInfo[ClkStateIndex].tdpLimit = PpWorkspace->DpmStateArray[Index].Tdp; |
| ClkStateIndex++; |
| } |
| } |
| ClockInfoArray->ucNumEntries = ClkStateIndex; |
| ClockInfoArray->ucEntrySize = sizeof (ATOM_PPLIB_SUMO_CLOCK_INFO); |
| PpWorkspace->PpTable->sHeader.usStructureSize += sizeof (CLOCK_INFO_ARRAY) + sizeof (ATOM_PPLIB_SUMO_CLOCK_INFO) * ClkStateIndex - sizeof (ATOM_PPLIB_SUMO_CLOCK_INFO); |
| return ClockInfoArray; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Copy non clock info to PPTable |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| */ |
| |
| STATIC VOID * |
| GfxPowerPlayAttachNonClockInfoBlock ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| NON_CLOCK_INFO_ARRAY *NonClockInfoArray; |
| UINT8 Index; |
| UINT8 NonClkStateIndex; |
| |
| NonClockInfoArray = (NON_CLOCK_INFO_ARRAY *) ((UINT8 *) PpWorkspace->PpTable + PpWorkspace->PpTable->sHeader.usStructureSize); |
| NonClkStateIndex = 0; |
| for (Index = 0; Index < MAX_NUM_OF_SW_STATES; Index++) { |
| if (PpWorkspace->SwStateArray[Index].Valid && PpWorkspace->SwStateArray[Index].NumberOfDpmStates != 0) { |
| NonClockInfoArray->NonClockInfo[NonClkStateIndex].usClassification = PpWorkspace->SwStateArray[Index].Classification; |
| NonClockInfoArray->NonClockInfo[NonClkStateIndex].ulCapsAndSettings = PpWorkspace->SwStateArray[Index].CapsAndSettings; |
| NonClockInfoArray->NonClockInfo[NonClkStateIndex].usClassification2 = PpWorkspace->SwStateArray[Index].Classification2; |
| NonClockInfoArray->NonClockInfo[NonClkStateIndex].ulDCLK = PpWorkspace->SwStateArray[Index].Dclk; |
| NonClockInfoArray->NonClockInfo[NonClkStateIndex].ulVCLK = PpWorkspace->SwStateArray[Index].Vclk; |
| NonClkStateIndex++; |
| } |
| } |
| NonClockInfoArray->ucNumEntries = NonClkStateIndex; |
| NonClockInfoArray->ucEntrySize = sizeof (ATOM_PPLIB_NONCLOCK_INFO); |
| PpWorkspace->PpTable->sHeader.usStructureSize += sizeof (NON_CLOCK_INFO_ARRAY) + sizeof (ATOM_PPLIB_NONCLOCK_INFO) * NonClkStateIndex - sizeof (ATOM_PPLIB_NONCLOCK_INFO); |
| return NonClockInfoArray; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Check if fused state valid |
| * |
| * |
| * @param[out] Index State index |
| * @param[in] PpFuses Pointer to fuse table |
| * @param[in] Gfx Gfx configuration info |
| * @retval TRUE State is valid |
| */ |
| STATIC BOOLEAN |
| GfxPowerPlayIsFusedStateValid ( |
| IN UINT8 Index, |
| IN PP_FUSE_ARRAY *PpFuses, |
| IN GFX_PLATFORM_CONFIG *Gfx |
| ) |
| { |
| BOOLEAN Result; |
| Result = FALSE; |
| if (PpFuses->SclkDpmValid[Index] != 0) { |
| Result = TRUE; |
| if (PpFuses->PolicyLabel[Index] == POLICY_LABEL_BATTERY && (Gfx->AmdPlatformType & AMD_PLATFORM_MOBILE) == 0) { |
| Result = FALSE; |
| } |
| } |
| return Result; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Get SW state calssification from fuses |
| * |
| * |
| * @param[out] Index State index |
| * @param[in] PpFuses Pointer to fuse table |
| * @param[in] Gfx Gfx configuration info |
| * @retval State classification |
| */ |
| |
| STATIC UINT16 |
| GfxPowerPlayGetClassificationFromFuses ( |
| IN UINT8 Index, |
| IN PP_FUSE_ARRAY *PpFuses, |
| IN GFX_PLATFORM_CONFIG *Gfx |
| ) |
| { |
| UINT16 Classification; |
| Classification = 0; |
| switch (PpFuses->PolicyFlags[Index]) { |
| case 0x1: |
| Classification |= ATOM_PPLIB_CLASSIFICATION_NONUVDSTATE; |
| break; |
| case 0x2: |
| Classification |= ATOM_PPLIB_CLASSIFICATION_UVDSTATE; |
| break; |
| case 0x4: |
| //Possible SD + HD state |
| break; |
| case 0x8: |
| Classification |= ATOM_PPLIB_CLASSIFICATION_HDSTATE; |
| break; |
| case 0x10: |
| Classification |= ATOM_PPLIB_CLASSIFICATION_SDSTATE; |
| break; |
| default: |
| break; |
| } |
| switch (PpFuses->PolicyLabel[Index]) { |
| case POLICY_LABEL_BATTERY: |
| Classification |= ATOM_PPLIB_CLASSIFICATION_UI_BATTERY; |
| break; |
| case POLICY_LABEL_PERFORMANCE: |
| Classification |= ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE; |
| break; |
| default: |
| break; |
| } |
| return Classification; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Get SW state calssification2 from fuses |
| * |
| * |
| * @param[out] Index State index |
| * @param[in] PpFuses Pointer to fuse table |
| * @param[in] Gfx Gfx configuration info |
| * @retval State classification2 |
| */ |
| |
| STATIC UINT16 |
| GfxPowerPlayGetClassification2FromFuses ( |
| IN UINT8 Index, |
| IN PP_FUSE_ARRAY *PpFuses, |
| IN GFX_PLATFORM_CONFIG *Gfx |
| ) |
| { |
| UINT16 Classification2; |
| Classification2 = 0; |
| |
| switch (PpFuses->PolicyFlags[Index]) { |
| |
| case 0x4: |
| Classification2 |= ATOM_PPLIB_CLASSIFICATION2_MVC; |
| break; |
| |
| default: |
| break; |
| } |
| |
| return Classification2; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Build SCLK state info |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| */ |
| |
| STATIC VOID |
| GfxPowerPlayBuildSclkStateTable ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| UINT8 ClkStateIndex; |
| UINT8 DpmFuseIndex; |
| UINT8 Index; |
| UINT32 Sclk; |
| SW_STATE *State; |
| PP_FUSE_ARRAY *PpFuses; |
| |
| PpFuses = PpWorkspace->PpFuses; |
| // Create States from Fuses |
| for (Index = 0; Index < MAX_NUM_OF_FUSED_SW_STATES; Index++) { |
| if (GfxPowerPlayIsFusedStateValid (Index, PpFuses, PpWorkspace->Gfx)) { |
| //Create new SW State; |
| State = GfxPowerPlayCreateSwState (PpWorkspace); |
| State->Classification = GfxPowerPlayGetClassificationFromFuses (Index, PpFuses, PpWorkspace->Gfx); |
| State->Classification2 = GfxPowerPlayGetClassification2FromFuses (Index, PpFuses, PpWorkspace->Gfx); |
| if ((State->Classification & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_UVDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) != 0 || |
| (State->Classification2 & ATOM_PPLIB_CLASSIFICATION2_MVC) != 0) { |
| State->Vclk = (PpFuses->VclkDid[PpFuses->VclkDclkSel[Index]] != 0) ? GfxFmCalculateClock (PpFuses->VclkDid[PpFuses->VclkDclkSel[Index]], GnbLibGetHeader (PpWorkspace->Gfx)) : 0; |
| State->Dclk = (PpFuses->DclkDid[PpFuses->VclkDclkSel[Index]] != 0) ? GfxFmCalculateClock (PpFuses->DclkDid[PpFuses->VclkDclkSel[Index]], GnbLibGetHeader (PpWorkspace->Gfx)) : 0; |
| } |
| if (((State->Classification & 0x7) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) || |
| ((State->Classification & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) != 0)) { |
| if (PpWorkspace->Gfx->AbmSupport != 0) { |
| State->CapsAndSettings |= ATOM_PPLIB_ENABLE_VARIBRIGHT; |
| } |
| if (PpWorkspace->Gfx->DynamicRefreshRate != 0) { |
| State->CapsAndSettings |= ATOM_PPLIB_ENABLE_DRR; |
| } |
| } |
| for (DpmFuseIndex = 0; DpmFuseIndex < MAX_NUM_OF_FUSED_DPM_STATES; DpmFuseIndex++) { |
| if ((PpFuses->SclkDpmValid[Index] & (1 << DpmFuseIndex)) != 0 ) { |
| Sclk = (PpFuses->SclkDpmDid[DpmFuseIndex] != 0) ? GfxFmCalculateClock (PpFuses->SclkDpmDid[DpmFuseIndex], GnbLibGetHeader (PpWorkspace->Gfx)) : 0; |
| if (Sclk != 0) { |
| ClkStateIndex = GfxPowerPlayAddDpmState (PpWorkspace, Sclk, PpFuses->SclkDpmVid[DpmFuseIndex], PpFuses->SclkDpmTdpLimit[DpmFuseIndex]); |
| GfxPowerPlayAddDpmStateToSwState (State, ClkStateIndex); |
| } |
| } |
| } |
| } |
| } |
| // Create Boot State |
| State = GfxPowerPlayCreateSwState (PpWorkspace); |
| State->Classification = ATOM_PPLIB_CLASSIFICATION_BOOT; |
| Sclk = 200 * 100; |
| ClkStateIndex = GfxPowerPlayAddDpmState (PpWorkspace, Sclk, 0, GfxPowerPlayLocateTdp (PpFuses, Sclk, GnbLibGetHeader (PpWorkspace->Gfx))); |
| GfxPowerPlayAddDpmStateToSwState (State, ClkStateIndex); |
| |
| // Create Thermal State |
| State = GfxPowerPlayCreateSwState (PpWorkspace); |
| State->Classification = ATOM_PPLIB_CLASSIFICATION_THERMAL; |
| Sclk = GfxFmCalculateClock (PpFuses->SclkThermDid, GnbLibGetHeader (PpWorkspace->Gfx)); |
| ClkStateIndex = GfxPowerPlayAddDpmState (PpWorkspace, Sclk, 0, GfxPowerPlayLocateTdp (PpFuses, Sclk, GnbLibGetHeader (PpWorkspace->Gfx))); |
| GfxPowerPlayAddDpmStateToSwState (State, ClkStateIndex); |
| } |
| |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Add ECLK state |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| * @param[in] Eclk SCLK in kHz |
| * @retval Index of state entry in ECLK clock array |
| */ |
| |
| STATIC UINT8 |
| GfxPowerPlayAddEclkState ( |
| IN OUT PP_WORKSPACE *PpWorkspace, |
| IN UINT32 Eclk |
| ) |
| { |
| UINT8 Index; |
| USHORT EclkLow; |
| UCHAR EclkHigh; |
| EclkLow = (USHORT) (Eclk & 0xffff); |
| EclkHigh = (UCHAR) (Eclk >> 16); |
| for (Index = 0; Index < PpWorkspace->NumOfVceClockEnties; Index++) { |
| if (PpWorkspace->VceClockInfoArray[Index].ucECClkHigh == EclkHigh && PpWorkspace->VceClockInfoArray[Index].usECClkLow == EclkLow) { |
| return Index; |
| } |
| } |
| PpWorkspace->VceClockInfoArray[PpWorkspace->NumOfVceClockEnties].ucECClkHigh = EclkHigh; |
| PpWorkspace->VceClockInfoArray[PpWorkspace->NumOfVceClockEnties].usECClkLow = EclkLow; |
| PpWorkspace->VceClockInfoArray[PpWorkspace->NumOfVceClockEnties].ucEVClkHigh = EclkHigh; |
| PpWorkspace->VceClockInfoArray[PpWorkspace->NumOfVceClockEnties].usEVClkLow = EclkLow; |
| return PpWorkspace->NumOfVceClockEnties++; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Add ECLK state |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| * @param[in] EclkIndex ECLK index |
| * @param[in] Vid Vid index |
| * @retval Index of state entry in Eclk Voltage record array |
| */ |
| |
| STATIC UINT8 |
| GfxPowerPlayAddEclkVoltageRecord ( |
| IN OUT PP_WORKSPACE *PpWorkspace, |
| IN UINT8 EclkIndex, |
| IN UINT8 Vid |
| ) |
| { |
| UINT8 Index; |
| for (Index = 0; Index < PpWorkspace->NumOfClockVoltageLimitEnties; Index++) { |
| if (PpWorkspace->VceClockVoltageLimitArray[Index].ucVCEClockInfoIndex == EclkIndex) { |
| return Index; |
| } |
| } |
| PpWorkspace->VceClockVoltageLimitArray[PpWorkspace->NumOfClockVoltageLimitEnties].ucVCEClockInfoIndex = EclkIndex; |
| PpWorkspace->VceClockVoltageLimitArray[PpWorkspace->NumOfClockVoltageLimitEnties].usVoltage = Vid; |
| return PpWorkspace->NumOfClockVoltageLimitEnties++; |
| } |
| |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Attach extended header |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| */ |
| |
| STATIC VOID * |
| GfxPowerPlayAttachVceTableRevBlock ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| ATOM_PPLIB_VCE_TABLE *VceTable; |
| VceTable = (ATOM_PPLIB_VCE_TABLE *) ((UINT8 *) PpWorkspace->PpTable + PpWorkspace->PpTable->sHeader.usStructureSize); |
| VceTable->revid = 0; |
| PpWorkspace->PpTable->sHeader.usStructureSize += sizeof (ATOM_PPLIB_VCE_TABLE); |
| return VceTable; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Attach extended header |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| */ |
| |
| STATIC VOID * |
| GfxPowerPlayAttachExtendedHeaderBlock ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| ATOM_PPLIB_EXTENDEDHEADER *ExtendedHeader; |
| ExtendedHeader = (ATOM_PPLIB_EXTENDEDHEADER *) ((UINT8 *) PpWorkspace->PpTable + PpWorkspace->PpTable->sHeader.usStructureSize); |
| ExtendedHeader->usSize = sizeof (ATOM_PPLIB_EXTENDEDHEADER); |
| PpWorkspace->PpTable->sHeader.usStructureSize += sizeof (ATOM_PPLIB_EXTENDEDHEADER); |
| return ExtendedHeader; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Attach VCE clock info block |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| */ |
| |
| STATIC VOID * |
| GfxPowerPlayAttachVceClockInfoBlock ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| VCECLOCKINFOARRAY *VceClockInfoArray; |
| VceClockInfoArray = (VCECLOCKINFOARRAY *) ((UINT8 *) PpWorkspace->PpTable + PpWorkspace->PpTable->sHeader.usStructureSize); |
| VceClockInfoArray->ucNumEntries = PpWorkspace->NumOfVceClockEnties; |
| LibAmdMemCopy ( |
| &VceClockInfoArray->entries[0], |
| &PpWorkspace->VceClockInfoArray[0], |
| VceClockInfoArray->ucNumEntries * sizeof (VCECLOCKINFO), |
| GnbLibGetHeader (PpWorkspace->Gfx) |
| ); |
| PpWorkspace->PpTable->sHeader.usStructureSize = PpWorkspace->PpTable->sHeader.usStructureSize + |
| sizeof (VCECLOCKINFOARRAY) + |
| VceClockInfoArray->ucNumEntries * sizeof (VCECLOCKINFO) - |
| sizeof (VCECLOCKINFO); |
| return VceClockInfoArray; |
| } |
| |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Attach VCE voltage limit block |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| */ |
| |
| STATIC VOID * |
| GfxPowerPlayAttachVceVoltageLimitBlock ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_TABLE *VceClockVoltageLimitTable; |
| VceClockVoltageLimitTable = (ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_TABLE *) ((UINT8 *) PpWorkspace->PpTable + PpWorkspace->PpTable->sHeader.usStructureSize); |
| VceClockVoltageLimitTable->numEntries = PpWorkspace->NumOfClockVoltageLimitEnties; |
| LibAmdMemCopy ( |
| &VceClockVoltageLimitTable->entries[0], |
| &PpWorkspace->VceClockVoltageLimitArray[0], |
| VceClockVoltageLimitTable->numEntries * sizeof (ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_RECORD), |
| GnbLibGetHeader (PpWorkspace->Gfx) |
| ); |
| PpWorkspace->PpTable->sHeader.usStructureSize = PpWorkspace->PpTable->sHeader.usStructureSize + |
| sizeof (ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_TABLE) + |
| VceClockVoltageLimitTable->numEntries * sizeof (ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_RECORD) - |
| sizeof (ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_RECORD); |
| return VceClockVoltageLimitTable; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Attach VCE state block |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| */ |
| |
| STATIC VOID * |
| GfxPowerPlayAttachVceStateTaleBlock ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| ATOM_PPLIB_VCE_STATE_TABLE *VceStateTable; |
| VceStateTable = (ATOM_PPLIB_VCE_STATE_TABLE *) ((UINT8 *) PpWorkspace->PpTable + PpWorkspace->PpTable->sHeader.usStructureSize); |
| VceStateTable->numEntries = PpWorkspace->NumOfVceStateEntries; |
| LibAmdMemCopy ( |
| &VceStateTable->entries[0], |
| &PpWorkspace->VceStateArray[0], |
| VceStateTable->numEntries * sizeof (ATOM_PPLIB_VCE_STATE_RECORD), |
| GnbLibGetHeader (PpWorkspace->Gfx) |
| ); |
| PpWorkspace->PpTable->sHeader.usStructureSize = PpWorkspace->PpTable->sHeader.usStructureSize + |
| sizeof (ATOM_PPLIB_VCE_STATE_TABLE) + |
| VceStateTable->numEntries * sizeof (ATOM_PPLIB_VCE_STATE_RECORD) - |
| sizeof (ATOM_PPLIB_VCE_STATE_RECORD); |
| return VceStateTable; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Build VCE state info |
| * |
| * |
| * @param[in, out] PpWorkspace PP workspace |
| */ |
| |
| STATIC VOID |
| GfxPowerPlayBuildVceStateTable ( |
| IN OUT PP_WORKSPACE *PpWorkspace |
| ) |
| { |
| UINT8 Index; |
| UINT8 VceStateIndex; |
| UINT8 Vid; |
| UINT32 Eclk; |
| UINT32 Sclk; |
| UINT8 UsedStateBitmap; |
| UsedStateBitmap = 0; |
| // build used state |
| for (Index = 0; Index < ARRAY_SIZE(PpWorkspace->PpFuses->VceFlags); Index++) { |
| UsedStateBitmap |= PpWorkspace->PpFuses->VceFlags[Index]; |
| for (VceStateIndex = 0; VceStateIndex < ARRAY_SIZE(PpWorkspace->VceStateArray); VceStateIndex++) { |
| if ((PpWorkspace->PpFuses->VceFlags[Index] & (1 << VceStateIndex)) != 0) { |
| Sclk = GfxFmCalculateClock (PpWorkspace->PpFuses->SclkDpmDid[PpWorkspace->PpFuses->VceReqSclkSel[Index]], GnbLibGetHeader (PpWorkspace->Gfx)); |
| Vid = PpWorkspace->PpFuses->SclkDpmVid[PpWorkspace->PpFuses->VceReqSclkSel[Index]]; |
| PpWorkspace->VceStateArray[VceStateIndex].ucClockInfoIndex = GfxPowerPlayAddDpmState (PpWorkspace, Sclk, Vid, GfxPowerPlayLocateTdp (PpWorkspace->PpFuses, Sclk, GnbLibGetHeader (PpWorkspace->Gfx))); |
| if (PpWorkspace->PpFuses->VceMclk[Index] == 1) { |
| PpWorkspace->VceStateArray[VceStateIndex].ucClockInfoIndex |= (PpWorkspace->PpFuses->VceMclk[Index] << 6); |
| } |
| Eclk = GfxFmCalculateClock (PpWorkspace->PpFuses->EclkDid[Index], GnbLibGetHeader (PpWorkspace->Gfx)); |
| PpWorkspace->VceStateArray[VceStateIndex].ucVCEClockInfoIndex = GfxPowerPlayAddEclkState (PpWorkspace, Eclk); |
| GfxPowerPlayAddEclkVoltageRecord (PpWorkspace, PpWorkspace->VceStateArray[VceStateIndex].ucVCEClockInfoIndex, Vid); |
| PpWorkspace->NumOfVceStateEntries++; |
| } |
| } |
| } |
| //build unused states |
| for (VceStateIndex = 0; VceStateIndex < ARRAY_SIZE(PpWorkspace->VceStateArray); VceStateIndex++) { |
| if ((UsedStateBitmap & (1 << VceStateIndex)) == 0) { |
| PpWorkspace->VceStateArray[VceStateIndex].ucClockInfoIndex = 0; |
| PpWorkspace->VceStateArray[VceStateIndex].ucVCEClockInfoIndex = GfxPowerPlayAddEclkState (PpWorkspace, 0); |
| PpWorkspace->NumOfVceStateEntries++; |
| } |
| } |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Build PP table |
| * |
| * |
| * @param[out] Buffer Buffer to create PP table |
| * @param[in] Gfx Gfx configuration info |
| * @retval AGESA_SUCCESS |
| * @retval AGESA_ERROR |
| */ |
| |
| AGESA_STATUS |
| GfxPowerPlayBuildTable ( |
| OUT VOID *Buffer, |
| IN GFX_PLATFORM_CONFIG *Gfx |
| ) |
| { |
| PP_WORKSPACE PpWorkspace; |
| VOID *BlockPtr; |
| |
| LibAmdMemFill (&PpWorkspace, 0x00, sizeof (PP_WORKSPACE), GnbLibGetHeader (Gfx)); |
| PpWorkspace.PpFuses = GnbLocateHeapBuffer (AMD_PP_FUSE_TABLE_HANDLE, GnbLibGetHeader (Gfx)); |
| ASSERT (PpWorkspace.PpFuses != NULL); |
| if (PpWorkspace.PpFuses == NULL) { |
| return AGESA_ERROR; |
| } |
| PpWorkspace.PpTable = (ATOM_PPLIB_POWERPLAYTABLE3 *) Buffer; |
| PpWorkspace.Gfx = Gfx; |
| //Fill static info |
| PpWorkspace.PpTable->sHeader.ucTableFormatRevision = 6; |
| PpWorkspace.PpTable->sHeader.ucTableContentRevision = 1; |
| PpWorkspace.PpTable->ucDataRevision = PpWorkspace.PpFuses->PPlayTableRev; |
| PpWorkspace.PpTable->sThermalController.ucType = ATOM_PP_THERMALCONTROLLER_SUMO; |
| PpWorkspace.PpTable->sThermalController.ucFanParameters = ATOM_PP_FANPARAMETERS_NOFAN; |
| PpWorkspace.PpTable->sHeader.usStructureSize = sizeof (ATOM_PPLIB_POWERPLAYTABLE3); |
| PpWorkspace.PpTable->usTableSize = sizeof (ATOM_PPLIB_POWERPLAYTABLE3); |
| PpWorkspace.PpTable->usFormatID = 7; |
| if ((Gfx->AmdPlatformType & AMD_PLATFORM_MOBILE) != 0) { |
| PpWorkspace.PpTable->ulPlatformCaps |= ATOM_PP_PLATFORM_CAP_POWERPLAY; |
| } |
| |
| // Fill Slck SW/DPM state info |
| GfxPowerPlayBuildSclkStateTable (&PpWorkspace); |
| // Fill Eclk state info |
| if (PpWorkspace.PpFuses->VceSateTableSupport) { |
| GfxPowerPlayBuildVceStateTable (&PpWorkspace); |
| } |
| |
| //Copy state info to actual PP table |
| BlockPtr = GfxPowerPlayAttachStateInfoBlock (&PpWorkspace); |
| PpWorkspace.PpTable->usStateArrayOffset = (USHORT) ((UINT8 *) BlockPtr - (UINT8 *) (PpWorkspace.PpTable)); |
| BlockPtr = GfxPowerPlayAttachClockInfoBlock (&PpWorkspace); |
| PpWorkspace.PpTable->usClockInfoArrayOffset = (USHORT) ((UINT8 *) BlockPtr - (UINT8 *) (PpWorkspace.PpTable)); |
| BlockPtr = GfxPowerPlayAttachNonClockInfoBlock (&PpWorkspace); |
| PpWorkspace.PpTable->usNonClockInfoArrayOffset = (USHORT) ((UINT8 *) BlockPtr - (UINT8 *) (PpWorkspace.PpTable)); |
| if (PpWorkspace.PpFuses->VceSateTableSupport) { |
| ATOM_PPLIB_EXTENDEDHEADER *ExtendedHeader; |
| ExtendedHeader = (ATOM_PPLIB_EXTENDEDHEADER *) GfxPowerPlayAttachExtendedHeaderBlock (&PpWorkspace); |
| PpWorkspace.PpTable->usExtendendedHeaderOffset = (USHORT) ((UINT8 *) ExtendedHeader - (UINT8 *) (PpWorkspace.PpTable)); |
| BlockPtr = GfxPowerPlayAttachVceTableRevBlock (&PpWorkspace); |
| ExtendedHeader->usVCETableOffset = (USHORT) ((UINT8 *) BlockPtr - (UINT8 *) (PpWorkspace.PpTable)); |
| GfxPowerPlayAttachVceClockInfoBlock (&PpWorkspace); |
| GfxPowerPlayAttachVceVoltageLimitBlock (&PpWorkspace); |
| GfxPowerPlayAttachVceStateTaleBlock (&PpWorkspace); |
| |
| } |
| GNB_DEBUG_CODE ( |
| GfxIntegratedDebugDumpPpTable (PpWorkspace.PpTable, Gfx); |
| ); |
| return AGESA_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Dump PP table |
| * |
| * |
| * |
| * @param[in] PpTable Power Play table |
| * @param[in] Gfx Gfx configuration info |
| */ |
| |
| VOID |
| GfxIntegratedDebugDumpPpTable ( |
| IN ATOM_PPLIB_POWERPLAYTABLE3 *PpTable, |
| IN GFX_PLATFORM_CONFIG *Gfx |
| ) |
| { |
| UINTN Index; |
| UINTN DpmIndex; |
| STATE_ARRAY *StateArray; |
| ATOM_PPLIB_STATE_V2 *StatesPtr; |
| NON_CLOCK_INFO_ARRAY *NonClockInfoArrayPtr; |
| CLOCK_INFO_ARRAY *ClockInfoArrayPtr; |
| ATOM_PPLIB_EXTENDEDHEADER *ExtendedHeader; |
| ATOM_PPLIB_VCE_STATE_TABLE *VceStateTable; |
| ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_TABLE *VceClockVoltageLimitTable; |
| VCECLOCKINFOARRAY *VceClockInfoArray; |
| UINT8 SclkIndex; |
| UINT8 EclkIndex; |
| |
| IDS_HDT_CONSOLE (GFX_MISC, " < --- Power Play Table ------ > \n"); |
| IDS_HDT_CONSOLE (GFX_MISC, " Table Revision = %d\n", PpTable->ucDataRevision); |
| StateArray = (STATE_ARRAY *) ((UINT8 *) PpTable + PpTable->usStateArrayOffset); |
| StatesPtr = StateArray->States; |
| NonClockInfoArrayPtr = (NON_CLOCK_INFO_ARRAY *) ((UINT8 *) PpTable + PpTable->usNonClockInfoArrayOffset); |
| ClockInfoArrayPtr = (CLOCK_INFO_ARRAY *) ((UINT8 *) PpTable + PpTable->usClockInfoArrayOffset); |
| IDS_HDT_CONSOLE (GFX_MISC, " < --- SW State Table ---------> \n"); |
| for (Index = 0; Index < StateArray->ucNumEntries; Index++) { |
| IDS_HDT_CONSOLE (GFX_MISC, " State #%ld\n", Index + 1 |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " Classification 0x%x\n", |
| NonClockInfoArrayPtr->NonClockInfo[StatesPtr->nonClockInfoIndex].usClassification |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " Classification2 0x%x\n", |
| NonClockInfoArrayPtr->NonClockInfo[StatesPtr->nonClockInfoIndex].usClassification2 |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " VCLK = %dkHz\n", |
| NonClockInfoArrayPtr->NonClockInfo[StatesPtr->nonClockInfoIndex].ulVCLK |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " DCLK = %dkHz\n", |
| NonClockInfoArrayPtr->NonClockInfo[StatesPtr->nonClockInfoIndex].ulDCLK |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " DPM State Index: "); |
| for (DpmIndex = 0; DpmIndex < StatesPtr->ucNumDPMLevels; DpmIndex++) { |
| IDS_HDT_CONSOLE (GFX_MISC, "%d ", |
| StatesPtr->ClockInfoIndex [DpmIndex] |
| ); |
| } |
| IDS_HDT_CONSOLE (GFX_MISC, "\n"); |
| StatesPtr = (ATOM_PPLIB_STATE_V2 *) ((UINT8 *) StatesPtr + sizeof (ATOM_PPLIB_STATE_V2) + StatesPtr->ucNumDPMLevels - 1); |
| } |
| IDS_HDT_CONSOLE (GFX_MISC, " < --- SCLK DPM State Table ---> \n"); |
| for (Index = 0; Index < ClockInfoArrayPtr->ucNumEntries; Index++) { |
| UINT32 Sclk; |
| Sclk = ClockInfoArrayPtr->ClockInfo[Index].usEngineClockLow | (ClockInfoArrayPtr->ClockInfo[Index].ucEngineClockHigh << 16); |
| IDS_HDT_CONSOLE (GFX_MISC, " DPM State #%ld\n", |
| Index |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " SCLK = %d\n", |
| ClockInfoArrayPtr->ClockInfo[Index].usEngineClockLow | (ClockInfoArrayPtr->ClockInfo[Index].ucEngineClockHigh << 16) |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " VID index = %d\n", |
| ClockInfoArrayPtr->ClockInfo[Index].vddcIndex |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " tdpLimit = %d\n", |
| ClockInfoArrayPtr->ClockInfo[Index].tdpLimit |
| ); |
| } |
| if (PpTable->usExtendendedHeaderOffset != 0) { |
| ExtendedHeader = (ATOM_PPLIB_EXTENDEDHEADER *) ((UINT8 *) PpTable + PpTable->usExtendendedHeaderOffset); |
| VceClockInfoArray = (VCECLOCKINFOARRAY *) ((UINT8 *) ExtendedHeader + sizeof (ATOM_PPLIB_EXTENDEDHEADER) + sizeof (ATOM_PPLIB_VCE_TABLE)); |
| VceClockVoltageLimitTable = (ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_TABLE *) ((UINT8 *) VceClockInfoArray + |
| sizeof (VCECLOCKINFOARRAY) + |
| VceClockInfoArray->ucNumEntries * sizeof (VCECLOCKINFO) - |
| sizeof (VCECLOCKINFO)); |
| VceStateTable = (ATOM_PPLIB_VCE_STATE_TABLE *) ((UINT8 *) VceClockVoltageLimitTable + |
| sizeof (ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_TABLE) + |
| VceClockVoltageLimitTable->numEntries * sizeof (ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_RECORD) - |
| sizeof (ATOM_PPLIB_VCE_CLOCK_VOLTAGE_LIMIT_RECORD)); |
| |
| IDS_HDT_CONSOLE (GFX_MISC, " < --- VCE State Table [%d]--> \n", VceStateTable->numEntries); |
| for (Index = 0; Index < VceStateTable->numEntries; Index++) { |
| SclkIndex = VceStateTable->entries[Index].ucClockInfoIndex & 0x3F; |
| EclkIndex = VceStateTable->entries[Index].ucVCEClockInfoIndex; |
| IDS_HDT_CONSOLE (GFX_MISC, " VCE State #%ld\n", Index |
| ); |
| if ((VceClockInfoArray->entries[EclkIndex].usECClkLow | (VceClockInfoArray->entries[EclkIndex].ucECClkHigh << 16)) == 0) { |
| IDS_HDT_CONSOLE (GFX_MISC, " Disable\n"); |
| } else { |
| IDS_HDT_CONSOLE (GFX_MISC, " SCLK = %d\n", |
| ClockInfoArrayPtr->ClockInfo[SclkIndex].usEngineClockLow | (ClockInfoArrayPtr->ClockInfo[SclkIndex].ucEngineClockHigh << 16) |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " ECCLK = %d\n", |
| VceClockInfoArray->entries[EclkIndex].usECClkLow | (VceClockInfoArray->entries[EclkIndex].ucECClkHigh << 16) |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " EVCLK = %d\n", |
| VceClockInfoArray->entries[EclkIndex].usEVClkLow | (VceClockInfoArray->entries[EclkIndex].ucEVClkHigh << 16) |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " MCLK = %d\n", |
| (VceStateTable->entries[Index].ucClockInfoIndex >> 6 ) & 0x3 |
| ); |
| } |
| } |
| IDS_HDT_CONSOLE (GFX_MISC, " < --- VCE Voltage Record Table ---> \n"); |
| for (Index = 0; Index < VceClockVoltageLimitTable->numEntries; Index++) { |
| EclkIndex = VceClockVoltageLimitTable->entries[Index].ucVCEClockInfoIndex; |
| IDS_HDT_CONSOLE (GFX_MISC, " VCE Voltage Record #%ld\n", Index |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " ECLK = %d\n", |
| VceClockInfoArray->entries[EclkIndex].usECClkLow | (VceClockInfoArray->entries[EclkIndex].ucECClkHigh << 16) |
| ); |
| IDS_HDT_CONSOLE (GFX_MISC, " VID index = %d\n", |
| VceClockVoltageLimitTable->entries[Index].usVoltage |
| ); |
| } |
| } |
| } |