diff options
author | Terry J. Opie <opiet@us.ibm.com> | 2011-08-05 08:51:38 -0500 |
---|---|---|
committer | Terry J. Opie <opiet@us.ibm.com> | 2011-08-15 13:57:29 -0500 |
commit | fa0113e4599fcca0c2d4c938c88d445d288a952a (patch) | |
tree | ca797228d6c31b9dcd3ed617f7a82e77d9e27138 /src/usr | |
parent | b0ceda93e7d5b6b06465a5fcc0b261a52dad987d (diff) | |
download | talos-hostboot-fa0113e4599fcca0c2d4c938c88d445d288a952a.tar.gz talos-hostboot-fa0113e4599fcca0c2d4c938c88d445d288a952a.zip |
I2C Device Driver Skeleton
Change-Id: I0b092ea67e5bb8789378041c8c3a6a3f5cf3025e
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/242
Reviewed-by: Terry J. Opie <opiet@us.ibm.com>
Tested-by: Jenkins Server
Diffstat (limited to 'src/usr')
-rwxr-xr-x | src/usr/i2c/i2c.C | 192 | ||||
-rwxr-xr-x | src/usr/i2c/i2c.H | 450 | ||||
-rw-r--r-- | src/usr/i2c/makefile | 8 | ||||
-rwxr-xr-x | src/usr/i2c/test/i2ctest.H | 113 | ||||
-rw-r--r-- | src/usr/i2c/test/makefile | 6 | ||||
-rw-r--r-- | src/usr/makefile | 2 | ||||
-rw-r--r-- | src/usr/targeting/targetservice.C | 12 |
7 files changed, 782 insertions, 1 deletions
diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C new file mode 100755 index 000000000..8d7aa8542 --- /dev/null +++ b/src/usr/i2c/i2c.C @@ -0,0 +1,192 @@ +/** + * @file i2c.C + * + * @brief Implementation of the i2c device driver + * + */ + +// ---------------------------------------------- +// Includes +// ---------------------------------------------- +#include <string.h> +#include <trace/interface.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <targeting/targetservice.H> +#include <devicefw/driverif.H> +#include <i2c/i2creasoncodes.H> + +#include "i2c.H" +// ---------------------------------------------- +// Trace definition +trace_desc_t* g_trac_i2c = NULL; +TRAC_INIT( & g_trac_i2c, "I2C", 4096 ); + +namespace I2C +{ + +// Register the perform Op with the routing code for Procs. +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::I2C, + TARGETING::TYPE_PROC, + i2cPerformOp ); + +// TODO - This will be added back in once the bug in the registration +// code has been fixed. Right now it will not compile with 2 registrations +// to the same function. +// Register the perform Op with the routing code for Memory Buffers. +//DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, +// DeviceFW::I2C, +// TARGETING::TYPE_MEMBUF, +// i2cPerformOp ); + +// ------------------------------------------------------------------ +// i2cPerformOp +// ------------------------------------------------------------------ +errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType, + TARGETING::Target * i_target, + void * io_buffer, + size_t & io_buflen, + int64_t i_accessType, + va_list i_args ) +{ + errlHndl_t err = NULL; + uint64_t addr = va_arg( i_args, uint64_t ); + + TRACFCOMP( g_trac_i2c, + ENTER_MRK"i2cPerformOp()" ); + + // -------------------------------------------------------------- + // NOTE: There are attributes that can be read for targetted + // devices (slaves). But since we don't have any of those + // targets yet, there isn't a way to test reading those + // attributes yet. I assume those will be added as full device + // driver testing is started on Simics. + // -------------------------------------------------------------- + if( i_opType == DeviceFW::READ ) + { + err = i2cRead( i_target, + addr, + io_buffer, + io_buflen ); + } + else if( i_opType == DeviceFW::WRITE ) + { + err = i2cWrite( i_target, + addr, + io_buffer, + io_buflen ); + } + else + { + TRACFCOMP( g_trac_i2c, + ERR_MRK"i2cPerformOp() - Unknown Operation Type!" ); + + /*@ + * @errortype + * @reasoncode I2C_INVALID_OP_TYPE + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid I2C_PERFORM_OP + * @userdata1 i_opType + * @userdata2 addr + * @devdesc Invalid Operation type. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + I2C_PERFORM_OP, + I2C_INVALID_OP_TYPE, + i_opType, + addr ); + + } + + TRACFCOMP( g_trac_i2c, + EXIT_MRK"i2cPerformOp() - %s", + ((NULL == err) ? "No Error" : "With Error") ); + + return err; +} // end i2cPerformOp + +// ------------------------------------------------------------------ +// i2cRead +// ------------------------------------------------------------------ +errlHndl_t i2cRead ( TARGETING::Target * i_target, + uint64_t i_addr, + void * o_buffer, + size_t & i_size ) +{ + errlHndl_t err = NULL; + + TRACFCOMP( g_trac_i2c, + ENTER_MRK"i2cRead()" ); + + do + { + // TODO - Functionality still needs to be added. + err = i2cSetup( i_target, + i_addr, + i_size, + true, + true ); + } while( 0 ); + + TRACFCOMP( g_trac_i2c, + EXIT_MRK"i2cRead()" ); + + return err; +} // end i2cRead + +// ------------------------------------------------------------------ +// i2cWrite +// ------------------------------------------------------------------ +errlHndl_t i2cWrite ( TARGETING::Target * i_target, + uint64_t i_addr, + void * i_buffer, + size_t & io_size ) +{ + errlHndl_t err = NULL; + + TRACFCOMP( g_trac_i2c, + ENTER_MRK"i2cWrite()" ); + + do + { + // TODO - Functionality still needs to be added. + err = i2cSetup( i_target, + i_addr, + io_size, + true, + false ); + } while( 0 ); + + TRACFCOMP( g_trac_i2c, + EXIT_MRK"i2cWrite()" ); + + return err; +} // end i2cWrite + +// ------------------------------------------------------------------ +// i2cSetup +// ------------------------------------------------------------------ +errlHndl_t i2cSetup ( TARGETING::Target * i_target, + uint64_t i_addr, + size_t & i_size, + bool i_withStop, + bool i_readNotWrite ) +{ + errlHndl_t err = NULL; + + TRACFCOMP( g_trac_i2c, + ENTER_MRK"i2cSetup()" ); + + do + { + // TODO - Functionality still needs to be added. + } while( 0 ); + + TRACFCOMP( g_trac_i2c, + EXIT_MRK"i2cSetup()" ); + + return err; +} // end i2cSetup + +} // end namespace I2C diff --git a/src/usr/i2c/i2c.H b/src/usr/i2c/i2c.H new file mode 100755 index 000000000..75e4554dd --- /dev/null +++ b/src/usr/i2c/i2c.H @@ -0,0 +1,450 @@ +#ifndef __I2C_H +#define __I2C_H + +/** + * @file i2c.H + * + * @brief Provides the interfaces for the i2c device driver + * + */ + +// ---------------------------------------------- +// Includes +// ---------------------------------------------- +#include <errl/errltypes.H> + +namespace I2C +{ + +/** + * @brief FIFO size (width) in bytes. This dictates how many bytes + * we can read/write in one FIFO access. + */ +#define I2C_FIFO_SIZE 4 + +/** + * @brief FIFO capacity in bytes. This dictates the maximum number + * of bytes that the FIFO can hold. + */ +#define I2C_MAX_FIFO_CAPACITY 8 + +/** + * @brief I2C Clock setting values + * + * The clock divisors are found by using a 600Mhz local bus, using the + * equation that was given in the I2C Master Spec. + * + */ +#define I2C_MAX_BUS_SPEED 400 +#define I2C_CLOCK_DIVISOR_100KHZ 1499 // 0x5DB +#define I2C_CLOCK_DIVISOR_400KHZ 374 // 0x176 + +/** + * @brief I2C Master Base Addresses + */ +#define I2C_MASTER0_BASE 0x00 +#define I2C_MASTER1_BASE 0x20 +#define I2C_MASTER2_BASE 0x40 + +/** +* @brief I2C FIFO register definition +* Address 0x00 +*/ +union fiforeg +{ + uint64_t value; + uint8_t bytes[8]; + struct + { + uint64_t byte_0 : 8; + uint64_t byte_1 : 8; + uint64_t byte_2 : 8; + uint64_t byte_3 : 8; + uint64_t byte_4 : 8; + uint64_t byte_5 : 8; + uint64_t byte_6 : 8; + uint64_t byte_7 : 8; + } PACKED; +} fifo_reg_t; + +/** + * @brief I2C Command register definition. + * Address 0x01 + */ +union cmdreg +{ + uint64_t value; + struct + { + uint64_t with_start : 1; + uint64_t with_addr : 1; + uint64_t read_continue : 1; // Not Supported at this time + uint64_t with_stop : 1; + uint64_t reserved : 4; + uint64_t device_addr : 7; + uint64_t read_not_write : 1; + uint64_t length_b : 16; + uint64_t padding : 32; + } PACKED; +} command_reg_t; + +/** + * @brief I2C Mode register definition + * Address 0x02 + */ +union modereg +{ + uint64_t value; + struct + { + uint64_t bit_rate_div : 16; + uint64_t port_num : 6; + uint64_t reserved : 6; + uint64_t enhanced_mode : 1; + uint64_t diag_mode : 1; + uint64_t pacing_allow_mode : 1; + uint64_t wrap_mode : 1; + uint64_t padding : 32; + } PACKED; +} mode_reg_t; + +/** + * @brief Watermark register definition + * Address 0x03 + */ +union watermarkreg +{ + uint64_t value; + struct + { + uint64_t reserved0 : 16; + uint64_t high : 4; + uint64_t reserved1 : 4; + uint64_t low : 4; + uint64_t reserved2 : 4; + uint64_t padding : 32; + } PACKED; +} watermark_reg_t; + +/** + * @brief Interrupt Mask register definition + * Address 0x04 + */ +union intmaskreg +{ + uint64_t value; + struct + { + uint64_t reserved0 : 16; + uint64_t invalid_cmd : 1; + uint64_t lbus_parity_error : 1; + uint64_t backend_overrun_error : 1; + uint64_t backend_access_error : 1; + uint64_t arbitration_lost_error : 1; + uint64_t nack_received_error : 1; + uint64_t data_request : 1; + uint64_t command_complete : 1; + uint64_t stop_error : 1; + uint64_t i2c_busy : 1; + uint64_t not_i2c_busy : 1; + uint64_t reserved1 : 1; + uint64_t scl_eq_1 : 1; + uint64_t scl_eq_0 : 1; + uint64_t sda_eq_1 : 1; + uint64_t sda_eq_0 : 1; + uint64_t padding : 32; + } PACKED; +} interrupt_mask_reg_t; + +/** + * @brief Interrupt Condition register definition + * Address 0x05 + */ +union intcondreg +{ + uint64_t value; + struct + { + uint64_t reserved0 : 16; + uint64_t invalid_cmd : 1; + uint64_t lbus_parity_error : 1; + uint64_t backend_overrun_error : 1; + uint64_t backend_access_error : 1; + uint64_t arbitration_lost_error : 1; + uint64_t nack_received_error : 1; + uint64_t data_request : 1; + uint64_t command_complete : 1; + uint64_t stop_error : 1; + uint64_t i2c_busy : 1; + uint64_t not_i2c_busy : 1; + uint64_t reserved1 : 1; + uint64_t scl_eq_1 : 1; + uint64_t scl_eq_0 : 1; + uint64_t sda_eq_1 : 1; + uint64_t sda_eq_0 : 1; + uint64_t padding : 32; + } PACKED; +} interrupt_cond_reg_t; + +/** + * @brief Interrupt register definition + * Address 0x06 + */ +union interruptreg +{ + uint64_t value; + struct + { + uint64_t reserved0 : 16; + uint64_t invalid_cmd : 1; + uint64_t lbus_parity_error : 1; + uint64_t backend_overrun_error : 1; + uint64_t backend_access_error : 1; + uint64_t arbitration_lost_error : 1; + uint64_t nack_received_error : 1; + uint64_t data_request : 1; + uint64_t command_complete : 1; + uint64_t stop_error : 1; + uint64_t i2c_busy : 1; + uint64_t not_i2c_busy : 1; + uint64_t reserved1 : 1; + uint64_t scl_eq_1 : 1; + uint64_t scl_eq_0 : 1; + uint64_t sda_eq_1 : 1; + uint64_t sda_eq_0 : 1; + uint64_t padding: 32; + } PACKED; +} interrupt_reg_t; + +/** + * @brief Status register definition + * Address 0x07 + */ +union statusreg +{ + uint64_t value; + struct + { + uint64_t invalid_cmd : 1; + uint64_t lbus_parity_error : 1; + uint64_t backend_overrun_error : 1; + uint64_t backend_access_error : 1; + uint64_t arbitration_lost_error : 1; + uint64_t nack_received_error : 1; + uint64_t data_request : 1; + uint64_t command_complete : 1; + uint64_t stop_error : 1; + uint64_t upper_threshold : 7; + uint64_t any_i2_interrupt : 1; + uint64_t reserved0 : 2; + uint64_t i2c_port_history_busy : 1; + uint64_t scl_input_level : 1; + uint64_t sda_inupt_level : 1; + uint64_t i2c_port_busy : 1; + uint64_t i2c_interface_busy : 1; + uint64_t fifo_entry_count : 8; + uint64_t padding : 32; + } PACKED; +} status_reg_t; + +/** + * @brief Extended Status register definition + * Address 0x08 + */ +union extstatusreg +{ + uint64_t value; + struct + { + uint64_t fifo_size : 8; + uint64_t reserved0 : 3; + uint64_t msm_current_state : 5; + uint64_t scl_in_syn : 1; + uint64_t sda_in_syn : 1; + uint64_t s_scl : 1; + uint64_t s_sda : 1; + uint64_t m_scl : 1; + uint64_t m_sda : 1; + uint64_t high_water : 1; + uint64_t low_water : 1; + uint64_t i2c_busy : 1; + uint64_t self_busy : 1; + uint64_t reserved1 : 1; + uint64_t i2c_version : 5; + uint64_t padding : 32; + } PACKED; +} extended_status_reg_t; + +/** + * @brief Residual Front/Back end length register definition + * Address 0x09 + */ +union residuallengthreg +{ + uint64_t value; + struct + { + uint64_t front_end_length : 16; + uint64_t back_end_length : 16; + uint64_t padding : 32; + } PACKED; +} residual_length_reg_t; + +/** + * @brief Port Busy register definition + * Address 0x0A + */ +union portbusyreg +{ + uint64_t value; + struct + { + uint64_t port0_busy : 1; + uint64_t port1_busy : 1; + uint64_t port2_busy : 1; + uint64_t port3_busy : 1; + uint64_t port4_busy : 1; + uint64_t port5_busy : 1; + uint64_t port6_busy : 1; + uint64_t port7_busy : 1; + uint64_t port8_busy : 1; + uint64_t port9_busy : 1; + uint64_t port10_busy : 1; + uint64_t port11_busy : 1; + uint64_t port12_busy : 1; + uint64_t port13_busy : 1; + uint64_t port14_busy : 1; + uint64_t port15_busy : 1; + uint64_t port16_busy : 1; + uint64_t port17_busy : 1; + uint64_t port18_busy : 1; + uint64_t port19_busy : 1; + uint64_t port20_busy : 1; + uint64_t port21_busy : 1; + uint64_t port22_busy : 1; + uint64_t port23_busy : 1; + uint64_t port24_busy : 1; + uint64_t port25_busy : 1; + uint64_t port26_busy : 1; + uint64_t port27_busy : 1; + uint64_t port28_busy : 1; + uint64_t port29_busy : 1; + uint64_t port30_busy : 1; + uint64_t port31_busy : 1; + uint64_t padding : 32; + } PACKED; +} port_busy_reg_t; + + +/** +* +* @brief Perform an I2C access operation. It follows a pre-defined +* prototype function in order to be registered with the device +* driver framework. +* +* @param[in] i_opType - Operation Type - See DeviceFW::OperationType in +* driververif.H +* +* @param[in] i_target - I2C Target device +* +* @param [in/out] io_buffer +* INPUT: Pointer to the data that will be written to the target +* device. +* OUTPUT: Pointer to the data that was read from the target device. +* +* @param [in/out] io_buflen +* INPUT: Length of the buffer to be written to target device. +* OUTPUT: Length of buffer that was written, or length of buffer +* to be read from target device. +* +* @param [in] i_accessType - Access Type - See DeviceFW::AccessType in +* usrif.H +* +* @param [in] i_args - This is an argument list for the device driver +* framework. In this function there is only one argument, which +* is the I2C Address that is needed for bits 8:14 of the I2C +* Command register. +* +* @return errlHndl_t - NULL if successful, otherwise a pointer to the +* error log. +* +*/ +errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType, + TARGETING::Target * i_target, + void * io_buffer, + size_t & io_buflen, + int64_t i_accessType, + va_list i_args ); + +/** + * @brief This function will do the real work of reading from the I2C + * device. + * + * @param[in] i_target - The device target to read from. + * + * @param[in] i_addr - The I2C address to use for the read. + * + * @param[out] o_buffer - The buffer to place the retrieved data. + * + * @param[in] i_size - The size of the data to read and place in the + * buffer. + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to + * the error log. + */ +errlHndl_t i2cRead ( TARGETING::Target * i_target, + uint64_t i_addr, + void * o_buffer, + size_t & i_size ); + +/** + * @brief This function will do the real work of writinging to the I2C + * device. + * + * @param[in] i_target - The device target to write to. + * + * @param[in] i_addr - The I2C address to use for the write. + * + * @param[in] i_buffer - The buffer containing the data to be written + * to the target device. + * + * @param[in/out] i_size - INPUT: The size of the data to write to the + * target device. OUTPUT: The size of the data buffer written. + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to + * the error log. + + */ +errlHndl_t i2cWrite ( TARGETING::Target * i_target, + uint64_t i_addr, + void * i_buffer, + size_t & io_size ); + +/** + * @brief This function will do the I2C setup of the Address/Command registers + * before issuing the 'go' on the I2C bus. + * + * @param[in] i_target - The target device. + * + * @param[in] i_addr - The I2C address to use for the operation. + * + * @param[in] i_size - The size of the data that will be read/written. + * + * @param[in] i_withStop - Whether or not to set the with_stop bit in the + * I2C Command register. + * + * @param[in] i_readNotWrite - true if doing a read operation, false if + * doing a write operation. + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to + * the error log. + */ +errlHndl_t i2cSetup ( TARGETING::Target * i_target, + uint64_t i_addr, + size_t & i_size, + bool i_withStop, + bool i_readNotWrite ); + +}; // end I2C namespace + +#endif // __I2C_H diff --git a/src/usr/i2c/makefile b/src/usr/i2c/makefile new file mode 100644 index 000000000..7ce5033bf --- /dev/null +++ b/src/usr/i2c/makefile @@ -0,0 +1,8 @@ +ROOTPATH = ../../.. +MODULE = i2c + +OBJS = i2c.o + +SUBDIRS = test.d + +include ${ROOTPATH}/config.mk diff --git a/src/usr/i2c/test/i2ctest.H b/src/usr/i2c/test/i2ctest.H new file mode 100755 index 000000000..3828cf889 --- /dev/null +++ b/src/usr/i2c/test/i2ctest.H @@ -0,0 +1,113 @@ +#ifndef __I2CTEST_H +#define __I2CTEST_H + +/** + * @file i2ctest.H + * + * @brief Test case for I2C code +*/ + +#include <cxxtest/TestSuite.H> +#include <errl/errlmanager.H> +#include <errl/errlentry.H> +#include <errl/errltypes.H> +#include <devicefw/driverif.H> +#include <i2c/i2creasoncodes.H> + +extern trace_desc_t* g_trac_i2c; + +using namespace TARGETING; + +// Address and data to read/write +struct testI2CAddrData +{ + uint32_t addr; + uint64_t data; +}; + +// Test table values +const testI2CAddrData g_i2cAddrTable[] = +{ + // Write data to be ORed with read value + {0x13030007, 0x0000040000000000}, + {0x13010002, 0x00000C0000000000}, +}; + +const uint32_t g_i2cmAddrTableSz = + sizeof(g_i2cAddrTable)/sizeof(testI2CAddrData); + + +class I2CTest: public CxxTest::TestSuite +{ +public: + + /** + * @brief I2C test #1 + * Write value and read back to verify + */ + void testI2C1(void) + { + errlHndl_t l_err = NULL; + TS_TRACE( "I2C Test 1: its running!" ); + + do + { + TARGETING::TargetService& targetService = TARGETING::targetService(); + TARGETING::Target* l_testTarget = NULL; + targetService.masterProcChipTargetHandle( l_testTarget ); + + if( NULL == l_testTarget ) + { + TS_TRACE( "I2C Test - PROC test target is NULL!" ); + break; + } + + size_t l_size = sizeof(uint64_t); + testI2CAddrData l_testEntry = g_i2cAddrTable[0]; + + // -------------------------------------------- + // NOTE: The following doesn't actually read + // or write any data, it is strictly there to + // prove that the interfaces are working. The + // real tests will be added at a later time. + // -------------------------------------------- + + // Perform I2C write + uint64_t l_data = 0; + + l_err = deviceOp( DeviceFW::WRITE, + l_testTarget, + &l_data, + l_size, + DEVICE_I2C_ADDRESS(l_testEntry.addr) ); + + if( l_err ) + { + break; + } + + // Perform I2C read + l_err = deviceOp( DeviceFW::READ, + l_testTarget, + &l_data, + l_size, + DEVICE_I2C_ADDRESS(l_testEntry.addr) ); + + + } while( 0 ); + + if (l_err) + { + TS_FAIL("testI2C1 failed! Error committed."); + errlCommit(l_err); + } + else + { + TS_TRACE("testI2C1 runs successfully!"); + } + + return; + } +}; + +#endif diff --git a/src/usr/i2c/test/makefile b/src/usr/i2c/test/makefile new file mode 100644 index 000000000..6e8623758 --- /dev/null +++ b/src/usr/i2c/test/makefile @@ -0,0 +1,6 @@ +ROOTPATH = ../../../.. + +MODULE = testi2c +TESTS = *.H + +include ${ROOTPATH}/config.mk diff --git a/src/usr/makefile b/src/usr/makefile index cfd8aba1a..dc1bffa15 100644 --- a/src/usr/makefile +++ b/src/usr/makefile @@ -4,6 +4,6 @@ OBJS = module_init.o SUBDIRS = example.d trace.d cxxtest.d testcore.d errl.d devicefw.d \ scom.d xscom.d targeting.d initservice.d hwpf.d \ - ecmddatabuffer.d isteps.d pnor.d + ecmddatabuffer.d isteps.d pnor.d i2c.d include ${ROOTPATH}/config.mk diff --git a/src/usr/targeting/targetservice.C b/src/usr/targeting/targetservice.C index 305e96ca7..df713614a 100644 --- a/src/usr/targeting/targetservice.C +++ b/src/usr/targeting/targetservice.C @@ -470,6 +470,18 @@ void TargetService::dump() const TARG_INF("XSCOM Chip ID = 0x%X",l_xscomChipInfo.chipId); } + I2cChipInfo l_i2cChipInfo = {0}; + if( (*iv_targets)[i].tryGetAttr<ATTR_I2C_CHIP_INFO>( l_i2cChipInfo ) ) + { + TARG_INF( "I2C Bus Speed = 0x%X", + l_i2cChipInfo.busSpeed ); + TARG_INF( "I2C Device Address = 0x%X", + l_i2cChipInfo.deviceAddr ); + TARG_INF( "I2C Device Port = 0x%X", + l_i2cChipInfo.devicePort ); + TARG_INF( "I2C Master Engine = 0x%X", + l_i2cChipInfo.deviceMasterEng ); + } } } else |