diff options
Diffstat (limited to 'src/occ_405/firdata/lpc.c')
-rw-r--r-- | src/occ_405/firdata/lpc.c | 297 |
1 files changed, 193 insertions, 104 deletions
diff --git a/src/occ_405/firdata/lpc.c b/src/occ_405/firdata/lpc.c index fe69efc..ffe2b48 100644 --- a/src/occ_405/firdata/lpc.c +++ b/src/occ_405/firdata/lpc.c @@ -1,11 +1,11 @@ /* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ -/* $Source: src/occ/firdata/lpc.C $ */ +/* $Source: src/occ_405/firdata/lpc.c $ */ /* */ /* OpenPOWER OnChipController Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -26,14 +26,19 @@ #include <native.h> #include <lpc.h> #include <trac_interface.h> +#include <scom_util.h> #define LPCHC_FW_SPACE 0xF0000000 /**< LPC Host Controller FW Space */ #define LPCHC_MEM_SPACE 0xE0000000 /**< LPC Host Controller Mem Space */ #define LPCHC_IO_SPACE 0xD0010000 /**< LPC Host Controller I/O Space */ #define LPCHC_REG_SPACE 0xC0012000 /**< LPC Host Ctlr Register Space */ - #define ECCB_NON_FW_RESET_REG 0x000B0001 /**< ECCB Reset Reg (non-FW) */ +#define LPC_BASE_REG 0x00090040 /**< LPC Base Address Register */ +#define LPC_CMD_REG 0x00090041 /**< LPC Command Register */ +#define LPC_DATA_REG 0x00090042 /**< LPC Data Register */ +#define LPC_STATUS_REG 0x00090043 /**< LPC Status Register */ + #define ECCB_CTL_REG 0x000B0020 /**< ECCB Control Reg (FW) */ #define ECCB_RESET_REG 0x000B0021 /**< ECCB Reset Reg (FW) */ #define ECCB_STAT_REG 0x000B0022 /**< ECCB Status Reg (FW) */ @@ -43,8 +48,8 @@ 1101.0100.0000.000x.0000.0001.0000.0000.<address> */ #define ECCB_CTL_REG_DEFAULT 0xD400010000000000 -/* Error bits: 41-43 56 (52cmd complete) (not 57: only non-fw use) */ -#define ECCB_STAT_REG_ERROR_MASK 0x0000000000700080 /**< Error Bits */ +/* Error bits: wh_todo comments here */ +#define LPC_STAT_REG_ERROR_MASK 0x0000000000000000 /**< Error Bits */ //wh_todo correctly set mask /**< OPB LPCM Sync FIR Reg - used to read the FIR*/ #define OPB_LPCM_FIR_REG 0x01010C00 @@ -63,67 +68,65 @@ #define ECCB_RESET_LPC_FAST_RESET (1ULL << 62) /**< bit 1 Fast reset */ -#define ECCB_POLL_TIME_NS 400000 /**< max time should be 400ms */ -//dc99 #define ECCB_POLL_INCR_NS 10 /**< minimum increment during poll */ -#define ECCB_POLL_INCR_NS 100000 /**< increase for testing */ +#define LPC_POLL_TIME_NS 400000 /**< max time should be 400ms */ +#define LPC_POLL_INCR_NS 100000 /**< increase for testing */ #define LPCHC_SYNC_CYCLE_COUNTER_INFINITE 0xFF000000 -int TRACE_LPC = 0; -#define TRACZCOMP(args...) if(TRACE_LPC){TRACFCOMP(args);} +/** + * @brief LPC Base Register Layout +*/ +typedef union +{ + + uint64_t data64; -/* Set to enable LPC tracing. */ -/* #define LPC_TRACING 1 */ -#ifdef LPC_TRACING -#define LPC_TRACFCOMP(des,printf_string,args...) \ - TRACFCOMP(des,printf_string,##args) /* FIX FIRDATA */ -#else -#define LPC_TRACFCOMP(args...) -#endif + struct + { + /* unused sections should be set to zero */ + uint64_t unused0 : 8; /**< 0:7 */ + uint64_t base_addr : 24; /**< 8:31 */ + uint64_t unused1 : 31; /**< 32:62 */ + uint64_t disable : 1; /**< 63 */ + }; +} BaseReg_t; /** - * @brief ECCB Control Register Layout + * @brief LPC Control Register Layout */ typedef union { + uint64_t data64; + struct { /* unused sections should be set to zero */ - uint64_t magic1 : 4; /**< 0:3 = b1101 per spec */ - uint64_t data_len : 4; /**< 4:7 = b0100 means 4 byte */ - uint64_t unused1 : 7; /**< 8:14 */ - uint64_t read_op : 1; /**< 15 = set for read operation */ - uint64_t unused2 : 7; /**< 16:22 */ - uint64_t addr_len : 3; /**< 23:25 = b100 means 4 byte */ - uint64_t unused3 : 6; /**< 26:31 */ - uint64_t address : 32; /**< 32:63 = LPC Address */ + // rnw == read not write + uint64_t rnw : 1; /**< 0 = Setting to 1 causes read */ + uint64_t unused0 : 4; /**< 1:4 */ + uint64_t size : 7; /**< 5:11 */ + uint64_t unused1 : 20; /**< 12:31 */ + uint64_t address : 32; /**< 32:63 = LPC Address */ }; -} ControlReg_t; +} CommandReg_t; /** - * @brief ECCB Status Register Layout + * @brief LPC Status Register Layout */ typedef union { uint64_t data64; struct { - uint64_t unused : 6; /**< 0:5 */ - uint64_t read_data : 32; /**< 6:37 */ - uint64_t unused1 : 3; /**< 38:40 */ - uint64_t eccb_err : 3; /**< 41:43 = ECCB_Error_Info */ - uint64_t busy : 1; /**< 44 = Operation Busy */ - uint64_t unused2 : 7; /**< 45:51 */ - uint64_t op_done : 1; /**< 52 = Command Complete */ - uint64_t unused3 : 3; /**< 53:55 */ - uint64_t addr_parity_err : 1; /**< 56 = ECC Address Register - Parity Error */ - uint64_t unused4 : 7; /**< 57:63 */ + uint64_t op_done : 1; /**< 0 */ + uint64_t unused0 : 9; /**< 1:9 */ + uint64_t opb_valid : 1; /**< 10 */ + uint64_t opb_ack : 1; /**< 11 */ + uint64_t unused1 : 52; /**< 12:63 */ }; } StatusReg_t; - uint32_t checkAddr(LpcTransType i_type, uint32_t i_addr) { @@ -141,8 +144,8 @@ uint32_t checkAddr(LpcTransType i_type, } -errorHndl_t pollComplete(const ControlReg_t* i_ctrl, - StatusReg_t* o_stat) +errorHndl_t pollComplete(CommandReg_t* i_ctrl, + StatusReg_t* o_stat) { errorHndl_t l_err = NO_ERROR; @@ -151,11 +154,11 @@ errorHndl_t pollComplete(const ControlReg_t* i_ctrl, uint64_t loop = 0; do { - xscom_read( ECCB_STAT_REG, &(o_stat->data64) ); - LPC_TRACFCOMP( "writeLPC> Poll on ECCB Status, " - "poll_time=0x%.16x, stat=0x%.16x", - poll_time, - o_stat->data64 ); + SCOM_Trgt_t l_target; + l_target.type = TRGT_PROC; + l_target.isMaster = TRUE; + l_err = SCOM_getScom(l_target, LPC_STATUS_REG, &(o_stat->data64)); + if( l_err ) { break; @@ -166,19 +169,19 @@ errorHndl_t pollComplete(const ControlReg_t* i_ctrl, break; } - /* want to start out incrementing by small numbers then get bigger + /* Want to start out incrementing by small numbers then get bigger to avoid a really tight loop in an error case so we'll increase the wait each time through */ - sleep( ECCB_POLL_INCR_NS*(++loop) ); - poll_time += ECCB_POLL_INCR_NS * loop; - } while ( poll_time < ECCB_POLL_TIME_NS ); + sleep( LPC_POLL_INCR_NS*(++loop) ); + poll_time += LPC_POLL_INCR_NS * loop; + } while ( poll_time < LPC_POLL_TIME_NS ); /* Check for hw errors or timeout if no previous logs */ if( (l_err == NO_ERROR) && - ((o_stat->data64 & ECCB_STAT_REG_ERROR_MASK) + ((o_stat->data64 & LPC_STAT_REG_ERROR_MASK) || (!o_stat->op_done)) ) { - TRACFCOMP( "LpcDD::pollComplete> LPC error or timeout: addr=0x%.8X, status=0x%.8X%.8X", + TRAC_ERR( "LpcDD::pollComplete> LPC error or timeout: addr=0x%.8X, status=0x%.8X%.8X", i_ctrl->address, (uint32_t)(o_stat->data64>>32), (uint32_t)o_stat->data64 ); l_err = -1; break; @@ -186,6 +189,7 @@ errorHndl_t pollComplete(const ControlReg_t* i_ctrl, } while(0); return l_err; + } @@ -197,7 +201,10 @@ errorHndl_t lpc_read( LpcTransType i_type, size_t i_size ) { errorHndl_t l_err = NO_ERROR; - uint32_t l_addr = 0; + int32_t l_addr = 0; + uint64_t l_ret; + uint32_t l_shift_amount; + uint64_t l_temp_data; do { if( o_data == NULL ) @@ -207,40 +214,85 @@ errorHndl_t lpc_read( LpcTransType i_type, break; } + /* Generate the full absolute LPC address */ l_addr = checkAddr( i_type, i_addr ); - /* Execute command. */ - ControlReg_t eccb_cmd; - eccb_cmd.data64 = ECCB_CTL_REG_DEFAULT; - eccb_cmd.data_len = i_size; - eccb_cmd.read_op = 1; - eccb_cmd.addr_len = sizeof(l_addr); - eccb_cmd.address = l_addr; - xscom_write( ECCB_CTL_REG, eccb_cmd.data64 ); + /* Setup command */ + CommandReg_t lpc_cmd; + lpc_cmd.rnw = 1; //Indicate read not write + lpc_cmd.size = i_size; + lpc_cmd.address = l_addr; + + /* Execute command via Scom */ + SCOM_Trgt_t l_target; + l_target.type = TRGT_PROC; + l_target.isMaster = TRUE; + + //First write the address we want to read from in the + //LPC_CMD_REG scom address + l_err = SCOM_putScom(l_target, LPC_CMD_REG, lpc_cmd.data64); + if(l_err != SUCCESS) + { + TRAC_ERR("lpc_read: SCOM_putScom failed to write to LPC_CMD_REG command rc=0x%08x", + (uint32_t)l_err); + break; + } /* Poll for completion */ - StatusReg_t eccb_stat; - l_err = pollComplete( &eccb_cmd, &eccb_stat ); + StatusReg_t lpc_status; + l_err = pollComplete( &lpc_cmd, &lpc_status ); if( l_err ) { break; } - /* Copy data out to caller's buffer. */ - if( i_size <= sizeof(uint32_t) ) + // Read data from the LPC_DATA_REG + l_err = SCOM_getScom(l_target, LPC_DATA_REG, &l_ret); + if(l_err != SUCCESS) + { + TRAC_ERR("lpc_read: SCOM_getScom failed rc=0x%08x", (uint32_t)l_err); + break; + } + + //The scom returns the data in the byte offset represented by last + //3 bits of the address. For example, addr 0x21 will have have data + //starting in byte1 on value returned from scom. + //addr & 0x7 <-- this gives the byte offset + //7 - (addr & 0x7) <-- subratcing from 7 as the data is left aligned + //adding (size - 1) <-- to incorporate reading more than one byte + //multiply by 8 to convert from byte to bits + l_shift_amount = (7 - ((l_addr & 0x7) + (i_size-1))) * 8; + l_temp_data = l_ret >> l_shift_amount; + + //Had some weird problems with memcpy, that's why typecasting + //to the size of data asked. + if (i_size == sizeof(uint8_t)) + { + uint8_t* l_temp_ptr = (uint8_t*)(o_data); + *l_temp_ptr = l_temp_data; + } + else if (i_size == sizeof(uint16_t)) + { + uint16_t* l_temp_ptr = (uint16_t*)(o_data); + *l_temp_ptr = l_temp_data; + } + else if (i_size == sizeof(uint32_t)) + { + uint32_t* l_temp_ptr = (uint32_t*)(o_data); + *l_temp_ptr = l_temp_data; + } + else if (i_size == sizeof(uint64_t)) { - uint32_t tmpbuf = eccb_stat.read_data; - memcpy( o_data, &tmpbuf, i_size ); + uint64_t* l_temp_ptr = (uint64_t*)(o_data); + *l_temp_ptr = l_temp_data; } else { - TRACFCOMP( "readLPC> Unsupported buffer size : %d", i_size ); + TRAC_ERR("lpc_read: unsupported size length"); l_err = -1; break; } } while(0); - LPC_TRACFCOMP( "readLPC> %08X[%d] = %08X", l_addr, i_size, *reinterpret_cast<uint32_t*>( o_data ) >> (8 * (4 - i_size)) ); - return l_err; } @@ -251,51 +303,88 @@ errorHndl_t lpc_write( LpcTransType i_type, { errorHndl_t l_err = NO_ERROR; uint32_t l_addr = 0; + uint64_t l_write_data = 0; + uint64_t l_data = 0; + uint32_t l_shift_amount; do { /* Generate the full absolute LPC address */ l_addr = checkAddr( i_type, i_addr ); - uint64_t eccb_data = 0; - /* Left-justify user data into data register. */ - switch ( i_size ) + /* Setup Write Command */ + CommandReg_t lpc_cmd; + lpc_cmd.rnw = 0; //Indicate write + lpc_cmd.size = i_size; + lpc_cmd.address = l_addr; + + /* Setup Write command via Scom */ + SCOM_Trgt_t l_target; + l_target.type = TRGT_PROC; + l_target.isMaster = TRUE; + + //First write the address we want to write to in LPC_CMD_REG + l_err = SCOM_putScom(l_target, LPC_CMD_REG, lpc_cmd.data64); + if(l_err != SUCCESS) { - case 1: - eccb_data = (uint64_t) - (*(const uint8_t*)(i_data)) << 56; - break; - case 2: - eccb_data = (uint64_t) - (*(const uint16_t*)( i_data ) ) << 48; - break; - case 4: - eccb_data = (uint64_t) - (*(const uint32_t*)( i_data ) ) << 32; - break; - default: - TRACFCOMP( "writeLPC> Unsupported buffer size : %d", i_size ); - break; + TRAC_ERR("ERROR> lpc_write: SCOM_putScom failed to write to LPC_CMD_REG command: rc=0x%08x", + (uint32_t)l_err); + break; } - /* Write data out */ - TRACZCOMP("ECCB_DATA_REG=%.8X%.8X",(uint32_t)(eccb_data>>32),(uint32_t)eccb_data); - xscom_write( ECCB_DATA_REG, eccb_data ); + //There were some weird memcpy problems. That's why, typecasting + //to the size of data requested to write + if (i_size == sizeof(uint8_t)) + { + l_write_data = (*i_data); + } + else if (i_size == sizeof(uint16_t)) + { + uint16_t* l_temp_ptr = (uint16_t*)(i_data); + l_write_data = *l_temp_ptr; + } + else if (i_size == sizeof(uint32_t)) + { + uint32_t* l_temp_ptr = (uint32_t*)(i_data); + l_write_data = *l_temp_ptr; + } + else if (i_size == sizeof(uint64_t)) + { + uint64_t* l_temp_ptr = (uint64_t*)(i_data); + l_write_data = *l_temp_ptr; + } + else + { + TRAC_ERR("lpc_write: unsupported size length"); + l_err = -1; + break; + } - /* Execute command. */ - ControlReg_t eccb_cmd; - eccb_cmd.data64 = ECCB_CTL_REG_DEFAULT; - eccb_cmd.data_len = i_size; - eccb_cmd.read_op = 0; - eccb_cmd.addr_len = sizeof(l_addr); - eccb_cmd.address = l_addr; - xscom_write( ECCB_CTL_REG, eccb_cmd.data64 ); - TRACZCOMP("ECCB_CTL_REG=%.8X%.8X",(uint32_t)(eccb_cmd.data64>>32),(uint32_t)eccb_cmd.data64); + //The scom expects the data in the byte offset represented by last + //3 bits of the address. For example, addr 0x21 will have have data + //starting in byte1 on value returned from scom. + //addr & 0x7 <-- this gives the byte offset + //7 - (addr & 0x7) <-- subratcing from 7 as the data in the scom reg + //is expected to be left aligned + //adding (size - 1) <-- to incorporate reading more than one byte + //multiply by 8 to convert from byte to bits + l_shift_amount = (7 - ((l_addr & 0x7) + (i_size-1))) * 8; + l_data = (l_write_data << l_shift_amount); + + //Write the value to the LPC_DATA_REG + l_err = SCOM_putScom(l_target, LPC_DATA_REG, l_data); + if(l_err != SUCCESS) + { + TRAC_ERR("ERROR> lpc_write: SCOM_putScom failed to write to LPC_DATA_REG data: rc=0x%08x", + (uint32_t)l_err); + break; + } /* Poll for completion */ - StatusReg_t eccb_stat; - l_err = pollComplete( &eccb_cmd, &eccb_stat ); + StatusReg_t lpc_stat; + l_err = pollComplete( &lpc_cmd, &lpc_stat ); if( l_err ) { break; } + } while(0); return l_err; |