/** @file * * Copyright (c) 2018, Hisilicon Limited. All rights reserved. * Copyright (c) 2018, Linaro Limited. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #define INVALID_CAPABILITY_00 0x00 #define INVALID_CAPABILITY_FF 0xFF #define PCI_CAPABILITY_POINTER_MASK 0xFC STATIC UINT64 GetPcieCfgAddress ( UINT64 Ecam, UINTN Bus, UINTN Device, UINTN Function, UINTN Reg ) { return Ecam + PCI_EXPRESS_LIB_ADDRESS (Bus, Device, Function, Reg); } STATIC PCI_ROOT_BRIDGE_RESOURCE_APPETURE * GetAppetureByRootBridgeIo ( IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridge ) { EFI_STATUS Status; EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration = NULL; UINTN Hb; UINTN Rb; Status = RootBridge->Configuration ( RootBridge, (VOID **)&Configuration ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "[%a:%d] RootBridgeIo->Configuration failed %r\n", __FUNCTION__, __LINE__, Status)); return NULL; }; while (Configuration->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) { if (Configuration->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { break; } Configuration++; } if (Configuration->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) { DEBUG ((DEBUG_ERROR, "[%a:%d] Can't find bus descriptor\n", __FUNCTION__, __LINE__)); return NULL; } for (Hb = 0; Hb < PCIE_MAX_HOSTBRIDGE; Hb++) { for (Rb = 0; Rb < PCIE_MAX_ROOTBRIDGE; Rb++) { if (RootBridge->SegmentNumber == mResAppeture[Hb][Rb].Segment && Configuration->AddrRangeMin >= mResAppeture[Hb][Rb].BusBase && Configuration->AddrRangeMax <= mResAppeture[Hb][Rb].BusLimit) { return &mResAppeture[Hb][Rb]; } } } DEBUG ((DEBUG_ERROR, "[%a:%d] Can't find PCI appeture\n", __FUNCTION__, __LINE__)); return NULL; } STATIC VOID SetAtuConfig0RW ( PCI_ROOT_BRIDGE_RESOURCE_APPETURE *Private, UINT32 Index ) { UINTN RbPciBase = Private->RbPciBar; UINT64 MemLimit = GetPcieCfgAddress (Private->Ecam, Private->BusBase + 1, 1, 0, 0) - 1; UINT64 MemBase = GetPcieCfgAddress (Private->Ecam, Private->BusBase, 0, 0, 0); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_VIEW_POINT, Index); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_LOW, (UINT32)MemBase); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_HIGH, (UINT32)(MemBase >> 32)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_LIMIT, (UINT32) MemLimit); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_TARGET_LOW, 0); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_TARGET_HIGH, 0); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_CTRL1, IATU_CTRL1_TYPE_CONFIG0); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_CTRL2, IATU_SHIIF_MODE); { UINTN i; for (i=0; i<0x20; i+=4) { DEBUG ((DEBUG_ERROR, "[%a:%d] - Base=%p value=%x\n", __FUNCTION__, __LINE__, RbPciBase + 0x900 + i, MmioRead32(RbPciBase + 0x900 + i))); } } } STATIC VOID SetAtuConfig1RW ( PCI_ROOT_BRIDGE_RESOURCE_APPETURE *Private, UINT32 Index ) { UINTN RbPciBase = Private->RbPciBar; UINT64 MemLimit = GetPcieCfgAddress (Private->Ecam, Private->BusLimit + 1, 0, 0, 0) - 1; UINT64 MemBase = GetPcieCfgAddress (Private->Ecam, Private->BusBase + 2, 0, 0, 0); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_VIEW_POINT, Index); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_CTRL1, IATU_CTRL1_TYPE_CONFIG1); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_LOW, (UINT32)MemBase); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_HIGH, (UINT32)(MemBase >> 32)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_LIMIT, (UINT32) MemLimit); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_TARGET_LOW, 0); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_TARGET_HIGH, 0); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_CTRL2, IATU_SHIIF_MODE); { UINTN i; for (i=0; i<0x20; i+=4) { DEBUG ((DEBUG_ERROR, "[%a:%d] - Base=%p value=%x\n", __FUNCTION__, __LINE__, RbPciBase + 0x900 + i, MmioRead32(RbPciBase + 0x900 + i))); } } } STATIC VOID SetAtuIoRW (UINT64 RbPciBase,UINT64 IoBase,UINT64 CpuIoRegionLimit, UINT64 CpuIoRegionBase, UINT32 Index) { MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_VIEW_POINT, Index); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_CTRL1, IATU_CTRL1_TYPE_IO); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_LOW, (UINT32)(CpuIoRegionBase)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_HIGH, (UINT32)((UINT64)CpuIoRegionBase >> 32)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_LIMIT, (UINT32)(CpuIoRegionLimit)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_TARGET_LOW, (UINT32)(IoBase)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_TARGET_HIGH, (UINT32)((UINT64)(IoBase) >> 32)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_CTRL2, IATU_NORMAL_MODE); { UINTN i; for (i=0; i<0x20; i+=4) { DEBUG ((DEBUG_ERROR, "[%a:%d] - Base=%p value=%x\n", __FUNCTION__, __LINE__, RbPciBase + 0x900 + i, MmioRead32(RbPciBase + 0x900 + i))); } } } STATIC VOID SetAtuMemRW(UINT64 RbPciBase,UINT64 MemBase,UINT64 CpuMemRegionLimit, UINT64 CpuMemRegionBase, UINT32 Index) { MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_VIEW_POINT, Index); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_CTRL1, IATU_CTRL1_TYPE_MEM); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_LOW, (UINT32)(CpuMemRegionBase)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_HIGH, (UINT32)((UINT64)(CpuMemRegionBase) >> 32)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_LIMIT, (UINT32)(CpuMemRegionLimit)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_TARGET_LOW, (UINT32)(MemBase)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_TARGET_HIGH, (UINT32)((UINT64)(MemBase) >> 32)); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_CTRL2, IATU_NORMAL_MODE); { UINTN i; for (i=0; i<0x20; i+=4) { DEBUG ((DEBUG_ERROR, "[%a:%d] - Base=%p value=%x\n", __FUNCTION__, __LINE__, RbPciBase + 0x900 + i, MmioRead32(RbPciBase + 0x900 + i))); } } } VOID InitAtu (PCI_ROOT_BRIDGE_RESOURCE_APPETURE *Private) { SetAtuMemRW (Private->RbPciBar, Private->PciRegionBase, Private->PciRegionLimit, Private->CpuMemRegionBase, 0); SetAtuConfig0RW (Private, 1); SetAtuConfig1RW (Private, 2); SetAtuIoRW (Private->RbPciBar, Private->IoBase, Private->IoLimit, Private->CpuIoRegionBase, 3); } /*++ Routine Description: Perform Platform initialization first in PciPlatform. Arguments: Returns: VOID. --*/ VOID EFIAPI PciInitPlatform ( VOID ) { UINT32 Port; UINT32 HostBridgeNum = 0; for (HostBridgeNum = 0; HostBridgeNum < PCIE_MAX_HOSTBRIDGE; HostBridgeNum++) { for (Port = 0; Port < PCIE_MAX_ROOTBRIDGE; Port++) { InitAtu (&mResAppeture[HostBridgeNum][Port]); } } return; } STATIC BOOLEAN PcieCheckAriFwdEn ( UINTN PciBaseAddr ) { UINT8 PciPrimaryStatus; UINT8 CapabilityOffset; UINT8 CapId; UINT8 TempData; PciPrimaryStatus = MmioRead16 (PciBaseAddr + PCI_PRIMARY_STATUS_OFFSET); if (PciPrimaryStatus & EFI_PCI_STATUS_CAPABILITY) { CapabilityOffset = MmioRead8 (PciBaseAddr + PCI_CAPBILITY_POINTER_OFFSET); CapabilityOffset &= PCI_CAPABILITY_POINTER_MASK; while ((CapabilityOffset != INVALID_CAPABILITY_00) && (CapabilityOffset != INVALID_CAPABILITY_FF)) { CapId = MmioRead8 (PciBaseAddr + CapabilityOffset); if (CapId == EFI_PCI_CAPABILITY_ID_PCIEXP) { break; } CapabilityOffset = MmioRead8 (PciBaseAddr + CapabilityOffset + 1); CapabilityOffset &= PCI_CAPABILITY_POINTER_MASK; } } else { return FALSE; } if ((CapabilityOffset == INVALID_CAPABILITY_FF) || (CapabilityOffset == INVALID_CAPABILITY_00)) { return FALSE; } TempData = MmioRead16 (PciBaseAddr + CapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET); TempData &= EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING; if (TempData == EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) { return TRUE; } else { return FALSE; } } VOID EnlargeAtuConfig0 ( IN EFI_HANDLE HostBridge ) { EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *ResAlloc = NULL; EFI_STATUS Status; EFI_HANDLE RootBridgeHandle = NULL; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo = NULL; PCI_ROOT_BRIDGE_RESOURCE_APPETURE *Appeture; UINTN RbPciBase; UINT64 MemLimit; DEBUG ((DEBUG_INFO, "In Enlarge RP iATU Config 0.\n")); Status = gBS->HandleProtocol ( HostBridge, &gEfiPciHostBridgeResourceAllocationProtocolGuid, (VOID **)&ResAlloc ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "[%a:%d] - HandleProtocol failed %r\n", __FUNCTION__, __LINE__, Status)); return; } while (TRUE) { Status = ResAlloc->GetNextRootBridge ( ResAlloc, &RootBridgeHandle ); if (EFI_ERROR (Status)) { break; } Status = gBS->HandleProtocol ( RootBridgeHandle, &gEfiPciRootBridgeIoProtocolGuid, (VOID **)&RootBridgeIo ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "[%a:%d] - HandleProtocol failed %r\n", __FUNCTION__, __LINE__, Status)); // This should never happen so that it is a fatal error and we don't try // to continue break; } Appeture = GetAppetureByRootBridgeIo (RootBridgeIo); if (Appeture == NULL) { DEBUG ((DEBUG_ERROR, "[%a:%d] Get appeture failed\n", __FUNCTION__, __LINE__)); continue; } RbPciBase = Appeture->RbPciBar; // Those ARI FWD Enable Root Bridge, need enlarge iATU window. if (PcieCheckAriFwdEn (RbPciBase)) { MemLimit = GetPcieCfgAddress (Appeture->Ecam, Appeture->BusBase + 2, 0, 0, 0) - 1; MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_VIEW_POINT, 1); MmioWrite32 (RbPciBase + IATU_OFFSET + IATU_REGION_BASE_LIMIT, (UINT32) MemLimit); } } } /*++ Routine Description: Perform Platform initialization by the phase indicated. Arguments: HostBridge - The associated PCI host bridge handle. Phase - The phase of the PCI controller enumeration. ChipsetPhase - Defines the execution phase of the PCI chipset driver. Returns: --*/ VOID EFIAPI PhaseNotifyPlatform ( IN EFI_HANDLE HostBridge, IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase, IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase ) { switch (Phase) { case EfiPciHostBridgeEndEnumeration: // Only do once if (ChipsetPhase == ChipsetEntry) { DEBUG ((DEBUG_INFO, "PCI end enumeration platform hook\n")); EnlargeAtuConfig0 (HostBridge); } break; default: break; } return ; }