723 lines
23 KiB
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;
|
|
}
|
|
|
|
}
|
|
}
|
|
|