diff options
author | Chris Cain <cjcain@us.ibm.com> | 2015-11-19 12:27:03 -0600 |
---|---|---|
committer | William A. Bryan <wilbryan@us.ibm.com> | 2016-01-27 16:27:07 -0600 |
commit | 1cdc7f74cf7303b2d2e7e172b0e269928def09de (patch) | |
tree | bc88add88943f8389626a04c5219d0efc3d08f17 /src/occ_gpe1 | |
parent | 476a284b52f50c1d0f5a8fc637cc28a22c714185 (diff) | |
download | talos-occ-1cdc7f74cf7303b2d2e7e172b0e269928def09de.tar.gz talos-occ-1cdc7f74cf7303b2d2e7e172b0e269928def09de.zip |
Implement code to read DIMM temperatures
Change-Id: I98fc83ab1c78bd40241fe6e47a9ddeae24f78c38
RTC: 140093
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/22770
Reviewed-by: William A. Bryan <wilbryan@us.ibm.com>
Tested-by: FSP CI Jenkins
Reviewed-by: Martha Broyles <mbroyles@us.ibm.com>
Reviewed-by: Christopher Cain <cjcain@us.ibm.com>
Diffstat (limited to 'src/occ_gpe1')
-rwxr-xr-x | src/occ_gpe1/gpe1.h | 76 | ||||
-rwxr-xr-x | src/occ_gpe1/gpe1_dimm.h (renamed from src/occ_gpe1/gpe_export.h) | 53 | ||||
-rw-r--r-- | src/occ_gpe1/gpe1_dimm_read.c | 511 | ||||
-rw-r--r-- | src/occ_gpe1/gpe1_dimm_reset.c | 223 | ||||
-rw-r--r-- | src/occ_gpe1/gpe1_main.c | 6 | ||||
-rw-r--r-- | src/occ_gpe1/ipc_func_tables.c | 4 | ||||
-rw-r--r-- | src/occ_gpe1/topfiles.mk | 2 |
7 files changed, 853 insertions, 22 deletions
diff --git a/src/occ_gpe1/gpe1.h b/src/occ_gpe1/gpe1.h new file mode 100755 index 0000000..af26829 --- /dev/null +++ b/src/occ_gpe1/gpe1.h @@ -0,0 +1,76 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_405/gpe/gpe1.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] 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 */ + +#ifndef _GPE1_H +#define _GPE1_H + +#include "gpe_export.h" + + +// I2C SCOM Addresses: +// (There are unique constants/addresses per engine, but to make the calls generic, +// these constants are defined instead of using the base constants) +#define PIB_BASE 0x000A0000 +// Engine B 0x00A0000 +// Engine C 0x00A1000 +// Engine D 0x00A2000 +// Engine E 0x00A3000 +#define SCOM_ENGINE_OFFSET(engine) (engine << 12) +#define I2C_FIFO1_REG_READ 0x000A0004 +#define I2C_COMMAND_REG 0x000A0005 +#define I2C_MODE_REG 0x000A0006 +#define I2C_INTERRUPT_MASK_REG 0x000A0008 +#define I2C_STATUS_REG 0x000A000B // read +#define I2C_IMM_RESET_I2C 0x000A000B // write +#define I2C_BUSY_REGISTER 0x000A000E +#define I2C_FIFO4_REG_READ 0x000A0012 + + +// I2C Status Reigster masks +#define STATUS_ERROR_MASK 0xFE80330000000000 +#define STATUS_ERROR_OR_COMPLETE_MASK 0xFF80330000000000 +#define STATUS_COMPLETE_MASK 0x0100000000000000 +#define PEEK_ERROR_MASK 0x00000000FC000000 +#define PEEK_MORE_DATA 0x0000000002000000 + + +// Debug trace +#ifdef GPE1_DEBUG + #define GPE1_DIMM_DBG(frmt,args...) \ + PK_TRACE(frmt,##args) + #define GPE1_DIMM_DBG_HEXDUMP(data, len, string) \ + PK_TRACE_BIN(data, len, string) +#else + #define GPE1_DIMM_DBG(frmt,args...) + #define GPE1_DIMM_DBG_HEXDUMP(data, len, string) +#endif + + +void gpe_set_ffdc(GpeErrorStruct *o_error, uint32_t i_addr, uint32_t i_rc, uint64_t i_ffdc); + +void gpe_dimm_sm(ipc_msg_t* cmd, void* arg); + + +#endif //_GPE1_H diff --git a/src/occ_gpe1/gpe_export.h b/src/occ_gpe1/gpe1_dimm.h index 84184e7..c3249c6 100755 --- a/src/occ_gpe1/gpe_export.h +++ b/src/occ_gpe1/gpe1_dimm.h @@ -1,7 +1,7 @@ /* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ -/* $Source: src/occ_405/gpe/gpe_export.h $ */ +/* $Source: src/occ_405/gpe/gpe1_dimm.h $ */ /* */ /* OpenPOWER OnChipController Project */ /* */ @@ -23,19 +23,38 @@ /* */ /* IBM_PROLOG_END_TAG */ -#ifndef _GPE_EXPORT_H -#define _GPE_EXPORT_H - -typedef struct { - union - { - struct { - uint32_t rc; - uint32_t addr; - }; - uint64_t error; - }; - uint64_t ffdc; -} GpeErrorStruct; // Same for every GPE program - -#endif //_GPE_EXPORT_H +#ifndef _GPE1_DIMM_H +#define _GPE1_DIMM_H + +#include "gpe_export.h" + +#define PIB_BASE 0x000A0000 +// Engine B 0x00A0000 +// Engine C 0x00A1000 +// Engine D 0x00A2000 +// Engine E 0x00A3000 +#define I2C_FIFO1_REG_READ 0x000A0004 +#define I2C_COMMAND_REG 0x000A0005 +#define I2C_MODE_REG 0x000A0006 +#define I2C_INTERRUPT_MASK_REG 0x000A0008 +#define I2C_STATUS_REG 0x000A000B // read +#define I2C_IMM_RESET_I2C 0x000A000B // write +#define I2C_BUSY_REGISTER 0x000A000E +#define I2C_FIFO4_REG_READ 0x000A0012 + +#define SCOM_ENGINE_OFFSET(engine) (engine << 12) + +// I2C Status Reigster masks +#define STATUS_ERROR_MASK 0xFE80330000000000 +#define STATUS_ERROR_OR_COMPLETE_MASK 0xFF80330000000000 +#define STATUS_COMPLETE_MASK 0x0100000000000000 +#define PEEK_ERROR_MASK 0x00000000FC000000 +#define PEEK_MORE_DATA 0x0000000002000000 + + +void dimm_set_ffdc(GpeErrorStruct *o_error, uint32_t i_addr, uint32_t i_rc, uint64_t i_ffdc); + +void gpe_dimm_sm(ipc_msg_t* cmd, void* arg); + + +#endif //_GPE1_DIMM_H diff --git a/src/occ_gpe1/gpe1_dimm_read.c b/src/occ_gpe1/gpe1_dimm_read.c new file mode 100644 index 0000000..be19506 --- /dev/null +++ b/src/occ_gpe1/gpe1_dimm_read.c @@ -0,0 +1,511 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_gpe1/gpe1_dimm_read.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015 */ +/* [+] 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 */ + +/// \file gpe1_dimm_read.c +/// \brief Functions to handle reading the DIMM temperatures +/// + +//#define GPE1_DEBUG +#include "pk.h" +#include "ipc_api.h" +#include "ppe42_scom.h" +#include "ipc_async_cmd.h" +#include "gpe1.h" +#include "gpe1_dimm.h" + + +void dimm_write_int_mask(ipc_msg_t* cmd, void* arg); +void dimm_write_mode(ipc_msg_t* cmd, void* arg); +void dimm_write_ts_addr(ipc_msg_t* cmd, void* arg); +void dimm_initiate_read(ipc_msg_t* cmd, void* arg); +void dimm_read_temp(ipc_msg_t* cmd, void* arg); +// from gpe1_dimm_reset.c +void dimm_reset_master(ipc_msg_t* cmd, void* arg); +void dimm_reset_slave(ipc_msg_t* cmd, void* arg); +void dimm_reset_slave_status(ipc_msg_t* cmd, void* arg); + + +/* + * Function Specification + * + * Name: gpe_set_ffdc + * + * Description: Fills up the error struct with the given data. + * + * End Function Specification + */ +void gpe_set_ffdc(GpeErrorStruct *o_error, uint32_t i_addr, uint32_t i_rc, uint64_t i_ffdc) +{ + + o_error->addr = i_addr; + //Return codes defined in gpe_err.h + o_error->rc = i_rc; + o_error->ffdc = i_ffdc; +} + + +/* + * Function Specifications: + * + * Name: gpe_dimm_sm + * + * Description: DIMM I2C State Machine handler in the GPE + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * Outputs: error: sets rc, address, and ffdc in the cmd_data's + * GpeErrorStruct + * + * End Function Specification + */ +void gpe_dimm_sm(ipc_msg_t* cmd, void* arg) +{ + // Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it. + // the ipc arguments passed through the ipc_msg_t structure, has a pointer + // to the G_gpe_start_pwr_meas_read_args struct. + int rc; + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data; + + // clear error + args->error.error = 0; + args->error.ffdc = 0; + + switch(args->state) + { + case DIMM_STATE_INIT: + dimm_write_int_mask(cmd, arg); + break; + + // Read DIMM Temperature States + + case DIMM_STATE_WRITE_MODE: + dimm_write_mode(cmd, arg); + break; + + case DIMM_STATE_WRITE_ADDR: + dimm_write_ts_addr(cmd, arg); + break; + + case DIMM_STATE_INITIATE_READ: + dimm_initiate_read(cmd, arg); + break; + + case DIMM_STATE_READ_TEMP: + dimm_read_temp(cmd, arg); + break; + + // I2C Reset States + + case DIMM_STATE_RESET_MASTER: + dimm_reset_master(cmd, arg); + break; + + case DIMM_STATE_RESET_SLAVE_P0: + case DIMM_STATE_RESET_SLAVE_P1: + dimm_reset_slave(cmd, arg); + break; + + case DIMM_STATE_RESET_SLAVE_P0_COMPLETE: + case DIMM_STATE_RESET_SLAVE_P1_COMPLETE: + dimm_reset_slave_status(cmd, arg); + break; + + default: + PK_TRACE("gpe_dimm_sm: Invalid state (0x%02X) received!", args->state); + args->error.rc = 0; + gpe_set_ffdc(&(args->error), 0, GPE_RC_INVALID_STATE, args->state); + break; + } + + // Send back IPC response of success (IPC operation itself succeeded) + // (if any operation failed, the error (rc/ffdc) will be non-zero + // and can be handled by the 405) + rc = ipc_send_rsp(cmd, IPC_RC_SUCCESS); + if(rc) + { + PK_TRACE("gpe_dimm_sm: Failed to send response back. Halting GPE1", rc); + gpe_set_ffdc(&(args->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); + pk_halt(); + } + +} // end gpe_dimm_sm() + + +/* + * Function Specifications: + * + * Name: dimm_write_int_mask + * + * Description: Write the I2C interrupt mask and read I2C status register + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * Outputs: error: sets rc, address, and ffdc in the cmd_data's + * GpeErrorStruct + * + * End Function Specification + */ +void dimm_write_int_mask(ipc_msg_t* cmd, void* arg) +{ + int rc; + uint32_t scomAddr; + uint64_t regValue; // a pointer to hold the putscom_abs register value + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data; + + scomAddr = I2C_INTERRUPT_MASK_REG | SCOM_ENGINE_OFFSET(args->i2cEngine); + // Enable the following bit in the interrupt mask: + // invalid command, LBUS parity, back end overrun, back end access, + // arbitration lost, nack received, data request, command complete, + // stop, i2c busy + regValue = 0x0000FFC000000000; + rc = putscom_abs(scomAddr, regValue); + if(rc) + { + PK_TRACE("dimm_write_int_mask: I2C_INTERRUPT_MASK_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_write_int_mask: putscom(0x%08X,0x%08X%08X) SUCCESS - INT MASK", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + } + + // READ I2C STATUS REGISTER + scomAddr = I2C_STATUS_REG | SCOM_ENGINE_OFFSET(args->i2cEngine); + rc = getscom_abs(scomAddr, ®Value); + if(rc) + { + PK_TRACE("dimm_write_int_mask: I2C_STATUS_REG getscom 0x%08X FAILED. rc = 0x%08x - STATUS", + scomAddr, rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_GET_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_write_int_mask: getscom(0x%08X) returned 0x%08X%08X) - STATUS #1", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + // max_num_of_ports (bits 9:15) + args->maxPorts = (regValue >> 48) & 0x7F; + PK_TRACE("dimm_write_int_mask: maxPorts = %d", args->maxPorts); + } + +} // end dimm_write_int_mask() + + +/* + * Function Specifications: + * + * Name: dimm_write_mode + * + * Description: Write the I2C mode register (set speed and port) + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * Outputs: error: sets rc, address, and ffdc in the cmd_data's + * GpeErrorStruct + * + * End Function Specification + */ + +void dimm_write_mode(ipc_msg_t* cmd, void* arg) +{ + // Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it. + // the ipc arguments passed through the ipc_msg_t structure, has a pointer + // to the G_gpe_start_pwr_meas_read_args struct. + + int rc; + uint32_t scomAddr; + uint64_t regValue; // a pointer to hold the putscom_abs register value + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data; + + // MODE_REGISTER + scomAddr = I2C_MODE_REG | SCOM_ENGINE_OFFSET(args->i2cEngine); + regValue = 0x0177000000000000; + if ((args->i2cPort > 0) && (args->i2cPort < 6)) + { + regValue |= ((uint64_t)args->i2cPort << 42); + } + rc = putscom_abs(scomAddr, regValue); + if(rc) + { + PK_TRACE("dimm_write_mode: I2C_MODE_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_write_mode: putscom(0x%08X,0x%08X%08X) SUCCESS - MODE", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + } + +} // end dimm_write_mode() + + +/* + * Function Specifications: + * + * Name: dimm_write_ts_addr + * + * Description: Write the Temperature Sensor address to I2C + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * Outputs: error: sets rc, address, and ffdc in the cmd_data's + * GpeErrorStruct + * + * End Function Specification + */ +void dimm_write_ts_addr(ipc_msg_t* cmd, void* arg) +{ + int rc; + uint32_t scomAddr; + uint64_t regValue; // a pointer to hold the putscom_abs register value + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data; + + // Write I2C command register with a 1 byte write + scomAddr = I2C_COMMAND_REG | SCOM_ENGINE_OFFSET(args->i2cEngine); + // start+address + slave_address, rw=0=write, length=1, i2c address + regValue = 0xC000000100000000 | ((uint64_t)args->i2cAddr << 48); + rc = putscom_abs(scomAddr, regValue); + if(rc) + { + PK_TRACE("dimm_write_ts_addr: I2C_COMMAND_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_write_ts_addr: putscom(0x%08X,0x%08X%08X) SUCCESS - COMMAND (write)", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + + // Write the Temperature Sensor address to the FIFO register + scomAddr = I2C_FIFO1_REG_READ | SCOM_ENGINE_OFFSET(args->i2cEngine); + // 0x05 = temperature value + regValue = 0x0500000000000000; + rc = putscom_abs(scomAddr, regValue); + if(rc) + { + PK_TRACE("dimm_write_ts_addr: I2C_FIFO_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_write_ts_addr: putscom(0x%08X,0x%08X%08X) SUCCESS - FIFO", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + } + } + +} // end dimm_write_ts_addr() + + +/* + * Function Specifications: + * + * Name: dimm_initiate_read + * + * Description: Initiate the read of the temperature sensor + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * Outputs: error: sets rc, address, and ffdc in the cmd_data's + * GpeErrorStruct + * + * End Function Specification + */ +void dimm_initiate_read(ipc_msg_t* cmd, void* arg) +{ + int rc; + uint32_t scomAddr; + uint64_t regValue; // a pointer to hold the putscom_abs register value + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data; + + // Default the rc to NOT_COMPLETE (meaning the read was not initiated) + args->error.rc = GPE_RC_NOT_COMPLETE; + + // Read the I2c Status Register to ensure the TS address was written successfully + scomAddr = I2C_STATUS_REG | SCOM_ENGINE_OFFSET(args->i2cEngine); + rc = getscom_abs(scomAddr, ®Value); + if(rc) + { + PK_TRACE("dimm_initiate_read: I2C_STATUS_REG getscom 0x%08X FAILED. rc = 0x%08x", + scomAddr, rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_GET_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_initiate_read: getscom(0x%08X) returned 0x%08X%08X - STATUS", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + + if ((regValue & STATUS_ERROR_OR_COMPLETE_MASK) == STATUS_COMPLETE_MASK) + { + // Status register indicates no errors and last command completed. + // Write the I2C command register with a 2 byte read request + scomAddr = I2C_COMMAND_REG | SCOM_ENGINE_OFFSET(args->i2cEngine); + // start+address+stop + slave_address, rw=1=read, length=2 + regValue = 0xD001000200000000; + regValue |= ((uint64_t)args->i2cAddr << 48); + rc = putscom_abs(scomAddr, regValue); + if(rc) + { + PK_TRACE("dimm_initiate_read: I2C_COMMAND_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc); + } + else + { + // The read command has been started, return success + GPE1_DIMM_DBG("dimm_initiate_read: putscom(0x%08X,0x%08X%08X) SUCCESS - COMMAND (read)", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + args->error.error = 0; + args->error.rc = GPE_RC_SUCCESS; + args->error.ffdc = 0; + } + } + else + { + if ((regValue & STATUS_ERROR_OR_COMPLETE_MASK) != 0) + { + // I2C error was found + PK_TRACE("dimm_initiate_read: Error in status register: 0x%08X%08X", + WORD_HIGH(regValue), WORD_LOW(regValue)); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_I2C_ERROR, regValue); + } + else + { + // Last command (write TS address) has not completed yet + PK_TRACE("dimm_initiate_read: last command not complete yet..."); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_NOT_COMPLETE, regValue); + } + // else, not complete yet + } + } + +} // end dimm_initiate_read() + + +/* + * Function Specifications: + * + * Name: dimm_read_temp + * + * Description: Read the temperature sensor value + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * Outputs: error: sets rc, address, and ffdc in the cmd_data's + * GpeErrorStruct + * + * End Function Specification + */ +void dimm_read_temp(ipc_msg_t* cmd, void* arg) +{ + int rc; + uint32_t scomAddr; + uint64_t regValue; // a pointer to hold the putscom_abs register value + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data; + + // Default the rc to NOT_COMPLETE (meaning the read has not completed) + args->error.rc = GPE_RC_NOT_COMPLETE; + + // Read the I2C status register + scomAddr = I2C_STATUS_REG | SCOM_ENGINE_OFFSET(args->i2cEngine); + rc = getscom_abs(scomAddr, ®Value); + if(rc) + { + PK_TRACE("dimm_read_temp: I2C_STATUS_REG getscom 0x%08X FAILED. rc = 0x%08x - STATUS #1", + scomAddr, rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_GET_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_read_temp: getscom(0x%08X) returned 0x%08X%08X) - STATUS #1", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + + uint8_t fifoLength = (regValue >> 32) & 0xFF; + if ((regValue & STATUS_ERROR_MASK) != 0) + { + // I2C error was found + PK_TRACE("dimm_read_temp: Error in status register: 0x%08X%08X", + WORD_HIGH(regValue), WORD_LOW(regValue)); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_I2C_ERROR, regValue); + } + else + { + // Need to wait until both bytes are available + if (fifoLength >= 2) + { + // Read the sensor value from the FIFO4 register + scomAddr = I2C_FIFO4_REG_READ | SCOM_ENGINE_OFFSET(args->i2cEngine); + rc = getscom_abs(scomAddr, ®Value); + if(rc) + { + PK_TRACE("dimm_read_temp: I2C_FIFO4_REG getscom 0x%08X FAILED. rc = 0x%08x", + scomAddr, rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_GET_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_read_temp: getscom(0x%08X) returned 0x%08X%08X) - FIFO4", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + // Temperature is in bits 4-11 + args->temp = (regValue >> 52) & 0xFF; + args->error.error = 0; + args->error.rc = GPE_RC_SUCCESS; + args->error.ffdc = 0; + PK_TRACE("dimm_read_temp: DIMM%04X temperature=%dC", + (args->i2cPort<<8)|args->dimm, args->temp); + + // Check for operation complete bit + // (operation complete bit will not get set until all + // data has been read from the FIFO.) + if (regValue & PEEK_ERROR_MASK) + { + // I2C error was found + PK_TRACE("dimm_read_temp: Error in FIFO4 peek data: 0x%08X%08X", + WORD_HIGH(regValue), WORD_LOW(regValue)); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_I2C_ERROR, regValue); + } + else if (regValue & PEEK_MORE_DATA) + { + // The data_request bit is non-zero, but no more data is needed! + PK_TRACE("dimm_read_temp: Got data, but more data needs access??"); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_NOT_COMPLETE, regValue); + } + } + } + // else, all data not available yet (NOT_COMPLETE) + } + } + +} // end dimm_read_temp() + + diff --git a/src/occ_gpe1/gpe1_dimm_reset.c b/src/occ_gpe1/gpe1_dimm_reset.c new file mode 100644 index 0000000..9963eec --- /dev/null +++ b/src/occ_gpe1/gpe1_dimm_reset.c @@ -0,0 +1,223 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_gpe1/gpe1_dimm_reset.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015 */ +/* [+] 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 */ + +/// \file gpe1_dimm_reset.c +/// \brief Functions to handle resetting the I2C engine +/// + +//#define GPE1_DEBUG +#include "pk.h" +#include "ipc_api.h" +#include "ppe42_scom.h" +#include "ipc_async_cmd.h" +#include "gpe1.h" +#include "gpe1_dimm.h" + + +/* + * Function Specifications: + * + * Name: dimm_reset_master + * + * Description: Reset the I2C master + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * Outputs: error: sets rc, address, and ffdc in the cmd_data's + * GpeErrorStruct + * + * End Function Specification + */ +void dimm_reset_master(ipc_msg_t* cmd, void* arg) +{ + // Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it. + // the ipc arguments passed through the ipc_msg_t structure, has a pointer + // to the G_gpe_start_pwr_meas_read_args struct. + + int rc; + uint32_t scomAddr; + uint64_t regValue; // a pointer to hold the putscom_abs register value + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data; + + // Reset I2C Master + scomAddr = I2C_IMM_RESET_I2C | SCOM_ENGINE_OFFSET(args->i2cEngine); + regValue = 0x0000000000000000; + rc = putscom_abs(scomAddr, regValue); + if(rc) + { + PK_TRACE("dimm_reset_master: I2C_IMM_RESET_I2C putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_reset_master: putscom(0x%08X,0x%08X%08X) SUCCESS - IMM_RESET_I2C", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + } + + // Force reset of Port_busy_register + scomAddr = I2C_BUSY_REGISTER | SCOM_ENGINE_OFFSET(args->i2cEngine); + regValue = 0x8000000000000000; + rc = putscom_abs(scomAddr, regValue); + if(rc) + { + PK_TRACE("dimm_reset_master: I2C_BUSY_REGISTER putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_reset_master: putscom(0x%08X,0x%08X%08X) SUCCESS - I2C_BUSY_REGISTER", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + } + +} // end dimm_reset_master() + + +/* + * Function Specifications: + * + * Name: dimm_reset_slave + * + * Description: Start reset of I2C slave + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * Outputs: error: sets rc, address, and ffdc in the cmd_data's + * GpeErrorStruct + * + * End Function Specification + */ + +void dimm_reset_slave(ipc_msg_t* cmd, void* arg) +{ + int rc; + uint32_t scomAddr; + uint64_t regValue; // a pointer to hold the putscom_abs register value + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data; + + // Write I2C mode register with the speed/port + scomAddr = I2C_MODE_REG | SCOM_ENGINE_OFFSET(args->i2cEngine); + regValue = 0x0177000000000000; + if ((args->i2cPort > 0) && (args->i2cPort < 6)) + { + regValue |= ((uint64_t)args->i2cPort << 42); + } + rc = putscom_abs(scomAddr, regValue); + if(rc) + { + PK_TRACE("dimm_reset_slave: I2C_MODE_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_reset_slave: putscom(0x%08X,0x%08X%08X) SUCCESS - MODE", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + + // Force a stop-condition to the I2C slave + scomAddr = I2C_COMMAND_REG | SCOM_ENGINE_OFFSET(args->i2cEngine); + // stop bit + regValue = 0x1000000000000000; + rc = putscom_abs(scomAddr, regValue); + if(rc) + { + PK_TRACE("dimm_reset_slave: I2C_COMMAND_REG putscom 0x%08X->0x%08X%08X FAILED. rc = 0x%08x", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue), rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_PUT_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_reset_slave: putscom(0x%08X,0x%08X%08X) SUCCESS - COMMAND (stop)", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + } + } + +} // end dimm_reset_slave() + + +/* + * Function Specifications: + * + * Name: dimm_reset_slave_status + * + * Description: Read I2C status register to ensure slave has been reset + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * Outputs: error: sets rc, address, and ffdc in the cmd_data's + * GpeErrorStruct + * + * End Function Specification + */ +void dimm_reset_slave_status(ipc_msg_t* cmd, void* arg) +{ + int rc; + uint32_t scomAddr; + uint64_t regValue; // a pointer to hold the putscom_abs register value + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + dimm_sm_args_t *args = (dimm_sm_args_t*)async_cmd->cmd_data; + + // Read I2C status register + scomAddr = I2C_STATUS_REG | SCOM_ENGINE_OFFSET(args->i2cEngine); + rc = getscom_abs(scomAddr, ®Value); + if(rc) + { + PK_TRACE("dimm_reset_slave_status: I2C_STATUS_REG getscom 0x%08X FAILED. rc = 0x%08x - STATUS #1", + scomAddr, rc); + gpe_set_ffdc(&(args->error), scomAddr, GPE_RC_SCOM_GET_FAILED, rc); + } + else + { + GPE1_DIMM_DBG("dimm_reset_slave_status: getscom(0x%08X) returned 0x%08X%08X) - STATUS #1", + scomAddr, WORD_HIGH(regValue), WORD_LOW(regValue)); + + // Wait until command complete is set + if (regValue & STATUS_COMPLETE_MASK) + { + // Reset completed + args->error.rc = GPE_RC_SUCCESS; + PK_TRACE("dimm_reset_slave_status: I2C Slave Port %d Reset completed", args->i2cPort); + + if ((regValue & STATUS_ERROR_OR_COMPLETE_MASK) != STATUS_COMPLETE_MASK) + { + // I2C errors found + PK_TRACE("dimm_reset_slave_status: I2C errors in status register: %08X%08X", + WORD_HIGH(regValue), WORD_LOW(regValue)); + // Continue with other slave resets and may trigger another reset... + } + } + else + { + // reset not complete yet... + args->error.rc = GPE_RC_NOT_COMPLETE; + } + } + +} // end dimm_reset_slave_status() + + diff --git a/src/occ_gpe1/gpe1_main.c b/src/occ_gpe1/gpe1_main.c index e81869e..88f3be8 100644 --- a/src/occ_gpe1/gpe1_main.c +++ b/src/occ_gpe1/gpe1_main.c @@ -1,7 +1,7 @@ /* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ -/* $Source: src/occ_gpe0/gpe0_main.c $ */ +/* $Source: src/occ_gpe1/gpe1_main.c $ */ /* */ /* OpenPOWER OnChipController Project */ /* */ @@ -31,12 +31,12 @@ #include "pk.h" #include "ipc_api.h" -#include "ipc_ping.h" #define KERNEL_STACK_SIZE 256 uint8_t G_kernel_stack[KERNEL_STACK_SIZE]; + // The main function is called by the boot code (after initializing some // registers) int main(int argc, char **argv) @@ -51,7 +51,7 @@ int main(int argc, char **argv) PK_TRACE("Kernel init completed"); - // Disable IPC's and register the IPC interrupt handler + // Disable IPC's and register the IPC interrupt handler rc = ipc_init(); if(rc) { diff --git a/src/occ_gpe1/ipc_func_tables.c b/src/occ_gpe1/ipc_func_tables.c index 1dfa02e..3c34920 100644 --- a/src/occ_gpe1/ipc_func_tables.c +++ b/src/occ_gpe1/ipc_func_tables.c @@ -1,4 +1,6 @@ #include "ipc_api.h" +#include "gpe1_dimm.h" + // Function table for multi target (common) functions IPC_MT_FUNC_TABLE_START @@ -14,7 +16,7 @@ IPC_MT_FUNC_TABLE_END // Function table for single target (processor-specific) functions IPC_ST_FUNC_TABLE_START -IPC_HANDLER_DEFAULT // 0 +IPC_HANDLER(gpe_dimm_sm, 0) // 0 - IPC_ST_DIMM_SM_FUNCID IPC_HANDLER_DEFAULT // 1 IPC_HANDLER_DEFAULT // 2 IPC_HANDLER_DEFAULT // 3 diff --git a/src/occ_gpe1/topfiles.mk b/src/occ_gpe1/topfiles.mk index 698d29f..0b8ca4b 100644 --- a/src/occ_gpe1/topfiles.mk +++ b/src/occ_gpe1/topfiles.mk @@ -1,4 +1,4 @@ -TOP-C-SOURCES = gpe1_main.c pk_app_irq_table.c ipc_func_tables.c +TOP-C-SOURCES = gpe1_main.c gpe1_dimm_read.c gpe1_dimm_reset.c pk_app_irq_table.c ipc_func_tables.c TOP-S-SOURCES = TOP_OBJECTS = $(TOP-C-SOURCES:.c=.o) $(TOP-S-SOURCES:.S=.o) |