From 079068a0dd84a877e3aa9b382b4dcaebecfa5f37 Mon Sep 17 00:00:00 2001 From: Mike Baiocchi Date: Thu, 25 Jan 2018 09:53:29 -0600 Subject: I2C Reset Path: Add Poll of SCL High Before Issuing Stop Command At the end of the I2C reset sequence, a 'stop' command is sent to each port on the master that was reset. Before sending this 'stop' command, a poll has been added such to check that SCL (clock line) is high. This addresses a known issue with current TPMs. Change-Id: I13b199f5b4d10d7224d3ccc5d1a8baaecb4f2326 CQ: SW405816 Backport: release-fips910 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/52636 Reviewed-by: Christopher J. Engel Reviewed-by: Timothy R. Block Tested-by: Jenkins Server Reviewed-by: Nicholas E. Bofferding Tested-by: Jenkins OP Build CI Tested-by: Jenkins OP HW Tested-by: FSP CI Jenkins Reviewed-by: William G. Hoffa --- src/usr/i2c/i2c.C | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/usr/i2c/i2c.H | 5 +++-- 2 files changed, 57 insertions(+), 3 deletions(-) (limited to 'src/usr/i2c') diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C index 762d66ec2..61256f3bd 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,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -80,6 +80,9 @@ TRAC_INIT( & g_trac_i2cr, "I2CR", KILOBYTE ); // Defines // ---------------------------------------------- #define I2C_RESET_DELAY_NS (5 * NS_PER_MSEC) // Sleep for 5 ms after reset +#define I2C_RESET_POLL_DELAY_NS (500 * 1000) // Sleep for 500usec per poll +#define I2C_RESET_POLL_DELAY_TOTAL_NS (500 * NS_PER_MSEC) // Total time to poll + #define P9_MASTER_PORTS 13 // Number of Ports used in P9 #define CENTAUR_MASTER_ENGINES 1 // Number of Engines in a Centaur #define MAX_NACK_RETRIES 3 @@ -2791,6 +2794,7 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target, // Master Registers mode_reg_t mode; command_reg_t cmd; + status_reg_t status_reg; uint64_t l_speed = I2C_BUS_SPEED_FROM_MRW; // I2C Bus Speed Array @@ -2897,6 +2901,55 @@ errlHndl_t i2cSendSlaveStop ( TARGETING::Target * i_target, continue; } + // Look for Clock Line (SCL) High such that 'stop' cmd will work + status_reg.value = 0x0ull; + size_t delay_ns = 0; + for ( ; + delay_ns <= I2C_RESET_POLL_DELAY_TOTAL_NS; + delay_ns += I2C_RESET_POLL_DELAY_NS) + { + err = i2cRegisterOp( DeviceFW::READ, + i_target, + &status_reg.value, + I2C_REG_STATUS, + i_args ); + + if( err ) + { + TRACFCOMP( g_trac_i2c, + ERR_MRK"Reading I2C Status Reg Failed!!" ); + break; + } + + if ( status_reg.scl_input_level != 0 ) + { + break; + } + + // Sleep before polling again + nanosleep( 0, I2C_RESET_POLL_DELAY_NS ); + + } + + if ( err ) + { + // We still need to send the slave stop to the other ports + // on this I2C engine + errlCommit( err, I2C_COMP_ID ); + continue; + } + + if ( delay_ns > I2C_RESET_POLL_DELAY_TOTAL_NS ) + { + // Even though we don't see the Clock Line High, just + // trace a warning here and continue to send the 'stop' cmd + TRACFCOMP( g_trac_i2c, INFO_MRK"i2cSendSlaveStop(): " + "Not seeing SCL High 0x%.16llX after 0x%X ns of " + "polling (max=0x%X)", + status_reg.value, delay_ns, + I2C_RESET_POLL_DELAY_TOTAL_NS ); + } + cmd.value = 0x0ull; cmd.with_stop = 1; diff --git a/src/usr/i2c/i2c.H b/src/usr/i2c/i2c.H index d644eae74..d2ba23009 100755 --- a/src/usr/i2c/i2c.H +++ b/src/usr/i2c/i2c.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -359,7 +359,8 @@ union status_reg_t uint64_t stop_error : 1; uint64_t upper_threshold : 7; uint64_t any_i2c_interrupt : 1; - uint64_t reserved0 : 2; + uint64_t waiting_for_i2c_busy : 1; + uint64_t error_in : 1; uint64_t i2c_port_history_busy : 1; uint64_t scl_input_level : 1; uint64_t sda_inupt_level : 1; -- cgit v1.2.1