summaryrefslogtreecommitdiffstats
path: root/src/usr/devtree/bld_devtree.C
diff options
context:
space:
mode:
authorDan Crowell <dcrowell@us.ibm.com>2015-01-12 10:26:06 -0600
committerA. Patrick Williams III <iawillia@us.ibm.com>2015-02-11 12:27:46 -0600
commit52561adeaa1c8d846e363d8386ca99a1ad89196b (patch)
treed4df89c98939044536f0262bd08ae8fa4c0dbb0d /src/usr/devtree/bld_devtree.C
parent35019a5b9b1916840c5551acd758bcded0596dc9 (diff)
downloadblackbird-hostboot-52561adeaa1c8d846e363d8386ca99a1ad89196b.tar.gz
blackbird-hostboot-52561adeaa1c8d846e363d8386ca99a1ad89196b.zip
Report I2C devices in devtree
Report all I2C masters, busses and end devices in the devtree. Current support includes the following devices: -Processor module vpd (primary and backup) -Processor SBE SEEPROM (x2) -Memory buffer VPD -DIMM SPD Change-Id: Ic0e08c208331ce9701de27111cc2e9f54a81fcf7 RTC: 117996 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/15203 Tested-by: Jenkins Server Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: Michael Baiocchi <baiocchi@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/devtree/bld_devtree.C')
-rw-r--r--src/usr/devtree/bld_devtree.C296
1 files changed, 294 insertions, 2 deletions
diff --git a/src/usr/devtree/bld_devtree.C b/src/usr/devtree/bld_devtree.C
index 07ec2536c..f1b0fb0da 100644
--- a/src/usr/devtree/bld_devtree.C
+++ b/src/usr/devtree/bld_devtree.C
@@ -46,6 +46,8 @@
#include <config.h>
#include <devicefw/userif.H>
#include <vpd/cvpdenums.H>
+#include <i2c/i2cif.H>
+#include <i2c/eepromif.H>
trace_desc_t *g_trac_devtree = NULL;
@@ -87,6 +89,7 @@ enum BuildConstants
+//@todo-RTC:123043 -- Should use the functions in RT_TARG
uint32_t getProcChipId(const TARGETING::Target * i_pProc)
{
uint32_t l_fabId = i_pProc->getAttr<TARGETING::ATTR_FABRIC_NODE_ID>();
@@ -94,6 +97,30 @@ uint32_t getProcChipId(const TARGETING::Target * i_pProc)
return ( (l_fabId << CHIPID_NODE_SHIFT) + l_procPos);
}
+//@todo-RTC:123043 -- Should use the functions in RT_TARG
+uint32_t getMembChipId(const TARGETING::Target * i_pMemb)
+{
+ PredicateCTM l_mcs(CLASS_UNIT,TYPE_MCS, MODEL_NA);
+ TargetHandleList mcs_list;
+ targetService().getAssociated(mcs_list,
+ i_pMemb,
+ TargetService::PARENT_BY_AFFINITY,
+ TargetService::ALL,
+ &l_mcs);
+
+ if( mcs_list.size() != 1 )
+ {
+ //should never happen
+ return 0;
+ }
+ Target* l_parentMCS = *(mcs_list.begin());
+ uint32_t l_procId = getProcChipId(getParentChip(l_parentMCS));
+ uint32_t l_membId = CEN_ID_TAG | (l_procId << CEN_ID_SHIFT);
+ l_membId |= l_parentMCS->getAttr<ATTR_CHIP_UNIT>();
+ return l_membId;
+}
+
+
uint64_t getHomerPhysAddr(const TARGETING::Target * i_pProc)
{
//If running Sapphire need to place this at the top of memory
@@ -116,6 +143,263 @@ uint64_t getHomerPhysAddr(const TARGETING::Target * i_pProc)
return targHomer;
}
+void add_i2c_info( const TARGETING::Target* i_targ,
+ devTree* i_dt,
+ dtOffset_t i_node )
+{
+ TRACFCOMP(g_trac_devtree,"add_i2c_info(%X)",TARGETING::get_huid(i_targ));
+
+ //get list of all I2C Masters
+ std::list<I2C::MasterInfo_t> l_i2cInfo;
+ I2C::getMasterInfo( i_targ, l_i2cInfo );
+
+ //find all of the EEPROMs connected via i2c
+ std::list<EEPROM::EepromInfo_t> l_eepromInfo;
+ EEPROM::getEEPROMs( l_eepromInfo );
+
+ //add any other i2c devices here as needed, e.g. TPM, etc
+
+ //figure out what kind of chip we're talking about
+ TARGETING::TYPE l_master_type = i_targ->getAttr<TARGETING::ATTR_TYPE>();
+ const char* l_masterName = "ibm,unknown";
+ const char* l_chipname = "xx";
+ uint32_t l_chipid = 0x0;
+ if( l_master_type == TARGETING::TYPE_PROC )
+ {
+ l_masterName = "ibm,power8-i2cm";
+ l_chipid = getProcChipId(i_targ);
+ l_chipname = "p8";
+ }
+ else if( l_master_type == TARGETING::TYPE_MEMBUF )
+ {
+ l_masterName = "ibm,centaur-i2cm";
+ l_chipid = getMembChipId(i_targ);
+ l_chipname = "cen";
+ }
+
+ //compatible devices to make Opal/Linux happy
+ static const struct
+ {
+ const char* name;
+ size_t byteSize;
+ size_t addrBytes;
+ } atmel_ids[] = {
+ { "atmel,24c128", 16*KILOBYTE, 2 },
+ { "atmel,24c256", 32*KILOBYTE, 2 },
+ { "atmel,24c02", 256, 1 },
+
+ //Currently our minimum is 1KB, even for the 256 byte SPD
+ { "atmel,24c02", 1*KILOBYTE, 1 },
+ };
+
+ /*
+ Devtree hierarchy is like so
+ i2cm@12345 {
+ i2c-bus@0 {
+ eeprom@12 {
+ }
+ }
+ i2c-bus@1 {
+ eeprom@12 {
+ }
+ eeprom@34 {
+ }
+ }
+ }
+ */
+ for( std::list<I2C::MasterInfo_t>::iterator i2cm = l_i2cInfo.begin();
+ i2cm != l_i2cInfo.end();
+ ++i2cm )
+ {
+ /*
+ i2cm@a0020 {
+ reg = <0xa0020 0x20>; << scom address space
+ chip-engine# = <0x1>; << i2c engine
+ compatible = "ibm,power8-i2cm"; << what Opal wants
+ clock-frequency = <0x2faf080>; << local bus in Hz
+ #address-cells = <0x1>;
+ phandle = <0x10000062>; << auto-filled
+ #size-cells = <0x0>;
+ linux,phandle = <0x10000062>; << Opal fills in
+ }
+ */
+ dtOffset_t l_i2cNode = i_dt->addNode(i_node,
+ "i2cm", i2cm->scomAddr);
+ uint32_t l_i2cProp[2] = {
+ static_cast<uint32_t>(i2cm->scomAddr),
+ 0x20 }; //0x20 is number of scom regs per engine
+ i_dt->addPropertyCells32(l_i2cNode, "reg", l_i2cProp, 2);
+ i_dt->addPropertyCell32(l_i2cNode, "chip-engine#", i2cm->engine);
+ const char* l_i2cCompatStrs[] = {l_masterName, NULL};
+ i_dt->addPropertyStrings(l_i2cNode, "compatible", l_i2cCompatStrs);
+ i_dt->addPropertyCell32(l_i2cNode, "clock-frequency",
+ i2cm->freq / 4); //Opal wants it pre-divided
+ i_dt->addPropertyCell32(l_i2cNode, "#address-cells", 1);
+ i_dt->addPropertyCell32(l_i2cNode, "#size-cells", 0);
+
+
+ /*I2C busses*/
+ std::list<EEPROM::EepromInfo_t>::iterator eep = l_eepromInfo.begin();
+ while( eep != l_eepromInfo.end() )
+ {
+ // ignore the devices that aren't on the current target
+ if( eep->i2cMaster != i_targ )
+ {
+ eep = l_eepromInfo.erase(eep);
+ continue;
+ }
+ // skip the devices that are on a different engine
+ else if( eep->engine != i2cm->engine )
+ {
+ ++eep;
+ continue;
+ }
+
+ /*
+ i2c-bus@0 {
+ reg = <0x0>;
+ bus-frequency = <0x61a80>;
+ compatible = "ibm,power8-i2c-port", << Opal fills in
+ "ibm,opal-i2c"; << Opal fills in
+ ibm,opal-id = <0x1>; << Opal fills in
+ ibm,port-name = "p8_00000000_e1p0"; << chip_chipid_eng_port
+ #address-cells = <0x1>;
+ phandle = <0x10000063>; << auto-filled
+ #size-cells = <0x0>;
+ linux,phandle = <0x10000063>;
+ }
+ */
+ dtOffset_t l_busNode = i_dt->addNode( l_i2cNode,
+ "i2c-bus", eep->port );
+ i_dt->addPropertyCell32(l_busNode, "reg", 0);
+ i_dt->addPropertyCell32(l_busNode, "bus-frequency", eep->busFreq);
+ i_dt->addPropertyCell32(l_busNode, "#address-cells", 1);
+ i_dt->addPropertyCell32(l_busNode, "#size-cells", 0);
+ char portname[20];
+ sprintf( portname, "%s_%.8X_e%dp%d",
+ l_chipname,
+ l_chipid,
+ eep->engine,
+ eep->port );
+ i_dt->addPropertyString(l_busNode,
+ "ibm,port-name",
+ portname);
+
+ // find any other devices on the same port so we can add them
+ // all at once
+ EEPROM::EepromInfo_t cur_eep = *eep;
+ std::list<EEPROM::EepromInfo_t>::iterator eep2 = eep;
+ while( eep2 != l_eepromInfo.end() )
+ {
+ // skip the devices for other busses
+ if( !((cur_eep.i2cMaster == eep2->i2cMaster)
+ && (cur_eep.engine == eep2->engine)
+ && (cur_eep.port == eep2->port)) )
+ {
+ ++eep2;
+ continue;
+ }
+
+ /*
+ eeprom@50 {
+ reg = <0x50>; << right-justified 7-bit addr
+ label = "system-vpd"; << arbitrary name
+ compatible = "atmel,24c64"; << use table above
+ status = "ok"; << Opal fills in
+ phandle = <0x10000065>; << auto-filled
+ linux,phandle = <0x10000065>; << Opal fills in
+ }
+ */
+ dtOffset_t l_eepNode = i_dt->addNode( l_busNode,
+ "eeprom",
+ eep2->devAddr >> 1 );
+ i_dt->addPropertyCell32(l_eepNode, "reg", eep2->devAddr >> 1);
+ char l_label[30];
+ TARGETING::TYPE l_type = TARGETING::TYPE_NA;
+ l_type = eep2->assocTarg->getAttr<TARGETING::ATTR_TYPE>();
+ if( (l_type == TARGETING::TYPE_SYS)
+ || (l_type == TARGETING::TYPE_NODE) )
+ {
+ sprintf( l_label, "system-vpd" );
+ }
+ else if( l_type == TARGETING::TYPE_PROC )
+ {
+ const char* l_type = "vpd";
+ switch( eep2->device )
+ {
+ case(EEPROM::VPD_PRIMARY):
+ l_type = "proc-vpd";
+ break;
+ case(EEPROM::VPD_BACKUP):
+ l_type = "proc-vpd-backup";
+ break;
+ case(EEPROM::SBE_PRIMARY):
+ l_type = "sbe0";
+ break;
+ case(EEPROM::SBE_BACKUP):
+ l_type = "sbe1";
+ break;
+ default:
+ break;
+ }
+ sprintf( l_label, "%s-%d",
+ l_type,
+ eep2->assocTarg
+ ->getAttr<TARGETING::ATTR_POSITION>() );
+ }
+ else if( l_type == TARGETING::TYPE_MEMBUF )
+ {
+ sprintf( l_label, "memb-vpd-%d",
+ eep2->assocTarg
+ ->getAttr<TARGETING::ATTR_POSITION>() );
+ }
+ else if( l_type == TARGETING::TYPE_DIMM )
+ {
+ sprintf( l_label, "dimm-spd-%d",
+ eep2->assocTarg
+ ->getAttr<TARGETING::ATTR_POSITION>() );
+ }
+ else
+ {
+ sprintf( l_label, "unknown" );
+ }
+ i_dt->addPropertyString(l_eepNode, "label", l_label);
+
+ // fill in atmel compatible
+ const char* l_compat = "unknown";
+ bool l_foundit = false;
+ for( size_t a = 0;
+ a < (sizeof(atmel_ids)/sizeof(atmel_ids[0]));
+ a++ )
+ {
+ if( (atmel_ids[a].byteSize == (KILOBYTE*eep2->sizeKB))
+ || (atmel_ids[a].addrBytes == eep2->addrBytes) )
+ {
+ l_compat = atmel_ids[a].name;
+ l_foundit = true;
+ break;
+ }
+ }
+ if( !l_foundit )
+ {
+ TRACFCOMP( g_trac_devtree, "Could not find matching eeprom device for %s : size=%d,addr=%d", l_label, eep2->sizeKB, eep2->addrBytes );
+ }
+ i_dt->addPropertyString(l_eepNode, "compatible", l_compat);
+
+ // need to increment the outer loop if we're going to
+ // remove the element it points to
+ if( eep == eep2 )
+ {
+ ++eep;
+ }
+ // now remove the device we added so we don't add it again
+ eep2 = l_eepromInfo.erase(eep2);
+ }
+ }
+ }
+
+}
+
void bld_xscom_node(devTree * i_dt, dtOffset_t & i_parentNode,
const TARGETING::Target * i_pProc, uint32_t i_chipid)
@@ -239,6 +523,10 @@ void bld_xscom_node(devTree * i_dt, dtOffset_t & i_parentNode,
reinterpret_cast<uint32_t*>(l_laneEq[l_phb]),
(sizeof(l_laneEq[l_phb])/sizeof(uint32_t)));
}
+
+ /*I2C Masters*/
+ add_i2c_info( i_pProc, i_dt, xscomNode );
+
}
uint32_t bld_l3_node(devTree * i_dt, dtOffset_t & i_parentNode,
@@ -927,6 +1215,8 @@ errlHndl_t bld_fdt_mem(devTree * i_dt, bool i_smallTree)
l_ibscomBase);
uint64_t propertyCells[2] = {l_ibscomBase,THIRTYTWO_GB};
i_dt->addPropertyCells64(membNode, "reg", propertyCells, 2);
+ i_dt->addPropertyCell32(membNode, "#address-cells", 1);
+ i_dt->addPropertyCell32(membNode, "#size-cells", 1);
uint32_t l_ec = l_pMemB->getAttr<ATTR_EC>();
char cenVerStr[32];
@@ -946,8 +1236,7 @@ errlHndl_t bld_fdt_mem(devTree * i_dt, bool i_smallTree)
i_dt->addPropertyCell32(membNode, "ibm,fsi-master-chip-id",
l_procId);
- uint32_t l_cenId = CEN_ID_TAG | (l_procId << CEN_ID_SHIFT);
- l_cenId |= parentMCS->getAttr<ATTR_CHIP_UNIT>();
+ uint32_t l_cenId = getMembChipId(l_pMemB);
i_dt->addPropertyCell32(membNode, "ibm,chip-id",l_cenId);
//Add the CMFSI (which CMFSI 0 or 1) and port
@@ -957,6 +1246,9 @@ errlHndl_t bld_fdt_mem(devTree * i_dt, bool i_smallTree)
{linkinfo.mPort,linkinfo.link};
i_dt->addPropertyCells32(membNode, "ibm,fsi-master-port",
cmfsiCells, 2);
+
+ //Add any I2C devices hanging off this chip
+ add_i2c_info( l_pMemB, i_dt, membNode );
}
OpenPOWER on IntegriCloud