From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../PcatSingleSegmentPciCfg2Pei/PciCfg2.c | 311 +++++++++++++++++++++ 1 file changed, 311 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c (limited to 'roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c') diff --git a/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c b/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c new file mode 100644 index 000000000..41fa92911 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c @@ -0,0 +1,311 @@ +/** @file + This driver installs Single Segment Pci Configuration 2 PPI + to provide read, write and modify access to Pci configuration space in PEI phase. + To follow PI specification, these services also support access to the unaligned Pci address. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Ppi/PciCfg2.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/PciLib.h> +#include <Library/PeimEntryPoint.h> +#include <Library/PeiServicesLib.h> +#include <IndustryStandard/Pci.h> + +/** + Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS. + + @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format. + + @return PCI address with PCI_LIB_ADDRESS format. + +**/ +UINTN +PciCfgAddressConvert ( + EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *Address + ) +{ + if (Address->ExtendedRegister == 0) { + return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->Register); + } + + return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->ExtendedRegister); +} + +/** + Reads from a given location in the PCI configuration space. + + @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param This Pointer to local data for the interface. + @param Width The width of the access. Enumerated in bytes. + See EFI_PEI_PCI_CFG_PPI_WIDTH above. + @param Address The physical address of the access. The format of + the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS. + @param Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER The invalid access width. + +**/ +EFI_STATUS +EFIAPI +PciCfg2Read ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_PCI_CFG2_PPI *This, + IN EFI_PEI_PCI_CFG_PPI_WIDTH Width, + IN UINT64 Address, + IN OUT VOID *Buffer + ) +{ + UINTN PciLibAddress; + + PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address); + + if (Width == EfiPeiPciCfgWidthUint8) { + *((UINT8 *) Buffer) = PciRead8 (PciLibAddress); + } else if (Width == EfiPeiPciCfgWidthUint16) { + if ((PciLibAddress & 0x01) == 0) { + // + // Aligned Pci address access + // + WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress)); + } else { + // + // Unaligned Pci address access, break up the request into byte by byte. + // + *((UINT8 *) Buffer) = PciRead8 (PciLibAddress); + *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1); + } + } else if (Width == EfiPeiPciCfgWidthUint32) { + if ((PciLibAddress & 0x03) == 0) { + // + // Aligned Pci address access + // + WriteUnaligned32 (((UINT32 *) Buffer), PciRead32 (PciLibAddress)); + } else if ((PciLibAddress & 0x01) == 0) { + // + // Unaligned Pci address access, break up the request into word by word. + // + WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress)); + WriteUnaligned16 (((UINT16 *) Buffer + 1), PciRead16 (PciLibAddress + 2)); + } else { + // + // Unaligned Pci address access, break up the request into byte by byte. + // + *((UINT8 *) Buffer) = PciRead8 (PciLibAddress); + *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1); + *((UINT8 *) Buffer + 2) = PciRead8 (PciLibAddress + 2); + *((UINT8 *) Buffer + 3) = PciRead8 (PciLibAddress + 3); + } + } else { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + Write to a given location in the PCI configuration space. + + @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param This Pointer to local data for the interface. + @param Width The width of the access. Enumerated in bytes. + See EFI_PEI_PCI_CFG_PPI_WIDTH above. + @param Address The physical address of the access. The format of + the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS. + @param Buffer A pointer to the buffer of data. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER The invalid access width. + +**/ +EFI_STATUS +EFIAPI +PciCfg2Write ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_PCI_CFG2_PPI *This, + IN EFI_PEI_PCI_CFG_PPI_WIDTH Width, + IN UINT64 Address, + IN OUT VOID *Buffer + ) +{ + UINTN PciLibAddress; + + PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address); + + if (Width == EfiPeiPciCfgWidthUint8) { + PciWrite8 (PciLibAddress, *((UINT8 *) Buffer)); + } else if (Width == EfiPeiPciCfgWidthUint16) { + if ((PciLibAddress & 0x01) == 0) { + // + // Aligned Pci address access + // + PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer)); + } else { + // + // Unaligned Pci address access, break up the request into byte by byte. + // + PciWrite8 (PciLibAddress, *((UINT8 *) Buffer)); + PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1)); + } + } else if (Width == EfiPeiPciCfgWidthUint32) { + if ((PciLibAddress & 0x03) == 0) { + // + // Aligned Pci address access + // + PciWrite32 (PciLibAddress, ReadUnaligned32 ((UINT32 *) Buffer)); + } else if ((PciLibAddress & 0x01) == 0) { + // + // Unaligned Pci address access, break up the request into word by word. + // + PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer)); + PciWrite16 (PciLibAddress + 2, ReadUnaligned16 ((UINT16 *) Buffer + 1)); + } else { + // + // Unaligned Pci address access, break up the request into byte by byte. + // + PciWrite8 (PciLibAddress, *((UINT8 *) Buffer)); + PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1)); + PciWrite8 (PciLibAddress + 2, *((UINT8 *) Buffer + 2)); + PciWrite8 (PciLibAddress + 3, *((UINT8 *) Buffer + 3)); + } + } else { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + + +/** + This function performs a read-modify-write operation on the contents from a given + location in the PCI configuration space. + + @param PeiServices An indirect pointer to the PEI Services Table + published by the PEI Foundation. + @param This Pointer to local data for the interface. + @param Width The width of the access. Enumerated in bytes. Type + EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read(). + @param Address The physical address of the access. + @param SetBits Points to value to bitwise-OR with the read configuration value. + The size of the value is determined by Width. + @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value. + The size of the value is determined by Width. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER The invalid access width. + +**/ +EFI_STATUS +EFIAPI +PciCfg2Modify ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_PCI_CFG2_PPI *This, + IN EFI_PEI_PCI_CFG_PPI_WIDTH Width, + IN UINT64 Address, + IN VOID *SetBits, + IN VOID *ClearBits + ) +{ + UINTN PciLibAddress; + UINT16 ClearValue16; + UINT16 SetValue16; + UINT32 ClearValue32; + UINT32 SetValue32; + + PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address); + + if (Width == EfiPeiPciCfgWidthUint8) { + PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits)); + } else if (Width == EfiPeiPciCfgWidthUint16) { + if ((PciLibAddress & 0x01) == 0) { + // + // Aligned Pci address access + // + ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits)); + SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits); + PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16); + } else { + // + // Unaligned Pci address access, break up the request into byte by byte. + // + PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits)); + PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1)); + } + } else if (Width == EfiPeiPciCfgWidthUint32) { + if ((PciLibAddress & 0x03) == 0) { + // + // Aligned Pci address access + // + ClearValue32 = (UINT32) (~ReadUnaligned32 ((UINT32 *) ClearBits)); + SetValue32 = ReadUnaligned32 ((UINT32 *) SetBits); + PciAndThenOr32 (PciLibAddress, ClearValue32, SetValue32); + } else if ((PciLibAddress & 0x01) == 0) { + // + // Unaligned Pci address access, break up the request into word by word. + // + ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits)); + SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits); + PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16); + + ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits + 1)); + SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits + 1); + PciAndThenOr16 (PciLibAddress + 2, ClearValue16, SetValue16); + } else { + // + // Unaligned Pci address access, break up the request into byte by byte. + // + PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits)); + PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1)); + PciAndThenOr8 (PciLibAddress + 2, (UINT8) (~(*((UINT8 *) ClearBits + 2))), *((UINT8 *) SetBits + 2)); + PciAndThenOr8 (PciLibAddress + 3, (UINT8) (~(*((UINT8 *) ClearBits + 3))), *((UINT8 *) SetBits + 3)); + } + } else { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi = { + PciCfg2Read, + PciCfg2Write, + PciCfg2Modify, + 0 +}; + +EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPciCfg2PpiGuid, + &gPciCfg2Ppi +}; + +/** + Module's entry function. + This routine will install EFI_PEI_PCI_CFG2_PPI. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @return Whether success to install service. +**/ +EFI_STATUS +EFIAPI +PeimInitializePciCfg ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + (**(EFI_PEI_SERVICES **)PeiServices).PciCfg = &gPciCfg2Ppi; + Status = PeiServicesInstallPpi (&gPciCfg2PpiList); + ASSERT_EFI_ERROR (Status); + + return Status; +} -- cgit