| /** @file | |
| Functions for processor information common to AARCH64. | |
| Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> | |
| Copyright (c) 2021 - 2022, Ampere Computing LLC. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Uefi.h> | |
| #include <IndustryStandard/ArmCache.h> | |
| #include <IndustryStandard/ArmStdSmc.h> | |
| #include <IndustryStandard/SmBios.h> | |
| #include <Library/ArmLib.h> | |
| #include <Library/ArmSmcLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include "SmbiosProcessor.h" | |
| /** Returns the maximum cache level implemented by the current CPU. | |
| @return The maximum cache level implemented. | |
| **/ | |
| UINT8 | |
| SmbiosProcessorGetMaxCacheLevel ( | |
| VOID | |
| ) | |
| { | |
| CLIDR_DATA Clidr; | |
| UINT8 CacheLevel; | |
| UINT8 MaxCacheLevel; | |
| MaxCacheLevel = 0; | |
| // Read the CLIDR register to find out what caches are present. | |
| Clidr.Data = ReadCLIDR (); | |
| // Get the cache type for the L1 cache. If it's 0, there are no caches. | |
| if (CLIDR_GET_CACHE_TYPE (Clidr.Data, 1) == ClidrCacheTypeNone) { | |
| return 0; | |
| } | |
| for (CacheLevel = 1; CacheLevel <= MAX_ARM_CACHE_LEVEL; CacheLevel++) { | |
| if (CLIDR_GET_CACHE_TYPE (Clidr.Data, CacheLevel) == ClidrCacheTypeNone) { | |
| MaxCacheLevel = CacheLevel; | |
| break; | |
| } | |
| } | |
| return MaxCacheLevel; | |
| } | |
| /** Returns whether or not the specified cache level has separate I/D caches. | |
| @param CacheLevel The cache level (L1, L2 etc.). | |
| @return TRUE if the cache level has separate I/D caches, FALSE otherwise. | |
| **/ | |
| BOOLEAN | |
| SmbiosProcessorHasSeparateCaches ( | |
| UINT8 CacheLevel | |
| ) | |
| { | |
| CLIDR_CACHE_TYPE CacheType; | |
| CLIDR_DATA Clidr; | |
| BOOLEAN SeparateCaches; | |
| SeparateCaches = FALSE; | |
| Clidr.Data = ReadCLIDR (); | |
| CacheType = CLIDR_GET_CACHE_TYPE (Clidr.Data, CacheLevel - 1); | |
| if (CacheType == ClidrCacheTypeSeparate) { | |
| SeparateCaches = TRUE; | |
| } | |
| return SeparateCaches; | |
| } | |
| /** Checks if ther ARM64 SoC ID SMC call is supported | |
| @return Whether the ARM64 SoC ID call is supported. | |
| **/ | |
| BOOLEAN | |
| HasSmcArm64SocId ( | |
| VOID | |
| ) | |
| { | |
| INT32 SmcCallStatus; | |
| BOOLEAN Arm64SocIdSupported; | |
| UINTN SmcParam; | |
| Arm64SocIdSupported = FALSE; | |
| SmcCallStatus = ArmCallSmc0 (SMCCC_VERSION, NULL, NULL, NULL); | |
| if ((SmcCallStatus < 0) || ((SmcCallStatus >> 16) >= 1)) { | |
| SmcParam = SMCCC_ARCH_SOC_ID; | |
| SmcCallStatus = ArmCallSmc1 (SMCCC_ARCH_FEATURES, &SmcParam, NULL, NULL); | |
| if (SmcCallStatus >= 0) { | |
| Arm64SocIdSupported = TRUE; | |
| } | |
| } | |
| return Arm64SocIdSupported; | |
| } | |
| /** Fetches the JEP106 code and SoC Revision. | |
| @param Jep106Code JEP 106 code. | |
| @param SocRevision SoC revision. | |
| @retval EFI_SUCCESS Succeeded. | |
| @retval EFI_UNSUPPORTED Failed. | |
| **/ | |
| EFI_STATUS | |
| SmbiosGetSmcArm64SocId ( | |
| OUT INT32 *Jep106Code, | |
| OUT INT32 *SocRevision | |
| ) | |
| { | |
| INT32 SmcCallStatus; | |
| EFI_STATUS Status; | |
| UINTN SmcParam; | |
| Status = EFI_SUCCESS; | |
| SmcParam = 0; | |
| SmcCallStatus = ArmCallSmc1 (SMCCC_ARCH_SOC_ID, &SmcParam, NULL, NULL); | |
| if (SmcCallStatus >= 0) { | |
| *Jep106Code = SmcCallStatus; | |
| } else { | |
| Status = EFI_UNSUPPORTED; | |
| } | |
| SmcParam = 1; | |
| SmcCallStatus = ArmCallSmc1 (SMCCC_ARCH_SOC_ID, &SmcParam, NULL, NULL); | |
| if (SmcCallStatus >= 0) { | |
| *SocRevision = SmcCallStatus; | |
| } else { | |
| Status = EFI_UNSUPPORTED; | |
| } | |
| return Status; | |
| } | |
| /** Returns a value for the Processor ID field that conforms to SMBIOS | |
| requirements. | |
| @return Processor ID. | |
| **/ | |
| UINT64 | |
| SmbiosGetProcessorId ( | |
| VOID | |
| ) | |
| { | |
| INT32 Jep106Code; | |
| INT32 SocRevision; | |
| UINT64 ProcessorId; | |
| if (HasSmcArm64SocId ()) { | |
| SmbiosGetSmcArm64SocId (&Jep106Code, &SocRevision); | |
| ProcessorId = ((UINT64)SocRevision << 32) | Jep106Code; | |
| } else { | |
| ProcessorId = ArmReadMidr (); | |
| } | |
| return ProcessorId; | |
| } | |
| /** Returns the external clock frequency. | |
| @return The external clock frequency. | |
| **/ | |
| UINTN | |
| SmbiosGetExternalClockFrequency ( | |
| VOID | |
| ) | |
| { | |
| return ArmReadCntFrq (); | |
| } | |
| /** Returns the SMBIOS ProcessorFamily field value. | |
| @return The value for the ProcessorFamily field. | |
| **/ | |
| UINT8 | |
| SmbiosGetProcessorFamily ( | |
| VOID | |
| ) | |
| { | |
| return ProcessorFamilyIndicatorFamily2; | |
| } | |
| /** Returns the ProcessorFamily2 field value. | |
| @return The value for the ProcessorFamily2 field. | |
| **/ | |
| UINT16 | |
| SmbiosGetProcessorFamily2 ( | |
| VOID | |
| ) | |
| { | |
| UINTN MainIdRegister; | |
| UINT16 ProcessorFamily2; | |
| MainIdRegister = ArmReadMidr (); | |
| if (((MainIdRegister >> 16) & 0xF) < 8) { | |
| ProcessorFamily2 = ProcessorFamilyARM; | |
| } else { | |
| if (sizeof (VOID *) == 4) { | |
| ProcessorFamily2 = ProcessorFamilyARMv7; | |
| } else { | |
| ProcessorFamily2 = ProcessorFamilyARMv8; | |
| } | |
| } | |
| return ProcessorFamily2; | |
| } | |
| /** Returns the SMBIOS Processor Characteristics. | |
| @return Processor Characteristics bitfield. | |
| **/ | |
| PROCESSOR_CHARACTERISTIC_FLAGS | |
| SmbiosGetProcessorCharacteristics ( | |
| VOID | |
| ) | |
| { | |
| PROCESSOR_CHARACTERISTIC_FLAGS Characteristics; | |
| ZeroMem (&Characteristics, sizeof (Characteristics)); | |
| Characteristics.ProcessorArm64SocId = HasSmcArm64SocId (); | |
| return Characteristics; | |
| } |