audk/QuarkPlatformPkg/Library/PlatformHelperLib/PlatformHelperLib.c

482 lines
12 KiB
C

/** @file
Helper routines with common PEI / DXE implementation.
Copyright (c) 2013-2016 Intel Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "CommonHeader.h"
#include <Library/I2cLib.h>
CHAR16 *mPlatTypeNameTable[] = { EFI_PLATFORM_TYPE_NAME_TABLE_DEFINITION };
UINTN mPlatTypeNameTableLen = ((sizeof(mPlatTypeNameTable)) / sizeof (CHAR16 *));
//
// Routines defined in other source modules of this component.
//
//
// Routines local to this source module.
//
//
// Routines shared with other souce modules in this component.
//
EFI_STATUS
WriteFirstFreeSpiProtect (
IN CONST UINT32 PchRootComplexBar,
IN CONST UINT32 DirectValue,
IN CONST UINT32 BaseAddress,
IN CONST UINT32 Length,
OUT UINT32 *OffsetPtr
)
{
UINT32 RegVal;
UINT32 Offset;
UINT32 StepLen;
ASSERT (PchRootComplexBar > 0);
Offset = 0;
if (OffsetPtr != NULL) {
*OffsetPtr = Offset;
}
if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) == 0) {
Offset = R_QNC_RCRB_SPIPBR0;
} else {
if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR1) == 0) {
Offset = R_QNC_RCRB_SPIPBR1;
} else {
if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR2) == 0) {
Offset = R_QNC_RCRB_SPIPBR2;
}
}
}
if (Offset != 0) {
if (DirectValue == 0) {
StepLen = ALIGN_VALUE (Length,SIZE_4KB); // Bring up to 4K boundary.
RegVal = BaseAddress + StepLen - 1;
RegVal &= 0x00FFF000; // Set EDS Protected Range Limit (PRL).
RegVal |= ((BaseAddress >> 12) & 0xfff); // or in EDS Protected Range Base (PRB).
} else {
RegVal = DirectValue;
}
//
// Enable protection.
//
RegVal |= B_QNC_RCRB_SPIPBRn_WPE;
MmioWrite32 (PchRootComplexBar + Offset, RegVal);
if (RegVal == MmioRead32 (PchRootComplexBar + Offset)) {
if (OffsetPtr != NULL) {
*OffsetPtr = Offset;
}
return EFI_SUCCESS;
}
return EFI_DEVICE_ERROR;
}
return EFI_NOT_FOUND;
}
//
// Routines exported by this component.
//
/**
Clear SPI Protect registers.
@retval EFI_SUCCESS SPI protect registers cleared.
@retval EFI_ACCESS_DENIED Unable to clear SPI protect registers.
**/
EFI_STATUS
EFIAPI
PlatformClearSpiProtect (
VOID
)
{
UINT32 PchRootComplexBar;
PchRootComplexBar = QNC_RCRB_BASE;
//
// Check if the SPI interface has been locked-down.
//
if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {
return EFI_ACCESS_DENIED;
}
MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0, 0);
if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) {
return EFI_ACCESS_DENIED;
}
MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR1, 0);
if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) {
return EFI_ACCESS_DENIED;
}
MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR2, 0);
if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) {
return EFI_ACCESS_DENIED;
}
return EFI_SUCCESS;
}
/**
Determine if an SPI address range is protected.
@param SpiBaseAddress Base of SPI range.
@param Length Length of SPI range.
@retval TRUE Range is protected.
@retval FALSE Range is not protected.
**/
BOOLEAN
EFIAPI
PlatformIsSpiRangeProtected (
IN CONST UINT32 SpiBaseAddress,
IN CONST UINT32 Length
)
{
UINT32 RegVal;
UINT32 Offset;
UINT32 Limit;
UINT32 ProtectedBase;
UINT32 ProtectedLimit;
UINT32 PchRootComplexBar;
PchRootComplexBar = QNC_RCRB_BASE;
if (Length > 0) {
Offset = R_QNC_RCRB_SPIPBR0;
Limit = SpiBaseAddress + (Length - 1);
do {
RegVal = MmioRead32 (PchRootComplexBar + Offset);
if ((RegVal & B_QNC_RCRB_SPIPBRn_WPE) != 0) {
ProtectedBase = (RegVal & 0xfff) << 12;
ProtectedLimit = (RegVal & 0x00fff000) + 0xfff;
if (SpiBaseAddress >= ProtectedBase && Limit <= ProtectedLimit) {
return TRUE;
}
}
if (Offset == R_QNC_RCRB_SPIPBR0) {
Offset = R_QNC_RCRB_SPIPBR1;
} else if (Offset == R_QNC_RCRB_SPIPBR1) {
Offset = R_QNC_RCRB_SPIPBR2;
} else {
break;
}
} while (TRUE);
}
return FALSE;
}
/**
Set Legacy GPIO Level
@param LevelRegOffset GPIO level register Offset from GPIO Base Address.
@param GpioNum GPIO bit to change.
@param HighLevel If TRUE set GPIO High else Set GPIO low.
**/
VOID
EFIAPI
PlatformLegacyGpioSetLevel (
IN CONST UINT32 LevelRegOffset,
IN CONST UINT32 GpioNum,
IN CONST BOOLEAN HighLevel
)
{
UINT32 RegValue;
UINT32 GpioBaseAddress;
UINT32 GpioNumMask;
GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;
ASSERT (GpioBaseAddress > 0);
RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset);
GpioNumMask = (1 << GpioNum);
if (HighLevel) {
RegValue |= (GpioNumMask);
} else {
RegValue &= ~(GpioNumMask);
}
IoWrite32 (GpioBaseAddress + LevelRegOffset, RegValue);
}
/**
Get Legacy GPIO Level
@param LevelRegOffset GPIO level register Offset from GPIO Base Address.
@param GpioNum GPIO bit to check.
@retval TRUE If bit is SET.
@retval FALSE If bit is CLEAR.
**/
BOOLEAN
EFIAPI
PlatformLegacyGpioGetLevel (
IN CONST UINT32 LevelRegOffset,
IN CONST UINT32 GpioNum
)
{
UINT32 RegValue;
UINT32 GpioBaseAddress;
UINT32 GpioNumMask;
GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;
RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset);
GpioNumMask = (1 << GpioNum);
return ((RegValue & GpioNumMask) != 0);
}
BOOLEAN
Pcal9555GetPortRegBit (
IN CONST UINT32 Pcal9555SlaveAddr,
IN CONST UINT32 GpioNum,
IN CONST UINT8 RegBase
)
{
EFI_STATUS Status;
UINTN ReadLength;
UINTN WriteLength;
UINT8 Data[2];
EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr;
EFI_I2C_ADDR_MODE I2cAddrMode;
UINT8 *RegValuePtr;
UINT8 GpioNumMask;
UINT8 SubAddr;
I2cDeviceAddr.I2CDeviceAddress = (UINTN)Pcal9555SlaveAddr;
I2cAddrMode = EfiI2CSevenBitAddrMode;
if (GpioNum < 8) {
SubAddr = RegBase;
GpioNumMask = (UINT8)(1 << GpioNum);
} else {
SubAddr = RegBase + 1;
GpioNumMask = (UINT8)(1 << (GpioNum - 8));
}
//
// Output port value always at 2nd byte in Data variable.
//
RegValuePtr = &Data[1];
//
// On read entry sub address at 2nd byte, on read exit output
// port value in 2nd byte.
//
Data[1] = SubAddr;
WriteLength = 1;
ReadLength = 1;
Status = I2cReadMultipleByte (
I2cDeviceAddr,
I2cAddrMode,
&WriteLength,
&ReadLength,
&Data[1]
);
ASSERT_EFI_ERROR (Status);
//
// Adjust output port bit given callers request.
//
return ((*RegValuePtr & GpioNumMask) != 0);
}
VOID
Pcal9555SetPortRegBit (
IN CONST UINT32 Pcal9555SlaveAddr,
IN CONST UINT32 GpioNum,
IN CONST UINT8 RegBase,
IN CONST BOOLEAN LogicOne
)
{
EFI_STATUS Status;
UINTN ReadLength;
UINTN WriteLength;
UINT8 Data[2];
EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr;
EFI_I2C_ADDR_MODE I2cAddrMode;
UINT8 *RegValuePtr;
UINT8 GpioNumMask;
UINT8 SubAddr;
I2cDeviceAddr.I2CDeviceAddress = (UINTN)Pcal9555SlaveAddr;
I2cAddrMode = EfiI2CSevenBitAddrMode;
if (GpioNum < 8) {
SubAddr = RegBase;
GpioNumMask = (UINT8)(1 << GpioNum);
} else {
SubAddr = RegBase + 1;
GpioNumMask = (UINT8)(1 << (GpioNum - 8));
}
//
// Output port value always at 2nd byte in Data variable.
//
RegValuePtr = &Data[1];
//
// On read entry sub address at 2nd byte, on read exit output
// port value in 2nd byte.
//
Data[1] = SubAddr;
WriteLength = 1;
ReadLength = 1;
Status = I2cReadMultipleByte (
I2cDeviceAddr,
I2cAddrMode,
&WriteLength,
&ReadLength,
&Data[1]
);
ASSERT_EFI_ERROR (Status);
//
// Adjust output port bit given callers request.
//
if (LogicOne) {
*RegValuePtr = *RegValuePtr | GpioNumMask;
} else {
*RegValuePtr = *RegValuePtr & ~(GpioNumMask);
}
//
// Update register. Sub address at 1st byte, value at 2nd byte.
//
WriteLength = 2;
Data[0] = SubAddr;
Status = I2cWriteMultipleByte (
I2cDeviceAddr,
I2cAddrMode,
&WriteLength,
Data
);
ASSERT_EFI_ERROR (Status);
}
/**
Set the direction of Pcal9555 IO Expander GPIO pin.
@param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
@param GpioNum Gpio direction to configure - values 0-7 for Port0
and 8-15 for Port1.
@param CfgAsInput If TRUE set pin direction as input else set as output.
**/
VOID
EFIAPI
PlatformPcal9555GpioSetDir (
IN CONST UINT32 Pcal9555SlaveAddr,
IN CONST UINT32 GpioNum,
IN CONST BOOLEAN CfgAsInput
)
{
Pcal9555SetPortRegBit (
Pcal9555SlaveAddr,
GpioNum,
PCAL9555_REG_CFG_PORT0,
CfgAsInput
);
}
/**
Set the level of Pcal9555 IO Expander GPIO high or low.
@param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
@param GpioNum Gpio to change values 0-7 for Port0 and 8-15
for Port1.
@param HighLevel If TRUE set pin high else set pin low.
**/
VOID
EFIAPI
PlatformPcal9555GpioSetLevel (
IN CONST UINT32 Pcal9555SlaveAddr,
IN CONST UINT32 GpioNum,
IN CONST BOOLEAN HighLevel
)
{
Pcal9555SetPortRegBit (
Pcal9555SlaveAddr,
GpioNum,
PCAL9555_REG_OUT_PORT0,
HighLevel
);
}
/**
Enable pull-up/pull-down resistors of Pcal9555 GPIOs.
@param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
@param GpioNum Gpio to change values 0-7 for Port0 and 8-15
for Port1.
**/
VOID
EFIAPI
PlatformPcal9555GpioEnablePull (
IN CONST UINT32 Pcal9555SlaveAddr,
IN CONST UINT32 GpioNum
)
{
Pcal9555SetPortRegBit (
Pcal9555SlaveAddr,
GpioNum,
PCAL9555_REG_PULL_EN_PORT0,
TRUE
);
}
/**
Disable pull-up/pull-down resistors of Pcal9555 GPIOs.
@param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
@param GpioNum Gpio to change values 0-7 for Port0 and 8-15
for Port1.
**/
VOID
EFIAPI
PlatformPcal9555GpioDisablePull (
IN CONST UINT32 Pcal9555SlaveAddr,
IN CONST UINT32 GpioNum
)
{
Pcal9555SetPortRegBit (
Pcal9555SlaveAddr,
GpioNum,
PCAL9555_REG_PULL_EN_PORT0,
FALSE
);
}
/**
Get state of Pcal9555 GPIOs.
@param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
@param GpioNum Gpio to change values 0-7 for Port0 and 8-15
for Port1.
@retval TRUE GPIO pin is high
@retval FALSE GPIO pin is low
**/
BOOLEAN
EFIAPI
PlatformPcal9555GpioGetState (
IN CONST UINT32 Pcal9555SlaveAddr,
IN CONST UINT32 GpioNum
)
{
return Pcal9555GetPortRegBit (Pcal9555SlaveAddr, GpioNum, PCAL9555_REG_IN_PORT0);
}