From: David Wei Date: Tue, 2 Jun 2015 01:47:57 +0000 (+0000) Subject: Add Sample I2C Library for Baytrail I2C Controller. X-Git-Tag: edk2-stable201903~9714 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;ds=sidebyside;h=4e5220964b7108bbc9f731b326680e865aa63560;p=mirror_edk2.git Add Sample I2C Library for Baytrail I2C Controller. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: David Wei Reviewed-by: Tim He git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17546 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/Vlv2TbltDevicePkg/Include/Library/I2CLib.h b/Vlv2TbltDevicePkg/Include/Library/I2CLib.h new file mode 100644 index 0000000000..893d88519c --- /dev/null +++ b/Vlv2TbltDevicePkg/Include/Library/I2CLib.h @@ -0,0 +1,64 @@ +/** @file + Interface Definitions for I2C Lib. + + Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
+ + 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 +#include + +#ifndef I2C_LIB_HEADER_H +#define I2C_LIB_HEADER_H + + +/** + 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 BusNo, + IN UINT8 SlaveAddress, + IN UINT8 Offset, + IN UINTN ReadBytes, + OUT UINT8 *ReadBuffer + ); + +/** + 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 BusNo, + IN UINT8 SlaveAddress, + IN UINT8 Offset, + IN UINTN WriteBytes, + IN UINT8 *WriteBuffer + ); + +#endif 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.
+ + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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.
+# +# 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.
+ + 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 diff --git a/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CAccess.h b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CAccess.h new file mode 100644 index 0000000000..27ec57322c --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CAccess.h @@ -0,0 +1,50 @@ +/** @file + Misc Registers Definition. + + Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+ + 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_ACCESS_H_ +#define _I2C_ACCESS_H_ + +#include "I2CIoLibPei.h" + +#define DEFAULT_PCI_BUS_NUMBER_PCH 0 + +#define PCI_DEVICE_NUMBER_PCH_LPC 31 +#define PCI_FUNCTION_NUMBER_PCH_LPC 0 + +#define R_PCH_LPC_ACPI_BASE 0x40 // ABASE, 16bit +#define R_PCH_LPC_ACPI_BASEADR 0x400 // ABASE, 16bit +#define B_PCH_LPC_ACPI_BASE_EN BIT1 // Enable Bit +#define B_PCH_LPC_ACPI_BASE_BAR 0x0000FF80 // Base Address, 128 Bytes +#define V_PCH_ACPI_PM1_TMR_MAX_VAL 0x1000000 // The timer is 24 bit overflow +#define B_PCH_ACPI_PM1_TMR_VAL 0xFFFFFF // The timer value mask + +#define R_PCH_ACPI_PM1_TMR 0x08 // Power Management 1 Timer +#define V_PCH_ACPI_PM1_TMR_FREQUENCY 3579545 // Timer Frequency + + +#define PchLpcPciCfg8(Register) I2CLibPeiMmioRead8 (MmPciAddress (0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, 0, Register)) + +#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) \ + ) +#endif + diff --git a/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CDelayPei.c b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CDelayPei.c new file mode 100644 index 0000000000..3fedc33d9e --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CDelayPei.c @@ -0,0 +1,52 @@ +/** @file + MicroSecondDelay implementation of ACPI Timer. + + Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+ + 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 "PiPei.h" +#include "I2CAccess.h" +#include "I2CDelayPei.h" +#include +#include +#include + +/** + Stalls the CPU for at least the given number of microseconds. + Stalls the CPU for the number of microseconds specified by MicroSeconds. + + @param MicroSeconds The minimum number of microseconds to delay. + + @return EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ) +{ + + EFI_PEI_STALL_PPI *StallPpi; + EFI_STATUS Status; + CONST EFI_PEI_SERVICES **PeiServices; + + PeiServices = GetPeiServicesTablePointer(); + + + Status = (**PeiServices).LocatePpi (PeiServices, &gEfiPeiStallPpiGuid, 0, NULL, &StallPpi); + ASSERT(!EFI_ERROR(Status)); + + StallPpi->Stall (PeiServices, StallPpi, MicroSeconds); + + return EFI_SUCCESS; +} diff --git a/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CDelayPei.h b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CDelayPei.h new file mode 100644 index 0000000000..44597f3f6b --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CDelayPei.h @@ -0,0 +1,36 @@ +/** @file + MicroSecondDelay implementation of ACPI Timer. + + Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef __I2C_DELAY_PEI__ + +#define __I2C_DELAY_PEI__ +#include "PiPei.h" + +/** + Stalls the CPU for at least the given number of microseconds. + + Stalls the CPU for the number of microseconds specified by MicroSeconds. + + @param MicroSeconds The minimum number of microseconds to delay. + + @return MicroSeconds + +**/ +EFI_STATUS +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ); + +#endif diff --git a/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CIoLibPei.c b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CIoLibPei.c new file mode 100644 index 0000000000..38e67bbd53 --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CIoLibPei.c @@ -0,0 +1,184 @@ +/** @file + Functions for access I2C MMIO register. + + Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include + +/** + Reads an 8-bit MMIO register. + + Reads the 8-bit MMIO register specified by Address. The 8-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 8-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT8 +EFIAPI +I2CLibPeiMmioRead8 ( + IN UINTN Address + ) +{ + UINT8 Value; + + Value = *(volatile UINT8*)Address; + return Value; +} + +/** + Reads a 16-bit MMIO register. + + Reads the 16-bit MMIO register specified by Address. The 16-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 16-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT16 +EFIAPI +I2CLibPeiMmioRead16 ( + IN UINTN Address + ) +{ + UINT16 Value; + + ASSERT ((Address & 1) == 0); + Value = *(volatile UINT16*)Address; + return Value; +} + +/** + Writes a 16-bit MMIO register. + + Writes the 16-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 16-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + + @return Value. + +**/ +UINT16 +EFIAPI +I2CLibPeiMmioWrite16 ( + IN UINTN Address, + IN UINT16 Value + ) +{ + ASSERT ((Address & 1) == 0); + *(volatile UINT16*)Address = Value; + return Value; +} + +/** + Reads a 32-bit MMIO register. + + Reads the 32-bit MMIO register specified by Address. The 32-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 32-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT32 +EFIAPI +I2CLibPeiMmioRead32 ( + IN UINTN Address + ) +{ + UINT32 Value; + + ASSERT ((Address & 3) == 0); + Value = *(volatile UINT32*)Address; + + return Value; +} + +/** + Writes a 32-bit MMIO register. + + Writes the 32-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 32-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + + @return Value. + +**/ +UINT32 +EFIAPI +I2CLibPeiMmioWrite32 ( + IN UINTN Address, + IN UINT32 Value + ) +{ + ASSERT ((Address & 3) == 0); + *(volatile UINT32*)Address = Value; + return Value; +} + +/** + OR a 32-bit MMIO register. + + OR the 32-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 32-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The MMIO register to write OR. + @param Value The value to OR to the MMIO register. + + @return Value. + +**/ +UINT32 +EFIAPI +I2CLibPeiMmioOr32 ( + IN UINTN Address, + IN UINT32 OrData + ) +{ + return I2CLibPeiMmioWrite32 (Address, I2CLibPeiMmioRead32(Address) | OrData); +} + + diff --git a/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CIoLibPei.h b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CIoLibPei.h new file mode 100644 index 0000000000..c82181af6e --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CIoLibPei.h @@ -0,0 +1,159 @@ +/** @file + Functions for access I2C MMIO register. + + Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef __I2C_IOLIB_PEI__ + +#define __I2C_IOLIB_PEI__ +#include + + +/** + Reads an 8-bit MMIO register. + + Reads the 8-bit MMIO register specified by Address. The 8-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 8-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ + +UINT8 +EFIAPI +I2CLibPeiMmioRead8 ( + IN UINTN Address + ); + + +/** + Reads a 16-bit MMIO register. + + Reads the 16-bit MMIO register specified by Address. The 16-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 16-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT16 +EFIAPI +I2CLibPeiMmioRead16 ( + IN UINTN Address + ); + + +/** + Writes a 16-bit MMIO register. + + Writes the 16-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 16-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + + @return Value. + +**/ +UINT16 +EFIAPI +I2CLibPeiMmioWrite16 ( + IN UINTN Address, + IN UINT16 Value + ); + + +/** + Reads a 32-bit MMIO register. + + Reads the 32-bit MMIO register specified by Address. The 32-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 32-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT32 +EFIAPI +I2CLibPeiMmioRead32 ( + IN UINTN Address + ); + + +/** + Writes a 32-bit MMIO register. + + Writes the 32-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 32-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + + @return Value. + +**/ +UINT32 +EFIAPI +I2CLibPeiMmioWrite32 ( + IN UINTN Address, + IN UINT32 Value + ); + + +/** + OR a 32-bit MMIO register. + + OR the 32-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 32-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The MMIO register to write OR. + @param Value The value to OR to the MMIO register. + + @return Value. + +**/ +UINT32 +EFIAPI +I2CLibPeiMmioOr32 ( + IN UINTN Address, + IN UINT32 OrData + ); + + +#endif diff --git a/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.c b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.c new file mode 100644 index 0000000000..006472ed8f --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.c @@ -0,0 +1,644 @@ +/** @file + I2C PEI Lib Instance. + + Copyright (c) 1999- 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "I2CDelayPei.h" +#include "I2CIoLibPei.h" +#include "I2CAccess.h" +#include "I2CLibPei.h" +#include +#include +#include +#include +#include +#include +#include + +#define LPSS_PCI_DEVICE_NUMBER 8 + +#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 + +#define PEI_TEPM_LPSS_DMA_BAR 0xFE900000 +#define PEI_TEPM_LPSS_I2C0_BAR 0xFE910000 +#define PCI_CONFIG_SPACE_SIZE 0x10000 + +EFI_GUID mI2CPeiInitGuid = { + 0x96DED71A, 0xB9E7, 0x4EAD, 0x96, 0x2C, 0x01, 0x69, 0x3C, 0xED, 0x2A, 0x64 +}; + + +UINT16 I2CGPIO[]= { + // + // 19.1.6 I2C0 + // I2C0_SDA-OD-O - write 0x2003CC81 to IOBASE + 0x0210 + // I2C0_SCL-OD-O - write 0x2003CC81 to IOBASE + 0x0200 + // + 0x0210, + 0x0200, + + // + // 19.1.7 I2C1 + // I2C1_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x01F0 + // I2C1_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x01E0 + // + 0x01F0, + 0x01E0, + + // + // 19.1.8 I2C2 + // I2C2_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x01D0 + // I2C2_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x01B0 + // + 0x01D0, + 0x01B0, + + // + // 19.1.9 I2C3 + // I2C3_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x0190 + // I2C3_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x01C0 + // + 0x0190, + 0x01C0, + + // + // 19.1.10 I2C4 + // I2C4_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x01A0 + // I2C4_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x0170 + // + 0x01A0, + 0x0170, + + // + // 19.1.11 I2C5 + // I2C5_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x0150 + // I2C5_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x0140 + // + 0x0150, + 0x0140, + + // + // 19.1.12 I2C6 + // I2C6_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x0180 + // I2C6_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x0160 + // + 0x0180, + 0x0160 +}; + +/** + Constructor of this library. + + @param VOID + + @return EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +IntelI2CPeiLibConstructor ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + UINTN Index; + + for (Index = 0; Index < sizeof(I2CGPIO)/sizeof(UINT16); Index ++) { + I2CLibPeiMmioWrite32(IO_BASE_ADDRESS+I2CGPIO[Index], 0x2003CC81); + } + + return EFI_SUCCESS; +} + +/** + Programe all I2C controllers on LPSS. + + I2C0 is function 1 of LPSS. I2C1 is function 2 of LPSS, etc.. + + @param VOID + + @return EFI_SUCCESS +**/ +EFI_STATUS +ProgramPciLpssI2C ( + VOID + ) +{ + UINT32 PmcBase; + UINT32 DevID; + UINTN PciMmBase=0; + UINTN Index; + UINTN Bar0; + UINTN Bar1; + DEBUG ((EFI_D_INFO, "Pei ProgramPciLpssI2C() Start\n")); + + // + // Set the VLV Function Disable Register to ZERO + // + PmcBase = I2CLibPeiMmioRead32(PciD31F0RegBase + R_PCH_LPC_PMC_BASE) & B_PCH_LPC_PMC_BASE_BAR; + + if(I2CLibPeiMmioRead32(PmcBase + R_PCH_PMC_FUNC_DIS)& + (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)) { + I2CLibPeiMmioWrite32( + PmcBase+R_PCH_PMC_FUNC_DIS, + I2CLibPeiMmioRead32(PmcBase + R_PCH_PMC_FUNC_DIS)& \ + ~(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() enable all I2C controllers\n")); + } + + for(Index = 0; Index < LPSS_PCI_DEVICE_NUMBER; Index ++) { + + PciMmBase = MmPciAddress ( + 0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPSS_I2C, + Index, + 0 + ); + DevID = I2CLibPeiMmioRead32(PciMmBase); + + Bar0 = PEI_TEPM_LPSS_DMA_BAR + (Index * PCI_CONFIG_SPACE_SIZE); + Bar1 = Bar0 + 0x8000; + + DEBUG((EFI_D_ERROR, "Program Pci Lpss I2C Device Function=%x DevID=%08x\n", Index, DevID)); + + // + // Check if device present + // + if (DevID != 0xFFFFFFFF) { + if(!(I2CLibPeiMmioRead32 (PciMmBase + R_PCH_LPSS_I2C_STSCMD) & B_PCH_LPSS_I2C_STSCMD_MSE)) { + // + // Program BAR 0 + // + I2CLibPeiMmioWrite32((UINTN) (PciMmBase + R_PCH_LPSS_I2C_BAR), (UINT32)(Bar0 & B_PCH_LPSS_I2C_BAR_BA)); + + DEBUG ((EFI_D_ERROR, "I2CBaseAddress1 = 0x%x \n",I2CLibPeiMmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR))); + + // + // Program BAR 1 + // + I2CLibPeiMmioWrite32 ((UINTN)(PciMmBase + R_PCH_LPSS_I2C_BAR1), (UINT32)(Bar1 & B_PCH_LPSS_I2C_BAR1_BA)); + DEBUG ((EFI_D_ERROR, "I2CBaseAddress1 = 0x%x \n",I2CLibPeiMmioRead32(PciMmBase+R_PCH_LPSS_I2C_BAR1))); + + // + // Bus Master Enable & Memory Space Enable + // + I2CLibPeiMmioWrite32((UINTN) (PciMmBase + R_PCH_LPSS_I2C_STSCMD), (UINT32)(B_PCH_LPSS_I2C_STSCMD_BME | B_PCH_LPSS_I2C_STSCMD_MSE)); + } + + // + // Release Resets + // + I2CLibPeiMmioWrite32 (Bar0 + R_PCH_LPIO_I2C_MEM_RESETS, (B_PCH_LPIO_I2C_MEM_RESETS_FUNC | B_PCH_LPIO_I2C_MEM_RESETS_APB)); + + // + // Activate Clocks + // + I2CLibPeiMmioWrite32 (Bar0 + R_PCH_LPSS_I2C_MEM_PCP, 0x80020003);//No use for A0 + + DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() Programmed()\n")); + } + + } + + DEBUG ((EFI_D_INFO, "Pei ProgramPciLpssI2C() End\n")); + + return EFI_SUCCESS; +} + +/** + Disable I2C Bus. + + @param I2cControllerIndex Index of I2C controller. + + @return EFI_SUCCESS +**/ +EFI_STATUS +I2cDisable ( + IN UINT8 I2cControllerIndex + ) +{ + UINTN I2CBaseAddress; + UINT32 NumTries = 10000; // 0.1 seconds + + I2CBaseAddress = (UINT32) PEI_TEPM_LPSS_I2C0_BAR + I2cControllerIndex * PCI_CONFIG_SPACE_SIZE; + + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_ENABLE, 0); + while (0 != ( I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_ENABLE_STATUS ) & 1)) { + MicroSecondDelay (10); + NumTries --; + if(0 == NumTries) return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + +/** + Enable I2C Bus. + + @param I2cControllerIndex Index of I2C controller. + + @return EFI_SUCCESS +**/ +EFI_STATUS +I2cEnable ( + IN UINT8 I2cControllerIndex + ) +{ + UINTN I2CBaseAddress; + UINT32 NumTries = 10000; // 0.1 seconds + + I2CBaseAddress = (UINT32) PEI_TEPM_LPSS_I2C0_BAR+ I2cControllerIndex * PCI_CONFIG_SPACE_SIZE; + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_ENABLE, 1); + while (0 == ( I2CLibPeiMmioRead16 ( I2CBaseAddress + R_IC_ENABLE_STATUS ) & 1)) { + MicroSecondDelay (10); + NumTries --; + if(0 == NumTries) return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + + +/** + Set the I2C controller bus clock frequency. + + @param[in] This Address of the library's I2C context structure + @param[in] PlatformData Address of the platform configuration data + @param[in] BusClockHertz New I2C bus clock frequency in Hertz + + @retval RETURN_SUCCESS The bus frequency was set successfully. + @retval RETURN_UNSUPPORTED The controller does not support this frequency. + +**/ +EFI_STATUS +I2cBusFrequencySet ( + IN UINTN I2CBaseAddress, + IN UINTN BusClockHertz, + IN UINT16 *I2cMode + ) +{ + DEBUG((EFI_D_INFO,"InputFreq BusClockHertz: %d\r\n",BusClockHertz)); + + *I2cMode = B_IC_RESTART_EN | B_IC_SLAVE_DISABLE | B_MASTER_MODE; + + // + // Set the 100 KHz clock divider + // + // From Table 10 of the I2C specification + // + // High: 4.00 uS + // Low: 4.70 uS + // + I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_SS_SCL_HCNT, (UINT16)0x214 ); + I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_SS_SCL_LCNT, (UINT16)0x272 ); + + // + // Set the 400 KHz clock divider + // + // From Table 10 of the I2C specification + // + // High: 0.60 uS + // Low: 1.30 uS + // + I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_FS_SCL_HCNT, (UINT16)0x50 ); + I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_FS_SCL_LCNT, (UINT16)0xAD ); + + switch ( BusClockHertz ) { + case 100 * 1000: + I2CLibPeiMmioWrite32 ( I2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x40);//100K + *I2cMode |= V_SPEED_STANDARD; + break; + case 400 * 1000: + I2CLibPeiMmioWrite32 ( I2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x32);//400K + *I2cMode |= V_SPEED_FAST; + break; + default: + I2CLibPeiMmioWrite32 ( I2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x09);//3.4M + *I2cMode |= V_SPEED_HIGH; + } + + 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 ( + UINT8 I2cControllerIndex, + UINT16 SlaveAddress + ) +{ + EFI_STATUS Status; + UINT32 NumTries = 0; + UINTN I2CBaseAddress; + UINT16 I2cMode; + UINTN PciMmBase=0; + + + PciMmBase = MmPciAddress ( + 0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPSS_I2C, + (I2cControllerIndex + 1), + 0 + ); + + I2CBaseAddress = I2CLibPeiMmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR); + + // + // Verify the parameters + // + if (1023 < SlaveAddress ) { + Status = EFI_INVALID_PARAMETER; + DEBUG((EFI_D_INFO,"I2cStartRequest Exit with Status %r\r\n", Status)); + return Status; + } + + if(I2CBaseAddress == (PEI_TEPM_LPSS_I2C0_BAR + I2cControllerIndex * PCI_CONFIG_SPACE_SIZE)) { + return EFI_SUCCESS; + } + ProgramPciLpssI2C(); + + I2CBaseAddress = (UINT32) (PEI_TEPM_LPSS_I2C0_BAR + I2cControllerIndex * PCI_CONFIG_SPACE_SIZE); + DEBUG ((EFI_D_ERROR, "I2CBaseAddress = 0x%x \n",I2CBaseAddress)); + NumTries = 10000; // 1 seconds + while ((1 == ( I2CLibPeiMmioRead32 ( I2CBaseAddress + R_IC_STATUS) & STAT_MST_ACTIVITY ))) { + MicroSecondDelay(10); + NumTries --; + if(0 == NumTries) + return EFI_DEVICE_ERROR; + } + + Status = I2cDisable (I2cControllerIndex); + DEBUG((EFI_D_INFO, "I2cDisable Status = %r\r\n", Status)); + + I2cBusFrequencySet(I2CBaseAddress, 400 * 1000, &I2cMode);//Set I2cMode + + I2CLibPeiMmioWrite16(I2CBaseAddress + R_IC_INTR_MASK, 0x0); + if (0x7F < SlaveAddress) { + SlaveAddress = (SlaveAddress & 0x3ff ) | IC_TAR_10BITADDR_MASTER; + } + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_TAR, (UINT16) SlaveAddress ); + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_RX_TL, 0); + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_TX_TL, 0 ); + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_CON, I2cMode); + + Status = I2cEnable(I2cControllerIndex); + DEBUG((EFI_D_INFO, "I2cEnable Status = %r\r\n", Status)); + I2CLibPeiMmioRead16 ( I2CBaseAddress + 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 + + @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; + UINTN I2CBaseAddress; + + I2CBaseAddress = (UINT32)(PEI_TEPM_LPSS_I2C0_BAR + I2cControllerIndex * PCI_CONFIG_SPACE_SIZE); + + Status = EFI_SUCCESS; + + I2CInit(I2cControllerIndex, SlaveAddress); + + 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 = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_RawIntrStat ); + if ( 0 != (RawIntrStat & I2C_INTR_TX_ABRT )) { + I2CLibPeiMmioRead16 ( I2CBaseAddress + 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 = I2CLibPeiMmioRead16 ( I2CBaseAddress + R_IC_STATUS ); + if ( 0 != ( I2cStatus & STAT_RFNE )) { + ReceiveData = I2CLibPeiMmioRead16 ( I2CBaseAddress + R_IC_DATA_CMD ); + *ReadBuffer++ = (UINT8)ReceiveData; + DEBUG((EFI_D_INFO,"MmioRead32 ,1 byte 0x:%x is received\r\n",ReceiveData)); + } + + if(ReceiveDataEnd==ReceiveRequest) { + // + // Waiting the last request to get data and make (ReceiveDataEnd > ReadBuffer) =TRUE. + // + continue; + } + + // + // Wait until a read request will fit + // + if ( 0 == ( I2cStatus & STAT_TFNF )) { + MicroSecondDelay ( 10 ); + continue; + } + + // + // Issue the next read request + // + if(End && Start ) { + I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_RESTART|B_CMD_STOP); + } else if (!End && Start ) { + I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_RESTART); + } else if (End && !Start ) { + I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_STOP); + } else if (!End && !Start ) { + I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD); + } + 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 + + @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; + UINTN I2CBaseAddress; + + I2CBaseAddress = (UINT32)PEI_TEPM_LPSS_I2C0_BAR+ I2cControllerIndex * PCI_CONFIG_SPACE_SIZE; + + Status = EFI_SUCCESS; + + I2CInit(I2cControllerIndex, SlaveAddress); + + TransmitEnd = &WriteBuffer [WriteBytes]; + if( WriteBytes ) { + + DEBUG((EFI_D_INFO,"Write: --------------%d bytes to TX\r\n", TransmitEnd - WriteBuffer)); + + while ( TransmitEnd > WriteBuffer) { + I2cStatus = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_STATUS); + RawIntrStat = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_RawIntrStat); + if ( 0 != (RawIntrStat & I2C_INTR_TX_ABRT)) { + I2CLibPeiMmioRead16 (I2CBaseAddress + 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)) { + continue; + } + if(End && Start) { + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++) | B_CMD_RESTART | B_CMD_STOP); + } else if (!End && Start ) { + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++) | B_CMD_RESTART); + } else if (End && !Start ) { + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++) | B_CMD_STOP); + } else if (!End && !Start ) { + I2CLibPeiMmioWrite16 (I2CBaseAddress + 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 ); + } + + } + + if(EFI_ERROR(Status)) { + DEBUG((EFI_D_INFO,"I2cStartRequest Exit with Status %r\r\n",Status)); + } + + 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_ERROR, "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_ERROR, "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/I2CLibPei/I2CLibPei.h b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.h new file mode 100644 index 0000000000..076d2a28be --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.h @@ -0,0 +1,286 @@ +/** @file + I2C PEI Lib Instance. + + Copyright (c) 1999- 2015, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef I2C_PEI_REGS_H +#define I2C_PEI_REGS_H + +#include "PiPei.h" + +#define R_PCH_LPC_PMC_BASE 0x44 +#define B_PCH_LPC_PMC_BASE_BAR 0xFFFFFE00 +#define R_PCH_PMC_FUNC_DIS 0x34 // Function Disable Register +#define PCIEX_BASE_ADDRESS 0xE0000000 +#define PciD31F0RegBase PCIEX_BASE_ADDRESS + (UINT32) (31 << 15) +#define B_PCH_PMC_FUNC_DIS_LPSS_FUNC7 BIT7 // LPSS SPI Disable +#define B_PCH_PMC_FUNC_DIS_LPSS_FUNC6 BIT6 // LPSS HSUART #2 Disable +#define B_PCH_PMC_FUNC_DIS_LPSS_FUNC5 BIT5 // LPSS HSUART #1 Disable +#define B_PCH_PMC_FUNC_DIS_LPSS_FUNC4 BIT4 // LPSS I2S Disable +#define B_PCH_PMC_FUNC_DIS_LPSS_FUNC3 BIT3 // LPSS PCM Disable +#define B_PCH_PMC_FUNC_DIS_LPSS_FUNC2 BIT2 // LPSS I2C #2 Disable +#define B_PCH_PMC_FUNC_DIS_LPSS_FUNC1 BIT1 // LPSS I2C #1 Disable +#define B_PCH_PMC_FUNC_DIS_LPSS_FUNC0 BIT0 // LPSS DMA Disable + + +#define DEFAULT_PCI_BUS_NUMBER_PCH 0 + +#define R_PCH_LPSS_I2C_STSCMD 0x04 // Status & Command +#define B_PCH_LPSS_I2C_STSCMD_RMA BIT29 // RMA +#define B_PCH_LPSS_I2C_STSCMD_RCA BIT28 // RCA +#define B_PCH_LPSS_I2C_STSCMD_CAPLIST BIT20 // Capability List +#define B_PCH_LPSS_I2C_STSCMD_INTRSTS BIT19 // Interrupt Status +#define B_PCH_LPSS_I2C_STSCMD_INTRDIS BIT10 // Interrupt Disable +#define B_PCH_LPSS_I2C_STSCMD_SERREN BIT8 // SERR# Enable +#define B_PCH_LPSS_I2C_STSCMD_BME BIT2 // Bus Master Enable +#define B_PCH_LPSS_I2C_STSCMD_MSE BIT1 // Memory Space Enable + +#define R_PCH_LPSS_I2C_BAR 0x10 // BAR +#define B_PCH_LPSS_I2C_BAR_BA 0xFFFFF000 // Base Address +#define B_PCH_LPSS_I2C_BAR_SI 0x00000FF0 // Size Indicator +#define B_PCH_LPSS_I2C_BAR_PF BIT3 // Prefetchable +#define B_PCH_LPSS_I2C_BAR_TYPE (BIT2 | BIT1) // Type +#define B_PCH_LPSS_I2C_BAR_MS BIT0 // Message Space + +#define R_PCH_LPSS_I2C_BAR1 0x14 // BAR 1 +#define B_PCH_LPSS_I2C_BAR1_BA 0xFFFFF000 // Base Address +#define B_PCH_LPSS_I2C_BAR1_SI 0x00000FF0 // Size Indicator +#define B_PCH_LPSS_I2C_BAR1_PF BIT3 // Prefetchable +#define B_PCH_LPSS_I2C_BAR1_TYPE (BIT2 | BIT1) // Type +#define B_PCH_LPSS_I2C_BAR1_MS BIT0 // Message Space + +#define NUM_RETRIES 0xFFFF + +// +// LPIO I2C Module Memory Space Registers +// +#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 + +#define bit(a) 1 << (a) + +// +// MMIO Register Definitions +// + +#define I2C0_REG_SPACE_ADDR_BASE 0xFF138000 //01K + +#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 + +// +// FIFO write workaround value. +// +#define FIFO_WRITE_DELAY 2 +#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 + +/** + Programe all I2C controllers on LPSS. + + I2C0 is function 1 of LPSS. I2C1 is function 2 of LPSS, etc.. + + @param VOID + + @return EFI_SUCCESS +**/ +EFI_STATUS +ProgramPciLpssI2C ( + VOID + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +#endif diff --git a/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.inf b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.inf new file mode 100644 index 0000000000..5a97452a7b --- /dev/null +++ b/Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.inf @@ -0,0 +1,45 @@ +## @file +# Instance of I2C Library. +# +# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+# +# 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 = I2CLibPei + FILE_GUID = 8EF61509-890B-4FF2-B352-1C0E9CDDEC8B + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = LockBoxLib|PEIM + CONSTRUCTOR = IntelI2CPeiLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + I2CLibPei.c + I2CIoLibPei.c + +[LibraryClasses] + TimerLib + +[PPIs] + gEfiPeiStallPpiGuid + + +[Packages] + MdePkg/MdePkg.dec + Vlv2DeviceRefCodePkg/Vlv2DeviceRefCodePkg.dec + +