summaryrefslogtreecommitdiff
path: root/Vlv2TbltDevicePkg/Library/I2CLibDxe
diff options
context:
space:
mode:
authorDavid Wei <david.wei@intel.com>2015-06-02 01:47:57 +0000
committerzwei4 <zwei4@Edk2>2015-06-02 01:47:57 +0000
commit4e5220964b7108bbc9f731b326680e865aa63560 (patch)
tree9d6e583c666ef58ab8d142c4858fe1f24e76ec36 /Vlv2TbltDevicePkg/Library/I2CLibDxe
parentc85bc0c9d425c04055496fd2111e12ab3471ef31 (diff)
downloadedk2-platforms-4e5220964b7108bbc9f731b326680e865aa63560.tar.xz
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
Diffstat (limited to 'Vlv2TbltDevicePkg/Library/I2CLibDxe')
-rw-r--r--Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CLib.c741
-rw-r--r--Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CLibDxe.inf44
-rw-r--r--Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CRegs.h132
3 files changed, 917 insertions, 0 deletions
diff --git a/Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CLib.c b/Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CLib.c
new file mode 100644
index 0000000000..dee286ba05
--- /dev/null
+++ b/Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CLib.c
@@ -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;
+}
diff --git a/Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CLibDxe.inf b/Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CLibDxe.inf
new file mode 100644
index 0000000000..277504ad39
--- /dev/null
+++ b/Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CLibDxe.inf
@@ -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
diff --git a/Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CRegs.h b/Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CRegs.h
new file mode 100644
index 0000000000..443d57eddf
--- /dev/null
+++ b/Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CRegs.h
@@ -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 \ No newline at end of file