summaryrefslogtreecommitdiffstats
path: root/src/usr/i2c
diff options
context:
space:
mode:
authorChristian Geddes <crgeddes@us.ibm.com>2019-10-16 10:10:34 -0500
committerWilliam G Hoffa <wghoffa@us.ibm.com>2019-11-01 15:41:41 -0500
commit632582f105da7a546708c4f9705761948d7688fa (patch)
treef76238e3071d6d7b39459b17eb83796aca6c95a1 /src/usr/i2c
parent3f41702fbfd6a5c4f4de9eabedf1d8acb801ae20 (diff)
downloadtalos-hostboot-632582f105da7a546708c4f9705761948d7688fa.tar.gz
talos-hostboot-632582f105da7a546708c4f9705761948d7688fa.zip
Allow dynmic i2c device addresses and set up PMIC targets to do this
Depending on which vendor made a given OCMB the i2c device address of the PMIC targets on the OCMB will be different. To account for this we have added a new DYNAMIC_DEVICE_ADDRESS attribute. This attribute is filled out on the PMIC target by looking at the SPD on parent OCMB chip. This means that we must do presence detection on the OCMB prior to the the PMIC targets. While doing i2c operations if a given target has the DYNAMIC_DEVICE_ADDRESS we will use that over the devAddr in the any complex i2c attribute for that target. Change-Id: I22a185a65c064a1514751dd5828547c57af98df1 RTC: 209714 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/85394 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M Crowell <dcrowell@us.ibm.com> Reviewed-by: Roland Veloz <rveloz@us.ibm.com> Reviewed-by: William G Hoffa <wghoffa@us.ibm.com>
Diffstat (limited to 'src/usr/i2c')
-rw-r--r--src/usr/i2c/eeprom_utils.C12
-rw-r--r--src/usr/i2c/fapi_i2c_dd.C12
-rw-r--r--src/usr/i2c/i2cTargetPres.C115
3 files changed, 128 insertions, 11 deletions
diff --git a/src/usr/i2c/eeprom_utils.C b/src/usr/i2c/eeprom_utils.C
index 7935094a3..8333ebf49 100644
--- a/src/usr/i2c/eeprom_utils.C
+++ b/src/usr/i2c/eeprom_utils.C
@@ -87,6 +87,18 @@ bool eepromPresence ( TARGETING::Target * i_target )
break;
}
+ // If the target has dynamic device address attribute, then use that instead of the
+ // read-only address found in ATTR_EEPROM_XX_INFO attrs. We use the dynamic address
+ // attribute because ATTR_EEPROM_XX_INFO attrs are not writable and its difficult
+ // to override complex attributes.
+ if(i_target->tryGetAttr<TARGETING::ATTR_DYNAMIC_I2C_DEVICE_ADDRESS>(i2cInfo.devAddr))
+ {
+ TRACDCOMP(g_trac_eeprom,
+ "Using DYNAMIC_I2C_DEVICE_ADDRESS %.2x for HUID %.8x",
+ i2cInfo.devAddr,
+ TARGETING::get_huid(i_target));
+ }
+
//Check for the target at the I2C level
l_present = I2C::i2cPresence(i2cMasterTarget,
i2cInfo.port,
diff --git a/src/usr/i2c/fapi_i2c_dd.C b/src/usr/i2c/fapi_i2c_dd.C
index d800af376..46e0720a1 100644
--- a/src/usr/i2c/fapi_i2c_dd.C
+++ b/src/usr/i2c/fapi_i2c_dd.C
@@ -108,6 +108,18 @@ errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType,
break;
}
+ // If the target has dynamic device address attribute, then use that instead of the
+ // read-only address found in ATTR_FAPI_I2C_CONTROL_INFO. We use the dynamic address
+ // attribute because ATTR_FAPI_I2C_CONTROL_INFO is not writable and its difficult
+ // to override complex attributes.
+ if(i_target->tryGetAttr<TARGETING::ATTR_DYNAMIC_I2C_DEVICE_ADDRESS>(l_i2cInfo.devAddr))
+ {
+ TRACDCOMP(g_trac_i2c,
+ "Using DYNAMIC_I2C_DEVICE_ADDRESS %.2x for HUID %.8x",
+ l_i2cInfo.devAddr,
+ TARGETING::get_huid(i_target));
+ }
+
// grab target pointer to master
TARGETING::TargetService& ts = TARGETING::targetService();
TARGETING::Target * i2cm = ts.toTarget(l_i2cInfo.i2cMasterPath);
diff --git a/src/usr/i2c/i2cTargetPres.C b/src/usr/i2c/i2cTargetPres.C
index 13bfa88c1..2aba61de3 100644
--- a/src/usr/i2c/i2cTargetPres.C
+++ b/src/usr/i2c/i2cTargetPres.C
@@ -32,6 +32,8 @@
#include <initservice/initserviceif.H>
#include <errl/errlmanager.H>
#include "i2c_common.H"
+#include <vpd/spdenums.H>
+#include <fapiwrap/fapiWrapif.H>
extern trace_desc_t* g_trac_i2c;
@@ -181,6 +183,18 @@ errlHndl_t genericI2CTargetPresenceDetect(TARGETING::Target* i_target,
//* If we make it through all of the checks then we have verified master is present *
//***********************************************************************************
+ // If the target has dynamic device address attribute, then use that instead of the
+ // read-only address found in ATTR_FAPI_I2C_CONTROL_INFO. We use the dynamic address
+ // attribute because ATTR_FAPI_I2C_CONTROL_INFO is not writable and its difficult
+ // to override complex attributes.
+ if(i_target->tryGetAttr<TARGETING::ATTR_DYNAMIC_I2C_DEVICE_ADDRESS>(l_i2cInfo.devAddr))
+ {
+ TRACDCOMP(g_trac_i2c,
+ "Using DYNAMIC_I2C_DEVICE_ADDRESS %.2x for HUID %.8x",
+ l_i2cInfo.devAddr,
+ TARGETING::get_huid(i_target));
+ }
+
//Check for the target at the I2C level
l_target_present = I2C::i2cPresence(l_i2cMasterTarget,
l_i2cInfo.port,
@@ -231,10 +245,89 @@ errlHndl_t ocmbI2CPresencePerformOp(DeviceFW::OperationType i_opType,
}
/**
- * @brief Performs a presence detect operation on a Target that has the
+ * @brief Performs a presence detect operation on a PMIC Target
+ *
+ * @param[in] i_opType Operation type, see DeviceFW::OperationType
+ * in driverif.H
+ * @param[in] i_target Presence detect target
+ * @param[in/out] io_buffer Read: Pointer to output data storage
+ * Write: Pointer to input data storage
+ * @param[in/out] io_buflen Input: size of io_buffer (in bytes, always 1)
+ * Output: Success = 1, Failure = 0
+ * @param[in] i_accessType DeviceFW::AccessType enum (userif.H)
+ * @param[in] i_args This is an argument list for DD framework.
+ * In this function, there are no arguments.
+ * @return errlHndl_t
+ */
+errlHndl_t pmicI2CPresencePerformOp(DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args)
+{
+
+ errlHndl_t l_errl = nullptr;
+ bool l_pmicPresent = 0;
+ TARGETING::Target* l_parentOcmb = TARGETING::getImmediateParentByAffinity(i_target);
+
+ uint8_t l_spdBlob[SPD::DDIMM_DDR4_SPD_SIZE];
+ size_t l_spdSize = SPD::DDIMM_DDR4_SPD_SIZE;
+
+ do{
+
+ l_errl = deviceRead(l_parentOcmb,
+ l_spdBlob,
+ l_spdSize,
+ DEVICE_SPD_ADDRESS(SPD::ENTIRE_SPD_WITHOUT_EFD));
+
+ if(l_errl)
+ {
+ TRACFCOMP( g_trac_i2c, ERR_MRK"pmicI2CPresencePerformOp() "
+ "Error reading SPD associated with PMIC 0x%.08X, failed to determine presence",
+ TARGETING::get_huid(i_target));
+ break;
+ }
+
+ TARGETING::ATTR_REL_POS_type l_relPos = i_target->getAttr<TARGETING::ATTR_REL_POS>();
+
+ // PMICs will have a different device address depending on the vendor.
+ // Prior to doing present detection on a pmic we must first query the
+ // device address from the parent OCMB's SPD
+ uint8_t l_devAddr = FAPIWRAP::get_pmic_dev_addr(reinterpret_cast<char *>(l_spdBlob),
+ l_relPos);
+
+ assert(l_devAddr != 0,
+ "Found devAddr for PMIC 0x%.08x to be 0, this cannot be. Check SPD and REL_POS on target",
+ TARGETING::get_huid(i_target));
+
+ i_target->setAttr<TARGETING::ATTR_DYNAMIC_I2C_DEVICE_ADDRESS>(l_devAddr);
+
+ l_errl = genericI2CTargetPresenceDetect(i_target,
+ io_buflen,
+ l_pmicPresent);
+
+ if (l_errl)
+ {
+ TRACFCOMP( g_trac_i2c, ERR_MRK"pmicI2CPresencePerformOp() "
+ "Error detecting target 0x%.08X, io_buffer will not be set",
+ TARGETING::get_huid(i_target));
+ break;
+ }
+
+ // Copy variable describing if target is present or not to i/o buffer param
+ memcpy(io_buffer, &l_pmicPresent, sizeof(l_pmicPresent));
+ io_buflen = sizeof(l_pmicPresent);
+
+ }while(0);
+
+ return l_errl;
+}
+
+/**
+ * @brief Performs a presence detect operation on a Mux Target that has the
* ATTR_FAPI_I2C_CONTROL_INFO and can be detected via that device
*
- * Currently used to detect I2C_MUTEX targets
*
* @param[in] i_opType Operation type, see DeviceFW::OperationType
* in driverif.H
@@ -248,7 +341,7 @@ errlHndl_t ocmbI2CPresencePerformOp(DeviceFW::OperationType i_opType,
* In this function, there are no arguments.
* @return errlHndl_t
*/
-errlHndl_t basicI2CPresencePerformOp(DeviceFW::OperationType i_opType,
+errlHndl_t muxI2CPresencePerformOp(DeviceFW::OperationType i_opType,
TARGETING::Target* i_target,
void* io_buffer,
size_t& io_buflen,
@@ -256,13 +349,13 @@ errlHndl_t basicI2CPresencePerformOp(DeviceFW::OperationType i_opType,
va_list i_args)
{
bool l_muxPresent = 0;
- errlHndl_t l_returnedError = nullptr;
+ errlHndl_t l_errl = nullptr;
- l_returnedError = genericI2CTargetPresenceDetect(i_target,
- io_buflen,
- l_muxPresent);
+ l_errl = genericI2CTargetPresenceDetect(i_target,
+ io_buflen,
+ l_muxPresent);
- if (l_returnedError)
+ if (l_errl)
{
TRACFCOMP( g_trac_i2c, ERR_MRK"basicI2CTargetPresenceDetect() "
"Error detecting target 0x%.08X, io_buffer will not be set",
@@ -275,7 +368,7 @@ errlHndl_t basicI2CPresencePerformOp(DeviceFW::OperationType i_opType,
io_buflen = sizeof(l_muxPresent);
}
- return l_returnedError;
+ return l_errl;
}
// Register the ocmb presence detect function with the device framework
@@ -288,12 +381,12 @@ DEVICE_REGISTER_ROUTE(DeviceFW::READ,
DEVICE_REGISTER_ROUTE( DeviceFW::READ,
DeviceFW::PRESENT,
TARGETING::TYPE_I2C_MUX,
- basicI2CPresencePerformOp );
+ muxI2CPresencePerformOp );
// Register the pmic vrm presence detect function with the device framework
DEVICE_REGISTER_ROUTE( DeviceFW::READ,
DeviceFW::PRESENT,
TARGETING::TYPE_PMIC,
- basicI2CPresencePerformOp );
+ pmicI2CPresencePerformOp );
}
OpenPOWER on IntegriCloud