Skip to content

Commit

Permalink
Add exp_i2c_scom driver that will be consumed by HB/SBE platforms
Browse files Browse the repository at this point in the history
This commit adds a new exp_i2c_scom.H file which contains two
functions, i2c_get_scom and i2c_put_scom. These functions will
take in a fapi2 OCMB target, an address and a buffer that either
contains scom data to write or space for scom data to be written
to. The functions use the fapi2::puti2c / fapi2::geti2c interfaces
to perform the scoms.

Change-Id: I4de680e187258cbfc57dd71f698dc1fc8760cefb
RTC:196806
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/67949
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com>
Reviewed-by: Louis Stermole <stermole@us.ibm.com>
Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com>
Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com>
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/67961
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>
  • Loading branch information
crgeddes authored and dcrowell77 committed Nov 6, 2018
1 parent c826f6a commit 0e15017
Show file tree
Hide file tree
Showing 7 changed files with 633 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

#include <mmio_access.H>
#include <generic/memory/lib/utils/c_str.H>
#include <generic/memory/lib/utils/endian_utils.H>

namespace mss
{
Expand Down Expand Up @@ -107,7 +108,7 @@ fapi2::ReturnCode putScom(
const fapi2::buffer<uint64_t>& i_data)
{
// Converts from the scom address to the MMIO address by shifting left by 3 bits
uint64_t l_scomAddr = i_scomAddr << 3;
uint64_t l_scomAddr = i_scomAddr << OCMB_ADDR_SHIFT;
return putMMIO64(i_target, l_scomAddr, i_data);
}

Expand Down Expand Up @@ -350,7 +351,7 @@ fapi2::ReturnCode getScom(
fapi2::buffer<uint64_t>& o_data)
{
// Converts from the scom address to the MMIO address by shifting left by 3 bits
uint64_t l_scomAddr = i_scomAddr << 3;
uint64_t l_scomAddr = i_scomAddr << OCMB_ADDR_SHIFT;
return getMMIO64(i_target, l_scomAddr, o_data);
}

Expand Down
100 changes: 0 additions & 100 deletions src/import/chips/ocmb/explorer/procedures/hwp/memory/exp_inband.H
Original file line number Diff line number Diff line change
Expand Up @@ -127,106 +127,6 @@ static const uint64_t EXPLR_IB_SENSOR_CACHE_ADDR = EXPLR_IB_MMIO_OFFSET | 0x4008
// Utilities
//--------------------------------------------------------------------------------

///
/// @brief Forces native data into LE order
/// @tparam T the data type to process
/// @param[in] i_input inputted data to process
/// @param[in,out] io_data vector to append data to
///
template < typename T >
void forceLE(const T& i_input, std::vector<uint8_t>& io_data)
{
// Temporary variable to process - we'll be doing bit shifts below
T l_temp = i_input;

for(size_t i = 0; i < sizeof(i_input); i++)
{
// Grab the lowe rorder byte and add it to the back of the vector
const uint8_t l_byte = l_temp & 0xFF;
io_data.push_back(l_byte);

// Shift higher byte value into lowest no matter existing endianness
l_temp >>= BITS_PER_BYTE;
}
}

///
/// @brief Forces native data into LE order for an array
/// @tparam T the data type to process
/// @param[in] i_input inputted data to process
/// @param[in] i_size size of the array
/// @param[in,out] io_data vector to append data to
///
template < typename T >
inline void forceLEArray(const T* i_input, const uint64_t i_size, std::vector<uint8_t>& io_data)
{
for(size_t i = 0; i < i_size; i++)
{
forceLE(i_input[i], io_data);
}
}

///
/// @brief Converts LE data into native order
/// @tparam T the data type to output to
/// @param[in] i_input inputted data to process
/// @param[in,out] io_idx current index
/// @param[out] o_data data that has been converted into native endianness
/// @return bool true if passing false if failing
/// @note Real FFDC will be handled outside
///
template < typename T >
bool readLE(const std::vector<uint8_t>& i_input, uint32_t& io_idx, T& o_data)
{
const uint32_t l_sz = static_cast<uint32_t>(sizeof(o_data));
io_idx = l_sz + io_idx;

// Checks that our final index is within the data range
// Note: we decrement the index prior, so equal to is ok
if(io_idx > i_input.size())
{
return false;
}

uint64_t l_idx = io_idx;

o_data = 0;

for(uint64_t i = 0; i < l_sz; i++)
{
l_idx--;
uint8_t v = i_input[l_idx];
o_data <<= BITS_PER_BYTE;
o_data |= v;
}

return true;
}

///
/// @brief Converts LE data into native order
/// @tparam T the data type to output to
/// @param[in] i_input inputted data to process
/// @param[in] i_size size of the array
/// @param[in,out] io_idx current index
/// @param[out] o_data data that has been converted into native endianness
/// @return bool true if passing false if failing
/// @note Real FFDC will be handled outside
///
template < typename T >
bool readLEArray(const std::vector<uint8_t>& i_input, const uint32_t i_size, uint32_t& io_idx, T* o_data)
{
// Loop while the readLE is still passing and we haven't looped through the array's boundaries
bool l_passing = true;

for(uint32_t i = 0; i < i_size && l_passing; ++i)
{
l_passing = readLE(i_input, io_idx, o_data[i]);
}

return l_passing;
}

///
/// @brief Converts user_input_msdg to little endian
/// @param[in] i_input user_input_msdg structure to convert
Expand Down
154 changes: 154 additions & 0 deletions src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@

#include <vector>
#include <lib/i2c/exp_i2c_fields.H>
#include <generic/memory/lib/utils/pos.H>
#include <generic/memory/lib/utils/endian_utils.H>

namespace mss
{
Expand Down Expand Up @@ -178,6 +180,158 @@ inline fapi2::ReturnCode is_ready(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CH
return fapi2::getI2c(i_target, l_size, l_cmd_id, l_data);
}

///
/// @brief Perform a register write operation on the given OCMB chip
/// @param[in] i_target the OCMB target
/// @param[in] i_addr The translated address on the OCMB chip
/// @param[in] i_data_buffer buffer of data we want to write to the register
/// @return FAPI2_RC_SUCCESS iff okay
///
inline fapi2::ReturnCode fw_reg_write(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
const uint32_t i_addr,
const fapi2::buffer<uint32_t>& i_data_buffer)
{
// create byte vector that will hold command bytes in sequence that will do the scom
std::vector<uint8_t> l_cmd_vector;
std::vector<uint8_t> l_le_addr_vector;
std::vector<uint8_t> l_le_data_vector;
uint32_t l_input_data = static_cast<uint32_t>(i_data_buffer);

forceLE(i_addr, l_le_addr_vector);
forceLE(l_input_data, l_le_data_vector);

// Start building the cmd vector for the write operation
l_cmd_vector.push_back(FW_REG_WRITE); // Byte 0 = 0x05 (FW_REG_WRITE)
l_cmd_vector.push_back(FW_WRITE_REG_DATA_SIZE); // Byte 1 = 0x08 (FW_SCOM_DATA_SIZE)

// i_addr and i_data_buffer were converted to LE above so we can
// write them directly to the cmd_vector in the same order they
// currently are
// Byte 2:5 = Address
l_cmd_vector.insert(l_cmd_vector.end(), l_le_addr_vector.begin(), l_le_addr_vector.end());
// Byte 6:9 = Data
l_cmd_vector.insert(l_cmd_vector.end(), l_le_data_vector.begin(), l_le_data_vector.end());

// Use fapi2 putI2c interface to execute command
FAPI_TRY(fapi2::putI2c(i_target, l_cmd_vector),
"I2C FW_REG_WRITE op failed to write to 0x%.8X on OCMB w/ fapiPos = 0x%.8X",
i_addr, mss::fapi_pos(i_target));

// Check status of operation
FAPI_TRY(fw_status(i_target),
"Invalid Status after FW_REG_WRITE operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X",
i_addr, mss::fapi_pos(i_target));


fapi_try_exit:
return fapi2::current_err;
}

///
/// @brief Perform a register write operation on the given OCMB chip
/// @param[in] i_target the OCMB target
/// @param[in] i_addr The translated address on the OCMB chip
/// @param[in] o_data_buffer buffer of data we will write the contents of the register to
/// @return FAPI2_RC_SUCCESS iff okay
///
inline fapi2::ReturnCode fw_reg_read(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
const uint32_t i_addr,
fapi2::buffer<uint32_t>& o_data_buffer)
{
// create byte vector that will hold command bytes in sequence that will do the scom
std::vector<uint8_t> l_cmd_vector;
std::vector<uint8_t> l_read_data;
std::vector<uint8_t> l_le_addr_vector;
uint32_t l_index = 0;
uint32_t l_read_value = 0;

forceLE(i_addr, l_le_addr_vector);

// Build the cmd vector for the Read
l_cmd_vector.push_back(FW_REG_ADDR_LATCH); // Byte 0 = 0x03 (FW_REG_ADDR_LATCH)
l_cmd_vector.push_back(FW_REG_ADDR_LATCH_SIZE); // Byte 1 = 0x04 (FW_REG_ADDR_LATCH_SIZE)

// i_addr was converted to LE above so we can write it
// directly to the cmd_vector in the same order it
// currently is in
// Byte 2:5 = Address
l_cmd_vector.insert(l_cmd_vector.end(), l_le_addr_vector.begin(), l_le_addr_vector.end());

// Use fapi2 putI2c interface to execute command
FAPI_TRY(fapi2::putI2c(i_target, l_cmd_vector),
"putI2c returned error for FW_REG_ADDR_LATCH operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X",
i_addr, mss::fapi_pos(i_target));

// Check i2c status after operation
FAPI_TRY(fw_status(i_target),
"Invalid Status after FW_REG_ADDR_LATCH operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X",
i_addr, mss::fapi_pos(i_target));

// Clear out cmd vector as i2c op is complete and we must prepare for next
l_cmd_vector.clear();

// Cmd vector is a single byte with FW_REG_READ code
l_cmd_vector.push_back(FW_REG_READ); // Byte 0 = 0x04 (FW_REG_READ)

// Use fapi2 getI2c interface to execute command
FAPI_TRY(fapi2::getI2c(i_target, FW_I2C_SCOM_READ_SIZE, l_cmd_vector, l_read_data),
"getI2c returned error for FW_REG_READ operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X",
i_addr, mss::fapi_pos(i_target));

// The first byte returned should be the size of the remaining data
// We requested FW_REG_ADDR_LATCH_SIZE bytes so that is what we
// expect to see as the first byte.
FAPI_ASSERT( (l_read_data.front() == FW_REG_ADDR_LATCH_SIZE),
fapi2::I2C_GET_SCOM_INVALID_READ_SIZE()
.set_TARGET(i_target)
.set_ADDRESS(i_addr)
.set_SIZE_RETURNED(l_read_data[0])
.set_SIZE_REQUESTED(FW_REG_ADDR_LATCH_SIZE),
"First byte of read data was expected to be 0x%lx but byte read = 0x%x",
FW_REG_ADDR_LATCH_SIZE, l_read_data[0] );

// Check i2c status after operation
FAPI_TRY(fw_status(i_target),
"Invalid Status after FW_REG_READ operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X",
i_addr, mss::fapi_pos(i_target));

// The OCMB is a 32-bit little endian engine so
// we must convert the buffer that we read into native
// incase native endian is different than LE
readLE(l_read_data, l_index, l_read_value);
o_data_buffer = l_read_value;


fapi_try_exit:
return fapi2::current_err;
}

///
/// @brief Perform a register write operation on the given OCMB chip
/// @param[in] i_addr The raw address that needs to be translated to IBM scom addr
/// @param[in] i_side LHS or RHS of the IBM i2c scom. IBM addresses expect 64 bits of
/// data returned from them so we must have a LHS and a RHS which is offset
/// by 4 bytes. This is because the OCMB is a 32 bit architecture
/// @return uint32 of translated address
///
inline uint32_t trans_ibm_i2c_scom_addr(const uint32_t i_addr,
const addrSide i_side)
{
return (i_side == LHS) ?
((LAST_THREE_BYTES_MASK & i_addr) << OCMB_ADDR_SHIFT) | IBM_SCOM_OFFSET_LHS | OCMB_UNCACHED_OFFSET :
((LAST_THREE_BYTES_MASK & i_addr) << OCMB_ADDR_SHIFT) | IBM_SCOM_OFFSET_RHS | OCMB_UNCACHED_OFFSET ;
}

///
/// @brief Perform a register write operation on the given OCMB chip
/// @param[in] i_addr The raw address that needs to be translated to Microchip scom addr
/// @return uint32 of translated address
///
inline uint32_t trans_micro_i2c_scom_addr(const uint32_t i_addr)
{
return (i_addr | OCMB_UNCACHED_OFFSET) ;
}

}// i2c
}// exp
}// mss
Expand Down

0 comments on commit 0e15017

Please sign in to comment.