From f301809e56b82fe61260a15f437183976db9ef75 Mon Sep 17 00:00:00 2001 From: Prachi Gupta Date: Fri, 14 Jul 2017 08:15:16 -0500 Subject: rt_xstop_analysis: move firdata code from occ_405 to occ_gpe0 Change-Id: Idaafd3bd9d40cfce4afd7b5d3308cd376f443967 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/43242 Reviewed-by: Zane C. Shelley Reviewed-by: ILYA SMIRNOV Reviewed-by: Brian J. Stegmiller Reviewed-by: William A. Bryan Tested-by: William A. Bryan --- src/occ_gpe0/firdata/lpc.c | 391 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 391 insertions(+) create mode 100644 src/occ_gpe0/firdata/lpc.c (limited to 'src/occ_gpe0/firdata/lpc.c') diff --git a/src/occ_gpe0/firdata/lpc.c b/src/occ_gpe0/firdata/lpc.c new file mode 100644 index 0000000..ffe2b48 --- /dev/null +++ b/src/occ_gpe0/firdata/lpc.c @@ -0,0 +1,391 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/firdata/lpc.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include +#include +#include +#include + +#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) */ +#define ECCB_DATA_REG 0x000B0023 /**< ECCB Data Reg (FW) */ + +/* Default Values to set for all operations + 1101.0100.0000.000x.0000.0001.0000.0000.
*/ +#define ECCB_CTL_REG_DEFAULT 0xD400010000000000 + +/* 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 + +/**< OPB LPCM Sync FIR Reg WOX_AND - used to clear the FIR */ +#define OPB_LPCM_FIR_WOX_AND_REG 0x01010C01 + +/**< OPB LPCM Sync FIR Mask Reg WO_OR - used to set the mask */ +#define OPB_LPCM_FIR_MASK_WO_OR_REG 0x01010C05 + +#define OPB_LPCM_FIR_ERROR_MASK 0xFF00000000000000 /**< Error Bits MASK */ + +/* LPCHC reset-related registers */ +#define OPB_MASTER_LS_CONTROL_REG 0x008 /**data64)); + + if( l_err ) + { + break; + } + + if( o_stat->op_done ) + { + break; + } + + /* 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( 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 & LPC_STAT_REG_ERROR_MASK) + || (!o_stat->op_done)) ) + { + 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; + } + } while(0); + + return l_err; + +} + + +/*========================================================*/ + +errorHndl_t lpc_read( LpcTransType i_type, + uint32_t i_addr, + uint8_t* o_data, + size_t i_size ) +{ + errorHndl_t l_err = NO_ERROR; + int32_t l_addr = 0; + uint64_t l_ret; + uint32_t l_shift_amount; + uint64_t l_temp_data; + + do { + if( o_data == NULL ) + { + TRACFCOMP( "o_data is NULL!" ); + l_err = -2; + break; + } + + + /* Generate the full absolute LPC address */ + l_addr = checkAddr( i_type, i_addr ); + + /* 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 lpc_status; + l_err = pollComplete( &lpc_cmd, &lpc_status ); + if( l_err ) { break; } + + // 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)) + { + uint64_t* l_temp_ptr = (uint64_t*)(o_data); + *l_temp_ptr = l_temp_data; + } + else + { + TRAC_ERR("lpc_read: unsupported size length"); + l_err = -1; + break; + } + + } while(0); + + return l_err; +} + +errorHndl_t lpc_write( LpcTransType i_type, + uint32_t i_addr, + uint8_t* i_data, + size_t i_size ) +{ + 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 ); + + /* 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) + { + TRAC_ERR("ERROR> lpc_write: SCOM_putScom failed to write to LPC_CMD_REG command: rc=0x%08x", + (uint32_t)l_err); + break; + } + + //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; + } + + //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 lpc_stat; + l_err = pollComplete( &lpc_cmd, &lpc_stat ); + if( l_err ) { break; } + + + } while(0); + + return l_err; +} -- cgit v1.2.1