summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/build/tools/listdeps.pl4
-rw-r--r--src/include/usr/devicefw/driverif.H92
-rw-r--r--src/include/usr/hbotcompid.H11
-rw-r--r--src/include/usr/i2c/i2creasoncodes.H53
-rw-r--r--src/include/usr/initservice/initsvcstructs.H4
-rw-r--r--src/include/usr/isteps/istep21list.H3
-rw-r--r--src/include/usr/isteps/ucd/updateUcdFlash.H64
-rw-r--r--src/makefile1
-rwxr-xr-xsrc/usr/i2c/i2c.C762
-rwxr-xr-xsrc/usr/i2c/i2c.H262
-rw-r--r--src/usr/i2c/i2c_common.H31
-rw-r--r--src/usr/isteps/istep21/call_update_ucd_flash.C11
-rw-r--r--src/usr/isteps/makefile3
-rw-r--r--src/usr/isteps/ucd/makefile32
-rw-r--r--src/usr/isteps/ucd/updateUcdFlash.C67
15 files changed, 1341 insertions, 59 deletions
diff --git a/src/build/tools/listdeps.pl b/src/build/tools/listdeps.pl
index c0a1fc476..be7b3a4d6 100755
--- a/src/build/tools/listdeps.pl
+++ b/src/build/tools/listdeps.pl
@@ -6,7 +6,7 @@
#
# OpenPOWER HostBoot Project
#
-# Contributors Listed Below - COPYRIGHT 2013,2018
+# Contributors Listed Below - COPYRIGHT 2013,2019
# [+] Google Inc.
# [+] International Business Machines Corp.
#
@@ -39,7 +39,7 @@ use File::Path;
use Cwd;
# This constant has a corresponding entry in src/include/usr/initservice/initsvcstructs.H.
-use constant MAX_DEPENDENT_MODULES => 10;
+use constant MAX_DEPENDENT_MODULES => 12;
# validate the number of input args
if( $#ARGV == -1 || $#ARGV > 4 )
diff --git a/src/include/usr/devicefw/driverif.H b/src/include/usr/devicefw/driverif.H
index 6e94f04e4..e91c43518 100644
--- a/src/include/usr/devicefw/driverif.H
+++ b/src/include/usr/devicefw/driverif.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2018 */
+/* Contributors Listed Below - COPYRIGHT 2011,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -91,6 +91,20 @@ namespace DeviceFW
WILDCARD = -1,
};
+ /**
+ * @brief Enum indicating which type of I2C sub-operation
+ * to perform
+ */
+ enum I2C_SUBOP : uint64_t
+ {
+ I2C_STANDARD = 0, ///< Traditional I2C
+ I2C_PAGE_OP = 1, ///< Page operation
+ I2C_SMBUS_BLOCK = 2, ///< I2c SMBUS Block Read/Write
+ I2C_SMBUS_WORD = 3, ///< I2c SMBUS Read/Write Word
+ I2C_SMBUS_BYTE = 4, ///< I2c SMBUS Read/Write Byte
+ I2C_SMBUS_SEND_OR_RECV = 5, ///< I2c SMBUS Send/Receive Byte
+ };
+
#ifndef PARSER
/** Construct the device addressing parameters for FSISCOM device ops.
* @param[in] i_address - FSISCOM address to operate on.
@@ -130,6 +144,7 @@ namespace DeviceFW
*/
#define DEVICE_I2C_PARMS(port, engine, devAddr, offset_len,\
offset, muxSelector, i_i2cMuxPath)\
+ static_cast<uint64_t>( DeviceFW::I2C_STANDARD ),\
static_cast<uint64_t>( port ),\
static_cast<uint64_t>( engine ),\
static_cast<uint64_t>( devAddr ),\
@@ -139,6 +154,33 @@ namespace DeviceFW
static_cast<const TARGETING::EntityPath*>(i_i2cMuxPath)
/**
+ * @brief Macro that handles the I2C SMBUS data transfers that use
+ * a command code (Read/Write Word/Byte or Block Read/Write)
+ */
+ #define I2C_SMBUS_RW_W_CMD_PARAMS(i_subop,i_engine,i_port,i_devAddr,\
+ i_commandCode,i_muxSelector,i_i2cMuxPath)\
+ static_cast<uint64_t>(i_subop),\
+ static_cast<uint64_t>(i_port),\
+ static_cast<uint64_t>(i_engine),\
+ static_cast<uint64_t>(i_devAddr),\
+ static_cast<uint64_t>(i_commandCode),\
+ static_cast<uint64_t>(i_muxSelector),\
+ static_cast<const TARGETING::EntityPath*>(i_i2cMuxPath)
+
+ /**
+ * @brief Macro that handles the I2C SMBUS data transfers that don't use
+ * a command code byte (Send/Receive Byte)
+ */
+ #define I2C_SMBUS_RW_WO_CMD_PARAMS(i_subop,i_engine,i_port,i_devAddr,\
+ i_muxSelector,i_i2cMuxPath)\
+ static_cast<uint64_t>(i_subop),\
+ static_cast<uint64_t>(i_port),\
+ static_cast<uint64_t>(i_engine),\
+ static_cast<uint64_t>(i_devAddr),\
+ static_cast<uint64_t>(i_muxSelector),\
+ static_cast<const TARGETING::EntityPath*>(i_i2cMuxPath)
+
+ /**
* Construct the device addressing parameters for the I2C device ops.
* @param[in] i_port - Which port to use from the I2C master.
* @param[in] i_engine - Which I2C master engine to use.
@@ -153,6 +195,53 @@ namespace DeviceFW
0, nullptr, i_i2cMuxBusSelector, i_i2cMuxPath)
/**
+ * @brief Construct the device addressing parameters for the I2C SMBUS
+ * data transfer commands that have a command parameter
+ *
+ * @param[in] i_engine Which I2C master engine to use
+ * @param[in] i_port Which port to use from the I2C master engine above
+ * @param[in] i_devAddr The device address to communicate with on a given
+ * engine/port.
+ * @param[in] i_commandCode The PMBUS command to execute
+ * @param[in] i_i2cMuxBusSelector The I2C MUX bus selector
+ * @param[in] i_i2cMuxPath The I2C MUX entity path
+ */
+ #define DEVICE_I2C_SMBUS_BLOCK(i_engine,i_port,i_devAddr,i_commandCode,\
+ i_i2cMuxBusSelector,i_i2cMuxPath)\
+ DeviceFW::I2C, I2C_SMBUS_RW_W_CMD_PARAMS(DeviceFW::I2C_SMBUS_BLOCK,\
+ i_engine,i_port,i_devAddr,\
+ i_commandCode,i_i2cMuxBusSelector,i_i2cMuxPath)
+
+ #define DEVICE_I2C_SMBUS_WORD(i_engine,i_port,i_devAddr,i_commandCode,\
+ i_i2cMuxBusSelector,i_i2cMuxPath )\
+ DeviceFW::I2C, I2C_SMBUS_RW_W_CMD_PARAMS(DeviceFW::I2C_SMBUS_WORD,\
+ i_engine,i_port,i_devAddr,\
+ i_commandCode,i_i2cMuxBusSelector,i_i2cMuxPath)
+
+ #define DEVICE_I2C_SMBUS_BYTE(i_engine, i_port,i_devAddr,i_commandCode,\
+ i_i2cMuxBusSelector,i_i2cMuxPath)\
+ DeviceFW::I2C, I2C_SMBUS_RW_W_CMD_PARAMS(DeviceFW::I2C_SMBUS_BYTE,\
+ i_engine,i_port,i_devAddr,\
+ i_commandCode,i_i2cMuxBusSelector,i_i2cMuxPath)
+ /**
+ * @brief Construct the device addressing parameters for the I2C SMBUS
+ * data transfer commands that lack a command parameter
+ *
+ * @param[in] i_engine Which I2C master engine to use
+ * @param[in] i_port Which port to use from the I2C master engine above
+ * @param[in] i_devAddr The device address to communicate with on a given
+ * engine/port.
+ * @param[in] i_i2cMuxBusSelector The I2C MUX bus selector
+ * @param[in] i_i2cMuxPath The I2C MUX entity path
+ */
+ #define DEVICE_I2C_SMBUS_SEND_OR_RECV(i_engine, i_port, i_devAddr,\
+ i_i2cMuxBusSelector,i_i2cMuxPath)\
+ DeviceFW::I2C, I2C_SMBUS_RW_WO_CMD_PARAMS(\
+ DeviceFW::I2C_SMBUS_SEND_OR_RECV,\
+ i_engine,i_port,i_devAddr,\
+ i_i2cMuxBusSelector,i_i2cMuxPath)
+
+ /**
* Construct the device addressing parameters for the I2C-offset device ops.
* @param[in] i_port - Which port to use from the I2C master.
* @param[in] i_engine - Which I2C master engine to use.
@@ -184,6 +273,7 @@ namespace DeviceFW
#define DEVICE_I2C_CONTROL_PAGE_OP( i_port, i_engine, i_shouldLock,\
i_desired_page, i_lockMutex )\
DeviceFW::I2C,\
+ static_cast<uint64_t>(DeviceFW::I2C_PAGE_OP),\
static_cast<uint64_t>(i_port),\
static_cast<uint64_t>(i_engine),\
0xffffffff,\
diff --git a/src/include/usr/hbotcompid.H b/src/include/usr/hbotcompid.H
index c9987ac6d..e3a3ec5d7 100644
--- a/src/include/usr/hbotcompid.H
+++ b/src/include/usr/hbotcompid.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2018 */
+/* Contributors Listed Below - COPYRIGHT 2011,2019 */
/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
@@ -476,6 +476,15 @@ const char SMF_COMP_NAME[] = "smf";
//@}
+/** @name UCD
+ * UCD flash update component
+ */
+//@{
+const compId_t UCD_COMP_ID = 0x4100;
+const char UCD_COMP_NAME[] = "ucd";
+
+//@}
+//
/** @name HDAT
* HDAT component
* @Note HDAT_COMP_ID=0x9000 matches with what
diff --git a/src/include/usr/i2c/i2creasoncodes.H b/src/include/usr/i2c/i2creasoncodes.H
index 6b08aefc2..6e29065db 100644
--- a/src/include/usr/i2c/i2creasoncodes.H
+++ b/src/include/usr/i2c/i2creasoncodes.H
@@ -77,30 +77,35 @@ enum i2cModuleId
*/
enum i2cReasonCode
{
- I2C_INVALID_REASONCODE = I2C_COMP_ID | 0x00, // Invalid Reasoncode
- I2C_INVALID_DATA_BUFFER = I2C_COMP_ID | 0x01, // Invalid Data Buffer pointer
- I2C_INVALID_OP_TYPE = I2C_COMP_ID | 0x02, // Invalid Operation type
- I2C_FIFO_TIMEOUT = I2C_COMP_ID | 0x03, // Timed out waiting on FIFO
- I2C_BUS_NOT_READY = I2C_COMP_ID | 0x04, // Bus Not ready
- I2C_CMD_COMP_TIMEOUT = I2C_COMP_ID | 0x05, // Timeout waiting for Cmd Complete
- I2C_HW_ERROR_FOUND = I2C_COMP_ID | 0x06, // Error found in status register
- I2C_MASTER_SENTINEL_TARGET = I2C_COMP_ID | 0x07, // Master Sentinel used as target
- I2C_NO_CENTAUR_FOUND = I2C_COMP_ID | 0x08, // No Centaur chip found
- I2C_NO_PROC_FOUND = I2C_COMP_ID | 0x09, // No Processor chip found
- I2C_ATTRIBUTE_NOT_FOUND = I2C_COMP_ID | 0x0A, // Needed I2C-related Attribute not found
- I2C_NACK_ONLY_FOUND = I2C_COMP_ID | 0x0B, // Only NACK found in status register
- I2C_ARBITRATION_LOST_ONLY_FOUND = I2C_COMP_ID | 0x0C, // Bus Arbi lost found in status reg
- I2C_RUNTIME_INTERFACE_ERR = I2C_COMP_ID | 0x0D, // Read/write unavailable at runtime
- I2C_RUNTIME_ERR = I2C_COMP_ID | 0x0E, // Failed run-time operation
- I2C_RUNTIME_INVALID_OFFSET_LENGTH = I2C_COMP_ID | 0x0F, // Offset length of invalid size
- I2C_INVALID_EEPROM_PAGE_MUTEX = I2C_COMP_ID | 0x10, // Error getting page mutex for i2c engine.
- I2C_INVALID_EEPROM_PAGE_REQUEST = I2C_COMP_ID | 0x11, // Invalid EEPROM page request
- I2C_FAILURE_UNLOCKING_EEPROM_PAGE = I2C_COMP_ID | 0x12, // Error while attempting to unlock the eeprom page
- INVALID_MASTER_TARGET = I2C_COMP_ID | 0x13, // Master I2C target not valid
- I2C_MUX_TARGET_NOT_FOUND = I2C_COMP_ID | 0x14, // The MUX target is not valid (null)
- I2C_MUX_TARGET_NON_FUNCTIONAL = I2C_COMP_ID | 0x15, // The MUX target is non functional
- I2C_INVALID_LENGTH = I2C_COMP_ID | 0x16, // Invalid data buffer length passed to function
- I2C_NULL_MASTER_TARGET = I2C_COMP_ID | 0x17, // Target Service's toPath() returned nullptr for target
+ I2C_INVALID_REASONCODE = I2C_COMP_ID | 0x00, // Invalid Reasoncode
+ I2C_INVALID_DATA_BUFFER = I2C_COMP_ID | 0x01, // Invalid Data Buffer pointer
+ I2C_INVALID_OP_TYPE = I2C_COMP_ID | 0x02, // Invalid Operation type
+ I2C_FIFO_TIMEOUT = I2C_COMP_ID | 0x03, // Timed out waiting on FIFO
+ I2C_BUS_NOT_READY = I2C_COMP_ID | 0x04, // Bus Not ready
+ I2C_CMD_COMP_TIMEOUT = I2C_COMP_ID | 0x05, // Timeout waiting for Cmd Complete
+ I2C_HW_ERROR_FOUND = I2C_COMP_ID | 0x06, // Error found in status register
+ I2C_MASTER_SENTINEL_TARGET = I2C_COMP_ID | 0x07, // Master Sentinel used as target
+ I2C_NO_CENTAUR_FOUND = I2C_COMP_ID | 0x08, // No Centaur chip found
+ I2C_NO_PROC_FOUND = I2C_COMP_ID | 0x09, // No Processor chip found
+ I2C_ATTRIBUTE_NOT_FOUND = I2C_COMP_ID | 0x0A, // Needed I2C-related Attribute not found
+ I2C_NACK_ONLY_FOUND = I2C_COMP_ID | 0x0B, // Only NACK found in status register
+ I2C_ARBITRATION_LOST_ONLY_FOUND = I2C_COMP_ID | 0x0C, // Bus Arbi lost found in status reg
+ I2C_RUNTIME_INTERFACE_ERR = I2C_COMP_ID | 0x0D, // Read/write unavailable at runtime
+ I2C_RUNTIME_ERR = I2C_COMP_ID | 0x0E, // Failed run-time operation
+ I2C_RUNTIME_INVALID_OFFSET_LENGTH = I2C_COMP_ID | 0x0F, // Offset length of invalid size
+ I2C_INVALID_EEPROM_PAGE_MUTEX = I2C_COMP_ID | 0x10, // Error getting page mutex for i2c engine.
+ I2C_INVALID_EEPROM_PAGE_REQUEST = I2C_COMP_ID | 0x11, // Invalid EEPROM page request
+ I2C_FAILURE_UNLOCKING_EEPROM_PAGE = I2C_COMP_ID | 0x12, // Error while attempting to unlock the eeprom page
+ INVALID_MASTER_TARGET = I2C_COMP_ID | 0x13, // Master I2C target not valid
+ I2C_MUX_TARGET_NOT_FOUND = I2C_COMP_ID | 0x14, // The MUX target is not valid (null)
+ I2C_MUX_TARGET_NON_FUNCTIONAL = I2C_COMP_ID | 0x15, // The MUX target is non functional
+ I2C_INVALID_LENGTH = I2C_COMP_ID | 0x16, // Invalid data buffer length passed to function
+ I2C_NULL_MASTER_TARGET = I2C_COMP_ID | 0x17, // Target Service's toPath() returned nullptr for target
+ I2C_INVALID_SEND_BYTE_LENGTH = I2C_COMP_ID | 0x18, // Invalid send byte length
+ I2C_INVALID_WRITE_BYTE_OR_WORD_LENGTH = I2C_COMP_ID | 0x19, // Invalid write byte/word length
+ I2C_INVALID_BLOCK_WRITE_LENGTH = I2C_COMP_ID | 0x1A, // Invalid block write length
+ I2C_INVALID_READ_BYTE_OR_WORD_LENGTH = I2C_COMP_ID | 0x1B, // Invalid read byte/word length
+ I2C_INVALID_BLOCK_READ_LENGTH = I2C_COMP_ID | 0x1C, // Invalid block read length
};
diff --git a/src/include/usr/initservice/initsvcstructs.H b/src/include/usr/initservice/initsvcstructs.H
index b1d4723e1..1dfd11638 100644
--- a/src/include/usr/initservice/initsvcstructs.H
+++ b/src/include/usr/initservice/initsvcstructs.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2016 */
+/* Contributors Listed Below - COPYRIGHT 2011,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -41,7 +41,7 @@
#include <initservice/initsvcstructs.H>
// This constant has a corresponding entry in src/build/tools/listdeps.pl.
-#define MAX_DEPENDENT_MODULES 10
+#define MAX_DEPENDENT_MODULES 12
namespace INITSERVICE
diff --git a/src/include/usr/isteps/istep21list.H b/src/include/usr/isteps/istep21list.H
index fabfc4be6..d9c3e5515 100644
--- a/src/include/usr/isteps/istep21list.H
+++ b/src/include/usr/isteps/istep21list.H
@@ -135,6 +135,9 @@ const DepModInfo g_istep21Dependancies = {
#ifdef CONFIG_NVDIMM
DEP_LIB(libnvdimm.so),
#endif
+#ifdef CONFIG_UCD_FLASH_UPDATES
+ DEP_LIB(libucd.so),
+#endif
NULL
}
};
diff --git a/src/include/usr/isteps/ucd/updateUcdFlash.H b/src/include/usr/isteps/ucd/updateUcdFlash.H
new file mode 100644
index 000000000..a1487e78d
--- /dev/null
+++ b/src/include/usr/isteps/ucd/updateUcdFlash.H
@@ -0,0 +1,64 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/include/usr/isteps/ucd/updateUcdFlash.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef __UPDATE_UCD_FLASH_H
+#define __UPDATE_UCD_FLASH_H
+
+#include <targeting/common/target.H>
+#include <errl/errlentry.H>
+
+namespace POWER_SEQUENCER
+{
+
+namespace TI // Texas Instruments
+{
+
+namespace UCD // UCD series
+{
+
+/**
+ * @brief Updates a UCD target's flash image
+ *
+ * @param[in] i_pUcd UCD's target; must not be nullptr
+ * @param[in] i_pFlashImage pointer to the start of the data flash
+ * image (its table of contents). Must not be nullptr.
+ *
+ * @return errlHndl_t Error log handle
+ * @retval nullptr Successfully updated the UCD's data flash image
+ * @retval !nullptr Failed to update the UCD's data flash image. Handle
+ * points to valid error log
+ */
+errlHndl_t updateUcdFlash(
+ TARGETING::Target* i_pUcd,
+ const void* i_pFlashImage);
+
+} // End namespace POWER_SEQUENCER
+
+} // End namespace TI
+
+} // End namespace UCD
+
+#endif // __UPDATE_UCD_FLASH_H
+
diff --git a/src/makefile b/src/makefile
index b7f731b89..e7d90f6da 100644
--- a/src/makefile
+++ b/src/makefile
@@ -211,6 +211,7 @@ EXTENDED_MODULES += isteps_nest
EXTENDED_MODULES += isteps_io
EXTENDED_MODULES += node_comm
EXTENDED_MODULES += $(if $(CONFIG_NVDIMM),nvdimm)
+EXTENDED_MODULES += $(if $(CONFIG_UCD_FLASH_UPDATES),ucd)
EXTENDED_MODULES += $(if $(CONFIG_FSP_BUILD),,nvram)
EXTENDED_MODULES += mmio
EXTENDED_MODULES += smf
diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C
index b61dc8b20..6854d58ac 100755
--- a/src/usr/i2c/i2c.C
+++ b/src/usr/i2c/i2c.C
@@ -58,6 +58,7 @@
#include <i2c/eepromif.H>
#include <i2c/tpmddif.H>
#include <hwas/common/hwas.H> // HwasState
+#include <algorithm>
#ifdef CONFIG_NVDIMM
#include <isteps/nvdimm/nvdimmif.H>
@@ -105,6 +106,102 @@ const TARGETING::ATTR_I2C_BUS_SPEED_ARRAY_type g_var = {{NULL}};
namespace I2C
{
+namespace SMBUS
+{
+
+uint8_t calculatePec(
+ const uint8_t* const i_pData,
+ const size_t i_size)
+{
+ uint8_t pec = 0;
+
+ for (size_t index=0; index<i_size; ++index)
+ {
+ pec ^= i_pData[index];
+ pec = pec ^ (pec<<1) ^ (pec<<2) ^ ((pec&128)?9:0) ^ ((pec&64)?7:0);
+ }
+
+ return pec;
+}
+
+BlockWrite::BlockWrite(
+ const uint8_t i_address,
+ const uint8_t i_commandCode,
+ const uint8_t i_byteCount,
+ const void* const i_pDataBytes,
+ const bool i_usePec)
+
+ : writeAddr(i_address),
+ commandCode(i_commandCode),
+ byteCount(i_byteCount)
+{
+ memcpy(dataBytes,i_pDataBytes,i_byteCount);
+ memset(dataBytes+i_byteCount,0x00,sizeof(dataBytes)-i_byteCount);
+ messageSize = offsetof(I2C::SMBUS::BlockWrite,dataBytes)
+ + byteCount - sizeof(writeAddr);
+ if(i_usePec)
+ {
+ ++messageSize;
+ const auto pec = I2C::SMBUS::calculatePec(
+ reinterpret_cast<uint8_t*>(&writeAddr),
+ messageSize);
+ *(reinterpret_cast<uint8_t*>(&writeAddr)+messageSize)=pec;
+ }
+}
+
+WriteByteOrWord::WriteByteOrWord(
+ const uint8_t i_address,
+ const uint8_t i_commandCode,
+ const uint8_t i_byteCount,
+ const void* const i_pDataBytes,
+ const bool i_usePec)
+ : writeAddr(i_address),
+ commandCode(i_commandCode),
+ byteCount(i_byteCount)
+{
+ assert(((byteCount==1) || (byteCount==2)),
+ "Invalid byte count %d for write byte or write word",
+ byteCount);
+ memcpy(dataBytes,i_pDataBytes,byteCount);
+ memset(dataBytes+byteCount,0x00,sizeof(dataBytes)-byteCount);
+ messageSize = offsetof(I2C::SMBUS::WriteByteOrWord,dataBytes)
+ - offsetof(I2C::SMBUS::WriteByteOrWord,commandCode)
+ + byteCount;
+ if(i_usePec)
+ {
+ // Currently message size does not reflect the address. If we
+ // are adding a PEC byte, that will up the amount of data we need
+ // to transmit. Leverage the preincrement to calculate the PEC over
+ // the right number of bytes.
+ const auto pec = I2C::SMBUS::calculatePec(
+ reinterpret_cast<uint8_t*>(&writeAddr),
+ ++messageSize);
+ *(dataBytes+byteCount)=pec;
+ }
+}
+
+SendByte::SendByte(const uint8_t i_address,
+ const void* const i_pDataByte,
+ const bool i_usePec)
+ : writeAddr(i_address),
+ dataByte(*reinterpret_cast<const uint8_t*>(i_pDataByte))
+{
+ messageSize = offsetof(I2C::SMBUS::SendByte,pec)
+ - offsetof(I2C::SMBUS::SendByte,dataByte);
+ if(i_usePec)
+ {
+ // Currently message size does not reflect the address. If we
+ // are adding a PEC byte, that will up the amount of data we need
+ // to transmit. Leverage the preincrement to calculate the PEC over
+ // the right number of bytes.
+ pec = I2C::SMBUS::calculatePec(
+ reinterpret_cast<uint8_t*>(&writeAddr),
+ ++messageSize);
+ }
+}
+
+} // End SMBUS namespace
+
// Register the generic I2C perform Op with the routing code for Procs.
DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
DeviceFW::I2C,
@@ -159,17 +256,20 @@ void dumpMiscArgsData(const I2C::misc_args_t & i_args)
l_muxPath = i_args.i2cMuxPath->toString();
}
- TRACFCOMP( g_trac_i2c,"dumpMiscArgsData: "
- "port(%d), engine(%d), devAddr(0x%X), skip_mode_step(%d), "
- "with_stop(%d), read_not_write(%d), bus_speed(%d)",
- i_args.port, i_args.engine, i_args.devAddr,
+ TRACFCOMP( g_trac_i2c,"dumpMiscArgsData: subop(0x%016llX), "
+ "engine(%d), port(%d), devAddr(0x%X), skip_mode_step(%d), "
+ "with_stop(%d), read_not_write(%d), with_address(%d), "
+ "with_start(%d)",
+ i_args.subop,i_args.engine, i_args.port, i_args.devAddr,
i_args.skip_mode_setup, i_args.with_stop,
- i_args.read_not_write, i_args.bus_speed );
+ i_args.read_not_write, i_args.with_address,
+ i_args.with_start);
- TRACFCOMP( g_trac_i2c,"dumpMiscArgsData cont.: "
- "bit_rate_divisor(%d), polling_interval_ns(%d), "
+ TRACFCOMP( g_trac_i2c,"dumpMiscArgsData cont.: read_continue(%d), "
+ "bus_speed(%d), bit_rate_divisor(%d), polling_interval_ns(%d), "
"timeout_count(%d), offset_length(%d), offset_buffer(%p/0x%X)",
- i_args.bit_rate_divisor, i_args.polling_interval_ns,
+ i_args.read_continue,i_args.bus_speed,i_args.bit_rate_divisor,
+ i_args.polling_interval_ns,
i_args.timeout_count, i_args.offset_length,
i_args.offset_buffer,
(0x0 == i_args.offset_buffer ? 0 : *(i_args.offset_buffer) ) );
@@ -208,6 +308,11 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
// Address, Port, Engine, Device Addr.
// Other args set below
misc_args_t args;
+
+ // Read in the sub-operation
+ const auto subop =
+ static_cast<DeviceFW::I2C_SUBOP>(va_arg(i_args,uint64_t));
+
args.port = va_arg( i_args, uint64_t );
args.engine = va_arg( i_args, uint64_t );
args.devAddr = va_arg( i_args, uint64_t );
@@ -287,17 +392,42 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
// Else this is not a page operation, call the normal common function
else
{
- args.offset_length = va_arg( i_args, uint64_t);
- uint8_t* temp = reinterpret_cast<uint8_t*>(va_arg(i_args, uint64_t));
- args.i2cMuxBusSelector = va_arg( i_args, uint64_t);
- args.i2cMuxPath = reinterpret_cast<const TARGETING::EntityPath*>(va_arg(i_args, uint64_t));
-
- if ( args.offset_length != 0 )
+ if( (subop==DeviceFW::I2C_SMBUS_BLOCK)
+ || (subop==DeviceFW::I2C_SMBUS_BYTE)
+ || (subop==DeviceFW::I2C_SMBUS_WORD))
+ {
+ args.smbus.commandCode =
+ static_cast<decltype(args.smbus.commandCode)>(
+ va_arg(i_args,uint64_t));
+ args.smbus.usePec = true; // All implementations use PEC
+ args.i2cMuxBusSelector = va_arg(i_args,uint64_t);
+ args.i2cMuxPath = reinterpret_cast<const TARGETING::EntityPath*>(
+ va_arg(i_args, uint64_t));
+ }
+ else if(subop==DeviceFW::I2C_SMBUS_SEND_OR_RECV)
+ {
+ args.smbus.usePec = true; // All implementations use PEC
+ args.i2cMuxBusSelector = va_arg(i_args,uint64_t);
+ args.i2cMuxPath = reinterpret_cast<const TARGETING::EntityPath*>(
+ va_arg(i_args, uint64_t));
+ }
+ else // Standard ops
{
- args.offset_buffer = temp;
+ args.offset_length = va_arg( i_args, uint64_t);
+ uint8_t* temp = reinterpret_cast<uint8_t*>(
+ va_arg(i_args, uint64_t));
+ args.i2cMuxBusSelector = va_arg( i_args, uint64_t);
+ args.i2cMuxPath = reinterpret_cast<const TARGETING::EntityPath*>(
+ va_arg(i_args, uint64_t));
+ if ( args.offset_length != 0 )
+ {
+ args.offset_buffer = temp;
+ }
}
+ args.subop=subop;
+
err = i2cCommonOp( i_opType,
i_target,
io_buffer,
@@ -1240,9 +1370,594 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
/*******************************************************/
/***********************************************/
+ /* I2C SMBUS Send Byte */
+ /***********************************************/
+ if( (i_opType == DeviceFW::WRITE )
+ && (i_args.subop == DeviceFW::I2C_SMBUS_SEND_OR_RECV))
+ {
+ TRACUCOMP(g_trac_i2c, INFO_MRK
+ "I2C SMBUS Send Byte, "
+ "Use PEC = %d.",
+ i_args.smbus.usePec);
+
+ // If requested length is anything other than 1 byte, throw an
+ // error.
+ if(io_buflen != sizeof(uint8_t))
+ {
+ /*@
+ * @errortype
+ * @reasoncode I2C_INVALID_SEND_BYTE_LENGTH
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid I2C_PERFORM_OP
+ * @userdata1 Size of request
+ * @devdesc Invalid input buffer length for send byte request
+ * @custdesc Unexpected firmware error
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_PERFORM_OP,
+ I2C_INVALID_SEND_BYTE_LENGTH,
+ io_buflen,
+ 0,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ err->collectTrace(I2C_COMP_NAME);
+
+ io_buflen = 0;
+
+ break;
+ }
+
+ // Write SMBUS Send Byte command to device.
+ i_args.read_not_write = false;
+ i_args.with_stop = true;
+ i_args.skip_mode_setup = false;
+ i_args.with_address = true;
+ i_args.with_start = true;
+
+ I2C::SMBUS::SendByte sendByte(i_args.devAddr,
+ io_buffer,
+ i_args.smbus.usePec);
+ do {
+
+ size_t writeSize = sendByte.messageSize;
+ const auto writeSizeExp = writeSize;
+ err = i2cWrite(i_target,
+ &sendByte.dataByte,
+ writeSize,
+ i_args);
+ if(err)
+ {
+ break;
+ }
+
+ assert(writeSize == writeSizeExp,
+ "Write size mismatch; expected %d but got %d",
+ writeSizeExp,writeSize);
+
+ io_buflen = sizeof(sendByte.dataByte);
+
+ } while(0);
+
+ if(err)
+ {
+ io_buflen = 0;
+ }
+ }
+ /***********************************************/
+ /* I2C SMBUS Write Byte / Write Word */
+ /***********************************************/
+ else if( (i_opType == DeviceFW::WRITE )
+ && ( (i_args.subop == DeviceFW::I2C_SMBUS_BYTE)
+ || (i_args.subop == DeviceFW::I2C_SMBUS_WORD)))
+ {
+ // Note: The SMBUS spec calls a 2 byte value a "word"
+
+ TRACUCOMP(g_trac_i2c, INFO_MRK
+ "I2C SMBUS Write %s: Command code = 0x%02X, "
+ "Use PEC = %d.",
+ i_args.subop == DeviceFW::I2C_SMBUS_BYTE ?
+ "Byte" : "Word",
+ i_args.smbus.commandCode,
+ i_args.smbus.usePec);
+
+ // If requested length is != 1 byte for a write byte transaction,
+ // or != 2 bytes for a write word transaction, throw an error.
+ if( ( (i_args.subop == DeviceFW::I2C_SMBUS_BYTE)
+ && (io_buflen != sizeof(uint8_t)))
+ || ( (i_args.subop == DeviceFW::I2C_SMBUS_WORD)
+ && (io_buflen != sizeof(uint16_t))))
+ {
+ /*@
+ * @errortype
+ * @reasoncode I2C_INVALID_WRITE_BYTE_OR_WORD_LENGTH
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid I2C_PERFORM_OP
+ * @userdata1 Size of request
+ * @userdata2 Sub-op
+ * @devdesc Invalid input buffer length for write byte or
+ * write word request
+ * @custdesc Unexpected firmware error
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_PERFORM_OP,
+ I2C_INVALID_WRITE_BYTE_OR_WORD_LENGTH,
+ io_buflen,
+ i_args.subop,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ err->collectTrace(I2C_COMP_NAME);
+
+ io_buflen = 0;
+
+ break;
+ }
+
+ // Write SMBUS Write Byte or Write Word command to device.
+ i_args.read_not_write = false;
+ i_args.with_stop = true;
+ i_args.skip_mode_setup = false;
+ i_args.with_address = true;
+ i_args.with_start = true;
+
+ uint8_t bytes = (i_args.subop == DeviceFW::I2C_SMBUS_BYTE) ?
+ sizeof(uint8_t) : sizeof(uint16_t);
+ I2C::SMBUS::WriteByteOrWord writeByteOrWord(i_args.devAddr,
+ i_args.smbus.commandCode,
+ bytes,
+ io_buffer,
+ i_args.smbus.usePec);
+ do {
+
+ size_t writeSize = writeByteOrWord.messageSize;
+ const auto writeSizeExp = writeSize;
+ err = i2cWrite(i_target,
+ &writeByteOrWord.commandCode,
+ writeSize,
+ i_args);
+ if(err)
+ {
+ break;
+ }
+
+ assert(writeSize == writeSizeExp,
+ "Write size mismatch; expected %d but got %d",
+ writeSizeExp,writeSize);
+
+ io_buflen = writeByteOrWord.byteCount;
+
+ } while(0);
+
+ if(err)
+ {
+ io_buflen = 0;
+ }
+ }
+ /***********************************************/
+ /* I2C SMBUS Block Write */
+ /***********************************************/
+ else if( (i_opType == DeviceFW::WRITE )
+ && (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK))
+ {
+ TRACUCOMP(g_trac_i2c, INFO_MRK
+ "I2C SMBUS Block Write: Command code = 0x%02X, "
+ "Use PEC = %d.",
+ i_args.smbus.commandCode,
+ i_args.smbus.usePec);
+
+ // If requested length is for < 1 byte or > 255 bytes for a block
+ // write transaction, throw an error.
+ if( (!io_buflen)
+ || (io_buflen > UINT8_MAX) )
+ {
+ /*@
+ * @errortype
+ * @reasoncode I2C_INVALID_BLOCK_WRITE_LENGTH
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid I2C_PERFORM_OP
+ * @userdata1 Size of request
+ * @devdesc Invalid input buffer length for block write
+ * request
+ * @custdesc Unexpected firmware error
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_PERFORM_OP,
+ I2C_INVALID_BLOCK_WRITE_LENGTH,
+ io_buflen,
+ 0,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT );
+
+ err->collectTrace(I2C_COMP_NAME);
+
+ io_buflen = 0;
+
+ break;
+ }
+
+ // Write SMBUS block write command to device.
+ i_args.read_not_write = false;
+ i_args.with_stop = true;
+ i_args.skip_mode_setup = false;
+ i_args.with_address = true;
+ i_args.with_start = true;
+
+ I2C::SMBUS::BlockWrite blockWrite(i_args.devAddr,
+ i_args.smbus.commandCode,
+ io_buflen,
+ io_buffer,
+ i_args.smbus.usePec);
+ do {
+
+ size_t writeSize = blockWrite.messageSize;
+ const auto writeSizeExp = writeSize;
+ err = i2cWrite(i_target,
+ &blockWrite.commandCode,
+ writeSize,
+ i_args);
+ if(err)
+ {
+ break;
+ }
+
+ assert(writeSize == writeSizeExp,
+ "Write size mismatch; expected %d but got %d",
+ writeSizeExp,writeSize);
+
+ io_buflen = blockWrite.byteCount;
+
+ } while(0);
+
+ if(err)
+ {
+ io_buflen = 0;
+ }
+ }
+ /***********************************************/
+ /* I2C SMBUS Read Word or Byte */
+ /***********************************************/
+ else if( (i_opType == DeviceFW::READ )
+ && ( (i_args.subop == DeviceFW::I2C_SMBUS_BYTE)
+ || (i_args.subop == DeviceFW::I2C_SMBUS_WORD)))
+ {
+ // Note: The SMBUS spec calls a 2 byte value a "word"
+
+ TRACUCOMP(g_trac_i2c, INFO_MRK
+ "I2C SMBUS Read %s: Command code = 0x%02X, "
+ "Use PEC = %d",
+ i_args.subop == DeviceFW::I2C_SMBUS_BYTE ?
+ "Byte" : "Word",
+ i_args.smbus.commandCode,
+ i_args.smbus.usePec);
+
+ // If requested length is != 1 byte for a read byte transaction,
+ // or != 2 bytes for a read word transaction, throw an error.
+ if( ( (i_args.subop == DeviceFW::I2C_SMBUS_BYTE)
+ && (io_buflen != sizeof(uint8_t)))
+ || ( (i_args.subop == DeviceFW::I2C_SMBUS_WORD)
+ && (io_buflen != sizeof(uint16_t))))
+ {
+ /*@
+ * @errortype
+ * @reasoncode I2C_INVALID_READ_BYTE_OR_WORD_LENGTH
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid I2C_PERFORM_OP
+ * @userdata1 Size of request
+ * @userdata2 Sub-op
+ * @devdesc Invalid input buffer length for read byte or
+ * read word request
+ * @custdesc Unexpected firmware error
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_PERFORM_OP,
+ I2C_INVALID_READ_BYTE_OR_WORD_LENGTH,
+ io_buflen,
+ i_args.subop,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ err->collectTrace(I2C_COMP_NAME);
+
+ io_buflen = 0;
+
+ break;
+ }
+
+ // Write SMBUS Read Byte|Word command to device. Inhibit stop
+ // because the protocol requires a chained read operation without
+ // a stop in between.
+ i_args.read_not_write = false;
+ i_args.with_stop = false;
+ i_args.skip_mode_setup = false;
+ i_args.with_address = true;
+ i_args.with_start = true;
+
+ uint8_t bytes = ( i_args.subop
+ == DeviceFW::I2C_SMBUS_BYTE) ?
+ sizeof(uint8_t) : sizeof(uint16_t);
+
+ I2C::SMBUS::ReadByteOrWord readByteOrWord(i_args.devAddr,
+ i_args.smbus.commandCode,
+ bytes);
+ do {
+
+ size_t commandCodeSize = sizeof(readByteOrWord.commandCode);
+ const auto commandCodeSizeExp = commandCodeSize;
+ err = i2cWrite(i_target,
+ &readByteOrWord.commandCode,
+ commandCodeSize,
+ i_args);
+ if(err)
+ {
+ break;
+ }
+
+ assert(commandCodeSize == commandCodeSizeExp,
+ "Command code write size mismatch; expected %d but got %d",
+ commandCodeSizeExp,commandCodeSize);
+
+ // Now read the required number of data bytes (1 or 2).
+ // If there is no PEC byte, complete the transaction with a stop
+ // and inform the engine there is no subsequent read. If the PEC
+ // byte is supported, withhold the stop and inform the engine there
+ // is an additional read transaction coming. Since this is a
+ // continuation of the original operation but as a read, repeat the
+ // start bit and address.
+ i_args.read_not_write = true;
+ i_args.skip_mode_setup = true;
+ i_args.with_stop = i_args.smbus.usePec ? false : true;
+ i_args.read_continue = i_args.smbus.usePec ? true : false;
+
+ size_t dataBytesSize = readByteOrWord.byteCount;
+ const auto dataBytesSizeExp = dataBytesSize;
+ err = i2cRead(i_target,
+ readByteOrWord.dataBytes,
+ dataBytesSize,
+ i_args);
+ if(err)
+ {
+ break;
+ }
+
+ assert(dataBytesSize == dataBytesSizeExp,
+ "Data bytes read size mismatch; expected %d but got %d",
+ dataBytesSizeExp,dataBytesSize);
+
+ if(i_args.smbus.usePec)
+ {
+ // Read the PEC byte with stop at the end and inform engine
+ // the chained reads are complete
+ i_args.with_stop = true;
+ i_args.read_continue = false;
+ i_args.with_address = false;
+ i_args.with_start = false;
+
+ size_t pecSize=sizeof(readByteOrWord.pec);
+ const auto pecSizeExp=pecSize;
+ err = i2cRead(i_target,
+ &readByteOrWord.pec,
+ pecSize,
+ i_args);
+ if(err)
+ {
+ break;
+ }
+
+ assert(pecSize == pecSizeExp,
+ "PEC byte read size mismatch; expected %d but got %d",
+ pecSizeExp,pecSize);
+
+ const size_t pecBytes =
+ offsetof(I2C::SMBUS::ReadByteOrWord,dataBytes)
+ + readByteOrWord.byteCount;
+ const auto expectedPec = I2C::SMBUS::calculatePec(
+ reinterpret_cast<uint8_t*>(&readByteOrWord),pecBytes);
+ if(readByteOrWord.pec != expectedPec)
+ {
+ TRACFCOMP(g_trac_i2c, ERR_MRK
+ "Bad PEC byte detected; expected 0x%02X "
+ "but received 0x%02X. # PEC bytes = %d",
+ expectedPec,readByteOrWord.pec,pecBytes);
+
+ // @TODO RTC 201990 support bad PEC handling
+ // Right now just ignore it
+ }
+ }
+
+ // Copy the amount of data returned by the remote device, or
+ // the user requested amount, whichever is smaller
+ io_buflen = readByteOrWord.byteCount;
+ memcpy(io_buffer,readByteOrWord.dataBytes,io_buflen);
+
+ } while(0);
+
+ if(err)
+ {
+ io_buflen = 0;
+ }
+ }
+ /***********************************************/
+ /* I2C SMBUS Block Read */
+ /***********************************************/
+ else if( (i_opType == DeviceFW::READ )
+ && (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK))
+ {
+ TRACUCOMP(g_trac_i2c, INFO_MRK
+ "I2C SMBUS Block Read: Command code = 0x%02X, "
+ "Use PEC = %d.",
+ i_args.smbus.commandCode,
+ i_args.smbus.usePec);
+
+ // If requested length is < 1 byte or > 255 bytes for a block
+ // read transaction, throw an error.
+ if( (!io_buflen)
+ || (io_buflen > UINT8_MAX) )
+ {
+ /*@
+ * @errortype
+ * @reasoncode I2C_INVALID_BLOCK_READ_LENGTH
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid I2C_PERFORM_OP
+ * @userdata1 Size of request
+ * @devdesc Invalid input buffer length for block read
+ * request
+ * @custdesc Unexpected firmware error
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_PERFORM_OP,
+ I2C_INVALID_BLOCK_READ_LENGTH,
+ io_buflen,
+ 0,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT );
+
+ err->collectTrace(I2C_COMP_NAME);
+
+ io_buflen = 0;
+
+ break;
+ }
+
+ // Write SMBUS block read command to device. Inhibit stop
+ // because the protocol requires a chained read operation without
+ // a stop in between.
+ i_args.read_not_write = false;
+ i_args.with_stop = false;
+ i_args.skip_mode_setup = false;
+ i_args.with_address = true;
+ i_args.with_start = true;
+
+ I2C::SMBUS::BlockRead blockRead(i_args.devAddr,
+ i_args.smbus.commandCode);
+
+ do {
+
+ size_t commandCodeSize = sizeof(i_args.smbus.commandCode);
+ const auto commandCodeSizeExp = commandCodeSize;
+ err = i2cWrite(i_target,
+ &i_args.smbus.commandCode,
+ commandCodeSize,
+ i_args);
+ if(err)
+ {
+ break;
+ }
+
+ assert(commandCodeSize == commandCodeSizeExp,
+ "Command code write size mismatch; expected %d but got %d",
+ commandCodeSizeExp,commandCodeSize);
+
+ // Read the block count byte, which indicates how many
+ // bytes (up to 255) the remote device will return as part of the
+ // logical response. Does -not- include PEC byte.
+ // Since it's a continuation of an existing command, send a repeated
+ // start and address, but again do not send the stop because
+ // the read must continue later. Also set read-continue in the
+ // engine so that we can break the full set of reads into multiple
+ // transactions and don't setup the engine again.
+ i_args.read_not_write = true;
+ i_args.read_continue = true;
+ i_args.skip_mode_setup = true;
+
+ size_t blockCountSize = sizeof(blockRead.blockCount);
+ const auto blockCountSizeExp = blockCountSize;
+ err = i2cRead(i_target,
+ &blockRead.blockCount,
+ blockCountSize,
+ i_args);
+ if(err)
+ {
+ break;
+ }
+
+ assert(blockCountSize == blockCountSizeExp,
+ "Block count read size mismatch; expected %d but got %d",
+ blockCountSizeExp,blockCountSize);
+
+ // Now read the specified number of data bytes.
+ // If there is no PEC byte, complete the transaction with a stop
+ // and inform the engine there is no subsequent read. If the PEC
+ // byte is supported, withhold the stop inform the engine there is
+ // an additional read transaction coming. Since this is a
+ // continuation of the read, withhold the start bit and the address.
+ // nor is an address.
+ i_args.with_start = false;
+ i_args.with_address = false;
+ i_args.with_stop = i_args.smbus.usePec ? false : true;
+ i_args.read_continue = i_args.smbus.usePec ? true : false;
+
+ size_t dataBytesSize = blockRead.blockCount;
+ const auto dataBytesSizeExp = dataBytesSize;
+ err = i2cRead(i_target,
+ blockRead.dataBytes,
+ dataBytesSize,
+ i_args);
+ if(err)
+ {
+ break;
+ }
+
+ assert(dataBytesSize == dataBytesSizeExp,
+ "Data bytes read size mismatch; expected %d but got %d",
+ dataBytesSizeExp,dataBytesSize);
+
+ if(i_args.smbus.usePec)
+ {
+ // Read the PEC byte with stop at the end and inform engine
+ // the chained reads are complete
+ i_args.with_stop = true;
+ i_args.read_continue = false;
+
+ size_t pecSize=sizeof(blockRead.pec);
+ const auto pecSizeExp=pecSize;
+ err = i2cRead(i_target,
+ &blockRead.pec,
+ pecSize,
+ i_args);
+ if(err)
+ {
+ break;
+ }
+
+ assert(pecSize == pecSizeExp,
+ "PEC byte read size mismatch; expected %d but got %d",
+ pecSizeExp,pecSize);
+
+ const size_t pecBytes =
+ offsetof(I2C::SMBUS::BlockRead,dataBytes)
+ + blockRead.blockCount;
+ const auto expectedPec = I2C::SMBUS::calculatePec(
+ reinterpret_cast<uint8_t*>(&blockRead),pecBytes);
+ if(blockRead.pec != expectedPec)
+ {
+ TRACFCOMP(g_trac_i2c, ERR_MRK
+ "Bad PEC byte detected; expected 0x%02X "
+ "but received 0x%02X. # PEC bytes = %d",
+ expectedPec,blockRead.pec,pecBytes);
+
+ // @TODO RTC 201990 support bad PEC handling
+ // Right now just ignore it
+ }
+ }
+
+ // Copy the amount of data returned by the remote device, or
+ // the user requested amount, whichever is smaller
+ io_buflen = std::min(io_buflen,
+ static_cast<size_t>(blockRead.blockCount));
+ memcpy(io_buffer,blockRead.dataBytes,io_buflen);
+
+ } while(0);
+
+ if(err)
+ {
+ io_buflen = 0;
+ }
+ }
+ /***********************************************/
/* I2C Read with Offset */
/***********************************************/
- if( i_opType == DeviceFW::READ &&
+ else if( i_opType == DeviceFW::READ &&
i_args.offset_length != 0 )
{
// First WRITE offset to device without a stop
@@ -2027,9 +2742,11 @@ errlHndl_t i2cSetup ( TARGETING::Target * i_target,
errlHndl_t err = NULL;
TRACUCOMP( g_trac_i2c,
- ENTER_MRK"i2cSetup(): buf_len=%d, r_nw=%d, w_stop=%d, sms=%d",
- i_buflen, i_args.read_not_write, i_args.with_stop,
- i_args.skip_mode_setup);
+ ENTER_MRK"i2cSetup(): buf_len=%d, r_nw=%d, w_start=%d, "
+ "w_address=%d, w_stop=%d, read_continue=%d, sms=%d",
+ i_buflen, i_args.read_not_write, i_args.with_start,
+ i_args.with_address, i_args.with_stop,
+ i_args.read_continue,i_args.skip_mode_setup);
// Define the registers that we'll use
mode_reg_t mode;
@@ -2104,13 +2821,16 @@ errlHndl_t i2cSetup ( TARGETING::Target * i_target,
// Write Command Register:
// - with start
+ // - with continue
// - with stop
+ // - with address
// - RnW
// - length
cmd.value = 0x0ull;
- cmd.with_start = 1;
+ cmd.with_start = (i_args.with_start ? 1 : 0);
+ cmd.read_continue = (i_args.read_continue ? 1 : 0);
cmd.with_stop = (i_args.with_stop ? 1 : 0);
- cmd.with_addr = 1;
+ cmd.with_addr = (i_args.with_address ? 1 : 0);
// cmd.device_addr is 7 bits
// devAddr though is a uint64_t
diff --git a/src/usr/i2c/i2c.H b/src/usr/i2c/i2c.H
index baf95df32..5b69b302e 100755
--- a/src/usr/i2c/i2c.H
+++ b/src/usr/i2c/i2c.H
@@ -63,6 +63,15 @@ enum
PAGE_ONE_ADDR = 0x6E,
};
+/**
+ * @brief Value of the rightmost (7th) bit of an I2C address, which on the
+ * wire indicates whether the operation is a read or a write
+ */
+enum I2C_OP_DIRECTION : uint8_t
+{
+ WRITE = 0x00, ///< Write operation
+ READ = 0x01, ///< Read operation
+};
/**
* @brief FIFO size (width) in bytes. This dictates how many bytes
@@ -959,6 +968,259 @@ void setLogicalFsiEnginePort(size_t &io_logical_engine,
void addHwCalloutsI2c(errlHndl_t i_err,
TARGETING::Target * i_target,
const misc_args_t & i_args);
+
+namespace SMBUS
+{
+
+/**
+ * @brief Calculates a packet error code (PEC) over the specified number of
+ * bytes at the specified address.
+ *
+ * @par Detailed Description:
+ * Calculates a packet error code (PEC) over the specified number of bytes
+ * at the specified address. Specifically, it applies a CRC-8 algorithm, a
+ * very common/simple CRC detailed @
+ * https://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks
+ *
+ * @param[in] i_pData Pointer to the start of the data; must not be nullptr
+ * @param[in] i_size Number of bytes to consider when computing the PEC
+ *
+ * return uint8_t Computed PEC byte
+ */
+uint8_t calculatePec(
+ const uint8_t* const i_pData,
+ const size_t i_size);
+
+/**
+ * @brief Structure which tracks the Send Byte
+ * transaction to assist in calculating the PEC byte at the end (if
+ * applicable)
+ */
+struct SendByte
+{
+ // The following fields are known prior to the transaction:
+
+ // The remote device's address which starts the transaction;
+ // RW bit will be 0
+ uint8_t writeAddr;
+
+ // Data byte to send
+ uint8_t dataByte;
+
+ // PEC byte
+ uint8_t pec;
+
+ // Size of message to send, excluding address byte, including PEC byte if
+ // applicable
+ size_t messageSize;
+
+ /**
+ * @brief Constructor
+ *
+ * @param[in] i_address Address of the remote device
+ * @param[in] i_pDataByte Pointer to byte to send. Must not be nullptr.
+ * @param[in] i_usePec Whether to suffix transaction with PEC byte or not
+ */
+ SendByte( uint8_t i_address,
+ const void* i_pDataByte,
+ bool i_usePec);
+} PACKED;
+
+/**
+ * @brief Structure which tracks the Write Byte or Write Word
+ * transaction to assist in calculating the PEC byte at the end (if
+ * applicable)
+ */
+struct WriteByteOrWord
+{
+ // The following fields are known prior to the transaction:
+
+ // The remote device's address which starts the transaction;
+ // RW bit will be 0
+ uint8_t writeAddr;
+
+ // The PMBUS command code to send as part of the write
+ uint8_t commandCode;
+
+ // Data bytes the originator intends to send.
+ // 1 for Write byte
+ // 2 for Write word
+ // One more byte is added in case there is a PEC byte.
+ uint8_t dataBytes[sizeof(uint16_t)+sizeof(uint8_t)];
+
+ // How many data bytes (excluding PEC) the originator intends to send
+ uint8_t byteCount;
+
+ // Size of message to send, excluding address byte, including PEC byte if
+ // applicable
+ size_t messageSize;
+
+ /**
+ * @brief Constructor
+ *
+ * @param[in] i_address Address of the remote device
+ * @param[in] i_commandCode PMBUS command code to execute
+ * @param[in] i_byteCount Number of data bytes to send (1 or 2)
+ * @param[in] i_pDataBytes Pointer to byte stream to send. Must not be
+ * nullptr
+ * @param[in] i_usePec Whether to suffix transaction with PEC byte or not
+ */
+ WriteByteOrWord( uint8_t i_address,
+ uint8_t i_commandCode,
+ uint8_t i_byteCount,
+ const void* i_pDataBytes,
+ bool i_usePec);
+} PACKED;
+
+/**
+ * @brief Structure which tracks the block write transaction to assist in
+ * calculating the PEC byte at the end
+ */
+struct BlockWrite
+{
+ // The following fields are known prior to the transaction:
+
+ // The remote device's address which starts the transaction;
+ // RW bit will be 0
+ uint8_t writeAddr;
+
+ // The PMBUS command code to send as part of the write
+ uint8_t commandCode;
+
+ // How many data bytes (excluding PEC) the originator intends to send
+ uint8_t byteCount;
+
+ // Data bytes the originator intends to send. Max 255. One more byte is
+ // added in case there is a PEC byte
+ uint8_t dataBytes[UINT8_MAX+sizeof(uint8_t)];
+
+ // Size of message to send, excluding address byte, including PEC byte if
+ // applicable
+ size_t messageSize;
+
+ /**
+ * @brief Constructor
+ *
+ * @param[in] i_address Address of the remote device
+ * @param[in] i_commandCode PMBUS command code to execute
+ * @param[in] i_byteCount Number of data bytes to send
+ * @param[in] i_pDataBytes Pointer to byte stream to send. Must not be
+ * nullptr
+ * @param[in] i_usePec Whether to suffix transaction with PEC byte or not
+ */
+ BlockWrite( uint8_t i_address,
+ uint8_t i_commandCode,
+ uint8_t i_byteCount,
+ const void* i_pDataBytes,
+ bool i_usePec);
+
+} PACKED;
+
+/**
+ * @brief Structure which tracks the read byte|word transaction to assist in
+ * calculating the PEC byte at the end
+ */
+struct ReadByteOrWord
+{
+ // The following fields are known prior to the transaction:
+
+ // The remote device's address which starts the transaction;
+ // RW bit will be 0
+ uint8_t writeAddr;
+
+ // The PMBUS command code to send as part of the write
+ uint8_t commandCode;
+
+ // The remote device's address (sent after repeated start);
+ // RW bit will be 1
+ uint8_t readAddr;
+
+ // The following fields are filled in during the transaction:
+
+ // Data bytes (1 if read byte, 2 if read word) returned by the remote device
+ uint8_t dataBytes[sizeof(uint16_t)];
+
+ // PEC byte returned by the remote device (if supported)
+ uint8_t pec;
+
+ // # data byte requested (1 or 2)
+ uint8_t byteCount;
+
+ /**
+ * @brief Constructor
+ *
+ * @param[in] i_address Address of the remote device
+ * @param[in] i_commandCode PMBUS command code to execute
+ * @param[in] i_byteCount Number of bytes to read (1 or 2)
+ */
+ ReadByteOrWord(uint8_t i_address,
+ uint8_t i_commandCode,
+ uint8_t i_byteCount)
+ : writeAddr(i_address),
+ commandCode(i_commandCode),
+ readAddr(i_address | I2C_OP_DIRECTION::READ),
+ pec(0),
+ byteCount(i_byteCount)
+ {
+ assert(((byteCount==1) || (byteCount==2)),
+ "Invalid byte count %d for read byte or read word", byteCount);
+ memset(dataBytes,0x00,sizeof(dataBytes));
+ }
+
+} PACKED;
+
+/**
+ * @brief Structure which tracks the block read transaction to assist in
+ * calculating the PEC byte at the end
+ */
+struct BlockRead
+{
+ // The following fields are known prior to the transaction:
+
+ // The remote device's address which starts the transaction;
+ // RW bit will be 0
+ uint8_t writeAddr;
+
+ // The PMBUS command code to send as part of the write
+ uint8_t commandCode;
+
+ // The remote device's address (sent after repeated start);
+ // RW bit will be 1
+ uint8_t readAddr;
+
+ // The following fields are filled in during the transaction:
+
+ // How many data bytes (excluding PEC) the remote device intends
+ // to return.
+ uint8_t blockCount;
+
+ // Data bytes (blockCount of them) returned by the remote device
+ uint8_t dataBytes[UINT8_MAX];
+
+ // PEC byte returned by the remote device (if supported)
+ uint8_t pec;
+
+ /**
+ * @brief Constructor
+ *
+ * @param[in] i_address Address of the remote device
+ * @param[in] i_commandCode PMBUS command code to execute
+ */
+ BlockRead(const uint8_t i_address,
+ const uint8_t i_commandCode)
+ : writeAddr(i_address),
+ commandCode(i_commandCode),
+ readAddr(i_address | I2C_OP_DIRECTION::READ),
+ blockCount(0),
+ pec(0)
+ {
+ memset(dataBytes,0x00,sizeof(dataBytes));
+ }
+
+} PACKED;
+
+} // End SMBUS namespace
+
}; // end I2C namespace
#endif // __I2C_H
diff --git a/src/usr/i2c/i2c_common.H b/src/usr/i2c/i2c_common.H
index 61c5472c9..689d4fc8d 100644
--- a/src/usr/i2c/i2c_common.H
+++ b/src/usr/i2c/i2c_common.H
@@ -25,7 +25,7 @@
#ifndef __I2C_COMMON_H
#define __I2C_COMMON_H
-
+#include <devicefw/driverif.H>
/**
* @file i2c_common.H
*
@@ -40,20 +40,32 @@
namespace I2C
{
+struct Smbus_t
+{
+ uint8_t commandCode; // Command for read/write block operations
+ bool usePec; // Whether to use PEC byte or not
+};
+
/**
* @brief Structure used to pass important variables between functions
*/
struct misc_args_t
{
+ DeviceFW::I2C_SUBOP subop; ///< Sub-operation to perform
uint8_t port;
uint8_t engine;
uint64_t devAddr;
bool skip_mode_setup;
bool with_stop;
bool read_not_write;
- uint64_t bus_speed; // in kbits/sec (ie 400KHz)
- uint16_t bit_rate_divisor; // uint16_t to match size in mode register
- uint64_t polling_interval_ns; // in nanoseconds
+ bool with_address; ///< Send address
+ bool with_start; ///< Send start bit
+ bool read_continue; ///< Allow one logical read across multiple I2C
+ ///< ops. Set when next read will be tied to
+ ///< current read
+ uint64_t bus_speed; ///< in kbits/sec (ie 400KHz)
+ uint16_t bit_rate_divisor; ///< uint16_t to match size in mode register
+ uint64_t polling_interval_ns; ///< in nanoseconds
uint64_t timeout_count;
uint64_t offset_length;
uint8_t* offset_buffer;
@@ -62,12 +74,18 @@ struct misc_args_t
TARGETING::I2cSwitches switches;
- misc_args_t():port(0xFF),
+ Smbus_t smbus;
+
+ misc_args_t():subop(DeviceFW::I2C_STANDARD),
+ port(0xFF),
engine(0xFF),
devAddr(0xFFFFFFFF),
skip_mode_setup(false),
with_stop(true),
read_not_write(true),
+ with_address(true),
+ with_start(true),
+ read_continue(false),
bus_speed(0),
bit_rate_divisor(0),
polling_interval_ns(0),
@@ -75,7 +93,8 @@ struct misc_args_t
offset_length(0),
offset_buffer(nullptr),
i2cMuxBusSelector(I2C_MUX::NOT_APPLICABLE),
- i2cMuxPath(nullptr)
+ i2cMuxPath(nullptr),
+ smbus( {0,true} )
{
memset(&switches, 0x0, sizeof(switches));
};
diff --git a/src/usr/isteps/istep21/call_update_ucd_flash.C b/src/usr/isteps/istep21/call_update_ucd_flash.C
index fa2d36896..78b59653f 100644
--- a/src/usr/isteps/istep21/call_update_ucd_flash.C
+++ b/src/usr/isteps/istep21/call_update_ucd_flash.C
@@ -31,7 +31,8 @@
#include <hbotcompid.H>
#include <config.h>
#include <initservice/isteps_trace.H>
-
+#include <isteps/ucd/updateUcdFlash.H>
+#include <secureboot/trustedbootif.H>
#include "call_update_ucd_flash.H"
namespace POWER_SEQUENCER
@@ -67,7 +68,15 @@ void call_update_ucd_flash(void)
break;
}
+ // Make sure TPM queue is flushed before doing any I2C operations
+ TRUSTEDBOOT::flushTpmQueue();
+
// @TODO RTC 201990 add flash update algorithm and make trace TRACDBIN
+ // call into:
+ //
+ // errlHndl_t updateUcdFlash(
+ // TARGETING::Target* i_pUcd,
+ // const void* i_pFlashImage);
for(const auto& lid : info.lidIds)
{
TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,"LID ID=0x%08X, "
diff --git a/src/usr/isteps/makefile b/src/usr/isteps/makefile
index e5aa9935d..dca7777f7 100644
--- a/src/usr/isteps/makefile
+++ b/src/usr/isteps/makefile
@@ -5,7 +5,7 @@
#
# OpenPOWER HostBoot Project
#
-# Contributors Listed Below - COPYRIGHT 2011,2018
+# Contributors Listed Below - COPYRIGHT 2011,2019
# [+] International Business Machines Corp.
#
#
@@ -51,6 +51,7 @@ SUBDIRS+=fab_iovalid.d
SUBDIRS+=nest.d
SUBDIRS+=io.d
SUBDIRS+=nvdimm.d
+SUBDIRS+=ucd.d
#TODO: RTC 176018
EXTRAINCDIR += ${ROOTPATH}/src/import/
diff --git a/src/usr/isteps/ucd/makefile b/src/usr/isteps/ucd/makefile
new file mode 100644
index 000000000..9ffe7a69b
--- /dev/null
+++ b/src/usr/isteps/ucd/makefile
@@ -0,0 +1,32 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/isteps/ucd/makefile $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2019
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+
+ROOTPATH = ../../../..
+
+MODULE = ucd
+
+OBJS += updateUcdFlash.o
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/isteps/ucd/updateUcdFlash.C b/src/usr/isteps/ucd/updateUcdFlash.C
new file mode 100644
index 000000000..4e1e3b13d
--- /dev/null
+++ b/src/usr/isteps/ucd/updateUcdFlash.C
@@ -0,0 +1,67 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/isteps/ucd/updateUcdFlash.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include <config.h>
+#include <isteps/ucd/updateUcdFlash.H>
+#include <devicefw/driverif.H>
+#include <targeting/common/entitypath.H>
+#include <targeting/common/target.H>
+#include <targeting/common/targetservice.H>
+#include <errl/errlentry.H>
+#include <devicefw/driverif.H>
+#include <trace/interface.H>
+#include <string.h>
+#include <hbotcompid.H>
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+
+namespace POWER_SEQUENCER
+{
+
+namespace TI // Texas Instruments
+{
+
+namespace UCD // UCD Series
+{
+
+trace_desc_t* g_trac_ucd = nullptr;
+TRAC_INIT(&g_trac_ucd, UCD_COMP_NAME, 2*KILOBYTE);
+
+errlHndl_t updateUcdFlash(
+ TARGETING::Target* i_pUcd,
+ const void* i_pFlashImage)
+{
+ errlHndl_t pError=nullptr;
+
+ // Stub for future additional support
+
+ return pError;
+}
+
+} // End namespace POWER_SEQUENCER
+
+} // End namespace TI
+
+} // End namespace UCD
OpenPOWER on IntegriCloud