| /** @file | |
| FDT client library for ARM's TimerDxe | |
| Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Uefi.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/PcdLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Protocol/FdtClient.h> | |
| #pragma pack (1) | |
| typedef struct { | |
| UINT32 Type; | |
| UINT32 Number; | |
| UINT32 Flags; | |
| } INTERRUPT_PROPERTY; | |
| #pragma pack () | |
| RETURN_STATUS | |
| EFIAPI | |
| ArmVirtTimerFdtClientLibConstructor ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| FDT_CLIENT_PROTOCOL *FdtClient; | |
| CONST INTERRUPT_PROPERTY *InterruptProp; | |
| UINT32 PropSize; | |
| INT32 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum; | |
| INT32 HypVirtIntrNum; | |
| RETURN_STATUS PcdStatus; | |
| Status = gBS->LocateProtocol ( | |
| &gFdtClientProtocolGuid, | |
| NULL, | |
| (VOID **)&FdtClient | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = FdtClient->FindCompatibleNodeProperty ( | |
| FdtClient, | |
| "arm,armv7-timer", | |
| "interrupts", | |
| (CONST VOID **)&InterruptProp, | |
| &PropSize | |
| ); | |
| if (Status == EFI_NOT_FOUND) { | |
| Status = FdtClient->FindCompatibleNodeProperty ( | |
| FdtClient, | |
| "arm,armv8-timer", | |
| "interrupts", | |
| (CONST VOID **)&InterruptProp, | |
| &PropSize | |
| ); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // - interrupts : Interrupt list for secure, non-secure, virtual, | |
| // hypervisor and hypervisor virtual timers, in that order. | |
| // | |
| ASSERT (PropSize >= 36); | |
| SecIntrNum = SwapBytes32 (InterruptProp[0].Number) | |
| + (InterruptProp[0].Type ? 16 : 0); | |
| IntrNum = SwapBytes32 (InterruptProp[1].Number) | |
| + (InterruptProp[1].Type ? 16 : 0); | |
| VirtIntrNum = SwapBytes32 (InterruptProp[2].Number) | |
| + (InterruptProp[2].Type ? 16 : 0); | |
| HypIntrNum = PropSize < 48 ? 0 : SwapBytes32 (InterruptProp[3].Number) | |
| + (InterruptProp[3].Type ? 16 : 0); | |
| HypVirtIntrNum = PropSize < 60 ? 0 : SwapBytes32 (InterruptProp[4].Number) | |
| + (InterruptProp[4].Type ? 16 : 0); | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "Found Timer interrupts %d, %d, %d, %d\n", | |
| SecIntrNum, | |
| IntrNum, | |
| VirtIntrNum, | |
| HypIntrNum | |
| )); | |
| PcdStatus = PcdSet32S (PcdArmArchTimerSecIntrNum, SecIntrNum); | |
| ASSERT_RETURN_ERROR (PcdStatus); | |
| PcdStatus = PcdSet32S (PcdArmArchTimerIntrNum, IntrNum); | |
| ASSERT_RETURN_ERROR (PcdStatus); | |
| PcdStatus = PcdSet32S (PcdArmArchTimerVirtIntrNum, VirtIntrNum); | |
| ASSERT_RETURN_ERROR (PcdStatus); | |
| PcdStatus = PcdSet32S (PcdArmArchTimerHypIntrNum, HypIntrNum); | |
| ASSERT_RETURN_ERROR (PcdStatus); | |
| PcdStatus = PcdSet32S (PcdArmArchTimerHypVirtIntrNum, HypVirtIntrNum); | |
| ASSERT_RETURN_ERROR (PcdStatus); | |
| return EFI_SUCCESS; | |
| } |