Changes for V4 ============== 1) Remove Unicode character from C source file 2) Move delete of QuarkSocPkg\QuarkNorthCluster\Binary\QuarkMicrocode from QuarkPlatformPkg commit to QuarkSocPkg commit Changes for V2 ============== 1) Sync with new APIs in SmmCpuFeaturesLib class 2) Use new generic PCI serial driver PciSioSerialDxe in MdeModulePkg 3) Remove PCI serial driver from QuarkSocPkg 4) Apply optimizations to MtrrLib from MtrrLib in UefiCpuPkg 5) Convert all UNI files to utf-8 6) Replace tabs with spaces and remove trailing spaces 7) Add License.txt Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney <michael.d.kinney@intel.com> Acked-by: Jordan Justen <jordan.l.justen@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19286 6f19259b-4bc3-4df7-8a09-765794883524
1005 lines
27 KiB
C
1005 lines
27 KiB
C
/** @file
|
|
I2C Library for Quark I2C Controller.
|
|
Follows I2C Controller setup instructions as detailed in
|
|
Quark DataSheet (doc id: 329676) Section 19.1/19.1.3.
|
|
|
|
|
|
Copyright (c) 2013-2015 Intel Corporation.
|
|
|
|
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 "CommonHeader.h"
|
|
|
|
/**
|
|
The Called to Common Service Entry.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
|
|
VOID
|
|
I2cCommonServiceEntry (
|
|
OUT UINT16 *SaveCmdPtr,
|
|
OUT UINT32 *SaveBar0Ptr
|
|
)
|
|
{
|
|
*SaveBar0Ptr = IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);
|
|
if (((*SaveBar0Ptr) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {
|
|
|
|
IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) =
|
|
FixedPcdGet32 (PcdIohI2cMmioBase) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK;
|
|
|
|
//
|
|
// also Save Cmd Register, Setup by InitializeInternal later during xfers.
|
|
//
|
|
*SaveCmdPtr = IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD);
|
|
}
|
|
}
|
|
|
|
/**
|
|
The Called on Common Service Exit.
|
|
|
|
@return None.
|
|
|
|
**/
|
|
VOID
|
|
I2cCommonServiceExit (
|
|
IN CONST UINT16 SaveCmd,
|
|
IN CONST UINT32 SaveBar0
|
|
|
|
)
|
|
{
|
|
if ((SaveBar0 & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {
|
|
IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD) = SaveCmd;
|
|
IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) = SaveBar0;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller.
|
|
|
|
Always reads PCI configuration space to get MMIO base address of I2C Controller.
|
|
|
|
@return The IO port base address of I2C controller.
|
|
|
|
**/
|
|
UINTN
|
|
GetI2CIoPortBaseAddress (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN I2CIoPortBaseAddress;
|
|
|
|
//
|
|
// Get I2C Memory Mapped registers base address.
|
|
//
|
|
I2CIoPortBaseAddress = IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);
|
|
|
|
//
|
|
// Make sure that the IO port base address has been properly set.
|
|
//
|
|
ASSERT (I2CIoPortBaseAddress != 0);
|
|
ASSERT (I2CIoPortBaseAddress != 0xFF);
|
|
|
|
return I2CIoPortBaseAddress;
|
|
}
|
|
|
|
|
|
/**
|
|
The EnableI2CMmioSpace() function enables access to I2C MMIO space.
|
|
|
|
**/
|
|
VOID
|
|
EnableI2CMmioSpace (
|
|
VOID
|
|
)
|
|
{
|
|
UINT8 PciCmd;
|
|
|
|
//
|
|
// Read PCICMD. Bus=0, Dev=0, Func=0, Reg=0x4
|
|
//
|
|
PciCmd = IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD);
|
|
|
|
//
|
|
// Enable Bus Master(Bit2), MMIO Space(Bit1) & I/O Space(Bit0)
|
|
//
|
|
PciCmd |= 0x7;
|
|
IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD) = PciCmd;
|
|
|
|
}
|
|
|
|
/**
|
|
The DisableI2CController() functions disables I2C Controller.
|
|
|
|
**/
|
|
VOID
|
|
DisableI2CController (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN I2CIoPortBaseAddress;
|
|
UINT32 Addr;
|
|
UINT32 Data;
|
|
UINT8 PollCount;
|
|
|
|
PollCount = 0;
|
|
|
|
//
|
|
// Get I2C Memory Mapped registers base address.
|
|
//
|
|
I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
|
|
|
|
//
|
|
// Disable the I2C Controller by setting IC_ENABLE.ENABLE to zero
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= ~B_I2C_REG_ENABLE;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
//
|
|
// Read the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled
|
|
//
|
|
Data = 0xFF;
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE_STATUS;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr)) & I2C_REG_ENABLE_STATUS;
|
|
while (Data != 0) {
|
|
//
|
|
// Poll the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled, until timeout (TI2C_POLL*MAX_T_POLL_COUNT).
|
|
//
|
|
PollCount++;
|
|
if (PollCount >= MAX_T_POLL_COUNT) {
|
|
break;
|
|
}
|
|
MicroSecondDelay(TI2C_POLL);
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= I2C_REG_ENABLE_STATUS;
|
|
}
|
|
|
|
//
|
|
// Asset if controller does not enter Disabled state.
|
|
//
|
|
ASSERT (PollCount < MAX_T_POLL_COUNT);
|
|
|
|
//
|
|
// Read IC_CLR_INTR register to automatically clear the combined interrupt,
|
|
// all individual interrupts and the IC_TX_ABRT_SOURCE register.
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_CLR_INT;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
|
|
}
|
|
|
|
/**
|
|
The EnableI2CController() function enables the I2C Controller.
|
|
|
|
**/
|
|
VOID
|
|
EnableI2CController (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN I2CIoPortBaseAddress;
|
|
UINT32 Addr;
|
|
UINT32 Data;
|
|
|
|
//
|
|
// Get I2C Memory Mapped registers base address.
|
|
//
|
|
I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
|
|
|
|
//
|
|
// Enable the I2C Controller by setting IC_ENABLE.ENABLE to 1
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data |= B_I2C_REG_ENABLE;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
//
|
|
// Clear overflow and abort error status bits before transactions.
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_OVER;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_OVER;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_ABRT;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
|
|
}
|
|
|
|
/**
|
|
The WaitForStopDet() function waits until I2C STOP Condition occurs,
|
|
indicating transfer completion.
|
|
|
|
@retval EFI_SUCCESS Stop detected.
|
|
@retval EFI_TIMEOUT Timeout while waiting for stop condition.
|
|
@retval EFI_ABORTED Tx abort signaled in HW status register.
|
|
@retval EFI_DEVICE_ERROR Tx or Rx overflow detected.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
WaitForStopDet (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN I2CIoPortBaseAddress;
|
|
UINT32 Addr;
|
|
UINT32 Data;
|
|
UINT32 PollCount;
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
PollCount = 0;
|
|
|
|
//
|
|
// Get I2C Memory Mapped registers base address.
|
|
//
|
|
I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
|
|
|
|
//
|
|
// Wait for STOP Detect.
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
|
|
|
|
do {
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
if ((Data & I2C_REG_RAW_INTR_STAT_TX_ABRT) != 0) {
|
|
Status = EFI_ABORTED;
|
|
break;
|
|
}
|
|
if ((Data & I2C_REG_RAW_INTR_STAT_TX_OVER) != 0) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
break;
|
|
}
|
|
if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
break;
|
|
}
|
|
if ((Data & I2C_REG_RAW_INTR_STAT_STOP_DET) != 0) {
|
|
Status = EFI_SUCCESS;
|
|
break;
|
|
}
|
|
MicroSecondDelay(TI2C_POLL);
|
|
PollCount++;
|
|
if (PollCount >= MAX_STOP_DET_POLL_COUNT) {
|
|
Status = EFI_TIMEOUT;
|
|
break;
|
|
}
|
|
|
|
} while (TRUE);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
The InitializeInternal() function initialises internal I2C Controller
|
|
register values that are commonly required for I2C Write and Read transfers.
|
|
|
|
@param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
|
|
|
|
@retval EFI_SUCCESS I2C Operation completed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InitializeInternal (
|
|
IN EFI_I2C_ADDR_MODE AddrMode
|
|
)
|
|
{
|
|
UINTN I2CIoPortBaseAddress;
|
|
UINTN Addr;
|
|
UINT32 Data;
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// Enable access to I2C Controller MMIO space.
|
|
//
|
|
EnableI2CMmioSpace ();
|
|
|
|
//
|
|
// Disable I2C Controller initially
|
|
//
|
|
DisableI2CController ();
|
|
|
|
//
|
|
// Get I2C Memory Mapped registers base address.
|
|
//
|
|
I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
|
|
|
|
//
|
|
// Clear START_DET
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_CLR_START_DET;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= ~B_I2C_REG_CLR_START_DET;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
//
|
|
// Clear STOP_DET
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_CLR_STOP_DET;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= ~B_I2C_REG_CLR_STOP_DET;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
//
|
|
// Set addressing mode to user defined (7 or 10 bit) and
|
|
// speed mode to that defined by PCD (standard mode default).
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_CON;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
// Set Addressing Mode
|
|
if (AddrMode == EfiI2CSevenBitAddrMode) {
|
|
Data &= ~B_I2C_REG_CON_10BITADD_MASTER;
|
|
} else {
|
|
Data |= B_I2C_REG_CON_10BITADD_MASTER;
|
|
}
|
|
// Set Speed Mode
|
|
Data &= ~B_I2C_REG_CON_SPEED;
|
|
if (FeaturePcdGet (PcdI2CFastModeEnabled)) {
|
|
Data |= BIT2;
|
|
} else {
|
|
Data |= BIT1;
|
|
}
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
The WriteByte() function provides a standard way to execute a
|
|
standard single byte write to an IC2 device (without accessing
|
|
sub-addresses), as defined in the I2C Specification.
|
|
|
|
@param I2CAddress I2C Slave device address
|
|
@param Value The 8-bit value to write.
|
|
|
|
@retval EFI_SUCCESS Transfer success.
|
|
@retval EFI_UNSUPPORTED Unsupported input param.
|
|
@retval EFI_TIMEOUT Timeout while waiting xfer.
|
|
@retval EFI_ABORTED Controller aborted xfer.
|
|
@retval EFI_DEVICE_ERROR Device error detected by controller.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WriteByte (
|
|
IN UINTN I2CAddress,
|
|
IN UINT8 Value
|
|
)
|
|
{
|
|
UINTN I2CIoPortBaseAddress;
|
|
UINTN Addr;
|
|
UINT32 Data;
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Get I2C Memory Mapped registers base address
|
|
//
|
|
I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
|
|
|
|
//
|
|
// Write to the IC_TAR register the address of the slave device to be addressed
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= ~B_I2C_REG_TAR;
|
|
Data |= I2CAddress;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
//
|
|
// Enable the I2C Controller
|
|
//
|
|
EnableI2CController ();
|
|
|
|
//
|
|
// Write the data and transfer direction to the IC_DATA_CMD register.
|
|
// Also specify that transfer should be terminated by STOP condition.
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= 0xFFFFFF00;
|
|
Data |= (UINT8)Value;
|
|
Data &= ~B_I2C_REG_DATA_CMD_RW;
|
|
Data |= B_I2C_REG_DATA_CMD_STOP;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
//
|
|
// Wait for transfer completion.
|
|
//
|
|
Status = WaitForStopDet ();
|
|
|
|
//
|
|
// Ensure I2C Controller disabled.
|
|
//
|
|
DisableI2CController();
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
The ReadByte() function provides a standard way to execute a
|
|
standard single byte read to an IC2 device (without accessing
|
|
sub-addresses), as defined in the I2C Specification.
|
|
|
|
@param I2CAddress I2C Slave device address
|
|
@param ReturnDataPtr Pointer to location to receive read byte.
|
|
|
|
@retval EFI_SUCCESS Transfer success.
|
|
@retval EFI_UNSUPPORTED Unsupported input param.
|
|
@retval EFI_TIMEOUT Timeout while waiting xfer.
|
|
@retval EFI_ABORTED Controller aborted xfer.
|
|
@retval EFI_DEVICE_ERROR Device error detected by controller.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ReadByte (
|
|
IN UINTN I2CAddress,
|
|
OUT UINT8 *ReturnDataPtr
|
|
)
|
|
{
|
|
UINTN I2CIoPortBaseAddress;
|
|
UINTN Addr;
|
|
UINT32 Data;
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Get I2C Memory Mapped registers base address.
|
|
//
|
|
I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
|
|
|
|
//
|
|
// Write to the IC_TAR register the address of the slave device to be addressed
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= ~B_I2C_REG_TAR;
|
|
Data |= I2CAddress;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
//
|
|
// Enable the I2C Controller
|
|
//
|
|
EnableI2CController ();
|
|
|
|
//
|
|
// Write transfer direction to the IC_DATA_CMD register and
|
|
// specify that transfer should be terminated by STOP condition.
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= 0xFFFFFF00;
|
|
Data |= B_I2C_REG_DATA_CMD_RW;
|
|
Data |= B_I2C_REG_DATA_CMD_STOP;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
//
|
|
// Wait for transfer completion
|
|
//
|
|
Status = WaitForStopDet ();
|
|
if (!EFI_ERROR(Status)) {
|
|
|
|
//
|
|
// Clear RX underflow before reading IC_DATA_CMD.
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
|
|
//
|
|
// Obtain and return read data byte from RX buffer (IC_DATA_CMD[7:0]).
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= 0x000000FF;
|
|
*ReturnDataPtr = (UINT8) Data;
|
|
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;
|
|
if (Data != 0) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ensure I2C Controller disabled.
|
|
//
|
|
DisableI2CController ();
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
The WriteMultipleByte() function provides a standard way to execute
|
|
multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
|
|
when writing block of data), as defined in the I2C Specification.
|
|
|
|
@param I2CAddress The I2C slave address of the device
|
|
with which to communicate.
|
|
|
|
@param WriteBuffer Contains the value of byte to be written to the
|
|
I2C slave device.
|
|
|
|
@param Length No. of bytes to be written.
|
|
|
|
@retval EFI_SUCCESS Transfer success.
|
|
@retval EFI_UNSUPPORTED Unsupported input param.
|
|
@retval EFI_TIMEOUT Timeout while waiting xfer.
|
|
@retval EFI_ABORTED Tx abort signaled in HW status register.
|
|
@retval EFI_DEVICE_ERROR Tx overflow detected.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WriteMultipleByte (
|
|
IN UINTN I2CAddress,
|
|
IN UINT8 *WriteBuffer,
|
|
IN UINTN Length
|
|
)
|
|
{
|
|
UINTN I2CIoPortBaseAddress;
|
|
UINTN Index;
|
|
UINTN Addr;
|
|
UINT32 Data;
|
|
EFI_STATUS Status;
|
|
|
|
if (Length > I2C_FIFO_SIZE) {
|
|
return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size.
|
|
}
|
|
|
|
I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
|
|
|
|
//
|
|
// Write to the IC_TAR register the address of the slave device to be addressed
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= ~B_I2C_REG_TAR;
|
|
Data |= I2CAddress;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
//
|
|
// Enable the I2C Controller
|
|
//
|
|
EnableI2CController ();
|
|
|
|
//
|
|
// Write the data and transfer direction to the IC_DATA_CMD register.
|
|
// Also specify that transfer should be terminated by STOP condition.
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
|
|
for (Index = 0; Index < Length; Index++) {
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= 0xFFFFFF00;
|
|
Data |= (UINT8)WriteBuffer[Index];
|
|
Data &= ~B_I2C_REG_DATA_CMD_RW;
|
|
if (Index == (Length-1)) {
|
|
Data |= B_I2C_REG_DATA_CMD_STOP;
|
|
}
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
}
|
|
|
|
//
|
|
// Wait for transfer completion
|
|
//
|
|
Status = WaitForStopDet ();
|
|
|
|
//
|
|
// Ensure I2C Controller disabled.
|
|
//
|
|
DisableI2CController ();
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
The ReadMultipleByte() function provides a standard way to execute
|
|
multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
|
|
when reading block of data), as defined in the I2C Specification (I2C combined
|
|
write/read protocol).
|
|
|
|
@param I2CAddress The I2C slave address of the device
|
|
with which to communicate.
|
|
|
|
@param Buffer Contains the value of byte data written or read from the
|
|
I2C slave device.
|
|
|
|
@param WriteLength No. of bytes to be written. In this case data
|
|
written typically contains sub-address or sub-addresses
|
|
in Hi-Lo format, that need to be read (I2C combined
|
|
write/read protocol).
|
|
|
|
@param ReadLength No. of bytes to be read from I2C slave device.
|
|
|
|
@retval EFI_SUCCESS Transfer success.
|
|
@retval EFI_UNSUPPORTED Unsupported input param.
|
|
@retval EFI_TIMEOUT Timeout while waiting xfer.
|
|
@retval EFI_ABORTED Tx abort signaled in HW status register.
|
|
@retval EFI_DEVICE_ERROR Rx underflow or Rx/Tx overflow detected.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ReadMultipleByte (
|
|
IN UINTN I2CAddress,
|
|
IN OUT UINT8 *Buffer,
|
|
IN UINTN WriteLength,
|
|
IN UINTN ReadLength
|
|
)
|
|
{
|
|
UINTN I2CIoPortBaseAddress;
|
|
UINTN Index;
|
|
UINTN Addr;
|
|
UINT32 Data;
|
|
UINT8 PollCount;
|
|
EFI_STATUS Status;
|
|
|
|
if (WriteLength > I2C_FIFO_SIZE || ReadLength > I2C_FIFO_SIZE) {
|
|
return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size.
|
|
}
|
|
|
|
I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
|
|
|
|
//
|
|
// Write to the IC_TAR register the address of the slave device to be addressed
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= ~B_I2C_REG_TAR;
|
|
Data |= I2CAddress;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
|
|
//
|
|
// Enable the I2C Controller
|
|
//
|
|
EnableI2CController ();
|
|
|
|
//
|
|
// Write the data (sub-addresses) to the IC_DATA_CMD register.
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
|
|
for (Index = 0; Index < WriteLength; Index++) {
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= 0xFFFFFF00;
|
|
Data |= (UINT8)Buffer[Index];
|
|
Data &= ~B_I2C_REG_DATA_CMD_RW;
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
}
|
|
|
|
//
|
|
// Issue Read Transfers for each byte (Restart issued when write/read bit changed).
|
|
//
|
|
for (Index = 0; Index < ReadLength; Index++) {
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data |= B_I2C_REG_DATA_CMD_RW;
|
|
// Issue a STOP for last read transfer.
|
|
if (Index == (ReadLength-1)) {
|
|
Data |= B_I2C_REG_DATA_CMD_STOP;
|
|
}
|
|
*((volatile UINT32 *) (UINTN)(Addr)) = Data;
|
|
}
|
|
|
|
//
|
|
// Wait for STOP condition.
|
|
//
|
|
Status = WaitForStopDet ();
|
|
if (!EFI_ERROR(Status)) {
|
|
|
|
//
|
|
// Poll Receive FIFO Buffer Level register until valid (upto MAX_T_POLL_COUNT times).
|
|
//
|
|
Data = 0;
|
|
PollCount = 0;
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_RXFLR;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
while ((Data != ReadLength) && (PollCount < MAX_T_POLL_COUNT)) {
|
|
MicroSecondDelay(TI2C_POLL);
|
|
PollCount++;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
}
|
|
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
|
|
//
|
|
// If no timeout or device error then read rx data.
|
|
//
|
|
if (PollCount == MAX_T_POLL_COUNT) {
|
|
Status = EFI_TIMEOUT;
|
|
} else if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
} else {
|
|
|
|
//
|
|
// Clear RX underflow before reading IC_DATA_CMD.
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
|
|
//
|
|
// Read data.
|
|
//
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
|
|
for (Index = 0; Index < ReadLength; Index++) {
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= 0x000000FF;
|
|
*(Buffer+Index) = (UINT8)Data;
|
|
}
|
|
Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
|
|
Data = *((volatile UINT32 *) (UINTN)(Addr));
|
|
Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;
|
|
if (Data != 0) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
} else {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ensure I2C Controller disabled.
|
|
//
|
|
DisableI2CController ();
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
The I2cWriteByte() function is a wrapper function for the WriteByte function.
|
|
Provides a standard way to execute a standard single byte write to an IC2 device
|
|
(without accessing sub-addresses), as defined in the I2C Specification.
|
|
|
|
@param SlaveAddress The I2C slave address of the device
|
|
with which to communicate.
|
|
|
|
@param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
|
|
|
|
@param Buffer Contains the value of byte data to execute to the
|
|
I2C slave device.
|
|
|
|
|
|
@retval EFI_SUCCESS Transfer success.
|
|
@retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
|
|
@retval EFI_UNSUPPORTED Unsupported input param.
|
|
@retval EFI_TIMEOUT Timeout while waiting xfer.
|
|
@retval EFI_ABORTED Controller aborted xfer.
|
|
@retval EFI_DEVICE_ERROR Device error detected by controller.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
I2cWriteByte (
|
|
IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
|
|
IN EFI_I2C_ADDR_MODE AddrMode,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN I2CAddress;
|
|
UINT16 SaveCmd;
|
|
UINT32 SaveBar0;
|
|
|
|
if (Buffer == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
SaveCmd = 0;
|
|
SaveBar0 = 0;
|
|
|
|
I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
I2CAddress = SlaveAddress.I2CDeviceAddress;
|
|
Status = InitializeInternal (AddrMode);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = WriteByte (I2CAddress, *(UINT8 *) Buffer);
|
|
}
|
|
|
|
I2cCommonServiceExit (SaveCmd, SaveBar0);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
The I2cReadByte() function is a wrapper function for the ReadByte function.
|
|
Provides a standard way to execute a standard single byte read to an I2C device
|
|
(without accessing sub-addresses), as defined in the I2C Specification.
|
|
|
|
@param SlaveAddress The I2C slave address of the device
|
|
with which to communicate.
|
|
|
|
@param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
|
|
|
|
@param Buffer Contains the value of byte data read from the
|
|
I2C slave device.
|
|
|
|
|
|
@retval EFI_SUCCESS Transfer success.
|
|
@retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
|
|
@retval EFI_TIMEOUT Timeout while waiting xfer.
|
|
@retval EFI_ABORTED Controller aborted xfer.
|
|
@retval EFI_DEVICE_ERROR Device error detected by controller.
|
|
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
I2cReadByte (
|
|
IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
|
|
IN EFI_I2C_ADDR_MODE AddrMode,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN I2CAddress;
|
|
UINT16 SaveCmd;
|
|
UINT32 SaveBar0;
|
|
|
|
if (Buffer == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
SaveCmd = 0;
|
|
SaveBar0 =0;
|
|
|
|
I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
I2CAddress = SlaveAddress.I2CDeviceAddress;
|
|
|
|
Status = InitializeInternal (AddrMode);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = ReadByte (I2CAddress, (UINT8 *) Buffer);
|
|
}
|
|
I2cCommonServiceExit (SaveCmd, SaveBar0);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
The I2cWriteMultipleByte() function is a wrapper function for the
|
|
WriteMultipleByte() function. Provides a standard way to execute multiple
|
|
byte writes to an I2C device (e.g. when accessing sub-addresses or writing
|
|
block of data), as defined in the I2C Specification.
|
|
|
|
@param SlaveAddress The I2C slave address of the device
|
|
with which to communicate.
|
|
|
|
@param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
|
|
|
|
@param Length No. of bytes to be written.
|
|
|
|
@param Buffer Contains the value of byte to be written to the
|
|
I2C slave device.
|
|
|
|
@retval EFI_SUCCESS Transfer success.
|
|
@retval EFI_INVALID_PARAMETER This, Length or Buffer pointers are invalid.
|
|
@retval EFI_UNSUPPORTED Unsupported input param.
|
|
@retval EFI_TIMEOUT Timeout while waiting xfer.
|
|
@retval EFI_ABORTED Controller aborted xfer.
|
|
@retval EFI_DEVICE_ERROR Device error detected by controller.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
I2cWriteMultipleByte (
|
|
IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
|
|
IN EFI_I2C_ADDR_MODE AddrMode,
|
|
IN UINTN *Length,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN I2CAddress;
|
|
UINT16 SaveCmd;
|
|
UINT32 SaveBar0;
|
|
|
|
if (Buffer == NULL || Length == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
SaveCmd = 0;
|
|
SaveBar0 =0;
|
|
|
|
I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
|
|
Status = EFI_SUCCESS;
|
|
|
|
I2CAddress = SlaveAddress.I2CDeviceAddress;
|
|
|
|
Status = InitializeInternal (AddrMode);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = WriteMultipleByte (I2CAddress, Buffer, (*Length));
|
|
}
|
|
|
|
I2cCommonServiceExit (SaveCmd, SaveBar0);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte() function.
|
|
Provides a standard way to execute multiple byte writes to an I2C device
|
|
(e.g. when accessing sub-addresses or when reading block of data), as defined
|
|
in the I2C Specification (I2C combined write/read protocol).
|
|
|
|
@param SlaveAddress The I2C slave address of the device
|
|
with which to communicate.
|
|
|
|
@param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
|
|
|
|
@param WriteLength No. of bytes to be written. In this case data
|
|
written typically contains sub-address or sub-addresses
|
|
in Hi-Lo format, that need to be read (I2C combined
|
|
write/read protocol).
|
|
|
|
@param ReadLength No. of bytes to be read from I2C slave device.
|
|
|
|
@param Buffer Contains the value of byte data read from the
|
|
I2C slave device.
|
|
|
|
@retval EFI_SUCCESS Transfer success.
|
|
@retval EFI_INVALID_PARAMETER This, WriteLength, ReadLength or Buffer
|
|
pointers are invalid.
|
|
@retval EFI_UNSUPPORTED Unsupported input param.
|
|
@retval EFI_TIMEOUT Timeout while waiting xfer.
|
|
@retval EFI_ABORTED Controller aborted xfer.
|
|
@retval EFI_DEVICE_ERROR Device error detected by controller.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
I2cReadMultipleByte (
|
|
IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
|
|
IN EFI_I2C_ADDR_MODE AddrMode,
|
|
IN UINTN *WriteLength,
|
|
IN UINTN *ReadLength,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN I2CAddress;
|
|
UINT16 SaveCmd;
|
|
UINT32 SaveBar0;
|
|
|
|
if (Buffer == NULL || WriteLength == NULL || ReadLength == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
SaveCmd = 0;
|
|
SaveBar0 =0;
|
|
|
|
I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
I2CAddress = SlaveAddress.I2CDeviceAddress;
|
|
Status = InitializeInternal (AddrMode);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = ReadMultipleByte (I2CAddress, Buffer, (*WriteLength), (*ReadLength));
|
|
}
|
|
I2cCommonServiceExit (SaveCmd, SaveBar0);
|
|
return Status;
|
|
}
|
|
|
|
|