alder_lake_bios/Intel/AlderLake/AlderLakePlatSamplePkg/E3/Library/E3DongleLib/E3DongleLib.c

723 lines
23 KiB
C

/** @file
@copyright
INTEL CONFIDENTIAL
Copyright 2012 - 2019 Intel Corporation.
The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its suppliers
and licensors. The Material may contain trade secrets and proprietary and
confidential information of Intel Corporation and its suppliers and licensors,
and is protected by worldwide copyright and trade secret laws and treaty
provisions. No part of the Material may be used, copied, reproduced, modified,
published, uploaded, posted, transmitted, distributed, or disclosed in any way
without Intel's prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.
Unless otherwise agreed by Intel in writing, you may not remove or alter
this notice or any other notice embedded in Materials by Intel or
Intel's suppliers or licensors in any way.
This file contains a 'Sample Driver' and is licensed as such under the terms
of your license agreement with Intel or your vendor. This file may be modified
by the user, subject to the additional terms of the license agreement.
@par Specification Reference:
**/
#include <Uefi.h>
#include <Library/DebugLib.h>
#include <Library/TimerLib.h>
#include <Library/IoLib.h>
#include <Library/UefiLib.h>
#include <Library/I2cAccessLib.h>
#include <Library/MmPciLib.h>
#include <Library/BaseMemoryLib.h>
#include <Register/SerialIoI2cRegs.h>
#include <Register/SerialIoRegs.h>
#include <Register/PchRegs.h>
#include <IndustryStandard/Pci22.h>
#include "..\..\Include\E3DongleLib.h"
#include "E3DongleLibInternal.h"
#include "E3DongleLibPlatformInit.h"
/**
This function control the IO Expander on the E3 dongle to enable/disable the power from dongle to E3 chip
@param[in] bEnabled Ture: enable the power from dongle to E3 chip; False: disable
**/
EFI_STATUS
EFIAPI
ExternalPowerControlForE3Chip (
IN BOOLEAN bEnabled
)
{
EFI_STATUS Status;
if (!IsE3DongleAttached()) {
return EFI_NOT_FOUND;
}
// Configure the P0 and P1 pin level and keep P2 to high or input according to the requesting state
if (bEnabled) {
Status = WriteE3DongleIOExp(PCA9534A_OUTPUTPORT_REGISTER, 0x7);
} else {
Status = WriteE3DongleIOExp(PCA9534A_OUTPUTPORT_REGISTER, 0x4);
}
if (EFI_ERROR(Status)) {
IOEXPPRINT("ExternalPowerControlForE3Chip: failed to set output port!\n");
return Status;
}
// Configure the Polarity inversion to no inversion
Status = WriteE3DongleIOExp(PCA9534A_POLARITY_INVERSION_REGISTER, 0);
if (EFI_ERROR(Status)) {
IOEXPPRINT("ExternalPowerControlForE3Chip: failed to set Polarity inversion!\n");
return Status;
}
// Configure the P0 pin on the GPIO Expander to GPO
Status = WriteE3DongleIOExp(PCA9534A_CONFIGURATION_REGISTER, 0xFC);
if (EFI_ERROR(Status)) {
IOEXPPRINT("ExternalPowerControlForE3Chip: failed to set direction!\n");
return Status;
}
return Status;
}
/**
This function control the IO Expander on the E3 dongle to enable/disable the power from dongle to E3 chip
@param[in] bEnabled Ture: enable the power from dongle to E3 chip; False: disable
**/
EFI_STATUS
EFIAPI
PeiExternalPowerControlForE3Chip (
IN BOOLEAN bEnabled
)
{
EFI_STATUS Status;
if (!PeiIsE3DongleAttached()) {
return EFI_NOT_FOUND;
}
// Configure the P0 and P1 pin level and keep P2 to high or input according to the requesting state
if (bEnabled) {
Status = PeiWriteE3DongleIOExp(PCA9534A_OUTPUTPORT_REGISTER, 0x7);
} else {
Status = PeiWriteE3DongleIOExp(PCA9534A_OUTPUTPORT_REGISTER, 0x4);
}
if (EFI_ERROR(Status)) {
IOEXPPRINT("ExternalPowerControlForE3Chip: failed to set output port!\n");
return Status;
}
// Configure the Polarity inversion to no inversion
Status = PeiWriteE3DongleIOExp(PCA9534A_POLARITY_INVERSION_REGISTER, 0);
if (EFI_ERROR(Status)) {
IOEXPPRINT("ExternalPowerControlForE3Chip: failed to set Polarity inversion!\n");
return Status;
}
// Configure the P0 pin on the GPIO Expander to GPO
Status = PeiWriteE3DongleIOExp(PCA9534A_CONFIGURATION_REGISTER, 0xFC);
if (EFI_ERROR(Status)) {
IOEXPPRINT("ExternalPowerControlForE3Chip: failed to set direction!\n");
return Status;
}
return Status;
}
// return:
// TRUE: Detected and attached;
// FALSE: Not detected
BOOLEAN
IsE3DongleAttached(VOID)
{
UINTN Temp;
if (EFI_ERROR(ReadE3DongleByte(0, &Temp))) {
IOEXPPRINT("USB device is attached on the port.");
return FALSE;
} else {
IOEXPPRINT("E3 Dongle is attached on the port.");
return TRUE;
}
}
// return:
// TRUE: Detected and attached;
// FALSE: Not detected
BOOLEAN
PeiIsE3DongleAttached(VOID)
{
UINTN Temp;
if (EFI_ERROR(PeiReadE3DongleByte(0, &Temp))) {
IOEXPPRINT("USB device is attached on the port.");
return FALSE;
} else {
IOEXPPRINT("E3 Dongle is attached on the port.");
return TRUE;
}
}
EFI_STATUS
WriteE3DongleByte (
IN UINTN offset,
IN UINTN value
)
{
EFI_STATUS Status;
UINT8 WriBuf[4] = {0, 0, 0 ,0};
WriBuf[1] = (UINT8)(offset&0xFF);
WriBuf[0] = (UINT8)((offset>>8)&0xFF);
WriBuf[2] = (UINT8) value;
Status = PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, PREPARE_I2C_FLAG);
if (EFI_ERROR(Status)) {
IOEXPPRINT("PrepareOrRestoreI2C error, Status=%r\n", Status);
return Status;
}
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, 3, WriBuf, 0, NULL, WAIT_1_SECOND, 0);
PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, RESTORE_I2C_FLAG);
return Status;
}
EFI_STATUS
WriteE3DongleBuffer(
IN UINTN offset,
IN UINTN length,
IN UINT8 *buf
)
{
EFI_STATUS Status;
UINT8 WriBuf[EEPROM_24C32_CACHE_SIZE+2];
UINT8 *Ptr;
UINTN i;
UINTN offsetTmp;
ZeroMem(WriBuf,sizeof(WriBuf));
WriBuf[1] = (UINT8)(offset&0xFF);
WriBuf[0] = (UINT8)((offset>>8)&0xFF);
Ptr = buf;
i = length;
offsetTmp = offset;
Status = PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, PREPARE_I2C_FLAG);
if (EFI_ERROR(Status)) {
IOEXPPRINT("PrepareOrRestoreI2C error, Status=%r\n", Status);
return Status;
}
while(i != 0) {
if (i >= EEPROM_24C32_CACHE_SIZE) {
CopyMem(&WriBuf[2],Ptr,EEPROM_24C32_CACHE_SIZE);
Ptr = Ptr + EEPROM_24C32_CACHE_SIZE;
i = i - EEPROM_24C32_CACHE_SIZE;
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, EEPROM_24C32_CACHE_SIZE+2, WriBuf, 0, NULL, WAIT_1_SECOND, 0);
if (EFI_ERROR(Status)) {
break;
}
offsetTmp = offsetTmp + EEPROM_24C32_CACHE_SIZE;
WriBuf[1] = (UINT8)(offsetTmp&0xFF);
WriBuf[0] = (UINT8)((offsetTmp>>8)&0xFF);
//gBS->Stall(30000);
MicroSecondDelay(30000);
} else {
CopyMem(&WriBuf[2],Ptr,i);
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, i+2, WriBuf, 0, NULL, WAIT_1_SECOND, 0);
if (EFI_ERROR(Status)) {
break;
}
Ptr = Ptr + i;
i = 0;
//gBS->Stall(30000);
MicroSecondDelay(30000);
}
}
PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, RESTORE_I2C_FLAG);
return Status;
}
EFI_STATUS
ReadE3DongleByte (
IN UINTN offset,
OUT UINTN* value
)
{
EFI_STATUS Status;
UINT8 WriBuf[2] = {0, 0};
UINT8 ReBuf[1] = {0};
WriBuf[1] = (UINT8)(offset&0xFF);
WriBuf[0] = (UINT8)((offset>>8)&0xFF);
ReBuf[0] = 0;
Status = PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, PREPARE_I2C_FLAG);
if (EFI_ERROR(Status)) {
IOEXPPRINT("PrepareOrRestoreI2C error, Status=%r\n", Status);
return Status;
}
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, 2, WriBuf, 0, NULL, WAIT_1_SECOND, FLAG_24C32_READ_PHASE1);
//gBS->Stall(1000);
MicroSecondDelay(1000);
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, 0, NULL, 1, ReBuf, WAIT_1_SECOND, 0);
*value = ReBuf[0];
PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, RESTORE_I2C_FLAG);
IOEXPPRINT("offset=0x%X, Value=0x%X, Status=%r\n", offset, ReBuf[0], Status);
return Status;
}
EFI_STATUS
PeiReadE3DongleByte (
IN UINTN offset,
OUT UINTN* value
)
{
EFI_STATUS Status;
UINT8 WriBuf[2] = {0, 0};
UINT8 ReBuf[1] = {0};
WriBuf[1] = (UINT8)(offset&0xFF);
WriBuf[0] = (UINT8)((offset>>8)&0xFF);
ReBuf[0] = 0;
Status = PeiPrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, PREPARE_I2C_FLAG);
if (EFI_ERROR(Status)) {
IOEXPPRINT("PeiPrepareOrRestoreI2C error, Status=%r\n", Status);
return Status;
}
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, 2, WriBuf, 0, NULL, WAIT_1_SECOND, FLAG_24C32_READ_PHASE1);
//gBS->Stall(1000);
MicroSecondDelay(1000);
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, 0, NULL, 1, ReBuf, WAIT_1_SECOND, 0);
*value = ReBuf[0];
PeiPrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, RESTORE_I2C_FLAG);
IOEXPPRINT("offset=0x%X, Value=0x%X, Status=%r\n", offset, ReBuf[0], Status);
return Status;
}
EFI_STATUS
ReadE3DongleBuffer (
IN UINTN offset,
IN UINTN length,
OUT UINT8 *buf
)
{
EFI_STATUS Status;
UINT8 WriBuf[2] = {0, 0};
UINTN TmpLength;
UINT8 *Ptr;
UINTN TmpOffset;
WriBuf[1] = (UINT8)(offset&0xFF);
WriBuf[0] = (UINT8)((offset>>8)&0xFF);
TmpLength = length;
Ptr = buf;
TmpOffset = offset;
Status = PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, PREPARE_I2C_FLAG);
if (EFI_ERROR(Status)) {
IOEXPPRINT("PrepareOrRestoreI2C error, Status=%r\n", Status);
return Status;
}
while(TmpLength != 0) {
if (TmpLength >= EEPROM_24C32_MAX_CACHE_SIZE) {
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, 2, WriBuf, 0, NULL, WAIT_1_SECOND, FLAG_24C32_READ_PHASE1);
//gBS->Stall(1000);
MicroSecondDelay(1000);
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, 0, NULL, EEPROM_24C32_MAX_CACHE_SIZE, Ptr, WAIT_1_SECOND, 0);
if (EFI_ERROR(Status)) {
break;
}
//gBS->Stall(1000);
MicroSecondDelay(1000);
Ptr = Ptr + EEPROM_24C32_MAX_CACHE_SIZE;
TmpLength = TmpLength - EEPROM_24C32_MAX_CACHE_SIZE;
TmpOffset = TmpOffset + EEPROM_24C32_MAX_CACHE_SIZE;
WriBuf[1] = (UINT8)(TmpOffset&0xFF);
WriBuf[0] = (UINT8)((TmpOffset>>8)&0xFF);
} else {
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, 2, WriBuf, 0, NULL, WAIT_1_SECOND, FLAG_24C32_READ_PHASE1);
//gBS->Stall(1000);
MicroSecondDelay(1000);
Status = I2cWriteRead_EEPROM24CXX((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), EEPROM_24C32_I2C_SLAVE_ADDR, 0, NULL, TmpLength, Ptr, WAIT_1_SECOND, 0);
if (EFI_ERROR(Status)) {
break;
}
//gBS->Stall(1000);
MicroSecondDelay(1000);
Ptr = Ptr + TmpLength;
TmpLength = 0;
TmpOffset = TmpOffset + TmpLength;
WriBuf[1] = (UINT8)(TmpOffset&0xFF);
WriBuf[0] = (UINT8)((TmpOffset>>8)&0xFF);
}
}
PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, RESTORE_I2C_FLAG);
IOEXPPRINT("offset=0x%X, length=0x%X, Status=%r\n", offset, offset, Status);
return Status;
}
// Input:
// bus: 0-i2c0...
// flag - prepare or restore
EFI_STATUS
PrepareOrRestoreI2C (
IN UINTN bus,
IN UINTN flag
)
{
static UINT32 PCICmdRegBak = 0;
static UINT32 PCIPmeCtrlRegBak = 0;
static UINT32 PCIPPRRESETSRegBak = 0;
static BOOLEAN Changed = FALSE;
UINTN PciI2cBase;
UINT16 VendorID;
PciI2cBase = (UINTN) PcdGet64 (PcdPciExpressBaseAddress) + (UINTN)GetSerialIoI2cPciCfg((UINT8)bus);
//MmPciBase (
// DEFAULT_PCI_BUS_NUMBER_PCH,
// GetSerialIoI2cDeviceNumber(bus),
// GetSerialIoI2cFunctionNumber(bus)
// );
VendorID = MmioRead16(PciI2cBase + PCI_VENDOR_ID_OFFSET);
if (VendorID != 0x8086) {
return EFI_DEVICE_ERROR;
}
if ((flag == PREPARE_I2C_FLAG) && !Changed) {
// Backup the registers
PCICmdRegBak = MmioRead32(PciI2cBase + PCI_COMMAND_OFFSET);
PCIPmeCtrlRegBak = MmioRead32(PciI2cBase + R_SERIAL_IO_CFG_PME_CTRL_STS);
PCIPPRRESETSRegBak = MmioRead32(PciI2cBase + R_SERIAL_IO_MEM_PPR_RESETS);
// Bring I2C to D0
MmioOr32 (PciI2cBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
MmioAnd32 (PciI2cBase + R_SERIAL_IO_CFG_PME_CTRL_STS, (UINT32) (~B_SERIAL_IO_CFG_PME_CTRL_STS_PWR_ST));
MmioOr32 (PciI2cBase + R_SERIAL_IO_MEM_PPR_RESETS,
B_SERIAL_IO_MEM_PPR_RESETS_FUNC | B_SERIAL_IO_MEM_PPR_RESETS_APB | B_SERIAL_IO_MEM_PPR_RESETS_IDMA);
Changed = TRUE;
return EFI_SUCCESS;
}
if ((flag == RESTORE_I2C_FLAG) && Changed) {
// Restore the registers
MmioWrite32(PciI2cBase + PCI_COMMAND_OFFSET, PCICmdRegBak);
MmioWrite32(PciI2cBase + R_SERIAL_IO_CFG_PME_CTRL_STS, PCIPmeCtrlRegBak);
MmioWrite32(PciI2cBase + R_SERIAL_IO_MEM_PPR_RESETS, PCIPPRRESETSRegBak);
Changed = FALSE;
return EFI_SUCCESS;
}
return EFI_INVALID_PARAMETER;
}
// Input:
// bus: 0-i2c0...
EFI_STATUS
PeiPrepareOrRestoreI2C (
IN UINTN bus,
IN UINTN flag
)
{
UINTN PciI2cBase;
BOOLEAN IsMmioEnabled;
UINT16 VendorID;
PciI2cBase = (UINTN) PcdGet64 (PcdPciExpressBaseAddress) + (UINTN)GetSerialIoI2cPciCfg((UINT8)bus);
//MmPciBase (
// DEFAULT_PCI_BUS_NUMBER_PCH,
// GetSerialIoDeviceNumber(bus),
// GetSerialIoFunctionNumber(bus)
// );
VendorID = MmioRead16(PciI2cBase + PCI_VENDOR_ID_OFFSET);
if (VendorID != 0x8086) {
return EFI_DEVICE_ERROR;
}
//MMIO is being enabled?
if ((MmioRead16(PciI2cBase + PCI_COMMAND_OFFSET) & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) {
IsMmioEnabled = FALSE;
} else {
IsMmioEnabled = TRUE;
}
//Set temp MMIO bar
MmioAnd16 (PciI2cBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE);
if ((flag == PREPARE_I2C_FLAG) && !IsMmioEnabled) {
MmioWrite32 (PciI2cBase + R_SERIAL_IO_CFG_BAR0_LOW, PcdGet32 (PcdSiliconInitTempMemBaseAddr));
MmioWrite32 (PciI2cBase + R_SERIAL_IO_CFG_BAR0_HIGH, 0x0);
}
// Bring I2C to D0
if (flag == PREPARE_I2C_FLAG) {
MmioOr32 (PciI2cBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER);
MmioAnd32 (PciI2cBase + R_SERIAL_IO_CFG_PME_CTRL_STS, (UINT32) (~B_SERIAL_IO_CFG_PME_CTRL_STS_PWR_ST));
MmioOr32 (PciI2cBase + R_SERIAL_IO_MEM_PPR_RESETS,
B_SERIAL_IO_MEM_PPR_RESETS_FUNC | B_SERIAL_IO_MEM_PPR_RESETS_APB | B_SERIAL_IO_MEM_PPR_RESETS_IDMA);
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
WriteE3DongleIOExp (
IN UINT8 offset,
IN UINT8 value
)
{
EFI_STATUS Status;
UINT8 WriBuf[2] = {0, 0};
WriBuf[0] = (UINT8)(offset&0xFF);
WriBuf[1] = (UINT8) value;
if (!IsE3DongleAttached()) {
return EFI_NOT_FOUND;
}
Status = PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, PREPARE_I2C_FLAG);
if (EFI_ERROR(Status)) {
IOEXPPRINT("PrepareOrRestoreI2C error, Status=%r\n", Status);
return Status;
}
Status = I2cWriteRead((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), E3DONGLE_IOEXPANDER_I2C_SLAVE_ADDR, 2, WriBuf, 0, NULL, WAIT_1_SECOND);
PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, RESTORE_I2C_FLAG);
return Status;
}
EFI_STATUS
EFIAPI
ReadE3DongleIOExp (
IN UINT8 offset,
OUT UINT8* value
)
{
EFI_STATUS Status;
UINT8 WriBuf[1] = {0};
UINT8 ReBuf[1] = {0};
WriBuf[0] = (UINT8)(offset&0xFF);
if (!IsE3DongleAttached()) {
return EFI_NOT_FOUND;
}
Status = PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, PREPARE_I2C_FLAG);
if (EFI_ERROR(Status)) {
IOEXPPRINT("PrepareOrRestoreI2C error, Status=%r\n", Status);
return Status;
}
Status = I2cWriteRead((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), E3DONGLE_IOEXPANDER_I2C_SLAVE_ADDR, 1, WriBuf, 1, ReBuf, WAIT_1_SECOND);
PrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, RESTORE_I2C_FLAG);
*value = ReBuf[0];
IOEXPPRINT("offset=0x%X, Value=0x%X, Status=%r\n", offset, ReBuf[0], Status);
return Status;
}
EFI_STATUS
EFIAPI
PeiWriteE3DongleIOExp (
IN UINT8 offset,
IN UINT8 value
)
{
EFI_STATUS Status;
UINT8 WriBuf[2] = {0, 0};
WriBuf[0] = (UINT8)(offset&0xFF);
WriBuf[1] = (UINT8) value;
if (!PeiIsE3DongleAttached()) {
return EFI_NOT_FOUND;
}
Status = PeiPrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, PREPARE_I2C_FLAG);
if (EFI_ERROR(Status)) {
IOEXPPRINT("PeiPrepareOrRestoreI2C error, Status=%r\n", Status);
return Status;
}
Status = I2cWriteRead((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), E3DONGLE_IOEXPANDER_I2C_SLAVE_ADDR, 2, WriBuf, 0, NULL, WAIT_1_SECOND);
PeiPrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, RESTORE_I2C_FLAG);
return Status;
}
EFI_STATUS
EFIAPI
PeiReadE3DongleIOExp (
IN UINT8 offset,
OUT UINT8* value
)
{
EFI_STATUS Status;
UINT8 WriBuf[1] = {0};
UINT8 ReBuf[1] = {0};
WriBuf[0] = (UINT8)(offset&0xFF);
if (!PeiIsE3DongleAttached()) {
return EFI_NOT_FOUND;
}
Status = PeiPrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, PREPARE_I2C_FLAG);
if (EFI_ERROR(Status)) {
IOEXPPRINT("PeiPrepareOrRestoreI2C error, Status=%r\n", Status);
return Status;
}
Status = I2cWriteRead((UINTN)GetSerialIoBar(GetSerialIoI2cPciCfg(E3_DONGLE_ON_I2CBUS_NUM)), E3DONGLE_IOEXPANDER_I2C_SLAVE_ADDR, 1, WriBuf, 1, ReBuf, WAIT_1_SECOND);
PeiPrepareOrRestoreI2C(E3_DONGLE_ON_I2CBUS_NUM, RESTORE_I2C_FLAG);
*value = ReBuf[0];
IOEXPPRINT("offset=0x%X, Value=0x%X, Status=%r\n", offset, ReBuf[0], Status);
return Status;
}
EFI_STATUS
EFIAPI
I2cWriteRead_EEPROM24CXX (
IN UINTN MmioBase,
IN UINT8 SlaveAddress,
IN UINTN WriteLength,
IN UINT8 *WriteBuffer,
IN UINTN ReadLength,
IN UINT8 *ReadBuffer,
IN UINT64 TimeBudget,
IN UINT8 Flag
//TODO: add Speed parameter
)
{
UINTN ReadsNeeded = ReadLength;
UINT64 CutOffTime;
if ((WriteLength == 0 && ReadLength == 0) ||
(WriteLength != 0 && WriteBuffer == NULL) ||
(ReadLength != 0 && ReadBuffer == NULL) ) {
DEBUG ((DEBUG_ERROR, "I2cWR Invalid Parameters\n"));
return EFI_INVALID_PARAMETER;
}
//
// Sanity checks to verify the I2C controller is alive
// Conveniently, ICON register's values of 0 or FFFFFFFF indicate
// I2c controller is out-of-order: either disabled, in D3 or in reset.
//
if (MmioRead32(MmioBase+R_I2C_MEM_CON) == 0xFFFFFFFF || MmioRead32(MmioBase+R_I2C_MEM_CON) == 0x0) {
DEBUG ((DEBUG_ERROR, "I2cWR Device Error\n"));
return EFI_DEVICE_ERROR;
}
MmioWrite32(MmioBase+R_I2C_MEM_ENABLE, 0x0);
MmioRead32(MmioBase+0x40);
MmioRead32(MmioBase+R_I2C_MEM_CLR_TX_ABRT);
MmioWrite32(MmioBase+R_SERIAL_IO_I2C_MEM_SDA_HOLD, 0x001C001C);
//
// Set I2C Bus Speed at 400 kHz for GPIO Expander
//
MmioWrite32(MmioBase + R_I2C_MEM_FS_SCL_HCNT, 128);
MmioWrite32(MmioBase + R_I2C_MEM_FS_SCL_LCNT, 160);
MmioWrite32(MmioBase + R_I2C_MEM_TAR, SlaveAddress);
MmioWrite32(MmioBase + R_I2C_MEM_CON, B_I2C_MEM_MASTER_MODE | V_I2C_MEM_SPEED_FAST | B_I2C_MEM_RESTART_EN | B_I2C_MEM_SLAVE_DISABLE );
MmioWrite32(MmioBase+R_I2C_MEM_ENABLE, 0x1);
CutOffTime = AsmReadTsc() + TimeBudget;
while ( (MmioRead32(MmioBase+R_I2C_MEM_ENABLE_STATUS) & 1)==0 ) {
if (AsmReadTsc() > CutOffTime) {
DEBUG ((DEBUG_ERROR, "I2cWR timeout\n"));
return EFI_TIMEOUT;
}
}
while(1) {
if(MmioRead32(MmioBase+R_I2C_MEM_INTR_STAT) & B_I2C_MEM_INTR_TX_ABRT) {
DEBUG ((DEBUG_ERROR, "I2cWR Transfer aborted, reason = 0x%08x\n",MmioRead32(MmioBase+R_I2C_MEM_TX_ABRT_SOURCE)));
MmioRead32(MmioBase+R_I2C_MEM_CLR_TX_ABRT);
MmioAnd32(MmioBase+R_I2C_MEM_ENABLE, 0xFFFFFFFE);
CutOffTime = AsmReadTsc() + TimeBudget;
while (((MmioRead32(MmioBase+R_I2C_MEM_ENABLE_STATUS) & 1)==1) && (AsmReadTsc() <= CutOffTime)) {}
return EFI_DEVICE_ERROR;
}
if (MmioRead32(MmioBase+R_I2C_MEM_STATUS) & B_I2C_MEM_STATUS_TFNF) {
if (WriteLength > 1) {
MmioWrite32(MmioBase+R_I2C_MEM_DATA_CMD, *WriteBuffer);
WriteBuffer++;
WriteLength--;
} else if (WriteLength==1 && (Flag & FLAG_24C32_READ_PHASE1)) {
MmioWrite32(MmioBase+R_I2C_MEM_DATA_CMD, *WriteBuffer);
WriteBuffer++;
WriteLength--;
} else if (WriteLength==1 && ReadLength != 0) {
MmioWrite32(MmioBase+R_I2C_MEM_DATA_CMD, *WriteBuffer);
WriteBuffer++;
WriteLength--;
} else if (WriteLength==1 && ReadLength == 0) {
MmioWrite32(MmioBase+R_I2C_MEM_DATA_CMD, *WriteBuffer | B_I2C_MEM_CMD_STOP);
WriteBuffer++;
WriteLength--;
} else if (ReadLength > 1) {
MmioWrite32(MmioBase+R_I2C_MEM_DATA_CMD, B_I2C_MEM_CMD_READ);
ReadLength--;
} else if (ReadLength == 1) {
MmioWrite32(MmioBase+R_I2C_MEM_DATA_CMD, B_I2C_MEM_CMD_READ|B_I2C_MEM_CMD_STOP);
ReadLength--;
}
}
if (ReadsNeeded) {
if (MmioRead32(MmioBase+R_I2C_MEM_STATUS) & B_I2C_MEM_STATUS_RFNE) {
*ReadBuffer = (UINT8)MmioRead32(MmioBase+R_I2C_MEM_DATA_CMD);
ReadBuffer++;
ReadsNeeded--;
}
}
if (WriteLength==0 && ReadsNeeded==0 && (Flag & FLAG_24C32_READ_PHASE1)) {
return EFI_SUCCESS;
}
if (WriteLength==0 && ReadsNeeded==0 && !(MmioRead32(MmioBase+R_I2C_MEM_STATUS)&B_I2C_MEM_STATUS_ACTIVITY)) {
MmioAnd32(MmioBase+R_I2C_MEM_ENABLE, 0xFFFFFFFE);
while ( (MmioRead32(MmioBase+R_I2C_MEM_ENABLE_STATUS) & 1)==1 ) {}
DEBUG ((DEBUG_INFO, "I2cWR success\n"));
return EFI_SUCCESS;
}
if (AsmReadTsc() > CutOffTime) {
MmioAnd32(MmioBase+R_I2C_MEM_ENABLE, 0xFFFFFFFE);
CutOffTime = AsmReadTsc() + TimeBudget;
while (((MmioRead32(MmioBase+R_I2C_MEM_ENABLE_STATUS) & 1)==1) && (AsmReadTsc() <= CutOffTime)) {}
DEBUG ((DEBUG_ERROR, "I2cWR wrong ENST value\n"));
return EFI_TIMEOUT;
}
}
}