Add Sample I2C Library for Baytrail I2C Controller.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: David Wei  <david.wei@intel.com>
Reviewed-by: Tim He <time.he@intel.com> 


git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17546 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
David Wei
2015-06-02 01:47:57 +00:00
committed by zwei4
parent c85bc0c9d4
commit 4e5220964b
12 changed files with 2437 additions and 0 deletions

View File

@@ -0,0 +1,741 @@
/** @file
Functions for accessing I2C registers.
Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that 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 <Library/DebugLib.h>
#include <Library/TimerLib.h>
#include <PchRegs/PchRegsPcu.h>
#include <PchRegs.h>
#include <PlatformBaseAddresses.h>
#include <PchRegs/PchRegsLpss.h>
#include <Library/I2CLib.h>
#include <Protocol/GlobalNvsArea.h>
#include <Library/UefiBootServicesTableLib.h>
#include <I2CRegs.h>
#define GLOBAL_NVS_OFFSET(Field) (UINTN)((CHAR8*)&((EFI_GLOBAL_NVS_AREA*)0)->Field - (CHAR8*)0)
#define PCIEX_BASE_ADDRESS 0xE0000000
#define PCI_EXPRESS_BASE_ADDRESS ((VOID *) (UINTN) PCIEX_BASE_ADDRESS)
#define MmPciAddress( Segment, Bus, Device, Function, Register ) \
((UINTN)PCI_EXPRESS_BASE_ADDRESS + \
(UINTN)(Bus << 20) + \
(UINTN)(Device << 15) + \
(UINTN)(Function << 12) + \
(UINTN)(Register) \
)
#define PCI_D31F0_REG_BASE PCIEX_BASE_ADDRESS + (UINT32) (31 << 15)
typedef struct _LPSS_PCI_DEVICE_INFO {
UINTN Segment;
UINTN BusNum;
UINTN DeviceNum;
UINTN FunctionNum;
UINTN Bar0;
UINTN Bar1;
} LPSS_PCI_DEVICE_INFO;
LPSS_PCI_DEVICE_INFO mLpssPciDeviceList[] = {
{0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_DMAC1, PCI_FUNCTION_NUMBER_PCH_LPSS_DMAC, 0xFE900000, 0xFE908000},
{0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C0, 0xFE910000, 0xFE918000},
{0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C1, 0xFE920000, 0xFE928000},
{0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C2, 0xFE930000, 0xFE938000},
{0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C3, 0xFE940000, 0xFE948000},
{0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C4, 0xFE950000, 0xFE958000},
{0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C5, 0xFE960000, 0xFE968000},
{0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C6, 0xFE970000, 0xFE978000}
};
#define LPSS_PCI_DEVICE_NUMBER sizeof(mLpssPciDeviceList)/sizeof(LPSS_PCI_DEVICE_INFO)
STATIC UINTN mI2CBaseAddress = 0;
STATIC UINT16 mI2CSlaveAddress = 0;
UINT16 mI2cMode=B_IC_RESTART_EN | B_IC_SLAVE_DISABLE | B_MASTER_MODE ;
UINTN mI2cNvsBaseAddress[] = {
GLOBAL_NVS_OFFSET(LDMA2Addr),
GLOBAL_NVS_OFFSET(I2C1Addr),
GLOBAL_NVS_OFFSET(I2C2Addr),
GLOBAL_NVS_OFFSET(I2C3Addr),
GLOBAL_NVS_OFFSET(I2C4Addr),
GLOBAL_NVS_OFFSET(I2C5Addr),
GLOBAL_NVS_OFFSET(I2C6Addr),
GLOBAL_NVS_OFFSET(I2C7Addr)
};
/**
This function get I2Cx controller base address (BAR0).
@param I2cControllerIndex Bus Number of I2C controller.
@return I2C BAR.
**/
UINTN
GetI2cBarAddr(
IN UINT8 I2cControllerIndex
)
{
EFI_STATUS Status;
EFI_GLOBAL_NVS_AREA_PROTOCOL *GlobalNvsArea;
UINTN AcpiBaseAddr;
UINTN PciMmBase=0;
ASSERT(gBS!=NULL);
Status = gBS->LocateProtocol (
&gEfiGlobalNvsAreaProtocolGuid,
NULL,
&GlobalNvsArea
);
//
// PCI mode from PEI ( Global NVS is not ready).
//
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_INFO, "GetI2cBarAddr() gEfiGlobalNvsAreaProtocolGuid:%r\n", Status));
//
// Global NVS is not ready.
//
return 0;
}
AcpiBaseAddr = *(UINTN*)((CHAR8*)GlobalNvsArea->Area + mI2cNvsBaseAddress[I2cControllerIndex + 1]);
//
//PCI mode from DXE (global NVS protocal) to LPSS OnReadytoBoot(swith to ACPI).
//
if(AcpiBaseAddr==0) {
PciMmBase = MmPciAddress (
mLpssPciDeviceList[I2cControllerIndex + 1].Segment,
mLpssPciDeviceList[I2cControllerIndex + 1].BusNum,
mLpssPciDeviceList[I2cControllerIndex + 1].DeviceNum,
mLpssPciDeviceList[I2cControllerIndex + 1].FunctionNum,
0
);
DEBUG((EFI_D_ERROR, "\nGetI2cBarAddr() I2C Device %x %x %x PciMmBase:%x\n", \
mLpssPciDeviceList[I2cControllerIndex + 1].BusNum, \
mLpssPciDeviceList[I2cControllerIndex + 1].DeviceNum, \
mLpssPciDeviceList[I2cControllerIndex + 1].FunctionNum, PciMmBase));
if (MmioRead32 (PciMmBase) != 0xFFFFFFFF) {
if((MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_STSCMD)& B_PCH_LPSS_I2C_STSCMD_MSE)) {
//
// Get the address allocted.
//
mLpssPciDeviceList[I2cControllerIndex + 1].Bar0=MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR);
mLpssPciDeviceList[I2cControllerIndex + 1].Bar1=MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR1);
}
}
AcpiBaseAddr =mLpssPciDeviceList[I2cControllerIndex+1].Bar0;
}
//
// ACPI mode from BDS: LPSS OnReadytoBoot
//
else {
DEBUG ((EFI_D_INFO, "GetI2cBarAddr() NVS Varialable is updated by this LIB or LPSS \n"));
}
DEBUG ((EFI_D_INFO, "GetI2cBarAddr() I2cControllerIndex+1 0x%x AcpiBaseAddr:0x%x \n", (I2cControllerIndex + 1), AcpiBaseAddr));
return AcpiBaseAddr;
}
/**
This function enables I2C controllers.
@param I2cControllerIndex Bus Number of I2C controllers.
@return Result of the I2C initialization.
**/
EFI_STATUS
ProgramPciLpssI2C (
IN UINT8 I2cControllerIndex
)
{
UINT32 PmcBase;
UINTN PciMmBase=0;
EFI_STATUS Status;
EFI_GLOBAL_NVS_AREA_PROTOCOL *GlobalNvsArea;
UINT32 PmcFunctionDsiable[]= {
B_PCH_PMC_FUNC_DIS_LPSS2_FUNC1,
B_PCH_PMC_FUNC_DIS_LPSS2_FUNC2,
B_PCH_PMC_FUNC_DIS_LPSS2_FUNC3,
B_PCH_PMC_FUNC_DIS_LPSS2_FUNC4,
B_PCH_PMC_FUNC_DIS_LPSS2_FUNC5,
B_PCH_PMC_FUNC_DIS_LPSS2_FUNC6,
B_PCH_PMC_FUNC_DIS_LPSS2_FUNC7
};
DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() Start\n"));
//
// Set the VLV Function Disable Register to ZERO
//
PmcBase = MmioRead32 (PCI_D31F0_REG_BASE + R_PCH_LPC_PMC_BASE) & B_PCH_LPC_PMC_BASE_BAR;
if(MmioRead32(PmcBase+R_PCH_PMC_FUNC_DIS)&PmcFunctionDsiable[I2cControllerIndex]) {
DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() End:I2C[%x] is disabled\n",I2cControllerIndex));
return EFI_NOT_READY;
}
DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C()------------I2cControllerIndex=%x,PMC=%x\n",I2cControllerIndex,MmioRead32(PmcBase+R_PCH_PMC_FUNC_DIS)));
{
PciMmBase = MmPciAddress (
mLpssPciDeviceList[I2cControllerIndex+1].Segment,
mLpssPciDeviceList[I2cControllerIndex+1].BusNum,
mLpssPciDeviceList[I2cControllerIndex+1].DeviceNum,
mLpssPciDeviceList[I2cControllerIndex+1].FunctionNum,
0
);
DEBUG((EFI_D_ERROR, "Program Pci Lpss I2C Device %x %x %x PciMmBase:%x\n", \
mLpssPciDeviceList[I2cControllerIndex+1].BusNum, \
mLpssPciDeviceList[I2cControllerIndex+1].DeviceNum, \
mLpssPciDeviceList[I2cControllerIndex+1].FunctionNum, PciMmBase));
if (MmioRead32 (PciMmBase) != 0xFFFFFFFF) {
if((MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_STSCMD)& B_PCH_LPSS_I2C_STSCMD_MSE)) {
//
// Get the address allocted.
//
mLpssPciDeviceList[I2cControllerIndex+1].Bar0=MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR);
mLpssPciDeviceList[I2cControllerIndex+1].Bar1=MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR1);
DEBUG((EFI_D_ERROR, "ProgramPciLpssI2C() bar0:0x%x bar1:0x%x\n",mLpssPciDeviceList[I2cControllerIndex+1].Bar0, mLpssPciDeviceList[I2cControllerIndex+1].Bar1));
} else {
//
// Program BAR 0
//
ASSERT (((mLpssPciDeviceList[I2cControllerIndex+1].Bar0 & B_PCH_LPSS_I2C_BAR_BA) == mLpssPciDeviceList[I2cControllerIndex+1].Bar0) && (mLpssPciDeviceList[I2cControllerIndex+1].Bar0 != 0));
MmioWrite32 ((UINTN) (PciMmBase + R_PCH_LPSS_I2C_BAR), (UINT32) (mLpssPciDeviceList[I2cControllerIndex+1].Bar0 & B_PCH_LPSS_I2C_BAR_BA));
//
// Program BAR 1
//
ASSERT (((mLpssPciDeviceList[I2cControllerIndex+1].Bar1 & B_PCH_LPSS_I2C_BAR1_BA) == mLpssPciDeviceList[I2cControllerIndex+1].Bar1) && (mLpssPciDeviceList[I2cControllerIndex+1].Bar1 != 0));
MmioWrite32 ((UINTN) (PciMmBase + R_PCH_LPSS_I2C_BAR1), (UINT32) (mLpssPciDeviceList[I2cControllerIndex+1].Bar1 & B_PCH_LPSS_I2C_BAR1_BA));
//
// Bus Master Enable & Memory Space Enable
//
MmioOr32 ((UINTN) (PciMmBase + R_PCH_LPSS_I2C_STSCMD), (UINT32) (B_PCH_LPSS_I2C_STSCMD_BME | B_PCH_LPSS_I2C_STSCMD_MSE));
ASSERT (MmioRead32 (mLpssPciDeviceList[I2cControllerIndex+1].Bar0) != 0xFFFFFFFF);
}
//
// Release Resets
//
MmioWrite32 (mLpssPciDeviceList[I2cControllerIndex+1].Bar0 + R_PCH_LPIO_I2C_MEM_RESETS,(B_PCH_LPIO_I2C_MEM_RESETS_FUNC | B_PCH_LPIO_I2C_MEM_RESETS_APB));
//
// Activate Clocks
//
MmioWrite32 (mLpssPciDeviceList[I2cControllerIndex+1].Bar0 + R_PCH_LPSS_I2C_MEM_PCP,0x80020003);//No use for A0
DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() Programmed()\n"));
}
//
// BDS: already switched to ACPI mode
//
else {
ASSERT(gBS!=NULL);
Status = gBS->LocateProtocol (
&gEfiGlobalNvsAreaProtocolGuid,
NULL,
&GlobalNvsArea
);
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_INFO, "GetI2cBarAddr() gEfiGlobalNvsAreaProtocolGuid:%r\n", Status));
//
// gEfiGlobalNvsAreaProtocolGuid is not ready.
//
return 0;
}
mLpssPciDeviceList[I2cControllerIndex + 1].Bar0 = *(UINTN*)((CHAR8*)GlobalNvsArea->Area + mI2cNvsBaseAddress[I2cControllerIndex + 1]);
DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C(): is switched to ACPI 0x:%x \n",mLpssPciDeviceList[I2cControllerIndex + 1].Bar0));
}
}
DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() End\n"));
return EFI_SUCCESS;
}
/**
Disable I2C Bus.
@param VOID.
@return Result of the I2C disabling.
**/
RETURN_STATUS
I2cDisable (
VOID
)
{
//
// 0.1 seconds
//
UINT32 NumTries = 10000;
MmioWrite32 ( mI2CBaseAddress + R_IC_ENABLE, 0 );
while ( 0 != ( MmioRead32 ( mI2CBaseAddress + R_IC_ENABLE_STATUS) & 1)) {
MicroSecondDelay (10);
NumTries --;
if(0 == NumTries) {
return RETURN_NOT_READY;
}
}
return RETURN_SUCCESS;
}
/**
Enable I2C Bus.
@param VOID.
@return Result of the I2C disabling.
**/
RETURN_STATUS
I2cEnable (
VOID
)
{
//
// 0.1 seconds
//
UINT32 NumTries = 10000;
MmioWrite32 (mI2CBaseAddress + R_IC_ENABLE, 1);
while (0 == (MmioRead32 (mI2CBaseAddress + R_IC_ENABLE_STATUS) & 1)) {
MicroSecondDelay (10);
NumTries --;
if(0 == NumTries){
return RETURN_NOT_READY;
}
}
return RETURN_SUCCESS;
}
/**
Enable I2C Bus.
@param VOID.
@return Result of the I2C enabling.
**/
RETURN_STATUS
I2cBusFrequencySet (
IN UINTN BusClockHertz
)
{
DEBUG((EFI_D_INFO,"InputFreq BusClockHertz: %d\r\n",BusClockHertz));
//
// Set the 100 KHz clock divider according to SV result and I2C spec
//
MmioWrite32 ( mI2CBaseAddress + R_IC_SS_SCL_HCNT, (UINT16)0x214 );
MmioWrite32 ( mI2CBaseAddress + R_IC_SS_SCL_LCNT, (UINT16)0x272 );
//
// Set the 400 KHz clock divider according to SV result and I2C spec
//
MmioWrite32 ( mI2CBaseAddress + R_IC_FS_SCL_HCNT, (UINT16)0x50 );
MmioWrite32 ( mI2CBaseAddress + R_IC_FS_SCL_LCNT, (UINT16)0xAD );
switch ( BusClockHertz ) {
case 100 * 1000:
MmioWrite32 ( mI2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x40);//100K
mI2cMode = V_SPEED_STANDARD;
break;
case 400 * 1000:
MmioWrite32 ( mI2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x32);//400K
mI2cMode = V_SPEED_FAST;
break;
default:
MmioWrite32 ( mI2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x09);//3.4M
mI2cMode = V_SPEED_HIGH;
}
//
// Select the frequency counter,
// Enable restart condition,
// Enable master FSM, disable slave FSM.
//
mI2cMode |= B_IC_RESTART_EN | B_IC_SLAVE_DISABLE | B_MASTER_MODE;
return EFI_SUCCESS;
}
/**
Initializes the host controller to execute I2C commands.
@param I2cControllerIndex Index of I2C controller in LPSS device. 0 represents I2C0, which is PCI function 1 of LPSS device.
@return EFI_SUCCESS Opcode initialization on the I2C host controller completed.
@return EFI_DEVICE_ERROR Device error, operation failed.
**/
EFI_STATUS
I2CInit (
IN UINT8 I2cControllerIndex,
IN UINT16 SlaveAddress
)
{
EFI_STATUS Status=RETURN_SUCCESS;
UINT32 NumTries = 0;
UINTN GnvsI2cBarAddr=0;
//
// Verify the parameters
//
if ((1023 < SlaveAddress) || (6 < I2cControllerIndex)) {
Status = RETURN_INVALID_PARAMETER;
DEBUG((EFI_D_INFO,"I2CInit Exit with RETURN_INVALID_PARAMETER\r\n"));
return Status;
}
MmioWrite32 ( mI2CBaseAddress + R_IC_TAR, (UINT16)SlaveAddress );
mI2CSlaveAddress = SlaveAddress;
//
// 1.PEI: program and init ( before pci enumeration).
// 2.DXE:update address and re-init ( after pci enumeration).
// 3.BDS:update ACPI address and re-init ( after acpi mode is enabled).
//
if(mI2CBaseAddress == mLpssPciDeviceList[I2cControllerIndex + 1].Bar0) {
//
// I2CInit is already called.
//
GnvsI2cBarAddr=GetI2cBarAddr(I2cControllerIndex);
if((GnvsI2cBarAddr == 0)||(GnvsI2cBarAddr == mI2CBaseAddress)) {
DEBUG((EFI_D_INFO,"I2CInit Exit with mI2CBaseAddress:%x == [%x].Bar0\r\n",mI2CBaseAddress,I2cControllerIndex+1));
return RETURN_SUCCESS;
}
}
Status=ProgramPciLpssI2C(I2cControllerIndex);
if(Status!=EFI_SUCCESS) {
return Status;
}
mI2CBaseAddress = (UINT32) mLpssPciDeviceList[I2cControllerIndex + 1].Bar0;
DEBUG ((EFI_D_ERROR, "mI2CBaseAddress = 0x%x \n",mI2CBaseAddress));
//
// 1 seconds.
//
NumTries = 10000;
while ((1 == ( MmioRead32 ( mI2CBaseAddress + R_IC_STATUS) & STAT_MST_ACTIVITY ))) {
MicroSecondDelay(10);
NumTries --;
if(0 == NumTries) {
DEBUG((EFI_D_INFO, "Try timeout\r\n"));
return RETURN_DEVICE_ERROR;
}
}
Status = I2cDisable();
DEBUG((EFI_D_INFO, "I2cDisable Status = %r\r\n", Status));
I2cBusFrequencySet(400 * 1000);
MmioWrite32(mI2CBaseAddress + R_IC_INTR_MASK, 0x0);
if (0x7f < SlaveAddress )
SlaveAddress = ( SlaveAddress & 0x3ff ) | IC_TAR_10BITADDR_MASTER;
MmioWrite32 ( mI2CBaseAddress + R_IC_TAR, (UINT16)SlaveAddress );
MmioWrite32 ( mI2CBaseAddress + R_IC_RX_TL, 0);
MmioWrite32 ( mI2CBaseAddress + R_IC_TX_TL, 0 );
MmioWrite32 ( mI2CBaseAddress + R_IC_CON, mI2cMode);
Status = I2cEnable();
DEBUG((EFI_D_INFO, "I2cEnable Status = %r\r\n", Status));
MmioRead32 ( mI2CBaseAddress + R_IC_CLR_TX_ABRT );
return EFI_SUCCESS;
}
/**
Reads a Byte from I2C Device.
@param I2cControllerIndex I2C Bus no to which the I2C device has been connected
@param SlaveAddress Device Address from which the byte value has to be read
@param Offset Offset from which the data has to be read
@param *Byte Address to which the value read has to be stored
@param Start Whether a RESTART is issued before the byte is sent or received
@param End Whether STOP is generated after a data byte is sent or received
@return EFI_SUCCESS IF the byte value has been successfully read
@return EFI_DEVICE_ERROR Operation Failed, Device Error
**/
EFI_STATUS
ByteReadI2CBasic(
IN UINT8 I2cControllerIndex,
IN UINT8 SlaveAddress,
IN UINTN ReadBytes,
OUT UINT8 *ReadBuffer,
IN UINT8 Start,
IN UINT8 End
)
{
EFI_STATUS Status;
UINT32 I2cStatus;
UINT16 ReceiveData;
UINT8 *ReceiveDataEnd;
UINT8 *ReceiveRequest;
UINT16 RawIntrStat;
UINT32 Count=0;
Status = EFI_SUCCESS;
ReceiveDataEnd = &ReadBuffer [ReadBytes];
if( ReadBytes ) {
ReceiveRequest = ReadBuffer;
DEBUG((EFI_D_INFO,"Read: ---------------%d bytes to RX\r\n",ReceiveDataEnd - ReceiveRequest));
while ((ReceiveDataEnd > ReceiveRequest) || (ReceiveDataEnd > ReadBuffer)) {
//
// Check for NACK
//
RawIntrStat = (UINT16)MmioRead32 (mI2CBaseAddress + R_IC_RawIntrStat);
if ( 0 != ( RawIntrStat & I2C_INTR_TX_ABRT )) {
MmioRead32 ( mI2CBaseAddress + R_IC_CLR_TX_ABRT );
Status = RETURN_DEVICE_ERROR;
DEBUG((EFI_D_INFO,"TX ABRT ,%d bytes hasn't been transferred\r\n",ReceiveDataEnd - ReceiveRequest));
break;
}
//
// Determine if another byte was received
//
I2cStatus = (UINT16)MmioRead32 (mI2CBaseAddress + R_IC_STATUS);
if (0 != ( I2cStatus & STAT_RFNE )) {
ReceiveData = (UINT16)MmioRead32 ( mI2CBaseAddress + R_IC_DATA_CMD );
*ReadBuffer++ = (UINT8)ReceiveData;
DEBUG((EFI_D_INFO,"MmioRead32 ,1 byte 0x:%x is received\r\n",ReceiveData));
}
if(ReceiveDataEnd == ReceiveRequest) {
MicroSecondDelay ( FIFO_WRITE_DELAY );
DEBUG((EFI_D_INFO,"ReceiveDataEnd==ReceiveRequest------------%x\r\n",I2cStatus & STAT_RFNE));
Count++;
if(Count<1024) {
//
// To avoid sys hung without ul-pmc device on RVP,
// waiting the last request to get data and make (ReceiveDataEnd > ReadBuffer) =TRUE.
//
continue;
} else {
break;
}
}
//
// Wait until a read request will fit.
//
if (0 == (I2cStatus & STAT_TFNF)) {
DEBUG((EFI_D_INFO,"Wait until a read request will fit\r\n"));
MicroSecondDelay (10);
continue;
}
//
// Issue the next read request.
//
if(End && Start) {
MmioWrite32 ( mI2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_RESTART|B_CMD_STOP);
} else if (!End && Start) {
MmioWrite32 ( mI2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_RESTART);
} else if (End && !Start) {
MmioWrite32 ( mI2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_STOP);
} else if (!End && !Start) {
MmioWrite32 ( mI2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD);
}
MicroSecondDelay (FIFO_WRITE_DELAY);
ReceiveRequest += 1;
}
}
return Status;
}
/**
Writes a Byte to I2C Device.
@param I2cControllerIndex I2C Bus no to which the I2C device has been connected
@param SlaveAddress Device Address from which the byte value has to be written
@param Offset Offset from which the data has to be read
@param *Byte Address to which the value written is stored
@param Start Whether a RESTART is issued before the byte is sent or received
@param End Whether STOP is generated after a data byte is sent or received
@return EFI_SUCCESS IF the byte value has been successfully written
@return EFI_DEVICE_ERROR Operation Failed, Device Error
**/
EFI_STATUS ByteWriteI2CBasic(
IN UINT8 I2cControllerIndex,
IN UINT8 SlaveAddress,
IN UINTN WriteBytes,
IN UINT8 *WriteBuffer,
IN UINT8 Start,
IN UINT8 End
)
{
EFI_STATUS Status;
UINT32 I2cStatus;
UINT8 *TransmitEnd;
UINT16 RawIntrStat;
UINT32 Count=0;
Status = EFI_SUCCESS;
Status=I2CInit(I2cControllerIndex, SlaveAddress);
if(Status!=EFI_SUCCESS)
return Status;
TransmitEnd = &WriteBuffer[WriteBytes];
if( WriteBytes ) {
DEBUG((EFI_D_INFO,"Write: --------------%d bytes to TX\r\n",TransmitEnd - WriteBuffer));
while (TransmitEnd > WriteBuffer) {
I2cStatus = MmioRead32 (mI2CBaseAddress + R_IC_STATUS);
RawIntrStat = (UINT16)MmioRead32 (mI2CBaseAddress + R_IC_RawIntrStat);
if (0 != ( RawIntrStat & I2C_INTR_TX_ABRT)) {
MmioRead32 ( mI2CBaseAddress + R_IC_CLR_TX_ABRT);
Status = RETURN_DEVICE_ERROR;
DEBUG((EFI_D_ERROR,"TX ABRT TransmitEnd:0x%x WriteBuffer:0x%x\r\n", TransmitEnd, WriteBuffer));
break;
}
if (0 == (I2cStatus & STAT_TFNF)) {
//
// If TX not full , will send cmd or continue to wait
//
MicroSecondDelay (FIFO_WRITE_DELAY);
continue;
}
if(End && Start) {
MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++)|B_CMD_RESTART|B_CMD_STOP);
} else if (!End && Start) {
MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++)|B_CMD_RESTART);
} else if (End && !Start) {
MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++)|B_CMD_STOP);
} else if (!End && !Start ) {
MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++));
}
//
// Add a small delay to work around some odd behavior being seen. Without this delay bytes get dropped.
//
MicroSecondDelay ( FIFO_WRITE_DELAY );//wait after send cmd
//
// Time out
//
while(1) {
RawIntrStat = MmioRead16 ( mI2CBaseAddress + R_IC_RawIntrStat );
if (0 != ( RawIntrStat & I2C_INTR_TX_ABRT)) {
MmioRead16 (mI2CBaseAddress + R_IC_CLR_TX_ABRT);
Status = RETURN_DEVICE_ERROR;
DEBUG((EFI_D_ERROR,"TX ABRT TransmitEnd:0x%x WriteBuffer:0x%x\r\n", TransmitEnd, WriteBuffer));
}
if(0 == MmioRead16(mI2CBaseAddress + R_IC_TXFLR)) break;
MicroSecondDelay (FIFO_WRITE_DELAY);
Count++;
if(Count<1024) {
//
// to avoid sys hung without ul-pmc device on RVP.
// Waiting the last request to get data and make (ReceiveDataEnd > ReadBuffer) =TRUE.
//
continue;
} else {
break;
}
}//while( 1 )
}
}
return Status;
}
/**
Reads a Byte from I2C Device.
@param I2cControllerIndex I2C Bus no to which the I2C device has been connected
@param SlaveAddress Device Address from which the byte value has to be read
@param Offset Offset from which the data has to be read
@param ReadBytes Number of bytes to be read
@param *ReadBuffer Address to which the value read has to be stored
@return EFI_SUCCESS IF the byte value has been successfully read
@return EFI_DEVICE_ERROR Operation Failed, Device Error
**/
EFI_STATUS ByteReadI2C(
IN UINT8 I2cControllerIndex,
IN UINT8 SlaveAddress,
IN UINT8 Offset,
IN UINTN ReadBytes,
OUT UINT8 *ReadBuffer
)
{
EFI_STATUS Status;
DEBUG ((EFI_D_INFO, "ByteReadI2C:---offset:0x%x\n",Offset));
Status = ByteWriteI2CBasic(I2cControllerIndex, SlaveAddress,1,&Offset,TRUE,FALSE);
Status = ByteReadI2CBasic(I2cControllerIndex, SlaveAddress,ReadBytes,ReadBuffer,TRUE,TRUE);
return Status;
}
/**
Writes a Byte to I2C Device.
@param I2cControllerIndex I2C Bus no to which the I2C device has been connected
@param SlaveAddress Device Address from which the byte value has to be written
@param Offset Offset from which the data has to be written
@param WriteBytes Number of bytes to be written
@param *Byte Address to which the value written is stored
@return EFI_SUCCESS IF the byte value has been successfully read
@return EFI_DEVICE_ERROR Operation Failed, Device Error
**/
EFI_STATUS ByteWriteI2C(
IN UINT8 I2cControllerIndex,
IN UINT8 SlaveAddress,
IN UINT8 Offset,
IN UINTN WriteBytes,
IN UINT8 *WriteBuffer
)
{
EFI_STATUS Status;
DEBUG ((EFI_D_INFO, "ByteWriteI2C:---offset/bytes/buf:0x%x,0x%x,0x%x,0x%x\n",Offset,WriteBytes,WriteBuffer,*WriteBuffer));
Status = ByteWriteI2CBasic(I2cControllerIndex, SlaveAddress,1,&Offset,TRUE,FALSE);
Status = ByteWriteI2CBasic(I2cControllerIndex, SlaveAddress,WriteBytes,WriteBuffer,FALSE,TRUE);
return Status;
}

View File

@@ -0,0 +1,44 @@
## @file
# Instance of I2C Library.
#
# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
#
# 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.
#
#
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = I2CLib
FILE_GUID = 7f62bf44-2ba7-4c2d-9d4a-91c8906ff053
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = I2CLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources.common]
I2CLib.c
[LibraryClasses]
BaseLib
IoLib
TimerLib
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
Vlv2TbltDevicePkg/PlatformPkg.dec
Vlv2DeviceRefCodePkg/Vlv2DeviceRefCodePkg.dec
[Protocols]
gEfiGlobalNvsAreaProtocolGuid

View File

@@ -0,0 +1,132 @@
/** @file
Register Definitions for I2C Driver/PEIM.
Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that 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.
--*/
#ifndef I2C_REGS_H
#define I2C_REGS_H
//
// FIFO write delay value.
//
#define FIFO_WRITE_DELAY 2
//
// MMIO Register Definitions.
//
#define R_IC_CON ( 0x00) // I2C Control
#define B_IC_RESTART_EN BIT5
#define B_IC_SLAVE_DISABLE BIT6
#define V_SPEED_STANDARD 0x02
#define V_SPEED_FAST 0x04
#define V_SPEED_HIGH 0x06
#define B_MASTER_MODE BIT0
#define R_IC_TAR ( 0x04) // I2C Target Address
#define IC_TAR_10BITADDR_MASTER BIT12
#define R_IC_SAR ( 0x08) // I2C Slave Address
#define R_IC_HS_MADDR ( 0x0C) // I2C HS MasterMode Code Address
#define R_IC_DATA_CMD ( 0x10) // I2C Rx/Tx Data Buffer and Command
#define B_READ_CMD BIT8 // 1 = read, 0 = write
#define B_CMD_STOP BIT9 // 1 = STOP
#define B_CMD_RESTART BIT10 // 1 = IC_RESTART_EN
#define V_WRITE_CMD_MASK ( 0xFF)
#define R_IC_SS_SCL_HCNT ( 0x14) // Standard Speed I2C Clock SCL High Count
#define R_IC_SS_SCL_LCNT ( 0x18) // Standard Speed I2C Clock SCL Low Count
#define R_IC_FS_SCL_HCNT ( 0x1C) // Full Speed I2C Clock SCL High Count
#define R_IC_FS_SCL_LCNT ( 0x20) // Full Speed I2C Clock SCL Low Count
#define R_IC_HS_SCL_HCNT ( 0x24) // High Speed I2C Clock SCL High Count
#define R_IC_HS_SCL_LCNT ( 0x28) // High Speed I2C Clock SCL Low Count
#define R_IC_INTR_STAT ( 0x2C) // I2C Inetrrupt Status
#define R_IC_INTR_MASK ( 0x30) // I2C Interrupt Mask
#define I2C_INTR_GEN_CALL BIT11 // General call received
#define I2C_INTR_START_DET BIT10
#define I2C_INTR_STOP_DET BIT9
#define I2C_INTR_ACTIVITY BIT8
#define I2C_INTR_TX_ABRT BIT6 // Set on NACK
#define I2C_INTR_TX_EMPTY BIT4
#define I2C_INTR_TX_OVER BIT3
#define I2C_INTR_RX_FULL BIT2 // Data bytes in RX FIFO over threshold
#define I2C_INTR_RX_OVER BIT1
#define I2C_INTR_RX_UNDER BIT0
#define R_IC_RawIntrStat ( 0x34) // I2C Raw Interrupt Status
#define R_IC_RX_TL ( 0x38) // I2C Receive FIFO Threshold
#define R_IC_TX_TL ( 0x3C) // I2C Transmit FIFO Threshold
#define R_IC_CLR_INTR ( 0x40) // Clear Combined and Individual Interrupts
#define R_IC_CLR_RX_UNDER ( 0x44) // Clear RX_UNDER Interrupt
#define R_IC_CLR_RX_OVER ( 0x48) // Clear RX_OVERinterrupt
#define R_IC_CLR_TX_OVER ( 0x4C) // Clear TX_OVER interrupt
#define R_IC_CLR_RD_REQ ( 0x50) // Clear RD_REQ interrupt
#define R_IC_CLR_TX_ABRT ( 0x54) // Clear TX_ABRT interrupt
#define R_IC_CLR_RX_DONE ( 0x58) // Clear RX_DONE interrupt
#define R_IC_CLR_ACTIVITY ( 0x5C) // Clear ACTIVITY interrupt
#define R_IC_CLR_STOP_DET ( 0x60) // Clear STOP_DET interrupt
#define R_IC_CLR_START_DET ( 0x64) // Clear START_DET interrupt
#define R_IC_CLR_GEN_CALL ( 0x68) // Clear GEN_CALL interrupt
#define R_IC_ENABLE ( 0x6C) // I2C Enable
#define R_IC_STATUS ( 0x70) // I2C Status
#define R_IC_SDA_HOLD ( 0x7C) // I2C IC_DEFAULT_SDA_HOLD//16bits
#define STAT_MST_ACTIVITY BIT5 // Master FSM Activity Status.
#define STAT_RFF BIT4 // RX FIFO is completely full
#define STAT_RFNE BIT3 // RX FIFO is not empty
#define STAT_TFE BIT2 // TX FIFO is completely empty
#define STAT_TFNF BIT1 // TX FIFO is not full
#define R_IC_TXFLR ( 0x74) // Transmit FIFO Level Register
#define R_IC_RXFLR ( 0x78) // Receive FIFO Level Register
#define R_IC_TX_ABRT_SOURCE ( 0x80) // I2C Transmit Abort Status Register
#define R_IC_SLV_DATA_NACK_ONLY ( 0x84) // Generate SLV_DATA_NACK Register
#define R_IC_DMA_CR ( 0x88) // DMA Control Register
#define R_IC_DMA_TDLR ( 0x8C) // DMA Transmit Data Level
#define R_IC_DMA_RDLR ( 0x90) // DMA Receive Data Level
#define R_IC_SDA_SETUP ( 0x94) // I2C SDA Setup Register
#define R_IC_ACK_GENERAL_CALL ( 0x98) // I2C ACK General Call Register
#define R_IC_ENABLE_STATUS ( 0x9C) // I2C Enable Status Register
#define R_IC_COMP_PARAM ( 0xF4) // Component Parameter Register
#define R_IC_COMP_VERSION ( 0xF8) // Component Version ID
#define R_IC_COMP_TYPE ( 0xFC) // Component Type
#define I2C_SS_SCL_HCNT_VALUE_100M 0x1DD
#define I2C_SS_SCL_LCNT_VALUE_100M 0x1E4
#define I2C_FS_SCL_HCNT_VALUE_100M 0x54
#define I2C_FS_SCL_LCNT_VALUE_100M 0x9a
#define I2C_HS_SCL_HCNT_VALUE_100M 0x7
#define I2C_HS_SCL_LCNT_VALUE_100M 0xE
#define IC_TAR_10BITADDR_MASTER BIT12
#define FIFO_SIZE 32
#define R_IC_INTR_STAT ( 0x2C) // I2c Inetrrupt Status
#define R_IC_INTR_MASK ( 0x30) // I2c Interrupt Mask
#define I2C_INTR_GEN_CALL BIT11 // General call received
#define I2C_INTR_START_DET BIT10
#define I2C_INTR_STOP_DET BIT9
#define I2C_INTR_ACTIVITY BIT8
#define I2C_INTR_TX_ABRT BIT6 // Set on NACK
#define I2C_INTR_TX_EMPTY BIT4
#define I2C_INTR_TX_OVER BIT3
#define I2C_INTR_RX_FULL BIT2 // Data bytes in RX FIFO over threshold
#define I2C_INTR_RX_OVER BIT1
#define I2C_INTR_RX_UNDER BIT0
#define R_PCH_LPIO_I2C_MEM_RESETS 0x804 // Software Reset
#define B_PCH_LPIO_I2C_MEM_RESETS_FUNC BIT1 // Function Clock Domain Reset
#define B_PCH_LPIO_I2C_MEM_RESETS_APB BIT0 // APB Domain Reset
#define R_PCH_LPSS_I2C_MEM_PCP 0x800 // Private Clock Parameters
#endif