AGESA_STATUS
GfxFmCalculateClock (
  IN       UINT8                       Did,
  IN       AMD_CONFIG_PARAMS          *StdHeader
  )
{
  UINT32  MainPllFreq10kHz;
  MainPllFreq10kHz = GfxLibGetMainPllFreq (StdHeader) * 100;
  return GfxLibCalculateClk (Did, MainPllFreq10kHz);
}
VOID
GfxIntegratedInfoInitDispclkTable (
  IN       PP_FUSE_ARRAY                    *PpFuseArray,
  IN       ATOM_INTEGRATED_SYSTEM_INFO_V6   *IntegratedInfoTable,
  IN       GFX_PLATFORM_CONFIG              *Gfx
  )
{
  UINTN   Index;
  for (Index = 0; Index < 4; Index++) {
    if (PpFuseArray->DisplclkDid[Index] != 0) {
      IntegratedInfoTable->sDISPCLK_Voltage[Index].ulMaximumSupportedCLK = GfxLibCalculateClk (
                                                                             PpFuseArray->DisplclkDid[Index],
                                                                             IntegratedInfoTable->ulDentistVCOFreq
                                                                             );
      IntegratedInfoTable->sDISPCLK_Voltage[Index].ulVoltageIndex = (ULONG) Index;
    }
  }
}
AGESA_STATUS
NbFmInitLclkDpmRcActivity (
  IN      AMD_CONFIG_PARAMS   *StdHeader
  )
{
  AGESA_STATUS    Status;
  PP_FUSE_ARRAY   *PpFuseArray;
  INT8            Index;
  UINTN           LclkState;
  Status = AGESA_SUCCESS;
  IDS_HDT_CONSOLE (GNB_TRACE, "NbFmInitLclkDpmRcActivity F14 Enter\n");
  PpFuseArray = GnbLocateHeapBuffer (AMD_PP_FUSE_TABLE_HANDLE, StdHeader);
  if (PpFuseArray != NULL) {
    UINT32  ActivityThreshold [8];
    UINT16  SamplingPeriod [10];
    UINT8   LclkScalingDid [4];
    UINT8   LclkScalingVid [4];
    UINT32  LclkDpmValid;
    UINT32  MainPllVcoKHz;
    LibAmdMemFill (&ActivityThreshold[0], 0, sizeof (ActivityThreshold), StdHeader);
    LibAmdMemFill (&SamplingPeriod[0], 0, sizeof (SamplingPeriod), StdHeader);
    MainPllVcoKHz = GfxLibGetMainPllFreq (StdHeader) * 100;
    LclkDpmValid = 0;
    LclkState = 7;
    for (Index = 3; Index >= 0; Index--) {
      if (PpFuseArray->LclkDpmValid [Index] != 0) {
        // Set valid DPM state
        LclkDpmValid |= (1 << (LclkState));
        // Set LCLK scaling DID
        LclkScalingDid [7 - LclkState] = PpFuseArray->LclkDpmDid [Index];
        // Set LCLK scaling VID
        LclkScalingVid [7 - LclkState] = PpFuseArray->LclkDpmVid [Index];
        // Set sampling period
        SamplingPeriod [LclkState] = 0xC350;
        //  Changed from 0xC350 to 0x1388 for DPM 0
        if (Index == 0) {
          SamplingPeriod [LclkState] = 0x1388;
        }
        // Set activity threshold from BKDG:
        // Raising -- ActivityThreshold [LclkState]  = ((102 * (GfxLibCalculateClk (LclkScalingDid [7 - LclkState], MainPllVcoKHz) / 100)) - 10) / 10;
        // Lowering -- ActivityThreshold [LclkState] |= (((407 * (GfxLibCalculateClk (LclkScalingDid [7 - LclkState], MainPllVcoKHz) / 100)) + 99) / 10) << 16;
        // For ON specific enable LCLK DPM :
        ActivityThreshold [LclkState]  = LclkDpmActivityThresholdTable [Index];

        IDS_HDT_CONSOLE (GNB_TRACE, "Fused State Index:%d  LCLK DPM State [%d]: LclkScalingDid - 0x%x, ActivityThreshold - 0x%x,  SamplingPeriod - 0x%x\n",
          Index, LclkState, LclkScalingDid [7 - LclkState], ActivityThreshold [LclkState], SamplingPeriod [LclkState]
          );
        LclkState--;
      }
    }
    if (LclkState != 7) {
      SMUx33_STRUCT         SMUx33;
      SMUx0B_x8434_STRUCT   SMUx0B_x8434;
      FCRxFF30_01E4_STRUCT  FCRxFF30_01E4;
      UINT8                 CurrentUnit;
      UINT16                FinalUnit;
      UINT16                FinalPeriod;
      UINT32                Freq;
      UINT32                FreqDelta;
      UINT32                Value;
      ASSERT (LclkScalingDid [0] != 0);
      FreqDelta = 0xffffffff;
      FinalPeriod = 0;
      FinalUnit = 0;
      Freq = (65535 * 100 * 100) / GfxLibCalculateClk (LclkScalingDid [0], MainPllVcoKHz);
      for (CurrentUnit = 0; CurrentUnit < 16; CurrentUnit++) {
        UINT32  CurrentFreqDelta;
        UINT32  CurrentPeriod;
        UINT32  Temp;
        Temp = GnbLibPowerOf (4, CurrentUnit);
        CurrentPeriod = Freq / Temp;
        if (CurrentPeriod <= 0xFFFF) {
          CurrentFreqDelta = Freq - Temp * CurrentPeriod;
          if (FreqDelta > CurrentFreqDelta) {
            FinalUnit = CurrentUnit;
            FinalPeriod = (UINT16) CurrentPeriod;
            FreqDelta = CurrentFreqDelta;
          }
        }
      }
      //Process to enablement LCLK DPM States
      NbSmuIndirectRead (SMUx33_ADDRESS, AccessWidth32, &SMUx33.Value, StdHeader);
      SMUx33.Field.BusyCntSel = 0x3;
      SMUx33.Field.LclkActMonUnt = FinalUnit;
      SMUx33.Field.LclkActMonPrd = FinalPeriod;
      NbSmuIndirectWrite (SMUx33_ADDRESS, AccessS3SaveWidth32, &SMUx33.Value, StdHeader);
      SMUx0B_x8434.Value = 0;
      SMUx0B_x8434.Field.LclkDpmType = 0x1;
      SMUx0B_x8434.Field.LclkDpmEn = 0x1;
      SMUx0B_x8434.Field.LclkTimerPeriod = 0x0C350;
      SMUx0B_x8434.Field.LclkTimerPrescalar = 0x1;
      NbSmuRcuRegisterWrite (
        SMUx0B_x8434_ADDRESS,
        &SMUx0B_x8434.Value,
        1,
        TRUE,
        StdHeader
        );
      NbSmuRcuRegisterWrite (
        0x84AC,
        &LclkDpmCacTable[0],
        sizeof (LclkDpmCacTable) / sizeof (UINT32),
        TRUE,
        StdHeader
        );
      // Program activity threshold
     IDS_HDT_CONSOLE (GNB_TRACE, "ActivityThreshold[4] - 0x%x ActivityThreshold[5] - 0x%x ActivityThreshold[6] - 0x%x ActivityThreshold[7] - 0x%x\n",
       ActivityThreshold[4], ActivityThreshold[5], ActivityThreshold[6], ActivityThreshold [7]
       );
      NbSmuRcuRegisterWrite (
        SMUx0B_x8470_ADDRESS,
        &ActivityThreshold[4],
        4,
        TRUE,
        StdHeader
        );
      // Program sampling period
      for (Index = 0; Index < (sizeof (SamplingPeriod) / sizeof (SamplingPeriod[0])); Index = Index + 2) {
        UINT16 Temp;
        Temp = SamplingPeriod[Index];
        SamplingPeriod[Index] = SamplingPeriod[Index + 1];
        SamplingPeriod[Index + 1] = Temp;
      }
      IDS_HDT_CONSOLE (GNB_TRACE, "SamplingPeriod[4] - 0x%x SamplingPeriod[5] - 0x%x SamplingPeriod[6] - 0x%x SamplingPeriod[7] - 0x%x  \n",
        SamplingPeriod[4], SamplingPeriod[5], SamplingPeriod[6], SamplingPeriod[7]
        );
      NbSmuRcuRegisterWrite (
        SMUx0B_x8440_ADDRESS,
        (UINT32*) &SamplingPeriod[4],
        2,
        TRUE,
        StdHeader
        );
     // Program LCK scaling DID
      NbSmuRcuRegisterWrite (
        SMUx0B_x848C_ADDRESS,
        (UINT32*) &LclkScalingDid[0],
        1,
        TRUE,
        StdHeader
        );
      // Program LCK scaling VID
      NbSmuRcuRegisterWrite (
        SMUx0B_x8498_ADDRESS,
        (UINT32*) &LclkScalingVid[0],
        1,
        TRUE,
        StdHeader
        );
      // Program valid LCLK DPM states
      LclkDpmValid = NbFmDpmStateBootupInit (LclkDpmValid, StdHeader);
      NbSmuRcuRegisterWrite (
        SMUx0B_x8490_ADDRESS,
        &LclkDpmValid,
        1,
        TRUE,
        StdHeader
        );
      //Setup Activity Monitor  Coefficients
      Value = (0x24 << SMUx35_DownTrendCoef_OFFSET) | (0x24 << SMUx35_UpTrendCoef_OFFSET);
      NbSmuIndirectWrite (SMUx35_ADDRESS, AccessS3SaveWidth32, &Value, StdHeader);
      Value = (0x22 << SMUx35_DownTrendCoef_OFFSET) | (0x22 << SMUx35_UpTrendCoef_OFFSET);
      for (Index = SMUx37_ADDRESS; Index <= SMUx51_ADDRESS; Index = Index + 2) {
        NbSmuIndirectWrite (Index, AccessS3SaveWidth32, &Value, StdHeader);
      }
      // Enable LCLK DPM as voltage client
      NbSmuSrbmRegisterRead (FCRxFF30_01E4_ADDRESS, &FCRxFF30_01E4.Value, StdHeader);
      FCRxFF30_01E4.Field.VoltageChangeEn = 0x1;
      NbSmuSrbmRegisterWrite (FCRxFF30_01E4_ADDRESS, &FCRxFF30_01E4.Value, TRUE, StdHeader);
      // Start LCLK service
      NbSmuServiceRequest (0x8, TRUE, StdHeader);
    }
  } else {
    IDS_HDT_CONSOLE (GNB_TRACE, "  ERROR! Cannot locate fuse table\n");
    Status = AGESA_ERROR;
  }
  IDS_HDT_CONSOLE (GNB_TRACE, "NbFmInitLclkDpmRcActivity F14 Exit [0x%x]\n", Status);
  return Status;
}
VOID
GfxIntegratedInfoInitSclkTable (
  IN       PP_FUSE_ARRAY                    *PpFuseArray,
  IN       ATOM_INTEGRATED_SYSTEM_INFO_V6   *IntegratedInfoTable,
  IN       GFX_PLATFORM_CONFIG              *Gfx
  )
{
  UINTN                       Index;
  UINTN                       TargetIndex;
  UINTN                       ValidSclkStateMask;
  UINT8                       TempDID;
  UINT8                       SclkVidArray[4];
  UINTN                       AvailSclkIndex;
  ATOM_AVAILABLE_SCLK_LIST    *AvailSclkList;
  BOOLEAN                     Sorting;
  AvailSclkList = &IntegratedInfoTable->sAvail_SCLK[0];
  GnbLibPciRead (
    MAKE_SBDFO ( 0, 0, 0x18, 3, D18F3x15C_ADDRESS),
    AccessWidth32,
    &SclkVidArray[0],
    GnbLibGetHeader (Gfx)
    );
  AvailSclkIndex = 0;
  for (Index = 0; Index < MAX_NUM_OF_FUSED_DPM_STATES; Index++) {
    if (PpFuseArray->SclkDpmDid[Index] != 0) {
      AvailSclkList[AvailSclkIndex].ulSupportedSCLK = GfxLibCalculateClk (PpFuseArray->SclkDpmDid[Index], IntegratedInfoTable->ulDentistVCOFreq);
      AvailSclkList[AvailSclkIndex].usVoltageIndex = PpFuseArray->SclkDpmVid[Index];
      AvailSclkList[AvailSclkIndex].usVoltageID = SclkVidArray [PpFuseArray->SclkDpmVid[Index]];
      AvailSclkIndex++;
    }
  }
  //Sort by VoltageIndex & ulSupportedSCLK
  do {
    Sorting = FALSE;
    for (Index = 0; Index < (AvailSclkIndex - 1); Index++) {
      ATOM_AVAILABLE_SCLK_LIST  Temp;
      BOOLEAN                   Exchange;
      Exchange = FALSE;
      if (AvailSclkList[Index].usVoltageIndex > AvailSclkList[Index + 1].usVoltageIndex) {
        Exchange = TRUE;
      }
      if ((AvailSclkList[Index].usVoltageIndex == AvailSclkList[Index + 1].usVoltageIndex) &&
          (AvailSclkList[Index].ulSupportedSCLK > AvailSclkList[Index + 1].ulSupportedSCLK)) {
        Exchange = TRUE;
      }
      if (Exchange) {
        Sorting = TRUE;
        LibAmdMemCopy (&Temp, &AvailSclkList[Index], sizeof (ATOM_AVAILABLE_SCLK_LIST), GnbLibGetHeader (Gfx));
        LibAmdMemCopy (&AvailSclkList[Index], &AvailSclkList[Index + 1], sizeof (ATOM_AVAILABLE_SCLK_LIST), GnbLibGetHeader (Gfx));
        LibAmdMemCopy (&AvailSclkList[Index + 1], &Temp, sizeof (ATOM_AVAILABLE_SCLK_LIST), GnbLibGetHeader (Gfx));
      }
    }
  } while (Sorting);

  if (PpFuseArray->GpuBoostCap == 1) {
    IntegratedInfoTable->SclkDpmThrottleMargin = PpFuseArray->SclkDpmThrottleMargin;
    IntegratedInfoTable->SclkDpmTdpLimitPG = PpFuseArray->SclkDpmTdpLimitPG;
    IntegratedInfoTable->EnableBoost = PpFuseArray->GpuBoostCap;
    IntegratedInfoTable->SclkDpmBoostMargin = PpFuseArray->SclkDpmBoostMargin;
    IntegratedInfoTable->SclkDpmTdpLimitBoost = (PpFuseArray->SclkDpmTdpLimit)[5];
    IntegratedInfoTable->ulBoostEngineCLock = GfxFmCalculateClock ((PpFuseArray->SclkDpmDid)[5], GnbLibGetHeader (Gfx));
    IntegratedInfoTable->ulBoostVid_2bit = (PpFuseArray->SclkDpmVid)[5];

    ValidSclkStateMask = 0;
    TargetIndex = 0;
    for (Index = 0; Index < 6; Index++) {
      ValidSclkStateMask |= (PpFuseArray->SclkDpmValid)[Index];
    }
    TempDID = 0x7F;
    for (Index = 0; Index < 6; Index++) {
      if ((ValidSclkStateMask & ((UINTN)1 << Index)) != 0) {
        if ((PpFuseArray->SclkDpmDid)[Index] <= TempDID) {
          TempDID = (PpFuseArray->SclkDpmDid)[Index];
          TargetIndex = Index;
        }
      }
    }
    IntegratedInfoTable->GnbTdpLimit = (PpFuseArray->SclkDpmTdpLimit)[TargetIndex];
  }

}