987 lines
39 KiB
C
987 lines
39 KiB
C
/* $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 #%d\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 #%d\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 #%d\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 #%d\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
|
|
);
|
|
}
|
|
}
|
|
}
|