/** @file
Copyright (c) 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
/**
Read PCR register. (This is internal function)
It returns PCR register and size in 1byte/2bytes/4bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of this Port ID
@param[in] Size Size for read. Must be 1 or 2 or 4.
@param[out] OutData Buffer of Output Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
STATIC
EFI_STATUS
PchPcrRead (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
IN UINTN Size,
OUT UINT32 *OutData
)
{
if ((Offset & (Size - 1)) != 0) {
DEBUG ((DEBUG_ERROR, "PchPcrRead error. Invalid Offset: %x Size: %x", Offset, Size));
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
//
// @todo SKL PCH: check PID that not expected to use this routine, such as CAM_FLIS, CSME0
//
switch (Size) {
case 4:
*(UINT32*)OutData = MmioRead32 (PCH_PCR_ADDRESS (Pid, Offset));
break;
case 2:
*(UINT16*)OutData = MmioRead16 (PCH_PCR_ADDRESS (Pid, Offset));
break;
case 1:
*(UINT8*) OutData = MmioRead8 (PCH_PCR_ADDRESS (Pid, Offset));
break;
default:
break;
}
return EFI_SUCCESS;
}
/**
Read PCR register.
It returns PCR register and size in 4bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of this Port ID
@param[out] OutData Buffer of Output Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
EFI_STATUS
PchPcrRead32 (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
OUT UINT32 *OutData
)
{
return PchPcrRead (Pid, Offset, 4, (UINT32*) OutData);
}
/**
Read PCR register.
It returns PCR register and size in 2bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of this Port ID
@param[out] OutData Buffer of Output Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
EFI_STATUS
PchPcrRead16 (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
OUT UINT16 *OutData
)
{
return PchPcrRead (Pid, Offset, 2, (UINT32*) OutData);
}
/**
Read PCR register.
It returns PCR register and size in 1bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of this Port ID
@param[out] OutData Buffer of Output Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
EFI_STATUS
PchPcrRead8 (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
OUT UINT8 *OutData
)
{
return PchPcrRead (Pid, Offset, 1, (UINT32*) OutData);
}
BOOLEAN
PchPcrWriteMmioCheck (
IN PCH_SBI_PID Pid,
IN UINT16 Offset
)
{
DEBUG_CODE_BEGIN();
PCH_SERIES PchSeries;
PchSeries = GetPchSeries ();
//
// 1. USB2 AFE register must use SBI method
//
//
// 2. GPIO unlock register field must use SBI method
//
if (Pid == PID_GPIOCOM0) {
if (((PchSeries == PchLp) &&
((Offset == R_PCH_LP_PCR_GPIO_GPP_A_PADCFGLOCK) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_A_PADCFGLOCKTX) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_B_PADCFGLOCK) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_B_PADCFGLOCKTX))) ||
((PchSeries == PchH) &&
((Offset == R_PCH_H_PCR_GPIO_GPP_A_PADCFGLOCK) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_A_PADCFGLOCKTX) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_B_PADCFGLOCK) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_B_PADCFGLOCKTX))))
{
return FALSE;
}
}
if (Pid == PID_GPIOCOM1) {
if (((PchSeries == PchLp) &&
((Offset == R_PCH_LP_PCR_GPIO_GPP_C_PADCFGLOCK) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_C_PADCFGLOCKTX) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_D_PADCFGLOCK) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_D_PADCFGLOCKTX) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_E_PADCFGLOCK) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_E_PADCFGLOCKTX))) ||
((PchSeries == PchH) &&
((Offset == R_PCH_H_PCR_GPIO_GPP_C_PADCFGLOCK) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_C_PADCFGLOCKTX) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_D_PADCFGLOCK) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_D_PADCFGLOCKTX) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_E_PADCFGLOCK) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_E_PADCFGLOCKTX) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_F_PADCFGLOCK) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_F_PADCFGLOCKTX) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_G_PADCFGLOCK) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_G_PADCFGLOCKTX) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_H_PADCFGLOCK) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_H_PADCFGLOCKTX))))
{
return FALSE;
}
}
if (Pid == PID_GPIOCOM2) {
if (((PchSeries == PchLp) &&
((Offset == R_PCH_LP_PCR_GPIO_GPD_PADCFGLOCK) ||
(Offset == R_PCH_LP_PCR_GPIO_GPD_PADCFGLOCKTX))) ||
((PchSeries == PchH) &&
((Offset == R_PCH_H_PCR_GPIO_GPD_PADCFGLOCK) ||
(Offset == R_PCH_H_PCR_GPIO_GPD_PADCFGLOCKTX))))
{
return FALSE;
}
}
if (Pid == PID_GPIOCOM3) {
if (((PchSeries == PchLp) &&
((Offset == R_PCH_LP_PCR_GPIO_GPP_F_PADCFGLOCK) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_F_PADCFGLOCKTX) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_G_PADCFGLOCK) ||
(Offset == R_PCH_LP_PCR_GPIO_GPP_G_PADCFGLOCKTX))) ||
((PchSeries == PchH) &&
((Offset == R_PCH_H_PCR_GPIO_GPP_I_PADCFGLOCK) ||
(Offset == R_PCH_H_PCR_GPIO_GPP_I_PADCFGLOCKTX))))
{
return FALSE;
}
}
//
// 3. CIO2 FLIS regsiter must use SBI method
//
//
// 4. CSME0 based PCR should use the SBI method due to the FID requirement
//
if (Pid == PID_CSME0) {
return FALSE;
}
DEBUG_CODE_END();
return TRUE;
}
/**
Write PCR register. (This is internal function)
It programs PCR register and size in 1byte/2bytes/4bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of Port ID.
@param[in] Size Size for read. Must be 1 or 2 or 4.
@param[in] AndData AND Data. Must be the same size as Size parameter.
@param[in] OrData OR Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
STATIC
EFI_STATUS
PchPcrWrite (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
IN UINTN Size,
IN UINT32 InData
)
{
if ((Offset & (Size - 1)) != 0) {
DEBUG ((DEBUG_ERROR, "PchPcrWrite error. Invalid Offset: %x Size: %x", Offset, Size));
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
DEBUG_CODE_BEGIN();
if (!PchPcrWriteMmioCheck (Pid, Offset)) {
DEBUG ((DEBUG_ERROR, "PchPcrWrite error. Pid: %x Offset: %x should access through SBI interface", Pid, Offset));
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
DEBUG_CODE_END();
//
// Write the PCR register with provided data
// Then read back PCR register to prevent from back to back write.
//
switch (Size) {
case 4:
MmioWrite32 (PCH_PCR_ADDRESS (Pid, Offset), (UINT32)InData);
break;
case 2:
MmioWrite16 (PCH_PCR_ADDRESS (Pid, Offset), (UINT16)InData);
break;
case 1:
MmioWrite8 (PCH_PCR_ADDRESS (Pid, Offset), (UINT8) InData);
break;
default:
break;
}
MmioRead32 (PCH_PCR_ADDRESS (PID_LPC, R_PCH_PCR_LPC_GCFD));
return EFI_SUCCESS;
}
/**
Write PCR register.
It programs PCR register and size in 4bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of Port ID.
@param[in] InData Input Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
EFI_STATUS
PchPcrWrite32 (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
IN UINT32 InData
)
{
return PchPcrWrite (Pid, Offset, 4, InData);
}
/**
Write PCR register.
It programs PCR register and size in 2bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of Port ID.
@param[in] InData Input Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
EFI_STATUS
PchPcrWrite16 (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
IN UINT16 InData
)
{
return PchPcrWrite (Pid, Offset, 2, InData);
}
/**
Write PCR register.
It programs PCR register and size in 1bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of Port ID.
@param[in] InData Input Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
EFI_STATUS
PchPcrWrite8 (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
IN UINT8 InData
)
{
return PchPcrWrite (Pid, Offset, 1, InData);
}
/**
Write PCR register.
It programs PCR register and size in 4bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of Port ID.
@param[in] AndData AND Data. Must be the same size as Size parameter.
@param[in] OrData OR Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
EFI_STATUS
PchPcrAndThenOr32 (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
IN UINT32 AndData,
IN UINT32 OrData
)
{
EFI_STATUS Status;
UINT32 Data32;
Data32 = 0x00;
Status = PchPcrRead (Pid, Offset, 4, &Data32);
if (EFI_ERROR (Status)) {
return Status;
}
Data32 &= AndData;
Data32 |= OrData;
Status = PchPcrWrite (Pid, Offset, 4, Data32);
return Status;
}
/**
Write PCR register.
It programs PCR register and size in 2bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of Port ID.
@param[in] AndData AND Data. Must be the same size as Size parameter.
@param[in] OrData OR Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
EFI_STATUS
PchPcrAndThenOr16 (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
IN UINT16 AndData,
IN UINT16 OrData
)
{
EFI_STATUS Status;
UINT16 Data16;
Data16 = 0x00;
Status = PchPcrRead (Pid, Offset, 2, (UINT32*) &Data16);
if (EFI_ERROR (Status)) {
return Status;
}
Data16 &= AndData;
Data16 |= OrData;
Status = PchPcrWrite (Pid, Offset, 2, Data16);
return Status;
}
/**
Write PCR register.
It programs PCR register and size in 1bytes.
The Offset should not exceed 0xFFFF and must be aligned with size.
@param[in] Pid Port ID
@param[in] Offset Register offset of Port ID.
@param[in] AndData AND Data. Must be the same size as Size parameter.
@param[in] OrData OR Data. Must be the same size as Size parameter.
@retval EFI_SUCCESS Successfully completed.
@retval EFI_INVALID_PARAMETER Invalid offset passed.
**/
EFI_STATUS
PchPcrAndThenOr8 (
IN PCH_SBI_PID Pid,
IN UINT16 Offset,
IN UINT8 AndData,
IN UINT8 OrData
)
{
EFI_STATUS Status;
UINT8 Data8;
Status = PchPcrRead (Pid, Offset, 1, (UINT32*) &Data8);
if (EFI_ERROR (Status)) {
return Status;
}
Data8 &= AndData;
Data8 |= OrData;
Status = PchPcrWrite (Pid, Offset, 1, Data8);
return Status;
}