/** @file
|
PCI Host Bridge Library instance for NXP SoCs
|
|
Copyright 2018-2020 NXP
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
**/
|
|
#include <PiDxe.h>
|
#include <IndustryStandard/Pci22.h>
|
#include <Library/DebugLib.h>
|
#include <Library/DevicePathLib.h>
|
#include <Library/IoAccessLib.h>
|
#include <Library/IoLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
#include <Library/PcdLib.h>
|
#include <Library/PciHostBridgeLib.h>
|
#include <Library/SerDes.h>
|
#include <Pcie.h>
|
#include <Protocol/PciHostBridgeResourceAllocation.h>
|
#include <Protocol/PciRootBridgeIo.h>
|
|
#pragma pack(1)
|
typedef struct {
|
ACPI_HID_DEVICE_PATH AcpiDevicePath;
|
EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
|
} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
|
#pragma pack ()
|
|
STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[] = {
|
{
|
{
|
{
|
ACPI_DEVICE_PATH,
|
ACPI_DP,
|
{
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)
|
}
|
},
|
EISA_PNP_ID (0x0A08), // PCI Express
|
PCI_SEG0_NUM
|
},
|
|
{
|
END_DEVICE_PATH_TYPE,
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
{
|
END_DEVICE_PATH_LENGTH,
|
0
|
}
|
}
|
},
|
{
|
{
|
{
|
ACPI_DEVICE_PATH,
|
ACPI_DP,
|
{
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)
|
}
|
},
|
EISA_PNP_ID (0x0A08), // PCI Express
|
PCI_SEG1_NUM
|
},
|
|
{
|
END_DEVICE_PATH_TYPE,
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
{
|
END_DEVICE_PATH_LENGTH,
|
0
|
}
|
}
|
},
|
{
|
{
|
{
|
ACPI_DEVICE_PATH,
|
ACPI_DP,
|
{
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)
|
}
|
},
|
EISA_PNP_ID (0x0A08), // PCI Express
|
PCI_SEG2_NUM
|
},
|
|
{
|
END_DEVICE_PATH_TYPE,
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
{
|
END_DEVICE_PATH_LENGTH,
|
0
|
}
|
}
|
},
|
{
|
{
|
{
|
ACPI_DEVICE_PATH,
|
ACPI_DP,
|
{
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)
|
}
|
},
|
EISA_PNP_ID (0x0A08), // PCI Express
|
PCI_SEG3_NUM
|
},
|
|
{
|
END_DEVICE_PATH_TYPE,
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
{
|
END_DEVICE_PATH_LENGTH,
|
0
|
}
|
}
|
},
|
{
|
{
|
{
|
ACPI_DEVICE_PATH,
|
ACPI_DP,
|
{
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)
|
}
|
},
|
EISA_PNP_ID (0x0A08), // PCI Express
|
PCI_SEG4_NUM
|
},
|
|
{
|
END_DEVICE_PATH_TYPE,
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
{
|
END_DEVICE_PATH_LENGTH,
|
0
|
}
|
}
|
},
|
{
|
{
|
{
|
ACPI_DEVICE_PATH,
|
ACPI_DP,
|
{
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
|
(UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)
|
}
|
},
|
EISA_PNP_ID (0x0A08), // PCI Express
|
PCI_SEG5_NUM
|
},
|
|
{
|
END_DEVICE_PATH_TYPE,
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
{
|
END_DEVICE_PATH_LENGTH,
|
0
|
}
|
}
|
}
|
};
|
|
#ifndef MDEPKG_NDEBUG
|
STATIC
|
GLOBAL_REMOVE_IF_UNREFERENCED
|
CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
|
L"Mem", L"I/O", L"Bus"
|
};
|
#endif
|
|
#define PCI_ALLOCATION_ATTRIBUTES EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | \
|
EFI_PCI_HOST_BRIDGE_MEM64_DECODE
|
|
#define PCI_SUPPORT_ATTRIBUTES EFI_PCI_ATTRIBUTE_ISA_IO_16 | \
|
EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO | \
|
EFI_PCI_ATTRIBUTE_VGA_MEMORY | \
|
EFI_PCI_ATTRIBUTE_VGA_IO_16 | \
|
EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16
|
|
PCI_ROOT_BRIDGE mPciRootBridges[NUM_PCIE_CONTROLLER];
|
|
|
/**
|
Function to read LsGen4 PCIe controller config space
|
LsGen4 PCIe controller requires page number to be set
|
in Bridge Control Register(PAB) for offset > 3KB.
|
|
@param Dbi GPEX host controller address.
|
@param Offset Offset to read from
|
|
**/
|
STATIC
|
INTN
|
PciLsGen4Read32 (
|
IN EFI_PHYSICAL_ADDRESS Dbi,
|
IN UINT32 Offset
|
)
|
{
|
if (Offset < INDIRECT_ADDR_BNDRY) {
|
PciLsGen4SetPg (Dbi, 0);
|
return MmioRead32 (Dbi + Offset);
|
} else {
|
// If Offset > 3KB, paging mechanism is used
|
// Select page index and offset within the page
|
PciLsGen4SetPg (Dbi, OFFSET_TO_PAGE_IDX (Offset));
|
return MmioRead32 (Dbi + OFFSET_TO_PAGE_ADDR (Offset));
|
}
|
}
|
|
/**
|
Function to write to LsGen4 PCIe controller config space
|
LsGen4 PCIe controller requires page number to be set
|
in Bridge Control Register(PAB) for offset > 3KB.
|
|
@param Dbi GPEX host controller address
|
@param Offset Offset to read from
|
|
**/
|
STATIC
|
VOID
|
PciLsGen4Write32 (
|
IN EFI_PHYSICAL_ADDRESS Dbi,
|
IN UINT32 Offset,
|
IN UINT32 Value
|
)
|
{
|
if (Offset < INDIRECT_ADDR_BNDRY) {
|
PciLsGen4SetPg (Dbi, 0);
|
MmioWrite32 (Dbi + Offset, Value);
|
} else {
|
PciLsGen4SetPg (Dbi, OFFSET_TO_PAGE_IDX (Offset));
|
MmioWrite32 (Dbi + OFFSET_TO_PAGE_ADDR (Offset), Value);
|
}
|
}
|
|
/**
|
Helper function to check PCIe link state
|
|
@param Pcie Address of PCIe host controller.
|
|
**/
|
STATIC
|
INTN
|
PcieLinkUp (
|
IN EFI_PHYSICAL_ADDRESS Pcie,
|
IN UINT32 Idx
|
)
|
{
|
MMIO_OPERATIONS *PcieOps;
|
UINT32 State;
|
UINT32 LtssmMask;
|
|
if (PCI_LS_GEN4_CTRL) {
|
LtssmMask = 0x7f;
|
} else {
|
LtssmMask = 0x3f;
|
}
|
|
PcieOps = GetMmioOperations (FeaturePcdGet (PcdPciLutBigEndian));
|
State = PcieOps->Read32 ((UINTN)Pcie + PCI_LUT_BASE + PCI_LUT_DBG) & LtssmMask;
|
|
if (State < LTSSM_PCIE_L0) {
|
DEBUG ((DEBUG_INFO,"PCIE%d : reg @ 0x%lx, no link: LTSSM=0x%02x\n",
|
Idx + 1, Pcie, State));
|
return PCI_LINK_DOWN;
|
}
|
|
return PCI_LINK_UP;
|
}
|
|
/**
|
Function to set-up PCIe outbound window
|
|
@param Dbi Address of PCIe host controller.
|
@param Idx Index of iATU outbound window.
|
@param Type Type(Cfg0/Cfg1/Mem/IO) of iATU outbound window.
|
@param Phys PCIe controller phy address for outbound window.
|
@param BusAdr PCIe controller bus address for outbound window.
|
@param Size Window size
|
|
**/
|
STATIC
|
VOID
|
PcieOutboundSet (
|
IN EFI_PHYSICAL_ADDRESS Dbi,
|
IN UINT32 Idx,
|
IN UINT32 Type,
|
IN UINT64 Phys,
|
IN UINT64 BusAddr,
|
IN UINT64 Size
|
)
|
{
|
UINT32 Val;
|
|
if (PCI_LS_GEN4_CTRL) {
|
// PCIe Layerscape Gen4: Outbound Window
|
Size = ~(Size -1 );
|
Val = PciLsGen4Read32 ((UINTN)Dbi, PAB_AXI_AMAP_CTRL (Idx));
|
Val &= ~((AXI_AMAP_CTRL_TYPE_MASK << AXI_AMAP_CTRL_TYPE_SHIFT) |
|
(AXI_AMAP_CTRL_SIZE_MASK << AXI_AMAP_CTRL_SIZE_SHIFT) |
|
AXI_AMAP_CTRL_EN);
|
Val |= ((Type & AXI_AMAP_CTRL_TYPE_MASK) << AXI_AMAP_CTRL_TYPE_SHIFT) |
|
(((UINT32)Size >> AXI_AMAP_CTRL_SIZE_SHIFT) <<
|
AXI_AMAP_CTRL_SIZE_SHIFT) | AXI_AMAP_CTRL_EN;
|
PciLsGen4Write32 ((UINTN)Dbi, PAB_AXI_AMAP_CTRL (Idx), Val);
|
PciLsGen4Write32 ((UINTN)Dbi, PAB_AXI_AMAP_AXI_WIN (Idx), (UINT32)Phys);
|
PciLsGen4Write32 ((UINTN)Dbi, PAB_EXT_AXI_AMAP_AXI_WIN (Idx), Phys >> 32);
|
PciLsGen4Write32 ((UINTN)Dbi, PAB_AXI_AMAP_PEX_WIN_L (Idx), (UINT32)BusAddr);
|
PciLsGen4Write32 ((UINTN)Dbi, PAB_AXI_AMAP_PEX_WIN_H (Idx), BusAddr >> 32);
|
PciLsGen4Write32 ((UINTN)Dbi, PAB_EXT_AXI_AMAP_SIZE (Idx), Size >> 32);
|
} else {
|
// PCIe Layerscape : Outbound Window
|
MmioWrite32 (Dbi + IATU_VIEWPORT_OFF,
|
(UINT32)(IATU_VIEWPORT_OUTBOUND | Idx));
|
|
MmioWrite32 (Dbi + IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0,
|
(UINT32)Phys);
|
|
MmioWrite32 (Dbi + IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0,
|
(UINT32)(Phys >> 32));
|
|
MmioWrite32 (Dbi + IATU_LIMIT_ADDR_OFF_OUTBOUND_0,
|
(UINT32)(Phys + Size - BIT0));
|
|
MmioWrite32 (Dbi + IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0,
|
(UINT32)BusAddr);
|
|
MmioWrite32 (Dbi + IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0,
|
(UINT32)(BusAddr >> 32));
|
|
MmioWrite32 (Dbi + IATU_REGION_CTRL_1_OFF_OUTBOUND_0,
|
(UINT32)Type);
|
|
if (CFG_SHIFT_ENABLE &&
|
((Type == IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG0) ||
|
(Type == IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG1))) {
|
MmioWrite32 (Dbi + IATU_REGION_CTRL_2_OFF_OUTBOUND_0,
|
(IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN |
|
IATU_ENABLE_CFG_SHIFT_FEATURE)
|
);
|
} else {
|
MmioWrite32 (Dbi + IATU_REGION_CTRL_2_OFF_OUTBOUND_0,
|
IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN);
|
}
|
}
|
}
|
|
/**
|
Dump PCIe Layerscape ATU
|
|
@param Pcie Address of PCIe host controller.
|
@param Count Number of Windows
|
**/
|
VOID
|
LsDumpAtu (
|
IN EFI_PHYSICAL_ADDRESS Pcie,
|
IN UINT32 Count
|
)
|
{
|
UINT32 Cnt;
|
|
for (Cnt = 0; Cnt < Count; Cnt++) {
|
MmioWrite32 ((UINTN)Pcie + IATU_VIEWPORT_OFF,
|
(UINT32)(IATU_VIEWPORT_OUTBOUND | Cnt));
|
|
DEBUG ((DEBUG_INFO, "iATU%d:\n",Cnt));
|
DEBUG ((DEBUG_INFO, "\tLOWER PHYS 0x%08x\n",
|
MmioRead32 ((UINTN)Pcie + IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0)));
|
|
DEBUG ((DEBUG_INFO, "\tUPPER PHYS 0x%08x\n",
|
MmioRead32 ((UINTN)Pcie + IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0)));
|
|
DEBUG ((DEBUG_INFO, "\tLOWER BUS 0x%08x\n",
|
MmioRead32 ((UINTN)Pcie + IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0)));
|
|
DEBUG ((DEBUG_INFO, "\tUPPER BUS 0x%08x\n",
|
MmioRead32 ((UINTN)Pcie + IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0)));
|
|
DEBUG ((DEBUG_INFO, "\tLIMIT 0x%08x\n",
|
MmioRead32 ((UINTN)Pcie + IATU_LIMIT_ADDR_OFF_OUTBOUND_0)));
|
|
DEBUG ((DEBUG_INFO, "\tCR1 0x%08x\n",
|
MmioRead32 ((UINTN)Pcie + IATU_REGION_CTRL_1_OFF_OUTBOUND_0)));
|
|
DEBUG ((DEBUG_INFO, "\tCR2 0x%08x\n",
|
MmioRead32 ((UINTN)Pcie + IATU_REGION_CTRL_2_OFF_OUTBOUND_0)));
|
}
|
}
|
|
/**
|
Function to set-up iATU windows for Layerscape PCIe controller
|
|
@param Pcie Address of PCIe host controller
|
@param Cfg0Base PCIe controller phy address Type0 Configuration Space.
|
@param Cfg1Base PCIe controller phy address Type1 Configuration Space.
|
@param MemBase PCIe controller phy address Memory Space.
|
@param Mem64Base PCIe controller phy address MMIO64 Space.
|
@param IoBase PCIe controller phy address IO Space.
|
**/
|
STATIC
|
VOID
|
PcieLsSetupAtu (
|
IN EFI_PHYSICAL_ADDRESS Pcie,
|
IN EFI_PHYSICAL_ADDRESS Cfg0Base,
|
IN EFI_PHYSICAL_ADDRESS Cfg1Base,
|
IN EFI_PHYSICAL_ADDRESS MemBase,
|
IN EFI_PHYSICAL_ADDRESS Mem64Base,
|
IN EFI_PHYSICAL_ADDRESS IoBase
|
)
|
{
|
UINT64 Cfg0BaseAddr;
|
UINT64 Cfg1BaseAddr;
|
UINT64 Cfg0BusAddress;
|
UINT64 Cfg1BusAddress;
|
UINT64 Cfg0Size;
|
UINT64 Cfg1Size;
|
UINT64 Mem64End;
|
UINT32 Index;
|
|
if (CFG_SHIFT_ENABLE) {
|
DEBUG ((DEBUG_INFO, "PCIe: CFG Shift Method Enabled \n"));
|
Cfg0BaseAddr = Cfg0Base + SIZE_1MB;
|
Cfg1BaseAddr = Cfg0Base + SIZE_2MB;
|
Cfg0BusAddress = SIZE_1MB;
|
Cfg1BusAddress = SIZE_2MB;
|
// Region for type0 CFG transactions (only for bus1)
|
if (PcdGetBool (PcdPciHideRootPort)) {
|
Cfg0Size = ECAM_DEVICE_SIZE;
|
} else {
|
Cfg0Size = ECAM_BUS_SIZE;
|
}
|
// Region for type1 CFG transactions (for bus > 1)
|
Cfg1Size = (ECAM_CFG_REGION_SIZE - ECAM_BUS_SIZE); // 255MB
|
} else {
|
Cfg0BaseAddr = Cfg0Base;
|
Cfg1BaseAddr = Cfg1Base;
|
Cfg0BusAddress = SEG_CFG_BUS;
|
Cfg1BusAddress = SEG_CFG_BUS;
|
Cfg0Size = SEG_CFG_SIZE;
|
Cfg1Size = SEG_CFG_SIZE;
|
}
|
|
Index = 0;
|
// iATU : OUTBOUND WINDOW 1 : CFG0
|
PcieOutboundSet (Pcie,
|
Index++,
|
IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG0,
|
Cfg0BaseAddr,
|
Cfg0BusAddress,
|
Cfg0Size);
|
|
// iATU : OUTBOUND WINDOW 2 : CFG1
|
PcieOutboundSet (Pcie,
|
Index++,
|
IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG1,
|
Cfg1BaseAddr,
|
Cfg1BusAddress,
|
Cfg1Size);
|
|
// iATU : OUTBOUND WINDOW 3 : MEM
|
PcieOutboundSet (Pcie,
|
Index++,
|
IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM,
|
MemBase,
|
SEG_MEM_BUS,
|
SEG_MEM_SIZE);
|
|
//
|
// To allow maximum MMIO64 space, MMIO64 window
|
// size must be multiple of max iATU size (4GB)
|
//
|
ASSERT ((PCI_MMIO64_WIN_SIZE & (SIZE_4GB - 1)) == 0);
|
|
Mem64End = Mem64Base + PCI_MMIO64_WIN_SIZE - 1;
|
while (Mem64Base < Mem64End) {
|
// iATU : OUTBOUND WINDOWs : MMIO64
|
PcieOutboundSet (Pcie,
|
Index++,
|
IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM,
|
Mem64Base,
|
Mem64Base,
|
SIZE_4GB);
|
Mem64Base += SIZE_4GB;
|
}
|
|
// iATU : OUTBOUND WINDOW : IO
|
PcieOutboundSet (Pcie,
|
Index++,
|
IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_IO,
|
IoBase,
|
SEG_IO_BUS,
|
SEG_IO_SIZE
|
);
|
|
DEBUG_CODE_BEGIN ();
|
LsDumpAtu (Pcie, Index);
|
DEBUG_CODE_END ();
|
}
|
|
/**
|
Dump PCIe LsGen4 ATU
|
|
@param Pcie Address of PCIe host controller.
|
@param Count Number of Windows
|
**/
|
VOID
|
LsGen4DumpAtu (
|
IN EFI_PHYSICAL_ADDRESS Pcie,
|
IN UINT32 Count
|
)
|
{
|
UINT32 Cnt;
|
|
for (Cnt = 0; Cnt < Count; Cnt++) {
|
DEBUG ((DEBUG_INFO,"APIO WINDOW%d:\n", Cnt));
|
DEBUG ((DEBUG_INFO,"\tLOWER PHYS 0x%08x\n",
|
PciLsGen4Read32 ((UINTN)Pcie, PAB_AXI_AMAP_AXI_WIN (Cnt))));
|
DEBUG ((DEBUG_INFO,"\tUPPER PHYS 0x%08x\n",
|
PciLsGen4Read32 ((UINTN)Pcie, PAB_EXT_AXI_AMAP_AXI_WIN (Cnt))));
|
DEBUG ((DEBUG_INFO,"\tLOWER BUS 0x%08x\n",
|
PciLsGen4Read32 ((UINTN)Pcie, PAB_AXI_AMAP_PEX_WIN_L (Cnt))));
|
DEBUG ((DEBUG_INFO,"\tUPPER BUS 0x%08x\n",
|
PciLsGen4Read32 ((UINTN)Pcie, PAB_AXI_AMAP_PEX_WIN_H (Cnt))));
|
DEBUG ((DEBUG_INFO,"\tSIZE 0x%08x\n",
|
PciLsGen4Read32 ((UINTN)Pcie, PAB_AXI_AMAP_CTRL (Cnt)) &
|
(AXI_AMAP_CTRL_SIZE_MASK << AXI_AMAP_CTRL_SIZE_SHIFT)));
|
DEBUG ((DEBUG_INFO,"\tEXT_SIZE 0x%08x\n",
|
PciLsGen4Read32 ((UINTN)Pcie, PAB_EXT_AXI_AMAP_SIZE (Cnt))));
|
DEBUG ((DEBUG_INFO,"\tCTRL: 0x%08x\n",
|
PciLsGen4Read32 ((UINTN)Pcie, PAB_AXI_AMAP_CTRL (Cnt))));
|
}
|
}
|
|
/**
|
Function to set-up ATU windows for PCIe LayerscapeGen4 controller
|
|
@param Pcie Address of PCIe host controller
|
@param Cfg0Base PCIe controller phy address Type0 Configuration Space.
|
@param Cfg1Base PCIe controller phy address Type1 Configuration Space.
|
@param MemBase PCIe controller phy address Memory Space.
|
@param Mem64Base PCIe controller phy address MMIO64 Space.
|
@param IoBase PCIe controller phy address IO Space.
|
**/
|
STATIC
|
VOID
|
PcieLsGen4SetupAtu (
|
IN EFI_PHYSICAL_ADDRESS Pcie,
|
IN EFI_PHYSICAL_ADDRESS Cfg0Base,
|
IN EFI_PHYSICAL_ADDRESS Cfg1Base,
|
IN EFI_PHYSICAL_ADDRESS MemBase,
|
IN EFI_PHYSICAL_ADDRESS Mem64Base,
|
IN EFI_PHYSICAL_ADDRESS IoBase
|
)
|
{
|
UINT64 Mem64End;
|
UINT32 Index;
|
|
Index=0;
|
|
// ATU : OUTBOUND WINDOW 1 : CFG0
|
PcieOutboundSet (Pcie, Index++,
|
PAB_AXI_TYPE_CFG,
|
Cfg0Base,
|
SEG_CFG_BUS,
|
SEG_CFG_SIZE);
|
|
// ATU : OUTBOUND WINDOW 2 : IO
|
PcieOutboundSet (Pcie, Index++,
|
PAB_AXI_TYPE_IO,
|
IoBase,
|
SEG_IO_BUS,
|
SEG_IO_SIZE);
|
|
// ATU : OUTBOUND WINDOW 3 : MEM
|
PcieOutboundSet (Pcie, Index++,
|
PAB_AXI_TYPE_MEM,
|
MemBase,
|
SEG_MEM_BUS,
|
SEG_MEM_SIZE);
|
|
//
|
// To allow maximum MMIO64 space, MMIO64 window
|
// size must be multiple of max iATU size (4GB)
|
//
|
ASSERT ((PCI_MMIO64_WIN_SIZE & (SIZE_4GB - 1)) == 0);
|
|
Mem64End = Mem64Base + PCI_MMIO64_WIN_SIZE - 1;
|
while (Mem64Base < Mem64End) {
|
// ATU : OUTBOUND WINDOW : MMIO64
|
PcieOutboundSet (Pcie, Index++,
|
PAB_AXI_TYPE_MEM,
|
Mem64Base,
|
Mem64Base,
|
SIZE_4GB);
|
|
Mem64Base += SIZE_4GB;
|
}
|
|
DEBUG_CODE_BEGIN ();
|
LsGen4DumpAtu (Pcie, Index);
|
DEBUG_CODE_END ();
|
}
|
|
/**
|
Function to set-up PCIe inbound window
|
|
@param Pcie Address of PCIe host controller.
|
@param Idx Index of inbound window.
|
@param Type Type(Cfg/Mem/IO) of iATU outbound window.
|
@param Phys PCIe controller phy address for inbound window.
|
@param BusAdr PCIe controller bus address for inbound window.
|
@param Size Window size
|
|
**/
|
|
STATIC
|
VOID
|
PciSetupInBoundWin (
|
IN EFI_PHYSICAL_ADDRESS Pcie,
|
IN UINT32 Idx,
|
IN UINT32 Type,
|
IN UINT64 Phys,
|
IN UINT64 BusAddr,
|
IN UINT64 Size)
|
{
|
UINT32 Val;
|
UINT64 WinSize;
|
|
if (PCI_LS_GEN4_CTRL) {
|
Val = PciLsGen4Read32 ((UINTN)Pcie, PAB_PEX_AMAP_CTRL(Idx));
|
Val &= ~(PEX_AMAP_CTRL_TYPE_MASK << PEX_AMAP_CTRL_TYPE_SHIFT);
|
Val &= ~(PEX_AMAP_CTRL_EN_MASK << PEX_AMAP_CTRL_EN_SHIFT);
|
Val = (Val | (Type << PEX_AMAP_CTRL_TYPE_SHIFT));
|
Val = (Val | (1 << PEX_AMAP_CTRL_EN_SHIFT));
|
|
WinSize = ~(Size - 1);
|
PciLsGen4Write32 ((UINTN)Pcie, PAB_PEX_AMAP_CTRL(Idx),
|
(Val | (UINT32)WinSize));
|
PciLsGen4Write32 ((UINTN)Pcie, PAB_EXT_PEX_AMAP_SIZE(Idx), (WinSize>>32));
|
PciLsGen4Write32 ((UINTN)Pcie, PAB_PEX_AMAP_AXI_WIN(Idx), (UINT32)Phys);
|
PciLsGen4Write32 ((UINTN)Pcie, PAB_EXT_PEX_AMAP_AXI_WIN(Idx), (Phys>>32));
|
PciLsGen4Write32 ((UINTN)Pcie, PAB_PEX_AMAP_PEX_WIN_L(Idx), (UINT32)BusAddr);
|
PciLsGen4Write32 ((UINTN)Pcie, PAB_PEX_AMAP_PEX_WIN_H(Idx), (BusAddr >>32));
|
}
|
}
|
|
/**
|
Helper function to set-up PCIe controller
|
|
@param Pcie Address of PCIe host controller
|
@param Cfg0Base PCIe controller phy address Type0 Configuration Space.
|
@param Cfg1Base PCIe controller phy address Type1 Configuration Space.
|
@param MemBase PCIe controller phy address Memory Space.
|
@param Mem64Base PCIe controller phy address MMIO64 Space.
|
@param IoBase PCIe controller phy address IO Space.
|
|
**/
|
STATIC
|
VOID
|
PcieSetupCntrl (
|
IN EFI_PHYSICAL_ADDRESS Pcie,
|
IN EFI_PHYSICAL_ADDRESS Cfg0Base,
|
IN EFI_PHYSICAL_ADDRESS Cfg1Base,
|
IN EFI_PHYSICAL_ADDRESS MemBase,
|
IN EFI_PHYSICAL_ADDRESS Mem64Base,
|
IN EFI_PHYSICAL_ADDRESS IoBase
|
)
|
{
|
UINT32 Val;
|
|
if (PCI_LS_GEN4_CTRL) {
|
// PCIe LsGen4 Controller Setup
|
|
// Workaround for A-011451
|
Val = PciLsGen4Read32 ((UINTN)Pcie, GPEX_ACK_REPLAY_TO);
|
Val &= ~(ACK_LAT_TO_VAL_MASK << ACK_LAT_TO_VAL_SHIFT);
|
Val |= (4 << ACK_LAT_TO_VAL_SHIFT);
|
PciLsGen4Write32 ((UINTN)Pcie, GPEX_ACK_REPLAY_TO, Val);
|
|
//Fix Class Code
|
Val = PciLsGen4Read32 ((UINTN)Pcie, GPEX_CLASSCODE);
|
Val &= ~(GPEX_CLASSCODE_MASK << GPEX_CLASSCODE_SHIFT);
|
Val |= PCI_CLASS_BRIDGE_PCI << GPEX_CLASSCODE_SHIFT;
|
PciLsGen4Write32 ((UINTN)Pcie, GPEX_CLASSCODE, Val);
|
|
// Enable APIO and Memory/IO/CFG Windows
|
Val = PciLsGen4Read32 ((UINTN)Pcie, PAB_AXI_PIO_CTRL (0));
|
Val |= APIO_EN | MEM_WIN_EN | IO_WIN_EN | CFG_WIN_EN;
|
PciLsGen4Write32 ((UINTN)Pcie, PAB_AXI_PIO_CTRL (0), Val);
|
|
// LsGen4 Inbound Window Setup
|
PciSetupInBoundWin (Pcie, 0, PAB_AXI_TYPE_MEM, 0 , 0, SIZE_1TB);
|
|
// LsGen4 Outbound Window Setup
|
PcieLsGen4SetupAtu (Pcie, Cfg0Base, Cfg1Base, MemBase, Mem64Base, IoBase);
|
|
// Enable AMBA & PEX PIO
|
Val = PciLsGen4Read32 ((UINTN)Pcie, PAB_CTRL);
|
Val |= PAB_CTRL_APIO_EN | PAB_CTRL_PPIO_EN;
|
PciLsGen4Write32 ((UINTN)Pcie, PAB_CTRL, Val);
|
|
Val = PciLsGen4Read32 ((UINTN)Pcie, PAB_PEX_PIO_CTRL(0));
|
Val |= PPIO_EN;
|
PciLsGen4Write32 ((UINTN)Pcie, PAB_PEX_PIO_CTRL(0), Val);
|
|
} else {
|
// PCIe Layerscape Controller Setup
|
PcieLsSetupAtu (Pcie, Cfg0Base, Cfg1Base, MemBase, Mem64Base, IoBase);
|
|
// Program Class code for Layerscape PCIe controller
|
MmioWrite32 ((UINTN)Pcie + PCI_DBI_RO_WR_EN, 1);
|
Val = MmioRead32 ((UINTN)Pcie + PCI_CLASS_DEVICE);
|
Val &= ~(CLASS_CODE_MASK << CLASS_CODE_SHIFT);
|
Val |= (PCI_CLASS_BRIDGE_PCI << CLASS_CODE_SHIFT);
|
MmioWrite32 ((UINTN)Pcie + PCI_CLASS_DEVICE, Val);
|
MmioWrite32 ((UINTN)Pcie + PCI_DBI_RO_WR_EN, 0);
|
}
|
}
|
|
/**
|
This function checks whether PCIe is enabled or not
|
depending upon SoC serdes protocol map
|
|
@param PcieNum PCIe number.
|
|
@return The PCIe number enabled in map.
|
@return FALSE PCIe number is disabled in map.
|
|
**/
|
STATIC
|
BOOLEAN
|
IsPcieNumEnabled(
|
IN UINTN PcieNum
|
)
|
{
|
UINT64 SerDesProtocolMap;
|
|
SerDesProtocolMap = 0;
|
|
// Reading serdes protocol map
|
GetSerDesProtocolMap (&SerDesProtocolMap);
|
|
return (SerDesProtocolMap & (BIT0 << (PcieNum))) != 0;
|
}
|
|
/**
|
Return all the root bridge instances in an array.
|
|
@param Count Return the count of root bridge instances.
|
|
@return All the root bridge instances in an array.
|
|
**/
|
PCI_ROOT_BRIDGE *
|
EFIAPI
|
PciHostBridgeGetRootBridges (
|
OUT UINTN *Count
|
)
|
{
|
UINTN Idx;
|
UINTN Loop;
|
UINT64 PciPhyMemAddr[NUM_PCIE_CONTROLLER];
|
UINT64 PciPhyMem64Addr[NUM_PCIE_CONTROLLER];
|
UINT64 PciPhyCfg0Addr[NUM_PCIE_CONTROLLER];
|
UINT64 PciPhyCfg1Addr[NUM_PCIE_CONTROLLER];
|
UINT64 PciPhyIoAddr[NUM_PCIE_CONTROLLER];
|
UINT64 Regs[NUM_PCIE_CONTROLLER];
|
INTN LinkUp;
|
|
for (Idx = 0, Loop = 0; Idx < NUM_PCIE_CONTROLLER; Idx++) {
|
PciPhyMemAddr[Idx] = PCI_SEG0_PHY_MEM_BASE + (PCI_BASE_DIFF * Idx);
|
PciPhyMem64Addr[Idx] = PCI_SEG0_PHY_MEM64_BASE + (PCI_BASE_DIFF * Idx);
|
PciPhyCfg0Addr[Idx] = PCI_SEG0_PHY_CFG0_BASE + (PCI_BASE_DIFF * Idx);
|
PciPhyCfg1Addr[Idx] = PCI_SEG0_PHY_CFG1_BASE + (PCI_BASE_DIFF * Idx);
|
PciPhyIoAddr [Idx] = PCI_SEG0_PHY_IO_BASE + (PCI_BASE_DIFF * Idx);
|
Regs[Idx] = PCI_SEG0_DBI_BASE + (PCI_DBI_SIZE_DIFF * Idx);
|
|
// Check is the PCIe controller is enabled
|
if (IsPcieNumEnabled (Idx + 1) == 0) {
|
DEBUG ((DEBUG_INFO, "PCIE%d reg @ 0x%lx is disabled \n", Idx + 1, Regs[Idx]));
|
continue;
|
}
|
|
// Check PCIe Link
|
LinkUp = PcieLinkUp(Regs[Idx], Idx);
|
|
if (!LinkUp) {
|
continue;
|
}
|
DEBUG ((DEBUG_INFO, "PCIE%d reg @ 0x%lx :Passed Linkup Phase\n", Idx + 1, Regs[Idx]));
|
// Set up PCIe Controller and ATU windows
|
PcieSetupCntrl (Regs[Idx],
|
PciPhyCfg0Addr[Idx],
|
PciPhyCfg1Addr[Idx],
|
PciPhyMemAddr[Idx],
|
PciPhyMem64Addr[Idx],
|
PciPhyIoAddr[Idx]);
|
|
mPciRootBridges[Loop].Segment = Idx;
|
mPciRootBridges[Loop].Supports = PCI_SUPPORT_ATTRIBUTES;
|
mPciRootBridges[Loop].Attributes = PCI_SUPPORT_ATTRIBUTES;
|
mPciRootBridges[Loop].DmaAbove4G = TRUE;
|
mPciRootBridges[Loop].NoExtendedConfigSpace = FALSE;
|
mPciRootBridges[Loop].ResourceAssigned = FALSE;
|
mPciRootBridges[Loop].AllocationAttributes = PCI_ALLOCATION_ATTRIBUTES;
|
|
mPciRootBridges[Loop].Bus.Base = PCI_SEG_BUSNUM_MIN;
|
mPciRootBridges[Loop].Bus.Limit = PCI_SEG_BUSNUM_MAX;
|
|
mPciRootBridges[Loop].Io.Base = PCI_SEG_PORTIO_MIN;
|
mPciRootBridges[Loop].Io.Limit = PCI_SEG_PORTIO_MAX;
|
mPciRootBridges[Loop].Io.Translation = MAX_UINT64 -
|
(SEG_IO_SIZE * Idx) + 1;
|
|
mPciRootBridges[Loop].Mem.Base = SEG_MEM_BASE;
|
mPciRootBridges[Loop].Mem.Limit = SEG_MEM_LIMIT;
|
mPciRootBridges[Loop].Mem.Translation = MAX_UINT64 -
|
(PCI_SEG0_MMIO_MEMBASE +
|
(PCI_BASE_DIFF *
|
Idx)) + 1;
|
|
mPciRootBridges[Loop].MemAbove4G.Base = PciPhyMem64Addr[Idx];
|
mPciRootBridges[Loop].MemAbove4G.Limit = PciPhyMem64Addr[Idx] +
|
(PCI_MMIO64_WIN_SIZE - 1);
|
|
mPciRootBridges[Loop].PMem.Base = MAX_UINT64;
|
mPciRootBridges[Loop].PMem.Limit = 0;
|
mPciRootBridges[Loop].PMemAbove4G.Base = MAX_UINT64;
|
mPciRootBridges[Loop].PMemAbove4G.Limit = 0;
|
mPciRootBridges[Loop].DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[Idx];
|
Loop++;
|
}
|
|
if (Loop == 0) {
|
return NULL;
|
}
|
|
*Count = Loop;
|
return mPciRootBridges;
|
}
|
|
/**
|
Free the root bridge instances array returned from PciHostBridgeGetRootBridges().
|
|
@param Bridges The root bridge instances array.
|
@param Count The count of the array.
|
**/
|
VOID
|
EFIAPI
|
PciHostBridgeFreeRootBridges (
|
PCI_ROOT_BRIDGE *Bridges,
|
UINTN Count
|
)
|
{
|
}
|
|
/**
|
Inform the platform that the resource conflict happens.
|
|
@param HostBridgeHandle Handle of the Host Bridge.
|
@param Configuration Pointer to PCI I/O and PCI memory resource
|
descriptors. The Configuration contains the resources
|
for all the root bridges. The resource for each root
|
bridge is terminated with END descriptor and an
|
additional END is appended indicating the end of the
|
entire resources. The resource descriptor field
|
values follow the description in
|
EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
|
.SubmitResources().
|
|
**/
|
VOID
|
EFIAPI
|
PciHostBridgeResourceConflict (
|
EFI_HANDLE HostBridgeHandle,
|
VOID *Configuration
|
)
|
{
|
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
|
UINTN RootBridgeIndex;
|
|
DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));
|
|
RootBridgeIndex = 0;
|
Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
|
|
while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
|
|
DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
|
|
for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
|
ASSERT (Descriptor->ResType <
|
ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr));
|
|
DEBUG ((DEBUG_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
|
mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
|
Descriptor->AddrLen, Descriptor->AddrRangeMax
|
));
|
|
if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
|
DEBUG ((DEBUG_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",
|
Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
|
((Descriptor->SpecificFlag &
|
EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
|
) != 0) ? L" (Prefetchable)" : L""
|
));
|
}
|
}
|
//
|
// Skip the END descriptor for root bridge
|
//
|
ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
|
Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
|
(EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
|
);
|
}
|
|
return;
|
}
|