Skip to content

Commit

Permalink
Allow dynmic i2c device addresses and set up PMIC targets to do this
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
crgeddes authored and wghoffa committed Nov 1, 2019
1 parent 3f41702 commit 632582f
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 17 deletions.
12 changes: 12 additions & 0 deletions src/include/usr/fapiwrap/fapiWrapif.H
Expand Up @@ -55,6 +55,18 @@ namespace FAPIWRAP
errlHndl_t explorer_getidec( TARGETING::Target * i_ocmbChip,
uint16_t& o_chipId,
uint8_t& o_ec);

/**
* @brief This function wraps around the FAPI2 HWP "get_pmic_i2c_addr" which
* takes in a DDIMM's DDR4 SPD data and a PMIC's position relative to
* its parent OCMB's chip and returns the device address of that pmic
* @param[in] i_spd - Binary blob containing addresses a given OCMB's PMICs
* @param[in] i_pmic_id - PMIC's position relative to parent OCMB
* @return uint8_t 0 if invalid pmic_id is passed, PMIC's devAddress otherwise
*/
uint8_t get_pmic_dev_addr( const char* i_spd,
const uint8_t i_pmic_id);

}

#endif
6 changes: 3 additions & 3 deletions src/include/usr/i2c/eeprom_const.H
Expand Up @@ -170,9 +170,9 @@ struct eecacheSectionHeader
*/
struct eeprom_addr_t
{
uint64_t port;
uint64_t engine;
uint64_t devAddr;
uint8_t port;
uint8_t engine;
uint8_t devAddr;
int64_t eepromRole;
uint64_t offset;
eeprom_addr_size_t addrSize;
Expand Down
9 changes: 8 additions & 1 deletion src/usr/fapiwrap/fapiWrap.C
Expand Up @@ -27,7 +27,8 @@
#include <fapi2/plat_hwp_invoker.H> // FAPI_INVOKE_HWP
#include <trace/interface.H> // tracing includes

#include <exp_getidec.H> // exp_getidec
#include <exp_getidec.H> // exp_getidec
#include <pmic_i2c_addr_get.H> // get_pmic_i2c_addr

trace_desc_t* g_trac_fapiwrap;
TRAC_INIT(&g_trac_fapiwrap, FAPIWRAP_COMP_NAME, 6*KILOBYTE, TRACE::BUFFER_SLOW);
Expand Down Expand Up @@ -55,4 +56,10 @@ namespace FAPIWRAP

return l_errl;
}

uint8_t get_pmic_dev_addr( const char* i_spd,
const uint8_t i_pmic_id)
{
return get_pmic_i2c_addr(i_spd, i_pmic_id);
}
}
1 change: 1 addition & 0 deletions src/usr/fapiwrap/makefile
Expand Up @@ -38,6 +38,7 @@ EXTRAINCDIR += ${ROOTPATH}/src/import/chips/p9/procedures/hwp/ffdc/

# HWP include directories :
EXTRAINCDIR += ${ROOTPATH}/src/import/chips/ocmb/explorer/procedures/hwp/memory/
EXTRAINCDIR += ${ROOTPATH}/src/import/chips/ocmb/common/spd_access/

# HWP objects
OBJS += exp_getidec.o
Expand Down
69 changes: 67 additions & 2 deletions src/usr/hwas/common/hwas.C
Expand Up @@ -569,6 +569,59 @@ errlHndl_t discoverMuxTargetsAndEnable(const Target &i_sysTarget)
return l_err;
}

/**
* @brief Do presence detect on only PMIC targets and enable HWAS state
*
* @param[in] i_sysTarget the top level target (CLASS_SYS)
* @return errlHndl_t return nullptr if no error,
* else return a handle to an error entry
*
*/
errlHndl_t discoverPmicTargetsAndEnable(const Target &i_sysTarget)
{
HWAS_INF(ENTER_MRK"discoverPmicTargetsAndEnable");

errlHndl_t l_err{nullptr};

do
{
// Only get PMIC targets
const PredicateCTM l_pmicPred(CLASS_ASIC, TYPE_PMIC);
TARGETING::PredicatePostfixExpr l_asicPredExpr;
l_asicPredExpr.push(&l_pmicPred);
TargetHandleList l_pPmicCheckPres;
targetService().getAssociated( l_pPmicCheckPres, (&i_sysTarget),
TargetService::CHILD, TargetService::ALL, &l_asicPredExpr);

// Do the presence detect on only PMIC targets
// NOTE: this function will remove any non-functional targets
// from pPmicCheckPres
l_err = platPresenceDetect(l_pPmicCheckPres);

// If an issue with platPresenceDetect, then exit, returning
// error back to caller
if (nullptr != l_err)
{
break;
}

// Enable the HWAS State for the PMICs
const bool l_present(true);
const bool l_functional(true);
const uint32_t l_errlEid(0);
for (TargetHandle_t pTarget : l_pPmicCheckPres)
{
// set HWAS state to show PMIC is present and functional
enableHwasState(pTarget, l_present, l_functional, l_errlEid);
}
} while (0);

HWAS_INF(EXIT_MRK"discoverPmicTargetsAndEnable exit with %s",
(nullptr == l_err ? "no error" : "error"));

return l_err;
}

errlHndl_t discoverTargets()
{
HWAS_DBG("discoverTargets entry");
Expand Down Expand Up @@ -643,11 +696,13 @@ errlHndl_t discoverTargets()
PredicateCTM predPmic(CLASS_ASIC, TYPE_PMIC);
// We can ignore chips of TYPE_I2C_MUX because they
// were already detected above in discoverMuxTargetsAndEnable
// Also we can ignore chips of type PMIC because they will be processed
// below.
PredicateCTM predMux(CLASS_CHIP, TYPE_I2C_MUX);
PredicatePostfixExpr checkExpr;
checkExpr.push(&predChip).push(&predDimm).Or().push(&predEnc).Or().
push(&predMcs).Or().push(&predPmic).Or().
push(&predMux).Not().And();
push(&predMcs).Or().push(&predMux).Not().And().
push(&predPmic).Not().And();

TargetHandleList pCheckPres;
targetService().getAssociated( pCheckPres, pSys,
Expand Down Expand Up @@ -865,6 +920,16 @@ errlHndl_t discoverTargets()

} // for pTarget_it

// After processing all other targets look at the pmics,
// we must wait because we need the SPD cached from the OCMBs
// which occurs when OCMBs go through presence detection above
errl = discoverPmicTargetsAndEnable(*pSys);

if (errl != NULL)
{
break; // break out of the do/while so that we can return
}

// Check for non-present Procs and if found, trigger
// DeconfigGard::_invokeDeconfigureAssocProc() to run by setting
// setXAOBusEndpointDeconfigured to true
Expand Down
12 changes: 12 additions & 0 deletions src/usr/i2c/eeprom_utils.C
Expand Up @@ -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,
Expand Down
12 changes: 12 additions & 0 deletions src/usr/i2c/fapi_i2c_dd.C
Expand Up @@ -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);
Expand Down
115 changes: 104 additions & 11 deletions src/usr/i2c/i2cTargetPres.C
Expand Up @@ -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;

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -248,21 +341,21 @@ 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,
int64_t i_accessType,
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",
Expand All @@ -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
Expand All @@ -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 );

}
15 changes: 15 additions & 0 deletions src/usr/targeting/common/xmltohb/attribute_types_hb.xml
Expand Up @@ -174,6 +174,21 @@
<writeable/>
</attribute>

<attribute>
<id>DYNAMIC_I2C_DEVICE_ADDRESS</id>
<description>
This attribute is used when a given target could have different
i2c device addresses depending on which manufacture's device we
are using.
</description>
<simpleType>
<uint8_t/>
</simpleType>
<persistency>volatile-zeroed</persistency>
<readable/>
<writeable/>
</attribute>

<attribute>
<id>EARLY_TESTCASES_ISTEP</id>
<description>
Expand Down

0 comments on commit 632582f

Please sign in to comment.