diff options
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/Smbus/Common')
5 files changed, 1078 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommon.h b/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommon.h new file mode 100644 index 0000000..35cf2e5 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommon.h @@ -0,0 +1,190 @@ +/** @file + PCH Smbus Protocol + +@copyright + Copyright (c) 2004 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#ifndef _PCH_SMBUS_COMMON_H +#define _PCH_SMBUS_COMMON_H + +// +// External include files do NOT need to be explicitly specified in real EDKII +// environment +// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGlueBase.h" +#include "PchAccess.h" +#include "PchPlatformLib.h" +#include "EfiSmbus.h" + +#endif +// +// Definitions +// +#define STALL_PERIOD 10 * STALL_ONE_MICRO_SECOND ///< 10 microseconds +#define STALL_TIME STALL_ONE_SECOND ///< 1 second +#define BUS_TRIES 3 ///< How many times to retry on Bus Errors +#define SMBUS_NUM_RESERVED 38 ///< Number of device addresses that are reserved by the SMBus spec. +#define SMBUS_ADDRESS_ARP 0xC2 >> 1 +#define SMBUS_DATA_PREPARE_TO_ARP 0x01 +#define SMBUS_DATA_RESET_DEVICE 0x02 +#define SMBUS_DATA_GET_UDID_GENERAL 0x03 +#define SMBUS_DATA_ASSIGN_ADDRESS 0x04 +#define SMBUS_GET_UDID_LENGTH 17 ///< 16 byte UDID + 1 byte address +// +// Private data and functions +// + +typedef +UINT8 +(EFIAPI *SMBUS_IO_READ) ( + IN UINT8 Offset + ); + +typedef +VOID +(EFIAPI *SMBUS_IO_WRITE) ( + IN UINT8 Offset, + IN UINT8 Data + ); + +typedef +BOOLEAN +(EFIAPI *SMBUS_IO_DONE) ( + IN UINT8 *StsReg + ); + +#define PCH_SMBUS_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('p', 's', 'm', 'b') + +/** + Get SMBUS IO Base address + + @param[in] None + + @retval UINT32 The SMBUS IO Base Address +**/ +UINT32 +SmbusGetIoBase ( + VOID + ); + +/** + 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 + ); + +/** + 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. + + @retval None. +**/ +VOID +EFIAPI +SmbusIoWrite ( + IN UINT8 Offset, + IN UINT8 Data + ); + +/** + This function provides a standard way to check if an 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 + ); + +/** + Check if it's ok to use the bus. + + @param[in] None + + @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 + ); + +/** + 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 + ); + +/** + This function initializes the Smbus Registers. + + @param[in] None. + + @retval None. +**/ +VOID +InitializeSmbusRegisters ( + VOID + ); +#endif diff --git a/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommonLib.cif b/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommonLib.cif new file mode 100644 index 0000000..e62b886 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommonLib.cif @@ -0,0 +1,11 @@ +<component> + name = "PchSmbusCommonLib" + category = ModulePart + LocalRoot = "ReferenceCode\Chipset\LynxPoint\Smbus\Common" + RefName = "PchSmbusCommonLib" +[files] +"PchSmbusCommonLib.sdl" +"PchSmbusCommonLib.mak" +"PchSmbusExec.c" +"PchSmbusCommon.h" +<endComponent>
\ No newline at end of file diff --git a/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommonLib.mak b/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommonLib.mak new file mode 100644 index 0000000..2eb1277 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommonLib.mak @@ -0,0 +1,124 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#************************************************************************* +# $Header: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchSmbusCommonLib/PchSmbusCommonLib.mak 1 2/08/12 9:18a Yurenlai $ +# +# $Revision: 1 $ +# +# $Date: 2/08/12 9:18a $ +#************************************************************************* +# Revision History +# ---------------- +# $Log: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchSmbusCommonLib/PchSmbusCommonLib.mak $ +# +# 1 2/08/12 9:18a Yurenlai +# Intel Lynx Point/SB eChipset initially releases. +# +#************************************************************************* +all : PchSmbusCommonLib + +PchSmbusCommonLib : PchSmbusCommonDxeLib PchSmbusCommonSmmLib PchSmbusCommonPeiLib + +$(PchSmbusCommonSmmLib_LIB) : PchSmbusCommonSmmLib +$(PchSmbusCommonDxeLib_LIB) : PchSmbusCommonDxeLib +$(PchSmbusCommonPeiLib_LIB) : PchSmbusCommonPeiLib + +PchSmbusCommonSmmLib : $(BUILD_DIR)\PchSmbusCommonLib.mak PchSmbusCommonLibSmmBin + +PchSmbusCommonDxeLib : $(BUILD_DIR)\PchSmbusCommonLib.mak PchSmbusCommonLibDxeBin + +PchSmbusCommonPeiLib : $(BUILD_DIR)\PchSmbusCommonLib.mak PchSmbusCommonLibPeiBin + +$(BUILD_DIR)\PchSmbusCommonLib.mak : $(PchSmbusCommonLib_DIR)\$(@B).cif $(PchSmbusCommonLib_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(PchSmbusCommonLib_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +PchSmbusCommonLib_INCLUDES=\ + $(EdkIIGlueLib_INCLUDES)\ + $(INTEL_PCH_INCLUDES)\ + +PchSmbusCommonLibSmm_INCLUDES=\ + $(PchSmbusCommonLib_INCLUDES) + +PchSmbusCommonLibDxe_INCLUDES=\ + $(PchSmbusCommonLib_INCLUDES) + +PchSmbusCommonLibPeim_INCLUDES=\ + $(PchSmbusCommonLib_INCLUDES) + +PchSmbusCommonLib_DEFINES = \ + $(CFLAGS) + +DxeCpuBuildDefine = \ +!IF "$(x64_BUILD)"=="1" + /DMDE_CPU_X64\ +!ELSE + /DMDE_CPU_IA32\ +!ENDIF + +PeimCpuBuildDefine = \ + /DMDE_CPU_IA32\ + +PchSmbusCommonLibPeim_DEFINES = \ + $(PchSmbusCommonLib_DEFINES)\ + $(PeimCpuBuildDefine)\ + +PchSmbusCommonLibDxe_DEFINES = \ + $(PchSmbusCommonLib_DEFINES)\ + $(DxeCpuBuildDefine)\ + +PchSmbusCommonLibSmm_DEFINES = \ + $(PchSmbusCommonLibDxe_DEFINES)\ + +PchSmbusCommonLibDxeBin : + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS) \ + /f $(BUILD_DIR)\PchSmbusCommonLib.mak all\ + "MY_INCLUDES=$(PchSmbusCommonLibDxe_INCLUDES)" \ + "CFLAGS=$(PchSmbusCommonLibDxe_DEFINES)"\ + TYPE=LIBRARY \ + LIBRARY_NAME=$(PchSmbusCommonDxeLib_LIB) + +PchSmbusCommonLibSmmBin : + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS) \ + /f $(BUILD_DIR)\PchSmbusCommonLib.mak all\ + "MY_INCLUDES=$(PchSmbusCommonLibSmm_INCLUDES)" \ + "CFLAGS=$(PchSmbusCommonLibSmm_DEFINES)"\ + TYPE=LIBRARY \ + BUILD_DIR=$(BUILD_DIR)\Smm\ + LIBRARY_NAME=$(PchSmbusCommonSmmLib_LIB) + +PchSmbusCommonLibPeiBin : +!IF "$(x64_BUILD)"=="1" + $(MAKE) /$(MAKEFLAGS) $(EDK_DEFAULTS) BUILD_DIR=$(BUILD_DIR)\IA32 \ +!ELSE + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS) \ +!ENDIF + /f $(BUILD_DIR)\PchSmbusCommonLib.mak all\ + "MY_INCLUDES=$(PchSmbusCommonLibPeim_INCLUDES)" \ + "CFLAGS=$(PchSmbusCommonLibPeim_DEFINES)"\ + TYPE=PEI_LIBRARY \ + LIBRARY_NAME=$(PchSmbusCommonPeiLib_LIB) +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommonLib.sdl b/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommonLib.sdl new file mode 100644 index 0000000..7785408 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusCommonLib.sdl @@ -0,0 +1,92 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#************************************************************************* +# $Header: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchSmbusCommonLib/PchSmbusCommonLib.sdl 1 2/08/12 9:18a Yurenlai $ +# +# $Revision: 1 $ +# +# $Date: 2/08/12 9:18a $ +#************************************************************************* +# Revision History +# ---------------- +# $Log: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchSmbusCommonLib/PchSmbusCommonLib.sdl $ +# +# 1 2/08/12 9:18a Yurenlai +# Intel Lynx Point/SB eChipset initially releases. +# +#************************************************************************* +TOKEN + Name = "PchSmbusCommonLib_SUPPORT" + Value = "1" + Help = "Main switch to enable PchSmbusCommonLib support in Project" + TokenType = Boolean + TargetMAK = Yes + Master = Yes +End + +PATH + Name = "PchSmbusCommonLib_DIR" +End + +MODULE + Help = "Includes PchSmbusCommonLib.mak to Project" + File = "PchSmbusCommonLib.mak" +End + +ELINK + Name = "PchSmbusCommonDxeLib_LIB" + InvokeOrder = ReplaceParent +End + +ELINK + Name = "$(BUILD_DIR)\PchSmbusCommonDxeLib.lib" + Parent = "PchSmbusCommonDxeLib_LIB" + InvokeOrder = AfterParent +End + +ELINK + Name = "PchSmbusCommonPeiLib_LIB" + InvokeOrder = ReplaceParent +End + +ELINK + Name = "$(BUILD_DIR)\PchSmbusCommonPeiLib.lib" + Parent = "PchSmbusCommonPeiLib_LIB" + InvokeOrder = AfterParent +End + +ELINK + Name = "PchSmbusCommonSmmLib_LIB" + InvokeOrder = ReplaceParent +End + +ELINK + Name = "$(BUILD_DIR)\PchSmbusCommonSmmLib.lib" + Parent = "PchSmbusCommonSmmLib_LIB" + InvokeOrder = AfterParent +End +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusExec.c b/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusExec.c new file mode 100644 index 0000000..4015dda --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Smbus/Common/PchSmbusExec.c @@ -0,0 +1,661 @@ +/** @file + PCH Smbus Executive Code (common PEI/DXE/SMM code) + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PchSmbusCommon.h" + +/** + Get SMBUS IO Base address + + @param[in] None + + @retval UINT32 The SMBUS IO Base Address +**/ +UINT32 +SmbusGetIoBase ( + VOID + ) +{ + UINT32 SmbusIoBase; + + SmbusIoBase = MmioRead32 ( + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_SMBUS, + PCI_FUNCTION_NUMBER_PCH_SMBUS, + R_PCH_SMBUS_BASE) + ) & B_PCH_SMBUS_BASE_BAR; + + ASSERT (SmbusIoBase != B_PCH_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. + + @retval None. +**/ +VOID +EFIAPI +SmbusIoWrite ( + IN UINT8 Offset, + IN UINT8 Data + ) +{ + /// + /// Write New Value + /// + IoWrite8 (SmbusGetIoBase () + Offset, Data); + return; +} + +/** + This function provides a standard way to check if an 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 + ) +{ + /// + /// Wait for IO to complete + /// + UINTN StallIndex; + UINTN StallTries; + + StallTries = STALL_TIME / STALL_PERIOD; + + for (StallIndex = 0; StallIndex < StallTries; StallIndex++) { + *StsReg = SmbusIoRead (R_PCH_SMBUS_HSTS); + if (*StsReg & (B_PCH_SMBUS_INTR | B_PCH_SMBUS_BYTE_DONE_STS | B_PCH_SMBUS_DERR | B_PCH_SMBUS_BERR)) { + return TRUE; + } else { + PchPmTimerStall (STALL_PERIOD); + } + } + + return FALSE; +} + +/** + Check if it's ok to use the bus. + + @param[in] None + + @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_PCH_SMBUS_HSTS); + if (StsReg & B_PCH_SMBUS_IUS) { + return EFI_TIMEOUT; + } else if (StsReg & B_PCH_SMBUS_HBSY) { + /// + /// Clear Status Register and exit + /// + SmbusIoWrite (R_PCH_SMBUS_HSTS, B_PCH_SMBUS_HSTS_ALL); + return EFI_TIMEOUT; + } else { + /// + /// Clear out any odd status information (Will Not Clear In Use) + /// + SmbusIoWrite (R_PCH_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_PCH_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_PCH_SMBUS_SMB_CMD_BYTE; + if (*Length < 1) { + Status = EFI_BUFFER_TOO_SMALL; + } + + *Length = 1; + break; + + case EfiSmbusWriteByte: + SmbusIoWrite (R_PCH_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_PCH_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_PCH_SMBUS_SMB_CMD_IIC_READ; + } else { + Status = EFI_INVALID_PARAMETER; + } + + break; + + case EfiSmbusReadWord: + SmbusOperation = V_PCH_SMBUS_SMB_CMD_WORD_DATA; + if (*Length < 2) { + Status = EFI_BUFFER_TOO_SMALL; + } + + *Length = 2; + break; + + case EfiSmbusWriteWord: + SmbusOperation = V_PCH_SMBUS_SMB_CMD_WORD_DATA; + SlvAddrReg--; + SmbusIoWrite (R_PCH_SMBUS_HD1, CallBuffer[1]); + SmbusIoWrite (R_PCH_SMBUS_HD0, CallBuffer[0]); + if (*Length < 2) { + Status = EFI_BUFFER_TOO_SMALL; + } + + *Length = 2; + break; + + case EfiSmbusWriteBlock: + SmbusIoWrite (R_PCH_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_PCH_SMBUS_SMB_CMD_BLOCK; + if ((*Length < 1) || (*Length > 32)) { + Status = EFI_INVALID_PARAMETER; + break; + } + + AuxcReg |= B_PCH_SMBUS_E32B; + break; + + case EfiSmbusProcessCall: + SmbusOperation = V_PCH_SMBUS_SMB_CMD_PROCESS_CALL; + SmbusIoWrite (R_PCH_SMBUS_HD1, CallBuffer[1]); + SmbusIoWrite (R_PCH_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_PCH_SMBUS_HD0, *(UINT8 *) Length); + BlockCount = (UINT8) (*Length); + SmbusOperation = V_PCH_SMBUS_SMB_CMD_BLOCK_PROCESS; + + AuxcReg |= B_PCH_SMBUS_E32B; + break; + + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + if (EFI_ERROR (Status)) { + break; + } + + if (PecCheck == TRUE) { + AuxcReg |= B_PCH_SMBUS_AAC; + } + /// + /// Set Auxiliary Control register + /// + SmbusIoWrite (R_PCH_SMBUS_AUXC, AuxcReg); + + /// + /// Reset the pointer of the internal buffer + /// + SmbusIoRead (R_PCH_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_PCH_SMBUS_HBD, CallBuffer[Index]); + } + } + /// + /// Set SMBus slave address for the device to send/receive from + /// + SmbusIoWrite (R_PCH_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_PCH_SMBUS_HD1, HostCmdReg); + } else { + /// + /// Set Command register + /// + SmbusIoWrite (R_PCH_SMBUS_HCMD, HostCmdReg); + } + /// + /// Set Control Register (Initiate Operation, Interrupt disabled) + /// + SmbusIoWrite (R_PCH_SMBUS_HCTL, (UINT8) (SmbusOperation + B_PCH_SMBUS_START)); + + /// + /// Wait for IO to complete + /// + if (!IoDone (&StsReg)) { + Status = EFI_TIMEOUT; + break; + } else if (StsReg & B_PCH_SMBUS_DERR) { + AuxStsReg = SmbusIoRead (R_PCH_SMBUS_AUXS); + if (AuxStsReg & B_PCH_SMBUS_CRCE) { + Status = EFI_CRC_ERROR; + } else { + Status = EFI_DEVICE_ERROR; + } + break; + } else if (StsReg & B_PCH_SMBUS_BERR) { + /// + /// Clear the Bus Error for another try + /// + Status = EFI_DEVICE_ERROR; + SmbusIoWrite (R_PCH_SMBUS_HSTS, B_PCH_SMBUS_BERR); + /// + /// Clear Status Registers + /// + SmbusIoWrite (R_PCH_SMBUS_HSTS, B_PCH_SMBUS_HSTS_ALL); + SmbusIoWrite (R_PCH_SMBUS_AUXS, B_PCH_SMBUS_CRCE); + /// + /// If bus collision happens, stall some time, then try again + /// Here we choose 10 milliseconds to avoid MTCP transfer. + /// + PchPmTimerStall (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_PCH_SMBUS_HD1); + CallBuffer[0] = SmbusIoRead (R_PCH_SMBUS_HD0); + break; + + case EfiSmbusReadByte: + if (*Length > 1) { + for (Index = 0; Index < *Length; Index++) { + /// + /// Read the byte + /// + CallBuffer[Index] = SmbusIoRead (R_PCH_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_PCH_SMBUS_HCTL) | (UINT8) B_PCH_SMBUS_LAST_BYTE; + SmbusIoWrite (R_PCH_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_PCH_SMBUS_HCTL) & (UINT8) ~B_PCH_SMBUS_LAST_BYTE; + SmbusIoWrite (R_PCH_SMBUS_HCTL, SmbusHctl); + } + /// + /// Clear the BYTE_DONE_STS bit + /// + SmbusIoWrite (R_PCH_SMBUS_HSTS, B_PCH_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_PCH_SMBUS_HSTS) & (UINT8) B_PCH_SMBUS_BYTE_DONE_STS) != 0) { + break; + } + /// + /// Delay 10 us + /// + PchPmTimerStall (STALL_PERIOD); + } + + if (Timeout >= 100) { + Status = EFI_TIMEOUT; + break; + } + } + } + break; + } + + case EfiSmbusReceiveByte: + CallBuffer[0] = SmbusIoRead (R_PCH_SMBUS_HD0); + break; + + case EfiSmbusWriteBlock: + SmbusIoWrite (R_PCH_SMBUS_HSTS, B_PCH_SMBUS_BYTE_DONE_STS); + break; + + case EfiSmbusReadBlock: + BufferTooSmall = FALSE; + /// + /// Find out how many bytes will be in the block + /// + BlockCount = SmbusIoRead (R_PCH_SMBUS_HD0); + if (*Length < BlockCount) { + BufferTooSmall = TRUE; + } else { + for (Index = 0; Index < BlockCount; Index++) { + /// + /// Read the byte + /// + CallBuffer[Index] = SmbusIoRead (R_PCH_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_PCH_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_PCH_SMBUS_HBD); + } + + *Length = BlockCount; + break; + + default: + break; + }; + + if ((StsReg & B_PCH_SMBUS_BERR) && (Status != EFI_BUFFER_TOO_SMALL)) { + /// + /// Clear the Bus Error for another try + /// + Status = EFI_DEVICE_ERROR; + SmbusIoWrite (R_PCH_SMBUS_HSTS, B_PCH_SMBUS_BERR); + /// + /// If bus collision happens, stall some time, then try again + /// Here we choose 10 milliseconds to avoid MTCP transfer. + /// + PchPmTimerStall (STALL_PERIOD); + continue; + } else { + break; + } + } + /// + /// Clear Status Registers and exit + /// + SmbusIoWrite (R_PCH_SMBUS_HSTS, B_PCH_SMBUS_HSTS_ALL); + SmbusIoWrite (R_PCH_SMBUS_AUXS, B_PCH_SMBUS_CRCE); + SmbusIoWrite (R_PCH_SMBUS_AUXC, 0); + return Status; +} + +/** + This function initializes the Smbus Registers. + + @param[in] None. + + @retval None. +**/ +VOID +InitializeSmbusRegisters ( + VOID + ) +{ + UINTN SmbusRegBase; + + SmbusRegBase = MmPciAddress ( + 0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_SMBUS, + PCI_FUNCTION_NUMBER_PCH_SMBUS, + 0 + ); + /// + /// Enable the Smbus I/O Enable + /// + MmioOr8 (SmbusRegBase + R_PCH_SMBUS_PCICMD, B_PCH_SMBUS_PCICMD_IOSE); + + /// + /// Enable the Smbus host controller + /// + MmioAndThenOr8 ( + SmbusRegBase + R_PCH_SMBUS_HOSTC, + (UINT8) (~(B_PCH_SMBUS_HOSTC_SMI_EN | B_PCH_SMBUS_HOSTC_I2C_EN)), + B_PCH_SMBUS_HOSTC_HST_EN + ); + + SmbusIoWrite (R_PCH_SMBUS_HSTS, B_PCH_SMBUS_HSTS_ALL); +}
\ No newline at end of file |