/** @file | |
Helper routines with common PEI / DXE implementation. | |
Copyright (c) 2013-2016 Intel Corporation. | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#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); | |
} | |