diff options
Diffstat (limited to 'src/usr/i2c/i2c.C')
-rwxr-xr-x | src/usr/i2c/i2c.C | 138 |
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 |