summaryrefslogtreecommitdiffstats
path: root/src/occ_gpe0
diff options
context:
space:
mode:
authorPrachi Gupta <pragupta@us.ibm.com>2017-07-14 08:15:16 -0500
committerWilliam A. Bryan <wilbryan@us.ibm.com>2017-07-21 16:26:20 -0400
commitf301809e56b82fe61260a15f437183976db9ef75 (patch)
treedaf1faba0c01d7e0c6ca818b05dddfcc987047d0 /src/occ_gpe0
parentfda31eb85acb9aa8dee9741848ad9740f54e2f63 (diff)
downloadtalos-occ-f301809e56b82fe61260a15f437183976db9ef75.tar.gz
talos-occ-f301809e56b82fe61260a15f437183976db9ef75.zip
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 <zshelle@us.ibm.com> Reviewed-by: ILYA SMIRNOV <ismirno@us.ibm.com> Reviewed-by: Brian J. Stegmiller <bjs@us.ibm.com> Reviewed-by: William A. Bryan <wilbryan@us.ibm.com> Tested-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/occ_gpe0')
-rw-r--r--src/occ_gpe0/firdata/ast_mboxdd.c326
-rw-r--r--src/occ_gpe0/firdata/ast_mboxdd.h292
-rw-r--r--src/occ_gpe0/firdata/ecc.c272
-rw-r--r--src/occ_gpe0/firdata/ecc.h76
-rw-r--r--src/occ_gpe0/firdata/firData.c1389
-rw-r--r--src/occ_gpe0/firdata/firData.h48
-rw-r--r--src/occ_gpe0/firdata/firDataConst_common.h132
-rw-r--r--src/occ_gpe0/firdata/fir_data_collect.c166
-rw-r--r--src/occ_gpe0/firdata/fir_data_collect.h56
-rw-r--r--src/occ_gpe0/firdata/fsi.c152
-rw-r--r--src/occ_gpe0/firdata/fsi.h47
-rw-r--r--src/occ_gpe0/firdata/homerData_common.h271
-rw-r--r--src/occ_gpe0/firdata/lpc.c391
-rw-r--r--src/occ_gpe0/firdata/lpc.h55
-rw-r--r--src/occ_gpe0/firdata/native.c76
-rw-r--r--src/occ_gpe0/firdata/native.h98
-rw-r--r--src/occ_gpe0/firdata/norflash.h154
-rw-r--r--src/occ_gpe0/firdata/pnorData_common.h162
-rw-r--r--src/occ_gpe0/firdata/pnor_mboxdd.c404
-rw-r--r--src/occ_gpe0/firdata/pnor_mboxdd.h135
-rw-r--r--src/occ_gpe0/firdata/pnor_util.c220
-rw-r--r--src/occ_gpe0/firdata/pnor_util.h41
-rw-r--r--src/occ_gpe0/firdata/sbe_fifo.c444
-rw-r--r--src/occ_gpe0/firdata/sbe_fifo.h123
-rw-r--r--src/occ_gpe0/firdata/scom_addr_util.c82
-rw-r--r--src/occ_gpe0/firdata/scom_addr_util.h81
-rw-r--r--src/occ_gpe0/firdata/scom_trgt.c180
-rw-r--r--src/occ_gpe0/firdata/scom_trgt.h89
-rw-r--r--src/occ_gpe0/firdata/scom_util.c607
-rw-r--r--src/occ_gpe0/firdata/scom_util.h98
30 files changed, 6667 insertions, 0 deletions
diff --git a/src/occ_gpe0/firdata/ast_mboxdd.c b/src/occ_gpe0/firdata/ast_mboxdd.c
new file mode 100644
index 0000000..064bcca
--- /dev/null
+++ b/src/occ_gpe0/firdata/ast_mboxdd.c
@@ -0,0 +1,326 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/ast_mboxdd.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 */
+/**
+ * @file ast_mboxdd.C
+ *
+ * @brief Implementation of the PNOR Accesser using the AST MBOX protocol
+ */
+
+/*****************************************************************************/
+// I n c l u d e s
+/*****************************************************************************/
+#include <native.h>
+#include <norflash.h>
+#include <ast_mboxdd.h>
+#include <lpc.h>
+
+errorHndl_t writeRegSIO(uint8_t i_regAddr, uint8_t i_data)
+{
+ errorHndl_t l_err = NO_ERROR;
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ /* Write out the register address */
+ l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_REG_2E,
+ &i_regAddr,
+ reg_size );
+ if( l_err ) { break; }
+
+ /* Write out the register data */
+ l_err = lpc_write( LPC_TRANS_IO, SIO_DATA_REG_2F,
+ &i_data,
+ reg_size );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ return l_err;
+}
+
+errorHndl_t readRegSIO(uint8_t i_regAddr, uint8_t* o_data)
+{
+ errorHndl_t l_err = NO_ERROR;
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ /* Write out the register address */
+ l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_REG_2E,
+ &i_regAddr,
+ reg_size );
+ if( l_err ) { break; }
+
+ /* Read in the register data */
+ l_err = lpc_read( LPC_TRANS_IO, SIO_DATA_REG_2F,
+ o_data,
+ reg_size );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ return l_err;
+}
+
+errorHndl_t mboxOut(uint64_t i_addr, uint8_t i_byte)
+{
+ size_t len = sizeof(i_byte);
+
+ return lpc_write( LPC_TRANS_IO,
+ i_addr + MBOX_IO_BASE,
+ &i_byte,
+ len );
+}
+
+errorHndl_t mboxIn(uint64_t i_addr, uint8_t *o_byte)
+{
+ size_t len = sizeof(uint8_t);
+
+ return lpc_read( LPC_TRANS_IO,
+ i_addr + MBOX_IO_BASE,
+ o_byte,
+ len );
+}
+
+errorHndl_t doMessage( astMbox_t *io_mbox, mboxMessage_t *io_msg )
+{
+ uint8_t* l_data = (uint8_t*)io_msg;
+ errorHndl_t l_err = NO_ERROR;
+ uint8_t l_stat1;
+ uint32_t l_loops = 0;
+ bool l_prot_error = false;
+ int i;
+
+ io_msg->iv_seq = io_mbox->iv_mboxMsgSeq++;
+
+ do
+ {
+ /* Write message out */
+ for (i = 0; i < BMC_MBOX_DATA_REGS && !l_err; i++)
+ {
+ l_err = mboxOut(i, l_data[i]);
+ }
+
+ if ( l_err )
+ {
+ break;
+ }
+
+ /* Clear status1 response bit as it was just set via reg write*/
+ l_err = mboxOut(MBOX_STATUS_1, MBOX_STATUS1_RESP);
+
+ if ( l_err )
+ {
+ break;
+ }
+
+ /* Ping BMC */
+ l_err = mboxOut(MBOX_HOST_CTRL, MBOX_CTRL_INT_SEND);
+
+ if ( l_err )
+ {
+ break;
+ }
+
+ /* Wait for response */
+ while ( l_loops++ < MBOX_MAX_RESP_WAIT_US && !l_err )
+ {
+ l_err = mboxIn(MBOX_STATUS_1, &l_stat1);
+
+ if ( l_err )
+ {
+ TRAC_ERR("doMessage error from MBOX_STATUS_1");
+ break;
+ }
+
+ if ( l_stat1 & MBOX_STATUS1_RESP )
+ {
+ break;
+ }
+ sleep(1000);
+ }
+
+ if ( l_err )
+ {
+ TRAC_ERR( "Got error waiting for response !");
+ break;
+ }
+
+ if ( !(l_stat1 & MBOX_STATUS1_RESP) )
+ {
+ TRAC_ERR( "Timeout waiting for response !");
+
+ // Don't try to interrupt the BMC anymore
+ l_err = mboxOut(MBOX_HOST_CTRL, 0);
+ if ( l_err)
+ {
+ //Note the command failed
+ TRAC_ERR( "Error communicating with MBOX daemon");
+ TRAC_ERR( "Mbox status 1 reg: %x", l_stat1);
+ }
+
+ // Tell the code below that we generated the error
+ // (not an LPC error)
+ l_prot_error = true;
+ break;
+ }
+
+ /* Clear status */
+ l_err = mboxOut(MBOX_STATUS_1, MBOX_STATUS1_RESP);
+ if (l_err)
+ {
+ TRAC_ERR( "Got error clearing status");
+ break;
+ }
+
+ // Remember some message fields before they get overwritten
+ // by the response
+ uint8_t old_seq = io_msg->iv_seq;
+
+ // Read response
+ for (i = 0; i < BMC_MBOX_DATA_REGS && !l_err; i++)
+ {
+ l_err = mboxIn(i, &l_data[i]);
+ }
+
+ if ( l_err )
+ {
+ TRAC_ERR( "Got error reading response !");
+ break;
+ }
+
+ if (old_seq != io_msg->iv_seq)
+ {
+ TRAC_ERR( "bad sequence number in mbox message, got %d want %d",
+ io_msg->iv_seq, old_seq);
+ l_err = -1;
+ break;
+ }
+
+ if (io_msg->iv_resp != MBOX_R_SUCCESS)
+ {
+ TRAC_ERR( "BMC mbox command failed with err %d",
+ io_msg->iv_resp);
+ l_err = -1;
+ // Tell code below that we generated the error (not an LPC error)
+ l_prot_error = true;
+ break;
+ }
+
+ }
+ while(0);
+
+ // If we got an LPC error, commit it and generate our own
+ if ( l_err && !l_prot_error )
+ {
+ l_err = -1;
+ }
+
+ return l_err;
+}
+
+errorHndl_t initializeMbox(void)
+{
+ errorHndl_t l_errl = NO_ERROR;
+
+ do
+ {
+ size_t reg_size = sizeof(uint8_t);
+
+ //First need to unlock SIO registers
+ /* Send SuperIO password - send A5 twice to offset 0x2E */
+ uint8_t data = SIO_PASSWORD_REG;
+ l_errl = lpc_write( LPC_TRANS_IO, SIO_ADDR_REG_2E,
+ &data, reg_size );
+ if( l_errl ) { break; }
+
+ l_errl = lpc_write( LPC_TRANS_IO, SIO_ADDR_REG_2E,
+ &data, reg_size );
+ if( l_errl ) { break; }
+
+ //Second need to select Mailbox SIO Device
+ // Register 0x07 is device select reg
+ // Device 0x0E is the sio mailbox device
+ l_errl = writeRegSIO( SIO_DEVICE_SELECT_REG, SIO_MB );
+ if( l_errl ) { break; }
+
+ //First disable SIO Mailbox engine to configure it
+ // 0x30 - Enable/Disable Reg
+ // 0x00 - Disable Device (previously selected mailbox device)
+ l_errl = writeRegSIO( 0x30, 0x00 );
+
+ if (l_errl)
+ {
+ break;
+ }
+
+ // Set MBOX Base Address
+ //Regs 0x60/0x61 are a BAR-like reg to configure the MBOX base address
+ l_errl = writeRegSIO( 0x60, (MBOX_IO_BASE >> 8) & 0xFF );
+
+ if (l_errl)
+ {
+ break;
+ }
+
+ // Set other half of MBOX Base Address
+ l_errl = writeRegSIO( 0x61, MBOX_IO_BASE & 0xFF );
+
+ if (l_errl)
+ {
+ break;
+ }
+
+ //Configure MBOX IRQs
+ //Regs 0x70 / 0x71 control that
+ l_errl = writeRegSIO( 0x70, MBOX_LPC_IRQ );
+
+ if (l_errl)
+ {
+ break;
+ }
+
+ //Other half of MBOX IRQ Configuration
+ // 1 == Low level trigger
+ l_errl = writeRegSIO( 0x71, 1 );
+
+ if (l_errl)
+ {
+ break;
+ }
+
+ //Re-enable Device now that base addr and IRQs are configured
+ // 1 == Enable Device
+ l_errl = writeRegSIO( 0x30, 0x01 );
+
+ if (l_errl)
+ {
+ break;
+ }
+ }
+ while(0);
+
+ return l_errl;
+}
diff --git a/src/occ_gpe0/firdata/ast_mboxdd.h b/src/occ_gpe0/firdata/ast_mboxdd.h
new file mode 100644
index 0000000..64ea40a
--- /dev/null
+++ b/src/occ_gpe0/firdata/ast_mboxdd.h
@@ -0,0 +1,292 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/ast_mboxdd.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 */
+
+#ifndef __AST_MBOXDD_H
+#define __AST_MBOXDD_H
+
+/** @file ast_mboxdd.H
+ * @brief Provides the interfaces Aspeed MBOX hardware
+ */
+
+/**
+ * @brief Provides the interface to exchange Mbox
+ * messages with the BMC.
+ */
+
+enum
+{
+ BMC_MBOX_DATA_REGS = 14,
+ BMC_MBOX_ARGS_REGS = 11,
+
+ /* Commands */
+ MBOX_C_RESET_STATE = 0x01,
+ MBOX_C_GET_MBOX_INFO = 0x02,
+ MBOX_C_GET_FLASH_INFO = 0x03,
+ MBOX_C_CREATE_READ_WINDOW = 0x04,
+ MBOX_C_CLOSE_WINDOW = 0x05,
+ MBOX_C_CREATE_WRITE_WINDOW = 0x06,
+ MBOX_C_MARK_WRITE_DIRTY = 0x07,
+ MBOX_C_WRITE_FLUSH = 0x08,
+ MBOX_C_BMC_EVENT_ACK = 0x09,
+ MBOX_C_MARK_WRITE_ERASED = 0x0a,
+
+ /* Responses */
+ MBOX_R_SUCCESS = 0x01,
+ MBOX_R_PARAM_ERROR = 0x02,
+ MBOX_R_WRITE_ERROR = 0x03,
+ MBOX_R_SYSTEM_ERROR = 0x04,
+ MBOX_R_TIMEOUT = 0x05,
+ MBOX_R_BUSY = 0x06,
+ MBOX_R_WINDOW_ERROR = 0x07,
+
+};
+
+enum{
+ SIO_DEVICE_SELECT_REG = 0x07, /**< Regsiter to select SIO device */
+ SIO_ADDR_REG_2E = 0x2E, /**< SuperIO address register */
+ SIO_DATA_REG_2F = 0x2F, /**< SuperIO data register */
+ SIO_PASSWORD_REG = 0xA5, /**< SuperIO password register (to be unlocked to access SIO) */
+ SIO_MB = 0x0E, /**< SIO device: Mailbox */
+ SIO_ENABLE_DEVICE = 0x01, /**< Enable SIO device by writing 1 to reg 30 of device */
+ SIO_DISABLE_DEVICE = 0x00, /**< Disable SIO device by writing 0 to reg 30 of device */
+};
+
+
+typedef struct
+{
+ uint8_t iv_cmd;
+ uint8_t iv_seq;
+ uint8_t iv_args[BMC_MBOX_ARGS_REGS];
+ uint8_t iv_resp;
+
+} mboxMessage_t;
+
+/**
+ * @brief Write a single byte into an SIO register
+ *
+ * @param[in] i_reg: Register to write
+ * @param[in] i_data: Data to write
+ *
+ * @return Error from operation
+ */
+errorHndl_t writeRegSIO(uint8_t i_regAddr,
+ uint8_t i_data );
+
+/**
+ * @brief Read a single byte from an SIO register
+ *
+ * @param[in] i_reg: Register to read
+ * @param[in] o_data: Data that was read
+ *
+ * @return Error from operation
+ */
+errorHndl_t readRegSIO(uint8_t i_regAddr,
+ uint8_t* o_data );
+
+
+//Helper functions to create mbox messages to send to the BMC
+
+/**
+ * @brief 8-bit read accessor of the args section
+ *
+ * @param[in] i_msg: mboxMessage_t pointer to access args section
+ * @param[in] i_index: Index into args section to be read from
+ *
+ * @return data requested
+ */
+static inline uint8_t get8( mboxMessage_t *i_msg, uint8_t i_index)
+{
+ if ( i_index >= BMC_MBOX_ARGS_REGS )
+ {
+ return 0;
+ }
+
+ return i_msg->iv_args[i_index];
+}
+
+/**
+ * @brief 8-bit write accessor of the args section
+ *
+ * @param[in] i_msg: mboxMessage_t pointer to access args section
+ * @param[in] i_index: Index into args section to be written to
+ * @param[in] i_value: data to be written
+ */
+static inline void put8(mboxMessage_t *i_msg, uint8_t i_index, uint8_t i_value)
+{
+ if ( i_index >= BMC_MBOX_ARGS_REGS )
+ {
+ return;
+ }
+
+ i_msg->iv_args[i_index] = i_value;
+}
+
+/**
+ * @brief 16-bit read accessor of the args section
+ * @param[in] i_msg: mboxMessage_t pointer to access args section
+ * @param[in] i_index: Index into args section to be read from
+ *
+ * @return data requested
+ */
+static inline uint16_t get16( mboxMessage_t *i_msg, uint8_t i_index )
+{
+ if ( i_index >= (BMC_MBOX_ARGS_REGS-1) )
+ {
+ return 0;
+ }
+
+ return i_msg->iv_args[i_index] | (i_msg->iv_args[i_index + 1] << 8);
+}
+
+/**
+ * @brief 16-bit write accessor of the args section
+ *
+ * @param[in] i_msg: mboxMessage_t pointer to access args section
+ * @param[in] i_index: Index into args section to be written to
+ * @param[in] i_value: data to be written
+ */
+static inline void put16(mboxMessage_t *i_msg,
+ uint8_t i_index,
+ uint16_t i_value)
+{
+ if ( i_index >= (BMC_MBOX_ARGS_REGS-1) )
+ {
+ return;
+ }
+
+ i_msg->iv_args[i_index] = i_value & 0xff;
+ i_msg->iv_args[i_index + 1] = i_value >> 8;
+}
+
+/**
+ * @brief 32-bit read accessor of the args section
+ *
+ * @param[in] i_msg: mboxMessage_t pointer to access args section
+ * @param[in] i_index: Index into args section to be read from
+ *
+ * @return data requested
+ */
+static inline uint32_t get32( mboxMessage_t *i_msg, uint8_t i_index )
+{
+ if ( i_index >= (BMC_MBOX_ARGS_REGS-3) )
+ {
+ return 0;
+ }
+
+ return i_msg->iv_args[i_index] |
+ (i_msg->iv_args[i_index + 1] << 8) |
+ (i_msg->iv_args[i_index + 2] << 16) |
+ (i_msg->iv_args[i_index + 3] << 24);
+}
+
+/**
+ * @brief 32-bit write accessor of the args section
+ *
+ * @param[in] i_msg: mboxMessage_t pointer to access args section
+ * @param[in] i_index: Index into args section to be read from
+ */
+static inline void put32(mboxMessage_t *i_msg,
+ uint8_t i_index,
+ uint32_t i_value)
+{
+ if ( i_index >= (BMC_MBOX_ARGS_REGS-3) )
+ {
+ return;
+ }
+
+ i_msg->iv_args[i_index] = i_value & 0xff;
+ i_msg->iv_args[i_index + 1] = (i_value >> 8) & 0xff;
+ i_msg->iv_args[i_index + 2] = (i_value >> 16) & 0xff;
+ i_msg->iv_args[i_index + 3 ] = i_value >> 24;
+}
+
+typedef struct {
+
+ uint8_t iv_mboxMsgSeq;
+ mboxMessage_t iv_msg;
+
+} astMbox_t;
+
+/**
+ * @brief Send a message and receive the response
+ *
+ * @parm[in/out] io_mbox Mbox pointer to send message
+ * @parm[in/out] io_msg Message to send, contains the response on exit
+ *
+ * @return Error from operation
+ */
+errorHndl_t doMessage( astMbox_t *io_mbox, mboxMessage_t *io_msg );
+
+enum
+{
+ MBOX_FLAG_REG = 0x0f,
+ MBOX_STATUS_0 = 0x10,
+ MBOX_STATUS_1 = 0x11,
+ MBOX_STATUS1_ATTN = 0x80,
+ MBOX_STATUS1_RESP = 0x20,
+ MBOX_BMC_CTRL = 0x12,
+ MBOX_CTRL_INT_STATUS = 0x80,
+ MBOX_CTRL_INT_MASK = 0x02,
+ MBOX_CTRL_INT_SEND = 0x01,
+ MBOX_HOST_CTRL = 0x13,
+ MBOX_BMC_INT_EN_0 = 0x14,
+ MBOX_BMC_INT_EN_1 = 0x15,
+ MBOX_HOST_INT_EN_0 = 0x16,
+ MBOX_HOST_INT_EN_1 = 0x17,
+
+ MBOX_IO_BASE = 0x1000,
+ MBOX_LPC_IRQ = 0x9,
+
+ MBOX_MAX_RESP_WAIT_US = 10000000, /* 10s timeout */
+};
+
+/**
+ * @brief Initialize/Enable the MBox in the SIO
+ *
+ * @return Error from operation
+ */
+errorHndl_t initializeMbox( void );
+
+/**
+ * @brief Write a byte to the mBox
+ *
+ * @parm[in] i_addr: Register offset in the mbox
+ * @parm[in] i_byte: Byte to write
+ *
+ * @return Error from operation
+*/
+errorHndl_t mboxOut( uint64_t i_addr, uint8_t i_byte );
+
+/**
+ * @brief Read a byte from the mBox
+ *
+ * @parm[in] i_addr: Register offset in the mbox
+ * @parm[out] o_byte: Byte read
+ *
+ * @return Error from operation
+ */
+errorHndl_t mboxIn( uint64_t i_addr, uint8_t *o_byte );
+
+#endif /* __AST_MBOXDD_H */
diff --git a/src/occ_gpe0/firdata/ecc.c b/src/occ_gpe0/firdata/ecc.c
new file mode 100644
index 0000000..6696678
--- /dev/null
+++ b/src/occ_gpe0/firdata/ecc.c
@@ -0,0 +1,272 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/ecc.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 */
+
+/*#include <stdio.h> */
+#include <endian.h>
+#include <assert.h>
+
+#include <native.h>
+#include <ecc.h>
+
+/** Matrix used for ECC calculation.
+ *
+ * Each row of this is the set of data word bits that are used for
+ * the calculation of the corresponding ECC bit. The parity of the
+ * bitset is the value of the ECC bit.
+ *
+ * ie. ECC[n] = eccMatrix[n] & data
+ *
+ * Note: To make the math easier (and less shifts in resulting code),
+ * row0 = ECC7. HW numbering is MSB, order here is LSB.
+ *
+ * These values come from the HW design of the ECC algorithm.
+ */
+static uint64_t eccMatrix[] = {
+ /*0000000000000000111010000100001000111100000011111001100111111111 */
+ 0x0000e8423c0f99ff,
+ /*0000000011101000010000100011110000001111100110011111111100000000 */
+ 0x00e8423c0f99ff00,
+ /*1110100001000010001111000000111110011001111111110000000000000000 */
+ 0xe8423c0f99ff0000,
+ /*0100001000111100000011111001100111111111000000000000000011101000 */
+ 0x423c0f99ff0000e8,
+ /*0011110000001111100110011111111100000000000000001110100001000010 */
+ 0x3c0f99ff0000e842,
+ /*0000111110011001111111110000000000000000111010000100001000111100 */
+ 0x0f99ff0000e8423c,
+ /*1001100111111111000000000000000011101000010000100011110000001111 */
+ 0x99ff0000e8423c0f,
+ /*1111111100000000000000001110100001000010001111000000111110011001 */
+ 0xff0000e8423c0f99
+};
+
+/** Syndrome calculation matrix.
+ *
+ * Maps syndrome to flipped bit.
+ *
+ * To perform ECC correction, this matrix is a look-up of the bit
+ * that is bad based on the binary difference of the good and bad
+ * ECC. This difference is called the "syndrome".
+ *
+ * When a particular bit is on in the data, it cause a column from
+ * eccMatrix being XOR'd into the ECC field. This column is the
+ * "effect" of each bit. If a bit is flipped in the data then its
+ * "effect" is missing from the ECC. You can calculate ECC on unknown
+ * quality data and compare the ECC field between the calculated
+ * value and the stored value. If the difference is zero, then the
+ * data is clean. If the difference is non-zero, you look up the
+ * difference in the syndrome table to identify the "effect" that
+ * is missing, which is the bit that is flipped.
+ *
+ * Notice that ECC bit flips are recorded by a single "effect"
+ * bit (ie. 0x1, 0x2, 0x4, 0x8 ...) and double bit flips are identified
+ * by the UE status in the table.
+ *
+ * Bits are in MSB order.
+ */
+static uint8_t syndromeMatrix[] = {
+ ECC_GD, ECC_E7, ECC_E6, ECC_UE, ECC_E5, ECC_UE, ECC_UE, 47,
+ ECC_E4, ECC_UE, ECC_UE, 37, ECC_UE, 35, 39, ECC_UE,
+ ECC_E3, ECC_UE, ECC_UE, 48, ECC_UE, 30, 29, ECC_UE,
+ ECC_UE, 57, 27, ECC_UE, 31, ECC_UE, ECC_UE, ECC_UE,
+ ECC_E2, ECC_UE, ECC_UE, 17, ECC_UE, 18, 40, ECC_UE,
+ ECC_UE, 58, 22, ECC_UE, 21, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, 16, 49, ECC_UE, 19, ECC_UE, ECC_UE, ECC_UE,
+ 23, ECC_UE, ECC_UE, ECC_UE, ECC_UE, 20, ECC_UE, ECC_UE,
+ ECC_E1, ECC_UE, ECC_UE, 51, ECC_UE, 46, 9, ECC_UE,
+ ECC_UE, 34, 10, ECC_UE, 32, ECC_UE, ECC_UE, 36,
+ ECC_UE, 62, 50, ECC_UE, 14, ECC_UE, ECC_UE, ECC_UE,
+ 13, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, 61, 8, ECC_UE, 41, ECC_UE, ECC_UE, ECC_UE,
+ 11, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ 15, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, ECC_UE, 12, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_E0, ECC_UE, ECC_UE, 55, ECC_UE, 45, 43, ECC_UE,
+ ECC_UE, 56, 38, ECC_UE, 1, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, 25, 26, ECC_UE, 2, ECC_UE, ECC_UE, ECC_UE,
+ 24, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, 28, ECC_UE,
+ ECC_UE, 59, 54, ECC_UE, 42, ECC_UE, ECC_UE, 44,
+ 6, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ 5, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, 63, 53, ECC_UE, 0, ECC_UE, ECC_UE, ECC_UE,
+ 33, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ 3, ECC_UE, ECC_UE, 52, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ 7, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, 60, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, ECC_UE, ECC_UE, ECC_UE, 4, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+};
+
+/** Returns the parity of x, i.e. the number of 1-bits in x modulo 2.
+ * Replacement for __builtin_parityl
+ */
+uint8_t parity_check( uint64_t i_data )
+{
+ int ones = 0;
+ size_t x;
+ for( x=0; x<(sizeof(i_data)*8); x++ )
+ {
+ if( i_data & (0x8000000000000000ull >> x) )
+ {
+ ones++;
+ }
+ }
+ return ones%2;
+}
+
+/** Create the ECC field corresponding to a 8-byte data field
+ *
+ * @param[in] i_data - The 8 byte data to generate ECC for.
+ * @return The 1 byte ECC corresponding to the data.
+ */
+uint8_t generateECC(uint64_t i_data)
+{
+ uint8_t result = 0;
+
+ int i = 0;
+ for (i = 0; i < 8; i++)
+ {
+ result |= (parity_check(eccMatrix[i] & i_data) << i);
+ }
+
+ return result;
+}
+
+/** Verify the data and ECC match or indicate how they are wrong.
+ *
+ * @param[in] i_data - The data to check ECC on.
+ * @param[in] i_ecc - The [supposed] ECC for the data.
+ *
+ * @return eccBitfield or 0-64.
+ *
+ * @retval GD - Indicates the data is good (matches ECC).
+ * @retval UE - Indicates the data is uncorrectable.
+ * @retval all others - Indication of which bit is incorrect.
+ */
+uint8_t verifyECC(uint64_t i_data, uint8_t i_ecc)
+{
+ return syndromeMatrix[generateECC(i_data) ^ i_ecc];
+}
+
+/** Correct the data and/or ECC.
+ *
+ * @param[in,out] io_data - Data to check / correct.
+ * @param[in,out] io_ecc - ECC to check / correct.
+ *
+ * @return eccBitfield or 0-64.
+ *
+ * @retval GD - Data is good.
+ * @retval UE - Data is uncorrectable.
+ * @retval all others - which bit was corrected.
+ */
+uint8_t correctECC(uint64_t* io_data, uint8_t* io_ecc)
+{
+ uint8_t badBit = verifyECC(*io_data, *io_ecc);
+
+ if ((badBit != ECC_GD) && (badBit != ECC_UE)) /* Good is done, UE is hopeless. */
+ {
+ /* Determine if the ECC or data part is bad, do bit flip. */
+ if (badBit >= ECC_E7)
+ {
+ *io_ecc ^= (1 << (badBit - ECC_E7));
+ }
+ else
+ {
+ *io_data ^= (1ul << (63 - badBit));
+ }
+ }
+ return badBit;
+}
+
+void injectECC(const uint8_t* i_src,
+ size_t i_srcSz,
+ uint8_t* o_dst)
+{
+ assert(0 == (i_srcSz % sizeof(uint64_t)));
+
+ size_t i = 0;
+ size_t o = 0;
+ for(i = 0, o = 0;
+ i < i_srcSz;
+ i += sizeof(uint64_t), o += sizeof(uint64_t) + sizeof(uint8_t))
+ {
+ /* Read data word, copy to destination. */
+ uint64_t data = *((const uint64_t*)(&i_src[i]));
+ *((uint64_t*)(&o_dst[o])) = data;
+ data = be64toh(data);
+
+ /* Calculate ECC, copy to destination. */
+ uint8_t ecc = generateECC(data);
+ o_dst[o + sizeof(uint64_t)] = ecc;
+ }
+}
+
+eccStatus removeECC(uint8_t* io_src,
+ uint8_t* o_dst, size_t i_dstSz)
+{
+ assert(0 == (i_dstSz % sizeof(uint64_t)));
+
+ eccStatus rc = ECC_CLEAN;
+
+ size_t i = 0, o = 0;
+ for(i = 0, o = 0;
+ o < i_dstSz;
+ i += sizeof(uint64_t) + sizeof(uint8_t), o += sizeof(uint64_t))
+ {
+ /* Read data and ECC parts. */
+ uint64_t data = *((uint64_t*)(&io_src[i]));
+ data = be64toh(data);
+ uint8_t ecc = io_src[i + sizeof(uint64_t)];
+
+ /* Calculate failing bit and fix data. */
+ uint8_t badBit = correctECC(&data, &ecc);
+
+ /* Return data to big endian. */
+ data = htobe64(data);
+
+ /* Perform correction and status update. */
+ if (badBit == ECC_UE)
+ {
+ rc = ECC_UNCORRECTABLE;
+ }
+ else if (badBit != ECC_GD)
+ {
+ if (rc != ECC_UNCORRECTABLE)
+ {
+ rc = ECC_CORRECTED;
+ }
+ *((uint64_t*)(&io_src[i])) = data;
+ io_src[i + sizeof(uint64_t)] = ecc;
+ }
+
+ /* Copy fixed data to destination buffer. */
+ *((uint64_t*)(&o_dst[o])) = data;
+ }
+
+ return rc;
+}
+
diff --git a/src/occ_gpe0/firdata/ecc.h b/src/occ_gpe0/firdata/ecc.h
new file mode 100644
index 0000000..12ffe4e
--- /dev/null
+++ b/src/occ_gpe0/firdata/ecc.h
@@ -0,0 +1,76 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/ecc.H $ */
+/* */
+/* 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 */
+#ifndef __PNOR_ECC_H
+#define __PNOR_ECC_H
+
+#include <native.h>
+
+/** @file ecc.H
+ * @brief Interfaces for the P8 8-byte ECC algorithm.
+ */
+
+/** Status for the ECC removal function. */
+typedef uint8_t eccStatus;
+#define ECC_CLEAN 0x00 /*< No ECC Error was detected. */
+#define ECC_CORRECTED 0x01 /*< ECC error detected and corrected. */
+#define ECC_UNCORRECTABLE 0x02 /*< ECC error detected and uncorrectable. */
+
+/** Bit field identifiers for syndrome calculations. */
+typedef uint8_t eccBitfields;
+#define ECC_GD 0xff /*< Good ECC matches. */
+#define ECC_UE 0xfe /*< Uncorrectable. */
+#define ECC_E0 71 /*< Error in ECC bit 0 */
+#define ECC_E1 70 /*< Error in ECC bit 1 */
+#define ECC_E2 69 /*< Error in ECC bit 2 */
+#define ECC_E3 68 /*< Error in ECC bit 3 */
+#define ECC_E4 67 /*< Error in ECC bit 4 */
+#define ECC_E5 66 /*< Error in ECC bit 5 */
+#define ECC_E6 65 /*< Error in ECC bit 6 */
+#define ECC_E7 64 /*< Error in ECC bit 7 */
+
+/** Inject ECC into a data stream.
+ *
+ * @param[in] i_src - Source data to create ECC on.
+ * @param[in] i_srcSz - Size in bytes of source data.
+ * @param[out] o_dst - Destination buffer of data+ECC.
+ *
+ * @note i_srcSz must be a multiple of 8 bytes.
+ */
+void injectECC(const uint8_t* i_src, size_t i_srcSz,
+ uint8_t* o_dst);
+
+/** Remove ECC from a data stream.
+ *
+ * @param[in,out] io_src - Source data+ECC stream.
+ * @param[out] o_dst - Destination buffer for data only.
+ * @param[in] i_dstSz - Size in bytes of destination ((srcSz / 9) * 8).
+ *
+ * @note i_dstSz must be a multiple of 8 bytes.
+ */
+eccStatus removeECC(uint8_t* io_src,
+ uint8_t* o_dst, size_t i_dstSz);
+
+
+#endif
diff --git a/src/occ_gpe0/firdata/firData.c b/src/occ_gpe0/firdata/firData.c
new file mode 100644
index 0000000..299f92b
--- /dev/null
+++ b/src/occ_gpe0/firdata/firData.c
@@ -0,0 +1,1389 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/firData.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 <native.h>
+
+#include <homerData_common.h>
+#include <pnorData_common.h>
+#include <pnor_util.h>
+#include <scom_trgt.h>
+#include <scom_util.h>
+
+/** Keeps track of pointers to register lists in the HOMER data for each target
+ * type. */
+typedef struct
+{
+ uint32_t * glbl; /*/< Global registers */
+ uint32_t * fir; /*/< Normal FIRs */
+ uint32_t * reg; /*/< Normal registers */
+ uint64_t * idFir; /*/< Indirect-SCOM FIRs */
+ uint64_t * idReg; /*/< Indirect-SCOM registers */
+} FirData_ListPointers_t;
+
+/** Contains pointers and sizes for the HOMER and PNOR data buffers. */
+typedef struct
+{
+ uint8_t * hBuf; /*/< Pointer to the HOMER data buffer */
+ uint32_t maxHBufSize; /*/< Maximum size of the HOMER data buffer */
+ HOMER_Data_t * hData; /*/< Pointer to the HOMER header data */
+
+ uint8_t * pBuf; /*/< Pointer to the PNOR data buffer */
+ uint32_t maxPBufSize; /*/< Maximum size of the PNOR data buffer */
+ PNOR_Data_t * pData; /*/< Pointer to the PNOR header data */
+ uint32_t pBufSize; /*/< Current size of the PNOR data buffer */
+
+ FirData_ListPointers_t hPtrs[TRGT_MAX]; /*/< Pointers to the reg lists */
+
+ HOMER_ChipSpecAddr_t * ecDepReg; /*/< EC dependent regs */
+
+} FirData_t;
+
+
+/** We move the chiplet exist bit fields into this structure left */
+/** justified for easy checking of the fields with a mask */
+typedef struct
+{
+ uint32_t xbusMask;
+ uint32_t obusMask;
+ uint32_t ecMask;
+
+ uint32_t eqMask;
+ uint32_t exMask;
+ uint32_t mcbist_mc_Mask;
+ uint32_t mcs_mi_Mask;
+ uint32_t mca_dmi_Mask;
+
+ uint32_t cappMask;
+ uint32_t pecMask;
+ uint32_t phbMask;
+
+} FirData_existBits_t;
+
+/* Uncomment for additional debug traces */
+#if 0
+#define DEBUG_PRD_CHKSTOP_ANALYSIS
+#endif
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Add generic data to the PNOR buffer.
+ * @param io_fd The FIR data stuct.
+ * @param i_data Pointer to the data to add to the buffer.
+ * @param i_dataSize Size of the data to add to the buffer.
+ * @return True, if where is no room to add the new data. False, otherwise.
+ */
+bool FirData_addDataToPnor( FirData_t * io_fd, void * i_data,
+ uint32_t i_dataSize )
+{
+ bool full = (io_fd->maxPBufSize < io_fd->pBufSize + i_dataSize);
+
+ if ( full )
+ {
+ /* Indicate the PNOR data is full. */
+ io_fd->pData->full = 1;
+ }
+ else
+ {
+ /* Copy data to PNOR buffer. */
+ memcpy( &io_fd->pBuf[io_fd->pBufSize], i_data, i_dataSize );
+ io_fd->pBufSize += i_dataSize;
+ }
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief SCOMs hardware and adds a normal register to PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @param i_addr 32-bit address to SCOM.
+ * @param o_nonZero True if the value of the register was non-zero. False,
+ * otherwise.
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addRegToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt, uint32_t i_addr,
+ bool * o_nonZero )
+{
+ bool full = false;
+
+ int32_t rc = 0;
+ PNOR_Reg_t reg = { i_addr, 0 };
+
+ *o_nonZero = false;
+
+ do
+ {
+ rc = SCOM_getScom( i_sTrgt, i_addr, &(reg.val) );
+ if ( SUCCESS != rc )
+ {
+ TRAC_ERR( "[FirData_addRegToPnor] t=%d p=%d u=%d rc=%d "
+ "addr=0x%08x val=0x%08x%08x", i_sTrgt.type,
+ i_sTrgt.procPos, i_sTrgt.procUnitPos, rc, i_addr,
+ (uint32_t)(reg.val >> 32), (uint32_t)reg.val );
+
+ if ( io_pTrgt->scomErrs < PNOR_Trgt_MAX_SCOM_ERRORS )
+ io_pTrgt->scomErrs++;
+
+ break;
+ }
+
+ if ( 0 == reg.val ) break; // Skip zero value registers.
+
+ full = FirData_addDataToPnor( io_fd, &reg, sizeof(reg) );
+ if ( full ) break;
+
+ *o_nonZero = true;
+
+ if ( io_pTrgt->regs < PNOR_Trgt_MAX_REGS_PER_TRGT )
+ io_pTrgt->regs++;
+
+ } while (0);
+
+#ifdef DEBUG_PRD_CHKSTOP_ANALYSIS
+ TRAC_INFO(" addToPnor: Type:%d Pos:%d Unit:%d Addr:%X Full:%d",
+ i_sTrgt.type, i_sTrgt.procPos, i_sTrgt.procUnitPos,
+ i_addr, full );
+#endif
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief SCOMs hardware and add a indirect-SCOM register to PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @param i_sTrgt Target to SCOM.
+ * @param i_addr 64-bit address to SCOM.
+ * @param o_nonZero True if the value of the register was non-zero. False,
+ * otherwise.
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addIdRegToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt, uint64_t i_addr,
+ bool * o_nonZero )
+{
+ bool full = false;
+
+ int32_t rc = 0;
+ PNOR_IdReg_t reg = { i_addr, 0 };
+
+ *o_nonZero = false;
+
+ do
+ {
+ rc = SCOM_getIdScom( i_sTrgt, i_addr, &(reg.val) );
+ if ( SUCCESS != rc )
+ {
+ if ( io_pTrgt->scomErrs < PNOR_Trgt_MAX_SCOM_ERRORS )
+ io_pTrgt->scomErrs++;
+ break;
+ }
+
+ if ( 0 == reg.val ) break; // Skip zero value registers.
+
+ full = FirData_addDataToPnor( io_fd, &reg, sizeof(reg) );
+ if ( full ) break;
+
+ *o_nonZero = true;
+
+ if ( io_pTrgt->idRegs < PNOR_Trgt_MAX_ID_REGS_PER_TRGT )
+ io_pTrgt->idRegs++;
+
+ } while (0);
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates a list of global registers and adds them to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @param o_noAttn True, if the global registers showed no active attentions
+ * on the target. False, otherwise.
+ * @param i_chipStruct Provides chipType and ecLevel we need
+ * for EC dependent regs
+ *
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addGlblsToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt, bool * o_noAttn,
+ HOMER_Chip_t *i_chipStruct )
+{
+ bool full = false;
+ bool l_isAnyGlobal = false; /* true when we find global reg */
+ bool l_isAnyNonZero = false; /* true if ATTN is active on any reg */
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->regCounts[t][REG_GLBL];
+
+ uint32_t i = 0;
+
+ uint32_t addr = 0;
+ bool nonZero = false;
+
+ *o_noAttn = false; /* Must be false if there are no global regs. */
+
+ if ( 0 != cnt )
+ {
+ /** If we get here, we have GLOBALS for this target **/
+ l_isAnyGlobal = true;
+
+ for ( i = 0; i < cnt; i++ )
+ {
+ addr = io_fd->hPtrs[t].glbl[i];
+ nonZero = false;
+
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr,
+ &nonZero );
+ if ( full ) break;
+
+ if ( nonZero ) l_isAnyNonZero = true;
+ }
+ }
+
+
+ /** Handle EC dependent registers, if any */
+ HOMER_ChipSpecAddr_t *l_ecAddrtPtr = io_fd->ecDepReg;
+ cnt = io_fd->hData->ecDepCounts;
+
+ /** We have a structure with one element for each EC dep address. */
+ /** Need to loop thru and verify we have same regType among */
+ /** other things prior to using the address. */
+ for ( i = 0; i < cnt; i++ )
+ {
+#ifdef DEBUG_PRD_CHKSTOP_ANALYSIS
+ TRAC_INFO(" addGlblsToPnor In/Array: chipType:%X::%X trgType:%X::%X"
+ " regType:%X::%X ecLevel %X::%X",
+ i_chipStruct->chipType, l_ecAddrtPtr->chipType,
+ t, l_ecAddrtPtr->trgtType,
+ REG_GLBL, l_ecAddrtPtr->regType,
+ i_chipStruct->chipEcLevel, l_ecAddrtPtr->ddLevel );
+#endif
+
+ /** Need same chipType (nimbus,cumulus,etc..), same target type, */
+ /** same register type and EC level must match too */
+ if ( (l_ecAddrtPtr->chipType == i_chipStruct->chipType) &&
+ (l_ecAddrtPtr->trgtType == t ) &&
+ (l_ecAddrtPtr->regType == REG_GLBL) &&
+ (l_ecAddrtPtr->ddLevel == i_chipStruct->chipEcLevel)
+ )
+ {
+ /** If we get here, we have GLOBALS for this target **/
+ l_isAnyGlobal = true;
+
+ /* address is right justified in 64 bits */
+ addr = (uint32_t)(l_ecAddrtPtr->address);
+ nonZero = false;
+
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr,
+ &nonZero );
+ if ( full ) break;
+
+ if ( nonZero ) l_isAnyNonZero = true;
+ } /* end if we found an EC dep reg */
+
+ /* prep pointer for next element (if any) */
+ l_ecAddrtPtr++;
+
+ } /** end EC dependent reg loop */
+
+ /* If we have no GLOBALS, we want to collect other regs */
+ /* so then we want to return 'attn is active)'. */
+ /* If we have GLOBALS, then we need non-zero reg to */
+ /* collect the rest of the regs (attn is active). */
+ if ( (true == l_isAnyGlobal) && (false == l_isAnyNonZero) )
+ {
+ /* This indicates we won't collect additional regs */
+ *o_noAttn = true; /* starts out as false */
+ }
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates a list of FIRs and adds them to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @param i_chipStruct Provides chipType and ecLevel we need
+ * for EC dependent regs
+ *
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addFirsToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt,
+ HOMER_Chip_t *i_chipStruct )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->regCounts[t][REG_FIR];
+
+ uint32_t i = 0;
+
+ uint32_t addr = 0;
+ bool nonZero = false;
+ bool tmp = false; /* ignored, not used */
+
+ for ( i = 0; i < cnt; i++ )
+ {
+ addr = io_fd->hPtrs[t].fir[i];
+ nonZero = false;
+
+ /* Add FIR */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr, &nonZero );
+ if ( full ) break;
+
+ /* Add MASK */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr + 3, &tmp );
+ if ( full ) break;
+
+ if ( nonZero )
+ {
+ /* Add ACT0 */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr + 6,
+ &tmp );
+ if ( full ) break;
+
+ /* Add ACT1 */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr + 7,
+ &tmp );
+ if ( full ) break;
+ }
+ }
+
+
+ /** Handle EC dependent registers, if any */
+ HOMER_ChipSpecAddr_t *l_ecAddrtPtr = io_fd->ecDepReg;
+ cnt = io_fd->hData->ecDepCounts;
+
+ /** We have a structure with one element for each EC dep address. */
+ /** Need to loop thru and verify we have same regType among */
+ /** other things prior to using the address. */
+ for ( i = 0; i < cnt; i++ )
+ {
+#ifdef DEBUG_PRD_CHKSTOP_ANALYSIS
+ TRAC_INFO(" addFirsToPnor In/Array: chipType:%X::%X trgType:%X::%X"
+ " regType:%X::%X ecLevel %X::%X",
+ i_chipStruct->chipType, l_ecAddrtPtr->chipType,
+ t, l_ecAddrtPtr->trgtType,
+ REG_GLBL, l_ecAddrtPtr->regType,
+ i_chipStruct->chipEcLevel, l_ecAddrtPtr->ddLevel );
+#endif
+
+ /** Need same chipType (nimbus,cumulus,etc..), same target type, */
+ /** same register type and EC level must match too */
+ if ( (l_ecAddrtPtr->chipType == i_chipStruct->chipType) &&
+ (l_ecAddrtPtr->trgtType == t ) &&
+ (l_ecAddrtPtr->regType == REG_FIR) &&
+ (l_ecAddrtPtr->ddLevel == i_chipStruct->chipEcLevel)
+ )
+ { /* address is right justified in 64 bits */
+ addr = (uint32_t)(l_ecAddrtPtr->address);
+ nonZero = false;
+
+ /* Add FIR */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr, &nonZero );
+ if ( full ) break;
+
+ /* Add MASK */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr + 3, &tmp );
+ if ( full ) break;
+
+ if ( nonZero )
+ {
+ /* Add ACT0 */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr + 6,
+ &tmp );
+ if ( full ) break;
+
+ /* Add ACT1 */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr + 7,
+ &tmp );
+ if ( full ) break;
+ }
+
+ } /* end if we found an EC dep reg */
+
+ /* prep pointer for next element (if any) */
+ l_ecAddrtPtr++;
+
+ } /** end EC dependent reg loop */
+
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates a list of REGs and adds them to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @param i_chipStruct Provides chipType and ecLevel we need
+ * for EC dependent regs
+ *
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addRegsToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt,
+ HOMER_Chip_t *i_chipStruct )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->regCounts[t][REG_REG];
+
+ uint32_t i = 0;
+
+ uint32_t addr = 0;
+ bool tmp = false; /* ignored, not used */
+
+ for ( i = 0; i < cnt; i++ )
+ {
+ addr = io_fd->hPtrs[t].reg[i];
+
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr, &tmp );
+ if ( full ) break;
+ }
+
+ /** Handle EC dependent registers, if any */
+ HOMER_ChipSpecAddr_t *l_ecAddrtPtr = io_fd->ecDepReg;
+ cnt = io_fd->hData->ecDepCounts;
+
+ /** We have a structure with one element for each EC dep address. */
+ /** Need to loop thru and verify we have same regType among */
+ /** other things prior to using the address. */
+ for ( i = 0; i < cnt; i++ )
+ {
+#ifdef DEBUG_PRD_CHKSTOP_ANALYSIS
+ TRAC_INFO(" addRegsToPnor In/Array: chipType:%X::%X trgType:%X::%X"
+ " regType:%X::%X ecLevel %X::%X",
+ i_chipStruct->chipType, l_ecAddrtPtr->chipType,
+ t, l_ecAddrtPtr->trgtType,
+ REG_GLBL, l_ecAddrtPtr->regType,
+ i_chipStruct->chipEcLevel, l_ecAddrtPtr->ddLevel );
+#endif
+
+ /** Need same chipType (nimbus,cumulus,etc..), same target type, */
+ /** same register type and EC level must match too */
+ if ( (l_ecAddrtPtr->chipType == i_chipStruct->chipType) &&
+ (l_ecAddrtPtr->trgtType == t ) &&
+ (l_ecAddrtPtr->regType == REG_REG) &&
+ (l_ecAddrtPtr->ddLevel == i_chipStruct->chipEcLevel)
+ )
+ { /* address is right justified in 64 bits */
+ addr = (uint32_t)(l_ecAddrtPtr->address);
+
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr,
+ &tmp );
+ if ( full ) break;
+ } /* end if we found an EC dep reg */
+
+ /* prep pointer for next element (if any) */
+ l_ecAddrtPtr++;
+
+ } /** end EC dependent reg loop */
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates a list of IDFIRs and adds them to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @param i_chipStruct Provides chipType and ecLevel we need
+ * for EC dependent regs
+ *
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addIdFirsToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt,
+ HOMER_Chip_t *i_chipStruct )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->regCounts[t][REG_IDFIR];
+
+ uint32_t i = 0;
+
+ uint64_t addr = 0;
+ bool nonZero = false;
+ bool tmp = false; /* ignored, not used */
+
+ for ( i = 0; i < cnt; i++ )
+ {
+ addr = io_fd->hPtrs[t].idFir[i];
+ nonZero = false;
+
+ /* Add FIR */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr,
+ &nonZero );
+ if ( full ) break;
+
+ /* Add MASK */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt,
+ addr + 0x300000000ll, &tmp );
+ if ( full ) break;
+
+ if ( nonZero )
+ {
+ /* Add ACT0 */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt,
+ addr + 0x600000000ll, &tmp );
+ if ( full ) break;
+
+ /* Add ACT1 */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt,
+ addr + 0x700000000ll, &tmp );
+ if ( full ) break;
+ }
+ }
+
+
+ /** Handle EC dependent registers, if any */
+ HOMER_ChipSpecAddr_t *l_ecAddrtPtr = io_fd->ecDepReg;
+ cnt = io_fd->hData->ecDepCounts;
+
+ /** We have a structure with one element for each EC dep address. */
+ /** Need to loop thru and verify we have same regType among */
+ /** other things prior to using the address. */
+ for ( i = 0; i < cnt; i++ )
+ {
+#ifdef DEBUG_PRD_CHKSTOP_ANALYSIS
+ TRAC_INFO(" addIdFirsToPnor In/Array: chipType:%X::%X trgType:%X::%X"
+ " regType:%X::%X ecLevel %X::%X",
+ i_chipStruct->chipType, l_ecAddrtPtr->chipType,
+ t, l_ecAddrtPtr->trgtType,
+ REG_GLBL, l_ecAddrtPtr->regType,
+ i_chipStruct->chipEcLevel, l_ecAddrtPtr->ddLevel );
+#endif
+
+ /** Need same chipType (nimbus,cumulus,etc..), same target type, */
+ /** same register type and EC level must match too */
+ if ( (l_ecAddrtPtr->chipType == i_chipStruct->chipType) &&
+ (l_ecAddrtPtr->trgtType == t ) &&
+ (l_ecAddrtPtr->regType == REG_IDFIR) &&
+ (l_ecAddrtPtr->ddLevel == i_chipStruct->chipEcLevel)
+ )
+ { /* need full 64 bit address here */
+ addr = l_ecAddrtPtr->address;
+ nonZero = false;
+
+ /* Add FIR */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr,
+ &nonZero );
+ if ( full ) break;
+
+ /* Add MASK */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt,
+ addr + 0x300000000ll, &tmp );
+ if ( full ) break;
+
+ if ( nonZero )
+ {
+ /* Add ACT0 */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt,
+ addr + 0x600000000ll, &tmp );
+ if ( full ) break;
+
+ /* Add ACT1 */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt,
+ addr + 0x700000000ll, &tmp );
+ if ( full ) break;
+ }
+
+ } /* end if we found an EC dep reg */
+
+ /* prep pointer for next element (if any) */
+ l_ecAddrtPtr++;
+
+ } /** end EC dependent reg loop */
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates a list of IDREGs and adds them to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @param i_chipStruct Provides chipType and ecLevel we need
+ * for EC dependent regs
+ *
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addIdRegsToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt,
+ HOMER_Chip_t *i_chipStruct )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->regCounts[t][REG_IDREG];
+
+ uint32_t i = 0;
+
+ uint64_t addr = 0;
+ bool tmp = false; /* ignored, not used */
+
+ for ( i = 0; i < cnt; i++ )
+ {
+ addr = io_fd->hPtrs[t].idReg[i];
+
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr, &tmp );
+ if ( full ) break;
+ }
+
+
+ /** Handle EC dependent registers, if any */
+ HOMER_ChipSpecAddr_t *l_ecAddrtPtr = io_fd->ecDepReg;
+ cnt = io_fd->hData->ecDepCounts;
+
+ /** We have a structure with one element for each EC dep address. */
+ /** Need to loop thru and verify we have same regType among */
+ /** other things prior to using the address. */
+ for ( i = 0; i < cnt; i++ )
+ {
+#ifdef DEBUG_PRD_CHKSTOP_ANALYSIS
+ TRAC_INFO(" addIdRegsToPnor In/Array: chipType:%X::%X trgType:%X::%X"
+ " regType:%X::%X ecLevel %X::%X",
+ i_chipStruct->chipType, l_ecAddrtPtr->chipType,
+ t, l_ecAddrtPtr->trgtType,
+ REG_GLBL, l_ecAddrtPtr->regType,
+ i_chipStruct->chipEcLevel, l_ecAddrtPtr->ddLevel );
+#endif
+
+ /** Need same chipType (nimbus,cumulus,etc..), same target type, */
+ /** same register type and EC level must match too */
+ if ( (l_ecAddrtPtr->chipType == i_chipStruct->chipType) &&
+ (l_ecAddrtPtr->trgtType == t ) &&
+ (l_ecAddrtPtr->regType == REG_IDREG) &&
+ (l_ecAddrtPtr->ddLevel == i_chipStruct->chipEcLevel)
+ )
+ { /* Using full 64 bit address here */
+ addr = l_ecAddrtPtr->address;
+
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr, &tmp );
+ if ( full ) break;
+ } /* end if we found an EC dep reg */
+
+ /* prep pointer for next element (if any) */
+ l_ecAddrtPtr++;
+
+ } /** end EC dependent reg loop */
+
+
+ return full;
+}
+
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Adds a target to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param i_sTrgt SCOM Target.
+ * @param o_noAttn True, if the global registers showed no active
+ * attentions on the target. False, otherwise.
+ * @param i_chipStruct Provides chipType and ecLevel we need
+ * for EC dependent regs
+ *
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addTrgtToPnor( FirData_t * io_fd, SCOM_Trgt_t i_sTrgt,
+ bool * o_noAttn, HOMER_Chip_t *i_chipStruct )
+{
+ bool full = false;
+
+ PNOR_Trgt_t * pTrgt = (PNOR_Trgt_t *)(&io_fd->pBuf[io_fd->pBufSize]);
+
+ PNOR_Trgt_t tmp_pTrgt = PNOR_getTrgt( i_sTrgt.type, i_sTrgt.procPos,
+ i_sTrgt.procUnitPos );
+
+ *o_noAttn = false; /* Must be false if there are no global regs. */
+
+ TRAC_IMP( "FIRDATA: t=%d p=%d u=%d FSI=0x%08x isM=%c", i_sTrgt.type,
+ i_sTrgt.procPos, i_sTrgt.procUnitPos, i_sTrgt.fsiBaseAddr,
+ i_sTrgt.isMaster ? 'T' : 'F' );
+
+ do
+ {
+ /* Add the target info to PNOR. */
+ full = FirData_addDataToPnor( io_fd, &tmp_pTrgt, sizeof(tmp_pTrgt) );
+ if ( full ) break;
+
+ /* Update the number of targets in the PNOR data. */
+ io_fd->pData->trgts++;
+
+ /* NOTE: Must add all regular registers (REG_GLBL, REG_FIR, REG_REG)
+ * before all indirect-SCOM registers. Also, must check REG_GLBL
+ * registers first to determine whether it is necessary to do the
+ * other registers. */
+
+ /* Add the GLBLs. */
+ full = FirData_addGlblsToPnor( io_fd, pTrgt, i_sTrgt, o_noAttn, i_chipStruct );
+ if ( full || *o_noAttn ) break;
+
+ /* Add the FIRs. */
+ full = FirData_addFirsToPnor( io_fd, pTrgt, i_sTrgt, i_chipStruct );
+ if ( full ) break;
+
+ /* Add the REGs. */
+ full = FirData_addRegsToPnor( io_fd, pTrgt, i_sTrgt, i_chipStruct );
+ if ( full ) break;
+
+ /* Add the IDFIRs. */
+ full = FirData_addIdFirsToPnor( io_fd, pTrgt, i_sTrgt, i_chipStruct );
+ if ( full ) break;
+
+ /* Add the IDREGs. */
+ full = FirData_addIdRegsToPnor( io_fd, pTrgt, i_sTrgt, i_chipStruct );
+ if ( full ) break;
+
+ } while (0);
+
+ return full;
+}
+
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates through configured targets and adds the data to PNOR.
+ * @param io_fd The FIR data stuct.
+ */
+void FirData_addTrgtsToPnor( FirData_t * io_fd )
+{
+ bool full = false;
+ bool noAttn = false;
+
+ uint8_t p = 0;
+ uint8_t u = 0;
+ uint8_t l_unit = 0;
+
+ bool isM = false;
+ uint32_t fsi = 0;
+
+ SCOM_Trgt_t sTrgt;
+ FirData_existBits_t l_existBits;
+
+ do
+ {
+ memset(&l_existBits, 0x00, sizeof(FirData_existBits_t) );
+
+ /* Point past HOMER header to first chiplet info */
+ /* The HOMER_Data_t struct may have some padding added after the struct
+ * to ensure the HOMER_Chip_t structs are 4-byte word aligned. */
+ uint32_t sz_word = sizeof(uint32_t);
+ uint32_t pad = (sz_word - (sizeof(HOMER_Data_t) % sz_word)) % sz_word;
+ uint8_t *l_bytePtr = io_fd->hBuf + sizeof(HOMER_Data_t) + pad;
+ HOMER_Chip_t *l_chipPtr = NULL;
+
+ TRAC_INFO("AddTgtsMain:numChips:%d", io_fd->hData->chipCount);
+
+ /* Iterate ALL CHIPs */
+ for ( p = 0; p < io_fd->hData->chipCount; p++ )
+ {
+ l_chipPtr = (HOMER_Chip_t *)l_bytePtr;
+
+ /* get FSI base address and chip position (proc or centaur) */
+ fsi = l_chipPtr->fsiBaseAddr;
+ p = l_chipPtr->chipPos;
+
+ TRAC_INFO( " AddTgtsMain:ChipType:%d ChipNumber:%d",
+ l_chipPtr->chipType, p );
+
+ /* Is this a PROC or Centaur chip ? */
+ if ( (HOMER_CHIP_NIMBUS == l_chipPtr->chipType) ||
+ (HOMER_CHIP_CUMULUS == l_chipPtr->chipType) )
+ {
+ /* To access the 'chiplet exist' structure */
+ l_bytePtr += sizeof(HOMER_Chip_t);
+
+ /* 'Existing chiplet area' varies in size */
+ if (HOMER_CHIP_NIMBUS == l_chipPtr->chipType)
+ {
+ HOMER_ChipNimbus_t *l_nimExistBitPtr =
+ (HOMER_ChipNimbus_t *)l_bytePtr;
+
+ /* get master proc indicator */
+ isM = l_nimExistBitPtr->isMaster;
+
+ /* Exist bit structure can differ so move to */
+ /* common format and left justify for ease of use */
+ l_existBits.xbusMask = ((uint32_t)(l_nimExistBitPtr->xbusMask))
+ << (32 - MAX_XBUS_PER_PROC);
+ l_existBits.obusMask = ((uint32_t)(l_nimExistBitPtr->obusMask))
+ << (32 - MAX_OBUS_PER_PROC);
+ l_existBits.ecMask = ((uint32_t)(l_nimExistBitPtr->ecMask))
+ << (32 - MAX_EC_PER_PROC);
+ l_existBits.eqMask = ((uint32_t)(l_nimExistBitPtr->eqMask))
+ << (32 - MAX_EQ_PER_PROC);
+ l_existBits.exMask = ((uint32_t)(l_nimExistBitPtr->exMask))
+ << (32 - MAX_EX_PER_PROC);
+ l_existBits.mcbist_mc_Mask = ((uint32_t)(l_nimExistBitPtr->mcbistMask))
+ << (32 - MAX_MCBIST_PER_PROC);
+ l_existBits.mcs_mi_Mask = ((uint32_t)(l_nimExistBitPtr->mcsMask))
+ << (32 - MAX_MCS_PER_PROC);
+ l_existBits.mca_dmi_Mask = ((uint32_t)(l_nimExistBitPtr->mcaMask))
+ << (32 - MAX_MCA_PER_PROC);
+ l_existBits.cappMask = ((uint32_t)(l_nimExistBitPtr->cappMask))
+ << (32 - MAX_CAPP_PER_PROC);
+ l_existBits.pecMask = ((uint32_t)(l_nimExistBitPtr->pecMask))
+ << (32 - MAX_PEC_PER_PROC);
+ l_existBits.phbMask = ((uint32_t)(l_nimExistBitPtr->phbMask))
+ << (32 - MAX_PHB_PER_PROC);
+
+ /* advance our pointer to next chip type */
+ l_bytePtr += sizeof(HOMER_ChipNimbus_t);
+
+ } /* if nimbus */
+ else if (HOMER_CHIP_CUMULUS == l_chipPtr->chipType)
+ {
+ HOMER_ChipCumulus_t *l_cumExistBitPtr =
+ (HOMER_ChipCumulus_t *)l_bytePtr;
+
+ /* get master proc indicator */
+ isM = l_cumExistBitPtr->isMaster;
+
+ /* Exist bit structure can differ so move to */
+ /* common format and left justify for ease of use */
+ l_existBits.xbusMask = ((uint32_t)(l_cumExistBitPtr->xbusMask))
+ << (32 - MAX_XBUS_PER_PROC);
+ l_existBits.obusMask = ((uint32_t)(l_cumExistBitPtr->obusMask))
+ << (32 - MAX_OBUS_PER_PROC);
+ l_existBits.ecMask = ((uint32_t)(l_cumExistBitPtr->ecMask))
+ << (32 - MAX_EC_PER_PROC);
+ l_existBits.eqMask = ((uint32_t)(l_cumExistBitPtr->eqMask))
+ << (32 - MAX_EQ_PER_PROC);
+ l_existBits.exMask = ((uint32_t)(l_cumExistBitPtr->exMask))
+ << (32 - MAX_EX_PER_PROC);
+ l_existBits.mcbist_mc_Mask = ((uint32_t)(l_cumExistBitPtr->mcMask))
+ << (32 - MAX_MC_PER_PROC);
+ l_existBits.mcs_mi_Mask = ((uint32_t)(l_cumExistBitPtr->miMask))
+ << (32 - MAX_MI_PER_PROC);
+ l_existBits.mca_dmi_Mask = ((uint32_t)(l_cumExistBitPtr->dmiMask))
+ << (32 - MAX_DMI_PER_PROC);
+ l_existBits.cappMask = ((uint32_t)(l_cumExistBitPtr->cappMask))
+ << (32 - MAX_CAPP_PER_PROC);
+ l_existBits.pecMask = ((uint32_t)(l_cumExistBitPtr->pecMask))
+ << (32 - MAX_PEC_PER_PROC);
+ l_existBits.phbMask = ((uint32_t)(l_cumExistBitPtr->phbMask))
+ << (32 - MAX_PHB_PER_PROC);
+
+ /* advance our pointer to next chip type */
+ l_bytePtr += sizeof(HOMER_ChipCumulus_t);
+ } /* else if cumulus */
+
+ TRAC_INFO( " Masks XBUS:%X OBUS:%X EC:%X EQ:%X EX:%X CAPP:%X PEC:%X PHB:%X",
+ l_existBits.xbusMask, l_existBits.obusMask, l_existBits.ecMask,
+ l_existBits.eqMask, l_existBits.exMask, l_existBits.cappMask,
+ l_existBits.pecMask, l_existBits.phbMask );
+ TRAC_INFO( " Masks MCBIST:%X MCS:%X MCA:%X",
+ l_existBits.mcbist_mc_Mask, l_existBits.mcs_mi_Mask,
+ l_existBits.mca_dmi_Mask );
+
+ /* Add this PROC to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(TRGT_PROC, p, 0, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ /* noAttn is true when we have global regs but none */
+ /* indicate an attention is present */
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip other proc chiplets */
+
+
+ /* gather other chiplets on the processor */
+ for ( u = 0; u < MAX_XBUS_PER_PROC; u++ )
+ {
+ /* Check if the XBUS is configured. */
+ if ( 0 == (l_existBits.xbusMask & (0x80000000 >> u)) ) continue;
+
+ /* Add this XBUS to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(TRGT_XBUS, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+ }
+ if ( full ) break;
+
+ /* gather other chiplets on the processor */
+ for ( u = 0; u < MAX_OBUS_PER_PROC; u++ )
+ {
+ /* Check if the OBUS is configured. */
+ if ( 0 == (l_existBits.obusMask & (0x80000000 >> u)) ) continue;
+
+ /* Add this OBUS to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(TRGT_OBUS, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+ }
+ if ( full ) break;
+
+ /* gather more proc chiplets */
+ for ( u = 0; u < MAX_CAPP_PER_PROC; u++ )
+ {
+ /* Check if the CAPP is configured. */
+ if ( 0 == (l_existBits.cappMask & (0x80000000 >> u)) ) continue;
+
+ /* Add this CAPP to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(TRGT_CAPP, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+ }
+ if ( full ) break;
+
+ /* gather other chiplets on the processor */
+ for ( u = 0; u < MAX_PEC_PER_PROC; u++ )
+ {
+ /* Check if the PEC is configured. */
+ if ( 0 == (l_existBits.pecMask & (0x80000000 >> u)) ) continue;
+
+ /* Add this PEC to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(TRGT_PEC, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the rest */
+
+ /* gather PHB's under the PEC */
+ /* ************************** */
+ /* PEC0-> PHB0 */
+ /* PEC1-> PHB1 PHB2 */
+ /* PEC2-> PHB3 PHB4 PHB5 */
+ /* ************************** */
+ uint32_t l_PhbPos;
+
+ /* u will be 0, l_unit 0 */
+ /* u will be 1, l_unit 0 and 1 */
+ /* u will be 2, l_unit 0 and 1 and 2 */
+ for ( l_unit = 0; l_unit < (u+1); l_unit++ )
+ {
+ l_PhbPos = u + l_unit;
+ /** When we hit PEC2, need to bump PHB position */
+ if ((MAX_PEC_PER_PROC - 1) == u)
+ {
+ l_PhbPos++;
+ } /* if last PEC unit */
+
+ /* Check if the PHB is configured. */
+ if ( 0 == (l_existBits.phbMask & (0x80000000 >> l_PhbPos)) ) continue;
+
+ /* Add this PHB to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(TRGT_PHB, p, l_PhbPos, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the rest */
+
+ } /* end for on PHB chiplet */
+ if ( full ) break;
+
+ } /* end for on PEC chiplet */
+ if ( full ) break;
+
+ /* gather other chiplets on the processor */
+ for ( u = 0; u < MAX_EC_PER_PROC; u++ )
+ {
+ /* Check if the EC is configured. */
+ if ( 0 == (l_existBits.ecMask & (0x80000000 >> u)) ) continue;
+
+ /* Add this EC to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(TRGT_EC, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the rest */
+
+ } /* end for on EC chiplet */
+ if ( full ) break;
+
+ /* gather other chiplets on the processor */
+ for ( u = 0; u < MAX_EQ_PER_PROC; u++ )
+ {
+ /* Check if the EQ is configured. */
+ if ( 0 == (l_existBits.eqMask & (0x80000000 >> u)) ) continue;
+
+ /* Add this EQ to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(TRGT_EQ, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the rest */
+
+ /* gather other chiplets on the processor */
+ uint32_t l_ExPerEq = (MAX_EX_PER_PROC/MAX_EQ_PER_PROC);
+ uint32_t l_ExPos;
+
+ for (l_unit=0; l_unit < l_ExPerEq; l_unit++)
+ {
+ l_ExPos = (l_ExPerEq * u) + l_unit;
+
+ /* Check if the EX is configured. */
+ if ( 0 == (l_existBits.exMask & (0x80000000 >> l_ExPos)) ) continue;
+
+ /* Add this EX to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(TRGT_EX, p, l_ExPos, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the rest */
+
+ } /* end for on EX chiplet */
+ if ( full ) break;
+
+ } /* end for on EQ chiplet */
+ if ( full ) break;
+
+
+ /* processor type can impact next few units */
+ TrgtType_t l_pnorTarget = (HOMER_CHIP_NIMBUS == l_chipPtr->chipType) ?
+ TRGT_MCBIST : TRGT_MC;
+ uint32_t l_maxPerProc = (HOMER_CHIP_NIMBUS == l_chipPtr->chipType) ?
+ MAX_MCBIST_PER_PROC : MAX_MC_PER_PROC;
+
+ TrgtType_t l_pnorTarg2 = (HOMER_CHIP_NIMBUS == l_chipPtr->chipType) ?
+ TRGT_MCA : TRGT_DMI;
+ uint32_t l_maxPerProc2 = (HOMER_CHIP_NIMBUS == l_chipPtr->chipType) ?
+ MAX_MCA_PER_PROC : MAX_DMI_PER_PROC;
+
+ uint32_t l_UnitPerMc = l_maxPerProc2 / l_maxPerProc;
+ uint8_t l_unitNumber;
+
+ for ( u = 0; u < l_maxPerProc; u++ )
+ {
+ /* Check if MCBIST / MC is configured. */
+ if ( 0 == (l_existBits.mcbist_mc_Mask & (0x80000000 >> u)) ) continue;
+
+ /* Add this MCBIST or MC to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(l_pnorTarget, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the rest */
+
+ /* Grab underlying MCA/DMI chiplet */
+ for ( l_unit = 0; l_unit < l_UnitPerMc; l_unit++ )
+ {
+ /* u=0 or 1 while l_unit is 0 thru 3 */
+ /* Leading to unit number 0:3 or 4:7 */
+ l_unitNumber = l_unit + (u * l_UnitPerMc);
+ /* Check if the MCA / DMI is configured. */
+ if ( 0 == (l_existBits.mca_dmi_Mask & (0x80000000 >> l_unitNumber)) ) continue;
+
+ /* Add this MCA / DMI to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(l_pnorTarg2, p, l_unitNumber, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+
+ } /* end for on MCA/DMI */
+ if ( full ) break;
+
+ } /* end for on MCBIST */
+ if ( full ) break;
+
+
+ l_pnorTarget = (HOMER_CHIP_NIMBUS == l_chipPtr->chipType) ?
+ TRGT_MCS : TRGT_MI;
+ l_maxPerProc = (HOMER_CHIP_NIMBUS == l_chipPtr->chipType) ?
+ MAX_MCS_PER_PROC : MAX_MI_PER_PROC;
+
+ for ( u = 0; u < l_maxPerProc; u++ )
+ {
+ /* Check if the MCS / MI is configured. */
+ if ( 0 == (l_existBits.mcs_mi_Mask & (0x80000000 >> u)) ) continue;
+
+ /* Add this MCS or MI to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(l_pnorTarget, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn, l_chipPtr );
+ if ( full ) break;
+ }
+ if ( full ) break;
+
+
+ } /* if processor chip type */
+ else if (HOMER_CHIP_CENTAUR == l_chipPtr->chipType)
+ {
+ /* HOMER_ChipCentaur_t *l_cenExistBitPtr =
+ (HOMER_ChipCentaur_t *)l_bytePtr; */
+ /* uint32_t l_mbaMask = ((uint32_t) l_cenExistBitPtr->mbaMask) <<
+ (sizeof(uint32_t) - MAX_MBA_PER_MEMBUF) */
+
+ /* we have Centaur chipPos in 'p' and fsi address in 'fsi' */
+
+ /* add this centaur later and iterate thru l_mbaMask */
+ /* don't need for initial support */
+ /* TODO RTC 173614 -- with CUMULUS */
+
+ /* advance our pointer to next chip type */
+ l_bytePtr += sizeof(HOMER_ChipCentaur_t);
+
+ } /* end if centaur chip type */
+ else
+ {
+ /* unexpected chip type */
+ TRAC_ERR( "addTrgtsToPnor saw invalid chip:0x%X",
+ l_chipPtr->chipType );
+ break;
+ } /* end if centaur chip type */
+
+ } /* end for on all CHIPS we have in homer data */
+
+ } while (0);
+
+} /* end FirData_addTrgtsToPnor */
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Initializes the FIR data struct. Does range checking for the HOMER
+ * data. Initializes the PNOR header data.
+ * @param io_fd The FIR data stuct.
+ * @param i_hBuf SRAM pointer to the beginning of the HOMER data buffer.
+ * This should contain the FIR data information provided by
+ * PRD that is used to define which registers the OCC will
+ * need to SCOM.
+ * @param i_hBufSize Total size of the HOMER data buffer.
+ * @param i_pBuf SRAM pointer to the beginning of the PNOR data buffer.
+ * This will be used by this function as a temporary area of
+ * memory to store the PNOR data before writing that data to
+ * the PNOR.
+ * @param i_pBufSize Total size of the PNOR data buffer.
+ * @return Non-SUCCESS if HOMER or PNOR range checking fails or if an
+ * internal function fails. SUCCESS otherwise.
+ */
+int32_t FirData_init( FirData_t * io_fd,
+ uint8_t * i_hBuf, uint32_t i_hBufSize,
+ uint8_t * i_pBuf, uint32_t i_pBufSize )
+{
+ #define FUNC "[FirData_init] "
+
+ int32_t rc = SUCCESS;
+
+ size_t sz_hData = sizeof(HOMER_Data_t);
+ size_t sz_pnoNoEcc = 0;
+ size_t sz_u32 = sizeof(uint32_t);
+ size_t sz_u64 = sizeof(uint64_t);
+
+ bool full = false;
+
+ uint32_t x[TRGT_MAX][REG_MAX];
+ size_t curIdx = 0;
+
+ uint32_t t = TRGT_FIRST;
+
+ uint8_t * reglist = NULL;
+
+ PNOR_Data_t pData = PNOR_getData();
+
+ do
+ {
+ /* Init the struct. */
+ io_fd->hBuf = i_hBuf;
+ io_fd->maxHBufSize = i_hBufSize;
+ io_fd->hData = (HOMER_Data_t *)i_hBuf;
+
+ io_fd->pBuf = i_pBuf;
+ io_fd->maxPBufSize = i_pBufSize;
+ io_fd->pData = (PNOR_Data_t *)i_pBuf;
+ io_fd->pBufSize = 0;
+
+ memset( io_fd->hPtrs, 0x00, sizeof(io_fd->hPtrs) );
+
+ /* Check HOMER header data size. */
+ if ( io_fd->maxHBufSize < sz_hData )
+ {
+ TRAC_ERR( FUNC"HOMER header data size %d is larger than HOMER "
+ "data buffer %d", sz_hData, io_fd->maxHBufSize );
+ rc = FAIL;
+ break;
+ }
+
+ /* Check for valid HOMER data. */
+ if ( HOMER_FIR2 != io_fd->hData->header )
+ {
+ break; /* nothing to analyze. */
+ }
+
+ /* The actual maximum PNOR size may possibly be less then the PNOR data */
+ /* buffer. If so, adjust maximum size. */
+ sz_pnoNoEcc = (io_fd->hData->pnorInfo.pnorSize / 9) * 8;
+ if ( sz_pnoNoEcc < io_fd->maxPBufSize )
+ io_fd->maxPBufSize = sz_pnoNoEcc;
+
+ /* Initialize the PNOR header data. */
+ full = FirData_addDataToPnor( io_fd, &pData, sizeof(pData) );
+ if ( full )
+ {
+ TRAC_ERR( FUNC"Unable to add header to PNOR buffer" );
+ rc = FAIL;
+ break;
+ }
+
+ /* Copy the IPL state from the HOMER data to the PNOR data. */
+ io_fd->pData->iplState = io_fd->hData->iplState;
+
+ /* Get the register list byte indexes in HOMER data buffer */
+ memset( x, 0x00, sizeof(x) );
+ for ( t = TRGT_FIRST; t < TRGT_MAX; t++ )
+ {
+ x[t][REG_GLBL] = curIdx;
+ x[t][REG_FIR] = x[t][REG_GLBL] + sz_u32 * io_fd->hData->regCounts[t][REG_GLBL];
+ x[t][REG_REG] = x[t][REG_FIR] + sz_u32 * io_fd->hData->regCounts[t][REG_FIR];
+ x[t][REG_IDFIR] = x[t][REG_REG] + sz_u32 * io_fd->hData->regCounts[t][REG_REG];
+ x[t][REG_IDREG] = x[t][REG_IDFIR] + sz_u64 * io_fd->hData->regCounts[t][REG_IDFIR];
+ curIdx = x[t][REG_IDREG] + sz_u64 * io_fd->hData->regCounts[t][REG_IDREG];
+ }
+
+ /* Check to make sure the list data is not larger than the available */
+ /* Homer buffer. */
+ if ( io_fd->maxHBufSize - sz_hData < curIdx )
+ {
+ TRAC_ERR( FUNC"HOMER list size %d is larger than HOMER data "
+ "buffer %d", curIdx, io_fd->maxHBufSize - sz_hData );
+ rc = FAIL;
+ break;
+ }
+
+ /* Now, skip chip sections. Note that the HOMER_Data_t struct may have
+ * some padding added after the struct to ensure the HOMER_Chip_t
+ * structs are 4-byte word aligned. */
+ uint32_t pad = (sz_u32 - (sz_hData % sz_u32)) % sz_u32;
+ reglist = io_fd->hBuf + sz_hData + pad;
+ HOMER_Chip_t *l_chiptPtr = NULL;
+
+ /* Need to skip over chip list **/
+ uint32_t l_chipNum;
+ for ( l_chipNum=0;
+ (l_chipNum < io_fd->hData->chipCount);
+ l_chipNum++ )
+ {
+ l_chiptPtr = (HOMER_Chip_t *)reglist;
+
+ /* Skip section on chip type, chip position, etc... */
+ reglist += sizeof(HOMER_Chip_t);
+
+ /* 'Existing chiplet area' varies in size */
+ if (HOMER_CHIP_NIMBUS == l_chiptPtr->chipType)
+ {
+ reglist += sizeof(HOMER_ChipNimbus_t);
+ }
+ else if (HOMER_CHIP_CUMULUS == l_chiptPtr->chipType)
+ {
+ reglist += sizeof(HOMER_ChipCumulus_t);
+ }
+ else if (HOMER_CHIP_CENTAUR == l_chiptPtr->chipType)
+ {
+ reglist += sizeof(HOMER_ChipCentaur_t);
+ }
+ else
+ {
+ TRAC_ERR(FUNC"Chiptype is invalid %X ", l_chiptPtr->chipType);
+ rc = FAIL;
+ break;
+ }
+
+ } /* end for loop skipping chip info sections */
+
+
+ /* Now, get the pointers for each list. */
+ for ( t = TRGT_FIRST; t < TRGT_MAX; t++ )
+ {
+ (io_fd->hPtrs[t]).glbl = (uint32_t *)(reglist + x[t][REG_GLBL] );
+ (io_fd->hPtrs[t]).fir = (uint32_t *)(reglist + x[t][REG_FIR] );
+ (io_fd->hPtrs[t]).reg = (uint32_t *)(reglist + x[t][REG_REG] );
+ (io_fd->hPtrs[t]).idFir = (uint64_t *)(reglist + x[t][REG_IDFIR]);
+ (io_fd->hPtrs[t]).idReg = (uint64_t *)(reglist + x[t][REG_IDREG]);
+ }
+
+ /* Set EC level dep reg list ptr - at very end of list */
+ io_fd->ecDepReg = (HOMER_ChipSpecAddr_t *)(reglist + curIdx);
+
+
+ } while (0);
+
+ return rc;
+
+ #undef FUNC
+}
+
+/*------------------------------------------------------------------------------ */
+/* External functions */
+/*------------------------------------------------------------------------------ */
+
+int32_t FirData_captureCsFirData( uint8_t * i_hBuf, uint32_t i_hBufSize,
+ uint8_t * i_pBuf, uint32_t i_pBufSize )
+{
+ #define FUNC "[FirData_captureCsFirData] "
+
+ int32_t rc = SUCCESS;
+
+ do
+ {
+ /* Init the FIR data struct. */
+ FirData_t fd;
+ rc = FirData_init( &fd, i_hBuf, i_hBufSize, i_pBuf, i_pBufSize );
+ if ( SUCCESS != rc )
+ {
+ TRAC_ERR( FUNC"Failed to init FIR data" );
+ break;
+ }
+
+ /* Check for valid HOMER data. */
+ if ( HOMER_FIR2 != fd.hData->header )
+ {
+ TRAC_ERR( FUNC"No HOMER data detected: header=0x%08x",
+ fd.hData->header );
+ break; /* nothing to analyze. */
+ }
+
+ /* Start adding register data to PNOR for each target. */
+ FirData_addTrgtsToPnor( &fd );
+
+ /* Write Buffer to PNOR */
+/* TODO: enable when function is supported.
+ rc = PNOR_writeFirData( fd.hData->pnorInfo, fd.pBuf, fd.pBufSize );
+ if ( SUCCESS != rc )
+ {
+ TRAC_ERR( FUNC"Failed to process FIR data" );
+ break;
+ }
+*/
+
+ } while (0);
+
+ if ( SUCCESS != rc )
+ {
+ TRAC_ERR( FUNC"Failed: i_hBuf=%p, i_hBufSize=0x%08x, i_pBuf=%p, "
+ "i_pBufSize=%08x", i_hBuf, i_hBufSize, i_pBuf, i_pBufSize );
+ }
+
+ return rc;
+
+ #undef FUNC
+}
+
diff --git a/src/occ_gpe0/firdata/firData.h b/src/occ_gpe0/firdata/firData.h
new file mode 100644
index 0000000..f1475db
--- /dev/null
+++ b/src/occ_gpe0/firdata/firData.h
@@ -0,0 +1,48 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/firData.H $ */
+/* */
+/* 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 */
+
+#ifndef __firData_h
+#define __firData_h
+
+#include "native.h"
+
+/** @brief Reads the register list from the HOMER data, SCOMs hardware, and
+ * stores the register values in PNOR.
+ * @param i_hBuf SRAM pointer to the beginning of the HOMER data buffer.
+ * This should contain the FIR data information provided by
+ * PRD that is used to define which registers the OCC will
+ * need to SCOM.
+ * @param i_hBufSize Total size of the HOMER data buffer.
+ * @param i_pBuf SRAM pointer to the beginning of the PNOR data buffer.
+ * This will be used by this function as a temporary area
+ * of memory to store the PNOR data before writing that
+ * data to the PNOR.
+ * @param i_pBufSize Total size of the PNOR data buffer.
+ * @return Non-SUCCESS if an internal function fails. SUCCESS otherwise.
+ */
+int32_t FirData_captureCsFirData( uint8_t * i_hBuf, uint32_t i_hBufSize,
+ uint8_t * i_pBuf, uint32_t i_pBufSize );
+
+#endif /* __firData_h */
diff --git a/src/occ_gpe0/firdata/firDataConst_common.h b/src/occ_gpe0/firdata/firDataConst_common.h
new file mode 100644
index 0000000..403a028
--- /dev/null
+++ b/src/occ_gpe0/firdata/firDataConst_common.h
@@ -0,0 +1,132 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/firDataConst_common.h $ */
+/* */
+/* 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 */
+
+#ifndef __firDataConst_common_h
+#define __firDataConst_common_h
+
+/** NOTE: This file is common between OCC and Hosboot. Any change to this file
+ * must be mirrored to both repositories. Also, this must be C, not C++,
+ * because OCC strictly uses C. */
+
+#include <stdint.h>
+
+/** Target types for all supported targets. */
+/** NOTE: These are used to build the register list in HOMER data */
+/** and also to create the exiting chiplet masks. Hence, */
+/** the numbers assigned here have to match the sequence */
+/** of chiplets in HOMER_ChipNimbus_t, HOMER_ChipCumulus_t, etc. */
+typedef enum
+{
+ /* NOTE: These will be used as array indexes. */
+ TRGT_FIRST = 0,
+
+ /** Common Nimbus/Cumulus types */
+ TRGT_PROC = TRGT_FIRST,
+ TRGT_CAPP,
+ TRGT_XBUS,
+ TRGT_OBUS,
+ TRGT_PEC,
+ TRGT_PHB,
+ TRGT_EQ,
+ TRGT_EX,
+ TRGT_EC,
+
+ /* Nimbus only */
+ TRGT_MCBIST,
+ TRGT_MCS,
+ TRGT_MCA,
+
+ /* Cumulus only */
+ /* NOTE: Nimbus and Cumulus cannot be used at the same time. So we can have
+ * These array indexes overlap to save space. */
+ TRGT_MC = TRGT_MCBIST,
+ TRGT_MI,
+ TRGT_DMI,
+
+ /* Centaur only */
+ TRGT_MEMBUF,
+ TRGT_MBA,
+
+ TRGT_MAX,
+
+} TrgtType_t;
+
+/** Boundary/position ranges for each target type. */
+typedef enum
+{
+ /* Common Nimbus/Cumulus */
+ MAX_PROC_PER_NODE = 8,
+ MAX_CAPP_PER_PROC = 2,
+ MAX_XBUS_PER_PROC = 3, /* Nimbus 1 and 2, Cumulus 0, 1, and 2 */
+ MAX_OBUS_PER_PROC = 4, /* Nimbus 0 and 3, Cumulus 0, 1, 2, and 3 */
+ MAX_PEC_PER_PROC = 3,
+ MAX_PHB_PER_PROC = 6,
+ MAX_EQ_PER_PROC = 6,
+ MAX_EX_PER_PROC = 12,
+ MAX_EC_PER_PROC = 24,
+
+ /** Nimbus only */
+ MAX_MCBIST_PER_PROC = 2,
+ MAX_MCS_PER_PROC = 4,
+ MAX_MCA_PER_PROC = 8,
+
+ /** Cumulus only */
+ MAX_MC_PER_PROC = 2,
+ MAX_MI_PER_PROC = 4,
+ MAX_DMI_PER_PROC = 8,
+
+ /** Centaur only */
+ MAX_MEMBUF_PER_PROC = 8,
+ MAX_MEMBUF_PER_NODE = MAX_MEMBUF_PER_PROC * MAX_PROC_PER_NODE,
+ MAX_MBA_PER_MEMBUF = 2,
+ MAX_MBA_PER_PROC = MAX_MEMBUF_PER_PROC * MAX_MBA_PER_MEMBUF,
+
+} TrgtPos_t;
+
+/** All register types. */
+typedef enum
+{
+ /* NOTE: These will be used as array indexes. */
+ REG_FIRST = 0,
+
+ REG_GLBL = REG_FIRST, /* 32-bit addresses, 64-bit value */
+ REG_FIR, /* 32-bit addresses, 64-bit value */
+ REG_REG, /* 32-bit addresses, 64-bit value */
+ REG_IDFIR, /* 64-bit addresses, 32-bit value */
+ REG_IDREG, /* 64-bit addresses, 32-bit value */
+
+ REG_MAX,
+
+} RegType_t;
+
+/** Indicates the state of the machine when the checkstop occurred. */
+typedef enum
+{
+ FIRDATA_STATE_RUNTIME = 0,
+ FIRDATA_STATE_IPL = 1,
+
+} IplState_t;
+
+#endif /* __firDataConst_common_h */
diff --git a/src/occ_gpe0/firdata/fir_data_collect.c b/src/occ_gpe0/firdata/fir_data_collect.c
new file mode 100644
index 0000000..a2af34f
--- /dev/null
+++ b/src/occ_gpe0/firdata/fir_data_collect.c
@@ -0,0 +1,166 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/fir_data_collect.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 <fir_data_collect.h>
+#include <scom.h>
+#include <occ_service_codes.h>
+#include <errl.h>
+#include "tpc_firmware_registers.h"
+#include "tpc_register_addresses.h"
+#include <trac.h>
+#include <homer.h>
+#include <firData.h>
+
+FIR_HEAP_BUFFER(uint8_t G_fir_heap[FIR_HEAP_SECTION_SIZE]);
+FIR_PARMS_BUFFER(uint8_t G_fir_data_parms[FIR_PARMS_SECTION_SIZE]);
+uint32_t G_fir_master = FIR_OCC_NOT_FIR_MASTER;
+
+/*
+ * Function Specification
+ *
+ * Name: fir_data_collect
+ *
+ * Description: Collects FIR data on checkstop.
+ *
+ * End Function Specification
+ */
+void fir_data_collect(void)
+{
+
+ int32_t l_rc = 0;
+
+ // Homer data section and size
+ uint8_t *l_hBuf = (uint8_t*) FIR_PARMS_SECTION_BASE_ADDRESS;
+ uint32_t l_hBufSize = HOMER_FIR_PARM_SIZE;
+ // PNOR working buffer in SRAM and size
+ uint8_t *l_pBuf = (uint8_t*) FIR_HEAP_SECTION_BASE_ADDRESS;
+ uint32_t l_pBufSize = FIR_HEAP_SECTION_SIZE;
+
+ l_rc = FirData_captureCsFirData(l_hBuf,
+ l_hBufSize,
+ l_pBuf,
+ l_pBufSize);
+
+ // Trace the rc only, error logs cannot be collected in this state
+ TRAC_IMP("Checkstop FIR data capture completed with rc=%d", l_rc);
+}
+
+
+/*
+ * Function Specification
+ *
+ * Name: pnor_access_ok
+ *
+ * Description: Determines if it is ok for this OCC to access the PNOR.
+ *
+ * End Function Specification
+ */
+// TODO: This code is not allowed currently, as it relies on performing scom operations.
+#if 0
+bool pnor_access_allowed(void)
+{
+ /* BMC ownership of the PNOR is indicated by bit 18 in TPC_GP0 */
+ int l_rc = 0;
+ tpc_gp0_t l_tp_gp0_read;
+ bool l_access_allowed = FALSE;
+
+ l_tp_gp0_read.words.high_order = 0x00000000;
+ l_tp_gp0_read.words.low_order = 0x00000000;
+
+ l_rc = getscom_ffdc(TPC_GP0, (uint64_t *)&l_tp_gp0_read, NULL);
+
+ if (l_rc == 0)
+ {
+ if ((l_tp_gp0_read.words.high_order & TPC_GP0_BIT18_PNOR_OWNER_MASK) == 0)
+ {
+ TRAC_INFO("PNOR access allowed at this time");
+ l_access_allowed = TRUE;
+ }
+ else
+ {
+ TRAC_INFO("PNOR access NOT allowed at this time, tpc_gp0.hi = 0x%08x",
+ l_tp_gp0_read.words.high_order);
+
+ /* @
+ * @errortype
+ * @moduleid FIR_DATA_MID
+ * @reasoncode INTERNAL_FAILURE
+ * @userdata1 TPC_GP0 high word
+ * @userdata4 ERC_PNOR_OWNERSHIP_NOT_AVAILABLE
+ * @devdesc PNOR access not allowed at this time.
+ */
+ errlHndl_t l_errl = createErrl(
+ FIR_DATA_MID, /*ModId */
+ INTERNAL_FAILURE, /*Reasoncode */
+ ERC_PNOR_OWNERSHIP_NOT_AVAILABLE, /*Extended reasoncode */
+ ERRL_SEV_INFORMATIONAL, /*Severity */
+ NULL, /*Trace Buf */
+ DEFAULT_TRACE_SIZE, /*Trace Size */
+ l_tp_gp0_read.words.high_order, /*Userdata1 */
+ 0 /*Userdata2 */
+ );
+
+ /* Commit log */
+ commitErrl(&l_errl);
+ }
+ }
+ else
+ {
+ /* getscom failure */
+ TRAC_ERR("TPC_GP0 getscom failure rc = 0x%08x", -l_rc );
+
+ /* @
+ * @errortype
+ * @moduleid FIR_DATA_MID
+ * @reasoncode INTERNAL_HW_FAILURE
+ * @userdata1 getscom failure rc
+ * @userdata4 ERC_GETSCOM_TPC_GP0_FAILURE
+ * @devdesc Failure determining PNOR ownership. Cannot read TPC_GP0.
+ */
+ errlHndl_t l_errl = createErrl(
+ FIR_DATA_MID, /*ModId */
+ INTERNAL_HW_FAILURE, /*Reasoncode */
+ ERC_GETSCOM_TPC_GP0_FAILURE, /*Extended reasoncode */
+ ERRL_SEV_PREDICTIVE, /*Severity */
+ NULL, /*Trace Buf */
+ DEFAULT_TRACE_SIZE, /*Trace Size */
+ l_rc, /*Userdata1 */
+ 0 /*Userdata2 */
+ );
+
+ /* Callout firmware */
+ addCalloutToErrl(l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ /* Commit log */
+ commitErrl(&l_errl);
+ }
+
+ return l_access_allowed;
+}
+#endif
diff --git a/src/occ_gpe0/firdata/fir_data_collect.h b/src/occ_gpe0/firdata/fir_data_collect.h
new file mode 100644
index 0000000..c313956
--- /dev/null
+++ b/src/occ_gpe0/firdata/fir_data_collect.h
@@ -0,0 +1,56 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/fir_data_collect.h $ */
+/* */
+/* 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 */
+
+
+#ifndef _FIR_DATA_COLLECT_H
+#define _FIR_DATA_COLLECT_H
+
+#include <common_types.h>
+
+/* This size has to agree with the size _FIR_PARMS_SECTION_SIZE defined in the */
+/* OCC linker command file. */
+#define FIR_PARMS_SECTION_SIZE 0x1000
+// This size has to agree with the size _FIR_HEAP_SECTION_SIZE defined in the
+// OCC linker command file.
+#define FIR_HEAP_SECTION_SIZE 0x3000
+
+enum fir_master
+{
+ FIR_OCC_NOT_FIR_MASTER = 0x00000000,
+ FIR_OCC_IS_FIR_MASTER = 0x00000001
+};
+
+extern uint8_t G_fir_data_parms[FIR_PARMS_SECTION_SIZE];
+extern uint8_t G_fir_heap[FIR_HEAP_SECTION_SIZE];
+extern uint32_t G_fir_master;
+
+#define OCC_SET_FIR_MASTER(_fm_t) G_fir_master = _fm_t
+#define OCC_IS_FIR_MASTER() (G_fir_master == FIR_OCC_IS_FIR_MASTER) ? TRUE : FALSE
+#define TPC_GP0_BIT18_PNOR_OWNER_MASK 0x00002000
+
+void fir_data_collect(void);
+bool pnor_access_allowed(void);
+
+#endif /* _FIR_DATA_COLLECT_H */
diff --git a/src/occ_gpe0/firdata/fsi.c b/src/occ_gpe0/firdata/fsi.c
new file mode 100644
index 0000000..4bf105a
--- /dev/null
+++ b/src/occ_gpe0/firdata/fsi.c
@@ -0,0 +1,152 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/fsi.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 */
+
+#include <fsi.h>
+#include <scom_util.h>
+#include <native.h>
+
+#define OPB_REG_CMD 0x00020010
+#define OPB_REG_STAT 0x00020011
+#define OPB_REG_RES 0x00020014
+#define OPB_STAT_BUSY 0x0001000000000000 /**< 15 is the Busy bit */
+#define NS_PER_MSEC (1000000ull)
+
+
+void fsi_recovery()
+{
+ int32_t rc = SUCCESS;
+
+ /* Clear out OPB error */
+ uint64_t scom_data = 0;
+ scom_data = 0x8000000000000000; /*0=Unit Reset*/
+ rc |= xscom_write( OPB_REG_RES, scom_data );
+ rc |= xscom_write( OPB_REG_STAT, scom_data );
+
+ /* Check if we have any errors left */
+ rc |= xscom_read( OPB_REG_STAT, &scom_data );
+
+ TRACFCOMP( "PIB2OPB Status after cleanup = %08X%08X (rc=%d)",
+ (uint32_t)(scom_data >> 32), (uint32_t)scom_data, rc );
+}
+
+/**
+ * @brief Poll for completion of a FSI operation, return data on read
+ */
+int32_t poll_for_complete( uint32_t * o_val )
+{
+ int32_t rc = SUCCESS;
+
+ enum { MAX_OPB_TIMEOUT_NS = 10*NS_PER_MSEC }; /*=10ms */
+
+ *o_val = 0;
+
+ uint64_t read_data = 0;
+ uint64_t elapsed_time_ns = 0;
+ do
+ {
+ rc = xscom_read( OPB_REG_STAT, &read_data );
+ if ( SUCCESS != rc )
+ {
+ fsi_recovery(); /* Try to recover the engine. */
+ return rc;
+ }
+
+ /* Check for completion. Note: not checking for FSI errors. */
+ if ( (read_data & OPB_STAT_BUSY) == 0 ) break; /* Not busy */
+
+ sleep( 10000 ); /* sleep for 10,000 ns */
+ elapsed_time_ns += 10000;
+
+ } while ( elapsed_time_ns <= MAX_OPB_TIMEOUT_NS );
+
+ if ( MAX_OPB_TIMEOUT_NS < elapsed_time_ns )
+ {
+ TRAC_ERR( "[poll_for_complete] FSI request timed out." );
+ return FAIL;
+ }
+
+ *o_val = (uint32_t)read_data; /* Data in the bottom half. */
+
+ return rc;
+}
+
+/**
+ * @brief Read a FSI register
+ */
+int32_t getfsi( SCOM_Trgt_t i_trgt, uint32_t i_addr, uint32_t * o_val )
+{
+ int32_t rc = SUCCESS;
+
+ uint32_t fsi_addr = i_trgt.fsiBaseAddr | i_addr;
+
+ /* setup the OPB command register */
+ /* only supporting 4-byte access */
+ uint64_t fsi_cmd = fsi_addr | 0x60000000; /* 011=Read Full Word */
+ fsi_cmd <<= 32; /* Command is in the upper word of the scom */
+
+ /* Write the OPB command register to trigger the read */
+ rc = xscom_write( OPB_REG_CMD, fsi_cmd );
+ if ( SUCCESS != rc )
+ {
+ fsi_recovery(); /* Try to recover the engine. */
+ return rc;
+ }
+
+ /* Poll for complete and get the data back. */
+ rc = poll_for_complete( o_val );
+
+ return rc;
+}
+
+/**
+ * @brief Write a FSI register
+ */
+int32_t putfsi( SCOM_Trgt_t i_trgt, uint32_t i_addr, uint32_t i_val )
+{
+ int32_t rc = SUCCESS;
+
+ uint32_t fsi_addr = i_trgt.fsiBaseAddr | i_addr;
+
+ /* setup the OPB command register */
+ /* only supporting 4-byte access */
+ uint64_t fsi_cmd = fsi_addr | 0xE0000000; /* 111=Write Full Word */
+ fsi_cmd <<= 32; /* Command is in the upper word of the scom */
+ fsi_cmd |= i_val; /* Data is in the bottom 32-bits */
+
+ /* Write the OPB command register to trigger the read */
+ rc = xscom_write( OPB_REG_CMD, fsi_cmd );
+ if ( SUCCESS != rc )
+ {
+ fsi_recovery(); /* Try to recover the engine. */
+ return rc;
+ }
+
+ /* Poll for complete */
+ uint32_t junk = 0; // Not used.
+ rc = poll_for_complete( &junk );
+
+ return rc;
+}
+
diff --git a/src/occ_gpe0/firdata/fsi.h b/src/occ_gpe0/firdata/fsi.h
new file mode 100644
index 0000000..870e47f
--- /dev/null
+++ b/src/occ_gpe0/firdata/fsi.h
@@ -0,0 +1,47 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/fsi.H $ */
+/* */
+/* 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 */
+
+/* Interfaces to read/write FSI registers */
+
+#include <scom_trgt.h>
+
+/**
+ * @brief Read a FSI register.
+ * @param i_trgt Chip/unit to read from.
+ * @param i_addr FSI address to read, relative to slave's base address.
+ * @param o_val Returned value.
+ * @return Non-SUCCESS if an internal function fails. SUCCESS otherwise.
+ */
+int32_t getfsi( SCOM_Trgt_t i_trgt, uint32_t i_addr, uint32_t * o_val );
+
+/**
+ * @brief Write a FSI register.
+ * @param i_trgt Chip/unit to write to.
+ * @param i_addr FSI address to write, relative to slave's base address.
+ * @param o_val Value to write.
+ * @return Non-SUCCESS if an internal function fails. SUCCESS otherwise.
+ */
+int32_t putfsi( SCOM_Trgt_t i_trgt, uint32_t i_addr, uint32_t i_val );
+
diff --git a/src/occ_gpe0/firdata/homerData_common.h b/src/occ_gpe0/firdata/homerData_common.h
new file mode 100644
index 0000000..66aa53a
--- /dev/null
+++ b/src/occ_gpe0/firdata/homerData_common.h
@@ -0,0 +1,271 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/homerData_common.h $ */
+/* */
+/* 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 */
+
+#ifndef __homerData_common_h
+#define __homerData_common_h
+
+/** NOTE: This file is common between OCC and Hosboot. Any change to this file
+ * must be mirrored to both repositories. Also, this must be C, not C++,
+ * because OCC strictly uses C. */
+
+#include <firDataConst_common.h>
+#include <string.h>
+
+/** This file is used to define the format of the register list stored in the
+ * HOMER data that the OCC will use to determine what register data to capture
+ * in the event of a system checkstop. The data will be stored in the following
+ * format:
+ *
+ * - HOMER_Data_t struct - This contains PNOR information, IPL state, number of
+ * configured chips, and number of register addresses per target type per
+ * register type.
+ *
+ * - For each configured chip, the following format will be used:
+ * - HOMER_Chip_t struct - containing FSI base address, chip type, and chip
+ * position.
+ * - Immediately following will be a chip struct that is specific to the
+ * chip type stored in the preceding struct. These vary in size and
+ * structure depending on the chip type.
+ *
+ * - Register address lists - These lists vary in size depending on the number
+ * of register addresses needed in each list. The list counts are stored in
+ * HOMER_Data_t::regCounts. Order of the lists must match the array indexes
+ * of HOMER_Data_t::regCounts, which are specified in TrgtType_t and
+ * RegType_t.
+ *
+ * - Chip specific address list - This is a list of HOMER_ChipSpecAddr_t
+ * structs and will vary in size depending on the number of register
+ * addresses that are specific to a certain chip or DD level. The number of
+ * entries in this list is stored in HOMER_Data_t::ecDepCounts.
+ *
+ * IMPORTANT NOTE: All of the structs used here are packed. Therefore, we must
+ * ensure the variables within the struct are byte aligned. Meaning each
+ * uint32_t within the struct must be 4-byte aligned and each uint16_t must
+ * be 2-byte aligned. This also means the structs must always start on a
+ * 4-bye word boundary to maintain alignment. This is required due to the
+ * limitations of the PPE42/SRAM hardware.
+ *
+ * Note that FIRs and indirect-SCOM FIRs characterize a set of registers to
+ * capture. In addition to capturing the FIR (or ID FIR), the OCC will need to
+ * capture the following addresses for each type:
+ * - FIR
+ * - MASK (FIR address + 3)
+ * - ACT0 (FIR address + 6)
+ * - ACT1 (FIR address + 7)
+ * - ID FIR
+ * - ID MASK (ID FIR address + 0x300000000ll)
+ * - ID ACT0 (ID FIR address + 0x600000000ll)
+ * - ID ACT1 (ID FIR address + 0x700000000ll)
+ * Note that not all FIRs have a corresponding WOF register. So any WOFs needed
+ * for analysis will need to be explicitly listed in the corresponding
+ * 'Registers' lists.
+ */
+
+typedef enum
+{
+ HOMER_FIR1 = 0x46495231, /** FIR data version 1 ("FIR1" in ascii) P8 */
+ HOMER_FIR2 = 0x46495232, /** FIR data version 1 ("FIR2" in ascii) P9 */
+
+} HOMER_Version_t;
+
+/** PNOR information contained within the HOMER data. */
+/* NOTE: This structure is 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint32_t pnorOffset; /** Physical offset of FIRDATA in PNOR */
+ uint32_t pnorSize; /** Maximum size of FIRDATA (includes ECC) */
+ uint32_t mmioOffset; /** Address of MMIO access */
+ uint32_t norWorkarounds; /** NOR flash vendor */
+
+} HOMER_PnorInfo_t;
+
+/** HOMER data header information containing hardware configurations and
+ * register counts. */
+/* NOTE: This structure may, or may not, be 4-byte word aligned. It all depends
+ * on the size of regCounts, which will change based on the number of
+ * target types and register types we support. When reading/writing this
+ * data ensure that proper padding has been added after this structure so
+ * that subsequent structures are 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint32_t header; /** Magic number to indicate valid data and version */
+
+ uint32_t chipCount : 8; /** Number of configured chips per node */
+ uint32_t ecDepCounts : 8; /** Number of regs that are EC dependent */
+ uint32_t iplState : 1; /** See IplState_t. */
+ uint32_t reserved : 15;
+
+ /** Information regarding the PNOR location and size. */
+ HOMER_PnorInfo_t pnorInfo;
+
+ /** Contains number of registers per type for each target type. */
+ uint8_t regCounts[TRGT_MAX][REG_MAX];
+
+} HOMER_Data_t;
+
+/** @return An initialized HOMER_Data_t struct. */
+static inline HOMER_Data_t HOMER_getData()
+{
+ HOMER_Data_t d; memset( &d, 0x00, sizeof(d) ); /* init to zero */
+
+ d.header = HOMER_FIR2;
+
+ return d;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/** Supported chip types. */
+typedef enum
+{
+ HOMER_CHIP_NIMBUS, /** P9 Nimbus processor chip */
+ HOMER_CHIP_CUMULUS, /** P9 Cumulus processor chip */
+ HOMER_CHIP_CENTAUR, /** Centaur memory buffer chip */
+
+} HOMER_ChipType_t;
+
+/** Information for each configured chip. */
+/* NOTE: This structure is 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint32_t fsiBaseAddr; /** FSI base address for the chip. */
+
+ uint32_t chipType : 4; /** Chip type (see HOMER_ChipType_t) */
+ uint32_t chipPos : 6; /** Chip position relative to the node. */
+ uint32_t chipEcLevel : 8; /** EC level for this chip */
+ uint32_t reserved : 14;
+
+} HOMER_Chip_t;
+
+/** Used for Registers that have EC level dependencies */
+/* NOTE: This structure is 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint32_t chipType : 4; /** See HOMER_ChipType_t. */
+ uint32_t trgtType : 6; /** See TrgtType_t. */
+ uint32_t regType : 4; /** See RegType_t. */
+ uint32_t ddLevel : 8; /** A zero value applies to all levels on a chip. */
+ uint32_t reserved : 10; /** unused at this time */
+
+ /** The 32 or 64 bit address (right justified). */
+ uint64_t address;
+
+} HOMER_ChipSpecAddr_t;
+
+/** @return An initialized HOMER_Chip_t struct. */
+static inline HOMER_Chip_t HOMER_getChip( HOMER_ChipType_t i_type )
+{
+ HOMER_Chip_t c; memset( &c, 0x00, sizeof(c) ); /* init to zero */
+
+ c.fsiBaseAddr = 0xffffffff;
+ c.chipType = i_type;
+
+ return c;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/** Information specific to a P9 Nimbus processor chip. */
+/* NOTE: This structure is 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint32_t isMaster : 1; /** 1 if this is the master PROC, 0 otherwise */
+ uint32_t xbusMask : 3; /** Mask of configured XBUS units (0-2) */
+ uint32_t obusMask : 4; /** Mask of configured OBUS units (0-3) */
+ uint32_t ecMask : 24; /** Mask of configured EC units (0-23) */
+
+ uint32_t eqMask : 6; /** Mask of configured EQ units (0-5) */
+ uint32_t exMask : 12; /** Mask of configured EX units (0-11) */
+ uint32_t mcbistMask : 2; /** Mask of configured MCBIST units (0-1) */
+ uint32_t mcsMask : 4; /** Mask of configured MCS units (0-3) */
+ uint32_t mcaMask : 8; /** Mask of configured MCA units (0-7) */
+
+ uint32_t cappMask : 2; /** Mask of configured CAPP units (0-1) */
+ uint32_t pecMask : 3; /** Mask of configured PEC units (0-2) */
+ uint32_t phbMask : 6; /** Mask of configured PHB units (0-5) */
+ uint32_t reserved : 21;
+
+} HOMER_ChipNimbus_t;
+
+/** @return An initialized HOMER_ChipNimbus_t struct. */
+static inline HOMER_ChipNimbus_t HOMER_initChipNimbus()
+{
+ HOMER_ChipNimbus_t c; memset( &c, 0x00, sizeof(c) ); /* init to zero */
+
+ return c;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/** Information specific to a P9 Cumulus processor chip. */
+/* NOTE: This structure is 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint32_t isMaster : 1; /** 1 if this is the master PROC, 0 otherwise */
+ uint32_t xbusMask : 3; /** Mask of configured XBUS units (0-2) */
+ uint32_t obusMask : 4; /** Mask of configured OBUS units (0-3) */
+ uint32_t ecMask : 24; /** Mask of configured EC units (0-23) */
+
+ uint32_t eqMask : 6; /** Mask of configured EQ units (0-5) */
+ uint32_t exMask : 12; /** Mask of configured EX units (0-11) */
+ uint32_t mcMask : 2; /** Mask of configured MC units (0-1) */
+ uint32_t miMask : 4; /** Mask of configured MI units (0-3) */
+ uint32_t dmiMask : 8; /** Mask of configured DMI units (0-7) */
+
+ uint32_t cappMask : 2; /** Mask of configured CAPP units (0-1) */
+ uint32_t pecMask : 3; /** Mask of configured PEC units (0-2) */
+ uint32_t phbMask : 6; /** Mask of configured PHB units (0-5) */
+ uint32_t reserved : 21;
+
+} HOMER_ChipCumulus_t;
+
+/** @return An initialized HOMER_ChipCumulus_t struct. */
+static inline HOMER_ChipCumulus_t HOMER_initChipCumulus()
+{
+ HOMER_ChipCumulus_t c; memset( &c, 0x00, sizeof(c) ); /* init to zero */
+
+ return c;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/** Information specific to a Centaur memory buffer chip. */
+/* NOTE: This structure is 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint32_t mbaMask : 2; /** Mask of configured MBA units (0-1) */
+ uint32_t reserved : 30;
+
+} HOMER_ChipCentaur_t;
+
+/** @return An initialized HOMER_ChipCentaur_t struct. */
+static inline HOMER_ChipCentaur_t HOMER_initChipCentaur()
+{
+ HOMER_ChipCentaur_t c; memset( &c, 0x00, sizeof(c) ); /* init to zero */
+
+ return c;
+}
+
+#endif /* __homerData_common_h */
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 <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) */
+#define ECCB_DATA_REG 0x000B0023 /**< ECCB Data Reg (FW) */
+
+/* Default Values to set for all operations
+ 1101.0100.0000.000x.0000.0001.0000.0000.<address> */
+#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 /**<OPBM LS Control Reg */
+#define LPCHC_RESET_REG 0x0FC /**<LPC HC Reset Register */
+
+#define ECCB_RESET_LPC_FAST_RESET (1ULL << 62) /**< bit 1 Fast reset */
+
+#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
+
+/**
+ * @brief LPC Base Register Layout
+*/
+typedef union
+{
+
+ uint64_t data64;
+
+ 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 LPC Control Register Layout
+ */
+typedef union
+{
+
+ uint64_t data64;
+
+ struct
+ {
+ /* unused sections should be set to zero */
+ // 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 */
+ };
+} CommandReg_t;
+
+/**
+ * @brief LPC Status Register Layout
+ */
+typedef union
+{
+ uint64_t data64;
+ struct
+ {
+ 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)
+{
+ uint32_t full_addr = 0;
+ switch ( i_type )
+ {
+ case LPC_TRANS_IO:
+ full_addr = i_addr | LPCHC_IO_SPACE;
+ break;
+ case LPC_TRANS_FW:
+ full_addr = i_addr | LPCHC_FW_SPACE;
+ break;
+ }
+ return full_addr;
+}
+
+
+errorHndl_t pollComplete(CommandReg_t* i_ctrl,
+ StatusReg_t* o_stat)
+{
+ errorHndl_t l_err = NO_ERROR;
+
+ do {
+ uint64_t poll_time = 0;
+ uint64_t loop = 0;
+ do
+ {
+ 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;
+ }
+
+ 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;
+}
diff --git a/src/occ_gpe0/firdata/lpc.h b/src/occ_gpe0/firdata/lpc.h
new file mode 100644
index 0000000..177deda
--- /dev/null
+++ b/src/occ_gpe0/firdata/lpc.h
@@ -0,0 +1,55 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/lpc.h $ */
+/* */
+/* 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 */
+
+#ifndef _LPC_H
+#define _LPC_H
+
+#include <native.h>
+#include <errl.h>
+
+/**
+ * @enum LPC::TransType
+ * @brief LPC Transaction Types
+ */
+typedef enum {
+ LPC_TRANS_IO = 0, /* LPC IO Space */
+ LPC_TRANS_FW = 1, /* LPC Firmware Space */
+} LpcTransType;
+
+errorHndl_t lpc_read( LpcTransType i_type,
+ uint32_t i_addr,
+ uint8_t* o_data,
+ size_t i_size );
+
+errorHndl_t lpc_write( LpcTransType i_type,
+ uint32_t i_addr,
+ uint8_t* i_data,
+ size_t i_size );
+
+uint32_t checkAddr(LpcTransType i_type,
+ uint32_t i_addr);
+
+
+#endif
diff --git a/src/occ_gpe0/firdata/native.c b/src/occ_gpe0/firdata/native.c
new file mode 100644
index 0000000..d214468
--- /dev/null
+++ b/src/occ_gpe0/firdata/native.c
@@ -0,0 +1,76 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/native.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 <native.h>
+#include <scom.h>
+#include <trac.h>
+
+void sleep( SsxInterval i_nanoseconds )
+{
+ ssx_sleep(SSX_NANOSECONDS(i_nanoseconds));
+}
+
+int TRACE_XSCOM=0;
+
+int32_t xscom_read( uint32_t i_address, uint64_t * o_data )
+{
+ int32_t rc = SUCCESS;
+
+ *o_data = 0;
+
+ rc = getscom_ffdc( i_address, o_data, NULL );
+ if ( SUCCESS != rc )
+ {
+ TRAC_ERR( "SCOM error in xscom_read wrapper, rc=%d", rc );
+ }
+
+ if ( TRACE_XSCOM )
+ {
+ TRACFCOMP( "xscom_read(%08X)=%08X%08X", i_address,
+ (uint32_t)(*o_data>>32), (uint32_t)(*o_data) );
+ }
+
+ return rc;
+}
+
+int32_t xscom_write( uint32_t i_address, uint64_t i_data )
+{
+ int32_t rc = SUCCESS;
+
+ rc = putscom_ffdc( i_address, i_data, NULL );
+ if ( SUCCESS != rc )
+ {
+ TRAC_ERR( "SCOM error in xscom_write wrapper, rc=%d", rc );
+ }
+
+ if ( TRACE_XSCOM )
+ {
+ TRACFCOMP( "xscom_write(%08X)=%08X%08X", i_address,
+ (uint32_t)(i_data>>32), (uint32_t)i_data);
+ }
+
+ return rc;
+}
+
diff --git a/src/occ_gpe0/firdata/native.h b/src/occ_gpe0/firdata/native.h
new file mode 100644
index 0000000..dd0daa7
--- /dev/null
+++ b/src/occ_gpe0/firdata/native.h
@@ -0,0 +1,98 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/native.h $ */
+/* */
+/* 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 */
+
+/* Native functions provided by OCC code */
+#ifndef _NATIVE_H
+#define _NATIVE_H
+
+#include <common_types.h>
+#include <trac.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "ssx.h"
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef NO_TRAC_STRINGS
+
+#ifdef FIRD_DEBUG
+#define TRACDCOMP(frmt,args...) DBG_PRINT(frmt,##args)
+#else
+#define TRACDCOMP(frmt,args...)
+#endif // FIRD_DEBUG
+
+#define TRACFCOMP(frmt,args...) TRACE(&g_des_array[INF_TRACE_DESCRIPTOR],INFO_MRK frmt,##args)
+
+#else // NO_TRAC_STRINGS
+
+#define TRACDCOMP(frmt,args...)
+#define TRACFCOMP(frmt,args...)
+
+#endif // NO_TRAC_STRINGS
+
+typedef uint32_t errorHndl_t;
+
+#define ENTER_MRK
+#define NO_ERROR 0
+
+/* Return a number >= input that is aligned up to the next 4-byte boundary */
+#define ALIGN_4(u) (((u) + 0x3ull) & ~0x3ull)
+
+#define NS_PER_SEC (1000000000ull)
+
+#undef be64toh
+#undef htobe64
+#define be64toh(x) (x)
+#define htobe64(x) (x)
+
+#define KILOBYTE (1024ul) /**< 1 KB */
+#define MEGABYTE (1024 * 1024ul) /**< 1 MB */
+#define GIGABYTE (MEGABYTE * 1024ul) /**< 1 GB */
+#define TERABYTE (GIGABYTE * 1024ul) /**< 1 TB */
+
+#define PAGESIZE (4*KILOBYTE) /**< 4 KB */
+
+#undef SUCCESS
+#define SUCCESS 0
+
+#undef FAIL
+#define FAIL -1
+
+/*================================================ */
+
+/* XSCOM Read */
+int32_t xscom_read( uint32_t i_address, uint64_t * o_data );
+
+/* XSCOM Write */
+int32_t xscom_write( uint32_t i_address, uint64_t i_data );
+
+/* Sleep */
+void sleep( SsxInterval i_nanoseconds );
+
+
+#endif
diff --git a/src/occ_gpe0/firdata/norflash.h b/src/occ_gpe0/firdata/norflash.h
new file mode 100644
index 0000000..c4c9cdc
--- /dev/null
+++ b/src/occ_gpe0/firdata/norflash.h
@@ -0,0 +1,154 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/norflash.h $ */
+/* */
+/* 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 */
+
+#ifndef __PNOR_NORFLASH_H
+#define __PNOR_NORFLASH_H
+
+#include <native.h>
+#include <pnor_mboxdd.h>
+
+/** @file norflash.H
+ * @brief Contains constants related to specific types of
+ * of NOR flash chips
+ */
+
+/**
+ * @brief Supported NOR Chip IDs
+ */
+enum NorChipIDs
+{
+ UNKNOWN_NOR_ID = 0x12345600, /**< Initial value before read */
+
+ MICRON_MFG_ID = 0x20000000, /**< Micron Mfg ID */
+ MICRON_NOR_ID = 0x20ba2000, /**< Micron NOR */
+
+ MACRONIX_MFG_ID = 0xC2000000, /**< Macronix Mfg ID */
+ MACRONIX32_NOR_ID = 0xC2201A00, /**< Macronix NOR MXxxL51235F */
+ MACRONIX64_NOR_ID = 0xC2201900, /**< Macronix NOR MXxxL25635F */
+
+ /* Note: Simics currently models Micron NOR */
+ VPO_NOR_ID = 0x20201800, /**< VPO NOR chip ID */
+ FAKE_NOR_ID = 0xBADBAD00, /**< ID used during fake pnor */
+
+ ID_MASK = 0xFFFFFF00, /**< Only look at 3 bytes */
+ MFGID_MASK = 0xFF000000, /**< Manufacturer ID is the first byte */
+};
+
+/**
+ * @brief SPI Config Info
+ * OP Codes and other MISC info for configuring SFC
+ */
+typedef enum
+{
+ SPI_NO_OPCODE = 0x00, /**< Undefined value */
+
+ /*
+ * Micron Flash Commands
+ */
+ SPI_MICRON_FLAG_STAT = 0x70, /**< Check write/erase complete */
+ SPI_MICRON_CLRFLAG_STAT = 0x50, /**< Clear write/erase Status reg */
+
+ /*
+ * Macronix Flash Commands
+ */
+ SPI_MACRONIX_EN4B = 0xB7, /**< Enable Macronix 4-Byte addressing */
+
+ /* SPI protocol commands */
+ SPI_JEDEC_WRITE_STATUS = 0x01, /*WRSR */
+ SPI_JEDEC_PAGE_PROGRAM = 0x02, /*PP */
+ SPI_JEDEC_READ = 0x03, /*READ */
+ SPI_JEDEC_WRITE_DISABLE = 0x04, /*WRDI */
+ SPI_JEDEC_READ_STATUS = 0x05, /*RDSR */
+ SPI_JEDEC_WRITE_ENABLE = 0x06, /*WREN */
+ SPI_JEDEC_FAST_READ = 0x0B, /*FAST_READ */
+ SPI_JEDEC_SECTOR_ERASE = 0x20, /*SE */
+ SPI_JEDEC_READ_SFDP = 0x5A, /*RDSFDP */
+ SPI_JEDEC_CHIPID = 0x9F, /*RDID */
+ SPI_JEDEC_BLOCK_ERASE = 0xD8, /*BE */
+
+} SpiConfigInfo;
+
+/**
+ * @brief General Constants related to flash
+ */
+enum
+{
+ PAGE_PROGRAM_BYTES = 256, /***< 256 bytes per PP command */
+};
+
+
+/**
+ * Common format of Status Register
+ */
+typedef union
+{
+ uint8_t data8;
+ struct
+ {
+ uint8_t writeProtect : 1; /*0 */
+ uint8_t rsvd : 5; /*1:5 */
+ uint8_t writeEnable : 1; /*6 */
+ uint8_t writeInProgress : 1; /*7 */
+ };
+} NorStatusReg_t;
+
+/**
+ * Flags used to trigger Hardware workarounds
+ */
+enum
+{
+ /* No workarounds present */
+ HWWK_NO_WORKAROUNDS = 0x00000000,
+
+ /* Must perform 'read flag status' commands after */
+ /* any write or erase */
+ HWWK_MICRON_WRT_ERASE = 0x00000001,
+
+ /* Must do a read of a low flash address before issuing read */
+ /* commands that return more than 1 word of data */
+ HWWK_MICRON_EXT_READ = 0x00000002,
+};
+
+
+/*
+ * Vendor-specific interfaces
+ */
+
+/**
+ * @brief Check flag status bit on Micron NOR chips
+ * The current version of Micron parts require the Flag
+ * Status register be read after a read or erase operation,
+ * otherwise all future operations won't work..
+ *
+ * @parm i_pnorMbox Pnor Mbox Struct to operate on
+ *
+ * @return Error from operation
+ */
+errorHndl_t micronFlagStatus( pnorMbox_t* i_pnorMbox );
+
+
+
+
+#endif
diff --git a/src/occ_gpe0/firdata/pnorData_common.h b/src/occ_gpe0/firdata/pnorData_common.h
new file mode 100644
index 0000000..3037e39
--- /dev/null
+++ b/src/occ_gpe0/firdata/pnorData_common.h
@@ -0,0 +1,162 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/pnorData_common.h $ */
+/* */
+/* 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 */
+
+#ifndef __pnorData_common_h
+#define __pnorData_common_h
+
+/** NOTE: This file is common between OCC and Hosboot. Any change to this file
+ * must be mirrored to both repositories. Also, this must be C, not C++,
+ * because OCC strictly uses C. */
+
+#include <firDataConst_common.h>
+#include <string.h>
+
+/** This file is used to define the format of the register data captured by the
+ * OCC and stored in PNOR. The data will be stored in the following format:
+ *
+ * - PNOR_Data_t struct - This has all of the information characterizing how
+ * many targets that have register data.
+ * - For each target with register data, the following format will be used:
+ * - PNOR_Trgt_t struct - Contains the target type, position, and how many
+ * registers are in the register list.
+ * - A list of all regular registers (PNOR_Reg_t).
+ * - A list of all indirect-SCOM registers (PNOR_IdReg_t).
+ *
+ * IMPORTANT NOTE: All of the structs used here are packed. Therefore, we must
+ * ensure the variables within the struct are byte aligned. Meaning each
+ * uint32_t within the struct must be 4-byte aligned and each uint16_t must
+ * be 2-byte aligned. This also means the structs must always start on a
+ * 4-bye word boundary to maintain alignment. This is required due to the
+ * limitations of the PPE42/SRAM hardware.
+ *
+ * The PNOR has limited data space. So the following rules will apply:
+ * - Any registers with the value of zero will not be captured.
+ * - Registers with SCOM errors will not be captured, however, the number
+ * of SCOM errors detected should be stored in each PNOR_Trgt_t struct.
+ * - If the value of a FIR (or ID FIR) is zero, do not capture the
+ * associated ACT0 and ACT1 registers. Note that the associated MASK
+ * register is still needed for FFDC.
+ * - Each target type may have associated global registers. If none exist,
+ * simply capture all registers for that type. However, if they do exist
+ * and the values of ALL the global registers are zero, skip capturing
+ * the associated registers of the target and any subsequent targets on
+ * the affinity path. Example,
+ * - For a MCBIST, skip this MCBIST and all associated MCSs, and MCAs.
+ * - If for some reason we run out of space in the PNOR, do not SCOM any
+ * more registers, set the 'full' bit in the PNOR_Data_t struct, and
+ * write all data successfully captured to PNOR.
+ */
+
+typedef enum
+{
+ PNOR_FIR1 = 0x46495231, /** FIR data version 1 ("FIR1" in ascii) P8 */
+ PNOR_FIR2 = 0x46495232, /** FIR data version 2 ("FIR2" in ascii) P9 */
+
+} PNOR_Version_t;
+
+/** PNOR data header information. */
+/* NOTE: This structure is 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint32_t header; /** Magic number to indicate valid data and version */
+
+ uint32_t trgts : 12; /** Number of targets with register data */
+ uint32_t full : 1; /** 1 if PNOR data is full and data incomplete */
+ uint32_t iplState : 1; /** See enum IplState_t */
+ uint32_t reserved : 18;
+
+} PNOR_Data_t;
+
+/** @return An initialized PNOR_Data_t struct. */
+static inline PNOR_Data_t PNOR_getData()
+{
+ PNOR_Data_t d; memset( &d, 0x00, sizeof(d) ); /* init to zero */
+
+ d.header = PNOR_FIR2;
+
+ return d;
+};
+
+/** These values will match the corresponding bit fields in PNOR_Trgt_t. */
+typedef enum
+{
+ PNOR_Trgt_MAX_REGS_PER_TRGT = 511, /* Currently expect 266 on the PROC */
+ PNOR_Trgt_MAX_ID_REGS_PER_TRGT = 15, /* Currently expect 9 on the MBA */
+ PNOR_Trgt_MAX_SCOM_ERRORS = 255, /* Should be plenty */
+
+} PNOR_Trgt_RegLimits_t;
+
+/** Information for each target with SCOM data. */
+/* NOTE: This structure is 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint32_t chipPos : 6; /** Parent chip position relative to the node */
+ uint32_t unitPos : 5; /** Unit position relative to the parent chip */
+ uint32_t regs : 9; /** Number of normal registers */
+ uint32_t idRegs : 4; /** Number of indirect-SCOM registers */
+ uint32_t scomErrs : 8; /** Number of SCOM errors detected */
+
+ uint32_t trgtType : 6; /** Target type. See enum TrgtType_t */
+ uint32_t reserved : 26;
+
+} PNOR_Trgt_t;
+
+/** @param i_trgtType Target type. See enum TrgtType_t.
+ * @param i_chipPos Parent chip position relative to the node.
+ * @param i_unitPos Unit position relative to the parent chip.
+ * @return An initialized PNOR_Data_t struct.
+ */
+static inline PNOR_Trgt_t PNOR_getTrgt( uint32_t i_trgtType, uint32_t i_chipPos,
+ uint32_t i_unitPos )
+{
+ PNOR_Trgt_t t; memset( &t, 0x00, sizeof(t) ); /* init to zero */
+
+ t.trgtType = i_trgtType;
+ t.chipPos = i_chipPos;
+ t.unitPos = i_unitPos;
+
+ return t;
+};
+
+/** Information for a normal register. */
+/* NOTE: This structure is 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint32_t addr; /** 32-bit address */
+ uint64_t val; /** 64-bit value */
+
+} PNOR_Reg_t;
+
+/** Information for an indirect-SCOM register. */
+/* NOTE: This structure is 4-byte word aligned. */
+typedef struct __attribute__((packed))
+{
+ uint64_t addr; /** 64-bit address */
+ uint32_t val; /** 32-bit value */
+
+} PNOR_IdReg_t;
+
+#endif // __pnorData_common_h
+
diff --git a/src/occ_gpe0/firdata/pnor_mboxdd.c b/src/occ_gpe0/firdata/pnor_mboxdd.c
new file mode 100644
index 0000000..463e950
--- /dev/null
+++ b/src/occ_gpe0/firdata/pnor_mboxdd.c
@@ -0,0 +1,404 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/pnor_mboxdd.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 */
+
+/**
+ * @file ast_mboxdd.c
+ *
+ * @brief Implementation of the PNOR access code on top of AST MBOX protocol
+ */
+
+/*****************************************************************************/
+// I n c l u d e s
+/*****************************************************************************/
+#include <native.h>
+#include <norflash.h>
+#include <pnor_mboxdd.h>
+#include <lpc.h>
+
+errorHndl_t hwInit(pnorMbox_t* i_pnorMbox)
+{
+ errorHndl_t l_err = NO_ERROR;
+ uint8_t* l_data;
+ int i;
+ do
+ {
+ //Current window starts closed
+ i_pnorMbox->iv_curWindowOpen = false;
+ i_pnorMbox->iv_mbox.iv_mboxMsgSeq = 1;
+ l_err = initializeMbox();
+ if (l_err)
+ {
+ TRAC_ERR("initializeMbox failed rc:0x%x", l_err);
+ break;
+ }
+
+ //Send message to BMC Mbox to get MBOX info
+ // This message gets the MBOX protocol version
+ mboxMessage_t l_getInfoMsg;
+ l_data = (uint8_t*)(&l_getInfoMsg);
+ for (i = 0; i < BMC_MBOX_DATA_REGS; i++)
+ {
+ l_data[i] = 0;
+ }
+
+ l_getInfoMsg.iv_cmd = MBOX_C_GET_MBOX_INFO;
+ put8(&l_getInfoMsg, 0, 2);
+ l_err = doMessage(&i_pnorMbox->iv_mbox, &l_getInfoMsg);
+ if (l_err)
+ {
+ TRAC_ERR("doMessage to ping BMC failed with rc=0x%x", l_err);
+ break;
+ }
+
+ i_pnorMbox->iv_protocolVersion = get8(&l_getInfoMsg, 0);
+ if (i_pnorMbox->iv_protocolVersion == 1)
+ {
+ i_pnorMbox->iv_blockShift = 12;
+ i_pnorMbox->iv_readWindowSize = get16(&l_getInfoMsg, 1)
+ << i_pnorMbox->iv_blockShift;
+ i_pnorMbox->iv_writeWindowSize = get16(&l_getInfoMsg, 3)
+ << i_pnorMbox->iv_blockShift;
+ }
+ else
+ {
+ i_pnorMbox->iv_blockShift = get8(&l_getInfoMsg, 5);
+ }
+
+ //Now get the size of the flash
+ mboxMessage_t l_getSizeMsg;
+ l_getSizeMsg.iv_cmd = MBOX_C_GET_FLASH_INFO;
+ l_err = doMessage(&i_pnorMbox->iv_mbox, &l_getSizeMsg);
+ if (l_err)
+ {
+ TRAC_ERR("doMessage failed to get flash size rc=0x%x", l_err);
+ break;
+ }
+
+ if (i_pnorMbox->iv_protocolVersion == 1)
+ {
+ i_pnorMbox->iv_flashSize = get32(&l_getSizeMsg, 0);
+ i_pnorMbox->iv_flashEraseSize = get32(&l_getSizeMsg, 4);
+ }
+ else
+ {
+ i_pnorMbox->iv_flashSize = get16(&l_getSizeMsg, 0)
+ << i_pnorMbox->iv_blockShift;
+ i_pnorMbox->iv_flashEraseSize = get16(&l_getSizeMsg, 2)
+ << i_pnorMbox->iv_blockShift;
+ }
+ } while (0);
+ return l_err;
+}
+
+
+errorHndl_t readFlash(pnorMbox_t* i_pnorMbox,
+ uint32_t i_addr,
+ size_t i_size,
+ void* o_data)
+{
+ errorHndl_t l_err = NO_ERROR;
+
+ do
+ {
+ // Ensure we are operating on a 4-byte boundary
+ if ((i_size % 4 != 0) && (i_addr % 4 != 0))
+ {
+ TRAC_ERR("readFlash: not on 4-byte boundary");
+ return FAIL;
+ }
+
+ while (i_size)
+ {
+ uint32_t l_lpcAddr;
+ size_t l_chunkLen;
+
+ l_err = adjustMboxWindow(i_pnorMbox,
+ false,
+ i_addr,
+ i_size,
+ &l_lpcAddr,
+ &l_chunkLen);
+
+ if (l_err)
+ {
+ break;
+ }
+
+ //Directly access LPC to do read/write as BMC is setup now
+ l_err = lpc_read(LPC_TRANS_FW, l_lpcAddr, o_data, l_chunkLen);
+
+ if (l_err)
+ {
+ break;
+ }
+
+ i_addr += l_chunkLen;
+ i_size -= l_chunkLen;
+ o_data = (char*)o_data + l_chunkLen;
+ }
+
+ if(l_err)
+ {
+ break;
+ }
+
+ }
+ while(0);
+
+ return l_err;
+}
+
+errorHndl_t writeFlash(pnorMbox_t* i_pnorMbox,
+ uint32_t i_addr,
+ size_t i_size,
+ void* i_data)
+{
+ errorHndl_t l_err = NO_ERROR;
+
+ do
+ {
+ // Ensure we are operating on a 4-byte boundary
+ if (i_size % 4 != 0)
+ {
+ TRAC_ERR("writeFlash: not on 4-byte boundary");
+ return FAIL;
+ }
+
+
+ errorHndl_t l_flushErr = NO_ERROR;
+
+ while (i_size)
+ {
+ uint32_t l_lpcAddr;
+ size_t l_chunkLen;
+
+ l_err = adjustMboxWindow(i_pnorMbox,
+ true,
+ i_addr,
+ i_size,
+ &l_lpcAddr,
+ &l_chunkLen);
+
+ if (l_err)
+ {
+ break;
+ }
+
+ //Directly do LPC access to space pointed to by BMC
+ l_err = lpc_write(LPC_TRANS_FW, l_lpcAddr, i_data, l_chunkLen);
+
+ if (l_err)
+ {
+ break;
+ }
+
+ //Tell BMC to push data from LPC space into PNOR
+ l_err = writeDirty(i_pnorMbox, i_addr, l_chunkLen);
+
+ if (l_err)
+ {
+ break;
+ }
+
+ i_addr += l_chunkLen;
+ i_size -= l_chunkLen;
+ i_data = (char*)i_data + l_chunkLen;
+ }
+
+ /* We flush whether we had an error or not.
+ *
+ * NOTE: It would help the daemon a lot if we moved that out of here
+ * and instead had a single flush call over a series of writes.
+ */
+ l_flushErr = writeFlush(i_pnorMbox);
+
+ if ( l_err == NO_ERROR && l_flushErr )
+ {
+ l_err = l_flushErr;
+ }
+
+ if( l_err )
+ {
+ i_size = 0;
+ }
+
+ if(l_err)
+ {
+ break;
+ }
+
+ }
+ while(0);
+
+ return l_err;
+}
+
+errorHndl_t adjustMboxWindow(pnorMbox_t* i_pnorMbox,
+ bool i_isWrite, uint32_t i_reqAddr,
+ size_t i_reqSize, uint32_t *o_lpcAddr,
+ size_t *o_chunkLen)
+{
+ errorHndl_t l_err = NO_ERROR;
+ uint32_t l_pos, l_wSize, l_reqSize;
+
+ do
+ {
+ /*
+ * Handle the case where the window is already opened, is of
+ * the right type and contains the requested address.
+ */
+ uint32_t l_wEnd = i_pnorMbox->iv_curWindowOffset +
+ i_pnorMbox->iv_curWindowSize;
+
+ /* A read request can be serviced by a write window */
+ if (i_pnorMbox->iv_curWindowOpen &&
+ (i_pnorMbox->iv_curWindowWrite || !i_isWrite) &&
+ i_reqAddr >= i_pnorMbox->iv_curWindowOffset && i_reqAddr < l_wEnd)
+ {
+ size_t l_gap = (l_wEnd - i_reqAddr);
+
+ *o_lpcAddr = i_pnorMbox->iv_curWindowLpcOffset +
+ (i_reqAddr - i_pnorMbox->iv_curWindowOffset);
+ if (i_reqSize <= l_gap)
+ {
+ *o_chunkLen = i_reqSize;
+ }
+ else
+ {
+ *o_chunkLen = l_gap;
+ }
+ return NO_ERROR;
+ }
+
+ /*
+ * We need a window change, mark it closed first
+ */
+ i_pnorMbox->iv_curWindowOpen = false;
+
+ /*
+ * Then open the new one at the right position. The required
+ * alignment differs between protocol versions
+ */
+ if (i_pnorMbox->iv_protocolVersion == 1)
+ {
+ l_wSize = i_isWrite ? i_pnorMbox->iv_writeWindowSize
+ : i_pnorMbox->iv_readWindowSize;
+ l_pos = i_reqAddr & ~(l_wSize - 1);
+ l_reqSize = 0;
+ }
+ else
+ {
+ uint32_t l_blockMask = (1u << i_pnorMbox->iv_blockShift) - 1;
+ l_wSize = 0;
+ l_pos = i_reqAddr & ~l_blockMask;
+ l_reqSize = (((i_reqAddr + i_reqSize) + l_blockMask) & ~l_blockMask)
+ - l_pos;
+ }
+
+ mboxMessage_t winMsg;
+ if (i_isWrite)
+ {
+ winMsg.iv_cmd = MBOX_C_CREATE_WRITE_WINDOW;
+ }
+ else
+ {
+ winMsg.iv_cmd = MBOX_C_CREATE_READ_WINDOW;
+ }
+
+ put16(&winMsg, 0, l_pos >> i_pnorMbox->iv_blockShift);
+ put16(&winMsg, 2, l_reqSize >> i_pnorMbox->iv_blockShift);
+ l_err = doMessage(&i_pnorMbox->iv_mbox, &winMsg);
+
+ if (l_err)
+ {
+ break;
+ }
+
+ i_pnorMbox->iv_curWindowLpcOffset =
+ (get16(&winMsg,0)) << i_pnorMbox->iv_blockShift;
+
+ if (i_pnorMbox->iv_protocolVersion == 1)
+ {
+ i_pnorMbox->iv_curWindowOffset = l_pos;
+ i_pnorMbox->iv_curWindowLpcOffset =
+ (get16(&winMsg,0)) << i_pnorMbox->iv_blockShift;
+ i_pnorMbox->iv_curWindowSize = l_wSize;
+ }
+ else
+ {
+ i_pnorMbox->iv_curWindowLpcOffset = (get16(&winMsg,0))
+ << i_pnorMbox->iv_blockShift;
+ i_pnorMbox->iv_curWindowSize = (get16(&winMsg,2))
+ << i_pnorMbox->iv_blockShift;
+ i_pnorMbox->iv_curWindowOffset = (get16(&winMsg,4))
+ << i_pnorMbox->iv_blockShift;
+ }
+
+ i_pnorMbox->iv_curWindowOpen = true;
+ i_pnorMbox->iv_curWindowWrite = i_isWrite;
+
+ }
+ while (true);
+
+ return l_err;
+}
+
+errorHndl_t writeDirty(pnorMbox_t* i_pnorMbox, uint32_t i_addr, size_t i_size)
+{
+ /* To pass a correct "size" for both protocol versions, we
+ * calculate the block-aligned start and end.
+ */
+ uint32_t l_blockMask = (1u << i_pnorMbox->iv_blockShift) - 1;
+ uint32_t l_start = i_addr & ~l_blockMask;
+ uint32_t l_end = ((i_addr + i_size) + l_blockMask) & ~l_blockMask;
+
+ mboxMessage_t dirtyMsg;
+ dirtyMsg.iv_cmd = MBOX_C_MARK_WRITE_DIRTY;
+
+ if (i_pnorMbox->iv_protocolVersion == 1)
+ {
+ put16(&dirtyMsg, 0, i_addr >> i_pnorMbox->iv_blockShift);
+ put32(&dirtyMsg, 2, l_end - l_start);
+ }
+ else
+ {
+ put16(&dirtyMsg, 0, (i_addr - i_pnorMbox->iv_curWindowOffset)
+ >> i_pnorMbox->iv_blockShift);
+ put16(&dirtyMsg, 2, (l_end - l_start) >> i_pnorMbox->iv_blockShift);
+ }
+
+ return doMessage(&i_pnorMbox->iv_mbox, &dirtyMsg);
+}
+
+errorHndl_t writeFlush(pnorMbox_t* i_pnorMbox)
+{
+ mboxMessage_t flushMsg;
+ flushMsg.iv_cmd = MBOX_C_WRITE_FLUSH;
+
+ put16(&flushMsg, 0, 0);
+ put32(&flushMsg, 2, 0);
+
+ return doMessage(&i_pnorMbox->iv_mbox, &flushMsg);
+}
diff --git a/src/occ_gpe0/firdata/pnor_mboxdd.h b/src/occ_gpe0/firdata/pnor_mboxdd.h
new file mode 100644
index 0000000..ab8f05d
--- /dev/null
+++ b/src/occ_gpe0/firdata/pnor_mboxdd.h
@@ -0,0 +1,135 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/pnor_mboxdd.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 */
+#ifndef __PNOR_MBOX_H
+#define __PNOR_MBOX_H
+
+//NOTE: Protocol Definition is here:
+// https://github.com/openbmc/mboxbridge/blob/master/Documentation/mbox_protocol.md
+
+#include <ast_mboxdd.h>
+
+/** @file pnor_mbox.h
+ * @brief Provides the interfaces to the PNOR via the
+ * MBOX protocol
+ */
+
+typedef struct
+{
+ astMbox_t iv_mbox;
+ uint32_t iv_protocolVersion;
+ //Block size is either 4k (V1) or BMC defined (V2)
+ // the iv_blockShift parm is a representation of that size
+ // as a power of 2. Most command and response args are specified
+ // in some multiple of block size
+ uint32_t iv_blockShift;
+ uint32_t iv_flashSize;
+ uint32_t iv_flashEraseSize;
+ // Current Window
+ bool iv_curWindowOpen; // Currently open
+ bool iv_curWindowWrite; // Write vs Read window
+ uint32_t iv_curWindowOffset; // Offset into flash
+ uint32_t iv_curWindowSize; // Size
+ uint32_t iv_curWindowLpcOffset; // Offset into LPC FW space
+ // Legacy v1 protocol
+ uint32_t iv_readWindowSize;
+ uint32_t iv_writeWindowSize;
+
+} pnorMbox_t;
+
+/*
+ * @brief Do base initialization of the MBOX functionality
+ *
+ * @parm[io] io_pnorMbox - Pointer to pnorMbox_t structure
+ *
+ * @return Error from operation
+ */
+errorHndl_t hwInit(pnorMbox_t* i_pnorMbox);
+
+/*
+ * @brief Read data from the PNOR flash
+ *
+ * @param[in] Pointer to pnorMbox struct
+ * @parm[in] i_addr PNOR flash Address to read
+ * @parm[in] i_size Amount of data to read, in bytes.
+ * @parm[out] o_data Buffer to read data into
+ *
+ * @return Error from operation
+ */
+errorHndl_t readFlash(pnorMbox_t* i_pnorMbox,
+ uint32_t i_addr,
+ size_t i_size,
+ void* o_data);
+
+/**
+ * @brief Write data to the PNOR flash
+ * @param[in] Pointer to pnorMbox struct
+ * @parm i_addr PNOR flash Address to write
+ * @parm i_size Amount of data to write, in bytes.
+ * @parm i_data Buffer containing data to write
+ *
+ * @return Error from operation
+ */
+errorHndl_t writeFlash(pnorMbox_t* i_pnorMbox,
+ uint32_t i_addr,
+ size_t i_size,
+ void* i_data);
+
+/**
+ * @brief Open a window on the BMC for PNOR accesses
+ * if necessary and return adjusted LPC address and chunk size
+ * @param[in] Pointer to pnorMbbox struct
+ * @parm[in] i_isWrite Write or read window
+ * @parm[in] i_reqAddr Requested flash offset
+ * @parm[in] i_reqSize Requested size
+ * @parm[out] o_lpcAddr LPC offset for the requested offset
+ * @parm[out] o_chunkLen i_reqSize adjusted to fit in the window
+ *
+ * @return Error from operation
+ */
+errorHndl_t adjustMboxWindow(pnorMbox_t* i_pnorMbox,
+ bool i_isWrite,
+ uint32_t i_reqAddr,
+ size_t i_reqSize,
+ uint32_t *o_lpcAddr,
+ size_t *o_chunkLen);
+
+/**
+ * @brief Mark a range dirty in a write window
+ * @param[in] Pointer to pnorMbox struct
+ * @parm[in] i_addr Flash offset of the range
+ * @parm[in] i_size Size of the range
+ *
+ * @return Error from operation
+ */
+errorHndl_t writeDirty(pnorMbox_t* i_pnorMbox, uint32_t i_addr, size_t i_size);
+
+/**
+* @brief Flush all pending dirty data to the flash
+* @param[in] Pointer to pnorMbox struct
+* @return Error from operation
+*/
+errorHndl_t writeFlush(pnorMbox_t* i_pnorMbox);
+
+#endif /* __PNOR_MBOX_H */
diff --git a/src/occ_gpe0/firdata/pnor_util.c b/src/occ_gpe0/firdata/pnor_util.c
new file mode 100644
index 0000000..2c48179
--- /dev/null
+++ b/src/occ_gpe0/firdata/pnor_util.c
@@ -0,0 +1,220 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/pnor_util.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 */
+
+/* Interfaces to write into PNOR */
+
+#include <native.h>
+#include <pnor_mboxdd.h>
+#include <pnor_util.h>
+#include <norflash.h>
+
+/*================================================================= */
+/* The offset of the next byte to write */
+uint32_t g_next_byte = 0xFFFFFFFF;
+/* Size of the FIRDATA section of PNOR */
+uint32_t g_pnor_size = 0;
+/* Global PNOR Mbox object */
+pnorMbox_t* g_pnorMbox;
+
+/* Cache to queue up PNOR writes */
+uint8_t g_write_cache[PAGE_PROGRAM_BYTES];
+/* Current position of data inside write cache */
+size_t g_write_cache_index = 0;
+
+/**
+ * @brief Write 8 bytes of data into PNOR starting
+ */
+int32_t pnor_write_8B( uint64_t i_data )
+{
+ int32_t rc = SUCCESS;
+
+ if ( (g_next_byte == 0xFFFFFFFF) || /* initialized data */
+ ((g_next_byte + g_pnor_size) < (g_next_byte + 9)) ) /* make sure there is room */
+ {
+ TRACFCOMP("pnor_write_8B> g_next_byte=%.8X, g_pnor_size=%.8X",g_next_byte,g_pnor_size);
+ /* must have been some error in the prep */
+ return FAIL;
+ }
+
+//@TODO: Do we need ECC, or does the BMC handle that for us now?
+ /* Create 9-byte ECC-ified version */
+// uint8_t data9[9];
+// injectECC( (uint8_t*)(&i_data), 8, data9 );
+
+ /* Copy data into the write cache until we queue up
+ a big chunk of data to write. This is more efficient
+ and avoids handling the write boundary of the PP
+ command internally. */
+// size_t cpsz = 9;
+
+ uint8_t data8[8];
+ size_t cpsz = 8;
+
+ if( (g_write_cache_index + cpsz) > PAGE_PROGRAM_BYTES )
+ {
+ cpsz = PAGE_PROGRAM_BYTES - g_write_cache_index;
+ }
+ memcpy( &(g_write_cache[g_write_cache_index]), data8, cpsz );
+// memcpy( &(g_write_cache[g_write_cache_index]), data9, cpsz );
+
+ g_write_cache_index += cpsz;
+
+ /* Write a complete chunk into the flash */
+ if( g_write_cache_index == PAGE_PROGRAM_BYTES )
+ {
+ errorHndl_t tmp = writeFlash( g_pnorMbox,
+ g_next_byte,
+ PAGE_PROGRAM_BYTES,
+ g_write_cache );
+ if ( NO_ERROR != tmp )
+ {
+ TRACFCOMP("pnor_write_8B> writeFlash failed");
+ /* hit an error, stop any more writes from happening */
+ g_next_byte = 0xFFFFFFFF;
+ g_pnor_size = 0;
+ return FAIL;
+ }
+ g_next_byte += PAGE_PROGRAM_BYTES;
+ memset( g_write_cache, 0xFF, PAGE_PROGRAM_BYTES );
+ g_write_cache_index = 0;
+
+ if( (8 - cpsz) > 0 )
+ {
+ memcpy( &(g_write_cache[0]), &(data8[cpsz]), 8 - cpsz );
+ g_write_cache_index = 8 - cpsz;
+ }
+
+ /* Handle the overflow */
+// if( (9 - cpsz) > 0 )
+// {
+// memcpy( &(g_write_cache[0]), &(data9[cpsz]), 9 - cpsz );
+// g_write_cache_index = 9 - cpsz;
+// }
+ }
+
+ return rc;
+}
+
+
+/**
+ * @brief Perform any necessary operations to prepare
+ * the PNOR hw/code for writing
+ */
+errorHndl_t pnor_prep( HOMER_PnorInfo_t* i_pnorInfo )
+{
+ errorHndl_t l_err = NO_ERROR;
+
+ /* Figure out where to start */
+ TRACFCOMP("FIRDATA is at %.8X..%.8X", i_pnorInfo->pnorOffset, i_pnorInfo->pnorOffset+i_pnorInfo->pnorSize );
+ g_next_byte = i_pnorInfo->pnorOffset;
+ g_pnor_size = i_pnorInfo->pnorSize;
+ memset( g_write_cache, 0xFF, PAGE_PROGRAM_BYTES );
+
+ /* Can we rely on skiboot leaving things in a good state? */
+ l_err = hwInit(g_pnorMbox);
+ if( l_err )
+ {
+ TRACFCOMP("hwInit failed");
+ /* hit an error, stop any writes from happening */
+ g_next_byte = 0xFFFFFFFF;
+ g_pnor_size = 0;
+ }
+
+ return l_err;
+}
+
+/*------------------------------------------------------------------------------ */
+
+int32_t PNOR_writeFirData( HOMER_PnorInfo_t i_pnorInfo,
+ uint8_t * i_buf, uint32_t i_bufSize )
+{
+ int32_t rc = SUCCESS;
+ TRACFCOMP(">>PNOR_writeFirData");
+
+ do
+ {
+ /* Initialize the PNOR data. */
+ errorHndl_t l_err = pnor_prep( &i_pnorInfo );
+ if( l_err )
+ {
+ TRACFCOMP("pnor_prep failed");
+ rc = FAIL;
+ break; /*nothing more to do here*/
+ }
+
+ uint32_t idx = 0;
+ uint64_t dataChunk = 0;
+ size_t sz_dataChunk = sizeof(uint64_t);
+
+ /* Add PNOR data 8 bytes at a time. */
+ for ( idx = 0; idx < i_bufSize; idx += sz_dataChunk )
+ {
+ memcpy( &dataChunk, &i_buf[idx], sz_dataChunk );
+
+ rc = pnor_write_8B( dataChunk );
+ if ( SUCCESS != rc )
+ {
+ TRACFCOMP( "pnor_write_8B() failed during FIR write" );
+ break;
+ }
+ }
+ if ( SUCCESS != rc ) break;
+
+ /* Add any extra bytes if they exist at the end of the buffer. */
+ if ( idx != i_bufSize )
+ {
+ uint32_t extraBytes = idx - i_bufSize;
+
+ dataChunk = 0;
+ memcpy( &dataChunk, &i_buf[idx], extraBytes );
+
+ rc = pnor_write_8B( dataChunk );
+ if ( SUCCESS != rc )
+ {
+ TRACFCOMP( "pnor_write_8B() failed during blank fill" );
+ break;
+ }
+ }
+
+ /* Fill the rest of the page with good ECC */
+ for ( idx = i_bufSize;
+ idx < i_pnorInfo.pnorSize;
+ idx += sz_dataChunk )
+ {
+ dataChunk = 0xFFFFFFFFFFFFFFFFull;
+ rc = pnor_write_8B( dataChunk );
+ if ( SUCCESS != rc )
+ {
+ TRACFCOMP( "pnor_write_8B() failed during ECC fill" );
+ break;
+ }
+ }
+
+ } while (0);
+
+ TRACFCOMP("<<PNOR_writeFirData");
+ return rc;
+}
+
diff --git a/src/occ_gpe0/firdata/pnor_util.h b/src/occ_gpe0/firdata/pnor_util.h
new file mode 100644
index 0000000..d8b5518
--- /dev/null
+++ b/src/occ_gpe0/firdata/pnor_util.h
@@ -0,0 +1,41 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/pnor_util.H $ */
+/* */
+/* 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 */
+
+#ifndef __pnor_util_h
+#define __pnor_util_h
+
+#include <homerData_common.h>
+
+/**
+ * @brief Writes a buffer containing the FIR data to PNOR (adding ECC).
+ * @param i_pnorInfo Information regarding PNOR location, size, etc.
+ * @param i_buf Data buffer (no ECC included).
+ * @param i_bufSize Size of the data buffer.
+ * @return Non-SUCCESS, if the write fails. SUCCESS, otherwise.
+ */
+int32_t PNOR_writeFirData( HOMER_PnorInfo_t i_pnorInfo,
+ uint8_t * i_buf, uint32_t i_bufSize );
+
+#endif /* __pnor_util_h */
diff --git a/src/occ_gpe0/firdata/sbe_fifo.c b/src/occ_gpe0/firdata/sbe_fifo.c
new file mode 100644
index 0000000..9a2099a
--- /dev/null
+++ b/src/occ_gpe0/firdata/sbe_fifo.c
@@ -0,0 +1,444 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/sbe_fifo.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 "sbe_fifo.h"
+#include <trac.h>
+#include <fsi.h>
+#include <native.h>
+
+/** @brief Waits for FIFO to be ready to be written to
+ * @param i_target The SCOM target.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+uint32_t waitUpFifoReady(SCOM_Trgt_t* i_target)
+{
+ uint32_t l_rc = SUCCESS;
+
+ uint64_t l_elapsed_time_ns = 0;
+ uint32_t l_addr = SBE_FIFO_UPFIFO_STATUS;
+ uint32_t l_data = 0;
+
+ do
+ {
+ //Read upstream status to see if there is room for more data
+ l_rc = getfsi(*i_target, l_addr, &l_data);
+ if(l_rc != SUCCESS)
+ {
+ TRAC_ERR("waitUpFifoReady: failed to getfsi from addr 0x%08x",
+ l_addr);
+ break;
+ }
+
+ if(!(l_data & UPFIFO_STATUS_FIFO_FULL))
+ {
+ break;
+ }
+
+ //Check for timeout
+ if(l_elapsed_time_ns >= MAX_UP_FIFO_TIMEOUT_NS)
+ {
+ l_rc = FAIL;
+ TRAC_ERR("waitUpFifoReady: timeout occurred while waiting for"
+ " FIFO to clear");
+ break;
+ }
+
+ sleep(10000); //sleep for 10,000 ns
+ l_elapsed_time_ns += 10000;
+ }while(TRUE);
+
+ return l_rc;
+}
+
+/** @brief Waits for information to show up in FIFO
+ * @param i_target The SCOM target.
+ * @param o_status the status of the FIFO
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+uint32_t waitDnFifoReady(SCOM_Trgt_t* i_target, uint32_t* o_status)
+{
+ uint32_t l_rc = SUCCESS;
+
+ uint64_t l_elapsed_time_ns = 0;
+ uint32_t l_addr = SBE_FIFO_DNFIFO_STATUS;
+
+ do
+ {
+ // read dnstream status to see if data ready to be read
+ // or if has hit the EOT
+ l_rc = getfsi(*i_target, l_addr, o_status);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ if(!(*o_status & DNFIFO_STATUS_FIFO_EMPTY) ||
+ (*o_status & DNFIFO_STATUS_DEQUEUED_EOT_FLAG))
+ {
+ break;
+ }
+ else
+ {
+ TRAC_IMP("SBE status reg returned fifo empty or dequeued eot flag 0x%.8X",
+ *o_status);
+ }
+
+ // Check for timeout
+ if(l_elapsed_time_ns >= MAX_UP_FIFO_TIMEOUT_NS)
+ {
+ TRAC_ERR("waitDnFifoReady: timeout waiting for downstream FIFO"
+ " to be empty.");
+ l_rc = FAIL;
+ break;
+ }
+
+ sleep(10000); // wait for 10,000 ns
+ l_elapsed_time_ns += 10000;
+
+ }while(TRUE);
+
+ return l_rc;
+}
+
+/** @brief Writes a request to FIFO
+ * @param i_target The SCOM target.
+ * @param i_fifoRequest the request to execute.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+uint32_t writeRequest(SCOM_Trgt_t* i_target, uint32_t* i_fifoRequest)
+{
+ uint32_t l_rc = SUCCESS;
+
+ TRAC_IMP("Enter writeRequest");
+
+ // Ensure Downstream Max Transfer Counter is 0 non-0 can cause
+ // protocol issues)
+ uint32_t l_addr = SBE_FIFO_DNFIFO_MAX_TSFR;
+ uint32_t l_data = 0;
+ l_rc = putfsi(*i_target, l_addr, l_data);
+ if(l_rc != SUCCESS)
+ {
+ TRAC_ERR("writeRequest: failed to putfsi to addr 0x%08x",
+ l_addr);
+ return l_rc;
+ }
+
+ //The first uint32_t has the number of uint32_t words in the request
+ l_addr = SBE_FIFO_UPFIFO_DATA_IN;
+ uint32_t* l_sent = i_fifoRequest; //This pointer will advance as words are sent
+ uint32_t l_count = *l_sent;
+ uint32_t i;
+
+ for(i = 0; i < l_count; ++i)
+ {
+ //Wait for room to write into fifo
+ l_rc = waitUpFifoReady(i_target);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ //Send data into fifo
+ l_rc = putfsi(*i_target, l_addr, *l_sent);
+ if(l_rc != SUCCESS)
+ {
+ TRAC_ERR("writeRequest: failed to putfsi to addr 0x%08x",
+ l_addr);
+ return l_rc;
+ }
+
+ l_sent++;
+ }
+
+ //Notify SBE that last word has been sent
+ l_rc = waitUpFifoReady(i_target);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ l_addr = SBE_FIFO_UPFIFO_SIG_EOT;
+ l_data = FSB_UPFIFO_SIG_EOT;
+ l_rc = putfsi(*i_target, l_addr, l_data);
+ if(l_rc != SUCCESS)
+ {
+ TRAC_ERR("writeRequest: failed to putfsi to addr 0x%08x", l_addr);
+ }
+
+ TRAC_IMP("Exit writeRequest");
+
+ return l_rc;
+}
+
+/** @brief Reads and processes the FIFO response
+ * @param i_target The SCOM target.
+ * @param i_fifoRequest the original FIFO request.
+ * @param o_fifoResponse the FIFO response.
+ * @param i_responseSize the expected size of the response.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+uint32_t readResponse(SCOM_Trgt_t* i_target,
+ uint32_t* i_fifoRequest,
+ uint32_t* o_fifoResponse,
+ uint32_t i_responseSize)
+{
+ uint32_t l_rc = SUCCESS;
+ uint32_t l_readBuffer[READ_BUFFER_SIZE];
+
+ TRAC_IMP("Enter readResponse");
+
+ // EOT is expected before the response buffer is full. Room for
+ // the PCBPIB status or FFDC is included, but is only returned
+ // if there is an error. The last received word has the distance
+ // to the status, which is placed at the end of the returned data
+ // in order to reflect errors during transfer.
+
+ uint32_t* l_received = o_fifoResponse; // advance as words are received
+ uint32_t l_maxWords = i_responseSize / sizeof(uint32_t);
+ uint32_t l_wordsReceived = 0; // Used to validata the "distance" to status
+ bool l_eotReceived = FALSE;
+ uint32_t l_lastWord = 0; // Last word received. Final read is the "distance"
+ // in words to the status header.
+ bool l_overRun = FALSE;
+
+ do
+ {
+ // Wait for data to be ready to receive (download) or if the EOT
+ // has been sent. If not EOT, then data ready to receive.
+ uint32_t l_status = 0;
+ l_rc = waitDnFifoReady(i_target, &l_status);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ if(l_status & DNFIFO_STATUS_DEQUEUED_EOT_FLAG)
+ {
+ l_eotReceived = TRUE;
+ // Ignore EOT dummy word
+ if(l_wordsReceived >= (sizeof(struct statusHeader) / sizeof(uint32_t)))
+ {
+ if(l_overRun == FALSE)
+ {
+ l_received--;
+ l_wordsReceived--;
+ l_lastWord = o_fifoResponse[l_wordsReceived-1];
+ }
+ else
+ {
+ l_lastWord = l_readBuffer[l_wordsReceived-2];
+ }
+ }
+ break;
+ }
+
+ // When error occurs, SBE will write more than l_maxWords
+ // we have to keep reading 1 word at a time until we get EOT
+ // or more than READ_BUFFER_SIZE. Save what we read in the buffer
+ if(l_wordsReceived >= l_maxWords)
+ {
+ l_overRun = TRUE;
+ }
+
+ // Read next word
+ l_rc = getfsi(*i_target, SBE_FIFO_DNFIFO_DATA_OUT, &l_lastWord);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ l_readBuffer[l_wordsReceived] = l_lastWord;
+
+ if(l_overRun == FALSE)
+ {
+ *l_received = l_lastWord; // Copy to returned output buffer
+ l_received++; // Advance to the next position
+ }
+ l_wordsReceived++;
+
+ if(l_wordsReceived > READ_BUFFER_SIZE)
+ {
+ TRAC_ERR("readResponse: data overflow without EOT");
+ l_rc = FAIL;
+ return l_rc;
+ }
+
+ }while(TRUE);
+
+ // At this point, l_wordsReceived of words received.
+ // l_received points to 1 word past last word received.
+ // l_lastWord has last word received, which is "distance" to status
+ // EOT is expected before running out of response buffer
+ if(!l_eotReceived)
+ {
+ l_rc = FAIL;
+ TRAC_ERR("readResponse: no EOT cmd = 0x%08x size = %d",
+ i_fifoRequest[1], i_responseSize);
+ return l_rc;
+ }
+
+ // Notify SBE that EOT has been received
+ uint32_t l_eotSig = FSB_UPFIFO_SIG_EOT;
+ l_rc = putfsi(*i_target, SBE_FIFO_DNFIFO_ACK_EOT, l_eotSig);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ // Determine if transmission is successful.
+ // Last word received has the distance to status in words including itself.
+ // l_wordsReceived has number of words received.
+ // Need to have received at least status header and distance word.
+ if((l_lastWord < (sizeof(struct statusHeader)/sizeof(uint32_t) + 1)) ||
+ (l_wordsReceived < (sizeof(struct statusHeader)/sizeof(uint32_t) + 1)) ||
+ (l_lastWord > l_wordsReceived))
+ {
+ TRAC_ERR("readResponse: invalid status distance. Cmd = 0x%08x distance"
+ " = %d allocated response size = %d received word size = %d",
+ i_fifoRequest[1], l_lastWord, i_responseSize, l_wordsReceived);
+ l_rc = FAIL;
+ return l_rc;
+ }
+
+ // Check status for success.
+ // l_received points one word past last word received.
+ // l_lastWord has number of words to status header including self.
+ uint32_t* l_statusTmp = (l_overRun == FALSE) ? (l_received - l_lastWord) :
+ &l_readBuffer[l_wordsReceived - 1];
+ struct statusHeader* l_statusHeader = (struct statusHeader*)l_statusTmp;
+ if((FIFO_STATUS_MAGIC != l_statusHeader->magic) ||
+ (SBE_PRI_OPERATION_SUCCESSFUL != l_statusHeader->primaryStatus) ||
+ (SBE_SEC_OPERATION_SUCCESSFUL != l_statusHeader->secondaryStatus))
+ {
+ TRAC_ERR("readResponse: failing downstream status cmd = 0x%08x magic = "
+ "0x%08x primary status = 0x%08x secondary status = 0x%08x",
+ i_fifoRequest[1],
+ l_statusHeader->magic,
+ l_statusHeader->primaryStatus,
+ l_statusHeader->secondaryStatus);
+
+ l_rc = FAIL;
+ }
+
+ TRAC_IMP("Exit readResponse");
+ return l_rc;
+}
+
+/** @brief Performs a FIFO operation (read or write)
+ * @param i_target The SCOM target.
+ * @param i_fifoRequest the FIFO request data structure
+ * @param i_fifoResponse the response from SBE
+ * @param i_responseSize the size of the response
+ * @return Non-SUCCESS if the operation fails. SUCCESS otherwise.
+ */
+uint32_t performFifoChipOp(SCOM_Trgt_t* i_target,
+ uint32_t* i_fifoRequest,
+ uint32_t* i_fifoResponse,
+ uint32_t i_responseSize)
+{
+ uint32_t l_rc = SUCCESS;
+
+ TRAC_IMP("Enter performFifoChipOp");
+
+ l_rc = writeRequest(i_target, i_fifoRequest);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ l_rc = readResponse(i_target,
+ i_fifoRequest,
+ i_fifoResponse,
+ i_responseSize);
+
+ TRAC_IMP("Exit performFifoChioOp");
+
+ return l_rc;
+}
+
+/** @brief Performs a write SCOM operation using SBE FIFO
+ * @param i_target The SCOM target.
+ * @param i_addr 64-bit SCOM address.
+ * @param i_data 64-bit data to write.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+int32_t putFifoScom(SCOM_Trgt_t* i_target, uint64_t i_addr, uint64_t i_data)
+{
+ uint32_t l_rc = SUCCESS;
+
+ TRAC_IMP("Enter putFifoScom");
+
+ struct fifoPutScomRequest l_fifoRequest;
+ struct fifoPutScomResponse l_fifoResponse;
+
+ l_fifoRequest.wordCnt = PUT_SCOM_REQUEST_WORD_CNT;
+ l_fifoRequest.reserved = 0;
+ l_fifoRequest.commandClass = SBE_FIFO_CLASS_SCOM_ACCESS;
+ l_fifoRequest.command = SBE_FIFO_CMD_PUT_SCOM;
+ l_fifoRequest.address = i_addr;
+ l_fifoRequest.data = i_data;
+
+ l_rc = performFifoChipOp(i_target,
+ (uint32_t*)&l_fifoRequest,
+ (uint32_t*)&l_fifoResponse,
+ sizeof(struct fifoPutScomResponse));
+
+ TRAC_IMP("Exit putFifoScom");
+
+ return l_rc;
+}
+
+/** @brief Performs a read SCOM operation using SBE FIFO
+ * @param i_target The SCOM target.
+ * @param i_addr 64-bit SCOM address.
+ * @param o_data 64-bit returned value.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+int32_t getFifoScom(SCOM_Trgt_t* i_target, uint64_t i_addr, uint64_t* o_data)
+{
+ uint32_t l_rc = SUCCESS;
+
+ TRAC_IMP("Enter getFifoScom");
+
+ struct fifoGetScomRequest l_fifoRequest;
+ struct fifoGetScomResponse l_fifoResponse;
+
+ l_fifoRequest.wordCnt = GET_SCOM_REQUEST_WORD_CNT;
+ l_fifoRequest.reserved = 0;
+ l_fifoRequest.commandClass = SBE_FIFO_CLASS_SCOM_ACCESS;
+ l_fifoRequest.command = SBE_FIFO_CMD_GET_SCOM;
+ l_fifoRequest.address = i_addr;
+
+ l_rc = performFifoChipOp(i_target,
+ (uint32_t*)&l_fifoRequest,
+ (uint32_t*)&l_fifoResponse,
+ sizeof(struct fifoGetScomResponse));
+
+ //Always return data even if there is an error
+ *o_data = l_fifoResponse.data;
+
+ TRAC_IMP("Exit getFifoScom");
+
+ return l_rc;
+}
diff --git a/src/occ_gpe0/firdata/sbe_fifo.h b/src/occ_gpe0/firdata/sbe_fifo.h
new file mode 100644
index 0000000..4194471
--- /dev/null
+++ b/src/occ_gpe0/firdata/sbe_fifo.h
@@ -0,0 +1,123 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/sbe_fifo.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 */
+#ifndef __SBE_FIFO_H
+#define __SBE_FIFO_H
+
+#include <scom_trgt.h>
+#include <stdint.h>
+
+#define PACKED __attribute__((__packed__))
+
+#define PUT_SCOM_REQUEST_WORD_CNT 0x06
+#define GET_SCOM_REQUEST_WORD_CNT 0x04
+
+#define SBE_FIFO_CMD_GET_SCOM 0x01
+#define SBE_FIFO_CMD_PUT_SCOM 0x02
+#define SBE_FIFO_CLASS_SCOM_ACCESS 0xA2
+#define SBE_FIFO_DNFIFO_MAX_TSFR 0x00002458
+#define SBE_FIFO_UPFIFO_DATA_IN 0x00002400
+#define SBE_FIFO_UPFIFO_SIG_EOT 0x00002408
+#define FSB_UPFIFO_SIG_EOT 0x80000000
+#define SBE_FIFO_UPFIFO_STATUS 0x00002404
+#define SBE_FIFO_DNFIFO_STATUS 0x00002444
+#define UPFIFO_STATUS_FIFO_FULL 0x00200000
+#define DNFIFO_STATUS_FIFO_EMPTY 0x00100000
+#define DNFIFO_STATUS_DEQUEUED_EOT_FLAG 0x00800000
+#define SBE_FIFO_DNFIFO_ACK_EOT 0x00002454
+#define SBE_FIFO_DNFIFO_DATA_OUT 0x00002440
+#define NS_PER_MSEC (1000000ull)
+#define MAX_UP_FIFO_TIMEOUT_NS 10*NS_PER_MSEC
+#define READ_BUFFER_SIZE 2048
+#define FIFO_STATUS_MAGIC 0xC0DE
+#define SBE_PRI_OPERATION_SUCCESSFUL 0x00
+#define SBE_SEC_OPERATION_SUCCESSFUL 0x00
+
+struct statusHeader
+{
+ uint16_t magic; //set to 0xC0DE
+ uint8_t commandClass;
+ uint8_t command;
+ uint16_t primaryStatus;
+ uint16_t secondaryStatus;
+} PACKED;
+
+struct ffdc_struct
+{
+ const void* ptr;
+ size_t size;
+};
+
+struct fifoPutScomRequest
+{
+ uint32_t wordCnt;
+ uint16_t reserved;
+ uint8_t commandClass;
+ uint8_t command;
+ uint64_t address;
+ uint64_t data;
+} PACKED;
+
+struct fifoPutScomResponse
+{
+ struct statusHeader status;
+ struct ffdc_struct ffdc; //ffdc data
+ uint32_t status_distance; //distance to status
+} PACKED;
+
+struct fifoGetScomRequest
+{
+ uint32_t wordCnt;
+ uint16_t reserved;
+ uint8_t commandClass;
+ uint8_t command;
+ uint64_t address;
+} PACKED;
+
+struct fifoGetScomResponse
+{
+ uint64_t data; //Data (0..31) + (32..63)
+ struct statusHeader status;
+ struct ffdc_struct ffdc; //ffdc data
+ uint32_t status_distance; // distance to status
+} PACKED;
+
+/** @brief Performs a write SCOM operation using SBE FIFO
+ * @param i_target The SCOM target.
+ * @param i_addr 64-bit SCOM address.
+ * @param i_data 64-bit data to write.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+int32_t putFifoScom(SCOM_Trgt_t* i_target, uint64_t i_addr, uint64_t i_data);
+
+/** @brief Performs a read SCOM operation using SBE FIFO
+ * @param i_target The SCOM target.
+ * @param i_addr 64-bit SCOM address.
+ * @param o_data 64-bit returned value.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+int32_t getFifoScom(SCOM_Trgt_t* i_target, uint64_t i_addr, uint64_t* o_data);
+
+#endif
+
diff --git a/src/occ_gpe0/firdata/scom_addr_util.c b/src/occ_gpe0/firdata/scom_addr_util.c
new file mode 100644
index 0000000..a59a5a7
--- /dev/null
+++ b/src/occ_gpe0/firdata/scom_addr_util.c
@@ -0,0 +1,82 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/scom_addr_util.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 "scom_addr_util.h"
+
+
+void set_sat_id(const uint8_t i_sat_id, uint64_t * o_addr)
+{
+ *o_addr &= 0xFFFFFFFFFFFFFC3FULL;
+ *o_addr |= ((i_sat_id & 0xF) << 6);
+}
+
+void set_chiplet_id(const uint8_t i_chiplet_id, uint64_t * o_addr)
+{
+ *o_addr &= 0xFFFFFFFFC0FFFFFFULL;
+ *o_addr |= ((i_chiplet_id & 0x3F) << 24);
+}
+
+void set_ring(const uint8_t i_ring, uint64_t * o_addr)
+{
+ *o_addr &= 0xFFFFFFFFFFFF03FFULL;
+ *o_addr |= ((i_ring & 0x3F) << 10);
+}
+
+void set_sat_offset(const uint8_t i_sat_offset, uint64_t * o_addr)
+{
+ *o_addr &= 0xFFFFFFFFFFFFFFC0ULL;
+ *o_addr |= (i_sat_offset & 0x3F);
+}
+
+void set_rxtx_group_id(const uint8_t i_grp_id, uint64_t * o_addr)
+{
+ *o_addr &= 0xFFFFF81FFFFFFFFFULL;
+ *o_addr |= (i_grp_id & 0x3FULL) << 37;
+}
+
+uint8_t get_sat_id(const uint64_t i_addr)
+{
+ return ((i_addr >> 6) & 0xF);
+}
+
+uint8_t get_chiplet_id(const uint64_t i_addr)
+{
+ return ((i_addr >> 24) & 0x3F);
+}
+
+uint8_t get_ring(const uint64_t i_addr)
+{
+ return ((i_addr >> 10) & 0x3F);
+}
+
+uint8_t get_sat_offset(const uint64_t i_addr)
+{
+ return (i_addr & 0x3F);
+}
+
+uint8_t get_rxtx_group_id(const uint64_t i_addr)
+{
+ return (i_addr >> 37) & 0x3F;
+}
+
diff --git a/src/occ_gpe0/firdata/scom_addr_util.h b/src/occ_gpe0/firdata/scom_addr_util.h
new file mode 100644
index 0000000..51988b4
--- /dev/null
+++ b/src/occ_gpe0/firdata/scom_addr_util.h
@@ -0,0 +1,81 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/scom_addr_util.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 */
+#ifndef __scom_addr_util_h
+#define __scom_addr_util_h
+
+#include <stdint.h>
+
+//This file is a result of de-classing the p9_scom_addr that currently
+//lives in EKB: chips/p9/common/scominfo/p9_scom_addr.H
+
+// @brief Modify SCOM address, update satellite ID field
+// @param[in] i_sat_id Satellite ID value to write
+// @retval none
+//
+void set_sat_id(const uint8_t i_sat_id, uint64_t * o_addr);
+
+// @brief Modify SCOM address, update pervasive chiplet ID
+// @param[in] i_chiplet_id Chiplet ID value to write
+// @retval none
+//
+void set_chiplet_id(const uint8_t i_chiplet_id, uint64_t * o_addr);
+
+// @brief Modify SCOM address, update ring field value
+// @param[in] i_ring Ring field value to write
+// @retval none
+void set_ring(const uint8_t i_ring, uint64_t * o_addr);
+
+// @brief Modify SCOM address, update satellite offset field
+// @param[in] i_sat_offset Satellite offset value to write
+// @retval none
+void set_sat_offset(const uint8_t i_sat_offset, uint64_t * o_addr);
+
+// @brief Modify SCOM address, update the RX or TX Group ID
+// @param[in] i_grp_id Group id to set
+// @retval none
+void set_rxtx_group_id(const uint8_t i_grp_id, uint64_t * o_addr);
+
+// @brief Extract satellite ID field from SCOM address
+// @retval uint8_t Satellite ID field value
+uint8_t get_sat_id(const uint64_t i_addr);
+
+// @brief Extract pervasive chiplet ID from SCOM address
+// @retval uint8_t Pervasive chiplet ID value
+uint8_t get_chiplet_id(const uint64_t i_addr);
+
+// @brief Extract ring field from SCOM address
+// @retval uint8_t Ring field value
+uint8_t get_ring(const uint64_t i_addr);
+
+// @brief Extract satellite register offset field from SCOM address
+// @retval uint8_t Satellite register offset field value
+uint8_t get_sat_offset(const uint64_t i_addr);
+
+// @brief Extract the RX or TX Group ID of an indirect scom address
+// @retval uint8_t Satellite register offset field value
+uint8_t get_rxtx_group_id(const uint64_t i_addr);
+
+
+#endif
diff --git a/src/occ_gpe0/firdata/scom_trgt.c b/src/occ_gpe0/firdata/scom_trgt.c
new file mode 100644
index 0000000..15ad3fc
--- /dev/null
+++ b/src/occ_gpe0/firdata/scom_trgt.c
@@ -0,0 +1,180 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/scom_trgt.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 <native.h>
+#include <scom_trgt.h>
+#include <scom_util.h>
+
+/*------------------------------------------------------------------------------ */
+
+SCOM_Trgt_t SCOM_Trgt_getTrgt( TrgtType_t i_type, uint8_t i_procPos,
+ uint8_t i_procUnitPos, uint32_t i_fsiBaseAddr,
+ bool i_isMaster )
+{
+ SCOM_Trgt_t trgt = {
+ .type = i_type,
+ .procPos = i_procPos,
+ .procUnitPos = i_procUnitPos,
+ .isMaster = i_isMaster,
+ .fsiBaseAddr = i_fsiBaseAddr,
+ };
+
+ if (TRGT_PROC == trgt.type)
+ {
+ trgt.procUnitPos = 0;
+ }
+
+ if ( TRGT_MEMBUF == trgt.type || TRGT_MBA == trgt.type )
+ {
+ trgt.isMaster = false;
+ }
+
+ return trgt;
+}
+
+/*------------------------------------------------------------------------------ */
+
+uint8_t SCOM_Trgt_getChipPos( SCOM_Trgt_t i_trgt )
+{
+ uint32_t p = 0;
+
+ switch ( i_trgt.type )
+ {
+ case TRGT_PROC:
+ case TRGT_CAPP:
+ case TRGT_XBUS:
+ case TRGT_OBUS:
+ case TRGT_PEC:
+ case TRGT_PHB:
+ case TRGT_EQ:
+ case TRGT_EX:
+ case TRGT_EC:
+ case TRGT_MCBIST:
+ case TRGT_MCS:
+ case TRGT_MCA:
+ p = i_trgt.procPos;
+ break;
+
+ case TRGT_MEMBUF: /* TODO RTC 173614 -- with CUMULUS */
+ p = (i_trgt.procPos * MAX_MEMBUF_PER_PROC) + i_trgt.procUnitPos;
+ break;
+
+ case TRGT_MBA: /* TODO RTC 173614 -- with CUMULUS */
+ p = (i_trgt.procPos * MAX_MEMBUF_PER_PROC) +
+ (i_trgt.procUnitPos / MAX_MBA_PER_MEMBUF);
+ break;
+
+ default: ;
+ }
+
+ return p;
+}
+
+/*------------------------------------------------------------------------------ */
+
+uint8_t SCOM_Trgt_getChipUnitPos( SCOM_Trgt_t i_trgt )
+{
+ uint32_t u = 0;
+
+ switch ( i_trgt.type )
+ {
+ case TRGT_PROC:
+ case TRGT_MEMBUF: u = 0; break;
+
+ case TRGT_CAPP:
+ case TRGT_XBUS:
+ case TRGT_OBUS:
+ case TRGT_PEC:
+ case TRGT_PHB:
+ case TRGT_EQ:
+ case TRGT_EX:
+ case TRGT_EC:
+ case TRGT_MCBIST:
+ case TRGT_MCS:
+ case TRGT_MCA: u = i_trgt.procUnitPos; break;
+
+ case TRGT_MBA: u = i_trgt.procUnitPos % MAX_MBA_PER_MEMBUF; break;
+ /* TODO RTC 173614 -- with CUMULUS */
+
+ default: ;
+ }
+
+ return u;
+}
+
+/*------------------------------------------------------------------------------ */
+
+SCOM_Trgt_t SCOM_Trgt_getParentChip( SCOM_Trgt_t i_trgt )
+{
+ TrgtType_t t = TRGT_MAX;
+ switch ( i_trgt.type )
+ {
+ case TRGT_PROC:
+ case TRGT_CAPP:
+ case TRGT_XBUS:
+ case TRGT_OBUS:
+ case TRGT_PEC:
+ case TRGT_PHB:
+ case TRGT_EQ:
+ case TRGT_EX:
+ case TRGT_EC:
+ case TRGT_MCBIST:
+ case TRGT_MCS:
+ case TRGT_MCA: t = TRGT_PROC; break;
+
+ case TRGT_MEMBUF:
+ case TRGT_MBA: t = TRGT_MEMBUF; break;
+
+ default: ;
+ }
+
+ uint8_t u = 0;
+ switch ( i_trgt.type )
+ {
+ case TRGT_PROC:
+ case TRGT_CAPP:
+ case TRGT_XBUS:
+ case TRGT_OBUS:
+ case TRGT_PEC:
+ case TRGT_PHB:
+ case TRGT_EQ:
+ case TRGT_EX:
+ case TRGT_EC:
+ case TRGT_MCBIST:
+ case TRGT_MCS:
+ case TRGT_MCA:
+ case TRGT_MEMBUF: u = i_trgt.procUnitPos; break;
+ /* TODO RTC 173614 -- with CUMULUS */
+
+ case TRGT_MBA: u = i_trgt.procUnitPos / MAX_MBA_PER_MEMBUF; break;
+ /* TODO RTC 173614 -- with CUMULUS */
+
+ default: ;
+ }
+
+ return SCOM_Trgt_getTrgt( t, i_trgt.procPos, u, i_trgt.fsiBaseAddr,
+ i_trgt.isMaster );
+}
+
diff --git a/src/occ_gpe0/firdata/scom_trgt.h b/src/occ_gpe0/firdata/scom_trgt.h
new file mode 100644
index 0000000..4ffe8b5
--- /dev/null
+++ b/src/occ_gpe0/firdata/scom_trgt.h
@@ -0,0 +1,89 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/scom.H $ */
+/* */
+/* 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 */
+
+#ifndef __scom_trgt_h
+#define __scom_trgt_h
+
+#include <firDataConst_common.h>
+#include <native.h>
+
+typedef struct
+{
+ /** See enum TrgtType_t. NOTE: This value is not consistant with Hostboot
+ * target types. */
+ TrgtType_t type;
+
+ /** Absolute position of the connected PROC within the node. This value
+ * should be consistant with the Hostboot target positions. */
+ uint8_t procPos;
+
+ /** Unit position relative to the connected PROC. This value should be
+ * consistant with the Hostboot target positions. */
+ uint8_t procUnitPos;
+
+ /** Indicates this target is, or is connected to, the master processor. */
+ bool isMaster;
+
+ /** This target's FSI base address. */
+ uint32_t fsiBaseAddr;
+
+} SCOM_Trgt_t;
+
+/** @param i_type See enum Type.
+ * @param i_procPos Absolute position within the node of the connected
+ * PROC target.
+ * @param i_procUnitPos Unit position relative to the connected PROC. Will be
+ * explicitly set to 0 for PROC targets.
+ * @param i_fsiBaseAddr For EX and MCS, the FSI base address for the
+ * connected PROC. For MEMB and MBA, the FSI base
+ * address for the connected MEMB.
+ * @param i_isMaster True, if this target is, or is connected to, the
+ * master processor. False, otherwise. Will be explicitly
+ * set to false for MEMB and MBA targets.
+ * @return A SCOM_Trgt_t struct.
+ */
+SCOM_Trgt_t SCOM_Trgt_getTrgt( TrgtType_t i_type, uint8_t i_procPos,
+ uint8_t i_procUnitPos, uint32_t i_fsiBaseAddr,
+ bool i_isMaster );
+
+/** @param i_trgt The SCOM target.
+ * @return This target's absolute position of the parent chip (PROC or
+ * MEMB) within the node.
+ */
+uint8_t SCOM_Trgt_getChipPos( SCOM_Trgt_t i_trgt );
+
+/** @param i_trgt The SCOM target.
+ * @return This target's unit position relative to the parent chip. Only
+ * valid for EX, MCS, and MBA units. Will return 0 for PROC and
+ * MEMB chips.
+ */
+uint8_t SCOM_Trgt_getChipUnitPos( SCOM_Trgt_t i_trgt );
+
+/** @param i_trgt The SCOM target.
+ * @return A target for the containing parent chip (PROC or MEMB).
+ */
+SCOM_Trgt_t SCOM_Trgt_getParentChip( SCOM_Trgt_t i_trgt );
+
+#endif /* __scom_trgt_h */
diff --git a/src/occ_gpe0/firdata/scom_util.c b/src/occ_gpe0/firdata/scom_util.c
new file mode 100644
index 0000000..7709017
--- /dev/null
+++ b/src/occ_gpe0/firdata/scom_util.c
@@ -0,0 +1,607 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/scom_util.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 */
+
+/* Support for SCOM operations */
+#include <fsi.h>
+#include <native.h>
+#include <occhw_async.h>
+#include "occ_common.h"
+#include "gpe_export.h"
+#include <scom_util.h>
+#include "scom_addr_util.h"
+#include <sbe_fifo.h>
+
+bool G_request_created = FALSE;
+GPE_BUFFER(ipc_scom_op_t G_scom_op);
+GpeRequest G_request;
+
+enum {
+ /*FSI addresses are byte offsets, so need to multiply by 4
+ since each register is 4 bytes long.
+ prefix with 0x10xx for FSI2PIB engine offset */
+ DATA0_REG = 0x1000, /* SCOM Data Register 0 (0x00) */
+ DATA1_REG = 0x1004, /* SCOM Data Register 1 (0x01) */
+ COMMAND_REG = 0x1008, /* SCOM Command Register (0x02) */
+ ENGINE_RESET_REG = 0x1018, /* Engine Reset Register (0x06) */
+ STATUS_REG = 0x101C, /* STATUS Register (0x07) */
+ PIB_RESET_REG = 0x101C, /* PIB Reset Register (0x07) */
+
+ PIB_ABORT_BIT = 0x00100000, /* 12= PIB Abort */
+ PIB_ERROR_BITS = 0x00007000, /* 17:19= PCB/PIB Errors */
+};
+
+/**
+ * @brief Indirect SCOM Status
+ */
+typedef union
+{
+ uint64_t data64;
+ struct
+ {
+ uint64_t :12; /*0:11*/
+ uint64_t addr:20; /*12:31*/
+ uint64_t done:1; /*32*/
+ uint64_t piberr:3; /*33:35*/
+ uint64_t userstat:4; /*36:39*/
+ uint64_t :8; /*40:47*/
+ uint64_t data:16; /*48:63*/
+ };
+} IndirectScom_t;
+
+enum {
+ MCS_MASK = 0xFFFFFFFF7FFFFF80,
+ MCS_BASEADDR = 0x0000000002011800,
+ MCS_DMI_BASEADDR = 0x0000000002011A00,
+ IND_MCS_BASEADDR = 0x8000006002011A00,
+ IND_MCS_DMI_BASEADDR = 0x8000006002011A3F,
+ MBA_MASK = 0xFFFFFFFF7FFFFC00,
+ MBA_BASEADDR = 0x0000000003010400,
+ TCM_MBA_BASEADDR = 0x0000000003010800,
+ IND_MBA_BASEADDR = 0x800000000301143f,
+};
+
+/**
+ * @brief Translates a relative unit address to a real physical address
+ * @param i_trgt Chip/unit to SCOM.
+ * @param i_addr Address to SCOM (the unit's 0th address for unit SCOMs).
+ * @param o_addr Return address.
+ * @return Non-SUCCESS if an internal function fails. SUCCESS otherwise.
+ */
+int32_t translate_addr( SCOM_Trgt_t i_trgt, uint64_t i_addr, uint64_t * o_addr )
+{
+ #define FUNC "[translate_addr] "
+
+ int32_t rc = SUCCESS;
+ uint8_t l_chip_unit_num = SCOM_Trgt_getChipUnitPos(i_trgt);
+
+ *o_addr = i_addr;
+
+ //The following translation logic is a copy of p9_scominfo_createChipUnitScomAddr
+ //function from EKB (chips/p9/common/scominfo/p9_scominfo.C)
+
+ if(i_trgt.type == TRGT_PROC || i_trgt.type == TRGT_MEMBUF)
+ {
+ //No need to translate here.
+ //We already assigned i_addr to o_addr above, so just return SUCCESS.
+ return rc;
+ }
+ else if(i_trgt.type == TRGT_CAPP) //CAPP
+ {
+ set_chiplet_id(N0_CHIPLET_ID + (l_chip_unit_num * 2), o_addr);
+ }
+ else if(i_trgt.type == TRGT_XBUS) //XBUS
+ {
+ uint8_t l_ring_id = get_ring(i_addr) & 0xF;
+ if(l_ring_id <= XB_IOX_2_RING_ID && l_ring_id >= XB_IOX_0_RING_ID)
+ {
+ set_ring((XB_IOX_0_RING_ID + l_chip_unit_num) & 0xF, o_addr);
+ }
+ else if(l_ring_id <= XB_PBIOX_2_RING_ID &&
+ l_ring_id >= XB_PBIOX_0_RING_ID)
+ {
+ set_ring((XB_PBIOX_0_RING_ID + l_chip_unit_num) & 0xF, o_addr);
+ }
+ }
+ else if(i_trgt.type == TRGT_OBUS) //OBUS
+ {
+ set_chiplet_id(OB0_CHIPLET_ID + l_chip_unit_num, o_addr);
+ }
+ else if(i_trgt.type == TRGT_PEC) //PEC
+ {
+ if(get_chiplet_id(i_addr) == N2_CHIPLET_ID)
+ {
+ // nest
+ set_ring((N2_PCIS0_0_RING_ID + l_chip_unit_num) & 0xF, o_addr);
+ }
+ else
+ {
+ // iopci / pci
+ set_chiplet_id(PCI0_CHIPLET_ID + l_chip_unit_num, o_addr);
+ }
+ }
+ else if (i_trgt.type == TRGT_PHB) //PHB
+ {
+ if(get_chiplet_id(i_addr) == N2_CHIPLET_ID)
+ {
+ // nest
+ if(l_chip_unit_num == 0)
+ {
+ set_ring(N2_PCIS0_0_RING_ID & 0xF, o_addr);
+ set_sat_id((get_sat_id(i_addr) < 4) ? 1 : 4, o_addr);
+ }
+ else
+ {
+ set_ring((N2_PCIS0_0_RING_ID + (l_chip_unit_num / 3) + 1) & 0xF,
+ o_addr);
+ set_sat_id(((get_sat_id(i_addr) < 4) ? 1 : 4) +
+ ((l_chip_unit_num % 2) ? 0 : 1) +
+ (2 * l_chip_unit_num / 5), o_addr);
+ }
+ }
+ else
+ {
+ // pci
+ if(l_chip_unit_num == 0)
+ {
+ set_chiplet_id(PCI0_CHIPLET_ID, o_addr);
+ set_sat_id(((get_sat_id(i_addr) < 4) ? 1 : 4), o_addr);
+ }
+ else
+ {
+ set_chiplet_id(PCI0_CHIPLET_ID + (l_chip_unit_num / 3) + 1, o_addr);
+ set_sat_id(((get_sat_id(i_addr) < 4) ? 1 : 4) +
+ ((l_chip_unit_num % 2) ? 0 : 1) +
+ 2 * l_chip_unit_num / 5, o_addr);
+ }
+ }
+ }
+ else if(i_trgt.type == TRGT_EX) //EX
+ {
+ if(get_chiplet_id(i_addr) <= EP05_CHIPLET_ID &&
+ get_chiplet_id(i_addr) >= EP00_CHIPLET_ID)
+ {
+ set_chiplet_id(EP00_CHIPLET_ID + (l_chip_unit_num / 2), o_addr);
+ uint8_t l_ring_id = get_ring(i_addr) & 0xF;
+ l_ring_id = (l_ring_id - (l_ring_id % 2)) + (l_chip_unit_num % 2);
+ set_ring(l_ring_id & 0xF, o_addr);
+ }
+ else if(get_chiplet_id(i_addr) <= EC23_CHIPLET_ID &&
+ get_chiplet_id(i_addr) >= EC00_CHIPLET_ID)
+ {
+ set_chiplet_id(EC00_CHIPLET_ID +
+ (get_chiplet_id(i_addr) % 2) +
+ (l_chip_unit_num * 2), o_addr);
+ }
+ }
+ else if(i_trgt.type == TRGT_EQ) //EQ
+ {
+ set_chiplet_id(EP00_CHIPLET_ID + l_chip_unit_num, o_addr);
+ }
+ else if(i_trgt.type == TRGT_EC) //EC
+ {
+ set_chiplet_id(EC00_CHIPLET_ID + l_chip_unit_num, o_addr);
+ }
+ else if(i_trgt.type == TRGT_MBA) //MBA
+ {
+ if( (i_addr & MBA_MASK) == MBA_BASEADDR )
+ {
+ /* 0x00000000_03010400 MBA 0 # MBA01 */
+ /* 0x00000000_03010C00 MBA 1 # MBA23 */
+ if( l_chip_unit_num == 1 )
+ {
+ *o_addr |= 0x00000800;
+ }
+ }
+ else if( (i_addr & MBA_MASK) == TCM_MBA_BASEADDR )
+ {
+ /* 0x00000000_03010880 MBA 0 # Trace for MBA01 */
+ /* 0x00000000_030110C0 MBA 1 # Trace for MBA23 */
+ *o_addr |= (l_chip_unit_num * 0x840);
+ }
+ else if( (i_addr & MBA_MASK) == IND_MBA_BASEADDR )
+ {
+ /* 0x00000000_03011400 MBA 0 # DPHY01 (indirect addressing) */
+ /* 0x00000000_03011800 MBA 1 # DPHY23 (indirect addressing) */
+ /* 0x80000000_0301143f MBA 0 # DPHY01 (indirect addressing) */
+ /* 0x80000000_0301183f MBA 1 # DPHY23 (indirect addressing) */
+ /* 0x80000000_0701143f MBA 0 # DPHY01 (indirect addressing) */
+ /* 0x80000000_0701183f MBA 1 # DPHY23 (indirect addressing) */
+ if( l_chip_unit_num == 1 )
+ {
+ /* 030114zz->030118zz */
+ *o_addr &= 0xFFFFFFFFFFFFFBFF;
+ *o_addr |= 0x0000000000000800;
+ }
+ }
+ }
+ else if(i_trgt.type == TRGT_MCS || //MCS
+ i_trgt.type == TRGT_MI) //MI TODO RTC 175488
+ {
+ set_chiplet_id(N3_CHIPLET_ID - (2 * (l_chip_unit_num / 2)), o_addr);
+ set_sat_id(2 * (l_chip_unit_num % 2), o_addr);
+ }
+ else if(i_trgt.type == TRGT_MCBIST || //MCBIST
+ i_trgt.type == TRGT_MC) //MC TODO RTC 175488
+ {
+ set_chiplet_id(MC01_CHIPLET_ID + l_chip_unit_num, o_addr);
+ }
+ else if(i_trgt.type == TRGT_MCA) //MCA
+ {
+ if(get_chiplet_id(i_addr) == MC01_CHIPLET_ID ||
+ get_chiplet_id(i_addr) == MC23_CHIPLET_ID)
+ {
+ set_chiplet_id(MC01_CHIPLET_ID + (l_chip_unit_num / 4), o_addr);
+
+ if((get_ring(i_addr) & 0xf) == MC_MC01_0_RING_ID)
+ {
+ // mc
+ uint8_t l_sat_id = get_sat_id(i_addr);
+ set_sat_id((l_sat_id - (l_sat_id % 4)) + (l_chip_unit_num % 4)
+ , o_addr);
+ }
+ else
+ {
+ // iomc
+ set_ring((MC_IOM01_0_RING_ID + (l_chip_unit_num % 4)) & 0xF
+ , o_addr);
+ }
+ }
+ else
+ {
+ // mcs->mca registers
+ uint8_t l_mcs_unitnum = l_chip_unit_num / 2;
+ set_chiplet_id(N3_CHIPLET_ID - (2 * (l_mcs_unitnum / 2)) , o_addr);
+ set_sat_id(2 * (l_chip_unit_num % 2), o_addr);
+ uint8_t l_mcs_sat_offset = 0x2F & get_sat_offset(i_addr);
+ l_mcs_sat_offset |= (l_chip_unit_num % 2) << 4;
+ set_sat_offset(l_mcs_sat_offset, o_addr);
+ }
+ }
+ else if(i_trgt.type == TRGT_DMI) //DMI TODO RTC 175488
+ {
+ if(get_chiplet_id(i_addr) == N3_CHIPLET_ID || get_chiplet_id(i_addr) == N1_CHIPLET_ID)
+ {
+ set_chiplet_id(N3_CHIPLET_ID - 2 * (l_chip_unit_num / 4), o_addr);
+ set_sat_id(2 * ((l_chip_unit_num / 2) % 2), o_addr);
+ uint8_t l_sat_offset = get_sat_offset(i_addr);
+ l_sat_offset = (l_sat_offset & 0xF) + ((2 + (l_chip_unit_num % 2)) << 4);
+ set_sat_offset(l_sat_offset, o_addr);
+ }
+ else if(get_chiplet_id(i_addr) == MC01_CHIPLET_ID || get_chiplet_id(i_addr) == MC23_CHIPLET_ID)
+ {
+ if(get_ring(i_addr) == P9C_MC_CHAN_RING_ID)
+ {
+ set_chiplet_id(MC01_CHIPLET_ID + l_chip_unit_num / 4, o_addr);
+ uint8_t l_sat_id = get_sat_id(i_addr);
+ l_sat_id = l_sat_id & 0xC;
+ set_sat_id(l_sat_id + l_chip_unit_num % 4, o_addr);
+ }
+ else if(get_ring(i_addr) == P9C_MC_BIST_RING_ID)
+ {
+ set_chiplet_id(MC01_CHIPLET_ID + l_chip_unit_num / 4, o_addr);
+ uint8_t l_sat_offset = get_sat_offset(i_addr);
+ l_sat_offset = (l_sat_offset & 0xF) + ((l_chip_unit_num % 2) << 4);
+ set_sat_offset(l_sat_offset, o_addr);
+ }
+ else if(get_ring(i_addr) == P9C_MC_IO_RING_ID)
+ {
+ set_chiplet_id(MC01_CHIPLET_ID + l_chip_unit_num / 4, o_addr);
+ uint8_t l_rxtx_group = get_rxtx_group_id(i_addr);
+ l_rxtx_group = l_rxtx_group & 0xF0;
+
+ switch(l_chip_unit_num % 4)
+ {
+ case 0:
+ l_rxtx_group += 3;
+ break;
+ case 1:
+ l_rxtx_group += 2;
+ break;
+ case 2:
+ l_rxtx_group += 0;
+ break;
+ case 3:
+ l_rxtx_group += 1;
+ break;
+ default:
+ break;
+ }
+ set_rxtx_group_id(l_rxtx_group, o_addr);
+ }
+ }
+ }
+ else
+ {
+ TRAC_ERR( FUNC"unsupported unit type %d", i_trgt.type );
+ rc = FAIL;
+ }
+
+ return rc;
+
+ #undef FUNC
+}
+
+/**
+ * @brief Performs a getscom operation with no address translation.
+ * @param i_chip Chip to SCOM.
+ * @param i_addr Address to SCOM.
+ * @param o_val Returned value.
+ * @return Non-SUCCESS if an internal function fails. SUCCESS otherwise.
+ */
+int32_t getscomraw( SCOM_Trgt_t i_chip, uint32_t i_addr, uint64_t * o_val )
+{
+ int32_t l_rc = SUCCESS;
+
+ //Use SBE FIFO if it's a slave proc
+ if(!i_chip.isMaster)
+ {
+ return getFifoScom(&i_chip, i_addr, o_val);
+ }
+
+ if(!G_request_created) //Only need to create request once
+ {
+ l_rc = gpe_request_create(&G_request, //Request
+ &G_async_gpe_queue0, //Queue
+ IPC_ST_SCOM_OPERATION, //Function ID
+ &G_scom_op, //GPE arguments
+ SSX_SECONDS(5), //Timeout
+ NULL, //Callback function
+ NULL, //Callback args
+ ASYNC_REQUEST_BLOCKING); //Options
+ if(l_rc)
+ {
+ TRAC_ERR("getscomraw: failed to create gpe request, rc=0x%08X", l_rc);
+ return l_rc;
+ }
+ else
+ {
+ G_request_created = TRUE;
+ }
+ }
+
+ //Pack in the request data
+ G_scom_op.read = TRUE;
+ G_scom_op.addr = i_addr;
+
+ l_rc = gpe_request_schedule(&G_request);
+ if(l_rc)
+ {
+ TRAC_ERR("getscomraw: failed to schedule gpe request, rc=0x%08X", l_rc);
+ return l_rc;
+ }
+
+ //Since it's a blocking request, it should be completed by the time we
+ //get here. If it's not, then a timeout has occurred.
+ if(G_request.request.completion_state == ASYNC_REQUEST_STATE_COMPLETE)
+ {
+ *o_val = G_scom_op.data;
+ }
+ else
+ {
+ *o_val = 0;
+ l_rc = FAIL;
+ }
+
+ return l_rc;
+}
+
+/**
+ * @brief Perform a putscom operation with no address translation.
+ * @param i_chip Chip to SCOM.
+ * @param i_addr Address to SCOM.
+ * @param i_val Value to write.
+ * @return Non-SUCCESS if an internal function fails. SUCCESS otherwise.
+ */
+int32_t putscomraw( SCOM_Trgt_t i_chip, uint32_t i_addr, uint64_t i_val )
+{
+ int32_t l_rc = SUCCESS;
+
+ //Use SBE FIFO if it's a slave proc
+ if(!i_chip.isMaster)
+ {
+ return putFifoScom(&i_chip, i_addr, i_val);
+ }
+
+ if(!G_request_created) //Only need to create request once
+ {
+ l_rc = gpe_request_create(&G_request, //Request
+ &G_async_gpe_queue0, //Queue
+ IPC_ST_SCOM_OPERATION, //Function ID
+ &G_scom_op, //GPE arguments
+ SSX_SECONDS(5), //Timeout
+ NULL, //Callback function
+ NULL, //Callback args
+ ASYNC_REQUEST_BLOCKING); //Options
+ if(l_rc)
+ {
+ TRAC_ERR("putscomraw gpe request create failed, rc = 0x%08x", l_rc);
+ return l_rc;
+ }
+ else
+ {
+ G_request_created = TRUE;
+ }
+ }
+
+ //Pack in the request data
+ G_scom_op.read = FALSE;
+ G_scom_op.addr = i_addr;
+ G_scom_op.data = i_val;
+
+ l_rc = gpe_request_schedule(&G_request);
+ if(l_rc)
+ {
+ TRAC_ERR("putscomraw gpe request schedule failed, rc=0x%08X", l_rc);
+ return l_rc;
+ }
+
+ //It's a blocking request, so if the request hasn't been completed by this
+ //time, then a timeout has occurred.
+ if(G_request.request.completion_state != ASYNC_REQUEST_STATE_COMPLETE)
+ {
+ TRAC_ERR("putscomraw gpe request failed to complete, rc = 0x%08x", l_rc);
+ l_rc = FAIL;
+ }
+
+ return l_rc;
+}
+
+/**
+ * @brief Executes standard getscom.
+ * @param i_trgt Chip to SCOM.
+ * @param i_addr Address to SCOM.
+ * @param o_val Returned value.
+ * @return Non-SUCCESS if an internal function fails. SUCCESS otherwise.
+ */
+int32_t SCOM_getScom( SCOM_Trgt_t i_trgt, uint32_t i_addr, uint64_t * o_val )
+{
+ int32_t rc = SUCCESS;
+
+ /* Get the parent chip. */
+ SCOM_Trgt_t chip_targ = SCOM_Trgt_getParentChip(i_trgt);
+
+ /* Get the address relative to the parent chip. */
+ uint64_t trans_addr;
+ rc = translate_addr( i_trgt, i_addr, &trans_addr );
+ if ( SUCCESS == rc )
+ {
+ /* Do the SCOM. */
+ rc = getscomraw( chip_targ, trans_addr, o_val );
+ }
+
+ return rc;
+}
+
+/**
+ * @brief Execute indirect getscom.
+ * @param i_trgt Chip to SCOM.
+ * @param i_addr Address to SCOM.
+ * @param o_val Returned value.
+ * @return Non-SUCCESS if an internal function fails. SUCCESS otherwise.
+ */
+int32_t SCOM_getIdScom( SCOM_Trgt_t i_trgt, uint64_t i_addr, uint32_t * o_val )
+{
+ #define FUNC "[SCOM_getIdScom] "
+
+ int32_t rc = SUCCESS;
+
+ *o_val = 0;
+
+ /* Get the parent chip */
+ SCOM_Trgt_t chip_targ = SCOM_Trgt_getParentChip(i_trgt);
+
+ /* Get the address relative to the parent chip. */
+ uint64_t trans_addr;
+ rc = translate_addr( i_trgt, i_addr, &trans_addr );
+ if ( SUCCESS != rc ) return rc;
+
+ /* An indirect SCOM is performed by putting the top of the 64-bit address
+ * into the first data word of the SCOM */
+
+ /* Zero out the indirect address from the buffer. */
+ /* bit 0-31 - indirect area. */
+ /* bit 32 - always 0 */
+ /* bit 33-47 - bcast/chipletID/port */
+ /* bit 48-63 - local addr */
+ uint32_t phys_addr = trans_addr & 0x000000007FFFFFFF;
+
+ /* To do a read we need to do a write first. */
+
+ /* Start with the 20bit indirect address */
+ uint64_t data_buffer = trans_addr & 0x001FFFFF00000000;
+ /* Turn the read bit on. */
+ data_buffer |= 0x8000000000000000;
+
+ /* perform write before the read with the new */
+ rc = putscomraw( i_trgt, phys_addr, data_buffer );
+ if ( SUCCESS != rc ) return rc;
+
+ // Loop on read until we see done, error, or we timeout
+ IndirectScom_t scomout;
+ uint64_t elapsed_indScom_time_ns = 0;
+ do
+ {
+ /* Now perform the op requested using the passed in */
+ /* IO_Buffer to pass the read data back to caller. */
+ rc = getscomraw( chip_targ, phys_addr, &(scomout.data64) );
+ if ( SUCCESS != rc ) return rc;
+
+ /* Check for PIB error. */
+ if ( scomout.piberr )
+ {
+ TRAC_ERR( FUNC"ID SCOM PIB error: phys_addr=0x%08x "
+ "trans_addr=0x%08x%08x", phys_addr,
+ (uint32_t)(trans_addr >> 32), (uint32_t)trans_addr );
+ return FAIL;
+ }
+
+ /* Jump out when done. */
+ if ( scomout.done ) break;
+
+ sleep( 10000 ); /* sleep for 10,000 ns */
+ elapsed_indScom_time_ns += 10000;
+
+ } while ( elapsed_indScom_time_ns <= 100000 ); /* wait for .1ms */
+
+ if ( !scomout.done )
+ {
+ TRAC_ERR( FUNC"ID SCOM loop timeout exceeded: phys_addr=0x%08x "
+ "trans_addr=0x%08x%08x", phys_addr,
+ (uint32_t)(trans_addr >> 32), (uint32_t)trans_addr );
+ return FAIL;
+ }
+
+ *o_val = scomout.data;
+
+ return rc;
+
+ #undef FUNC
+}
+
+/**
+ * @brief Executes standard putscom.
+ * @param i_trgt Chip to SCOM.
+ * @param i_addr Address to SCOM.
+ * @param i_val Value to put.
+ * @return Non-SUCCESS if an internal function fails. SUCCESS otherwise.
+*/
+int32_t SCOM_putScom( SCOM_Trgt_t i_trgt, uint32_t i_addr, uint64_t i_val )
+{
+ int32_t l_rc = SUCCESS;
+
+ /* Get the parent chip. */
+ SCOM_Trgt_t l_chip_targ = SCOM_Trgt_getParentChip(i_trgt);
+
+ /* Get the address relative to the parent chip. */
+ uint64_t l_trans_addr;
+ l_rc = translate_addr( i_trgt, i_addr, &l_trans_addr );
+ if ( SUCCESS == l_rc )
+ {
+ /* Do the SCOM. */
+ l_rc = putscomraw( l_chip_targ, l_trans_addr, i_val );
+ }
+
+ return l_rc;
+}
diff --git a/src/occ_gpe0/firdata/scom_util.h b/src/occ_gpe0/firdata/scom_util.h
new file mode 100644
index 0000000..1ec7fd2
--- /dev/null
+++ b/src/occ_gpe0/firdata/scom_util.h
@@ -0,0 +1,98 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/scom_util.h $ */
+/* */
+/* 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 */
+
+/* Interfaces to read SCOM registers */
+
+/*#include <stdint.h> */
+#include <native.h>
+#include <scom_trgt.h>
+
+#define SCOMFAIL 0xDEADBEEF
+
+typedef enum
+{
+ N0_CHIPLET_ID = 0x02, ///< Nest0 (North) chiplet
+ N1_CHIPLET_ID = 0x03, ///< Nest1 (East) chiplet
+ N2_CHIPLET_ID = 0x04, ///< Nest2 (South) chiplet
+ N3_CHIPLET_ID = 0x05, ///< Nest3 (West) chiplet
+ MC01_CHIPLET_ID = 0x07, ///< MC01 (West) chiplet
+ MC23_CHIPLET_ID = 0x08, ///< MC23 (East) chiplet
+ OB0_CHIPLET_ID = 0x09, ///< OBus0 chiplet
+ PCI0_CHIPLET_ID = 0x0D, ///< PCIe0 chiplet
+ EP00_CHIPLET_ID = 0x10, ///< Quad0 chiplet (EX0/1)
+ EP05_CHIPLET_ID = 0x15, ///< Quad5 chiplet (EX10/11)
+ EC00_CHIPLET_ID = 0x20, ///< Core0 chiplet (Quad0, EX0, C0)
+ EC23_CHIPLET_ID = 0x37 ///< Core23 chiplet (Quad5, EX11, C1)
+} p9_chiplet_id_t;
+
+typedef enum
+{
+ MC_MC01_0_RING_ID = 0x2, ///< MC01_0 / MC23_0
+ MC_IOM01_0_RING_ID = 0x4, ///< IOM01_0 / IOM45_0
+} p9_mc_ring_id_t;
+
+typedef enum
+{
+ XB_IOX_0_RING_ID = 0x3, ///< IOX_0
+ XB_IOX_2_RING_ID = 0x5, ///< IOX_2
+ XB_PBIOX_0_RING_ID = 0x6, ///< PBIOX_0
+ XB_PBIOX_2_RING_ID = 0x8 ///< PBIOX_2
+} p9_xb_ring_id_t;
+
+typedef enum
+{
+ P9C_MC_CHAN_RING_ID = 0x2,
+ P9C_MC_IO_RING_ID = 0x4,
+ P9C_MC_BIST_RING_ID = 0x8
+} p9c_mc_ring_id_t;
+
+typedef enum
+{
+ N2_PCIS0_0_RING_ID = 0x3, ///< PCIS0_0
+} p9_n2_ring_id_t;
+
+/** @brief Performs a hardware scom on a regular register.
+ * @param i_trgt The SCOM target.
+ * @param i_addr 32-bit SCOM address.
+ * @param o_val 64-bit returned value.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+int32_t SCOM_getScom( SCOM_Trgt_t i_trgt, uint32_t i_addr, uint64_t * o_val );
+
+/** @brief Performs a hardware put scom on a regular register.
+ * @param i_trgt The SCOM target.
+ * @param i_addr 32-bit SCOM address.
+ * @param i_val 64-bit value to write to the address.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+*/
+int32_t SCOM_putScom( SCOM_Trgt_t i_trgt, uint32_t i_addr, uint64_t i_val );
+
+/** @brief Performs a hardware scom on an indirect-SCOM register.
+ * @param i_trgt The SCOM target.
+ * @param i_addr 64-bit SCOM address.
+ * @param o_val 32-bit returned value.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+int32_t SCOM_getIdScom( SCOM_Trgt_t i_trgt, uint64_t i_addr, uint32_t * o_val );
OpenPOWER on IntegriCloud