/** @file
  Install Iio Port Bifurcation Init Data.
  This is depreciated version of the code used for PLATFORM_IIO_CONFIG_UPDATE_VERSION == 1

  @copyright
  Copyright 2020 - 2021 Intel Corporation. <BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#include "PeiCommonBoardInitLib.h"
#include <PiPei.h>
#include <Library/PeiServicesTablePointerLib.h>
#include <Guid/SetupVariable.h>
#include <Guid/PlatformInfo.h>
#include <Ppi/Smbus2.h>
#include <GpioInitData.h>
#include <Upi/KtiHost.h>
#include "IioBifurcationSlotTable.h"
#include <Library/GpioLib.h>
#include <Library/UbaPlatLib.h>
#include <Library/HobLib.h>
#include <Library/UbaIioPortBifurcationInitLib.h>
#include <Library/PchMultiPchBase.h>
#include <CpuAndRevisionDefines.h>
#include <Ppi/DynamicSiLibraryPpi.h>

/**
  Function returns the board ID from running HW

  @return BoardId
**/
UINT8
EFIAPI
SystemBoardIdValue (
  VOID
  )
{
  EFI_HOB_GUID_TYPE       *GuidHob;
  EFI_PLATFORM_INFO       *mPlatformInfo;

  GuidHob = GetFirstGuidHob (&gEfiPlatformInfoGuid);
  ASSERT (GuidHob != NULL);
  if (GuidHob == NULL) {
    return TypePlatformUnknown;
  }
  mPlatformInfo = GET_GUID_HOB_DATA (GuidHob);
  return mPlatformInfo->BoardId;
}


/**
  DVP/Neon City platform support BW5 bifurcation card in socket0 and socket1
  Lightning Ridge platform support BW5 bifurcation card in socket1, socket2 and socket3
  The bifurcation info stored at I/O Expander (PCA9555) which BIOS
  can get through Smbus read.

  PCA9555 SMBus slave Address: 0x4C

----------------------------------
  Neon
----------------------------------
    data0 = BW5 socket0 iio2
    data1 = BW5 socket1 iio0
    data2 = BW5 socket1 iio3
----------------------------------
  Lighting Ridge
----------------------------------
    data1 = BW5 socket1 iio2
    data2 = BW5 socket2 iio1
    data3 = BW5 socket3 iio3

  The bifurcation encoding is [2:0]:
  BW5_BIFURCATE_x4x4x4x4  x 0 0 0
  BW5_BIFURCATE_xxx8x4x4  x 0 0 1
  BW5_BIFURCATE_x4x4xxx8  x 0 1 0
  BW5_BIFURCATE_xxx8xxx8  x 0 1 1
  No BW5                  x 1 1 1

  @param IioGlobalData - Pointer to IioGlobals
  @param Bw5Id         - Pointer to BW5ID

  @retval None

**/
VOID
GetBw5Id (
  IN IIO_GLOBALS *IioGlobalData,
  IN  OUT BW5_BIFURCATION_DATA_STRUCT        *Bw5Id
  )
{
  CONST EFI_PEI_SERVICES    **PeiServices;
  EFI_STATUS                Status;
  EFI_SMBUS_DEVICE_ADDRESS  SmbusDeviceAddress;
  EFI_SMBUS_DEVICE_COMMAND  SmbusCommand;
  EFI_PEI_SMBUS2_PPI        *Smbus = NULL;
  UINT16                    SmbusData = 0;
  UINT8                     RetryCount;
  UINTN                     SmbusLength = 2;
  UINT8                     Index;

  PeiServices = GetPeiServicesTablePointer ();

  Status = (**PeiServices).LocatePpi (
                              PeiServices,
                              &gEfiPeiSmbus2PpiGuid,
                              0,
                              NULL,
                              (VOID** ) &Smbus
                              );

  // Initialize Bw5Id to not present
  for (Index = 0; Index < BW5_CARDS_PRESENT; Index++){
    Bw5Id[Index].Data =  BW5_CARD_NOT_PRESENT;
  }

  if (Status != EFI_SUCCESS || Smbus == NULL) {
    DEBUG ((EFI_D_INFO, "!!!!Get SMBus protocol error %x\n", Status));
  } else {

    // Read Socket 0 HP Controller
    SmbusDeviceAddress.SmbusDeviceAddress = (BW5_SMBUS_ADDRESS >> 1);

    for (RetryCount = 0; RetryCount < NUM_OF_RETRIES; RetryCount++) {
      //
      // Read the current I/O pins Config for Port0
      //
      SmbusCommand = PCA9555_COMMAND_CONFIG_PORT0_REG;
      Status = Smbus->Execute (
                             Smbus,
                             SmbusDeviceAddress,
                             SmbusCommand,
                             EfiSmbusReadWord,
                             FALSE,
                             &SmbusLength,
                             &SmbusData
                             );
       if (!EFI_ERROR(Status)) {
        //
        // Configure the direction of I/O pins for Port0/Port1 as Input.
        //
        SmbusData = SmbusData | BW5_CONFIG_REG_MASK;
        Status = Smbus->Execute (
                             Smbus,
                             SmbusDeviceAddress,
                             SmbusCommand,
                             EfiSmbusWriteWord,
                             FALSE,
                             &SmbusLength,
                             &SmbusData
                             );
         if (!EFI_ERROR(Status)) {
           //
           // Read Input Port0/Port1 register to identify BW5 Id
           //
           SmbusCommand = PCA9555_COMMAND_INPUT_PORT0_REG;
           Status = Smbus->Execute( Smbus,
                               SmbusDeviceAddress,
                               SmbusCommand,
                               EfiSmbusReadWord,
                               FALSE,
                               &SmbusLength,
                               &SmbusData );
           if (!EFI_ERROR(Status)){
             DEBUG ((EFI_D_INFO, "SmbusData Port0/1 %x\n", SmbusData));
             //
             // Mask the Input Port0/1 register data [15:0] to get BW5 ID.
             //
             Bw5Id[0].Data = (SmbusData & BW5_0_ID_MASK);
             Bw5Id[1].Data = (SmbusData & BW5_1_ID_MASK) >> 4;
             Bw5Id[2].Data = (SmbusData & BW5_2_ID_MASK) >> 8;
             Bw5Id[3].Data = (SmbusData & BW5_3_ID_MASK) >> 12;
             break; // Break Loop if read was successfully.
          } // Read Port0
        } // Configure Port0
      } // Read Port0 Config
    } //RetryCount
  } // (Status != EFI_SUCCESS || Smbus == NULL)

  return;
}

EFI_STATUS
InternalPlatformGetSlotTableData2 (
  IN OUT IIO_BROADWAY_ADDRESS_DATA_ENTRY  **BroadwayTable,
  IN OUT UINT8                            *IOU0Setting,
  IN OUT UINT8                            *FlagValue,
  IN OUT UINT8                            *IOU2Setting,
  IN     UINT8                            SkuPersonalityType
  )
{
  EFI_STATUS                        Status;
  UBA_CONFIG_DATABASE_PPI           *UbaConfigPpi = NULL;
  PLATFORM_SLOT_UPDATE_TABLE2       IioSlotTable;
  UINTN                             TableSize;

  Status = PeiServicesLocatePpi (
    &gUbaConfigDatabasePpiGuid,
    0,
    NULL,
    (VOID **) &UbaConfigPpi
    );
  if (EFI_ERROR (Status)) {
    ASSERT_EFI_ERROR (Status);
    return Status;
  }

  TableSize = sizeof(IioSlotTable);
  if ((SkuPersonalityType == 1) || (SkuPersonalityType == 3)) {
    Status = UbaConfigPpi->GetData (
      UbaConfigPpi,
      &gPlatformSlotDataGuid2_1,
      &IioSlotTable,
      &TableSize
      );
  } else {
    Status = UbaConfigPpi->GetData (
      UbaConfigPpi,
      &gPlatformSlotDataGuid2,
      &IioSlotTable,
      &TableSize
      );
  }
  if (EFI_ERROR(Status)) {
    return Status;
  }

  ASSERT (IioSlotTable.Signature == PLATFORM_SLOT_UPDATE_SIGNATURE);
  ASSERT (IioSlotTable.Version == PLATFORM_SLOT_UPDATE_VERSION);

  *BroadwayTable = IioSlotTable.BroadwayTablePtr;
  *IOU0Setting   = IioSlotTable.GetIOU0Setting (*IOU0Setting);
  *FlagValue     = IioSlotTable.FlagValue;
  *IOU2Setting   = IioSlotTable.GetIOU2Setting (SkuPersonalityType, *IOU2Setting);

  return Status;
}

EFI_STATUS
InternalPlatformIioConfigInit2 (
  IN     UINT8                            SkuPersonalityType,
  IN OUT IIO_BIFURCATION_DATA_ENTRY       **BifurcationTable,
  IN OUT UINT8                            *BifurcationEntries,
  IN OUT IIO_SLOT_CONFIG_DATA_ENTRY       **SlotTable,
  IN OUT UINT8                            *SlotEntries
)
{
  EFI_STATUS                        Status = EFI_SUCCESS;
  UBA_CONFIG_DATABASE_PPI           *UbaConfigPpi = NULL;
  PLATFORM_IIO_CONFIG_UPDATE_TABLE  IioConfigTable;
  UINTN                             TableSize;

  Status = PeiServicesLocatePpi (
    &gUbaConfigDatabasePpiGuid,
    0,
    NULL,
    (VOID **) &UbaConfigPpi
    );
  if (EFI_ERROR (Status)) {
    ASSERT_EFI_ERROR (Status);
    return Status;
  }

  TableSize = sizeof(IioConfigTable);
  if (SkuPersonalityType == 1) {
    Status = UbaConfigPpi->GetData (
      UbaConfigPpi,
      &gPlatformIioConfigDataGuid_1,
      &IioConfigTable,
      &TableSize
      );
  } else if (SkuPersonalityType == 2) {
    Status = UbaConfigPpi->GetData (
      UbaConfigPpi,
      &gPlatformIioConfigDataGuid_2,
      &IioConfigTable,
      &TableSize
      );
  } else if (SkuPersonalityType == 3) {
    Status = UbaConfigPpi->GetData (
      UbaConfigPpi,
      &gPlatformIioConfigDataGuid_3,
      &IioConfigTable,
      &TableSize
      );
  } else {
    Status = UbaConfigPpi->GetData (
      UbaConfigPpi,
      &gPlatformIioConfigDataGuid,
      &IioConfigTable,
      &TableSize
      );
  }
  if (EFI_ERROR(Status)) {
    return Status;
  }

  ASSERT (IioConfigTable.Signature == PLATFORM_IIO_CONFIG_UPDATE_SIGNATURE);
  ASSERT (IioConfigTable.Version == PLATFORM_IIO_CONFIG_UPDATE_VERSION);

  *BifurcationTable = IioConfigTable.IioBifurcationTablePtr;
  *BifurcationEntries = (UINT8) (IioConfigTable.IioBifurcationTableSize / sizeof(IIO_BIFURCATION_DATA_ENTRY));

  *SlotTable = IioConfigTable.IioSlotTablePtr;
  *SlotEntries = (UINT8) (IioConfigTable.IioSlotTableSize / sizeof(IIO_SLOT_CONFIG_DATA_ENTRY));

  return Status;
}

VOID
EnableHotPlug_SKX (
    IN OUT IIO_GLOBALS *IioGlobalData,
    IN UINT8 Port,
    IN UINT8 VppPort,
    IN UINT8 VppAddress,
    IN UINT8 PortOwnership
  )
{
  IioGlobalData->SetupData.SLOTHPCAP[Port]= ENABLE;
  IioGlobalData->SetupData.SLOTAIP[Port]  = ENABLE;  // Attention Indicator Present
  IioGlobalData->SetupData.SLOTPIP[Port]  = ENABLE;  // Power Indicator Present
  IioGlobalData->SetupData.SLOTMRLSP[Port]= ENABLE; // MRL Sensor Present
  IioGlobalData->SetupData.SLOTABP[Port]  = ENABLE; // Attention Button Present
  IioGlobalData->SetupData.SLOTPCP[Port]  = ENABLE; // Power Controlled Present

 if (PortOwnership ==  PCIEAIC_OCL_OWNERSHIP){
    IioGlobalData->SetupData.SLOTAIP[Port]  = DISABLE;  // Attention Indicator Present
    IioGlobalData->SetupData.SLOTPIP[Port]  = DISABLE;  // Power Indicator Present
  }
  if (PortOwnership ==  VMD_OWNERSHIP){
    IioGlobalData->SetupData.SLOTABP[Port]  = DISABLE;
    IioGlobalData->SetupData.SLOTPCP[Port]  = DISABLE;
    IioGlobalData->SetupData.SLOTMRLSP[Port]= DISABLE;
  }
  //
  // Set SLTCAP settings based on VMD/PCIe SSD Ownership
  //
  if ((PortOwnership == PCIEAIC_OCL_OWNERSHIP) ||
      (PortOwnership == VMD_OWNERSHIP)){
    IioGlobalData->SetupData.SLOTHPSUP[Port]= ENABLE;   // HotPlug Surprise
  }

  if (VppPort!= VPP_PORT_MAX) {
    IioGlobalData->SetupData.VppEnabled[Port]= TRUE;
    IioGlobalData->SetupData.VppPort[Port]= VppPort;
    IioGlobalData->SetupData.VppAddress[Port] = VppAddress;
  } else {
      DEBUG((EFI_D_ERROR, "PCIE HOT Plug. Missing VPP values on slot table\n"));
  }
}

/**
    Auto determine which PCIe Root port to be hidden if its
    lanes are assigned to its preceding root port...use the
    Setup option variable of ConfigIOU to determine which ports
    are to be hidden on each IOU for corresponding IIO

    @param IOUx                  - IOUx Index
    @param IioIndex              - Index to Iio
    @param IioGlobalData           Pointer to Iio Globals.
**/
VOID
CalculatePEXPHideFromIouBif_SKX (
  IN     UINT8        Iou,
  IN     UINT8        IioIndex,
  IN OUT IIO_GLOBALS *IioGlobalData
  )
{
  UINT8 *PXPHide, *HidePEXPMenu;
  UINT8 CurrentIOUConfigValue;
  UINT8 PXPOffset;
  UINT8 MaxPortNumberPerSocket;

  if (IioIndex >= MaxIIO || Iou >= NELEMENTS (IioGlobalData->SetupData.ConfigIOU[IioIndex])) {

    DEBUG ((DEBUG_ERROR, "[IIO] ERROR: %a: IIO instance %d or IOU %d out of range", __FUNCTION__, IioIndex, Iou));
    ASSERT (FALSE);
    return;
  }
  PXPHide = IioGlobalData->SetupData.PEXPHIDE;
  HidePEXPMenu = IioGlobalData->SetupData.HidePEXPMenu;
  MaxPortNumberPerSocket = IioGlobalData->IioVar.IioOutData.MaxPciePortNumberPerSocket[IioIndex];

  PXPOffset = IioIndex * MaxPortNumberPerSocket;

  CurrentIOUConfigValue = IioGlobalData->SetupData.ConfigIOU[IioIndex][Iou];
  switch (Iou) {
  case Iio_Iou0:
    PXPOffset += PORT_1A_INDEX;
    break;
  case Iio_Iou1:
    PXPOffset += PORT_2A_INDEX;
    break;
  case Iio_Iou2:
    PXPOffset += PORT_3A_INDEX;
    break;
  case Iio_Iou3:
    PXPOffset += PORT_4A_INDEX;
    break;
  case Iio_Iou4:
    PXPOffset += PORT_5A_INDEX;
    break;
  default:
    break;
  }
  switch (CurrentIOUConfigValue) {
    case IIO_BIFURCATE_xxxxxxxx:
      PXPHide[PXPOffset + Iio_PortA] = HIDE;            // hide A
      PXPHide[PXPOffset + Iio_PortB] = HIDE;            // hide B
      PXPHide[PXPOffset + Iio_PortC] = HIDE;            // hide C
      PXPHide[PXPOffset + Iio_PortD] = HIDE;            // hide D
      HidePEXPMenu[PXPOffset + Iio_PortA] = HIDE;       // hide the Setup menu for A
      HidePEXPMenu[PXPOffset + Iio_PortB] = HIDE;       // hide the Setup menu for B
      HidePEXPMenu[PXPOffset + Iio_PortC] = HIDE;       // hide the Setup menu for C
      HidePEXPMenu[PXPOffset + Iio_PortD] = HIDE;       // hide the Setup menu for D
      break;
    case IIO_BIFURCATE_x4x4xxx8:
      PXPHide[PXPOffset + Iio_PortA] = NOT_HIDE;        // show A
      PXPHide[PXPOffset + Iio_PortB] = HIDE;            // hide B
      PXPHide[PXPOffset + Iio_PortC] = NOT_HIDE;        // show C
      PXPHide[PXPOffset + Iio_PortD] = NOT_HIDE;        // show D
      HidePEXPMenu[PXPOffset + Iio_PortA] = NOT_HIDE;   // show the Setup menu for B
      HidePEXPMenu[PXPOffset + Iio_PortB] = HIDE;       // hide the Setup menu for B
      HidePEXPMenu[PXPOffset + Iio_PortC] = NOT_HIDE;   // show the Setup menu for D
      HidePEXPMenu[PXPOffset + Iio_PortD] = NOT_HIDE;   // show the Setup menu for B
      break;
    case IIO_BIFURCATE_xxx8x4x4:
      PXPHide[PXPOffset + Iio_PortA] = NOT_HIDE;        // show A
      PXPHide[PXPOffset + Iio_PortB] = NOT_HIDE;        // show B
      PXPHide[PXPOffset + Iio_PortC] = NOT_HIDE;        // show C
      PXPHide[PXPOffset + Iio_PortD] = HIDE;            // hide port D
      HidePEXPMenu[PXPOffset + Iio_PortA] = NOT_HIDE;   // show the Setup menu for A
      HidePEXPMenu[PXPOffset + Iio_PortB] = NOT_HIDE;   // show the Setup menu for B
      HidePEXPMenu[PXPOffset + Iio_PortC] = NOT_HIDE;   // show the Setup menu for C
      HidePEXPMenu[PXPOffset + Iio_PortD] = HIDE;       // hide the Setup menu for D
      break;
    case IIO_BIFURCATE_xxx8xxx8:
      PXPHide[PXPOffset + Iio_PortA] = NOT_HIDE;        // show A
      PXPHide[PXPOffset + Iio_PortB] = HIDE;            // hide B
      PXPHide[PXPOffset + Iio_PortC] = NOT_HIDE;        // show C
      PXPHide[PXPOffset + Iio_PortD] = HIDE;            // hide D
      HidePEXPMenu[PXPOffset + Iio_PortA] = NOT_HIDE;   // show the Setup menu for A
      HidePEXPMenu[PXPOffset + Iio_PortB] = HIDE;       // hide the Setup menu for B
      HidePEXPMenu[PXPOffset + Iio_PortC] = NOT_HIDE;   // show the Setup menu for C
      HidePEXPMenu[PXPOffset + Iio_PortD] = HIDE;       // hide the Setup menu for D
      break;
    case IIO_BIFURCATE_xxxxxx16:
      PXPHide[PXPOffset + Iio_PortA] = NOT_HIDE;        // show A
      PXPHide[PXPOffset + Iio_PortB] = HIDE;            // hide B
      PXPHide[PXPOffset + Iio_PortC] = HIDE;            // hide C
      PXPHide[PXPOffset + Iio_PortD] = HIDE;            // hide D
      HidePEXPMenu[PXPOffset + Iio_PortA] = NOT_HIDE;   // show the Setup menu for A
      HidePEXPMenu[PXPOffset + Iio_PortB] = HIDE;       // hide the Setup menu for B
      HidePEXPMenu[PXPOffset + Iio_PortC] = HIDE;       // hide the Setup menu for C
      HidePEXPMenu[PXPOffset + Iio_PortD] = HIDE;       // hide the Setup menu for D
      break;
    default:
      PXPHide[PXPOffset + Iio_PortA] = NOT_HIDE;        // show A
      PXPHide[PXPOffset + Iio_PortB] = NOT_HIDE;        // show B
      PXPHide[PXPOffset + Iio_PortC] = NOT_HIDE;        // show C
      PXPHide[PXPOffset + Iio_PortD] = NOT_HIDE;        // show port D
      HidePEXPMenu[PXPOffset + Iio_PortA] = NOT_HIDE;   // show the Setup menu for A
      HidePEXPMenu[PXPOffset + Iio_PortB] = NOT_HIDE;   // show the Setup menu for B
      HidePEXPMenu[PXPOffset + Iio_PortC] = NOT_HIDE;   // show the Setup menu for C
      HidePEXPMenu[PXPOffset + Iio_PortD] = NOT_HIDE;   // show the Setup menu for D
     break;
  }
  //
  // Change PEXPHIDE setting to hide all PCIe port of a IOU if IIO_BIFURCATE_xxxxxxxx is set.
  // And set ConfigIOU/ConfigMCPx to default bifucation control value
  // Bifurcation_Control[2:0] in IOU Bifurcation Control (PCIE_IOU_BIF_CTRL) register should be 000b ~ 100b.
  //
  if (CurrentIOUConfigValue == IIO_BIFURCATE_xxxxxxxx) {

    IioGlobalData->SetupData.ConfigIOU[IioIndex][Iou] = IIO_BIFURCATE_x4x4x4x4;
  }
}

VOID
DumpPort_SKX(
    IIO_GLOBALS *IioGlobalData,
    UINT8        Port,
    UINT8        NumberOfPorts
)
{
  UINT8 Index;
  DEBUG((EFI_D_INFO, "IDX, Port Hide, Slot Impl, Slot Number, HotPlug, PcieSSD, VppPort, VppAddress, Interlock\n"));
  for (Index = Port; Index < (Port + NumberOfPorts); Index++ ) {
  DEBUG((EFI_D_INFO, "%3d|   %2d    |    %2d    |   %3d      |   %3d  |  %3d  |  0x%02x  |  0x%02x     |  %2d      \n", \
                       Index, \
                       IioGlobalData->SetupData.PEXPHIDE[Index],  \
                       IioGlobalData->SetupData.SLOTIMP[Index],   \
                       IioGlobalData->SetupData.SLOTPSP[Index],   \
                       IioGlobalData->SetupData.SLOTHPCAP[Index], \
                       IioGlobalData->IioVar.IioOutData.PciePortOwnership[Index],   \
                       IioGlobalData->SetupData.VppPort[Index],   \
                       IioGlobalData->SetupData.VppAddress[Index],\
                       IioGlobalData->SetupData.SLOTEIP[Index]));
  }
}


/// Dump iio configuration. Dump the current IIO configuration to the serial
/// log.
VOID
DumpIioConfiguration_SKX(
    IN UINT8 iio,
    IN IIO_GLOBALS *IioGlobalData
)
{
  UINT8 Iou;
  UINT8 PortIndex;
  UINT8 MaxPortNumberPerSocket;
  UINT8 Bifurcation;
  UINT8 IouPorts;

  MaxPortNumberPerSocket = IioGlobalData->IioVar.IioOutData.MaxPciePortNumberPerSocket[iio];
  PortIndex = iio * MaxPortNumberPerSocket;
  /// First dump the socket number;
  DEBUG((EFI_D_INFO, "Socket number: %d \n", iio));

  /// Dump DMI configuration:
  if ((iio == 0) && (PortIndex == 0)){
      DEBUG((EFI_D_INFO, "PORT 0: DMI Port\n"));
  } else {
      DEBUG((EFI_D_INFO, "PORT 0: DMI Port working as PCIE\n"));
      DumpPort_SKX(IioGlobalData, PortIndex, 1);
  }
  IouPorts=4;
  /// Dump IOU bifurcations:
  for (Iou = Iio_Iou0; Iou< Iio_IouMax; Iou ++) {
      /// Reset port index.
      PortIndex = iio * MaxPortNumberPerSocket;
      // Get the bifurcation
      switch (Iou) {
        case Iio_Iou0:
          Bifurcation = IioGlobalData->SetupData.ConfigIOU[iio][0];
          PortIndex += PORT_1A_INDEX;
          DEBUG((EFI_D_INFO, "IUO0: Root Port 1, Bifurcation: %d\n", Bifurcation));
          break;
        case Iio_Iou1:
          Bifurcation = IioGlobalData->SetupData.ConfigIOU[iio][1];
          PortIndex += PORT_2A_INDEX;
          DEBUG((EFI_D_INFO, "IUO1: Root Port 2, Bifurcation: %d\n", Bifurcation));
          break;
        case Iio_Iou2:
          Bifurcation = IioGlobalData->SetupData.ConfigIOU[iio][2];
          PortIndex += PORT_3A_INDEX;
          DEBUG((EFI_D_INFO, "IUO2: Root Port 3, Bifurcation: %d\n", Bifurcation));
          break;
        case Iio_Iou3:
          Bifurcation = IioGlobalData->SetupData.ConfigIOU[iio][3];
          PortIndex += PORT_4A_INDEX;
          DEBUG((EFI_D_INFO, "IOU3, Bifurcation: %d\n", Bifurcation));
          break;
        case Iio_Iou4:
          Bifurcation = IioGlobalData->SetupData.ConfigIOU[iio][4];
          PortIndex += PORT_5A_INDEX;
          DEBUG((EFI_D_INFO, "IOU4, Bifurcation: %d\n", Bifurcation));
          break;
        default:
          DEBUG((EFI_D_INFO, "Iou no detected = %d",Iou));
          break;
        }
      DumpPort_SKX(IioGlobalData, PortIndex, IouPorts);
  }
}


VOID
SystemHideIioPortsCommon_SKX(
    IIO_GLOBALS *IioGlobalData,
    UINT8       IioIndex
  )
{
    CalculatePEXPHideFromIouBif_SKX(Iio_Iou0, IioIndex, IioGlobalData);
    CalculatePEXPHideFromIouBif_SKX(Iio_Iou1, IioIndex, IioGlobalData);
    CalculatePEXPHideFromIouBif_SKX(Iio_Iou2, IioIndex, IioGlobalData);
    CalculatePEXPHideFromIouBif_SKX(Iio_Iou3, IioIndex, IioGlobalData);
    CalculatePEXPHideFromIouBif_SKX(Iio_Iou4, IioIndex, IioGlobalData);
    DumpIioConfiguration_SKX(IioIndex, IioGlobalData);
}

/**
    Verify if and Slot should be implemented based on IOUX bifurcation settings.

    @param IioGlobalData           Pointer to Iio Globals.
    @param Port                  - Port Index

    @retval TRUE/FALSE         to determine if an slot should be implemented or not
                               based on the IOUX bifurcation settings in case user want to do an
                               override and VMD is enabled.

**/
BOOLEAN
SlotImplemented_SKX (
    IN OUT IIO_GLOBALS        *IioGlobalData,
    IN UINT8                  Port
  )
{
  UINT8 IioIndex;
  UINT8 MaxPortNumberPerSocket;
  UINT8 PortIndex;
  UINT8 Stack;
  BOOLEAN  SlotImp = FALSE;

  MaxPortNumberPerSocket = IioGlobalData->IioVar.IioOutData.MaxPciePortNumberPerSocket[0];
  IioIndex = Port/MaxPortNumberPerSocket;
  PortIndex = (Port - (MaxPortNumberPerSocket * IioIndex));
  Stack = IioGlobalData->IioVar.IioVData.StackPerPort[IioIndex][PortIndex];
  DEBUG ((DEBUG_INFO, "SlotImplemented_SKX:IioIndex = %x, Stack = %x, Port = %x, PortIndex =%x\n", IioIndex, Stack, Port, PortIndex));

  switch (Stack) {
    case IIO_PSTACK0:
      if (IioGlobalData->SetupData.ConfigIOU[IioIndex][0] == IIO_BIFURCATE_x4x4x4x4) {
         SlotImp = TRUE;
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][0] == IIO_BIFURCATE_x4x4xxx8){
        if ((PortIndex == PORT_1D_INDEX) || (PortIndex == PORT_1C_INDEX) || (PortIndex == PORT_1A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][0] == IIO_BIFURCATE_xxx8x4x4) {
        if ((PortIndex == PORT_1C_INDEX) || (PortIndex == PORT_1B_INDEX) || (PortIndex == PORT_1A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][0] == IIO_BIFURCATE_xxx8xxx8) {
        if ((PortIndex == PORT_1C_INDEX) || (PortIndex == PORT_1A_INDEX)){
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][0] == IIO_BIFURCATE_xxxxxx16) {
        if (PortIndex == PORT_1A_INDEX) {
          SlotImp = TRUE;
        }
      }
      break;
    case IIO_PSTACK1:
      if (IioGlobalData->SetupData.ConfigIOU[IioIndex][1] == IIO_BIFURCATE_x4x4x4x4) {
         SlotImp = TRUE;
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][1] == IIO_BIFURCATE_x4x4xxx8) {
        if ((PortIndex == PORT_2D_INDEX) || (PortIndex == PORT_2C_INDEX) || (PortIndex == PORT_2A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][1] == IIO_BIFURCATE_xxx8x4x4){
        if ((PortIndex == PORT_2C_INDEX) || (PortIndex == PORT_2B_INDEX) || (PortIndex == PORT_2A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][1] == IIO_BIFURCATE_xxx8xxx8) {
        if ((PortIndex == PORT_2C_INDEX) || (PortIndex == PORT_2A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][1] == IIO_BIFURCATE_xxxxxx16) {
        if (PortIndex == PORT_2A_INDEX) {
          SlotImp = TRUE;
        }
      }
      break;
    case IIO_PSTACK2:
      if (IioGlobalData->SetupData.ConfigIOU[IioIndex][2] == IIO_BIFURCATE_x4x4x4x4){
         SlotImp = TRUE;
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][2] == IIO_BIFURCATE_x4x4xxx8) {
        if ((PortIndex == PORT_3D_INDEX) || (PortIndex == PORT_3C_INDEX) || (PortIndex == PORT_3A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][2] == IIO_BIFURCATE_xxx8x4x4) {
        if ((PortIndex == PORT_3C_INDEX) || (PortIndex == PORT_3B_INDEX) || (PortIndex == PORT_3A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][2] == IIO_BIFURCATE_xxx8xxx8) {
        if ((PortIndex == PORT_3C_INDEX) || (PortIndex == PORT_3A_INDEX)){
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][2] == IIO_BIFURCATE_xxxxxx16) {
        if (PortIndex == PORT_3A_INDEX) {
          SlotImp = TRUE;
        }
      }
      break;
    case IIO_PSTACK3:
      if (IioGlobalData->SetupData.ConfigIOU[IioIndex][3] == IIO_BIFURCATE_x4x4x4x4){
         SlotImp = TRUE;
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][3] == IIO_BIFURCATE_x4x4xxx8) {
        if ((PortIndex == PORT_4D_INDEX) || (PortIndex == PORT_4C_INDEX) || (PortIndex == PORT_4A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][3] == IIO_BIFURCATE_xxx8x4x4) {
        if ((PortIndex == PORT_4C_INDEX) || (PortIndex == PORT_4B_INDEX) || (PortIndex == PORT_4A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][3] == IIO_BIFURCATE_xxx8xxx8) {
        if ((PortIndex == PORT_4C_INDEX) || (PortIndex == PORT_4A_INDEX)){
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][3] == IIO_BIFURCATE_xxxxxx16) {
        if (PortIndex == PORT_4A_INDEX) {
          SlotImp = TRUE;
        }
      }
      break;
    case IIO_PSTACK4:
      if (IioGlobalData->SetupData.ConfigIOU[IioIndex][4] == IIO_BIFURCATE_x4x4x4x4){
         SlotImp = TRUE;
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][4] == IIO_BIFURCATE_x4x4xxx8) {
        if ((PortIndex == PORT_5D_INDEX) || (PortIndex == PORT_5C_INDEX) || (PortIndex == PORT_5A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][4] == IIO_BIFURCATE_xxx8x4x4) {
        if ((PortIndex == PORT_5C_INDEX) || (PortIndex == PORT_5B_INDEX) || (PortIndex == PORT_5A_INDEX)) {
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][4] == IIO_BIFURCATE_xxx8xxx8) {
        if ((PortIndex == PORT_5C_INDEX) || (PortIndex == PORT_5A_INDEX)){
          SlotImp = TRUE;
        }
      } else if (IioGlobalData->SetupData.ConfigIOU[IioIndex][4] == IIO_BIFURCATE_xxxxxx16) {
        if (PortIndex == PORT_5A_INDEX) {
          SlotImp = TRUE;
        }
      }
      break;
    default:
      DEBUG ((EFI_D_INFO, "default case.\n"));  //Auto added. Please review.
      break;
  }
  DEBUG ((DEBUG_INFO, "SlotImplemented_SKX:  = %x\n", SlotImp));
  return SlotImp;
}


VOID
ConfigSlots_SKX (
    IN OUT IIO_GLOBALS        *IioGlobalData,
    IN IIO_SLOT_CONFIG_DATA_ENTRY  *Slot,
    IN UINT8                  SlotEntries
  )
{
  UINT8 Index;
  UINT8 Port;

  for (Index =0; Index < SlotEntries; Index ++) {
    Port=Slot[Index].PortIndex;
    if (Slot[Index].Hidden != NOT_HIDE) {
      IioGlobalData->SetupData.HidePEXPMenu[Port] = HIDE;
      IioGlobalData->SetupData.PEXPHIDE[Port]= HIDE;
    }
    /// Check if slot is assigned.
    if (Slot[Index].SlotNumber!= NO_SLT_IMP){
       IioGlobalData->SetupData.SLOTIMP[Port]= SLT_IMP;
       IioGlobalData->SetupData.SLOTPSP[Port]=Slot[Index].SlotNumber;
       IioGlobalData->SetupData.SLOTEIP[Port]=Slot[Index].InterLockPresent;
       if (Slot[Index].SlotPowerLimitScale!= PWR_SCL_MAX) {
         IioGlobalData->SetupData.SLOTSPLS[Port] = Slot[Index].SlotPowerLimitScale;
         IioGlobalData->SetupData.SLOTSPLV[Port] = Slot[Index].SlotPowerLimitValue;
       }
       if (Slot[Index].HotPlugCapable != DISABLE) {
         EnableHotPlug_SKX(IioGlobalData, Port, Slot[Index].VppPort, Slot[Index].VppAddress, REGULAR_PCIE_OWNERSHIP);
       }
    }
  }
}


EFI_STATUS
PlatformUpdateIioConfig (
  IN  IIO_GLOBALS             *IioGlobalData
)
{
  EFI_STATUS                        Status;
  UBA_CONFIG_DATABASE_PPI           *UbaConfigPpi = NULL;
  PLATFORM_IIO_CONFIG_UPDATE_TABLE  IioConfigTable;
  UINTN                             TableSize;

  Status = PeiServicesLocatePpi (
    &gUbaConfigDatabasePpiGuid,
    0,
    NULL,
    (VOID **) &UbaConfigPpi
    );
  if (EFI_ERROR (Status)) {
    ASSERT_EFI_ERROR (Status);
    return Status;
  }

  TableSize = sizeof(IioConfigTable);
  Status = UbaConfigPpi->GetData (
    UbaConfigPpi,
    &gPlatformIioConfigDataGuid,
    &IioConfigTable,
    &TableSize
    );

  if (EFI_ERROR(Status)) {
    return Status;
  }

  ASSERT (IioConfigTable.Signature == PLATFORM_IIO_CONFIG_UPDATE_SIGNATURE);
  ASSERT (IioConfigTable.Version == PLATFORM_IIO_CONFIG_UPDATE_VERSION);

  Status = IioConfigTable.CallUpdate (IioGlobalData);
  if (EFI_ERROR(Status)) {
    return Status;
  }

  return Status;
}

VOID
OverrideDefaultBifSlots_SKX (
    IN IIO_GLOBALS *IioGlobalData,
    IN UINT8       BoardId,
    IN BOOLEAN     *AutoBifEnable
)
{
  EFI_STATUS                      Status;
  UINT32                          QATGpio;
  PCIE_RISER_ID                   RightRiser;
  PCIE_RISER_ID                   LeftRiser;
  UINT32                          RiserBit;
  UINT8                           Index;
  BW5_BIFURCATION_DATA_STRUCT     Bw5id[4]= {{{0,0,0,0,0}}, {{0,0,0,0,0,}}, {{0,0,0,0,0}}, {{0,0,0,0,0}}}; // Default, no BW card.
  IIO_BROADWAY_ADDRESS_ENTRY      *BroadwayTable;
  IIO_BROADWAY_ADDRESS_DATA_ENTRY *BroadwayTableTemp;
  UINT8                           IOU0Setting;
  UINT8                           IOU2Setting;
  UINT8                           FlagValue = 0;
  UINT8                           SkuPersonality = 0;
  DYNAMIC_SI_LIBARY_PPI           *DynamicSiLibraryPpi = NULL;

  BroadwayTable = NULL;
  IOU0Setting = IioGlobalData->SetupData.ConfigIOU[Iio_Socket0][0];
  IOU2Setting = IioGlobalData->SetupData.ConfigIOU[Iio_Socket0][2];

  //
  // Specific platform overrides.
  //
  // Changes because GPIO (QAT, Riser Cards, etc).
  // Read QAT and riser card GPIOs.
  //
  // Purley platforms need to read the QAT bit
  //
  Status = PeiServicesLocatePpi (&gDynamicSiLibraryPpiGuid, 0, NULL, (VOID **) &DynamicSiLibraryPpi);
  if (EFI_ERROR (Status)) {
    ASSERT_EFI_ERROR (Status);
    return;
  }

  Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_B3, &QATGpio);
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_INFO, "Get GPIO_SKL_H_GPP_B3 Failed\n"));
    return;
  }
  DEBUG ((EFI_D_INFO, "QAT GPIO: %d\n", QATGpio));

  if ((IioGlobalData->IioVar.IioVData.SkuPersonality[0] == TYPE_FPGA) &&\
      (IioGlobalData->IioVar.IioVData.SkuPersonality[1] == TYPE_FPGA)) {
    SkuPersonality = 1;
  } else if ((IioGlobalData->IioVar.IioVData.SkuPersonality[0] == TYPE_FPGA) &&\
      (IioGlobalData->IioVar.IioVData.SkuPersonality[1] != TYPE_FPGA)) {
    SkuPersonality = 2;
  } else if ((IioGlobalData->IioVar.IioVData.SkuPersonality[0] != TYPE_FPGA) &&\
      (IioGlobalData->IioVar.IioVData.SkuPersonality[1] == TYPE_FPGA)) {
    SkuPersonality = 3;
  } else {
    SkuPersonality = 0;
  }
  DEBUG((DEBUG_INFO, "SKU Personality Type: %d\n", SkuPersonality));

  BroadwayTableTemp = (IIO_BROADWAY_ADDRESS_DATA_ENTRY *) BroadwayTable;
  InternalPlatformGetSlotTableData2 (&BroadwayTableTemp, &IOU0Setting, &FlagValue, &IOU2Setting, SkuPersonality);
  BroadwayTable    = (IIO_BROADWAY_ADDRESS_ENTRY *)BroadwayTableTemp; // if no platform definition, BroadwayTable will be NULL

  if (AutoBifEnable[(Iio_Socket0 * Iio_IouMax) + Iio_Iou2] == TRUE) {
    IioGlobalData->SetupData.ConfigIOU[Iio_Socket0][2] = IOU2Setting;
  }

  if (FlagValue == 1) {
    //
    // Right riser
    //
    Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_B4, &RiserBit);  // PresentSignal
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_INFO, "Get GPIO_SKL_H_GPP_B4 Failed\n"));
      return;
    }
    RightRiser.Bits.PresentSignal = (UINT8) RiserBit;

    Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_C15, &RiserBit);  // HotPlugConf
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_INFO, "Get GPIO_SKL_H_GPP_C15 Failed\n"));
      return;
    }
    RightRiser.Bits.HPConf = (UINT8) RiserBit;

    Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_C16, &RiserBit);  // WingConf
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_INFO, "Get GPIO_SKL_H_GPP_C16 Failed\n"));
      return;
    }
    RightRiser.Bits.WingConf = (UINT8) RiserBit;

    Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_C17, &RiserBit);  // Slot9En
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_INFO, "Get GPIO_SKL_H_GPP_C17 Failed\n"));
      return;
    }
    RightRiser.Bits.Slot9En = (UINT8) RiserBit;

    DEBUG ((EFI_D_INFO, "GPIO Right riser information: PresentSignal=%x, HotPlugConf=%x, WingConf=%x, Slot9En=%x\n",
            RightRiser.Bits.PresentSignal, RightRiser.Bits.HPConf, RightRiser.Bits.WingConf, RightRiser.Bits.Slot9En));

    //
    // Left riser
    //
    Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_B5, &RiserBit);  // PresentSignal
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_INFO, "Get GPIO_SKL_H_GPP_B5 Failed\n"));
      return;
    }
    LeftRiser.Bits.PresentSignal = (UINT8) RiserBit;

    Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_C18, &RiserBit);  // HotPlugConf
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_INFO, "Get GPIO_SKL_H_GPP_C18 Failed\n"));
      return;
    }
    LeftRiser.Bits.HPConf = (UINT8) RiserBit;

    Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_C19, &RiserBit);  // WingConf
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_INFO, "Get GPIO_SKL_H_GPP_C19 Failed\n"));
      return;
    }
    LeftRiser.Bits.WingConf = (UINT8) RiserBit;

    Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_B21, &RiserBit);  // Slot9En
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_INFO, "Get GPIO_SKL_H_GPP_B21 Failed\n"));
      return;
    }
    LeftRiser.Bits.Slot9En = (UINT8) RiserBit;

    DEBUG ((EFI_D_INFO, "GPIO Left riser information: PresentSignal=%x, HotPlugConf=%x, WingConf=%x, Slot9En=%x\n",
            LeftRiser.Bits.PresentSignal, LeftRiser.Bits.HPConf, LeftRiser.Bits.WingConf, LeftRiser.Bits.Slot9En));
  }

  if (QATGpio == QAT_ENABLED) {
    // So Configuration of IUO0 is:
    //  1A-1B - QAT xxx8
    //  1C    - SSD x4
    //  1D    - SSD x4
    if (AutoBifEnable[(Iio_Socket0 * Iio_IouMax) + Iio_Iou0] == TRUE) {
      IioGlobalData->SetupData.ConfigIOU[Iio_Socket0][0] = IOU0Setting;
    }
  }

  if (FlagValue == 1) {
    if (QATGpio != QAT_ENABLED) {
      if ((RightRiser.Bits.Slot9En == RISER_SLOT9_DISABLE) &&
          (LeftRiser.Bits.Slot9En == RISER_SLOT9_DISABLE)) {
        //
        // SLOT 9 is disabled. SSDs are present.
        // Change configuration to x4x4x4x4.
        //
        if (AutoBifEnable[(Iio_Socket0 * Iio_IouMax) + Iio_Iou0] == TRUE) {
          IioGlobalData->SetupData.ConfigIOU[Iio_Socket0][0]  = IIO_BIFURCATE_x4x4x4x4;
          IioGlobalData->IioVar.IioOutData.PciePortOwnership[SOCKET_0_INDEX + PORT_1A_INDEX] = PCIEAIC_OCL_OWNERSHIP;
          IioGlobalData->IioVar.IioOutData.PciePortOwnership[SOCKET_0_INDEX + PORT_1B_INDEX] = PCIEAIC_OCL_OWNERSHIP;
          IioGlobalData->IioVar.IioOutData.PciePortOwnership[SOCKET_0_INDEX + PORT_1C_INDEX] = PCIEAIC_OCL_OWNERSHIP;
          IioGlobalData->IioVar.IioOutData.PciePortOwnership[SOCKET_0_INDEX + PORT_1D_INDEX] = PCIEAIC_OCL_OWNERSHIP;
        }
      } else if (RightRiser.Bits.PresentSignal == RISER_PRESENT) {
        //
        // Slot 9 is enabled. Keep the xxxxxx16 configuration (default) and
        // enable slot 9. Slot 9 supports HP.
        //
        IioGlobalData->SetupData.SLOTIMP[SOCKET_0_INDEX + PORT_1A_INDEX] = 1;
        IioGlobalData->SetupData.SLOTPSP[SOCKET_0_INDEX + PORT_1A_INDEX] = 9;
      } // End of RISER_PRESENT
    } // End of QAT_ENABLED

    if (RightRiser.Bits.PresentSignal == RISER_PRESENT) {
      IioGlobalData->SetupData.SLOTIMP[SOCKET_0_INDEX + PORT_3A_INDEX] = 1;
#if MAX_SOCKET > 2
      IioGlobalData->SetupData.SLOTIMP[SOCKET_3_INDEX + PORT_2A_INDEX] = 1;
      IioGlobalData->SetupData.SLOTIMP[SOCKET_3_INDEX + PORT_3A_INDEX] = 1;
#endif // MAX_SOCKET > 2
      if (RightRiser.Bits.WingConf == RISER_WINGED_IN) {
        IioGlobalData->SetupData.SLOTPSP[SOCKET_0_INDEX + PORT_3A_INDEX] = 1;
#if MAX_SOCKET > 2
        IioGlobalData->SetupData.SLOTPSP[SOCKET_3_INDEX + PORT_2A_INDEX] = 4;
        IioGlobalData->SetupData.SLOTPSP[SOCKET_3_INDEX + PORT_3A_INDEX] = 2;
#endif // MAX_SOCKET > 2
      } else {  // RISER_WINGED_OUT
        IioGlobalData->SetupData.SLOTPSP[SOCKET_0_INDEX + PORT_3A_INDEX] = 2;
#if MAX_SOCKET > 2
        IioGlobalData->SetupData.SLOTPSP[SOCKET_3_INDEX + PORT_2A_INDEX] = 3;
        IioGlobalData->SetupData.SLOTPSP[SOCKET_3_INDEX + PORT_3A_INDEX] = 1;
#endif // MAX_SOCKET > 2
        if (RightRiser.Bits.HPConf == RISER_HP_EN) {
          //
          // PCIe Hot Plug is supported on Winged-out riser only
          //
          EnableHotPlug_SKX(IioGlobalData, SOCKET_0_INDEX + PORT_3A_INDEX, VPP_PORT_0, 0x40, REGULAR_PCIE_OWNERSHIP);
#if MAX_SOCKET > 2
          EnableHotPlug_SKX(IioGlobalData, SOCKET_3_INDEX + PORT_2A_INDEX, VPP_PORT_1, 0x40, REGULAR_PCIE_OWNERSHIP);
          EnableHotPlug_SKX(IioGlobalData, SOCKET_3_INDEX + PORT_3A_INDEX, VPP_PORT_0, 0x40, REGULAR_PCIE_OWNERSHIP);
#endif // MAX_SOCKET > 2
        } // End of RISER_HP_EN
      } // End of RISER_WINGED_IN
    } // End of RISER_PRESENT

    if (LeftRiser.Bits.PresentSignal == RISER_PRESENT) {
      IioGlobalData->SetupData.SLOTIMP[SOCKET_1_INDEX + PORT_1A_INDEX] = 1;
      IioGlobalData->SetupData.SLOTIMP[SOCKET_1_INDEX + PORT_2A_INDEX] = 1;
      IioGlobalData->SetupData.SLOTIMP[SOCKET_2_INDEX + PORT_1A_INDEX] = 1;
      IioGlobalData->SetupData.SLOTIMP[SOCKET_2_INDEX + PORT_3A_INDEX] = 1;
      if (LeftRiser.Bits.WingConf == RISER_WINGED_IN) {
        IioGlobalData->SetupData.SLOTPSP[SOCKET_1_INDEX + PORT_1A_INDEX] = 7;
        IioGlobalData->SetupData.SLOTPSP[SOCKET_1_INDEX + PORT_2A_INDEX] = 5;
        IioGlobalData->SetupData.SLOTPSP[SOCKET_2_INDEX + PORT_1A_INDEX] = 6;
        IioGlobalData->SetupData.SLOTPSP[SOCKET_2_INDEX + PORT_3A_INDEX] = 8;
      } else {  // RISER_WINGED_OUT
        IioGlobalData->SetupData.SLOTPSP[SOCKET_1_INDEX + PORT_1A_INDEX] = 5;
        IioGlobalData->SetupData.SLOTPSP[SOCKET_1_INDEX + PORT_2A_INDEX] = 7;
        IioGlobalData->SetupData.SLOTPSP[SOCKET_2_INDEX + PORT_1A_INDEX] = 8;
        IioGlobalData->SetupData.SLOTPSP[SOCKET_2_INDEX + PORT_3A_INDEX] = 6;
        if (LeftRiser.Bits.HPConf == RISER_HP_EN) {
          //
          // PCIe Hot Plug is supported on Winged-out riser only
          //
          EnableHotPlug_SKX(IioGlobalData, SOCKET_1_INDEX + PORT_1A_INDEX, VPP_PORT_0, 0x42, REGULAR_PCIE_OWNERSHIP);
          EnableHotPlug_SKX(IioGlobalData, SOCKET_1_INDEX + PORT_2A_INDEX, VPP_PORT_1, 0x42, REGULAR_PCIE_OWNERSHIP);
          EnableHotPlug_SKX(IioGlobalData, SOCKET_2_INDEX + PORT_1A_INDEX, VPP_PORT_1, 0x42, REGULAR_PCIE_OWNERSHIP);
          EnableHotPlug_SKX(IioGlobalData, SOCKET_2_INDEX + PORT_3A_INDEX, VPP_PORT_0, 0x42, REGULAR_PCIE_OWNERSHIP);
        } // End of RISER_HP_EN
      } // End of RISER_WINGED_IN
    } // End of RISER_PRESENT
  } // End of FlagValue == 1

  /// Broadway overrides.
  if (BroadwayTable != NULL) {
    GetBw5Id (IioGlobalData, Bw5id);
    DEBUG ((EFI_D_INFO,"Broadway Config: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", Bw5id[Bw5_Addr_0].Data, Bw5id[Bw5_Addr_1].Data, Bw5id[Bw5_Addr_2].Data, Bw5id[Bw5_Addr_3].Data));
    for (Index = 0; Index < 3; Index ++) {
      //
      // Check if BW5 is present before override IOUx Bifurcation
      //
      if (BroadwayTable->BroadwayAddress == Bw5_Addr_Max) {
        break;
      }
      if (Bw5id[BroadwayTable->BroadwayAddress].Bits.BifBits != BW5_CARD_NOT_PRESENT){
        if (AutoBifEnable[(BroadwayTable->Socket * Iio_IouMax) + BroadwayTable->IouNumber] == TRUE) {
          switch (BroadwayTable->IouNumber) {
            case Iio_Iou0:
              IioGlobalData->SetupData.ConfigIOU[BroadwayTable->Socket][0] = Bw5id[BroadwayTable->BroadwayAddress].Bits.BifBits;
              DEBUG ((DEBUG_ERROR,"IioGlobalData->SetupData.ConfigIOU[%x][0] = %x\n",BroadwayTable->Socket, IioGlobalData->SetupData.ConfigIOU[BroadwayTable->Socket][0]));
              break;
            case Iio_Iou1:
              IioGlobalData->SetupData.ConfigIOU[BroadwayTable->Socket][1] = Bw5id[BroadwayTable->BroadwayAddress].Bits.BifBits;
              DEBUG ((DEBUG_ERROR,"IioGlobalData->SetupData.ConfigIOU[%x][1] = %x\n",BroadwayTable->Socket, IioGlobalData->SetupData.ConfigIOU[BroadwayTable->Socket][1]));
              break;
            case Iio_Iou2:
              IioGlobalData->SetupData.ConfigIOU[BroadwayTable->Socket][2] = Bw5id[BroadwayTable->BroadwayAddress].Bits.BifBits;
              DEBUG ((DEBUG_ERROR,"IioGlobalData->SetupData.ConfigIOU[%x][2] = %x\n",BroadwayTable->Socket,IioGlobalData->SetupData.ConfigIOU[BroadwayTable->Socket][2]));
              break;
            default:
             break;
          } // BroadwayTable->IouNumber
        } // AutoBifEnable == TRUE
     } // No BW5 present
      BroadwayTable ++;
    } // for Index
  } // BroadwayTable != NULL

  if (DynamicSiLibraryPpi->IsCpuAndRevision (CPU_SKX, REV_ALL) ||
      DynamicSiLibraryPpi->IsCpuAndRevision (CPU_CLX, REV_ALL) ||
      DynamicSiLibraryPpi->IsCpuAndRevision (CPU_CPX, REV_ALL)
      ) {
    PlatformUpdateIioConfig (IioGlobalData);
  }
}


/**
    Verify if VMD is enabled and override Slot configuration
    based on the VMD settings

    @param IioGlobalData           Pointer to Iio Globals.
    @param Slot                  - Slot configuration settings
    @param SlotEntries           - Number of slot entries

    @retval None

**/
VOID
OverrideConfigSlots_SKX (
    IN OUT IIO_GLOBALS        *IioGlobalData,
    IN IIO_SLOT_CONFIG_DATA_ENTRY  *Slot,
    IN UINT8                  SlotEntries
  )
{
  UINT8 Index;
  UINT8 Port;
  UINT8 MaxPortNumberPerSocket;
  UINT8 IioIndex;
  UINT8 Stack;
  UINT8 PortIndex;

  MaxPortNumberPerSocket = IioGlobalData->IioVar.IioOutData.MaxPciePortNumberPerSocket[0];
  for (Index =0; Index < SlotEntries; Index ++) {
    Port = Slot[Index].PortIndex;
    //
    // Check if Slot is capable of PcieSSD Solution and override the SLOT Config values
    //
    if (Slot[Index].PcieSSDCapable) {
      IioIndex = Port/MaxPortNumberPerSocket;
      PortIndex = (Port - (MaxPortNumberPerSocket * IioIndex));
      Stack = IioGlobalData->IioVar.IioVData.StackPerPort[IioIndex][PortIndex];
      DEBUG ((DEBUG_INFO, "Stack = %x, Port = %x, PortIndex = %x\n", Stack, Port, PortIndex));

      //
      // check if VMD will own Pcie Root Port
      //
      if (IioGlobalData->SetupData.VMDEnabled[IioIndex][Stack]) {
        if (IioGlobalData->SetupData.VMDPortEnable[IioIndex][PortIndex]) {
          IioGlobalData->IioVar.IioOutData.PciePortOwnership[Port] = VMD_OWNERSHIP;
        }
      } else {

        DEBUG ((DEBUG_INFO, "IioGlobalData->SetupData.PcieAICEnabled[%x] = %x\n", Stack, IioGlobalData->SetupData.PcieAICEnabled[(IioIndex * MAX_STACKS_PER_SOCKET) + Stack]));
        //
        // Check if Pcie AIC Card will be present on Pcie Root Port
        //
        if (IioGlobalData->SetupData.PcieAICEnabled[(IioIndex * MAX_STACKS_PER_SOCKET) + Stack]) {
          //
          // Force to have this port enabled by default for hot-plug.
          //
          IioGlobalData->SetupData.IioPcieConfig.PciePortEnable[(IioIndex * MaxPortNumberPerSocket) + Port] = ENABLE;
          IioGlobalData->IioVar.IioOutData.PciePortOwnership[Port] = PCIEAIC_OCL_OWNERSHIP;
          DEBUG ((DEBUG_ERROR, "Port = %x, PciePortEnable = %x\n", Port, IioGlobalData->SetupData.IioPcieConfig.PciePortEnable[(IioIndex * MaxPortNumberPerSocket) + Port]));
        }
      } // No _VMD Ownership

      DEBUG ((DEBUG_INFO, "PciePortOwnerShip[%x] = %x\n",Port, IioGlobalData->IioVar.IioOutData.PciePortOwnership[Port]));

      // if PcieSSDSupport required do slot override settings accordingly
      if ((IioGlobalData->IioVar.IioOutData.PciePortOwnership[Port] != REGULAR_PCIE_OWNERSHIP) &&
          (SlotImplemented_SKX(IioGlobalData, Port) == TRUE)) {
        IioGlobalData->SetupData.SLOTIMP[Port] = SLT_IMP;
        IioGlobalData->SetupData.SLOTPSP[Port] = 0x50  + Port; // Just program a value for PCIEACI_OCL/VMD
        IioGlobalData->SetupData.SLOTEIP[Port] = DISABLE;

        if (Slot[Index].SlotPowerLimitScale != PWR_SCL_MAX) {
          IioGlobalData->SetupData.SLOTSPLS[Port] = Slot[Index].SlotPowerLimitScale;
          IioGlobalData->SetupData.SLOTSPLV[Port] = Slot[Index].SlotPowerLimitValue;
        }
        DEBUG ((DEBUG_INFO,"Slot[Index].PcieSSDVppPort = %x\n", Slot[Index].PcieSSDVppPort));
        // Enable hot-plug if slot/port supports it
        if (Slot[Index].PcieSSDVppPort != VPP_PORT_MAX) {
        DEBUG ((DEBUG_INFO, "IioGlobalData->SetupData.VMDHotPlugEnable[%d][%x] = %x\n", IioIndex, Stack, IioGlobalData->SetupData.VMDHotPlugEnable[IioIndex][Stack]));
        DEBUG ((DEBUG_INFO, "IioGlobalData->SetupData.PcieAICHotPlugEnable[%x] = %x\n",Stack,IioGlobalData->SetupData.PcieAICHotPlugEnable[(IioIndex * MAX_STACKS_PER_SOCKET) + Stack]));
        // Check if hot-plug is enabled for VMD or PCIeAIC case.
          if (((IioGlobalData->IioVar.IioOutData.PciePortOwnership[Port] == VMD_OWNERSHIP) &&
               (IioGlobalData->SetupData.VMDHotPlugEnable[IioIndex][Stack])) ||
              ((IioGlobalData->IioVar.IioOutData.PciePortOwnership[Port] == PCIEAIC_OCL_OWNERSHIP) &&
               (IioGlobalData->SetupData.PcieAICHotPlugEnable[(IioIndex * MAX_STACKS_PER_SOCKET) + Stack]))) {
            EnableHotPlug_SKX(IioGlobalData, Port, Slot[Index].PcieSSDVppPort, Slot[Index].PcieSSDVppAddress, IioGlobalData->IioVar.IioOutData.PciePortOwnership[Port]);
            DEBUG((DEBUG_INFO,"Enable HotPlug Done\n"));
          }
        }
        //
        // Unhide the port in order to get configured and it will be hide later for VMDLateSetup if MD own the Pcie Root Port
        //
        IioGlobalData->SetupData.PEXPHIDE[Port] = NOT_HIDE;
      }// PcieSSDSupport
    }// PcieSSDCapable
  }// Per Slot
}

VOID
SetBifurcations_SKX(
    IN OUT IIO_GLOBALS *IioGlobalData,
    IN     IIO_BIFURCATION_DATA_ENTRY *BifurcationTable,
    IN     UINT8                  BifurcationEntries,
    IN     BOOLEAN                *AutoBifEnable
)
{
  UINT8 Socket;
  UINT8 Iou;
  UINT8 Index;

  for (Index = 0; Index < BifurcationEntries ; Index++) {
    Socket = BifurcationTable[Index].Socket;
    Iou = BifurcationTable[Index].IouNumber;

    if (AutoBifEnable[(Socket * Iio_IouMax) + Iou] == TRUE) {
      switch (Iou) {
        case Iio_Iou0:
          IioGlobalData->SetupData.ConfigIOU[Socket][0] = BifurcationTable[Index].Bifurcation;
          break;
        case Iio_Iou1:
          IioGlobalData->SetupData.ConfigIOU[Socket][1] = BifurcationTable[Index].Bifurcation;
          break;
        case Iio_Iou2:
          IioGlobalData->SetupData.ConfigIOU[Socket][2] = BifurcationTable[Index].Bifurcation;
          break;
        case Iio_Iou3:
          IioGlobalData->SetupData.ConfigIOU[Socket][3] = BifurcationTable[Index].Bifurcation;
          break;
        case Iio_Iou4:
          IioGlobalData->SetupData.ConfigIOU[Socket][4] = BifurcationTable[Index].Bifurcation;
          break;
        default:
          DEBUG ((EFI_D_ERROR, "Invalid bifurcation table: Bad Iou (%d)", Iou));
          ASSERT(Iou);
          break;
      }
    }
  }
}


/**

  SystemIioPortBifurcationInit - Program the UDS data structure with OEM IIO init values
  for SLOTs and Bifurcation.

  @param mSB - pointer to this protocol
  @param IioUds - Pointer to the IIO UDS datastructure.

  @retval EFI_SUCCESS

**/
VOID
SystemIioPortBifurcationInitCommon_SKX (
    UINT8 BoardId,
    IIO_GLOBALS *IioGlobalData,
    IIO_BIFURCATION_DATA_ENTRY    **BifurcationTable,
    UINT8                         *BifurcationEntries,
    IIO_SLOT_CONFIG_DATA_ENTRY    **SlotTable,
    UINT8                         *SlotEntries
)
{

  UINT8                         PortIndex;//, iio;
  IIO_BIFURCATION_DATA_ENTRY    **BifurcationTableTemp;
  IIO_SLOT_CONFIG_DATA_ENTRY    **SlotTableTemp;
  UINT8                         SkuPersonalityType = 0;
  UINT8                         MaxPortNumberPerSocket;

  /// This function outline:
  //// 1 Based on platform apply the default bifurcation and slot configuration.
  //// 2 Apply dynamic overrides based on GPIO and other configurations.
  //// 3 Hide unused ports due bifurcation.

  MaxPortNumberPerSocket = IioGlobalData->IioVar.IioOutData.MaxPciePortNumberPerSocket[0];
  for (PortIndex = 0; PortIndex < MAX_SOCKET*MaxPortNumberPerSocket; PortIndex++) {
    IioGlobalData->SetupData.PEXPHIDE[PortIndex] = 0;
    IioGlobalData->SetupData.HidePEXPMenu[PortIndex] = 0;
  }

  *BifurcationEntries = 0;
  *SlotEntries = 0;

  BifurcationTableTemp = (IIO_BIFURCATION_DATA_ENTRY **) BifurcationTable;
  SlotTableTemp        = (IIO_SLOT_CONFIG_DATA_ENTRY **) SlotTable;

  if ((IioGlobalData->IioVar.IioVData.SkuPersonality[0] == TYPE_FPGA) &&\
      (IioGlobalData->IioVar.IioVData.SkuPersonality[1] == TYPE_FPGA)) {
    SkuPersonalityType = 1;
  } else if ((IioGlobalData->IioVar.IioVData.SkuPersonality[0] == TYPE_FPGA) &&\
      (IioGlobalData->IioVar.IioVData.SkuPersonality[1] != TYPE_FPGA)) {
    SkuPersonalityType = 2;
  } else if ((IioGlobalData->IioVar.IioVData.SkuPersonality[0] != TYPE_FPGA) &&\
      (IioGlobalData->IioVar.IioVData.SkuPersonality[1] == TYPE_FPGA)) {
    SkuPersonalityType = 3;
  } else {
    SkuPersonalityType = 0;
  }

  InternalPlatformIioConfigInit2 (SkuPersonalityType, BifurcationTableTemp, BifurcationEntries, SlotTableTemp, SlotEntries);

  BifurcationTable = (IIO_BIFURCATION_DATA_ENTRY **) BifurcationTableTemp;
  SlotTable        = (IIO_SLOT_CONFIG_DATA_ENTRY **) SlotTableTemp;

}


/**
  This function prepare the data for silicon initialization based on
  bifuraction and slots table

  This function is for tables in version PLATFORM_IIO_CONFIG_UPDATE_VERSION = 1
 */
VOID
IioPortBifurcationInitVer1 (
  IN IIO_GLOBALS   *IioGlobalData
  )
{
  UINT8                         IioIndex;
  IIO_BIFURCATION_DATA_ENTRY    *BifurcationTable = NULL;
  UINT8                         BifurcationEntries;
  IIO_SLOT_CONFIG_DATA_ENTRY    *SlotTable = NULL;
  UINT8                         SlotEntries;
  BOOLEAN                       AutoBifEnable[MaxIIO * Iio_IouMax];
  UINT8                         BoardId;

  BoardId = SystemBoardIdValue();

  SetMem ((VOID *)AutoBifEnable, MaxIIO * Iio_IouMax, FALSE);

  for (IioIndex = Iio_Socket0; IioIndex < MaxIIO; IioIndex++) {
    if (IioGlobalData->SetupData.ConfigIOU[IioIndex][0] == IIO_BIFURCATE_AUTO) {
      AutoBifEnable[(IioIndex * Iio_IouMax) + Iio_Iou0] = TRUE;
    }

    if (IioGlobalData->SetupData.ConfigIOU[IioIndex][1] == IIO_BIFURCATE_AUTO) {
      AutoBifEnable[(IioIndex * Iio_IouMax) + Iio_Iou1] = TRUE;
    }

    if (IioGlobalData->SetupData.ConfigIOU[IioIndex][2] == IIO_BIFURCATE_AUTO) {
      AutoBifEnable[(IioIndex * Iio_IouMax) + Iio_Iou2] = TRUE;
    }

    if (IioGlobalData->SetupData.ConfigIOU[IioIndex][3] == IIO_BIFURCATE_AUTO) {
      AutoBifEnable[(IioIndex * Iio_IouMax) + Iio_Iou3] = TRUE;
    }

    if (IioGlobalData->SetupData.ConfigIOU[IioIndex][4] == IIO_BIFURCATE_AUTO) {
      AutoBifEnable[(IioIndex * Iio_IouMax) + Iio_Iou4] = TRUE;
    }
  }

  // This function outline:
  // 1. Based on platform apply the default bifurcation and slot configuration.
  // 2. Apply dynamic overrides based on GPIO and other configurations.
  // 3. Hide unused ports due bifurcation.

  // Set the default bifurcations for this platform.
  SystemIioPortBifurcationInitCommon_SKX (BoardId, IioGlobalData, &BifurcationTable, &BifurcationEntries, &SlotTable, &SlotEntries);
  SetBifurcations_SKX (IioGlobalData, BifurcationTable, BifurcationEntries, AutoBifEnable);
  ConfigSlots_SKX (IioGlobalData, SlotTable, SlotEntries);
  if (BoardId <= TypePlatformMax) {
    OverrideDefaultBifSlots_SKX (IioGlobalData, BoardId, AutoBifEnable);
  }
  OverrideConfigSlots_SKX (IioGlobalData, SlotTable, SlotEntries);


  // All overrides have been applied now.
  // Hide root ports whose lanes are assigned preceding ports.
  for (IioIndex = Iio_Socket0; IioIndex < MaxIIO; IioIndex++) {
    if (IioGlobalData->IioVar.IioVData.SocketPresent[IioIndex]) {
      SystemHideIioPortsCommon_SKX (IioGlobalData, IioIndex);
    }
  }
}
