summaryrefslogtreecommitdiffstats
path: root/src/usr/i2c/i2c.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/i2c/i2c.C')
-rwxr-xr-xsrc/usr/i2c/i2c.C138
1 files changed, 112 insertions, 26 deletions
diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C
index 63b579202..2439f1eff 100755
--- a/src/usr/i2c/i2c.C
+++ b/src/usr/i2c/i2c.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2019 */
+/* Contributors Listed Below - COPYRIGHT 2011,2020 */
/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
@@ -94,6 +94,7 @@ TRAC_INIT( & g_trac_i2cr, "I2CR", KILOBYTE );
#define MAX_NACK_RETRIES 3
#define PAGE_OPERATION 0xffffffff // Special value use to determine type of op
#define P9_ENGINE_SCOM_OFFSET 0x1000
+constexpr uint64_t FSI_BUS_SPEED_MHZ = 133; //FSI runs at 133MHz
// Derived from ATTR_I2C_BUS_SPEED_ARRAY[engine][port] attribute
const TARGETING::ATTR_I2C_BUS_SPEED_ARRAY_type g_var = {{NULL}};
@@ -447,14 +448,16 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
// Else this is not a page operation, call the normal common function
else
{
- if( (subop==DeviceFW::I2C_SMBUS_BLOCK)
- || (subop==DeviceFW::I2C_SMBUS_BYTE)
- || (subop==DeviceFW::I2C_SMBUS_WORD))
+ if( (subop == DeviceFW::I2C_SMBUS_BLOCK)
+ || (subop == DeviceFW::I2C_SMBUS_BYTE)
+ || (subop == DeviceFW::I2C_SMBUS_WORD)
+ || (subop == DeviceFW::I2C_SMBUS_WORD_NO_PEC)
+ || (subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT) )
{
args.smbus.commandCode =
static_cast<decltype(args.smbus.commandCode)>(
va_arg(i_args,uint64_t));
- args.smbus.usePec = true; // All implementations use PEC
+ args.smbus.usePec = true; // Most implementations use PEC
args.i2cMuxBusSelector = va_arg(i_args,uint64_t);
args.i2cMuxPath = reinterpret_cast<const TARGETING::EntityPath*>(
va_arg(i_args, uint64_t));
@@ -477,11 +480,23 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
if ( args.offset_length != 0 )
{
args.offset_buffer = temp;
-
}
}
- args.subop=subop;
+ if (subop == DeviceFW::I2C_SMBUS_WORD_NO_PEC)
+ {
+ args.smbus.usePec = false;
+ args.subop = DeviceFW::I2C_SMBUS_WORD;
+ }
+ else if (subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT)
+ {
+ args.smbus.usePec = false;
+ args.subop=subop;
+ }
+ else
+ {
+ args.subop=subop;
+ }
err = i2cCommonOp( i_opType,
i_target,
@@ -1284,11 +1299,22 @@ errlHndl_t i2cAccessMux( TARGETING::Target* i_masterTarget,
if (! (l_i2cMuxTarget->tryGetAttr<TARGETING::ATTR_FAPI_I2C_CONTROL_INFO>(l_muxData)) )
{
TRACFCOMP(g_trac_i2c,
- "i2cAccessMux(): get attributes failed");
+ "i2cAccessMux(): getting ATTR_FAPI_I2C_CONTROL_INFO failed");
break;
}
- uint8_t l_muxSelector = i_i2cMuxBusSelector;
+ TARGETING::ATTR_MODEL_type l_muxModel;
+ if (! (l_i2cMuxTarget->tryGetAttr<TARGETING::ATTR_MODEL>(l_muxModel)) )
+ {
+ TRACFCOMP(g_trac_i2c,
+ "i2cAccessMux(): getting ATTR_MODEL failed");
+ break;
+ }
+
+ assert(l_muxModel == TARGETING::MODEL_PCA9847, "Invalid model of mux detected");
+ const uint8_t PCA9847_ENABLE_BIT = 8;
+
+ uint8_t l_muxSelector = i_i2cMuxBusSelector | PCA9847_ENABLE_BIT;
uint8_t *l_ptrMuxSelector = &l_muxSelector;
size_t l_muxSelectorSize = sizeof(l_muxSelector);
@@ -1430,7 +1456,8 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
/*******************************************************/
/* Perform the I2C Operation */
/*******************************************************/
-
+ TRACUCOMP( g_trac_i2c, INFO_MRK "i2cCommonOp() -- opType: %d, subOp: %d",
+ static_cast<uint64_t>(i_opType), i_args.subop);
/***********************************************/
/* I2C SMBUS Send Byte */
/***********************************************/
@@ -1598,14 +1625,16 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
/***********************************************/
/* I2C SMBUS Block Write */
/***********************************************/
- else if( (i_opType == DeviceFW::WRITE )
- && (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK))
+ else if( (i_opType == DeviceFW::WRITE ) &&
+ ((i_args.subop == DeviceFW::I2C_SMBUS_BLOCK) ||
+ (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT)) )
{
TRACUCOMP(g_trac_i2c, INFO_MRK
- "I2C SMBUS Block Write: Command code = 0x%02X, "
- "Use PEC = %d. io_buflen = %lu",
- i_args.smbus.commandCode,
- i_args.smbus.usePec, io_buflen);
+ "I2C SMBUS Block Write: Command code = 0x%02X, SubCmd = 0x%02X "
+ "Use PEC = %d. io_buflen = %lu, io_buffer byte0: 0x%02X",
+ i_args.smbus.commandCode, i_args.subop,
+ i_args.smbus.usePec, io_buflen,
+ *reinterpret_cast<uint8_t*>(io_buffer));
// If requested length is for < 1 byte or > 255 bytes for a block
// write transaction, throw an error.
@@ -1649,12 +1678,29 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
io_buflen,
io_buffer,
i_args.smbus.usePec);
+ void * writeStart = &blockWrite.commandCode;
+
+ // byteCount might be altered into commandCode, so store its value
+ size_t dataByteCount = blockWrite.byteCount;
+ if (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT)
+ {
+ // Moving commandCode down a byte so it is followed
+ // immediately by dataBytes[] instead of byteCount
+ // (this removes byteCount from the block write)
+ writeStart = &blockWrite.byteCount;
+ blockWrite.byteCount = blockWrite.commandCode;
+ blockWrite.messageSize -= sizeof(blockWrite.commandCode);
+ TRACUCOMP(g_trac_i2c, INFO_MRK
+ "I2C SMBUS Block Write no-byte-count: removing byteCount,"
+ " msgSize = %d", blockWrite.messageSize);
+ }
+
do {
size_t writeSize = blockWrite.messageSize;
const auto writeSizeExp = writeSize;
err = i2cWrite(i_target,
- &blockWrite.commandCode,
+ writeStart,
writeSize,
i_args);
if(err)
@@ -1666,7 +1712,8 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
"Write size mismatch; expected %d but got %d",
writeSizeExp,writeSize);
- io_buflen = blockWrite.byteCount;
+
+ io_buflen = dataByteCount;
} while(0);
@@ -4308,13 +4355,23 @@ errlHndl_t i2cSetBusVariables ( TARGETING::Target * i_target,
if ( io_args.switches.useFsiI2C == 1 )
{
- // @todo RTC 117560 - verify correct frequency
- local_bus_MHZ = g_I2C_NEST_FREQ_MHZ;
+ // For FSI I2C we should use the FSI clock
+ local_bus_MHZ = FSI_BUS_SPEED_MHZ;
}
else
{
- // For Host I2C use Nest Frequency
- local_bus_MHZ = g_I2C_NEST_FREQ_MHZ;
+ // For Host I2C use Nest Frequency as base
+
+ // PIB_CLK = NEST_FREQ / 4
+ uint64_t pib_clk = g_I2C_NEST_FREQ_MHZ / 4;
+
+#ifdef CONFIG_AXONE
+ // Axone has a by-2 internal divider
+ local_bus_MHZ = pib_clk / 2;
+#else
+ // Nimbus/Cumulus have a by-4 internal divider
+ local_bus_MHZ = pib_clk / 4;
+#endif
}
io_args.bit_rate_divisor = i2cGetBitRateDivisor(io_args.bus_speed,
@@ -5148,8 +5205,13 @@ void getMasterInfo( const TARGETING::Target* i_chip,
info.engine = engine;
info.freq = i2cGetNestFreq()*FREQ_CONVERSION::HZ_PER_MHZ;
// PIB_CLK = NEST_FREQ /4
- // Local Bus = PIB_CLK / 4
+#ifdef CONFIG_AXONE
+ // Local Bus = PIB_CLK / 2 [Axone]
+ info.freq = info.freq/8; //convert nest to local bus
+#else
+ // Local Bus = PIB_CLK / 4 [Nimbus/Cumulus]
info.freq = info.freq/16; //convert nest to local bus
+#endif
TRACFCOMP(g_trac_i2c,"getMasterInfo(%.8X): pushing back engine=%d, scomAddr=0x%X",TARGETING::get_huid(i_chip), engine, info.scomAddr);
@@ -5447,6 +5509,7 @@ void getDeviceInfo( TARGETING::Target* i_i2cMaster,
// Lookup i2c info for the TPM
l_err = TPMDD::tpmReadAttributes(pTpm,
tpmInfo, locality);
+
if( NULL != l_err )
{
// Unable to get info, so we skip
@@ -5474,11 +5537,34 @@ void getDeviceInfo( TARGETING::Target* i_i2cMaster,
l_currentDI.slavePort = 0xFF;
l_currentDI.busFreqKhz = (tpmInfo.busFreq)
/ FREQ_CONVERSION::HZ_PER_KHZ;
- l_currentDI.deviceType =
- TARGETING::HDAT_I2C_DEVICE_TYPE_NUVOTON_TPM;
l_currentDI.devicePurpose =
TARGETING::HDAT_I2C_DEVICE_PURPOSE_TPM;
- strcpy(l_currentDI.deviceLabel,"?nuvoton,npct601,tpm,host");
+
+ // Read TPM Model attribute to determine some values
+ if (tpmInfo.model == TPMDD::TPM_MODEL_65x)
+ {
+ strcpy(l_currentDI.deviceLabel,"?nuvoton,npct601,tpm,host");
+ l_currentDI.deviceType =
+ TARGETING::HDAT_I2C_DEVICE_TYPE_NUVOTON_TPM;
+ }
+ else if (tpmInfo.model == TPMDD::TPM_MODEL_75x)
+ {
+ strcpy(l_currentDI.deviceLabel,"?tcg,tpm_i2c_ptp,tpm,host");
+ l_currentDI.deviceType =
+ TARGETING::HDAT_I2C_DEVICE_TYPE_TCG_I2C_TPM;
+ }
+ else
+ {
+ // Should never get here as tpmReadAttributes will fail if
+ // unknown TPM Model, but just in case do this:
+ strcpy(l_currentDI.deviceLabel,
+ "?unknwon,unknown,tpm,host");
+ }
+
+ TRACUCOMP(g_trac_i2c,"TPM 0x%X is Model %d using label %s",
+ TARGETING::get_huid(pTpm),
+ tpmInfo.model,
+ l_currentDI.deviceLabel);
o_deviceInfo.push_back(l_currentDI);
} //end of tpm iter
OpenPOWER on IntegriCloud