/** @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 <Guid/Cper.h>
|
#include <IndustryStandard/Acpi62.h>
|
#include <Library/DebugLib.h>
|
#include <Library/IoLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include "Bert/Bert.h"
|
#include "Einj/Einj.h"
|
#include "ErrorSource/Ghes.h"
|
#include "Erst/Erst.h"
|
#include "Hest/Hest.h"
|
#include "OemApeiHi1620.h"
|
|
VOID
|
GpioCombInit (
|
UINTN Base,
|
UINT32 Pin
|
)
|
{
|
UINT32 Val = MmioRead32 (Base + GPIO_INT_MASK);
|
MmioWrite32 (Base + GPIO_INT_MASK, Val | Pin);
|
Val = MmioRead32 (Base + GPIO_INT_EN);
|
MmioWrite32 (Base + GPIO_INT_EN, Val | Pin);
|
Val = MmioRead32 (Base + GPIO_SWPORT_DDR);
|
MmioWrite32 (Base + GPIO_SWPORT_DDR, Val & (~Pin));
|
Val = MmioRead32 (Base + GPIO_INT_TYPE);
|
MmioWrite32 (Base + GPIO_INT_TYPE, Val & (~Pin));
|
Val = MmioRead32 (Base + GPIO_INT_POLARITY);
|
MmioWrite32 (Base + GPIO_INT_POLARITY, Val | Pin);
|
Val = MmioRead32 (Base + GPIO_LS_SYNC);
|
MmioWrite32 (Base + GPIO_LS_SYNC, Val & (~Pin));
|
MmioWrite32 (Base + GPIO_INT_COMB, 1);
|
return;
|
}
|
/************************************************
|
*************** HEST ***************
|
************************************************/
|
|
/*****************************************************************************
|
* @param EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE* GhesV2,Vector of GhesV2
|
* @param UINT8 NumOfGhesV2
|
* @param_out
|
* @retval EFI_STATUS
|
*****************************************************************************/
|
EFI_STATUS
|
GhesV2ContextForHest (
|
IN EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE GhesV2[MAX_GHES],
|
IN UINT8 NumOfGhesV2
|
)
|
{
|
// ensuce the size is expected
|
if ((GhesV2 == NULL) || (NumOfGhesV2 != MAX_GHES)) {
|
return EFI_INVALID_PARAMETER;
|
}
|
|
UINT8 NumOfBlockPerGhes = 1;
|
UINT8 Iter = 0;
|
UINT32 BlockMemorySize;
|
UINT32 ErrorSeverityArray[MAX_GHES] = {
|
EFI_ACPI_6_2_ERROR_SEVERITY_CORRECTABLE,
|
EFI_ACPI_6_2_ERROR_SEVERITY_FATAL,
|
EFI_ACPI_6_2_ERROR_SEVERITY_CORRECTED};
|
VOID *ErrorBlockHead;
|
VOID *ErrorBlock;
|
VOID *BlockMemory;
|
GHES_REGISTER *GhesRegisters;
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
BlockMemorySize = MAX_GHES *
|
(sizeof (GHES_REGISTER) + NumOfBlockPerGhes * GENERIC_HARDWARE_ERROR_BLOCK_SIZE);
|
Status = gBS->AllocatePool (
|
EfiReservedMemoryType,
|
BlockMemorySize,
|
&BlockMemory
|
);
|
if (EFI_ERROR (Status)) {
|
return Status;
|
}
|
gBS->SetMem (BlockMemory, BlockMemorySize, 0);
|
GhesRegisters = BlockMemory;
|
ErrorBlockHead = BlockMemory + MAX_GHES * sizeof (GHES_REGISTER);
|
ErrorBlock = ErrorBlockHead;
|
for (Iter = 0; Iter < MAX_GHES; Iter++) {
|
GhesV2Initial (&GhesV2[Iter], GENERIC_HARDWARE_ERROR_BLOCK_SIZE);
|
GhesV2AddNotification (&GhesV2[Iter], EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_GSIV);
|
ErrorBlockInitial (ErrorBlock, ErrorSeverityArray[Iter]);
|
GhesV2LinkErrorBlock (&GhesV2[Iter], &GhesRegisters[Iter], ErrorBlock);
|
ErrorBlock += GhesV2[Iter].ErrorStatusBlockLength;
|
}
|
return EFI_SUCCESS;
|
}
|
/*****************************************************************************
|
* @param EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE* GhesV2,Vector of GhesV2
|
* @param UINT8 NumOfGhesV2
|
* @param_out
|
* @retval EFI_STATUS
|
*****************************************************************************/
|
|
EFI_STATUS
|
GhesV1ContextForHest (
|
IN EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE GhesV1[MAX_GHES],
|
IN UINT8 NumOfGhesV1
|
)
|
{
|
// ensuce the size is expected
|
if ((GhesV1 == NULL) || (NumOfGhesV1 != MAX_GHES)) {
|
return EFI_INVALID_PARAMETER;
|
}
|
|
UINT8 NumOfBlockPerGhes = 1;
|
UINT8 Iter = 0;
|
UINT32 BlockMemorySize = MAX_GHES *
|
(sizeof (UINT64) + NumOfBlockPerGhes * GENERIC_HARDWARE_ERROR_BLOCK_SIZE);
|
UINT32 ErrorSeverityArray[MAX_GHES] = {
|
EFI_ACPI_6_2_ERROR_SEVERITY_CORRECTABLE,
|
EFI_ACPI_6_2_ERROR_SEVERITY_FATAL,
|
EFI_ACPI_6_2_ERROR_SEVERITY_CORRECTED};
|
VOID *ErrorBlockHead;
|
VOID *ErrorBlock;
|
VOID *BlockMemory;
|
UINT64 *ptrBlockAddress;
|
EFI_STATUS Status = EFI_SUCCESS;
|
Status = gBS->AllocatePool (
|
EfiReservedMemoryType,
|
BlockMemorySize,
|
&BlockMemory
|
);
|
if (EFI_ERROR (Status)) {
|
return Status;
|
}
|
gBS->SetMem (BlockMemory, BlockMemorySize, 0);
|
ptrBlockAddress = BlockMemory;
|
ErrorBlockHead = BlockMemory + MAX_GHES * sizeof (UINT64);
|
ErrorBlock = ErrorBlockHead;
|
for (Iter = 0; Iter < MAX_GHES; Iter++) {
|
GhesV1Initial (&GhesV1[Iter], GENERIC_HARDWARE_ERROR_BLOCK_SIZE);
|
GhesV1AddNotification (&GhesV1[Iter], EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_GSIV);
|
ErrorBlockInitial (ErrorBlock, ErrorSeverityArray[Iter]);
|
GhesV1LinkErrorBlock (&GhesV1[Iter], &ptrBlockAddress[Iter], ErrorBlock);
|
ErrorBlock += GhesV1[Iter].ErrorStatusBlockLength;
|
}
|
return EFI_SUCCESS;
|
}
|
|
VOID
|
OemHestInitialNotification ()
|
{
|
// GPIO init
|
// use int_msk to simulate
|
UINTN Base = IOMUX_REG_BASE;
|
//GPIO9, in document 'PhosphorV680 Totemiomux' iomg051,
|
//Set GPIO9 to pad_ex_int1
|
MmioWrite32 (Base + IOMG051, PAD_EX_INT1);
|
return;
|
}
|
|
VOID
|
OemEinjInitialNotification ()
|
{
|
UINTN Base = IOMUX_REG_BASE;
|
//use TB_GPIO_PIN10 for EINJ
|
MmioWrite32 (Base + IOMG052, PAD_EX_INT1);
|
return;
|
}
|
|
EFI_STATUS
|
OemInitHestTable (
|
IN EFI_HANDLE ImageHandle
|
)
|
{
|
EFI_STATUS Status = EFI_SUCCESS;
|
HEST_CONTEXT HestContext;
|
EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE GhesV2[MAX_GHES];
|
Status = HestHeaderCreator (&HestContext, HEST_TABLE_SIZE);
|
if (EFI_ERROR (Status)) {
|
return Status;
|
}
|
Status = GhesV2ContextForHest(GhesV2, MAX_GHES);
|
if (EFI_ERROR (Status)) {
|
return Status;
|
}
|
Status |= HestAddErrorSourceDescriptor (
|
&HestContext,
|
&GhesV2[0],
|
sizeof (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE)
|
);
|
mApeiTrustedfirmwareData->HestRecoverableErrorGhesV2 = HestContext.KeyErrorSource;
|
Status |= HestAddErrorSourceDescriptor (
|
&HestContext,
|
&GhesV2[1],
|
sizeof (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE)
|
);
|
mApeiTrustedfirmwareData->HestFatalErrorGhesV2 = HestContext.KeyErrorSource;
|
Status |= HestAddErrorSourceDescriptor (
|
&HestContext,
|
&GhesV2[2],
|
sizeof (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE)
|
);
|
mApeiTrustedfirmwareData->HestCorrectedErrorGhesV2 = HestContext.KeyErrorSource;
|
OemHestInitialNotification ();
|
HestSetAcpiTable (&HestContext);
|
return Status;
|
}
|
/************************************************
|
*************** BERT ***************
|
************************************************/
|
|
EFI_STATUS
|
OemInitBertTable (
|
IN EFI_HANDLE ImageHandle
|
)
|
{
|
BERT_CONTEXT Context;
|
BOOLEAN Status;
|
Status = BertHeaderCreator (&Context, BOOT_ERROR_REGION_SIZE);
|
if (EFI_ERROR (Status)) {
|
return Status;
|
}
|
ErrorBlockInitial (Context.Block, EFI_ACPI_6_2_ERROR_SEVERITY_NONE);
|
BertSetAcpiTable (&Context);
|
DEBUG ((DEBUG_INFO, "[%a]:[%dL]: %r\n", __FUNCTION__, __LINE__, Status));
|
return EFI_SUCCESS;
|
}
|
/************************************************
|
*************** EINJ ***************
|
************************************************/
|
EFI_STATUS
|
OemEinjConfigExecuteOperationEntry (
|
EINJ_CONTEXT *Context
|
)
|
{
|
EFI_ACPI_6_0_EINJ_INJECTION_INSTRUCTION_ENTRY* KeyEntry = Context->ExecuteOperationEntry;
|
OemEinjInitialNotification ();
|
//use TB_GPIO_PIN10 for EINJ
|
KeyEntry->RegisterRegion.Address = PcdGet64 (PcdCpldBaseAddress) + CPLD_GPIO10_INT_OFFSET;
|
KeyEntry->Mask = CPLD_MASK;
|
KeyEntry->Value = CPLD_VALUE;
|
return EFI_SUCCESS;
|
}
|
|
EFI_STATUS
|
OemInitEinjTable (
|
)
|
{
|
EFI_STATUS Status;
|
EINJ_CONTEXT Context;
|
Status = EinjHeaderCreator (&Context);
|
if (EFI_ERROR (Status)) {
|
return Status;
|
}
|
(VOID)EinjConfigErrorInjectCapability (&Context, 0xFFF);// TBD
|
(VOID)OemEinjConfigExecuteOperationEntry (&Context);
|
EinjSetAcpiTable (&Context);
|
DEBUG ((DEBUG_INFO, "[%a]:[%dL]: %d\n", __FUNCTION__, __LINE__, Status));
|
return EFI_SUCCESS;
|
}
|
/************************************************
|
*************** ERST ***************
|
************************************************/
|
|
EFI_STATUS
|
OemErstConfigExecuteOperationEntry (
|
ERST_BOOT_CONTEXT *Context
|
)
|
{
|
EFI_ACPI_6_1_ERST_SERIALIZATION_INSTRUCTION_ENTRY *KeyEntry;
|
KeyEntry = Context->ExecuteOperationEntry;
|
KeyEntry->RegisterRegion.Address = GPIO1_BASE + GPIO_INT_MASK;
|
KeyEntry->Value = 0x10;
|
KeyEntry->Mask = 0xFFFFFFFF;
|
GpioCombInit (GPIO1_BASE, 0xFFFF);
|
return EFI_SUCCESS;
|
}
|
|
BOOLEAN
|
GetNvRamRegion (
|
OUT VOID **NvRamAddrRange,
|
OUT UINT64 *NvRamAddrRangeLength
|
)
|
{
|
UINT32 Store = ERST_RECORD_STORE_IN_MEM;
|
switch (Store) {
|
case (ERST_RECORD_STORE_IN_NVRAM):
|
break;
|
case (ERST_RECORD_STORE_IN_MEM):
|
* NvRamAddrRangeLength = ERST_DATASTORE_SIZE;
|
* NvRamAddrRange = AllocateReservedZeroPool (ERST_DATASTORE_SIZE);
|
break;
|
case (ERST_RECORD_STORE_IN_SPI_FLASH):
|
break;
|
default:
|
;
|
}
|
return TRUE;
|
}
|
|
/***OEM***/
|
EFI_STATUS
|
OemInitErstTable (
|
)
|
{
|
EFI_STATUS Status = ERST_STATUS_SUCCESS;
|
ERST_BOOT_CONTEXT Context;
|
UINT64 BufferSize = ERST_DATASTORE_SIZE;
|
VOID *NvRamAddrRange;
|
UINT64 NvRamAddrRangeLength;
|
UINT64 NvRamAllRecordLength;
|
|
GetNvRamRegion (&NvRamAddrRange, &NvRamAddrRangeLength);
|
NvRamAllRecordLength = 0;
|
Status = ErstHeaderCreator (
|
&Context,
|
BufferSize,
|
NvRamAddrRange,
|
NvRamAllRecordLength,
|
NvRamAddrRangeLength);
|
OemErstConfigExecuteOperationEntry (&Context);
|
mApeiTrustedfirmwareData->ErstContext = (VOID*)Context.Rt;
|
ErstSetAcpiTable (&Context);
|
return Status;
|
};
|