summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzwei4 <david.wei@intel.com>2018-02-12 16:06:29 +0800
committerzwei4 <david.wei@intel.com>2018-02-12 16:06:29 +0800
commit35269fe8952eff7b6ecf6050b65a4ede2d1f9d7f (patch)
tree7cf96d58af0287fff539a0881247bd952399eeee
parent46e02d6f1c0369135c1ea5ba116cdf0ab12a76f9 (diff)
downloadedk2-platforms-35269fe8952eff7b6ecf6050b65a4ede2d1f9d7f.tar.xz
SMBus Library.
Apollo Lake South Cluster SMBus executive code, which is common for PEI, DXE and SMM modules. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: zwei4 <david.wei@intel.com> Cc: Mang Guo <mang.guo@intel.com>
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/Private/PeiDxeSmmScSmbusCommonLib/PeiDxeSmmScSmbusCommonLib.inf35
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/Private/PeiDxeSmmScSmbusCommonLib/ScSmbusExec.c653
2 files changed, 688 insertions, 0 deletions
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/Private/PeiDxeSmmScSmbusCommonLib/PeiDxeSmmScSmbusCommonLib.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/Private/PeiDxeSmmScSmbusCommonLib/PeiDxeSmmScSmbusCommonLib.inf
new file mode 100644
index 0000000000..2ca6549b88
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/Private/PeiDxeSmmScSmbusCommonLib/PeiDxeSmmScSmbusCommonLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Apollo Lake South Cluster Smbus Common Lib.
+#
+# Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiDxeSmmPchSmbusCommonLib
+ FILE_GUID = 490CEB45-F3A8-41CD-89CB-C47BF7F7A4B4
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ScSmbusCommonLib
+
+[Sources]
+ ScSmbusExec.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+ BroxtonSiPkg/BroxtonSiPrivate.dec
+
+[LibraryClasses]
+ IoLib
+ DebugLib
+ MmPciLib
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/Private/PeiDxeSmmScSmbusCommonLib/ScSmbusExec.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/Private/PeiDxeSmmScSmbusCommonLib/ScSmbusExec.c
new file mode 100644
index 0000000000..2c5fe9b7b8
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/Private/PeiDxeSmmScSmbusCommonLib/ScSmbusExec.c
@@ -0,0 +1,653 @@
+/** @file
+ Apollo Lake South Cluster Smbus Executive Code (common PEI/DXE/SMM code).
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <IndustryStandard/SmBus.h>
+#include <IndustryStandard/Pci30.h>
+#include <ScAccess.h>
+#include <Library/MmPciLib.h>
+#include <Private/Library/ScSmbusCommonLib.h>
+
+/**
+ Get SMBUS IO Base address.
+
+ @param[in] None
+
+ @retval UINT32 The SMBUS IO Base Address
+**/
+UINT32
+SmbusGetIoBase (
+ VOID
+ )
+{
+ UINT32 SmbusIoBase;
+
+ SmbusIoBase = MmioRead32 (
+ MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_SC,
+ PCI_DEVICE_NUMBER_SMBUS,
+ PCI_FUNCTION_NUMBER_SMBUS)
+ + R_SMBUS_BASE) & B_SMBUS_BASE_BAR;
+
+ ASSERT (SmbusIoBase != B_SMBUS_BASE_BAR && SmbusIoBase != 0);
+
+ return SmbusIoBase;
+}
+
+/**
+ This function provides a standard way to read PCH Smbus IO registers.
+
+ @param[in] Offset Register offset from Smbus base IO address.
+
+ @retval UINT8 Returns data read from IO.
+**/
+UINT8
+EFIAPI
+SmbusIoRead (
+ IN UINT8 Offset
+ )
+{
+ return IoRead8 (SmbusGetIoBase () + Offset);
+}
+
+/**
+ This function provides a standard way to write PCH Smbus IO registers.
+
+ @param[in] Offset Register offset from Smbus base IO address.
+ @param[in] Data Data to write to register.
+
+**/
+VOID
+EFIAPI
+SmbusIoWrite (
+ IN UINT8 Offset,
+ IN UINT8 Data
+ )
+{
+
+ IoWrite8 (SmbusGetIoBase () + Offset, Data);
+ return;
+}
+
+/**
+ This function provides a standard way to check if a SMBus transaction has
+ completed.
+
+ @param[in] StsReg Not used for input. On return, contains the
+ value of the SMBus status register.
+
+ @retval TRUE Transaction is complete
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+IoDone (
+ IN UINT8 *StsReg
+ )
+{
+ UINTN StallIndex;
+ UINTN StallTries;
+
+ StallTries = STALL_TIME / STALL_PERIOD;
+
+ for (StallIndex = 0; StallIndex < StallTries; StallIndex++) {
+ *StsReg = SmbusIoRead (R_SMBUS_HSTS);
+ if (*StsReg & (B_SMBUS_INTR | B_SMBUS_BYTE_DONE_STS | B_SMBUS_DERR | B_SMBUS_BERR)) {
+ return TRUE;
+ } else {
+ MicroSecondDelay (STALL_PERIOD);
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Check if it's ok to use the bus.
+
+
+ @retval EFI_SUCCESS SmBus is acquired and it's safe to send commands.
+ @retval EFI_TIMEOUT SmBus is busy, it's not safe to send commands.
+**/
+EFI_STATUS
+AcquireBus (
+ VOID
+ )
+{
+ UINT8 StsReg;
+
+ StsReg = 0;
+ StsReg = SmbusIoRead (R_SMBUS_HSTS);
+ if (StsReg & B_SMBUS_IUS) {
+ return EFI_TIMEOUT;
+ } else if (StsReg & B_SMBUS_HBSY) {
+ ///
+ /// Clear Status Register and exit
+ ///
+ SmbusIoWrite (R_SMBUS_HSTS, B_SMBUS_HSTS_ALL);
+ return EFI_TIMEOUT;
+ } else {
+ ///
+ /// Clear out any odd status information (Will Not Clear In Use)
+ ///
+ SmbusIoWrite (R_SMBUS_HSTS, StsReg);
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ This function provides a standard way to execute Smbus protocols
+ as defined in the SMBus Specification. The data can either be of
+ the Length byte, word, or a block of data. The resulting transaction will be
+ either the SMBus Slave Device accepts this transaction or this function
+ returns with an error
+
+ @param[in] SlaveAddress Smbus Slave device the command is directed at
+ @param[in] Command Slave Device dependent
+ @param[in] Operation Which SMBus protocol will be used
+ @param[in] PecCheck Defines if Packet Error Code Checking is to be used
+ @param[in, out] Length How many bytes to read. Must be 0 <= Length <= 32 depending on Operation
+ It will contain the actual number of bytes read/written.
+ @param[in, out] Buffer Contain the data read/written.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @exception EFI_UNSUPPORTED The operation is unsupported.
+
+ @retval EFI_INVALID_PARAMETER Length or Buffer is NULL for any operation besides
+ quick read or quick write.
+ @retval EFI_TIMEOUT The transaction did not complete within an internally
+ specified timeout period, or the controller is not
+ available for use.
+ @retval EFI_DEVICE_ERROR There was an Smbus error (NACK) during the operation.
+ This could indicate the slave device is not present
+ or is in a hung condition.
+**/
+EFI_STATUS
+SmbusExec (
+ IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_SMBUS_DEVICE_COMMAND Command,
+ IN EFI_SMBUS_OPERATION Operation,
+ IN BOOLEAN PecCheck,
+ IN OUT UINTN *Length,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 AuxcReg;
+ UINT8 AuxStsReg;
+ UINT8 SmbusOperation;
+ UINT8 StsReg;
+ UINT8 SlvAddrReg;
+ UINT8 HostCmdReg;
+ UINT8 BlockCount;
+ BOOLEAN BufferTooSmall;
+ UINTN Index;
+ UINTN BusIndex;
+ UINT8 *CallBuffer;
+ UINT8 SmbusHctl;
+ UINT32 Timeout;
+
+ CallBuffer = Buffer;
+ BlockCount = 0;
+
+ ///
+ /// For any operations besides quick read & write, the pointers to
+ /// Length and Buffer must not be NULL.
+ ///
+ if ((Operation != EfiSmbusQuickRead) && (Operation != EfiSmbusQuickWrite)) {
+ if ((Length == NULL) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ ///
+ /// See if its ok to use the bus based upon INUSE_STS bit.
+ ///
+ Status = AcquireBus ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ///
+ /// This is the main operation loop. If the operation results in a Smbus
+ /// collision with another master on the bus, it attempts the requested
+ /// transaction again at least BUS_TRIES attempts.
+ ///
+ for (BusIndex = 0; BusIndex < BUS_TRIES; BusIndex++) {
+ ///
+ /// Operation Specifics (pre-execution)
+ ///
+ Status = EFI_SUCCESS;
+ SmbusOperation = V_SMBUS_SMB_CMD_QUICK;
+ SlvAddrReg = (UINT8) ((SlaveAddress.SmbusDeviceAddress << 1) | 1);
+ HostCmdReg = (UINT8) Command;
+ AuxcReg = 0;
+
+ switch (Operation) {
+
+ case EfiSmbusQuickWrite:
+ SlvAddrReg--;
+
+ ///
+ /// The "break;" command is not present here to allow code execution
+ /// do drop into the next case, which contains common code to this case.
+ ///
+ case EfiSmbusQuickRead:
+ if (PecCheck == TRUE) {
+ Status = EFI_UNSUPPORTED;
+ }
+ break;
+
+ case EfiSmbusSendByte:
+ HostCmdReg = CallBuffer[0];
+ SlvAddrReg--;
+
+ ///
+ /// The "break;" command is not present here to allow code execution
+ /// do drop into the next case, which contains common code to this case.
+ ///
+ case EfiSmbusReceiveByte:
+ SmbusOperation = V_SMBUS_SMB_CMD_BYTE;
+ if (*Length < 1) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *Length = 1;
+ break;
+
+ case EfiSmbusWriteByte:
+ SmbusIoWrite (R_SMBUS_HD0, CallBuffer[0]);
+ SlvAddrReg--;
+ *Length = 1;
+
+ ///
+ /// The "break;" command is not present here to allow code execution
+ /// do drop into the next case, which contains common code to this case.
+ ///
+ case EfiSmbusReadByte:
+ if (*Length < 1) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else if (*Length == 1) {
+ SmbusOperation = V_SMBUS_SMB_CMD_BYTE_DATA;
+ } else if (*Length <= 256) {
+ if (PecCheck == TRUE) {
+ ///
+ /// The I2C Read command with either PEC_EN or AAC bit set
+ /// produces undefined results.
+ ///
+ Status = EFI_UNSUPPORTED;
+ }
+
+ SmbusOperation = V_SMBUS_SMB_CMD_IIC_READ;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ break;
+
+ case EfiSmbusReadWord:
+ SmbusOperation = V_SMBUS_SMB_CMD_WORD_DATA;
+ if (*Length < 2) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *Length = 2;
+ break;
+
+ case EfiSmbusWriteWord:
+ SmbusOperation = V_SMBUS_SMB_CMD_WORD_DATA;
+ SlvAddrReg--;
+ SmbusIoWrite (R_SMBUS_HD1, CallBuffer[1]);
+ SmbusIoWrite (R_SMBUS_HD0, CallBuffer[0]);
+ if (*Length < 2) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *Length = 2;
+ break;
+
+ case EfiSmbusWriteBlock:
+ SmbusIoWrite (R_SMBUS_HD0, *(UINT8 *) Length);
+ SlvAddrReg--;
+ BlockCount = (UINT8) (*Length);
+
+ ///
+ /// The "break;" command is not present here to allow code execution
+ /// do drop into the next case, which contains common code to this case.
+ ///
+ case EfiSmbusReadBlock:
+ SmbusOperation = V_SMBUS_SMB_CMD_BLOCK;
+ if ((*Length < 1) || (*Length > 32)) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ AuxcReg |= B_SMBUS_E32B;
+ break;
+
+ case EfiSmbusProcessCall:
+ SmbusOperation = V_SMBUS_SMB_CMD_PROCESS_CALL;
+ SmbusIoWrite (R_SMBUS_HD1, CallBuffer[1]);
+ SmbusIoWrite (R_SMBUS_HD0, CallBuffer[0]);
+ if (*Length < 2) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *Length = 2;
+ break;
+
+ case EfiSmbusBWBRProcessCall:
+ ///
+ /// The write byte count cannot be zero or more than
+ /// 32 bytes.
+ ///
+ if ((*Length < 1) || (*Length > 32)) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ SmbusIoWrite (R_SMBUS_HD0, *(UINT8 *) Length);
+ BlockCount = (UINT8) (*Length);
+ SmbusOperation = V_SMBUS_SMB_CMD_BLOCK_PROCESS;
+
+ AuxcReg |= B_SMBUS_E32B;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (PecCheck == TRUE) {
+ AuxcReg |= B_SMBUS_AAC;
+ }
+ ///
+ /// Set Auxiliary Control register
+ ///
+ SmbusIoWrite (R_SMBUS_AUXC, AuxcReg);
+
+ ///
+ /// Reset the pointer of the internal buffer
+ ///
+ SmbusIoRead (R_SMBUS_HCTL);
+
+ ///
+ /// Now that the 32 byte buffer is turned on, we can write th block data
+ /// into it
+ ///
+ if ((Operation == EfiSmbusWriteBlock) || (Operation == EfiSmbusBWBRProcessCall)) {
+ for (Index = 0; Index < BlockCount; Index++) {
+ ///
+ /// Write next byte
+ ///
+ SmbusIoWrite (R_SMBUS_HBD, CallBuffer[Index]);
+ }
+ }
+ ///
+ /// Set SMBus slave address for the device to send/receive from
+ ///
+ SmbusIoWrite (R_SMBUS_TSA, SlvAddrReg);
+
+ ///
+ /// For I2C read, send DATA1 register for the offset (address)
+ /// within the serial memory chips
+ ///
+ if ((Operation == EfiSmbusReadByte) && (*Length > 1)) {
+ SmbusIoWrite (R_SMBUS_HD1, HostCmdReg);
+ } else {
+ ///
+ /// Set Command register
+ ///
+ SmbusIoWrite (R_SMBUS_HCMD, HostCmdReg);
+ }
+ ///
+ /// Set Control Register (Initiate Operation, Interrupt disabled)
+ ///
+ SmbusIoWrite (R_SMBUS_HCTL, (UINT8) (SmbusOperation + B_SMBUS_START));
+
+ ///
+ /// Wait for IO to complete
+ ///
+ if (!IoDone (&StsReg)) {
+ Status = EFI_TIMEOUT;
+ break;
+ } else if (StsReg & B_SMBUS_DERR) {
+ AuxStsReg = SmbusIoRead (R_SMBUS_AUXS);
+ if (AuxStsReg & B_SMBUS_CRCE) {
+ Status = EFI_CRC_ERROR;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ break;
+ } else if (StsReg & B_SMBUS_BERR) {
+ ///
+ /// Clear the Bus Error for another try
+ ///
+ Status = EFI_DEVICE_ERROR;
+ SmbusIoWrite (R_SMBUS_HSTS, B_SMBUS_BERR);
+ ///
+ /// Clear Status Registers
+ ///
+ SmbusIoWrite (R_SMBUS_HSTS, B_SMBUS_HSTS_ALL);
+ SmbusIoWrite (R_SMBUS_AUXS, B_SMBUS_CRCE);
+ ///
+ /// If bus collision happens, stall some time, then try again
+ /// Here we choose 10 milliseconds to avoid MTCP transfer.
+ ///
+ MicroSecondDelay (STALL_PERIOD);
+ continue;
+ }
+ ///
+ /// successfull completion
+ /// Operation Specifics (post-execution)
+ ///
+ switch (Operation) {
+
+ case EfiSmbusReadWord:
+ ///
+ /// The "break;" command is not present here to allow code execution
+ /// do drop into the next case, which contains common code to this case.
+ ///
+ case EfiSmbusProcessCall:
+ CallBuffer[1] = SmbusIoRead (R_SMBUS_HD1);
+ CallBuffer[0] = SmbusIoRead (R_SMBUS_HD0);
+ break;
+
+ case EfiSmbusReadByte:
+ if (*Length > 1) {
+ for (Index = 0; Index < *Length; Index++) {
+ ///
+ /// Read the byte
+ ///
+ CallBuffer[Index] = SmbusIoRead (R_SMBUS_HBD);
+ ///
+ /// After receiving byte n-1 (1-base) of the message, the
+ /// software will then set the LAST BYTE bit. The software
+ /// will then clear the BYTE_DONE_STS bit.
+ ///
+ if (Index == ((*Length - 1) - 1)) {
+ SmbusHctl = SmbusIoRead (R_SMBUS_HCTL) | (UINT8) B_SMBUS_LAST_BYTE;
+ SmbusIoWrite (R_SMBUS_HCTL, SmbusHctl);
+ } else if (Index == (*Length - 1)) {
+ ///
+ /// Clear the LAST BYTE bit after receiving byte n (1-base) of the message
+ ///
+ SmbusHctl = SmbusIoRead (R_SMBUS_HCTL) & (UINT8) ~B_SMBUS_LAST_BYTE;
+ SmbusIoWrite (R_SMBUS_HCTL, SmbusHctl);
+ }
+ ///
+ /// Clear the BYTE_DONE_STS bit
+ ///
+ SmbusIoWrite (R_SMBUS_HSTS, B_SMBUS_BYTE_DONE_STS);
+ ///
+ /// Check BYTE_DONE_STS bit to know if it has completed transmission
+ /// of a byte. No need to check it for the last byte.
+ ///
+ if (Index < (*Length - 1)) {
+ ///
+ /// If somehow board operates at 10Khz, it will take 0.9 ms (9/10Khz) for another byte.
+ /// Add 10 us delay for a loop of 100 that the total timeout is 1 ms to take care of
+ /// the slowest case.
+ ///
+ for (Timeout = 0; Timeout < 100; Timeout++) {
+ if ((SmbusIoRead (R_SMBUS_HSTS) & (UINT8) B_SMBUS_BYTE_DONE_STS) != 0) {
+ break;
+ }
+ ///
+ /// Delay 10 us
+ ///
+ MicroSecondDelay (STALL_PERIOD);
+ }
+
+ if (Timeout >= 100) {
+ Status = EFI_TIMEOUT;
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ case EfiSmbusReceiveByte:
+ CallBuffer[0] = SmbusIoRead (R_SMBUS_HD0);
+ break;
+
+ case EfiSmbusWriteBlock:
+ SmbusIoWrite (R_SMBUS_HSTS, B_SMBUS_BYTE_DONE_STS);
+ break;
+
+ case EfiSmbusReadBlock:
+ BufferTooSmall = FALSE;
+ ///
+ /// Find out how many bytes will be in the block
+ ///
+ BlockCount = SmbusIoRead (R_SMBUS_HD0);
+ if (*Length < BlockCount) {
+ BufferTooSmall = TRUE;
+ } else {
+ for (Index = 0; Index < BlockCount; Index++) {
+ ///
+ /// Read the byte
+ ///
+ CallBuffer[Index] = SmbusIoRead (R_SMBUS_HBD);
+ }
+ }
+
+ *Length = BlockCount;
+ if (BufferTooSmall) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case EfiSmbusBWBRProcessCall:
+ ///
+ /// Find out how many bytes will be in the block
+ ///
+ BlockCount = SmbusIoRead (R_SMBUS_HD0);
+ ///
+ /// The read byte count cannot be zero.
+ ///
+ if (BlockCount < 1) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ break;
+ }
+ ///
+ /// The combined data payload (the write byte count + the read byte count)
+ /// must not exceed 32 bytes
+ ///
+ if (((UINT8) (*Length) + BlockCount) > 32) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ for (Index = 0; Index < BlockCount; Index++) {
+ ///
+ /// Read the byte
+ ///
+ CallBuffer[Index] = SmbusIoRead (R_SMBUS_HBD);
+ }
+
+ *Length = BlockCount;
+ break;
+
+ default:
+ break;
+ };
+
+ if ((StsReg & B_SMBUS_BERR) && (Status != EFI_BUFFER_TOO_SMALL)) {
+ ///
+ /// Clear the Bus Error for another try
+ ///
+ Status = EFI_DEVICE_ERROR;
+ SmbusIoWrite (R_SMBUS_HSTS, B_SMBUS_BERR);
+ ///
+ /// If bus collision happens, stall some time, then try again
+ /// Here we choose 10 milliseconds to avoid MTCP transfer.
+ ///
+ MicroSecondDelay (STALL_PERIOD);
+ continue;
+ } else {
+ break;
+ }
+ }
+ ///
+ /// Clear Status Registers and exit
+ ///
+ SmbusIoWrite (R_SMBUS_HSTS, B_SMBUS_HSTS_ALL);
+ SmbusIoWrite (R_SMBUS_AUXS, B_SMBUS_CRCE);
+ SmbusIoWrite (R_SMBUS_AUXC, 0);
+ return Status;
+}
+
+/**
+ This function initializes the Smbus Registers.
+
+ @param[in] None
+
+ @retval[in] None
+**/
+VOID
+InitializeSmbusRegisters (
+ VOID
+ )
+{
+ UINTN SmbusRegBase;
+
+ SmbusRegBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_SC,
+ PCI_DEVICE_NUMBER_SMBUS,
+ PCI_FUNCTION_NUMBER_SMBUS
+ );
+ ///
+ /// Enable the Smbus I/O Enable
+ ///
+ MmioOr8 (SmbusRegBase + PCI_COMMAND_OFFSET, (UINT8) EFI_PCI_COMMAND_IO_SPACE);
+
+ ///
+ /// Enable the Smbus host controller
+ ///
+ MmioAndThenOr8 (
+ SmbusRegBase + R_SMBUS_HOSTC,
+ (UINT8) (~(B_SMBUS_HOSTC_SMI_EN | B_SMBUS_HOSTC_I2C_EN)),
+ B_SMBUS_HOSTC_HST_EN
+ );
+
+ SmbusIoWrite (R_SMBUS_HSTS, B_SMBUS_HSTS_ALL);
+} \ No newline at end of file