This introduces two input parameters to the I2cProbe() and updates the
InternalI2cRead() for the support of the SMBUS operation with optional
PEC check, which will be used by the IPMI SSIF driver.

Signed-off-by: Nhi Pham <n...@os.amperecomputing.com>
---
 Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h              |  11 +-
 Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.c |   6 +-
 Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c           | 129 
++++++++++++++++++--
 3 files changed, 131 insertions(+), 15 deletions(-)

diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h 
b/Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h
index f13794171029..3a312f7b6aed 100644
--- a/Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h
@@ -1,7 +1,7 @@
 /** @file
   Library implementation for the Designware I2C controller.
 
-  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+  Copyright (c) 2020 - 2024, Ampere Computing LLC. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -70,6 +70,9 @@ I2cRead (
 
   @param[in] Bus      I2C bus Id.
   @param[in] BusSpeed I2C bus speed in Hz.
+  @param[in] IsSmbus  Flag to indicate if the bus is used to execute an SMBus 
operation.
+  @param[in] PecCheck If Packet Error Code (PEC) checking is required for the 
SMBUS operation
+                      and is ignored when present in other operations.
 
   @retval EFI_SUCCESS           Success.
   @retval EFI_INVALID_PARAMETER A parameter is invalid.
@@ -78,8 +81,10 @@ I2cRead (
 EFI_STATUS
 EFIAPI
 I2cProbe (
-  IN UINT32 Bus,
-  IN UINTN  BusSpeed
+  IN UINT32   Bus,
+  IN UINTN    BusSpeed,
+  IN BOOLEAN  IsSmbus,
+  IN BOOLEAN  PecCheck
   );
 
 /**
diff --git 
a/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.c 
b/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.c
index bc886b530f3c..a9e7328381e6 100644
--- a/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.c
+++ b/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.c
@@ -1,6 +1,6 @@
 /** @file
 
-  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+  Copyright (c) 2020 - 2024, Ampere Computing LLC. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -104,7 +104,7 @@ RtcI2cRead (
     return EFI_DEVICE_ERROR;
   }
 
-  Status = I2cProbe (I2C_RTC_BUS_ADDRESS, I2C_RTC_BUS_SPEED);
+  Status = I2cProbe (I2C_RTC_BUS_ADDRESS, I2C_RTC_BUS_SPEED, FALSE, FALSE);
   if (EFI_ERROR (Status)) {
     return EFI_DEVICE_ERROR;
   }
@@ -148,7 +148,7 @@ RtcI2cWrite (
     return EFI_INVALID_PARAMETER;
   }
 
-  Status = I2cProbe (I2C_RTC_BUS_ADDRESS, I2C_RTC_BUS_SPEED);
+  Status = I2cProbe (I2C_RTC_BUS_ADDRESS, I2C_RTC_BUS_SPEED, FALSE, FALSE);
   if (EFI_ERROR (Status)) {
     return EFI_DEVICE_ERROR;
   }
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c 
b/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c
index 669ba2ea98a4..a6631ea17d69 100644
--- a/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.c
@@ -1,6 +1,6 @@
 /** @file
 
-  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+  Copyright (c) 2020 - 2024, Ampere Computing LLC. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -31,12 +31,14 @@
 // Private I2C bus data
 //
 typedef struct {
-  UINTN  Base;
-  UINT32 BusSpeed;
-  UINT32 RxFifo;
-  UINT32 TxFifo;
-  UINT32 PollingTime;
-  UINT32 Enabled;
+  UINTN      Base;
+  UINT32     BusSpeed;
+  UINT32     RxFifo;
+  UINT32     TxFifo;
+  UINT32     PollingTime;
+  UINT32     Enabled;
+  BOOLEAN    IsSmbus;
+  BOOLEAN    PecCheck;
 } DW_I2C_CONTEXT_T;
 
 //
@@ -337,6 +339,11 @@ I2cWaitTxData (
       DEBUG ((DEBUG_ERROR, "%a: Timeout waiting for TX buffer available\n", 
__FUNCTION__));
       return EFI_TIMEOUT;
     }
+
+    if ((I2cCheckErrors (Bus) & DW_IC_INTR_TX_ABRT) != 0) {
+      return EFI_ABORTED;
+    }
+
     MicroSecondDelay (mI2cBusList[Bus].PollingTime);
   }
 
@@ -542,6 +549,72 @@ InternalI2cWrite (
   return Status;
 }
 
+/**
+  This extracts the data length from the initial byte of the SMBUS 
transaction. This allows
+  the driver to accurately read the SMBUS response with the exact length, 
rather than
+  consistently reading 32-byte block of data.
+
+  @param[in]  Bus      I2C bus Id.
+  @param[out] BusSpeed Pointer to the buffer to store the read length.
+
+  @retval EFI_SUCCESS  The operation is successful.
+  @retval Others       An error occurred.
+
+**/
+EFI_STATUS
+InternalSmbusReadDataLength (
+  UINT32  Bus,
+  UINT32  *Length
+  )
+{
+  EFI_STATUS Status;
+  UINTN      Base;
+  UINT32     CmdSend;
+
+  Base = mI2cBusList[Bus].Base;
+
+  CmdSend = DW_IC_DATA_CMD_CMD;
+  MmioWrite32 (Base + DW_IC_DATA_CMD, CmdSend);
+  I2cSync ();
+
+  if (I2cCheckErrors (Bus) != 0) {
+    DEBUG ((DEBUG_ERROR, "%a: Sending reading command error\n", __func__));
+    return EFI_CRC_ERROR;
+  }
+
+  Status = I2cWaitRxData (Bus);
+  if (EFI_ERROR (Status)) {
+    //
+    // If the SMBUS target is not ready to handle the request
+    // or is busy with preparing the response data, it will response
+    // NACK, and the error status TX_ABRT is triggered to indicate that
+    // the RX FIFO is not ready for reading. Thus, the following message
+    // serves more as verbose alert rather than an error.
+    //
+    DEBUG ((DEBUG_VERBOSE,
+      "%a: Reading Smbus data length failed to wait data\n",
+      __func__
+      ));
+
+    if (Status != EFI_ABORTED) {
+      MmioWrite32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_STOP);
+      I2cSync ();
+    }
+
+    return Status;
+  }
+
+  *Length = MmioRead32 (Base + DW_IC_DATA_CMD) & DW_IC_DATA_CMD_DAT_MASK;
+  I2cSync ();
+
+  if (I2cCheckErrors (Bus) != 0) {
+    DEBUG ((DEBUG_ERROR, "%a: Sending reading command error\n", __func__));
+    return EFI_CRC_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
 EFI_STATUS
 InternalI2cRead (
   UINT32  Bus,
@@ -559,6 +632,7 @@ InternalI2cRead (
   UINTN      Count;
   UINTN      ReadCount;
   UINTN      WriteCount;
+  UINT32     ResponseLen;
 
   Status = EFI_SUCCESS;
   Base = mI2cBusList[Bus].Base;
@@ -601,6 +675,35 @@ InternalI2cRead (
   }
 
   WriteCount = 0;
+  if (mI2cBusList[Bus].IsSmbus) {
+    //
+    // Read Smbus Data Length, first byte of the Smbus response data.
+    //
+    Status = InternalSmbusReadDataLength (Bus, &ResponseLen);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+
+    WriteCount++;
+    Buf[ReadCount++] = ResponseLen;
+
+    //
+    // Abort the transaction when the requested length is shorter than the 
actual response data
+    // or if there is no response data when PEC disabled.
+    //
+    if ((*Length < (ResponseLen + 2)) || (!mI2cBusList[Bus].PecCheck && 
ResponseLen == 0)) {
+      MmioWrite32 (Base + DW_IC_DATA_CMD, DW_IC_DATA_CMD_CMD | 
DW_IC_DATA_CMD_STOP);
+      I2cSync ();
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+    }
+
+    *Length = ResponseLen + 1; // Response Data Length + 8-bit Byte Count field
+    if (mI2cBusList[Bus].PecCheck) {
+      *Length += 1; // ++ 8-bit PEC field
+    }
+  }
+
   while ((*Length - ReadCount) != 0) {
     TxLimit = mI2cBusList[Bus].TxFifo - MmioRead32 (Base + DW_IC_TXFLR);
     RxLimit = mI2cBusList[Bus].RxFifo - MmioRead32 (Base + DW_IC_RXFLR);
@@ -750,6 +853,9 @@ I2cRead (
 
   @param[in] Bus      I2C bus Id.
   @param[in] BusSpeed I2C bus speed in Hz.
+  @param[in] IsSmbus  Flag to indicate if the bus is used to execute an SMBus 
operation.
+  @param[in] PecCheck If Packet Error Code (PEC) checking is required for the 
SMBUS operation
+                      and is ignored when present in other operations.
 
   @retval EFI_SUCCESS           Success.
   @retval EFI_INVALID_PARAMETER A parameter is invalid.
@@ -758,8 +864,10 @@ I2cRead (
 EFI_STATUS
 EFIAPI
 I2cProbe (
-  IN UINT32 Bus,
-  IN UINTN  BusSpeed
+  IN UINT32   Bus,
+  IN UINTN    BusSpeed,
+  IN BOOLEAN  IsSmbus,
+  IN BOOLEAN  PecCheck
   )
 {
   if (Bus >= AC01_I2C_MAX_BUS_NUM
@@ -768,6 +876,9 @@ I2cProbe (
     return EFI_INVALID_PARAMETER;
   }
 
+  mI2cBusList[Bus].IsSmbus  = IsSmbus;
+  mI2cBusList[Bus].PecCheck = PecCheck;
+
   return I2cInit (Bus, BusSpeed);
 }
 
-- 
2.25.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#120262): https://edk2.groups.io/g/devel/message/120262
Mute This Topic: https://groups.io/mt/107765353/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to