summaryrefslogtreecommitdiffstats
path: root/src/occ_405/firdata
diff options
context:
space:
mode:
authorWilliam Bryan <wilbryan@us.ibm.com>2015-08-03 12:38:58 -0500
committerWilliam A. Bryan <wilbryan@us.ibm.com>2015-08-03 15:32:27 -0500
commit420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3 (patch)
treec9f6691eddba39193e39aa769367e1267fb9fc86 /src/occ_405/firdata
parentadade8c8ef30ed519322674c762d95663009c5d4 (diff)
downloadtalos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.tar.gz
talos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.zip
new ssx and lib files
Change-Id: I2328b1e86d59e3788910687d762fb70ec680058f Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/19503 Reviewed-by: William A. Bryan <wilbryan@us.ibm.com> Tested-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/occ_405/firdata')
-rw-r--r--src/occ_405/firdata/ecc.c272
-rw-r--r--src/occ_405/firdata/ecc.h76
-rw-r--r--src/occ_405/firdata/firData.c756
-rw-r--r--src/occ_405/firdata/firData.h48
-rw-r--r--src/occ_405/firdata/firDataConst_common.h76
-rw-r--r--src/occ_405/firdata/fir_data_collect.c163
-rw-r--r--src/occ_405/firdata/fir_data_collect.h56
-rw-r--r--src/occ_405/firdata/fsi.c152
-rw-r--r--src/occ_405/firdata/fsi.h47
-rw-r--r--src/occ_405/firdata/homerData_common.h172
-rw-r--r--src/occ_405/firdata/lpc.c302
-rw-r--r--src/occ_405/firdata/lpc.h51
-rw-r--r--src/occ_405/firdata/native.c76
-rw-r--r--src/occ_405/firdata/native.h99
-rw-r--r--src/occ_405/firdata/nor_micron.c73
-rw-r--r--src/occ_405/firdata/norflash.h154
-rw-r--r--src/occ_405/firdata/pnorData_common.h153
-rw-r--r--src/occ_405/firdata/pnor_util.c236
-rw-r--r--src/occ_405/firdata/pnor_util.h41
-rw-r--r--src/occ_405/firdata/scom_trgt.c135
-rw-r--r--src/occ_405/firdata/scom_trgt.h89
-rw-r--r--src/occ_405/firdata/scom_util.c427
-rw-r--r--src/occ_405/firdata/scom_util.h49
-rw-r--r--src/occ_405/firdata/sfc_ast2400.c728
-rw-r--r--src/occ_405/firdata/sfc_ast2400.h298
25 files changed, 4729 insertions, 0 deletions
diff --git a/src/occ_405/firdata/ecc.c b/src/occ_405/firdata/ecc.c
new file mode 100644
index 0000000..6696678
--- /dev/null
+++ b/src/occ_405/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_405/firdata/ecc.h b/src/occ_405/firdata/ecc.h
new file mode 100644
index 0000000..12ffe4e
--- /dev/null
+++ b/src/occ_405/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_405/firdata/firData.c b/src/occ_405/firdata/firData.c
new file mode 100644
index 0000000..b446e4a
--- /dev/null
+++ b/src/occ_405/firdata/firData.c
@@ -0,0 +1,756 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/firData.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 <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[MAX_TRGTS]; /*/< Pointers to the register lists */
+
+} FirData_t;
+
+/*------------------------------------------------------------------------------ */
+
+/** @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);
+
+ 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.
+ * @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 )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->counts[t][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 )
+ {
+ *o_noAttn = true; /* Assume no attentions. */
+ 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 ) *o_noAttn = 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.
+ * @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 )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->counts[t][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;
+ }
+ }
+
+ 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.
+ * @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 )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->counts[t][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;
+ }
+
+ 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.
+ * @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 )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->counts[t][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;
+ }
+ }
+
+ 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.
+ * @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 )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->counts[t][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;
+ }
+
+ 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.
+ * @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 )
+{
+ 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 (GLBL, FIR, REG) before all */
+ /* indirect-SCOM registers. Also, must check 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 );
+ if ( full || *o_noAttn ) break;
+
+ /* Add the FIRs. */
+ full = FirData_addFirsToPnor( io_fd, pTrgt, i_sTrgt );
+ if ( full ) break;
+
+ /* Add the REGs. */
+ full = FirData_addRegsToPnor( io_fd, pTrgt, i_sTrgt );
+ if ( full ) break;
+
+ /* Add the IDFIRs. */
+ full = FirData_addIdFirsToPnor( io_fd, pTrgt, i_sTrgt );
+ if ( full ) break;
+
+ /* Add the IDREGs. */
+ full = FirData_addIdRegsToPnor( io_fd, pTrgt, i_sTrgt );
+ 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 mu = 0;
+ uint8_t i = 0;
+ uint8_t j = 0;
+
+ bool isM = false;
+ uint32_t fsi = 0;
+
+ SCOM_Trgt_t sTrgt;
+
+ do
+ {
+ /* Iterate all PROCs. */
+ for ( p = 0; p < MAX_PROC_PER_NODE; p++ )
+ {
+ /* Check if the PROC is configured. */
+ if ( 0 == (io_fd->hData->procMask & (0x80 >> p)) ) continue;
+
+ /* Check if this PROC is the master PROC and get the FSI base addr. */
+ isM = ( p == io_fd->hData->masterProc );
+ fsi = io_fd->hData->procFsiBaseAddr[p];
+
+ /* Add this PROC to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(PROC, p, 0, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the PROC, EXs, and MCSs */
+
+ for ( u = 0; u < MAX_EX_PER_PROC; u++ )
+ {
+ /* Check if the EX is configured. */
+ if ( 0 == (io_fd->hData->exMasks[p] & (0x8000 >> u)) ) continue;
+
+ /* Add this EX to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(EX, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the EX */
+ }
+ if ( full ) break;
+
+ for ( u = 0; u < MAX_MCS_PER_PROC; u++ )
+ {
+ /* Check if the MCS is configured. */
+ if ( 0 == (io_fd->hData->mcsMasks[p] & (0x80 >> u)) ) continue;
+
+ /* Add this MCS to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(MCS, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the MCS */
+ }
+ if ( full ) break;
+ }
+ if ( full ) break;
+
+ /* Iterate all MEMBs. Must do this separate of from the PROCs because */
+ /* it is possible a MEMB could be reporting an attention but the */
+ /* connected PROC is not. */
+ for ( i = 0; i < MAX_MEMB_PER_NODE; i++ )
+ {
+ p = i / MAX_MEMB_PER_PROC;
+ u = i % MAX_MEMB_PER_PROC;
+
+ /* Check if the MEMB is configured. */
+ if ( 0 == (io_fd->hData->membMasks[p] & (0x80 >> u)) ) continue;
+
+ /* Get the FSI base address. */
+ fsi = io_fd->hData->membFsiBaseAddr[p][u];
+
+ /* Add this MEMB to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(MEMB, p, u, fsi, false);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the MEMB and MBAs */
+
+ for ( j = 0; j < MAX_MBA_PER_MEMB; j++ )
+ {
+ mu = u * MAX_MBA_PER_MEMB + j;
+
+ /* Check if the MBA is configured. */
+ if ( 0 == (io_fd->hData->mbaMasks[p] & (0x8000 >> mu)) )
+ continue;
+
+ /* Add this MBA to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(MBA, p, mu, fsi, false);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the MEMB */
+ }
+ if ( full ) break;
+ }
+ if ( full ) break;
+
+ } while (0);
+
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @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[MAX_TRGTS][MAX_REGS];
+ size_t curIdx = 0;
+
+ uint32_t t = FIRST_TRGT;
+
+ 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_FIR1 != 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;
+ }
+
+ /* Get the register list byte indexes in HOMER data buffer */
+ memset( x, 0x00, sizeof(x) );
+ for ( t = FIRST_TRGT; t < MAX_TRGTS; t++ )
+ {
+ x[t][GLBL] = curIdx;
+ x[t][FIR] = x[t][GLBL] + sz_u32 * io_fd->hData->counts[t][GLBL];
+ x[t][REG] = x[t][FIR] + sz_u32 * io_fd->hData->counts[t][FIR];
+ x[t][IDFIR] = x[t][REG] + sz_u32 * io_fd->hData->counts[t][REG];
+ x[t][IDREG] = x[t][IDFIR] + sz_u64 * io_fd->hData->counts[t][IDFIR];
+ curIdx = x[t][IDREG] + sz_u64 * io_fd->hData->counts[t][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, get the pointers for each list. */
+ reglist = io_fd->hBuf + sz_hData;
+ for ( t = FIRST_TRGT; t < MAX_TRGTS; t++ )
+ {
+ (io_fd->hPtrs[t]).glbl = (uint32_t *)(reglist + x[t][GLBL] );
+ (io_fd->hPtrs[t]).fir = (uint32_t *)(reglist + x[t][FIR] );
+ (io_fd->hPtrs[t]).reg = (uint32_t *)(reglist + x[t][REG] );
+ (io_fd->hPtrs[t]).idFir = (uint64_t *)(reglist + x[t][IDFIR]);
+ (io_fd->hPtrs[t]).idReg = (uint64_t *)(reglist + x[t][IDREG]);
+ }
+
+ } 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_FIR1 != 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 the buffer to PNOR. */
+ 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_405/firdata/firData.h b/src/occ_405/firdata/firData.h
new file mode 100644
index 0000000..f1475db
--- /dev/null
+++ b/src/occ_405/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_405/firdata/firDataConst_common.h b/src/occ_405/firdata/firDataConst_common.h
new file mode 100644
index 0000000..17952df
--- /dev/null
+++ b/src/occ_405/firdata/firDataConst_common.h
@@ -0,0 +1,76 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/occ_const.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 __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. */
+typedef enum
+{
+ /* NOTE: These will be used as array indexes. */
+ FIRST_TRGT = 0,
+ PROC = FIRST_TRGT,
+ EX,
+ MCS,
+ MEMB,
+ MBA,
+ MAX_TRGTS,
+
+} TrgtType_t;
+
+/** Boundary/position ranges for each target type. */
+typedef enum
+{
+ MAX_PROC_PER_NODE = 8,
+ MAX_EX_PER_PROC = 16,
+ MAX_MCS_PER_PROC = 8,
+ MAX_MEMB_PER_PROC = MAX_MCS_PER_PROC,
+ MAX_MEMB_PER_NODE = MAX_MEMB_PER_PROC * MAX_PROC_PER_NODE,
+ MAX_MBA_PER_MEMB = 2,
+ MAX_MBA_PER_PROC = MAX_MEMB_PER_PROC * MAX_MBA_PER_MEMB,
+
+} TrgtPos_t;
+
+/** All register types. */
+typedef enum
+{
+ /* NOTE: These will be used as array indexes. */
+ FIRST_REG = 0,
+ GLBL = FIRST_REG,
+ FIR,
+ REG,
+ IDFIR,
+ IDREG,
+ MAX_REGS,
+
+} RegType_t;
+
+#endif /* __firDataConst_common_h */
diff --git a/src/occ_405/firdata/fir_data_collect.c b/src/occ_405/firdata/fir_data_collect.c
new file mode 100644
index 0000000..1930fa5
--- /dev/null
+++ b/src/occ_405/firdata/fir_data_collect.c
@@ -0,0 +1,163 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/fir_data_collect.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 <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>
+
+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 = FIR_PARMS_SECTION_BASE_ADDRESS;
+ uint32_t l_hBufSize = HOMER_FIR_PARM_SIZE;
+ // PNOR working buffer in SRAM and size
+ uint8_t *l_pBuf = 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
+ */
+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;
+}
+
+
diff --git a/src/occ_405/firdata/fir_data_collect.h b/src/occ_405/firdata/fir_data_collect.h
new file mode 100644
index 0000000..c313956
--- /dev/null
+++ b/src/occ_405/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_405/firdata/fsi.c b/src/occ_405/firdata/fsi.c
new file mode 100644
index 0000000..4bf105a
--- /dev/null
+++ b/src/occ_405/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_405/firdata/fsi.h b/src/occ_405/firdata/fsi.h
new file mode 100644
index 0000000..870e47f
--- /dev/null
+++ b/src/occ_405/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_405/firdata/homerData_common.h b/src/occ_405/firdata/homerData_common.h
new file mode 100644
index 0000000..9dfa579
--- /dev/null
+++ b/src/occ_405/firdata/homerData_common.h
@@ -0,0 +1,172 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/homerData.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 __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 has all of the information characterizing what
+ * hardware is configured and how many addresses are in each register
+ * list. See the struct definition below.
+ *
+ * - Rgister 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::counts. All lists for each target type will
+ * be stored in the following order:
+ * - PROC lists
+ * - EX lists
+ * - MCS lists
+ * - MEMB lists
+ * - MBA lists
+ * Each target type will have a set of lists that will be stored in the
+ * following order:
+ * - Global FIRs 32-bit addresses
+ * - FIRs 32-bit addresses
+ * - Registers 32-bit addresses
+ * - Indirect-SCOM FIRs 64-bit addresses
+ * - Indirect-SCOM registers 64-bit addresses
+ *
+ * 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) */
+
+} HOMER_Version_t;
+
+/** PNOR information contained within the HOMER data. */
+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. */
+typedef struct __attribute__((packed))
+{
+ uint32_t header; /*/< Magic number to indicate valid data and version */
+
+ uint16_t reserved;
+
+ uint8_t masterProc; /*/< The position of the master PROC */
+
+ /** Bitwise mask to indicate which PROCs are configured (max 8). The mask
+ * bit position is consistant with PROC ATTR_POSITION attribute. */
+ uint8_t procMask;
+
+ /** Bitwise masks to indicate which EXs are configured (16 per PROC). The
+ * array index is the associated PROC position. The mask bit position is
+ * consistant with the EX's ATTR_CHIP_UNIT attribute. */
+ uint16_t exMasks[MAX_PROC_PER_NODE];
+
+ /** Bitwise masks to indicate which MCSs are configured (8 per PROC). The
+ * array index is the associated PROC position. The mask bit position is
+ * consistant with the MCS's ATTR_CHIP_UNIT attribute. */
+ uint8_t mcsMasks[MAX_PROC_PER_NODE];
+
+ /** Bitwise masks to indicate which MEMBs are configured (8 per PROC). The
+ * array index is the associated PROC position. The mask bit position is
+ * consistant with the ATTR_CHIP_UNIT attribute of the connected MCS. */
+ uint8_t membMasks[MAX_PROC_PER_NODE];
+
+ /** Bitwise masks to indicate which MBAs are configured (16 per PROC). The
+ * array index is the associated PROC position. The mask bit position is
+ * calculated as:
+ * (MEMB position * MAX_MBA_PER_MEMB) + MBA's ATTR_CHIP_UNIT attribute
+ */
+ uint16_t mbaMasks[MAX_PROC_PER_NODE];
+
+ /** Contains number of registers per type for each target type. */
+ uint8_t counts[MAX_TRGTS][MAX_REGS];
+
+ /** FSI base address for each PROC chip. */
+ uint32_t procFsiBaseAddr[MAX_PROC_PER_NODE];
+
+ /** FSI base address for each MEMB chip. */
+ uint32_t membFsiBaseAddr[MAX_PROC_PER_NODE][MAX_MEMB_PER_PROC];
+
+ /** Information regarding the PNOR location and size. */
+ HOMER_PnorInfo_t pnorInfo;
+
+} HOMER_Data_t;
+
+/** @return An initialized HOMER_Data_t struct. */
+static inline HOMER_Data_t HOMER_getData()
+{
+ HOMER_PnorInfo_t p;
+ HOMER_Data_t d;
+
+ p.pnorOffset = 0;
+ p.pnorSize = 0;
+ p.mmioOffset = 0;
+ p.norWorkarounds = 0;
+
+ d.header = HOMER_FIR1;
+ d.reserved = 0;
+ d.masterProc = 0;
+ d.procMask = 0;
+ d.pnorInfo = p;
+
+ memset( d.exMasks, 0x00, sizeof(d.exMasks) );
+ memset( d.mcsMasks, 0x00, sizeof(d.mcsMasks) );
+ memset( d.membMasks, 0x00, sizeof(d.membMasks) );
+ memset( d.mbaMasks, 0x00, sizeof(d.mbaMasks) );
+ memset( d.counts, 0x00, sizeof(d.counts) );
+ memset( d.procFsiBaseAddr, 0xff, sizeof(d.procFsiBaseAddr) );
+ memset( d.membFsiBaseAddr, 0xff, sizeof(d.membFsiBaseAddr) );
+
+ return d;
+}
+
+#endif /* __homerData_common_h */
diff --git a/src/occ_405/firdata/lpc.c b/src/occ_405/firdata/lpc.c
new file mode 100644
index 0000000..fe69efc
--- /dev/null
+++ b/src/occ_405/firdata/lpc.c
@@ -0,0 +1,302 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/lpc.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 <native.h>
+#include <lpc.h>
+#include <trac_interface.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 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: 41-43 56 (52cmd complete) (not 57: only non-fw use) */
+#define ECCB_STAT_REG_ERROR_MASK 0x0000000000700080 /**< Error Bits */
+
+/**< 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 ECCB_POLL_TIME_NS 400000 /**< max time should be 400ms */
+//dc99 #define ECCB_POLL_INCR_NS 10 /**< minimum increment during poll */
+#define ECCB_POLL_INCR_NS 100000 /**< increase for testing */
+
+#define LPCHC_SYNC_CYCLE_COUNTER_INFINITE 0xFF000000
+
+int TRACE_LPC = 0;
+#define TRACZCOMP(args...) if(TRACE_LPC){TRACFCOMP(args);}
+
+/* Set to enable LPC tracing. */
+/* #define LPC_TRACING 1 */
+#ifdef LPC_TRACING
+#define LPC_TRACFCOMP(des,printf_string,args...) \
+ TRACFCOMP(des,printf_string,##args) /* FIX FIRDATA */
+#else
+#define LPC_TRACFCOMP(args...)
+#endif
+
+/**
+ * @brief ECCB Control Register Layout
+ */
+typedef union
+{
+ uint64_t data64;
+ struct
+ {
+ /* unused sections should be set to zero */
+ uint64_t magic1 : 4; /**< 0:3 = b1101 per spec */
+ uint64_t data_len : 4; /**< 4:7 = b0100 means 4 byte */
+ uint64_t unused1 : 7; /**< 8:14 */
+ uint64_t read_op : 1; /**< 15 = set for read operation */
+ uint64_t unused2 : 7; /**< 16:22 */
+ uint64_t addr_len : 3; /**< 23:25 = b100 means 4 byte */
+ uint64_t unused3 : 6; /**< 26:31 */
+ uint64_t address : 32; /**< 32:63 = LPC Address */
+ };
+} ControlReg_t;
+
+/**
+ * @brief ECCB Status Register Layout
+ */
+typedef union
+{
+ uint64_t data64;
+ struct
+ {
+ uint64_t unused : 6; /**< 0:5 */
+ uint64_t read_data : 32; /**< 6:37 */
+ uint64_t unused1 : 3; /**< 38:40 */
+ uint64_t eccb_err : 3; /**< 41:43 = ECCB_Error_Info */
+ uint64_t busy : 1; /**< 44 = Operation Busy */
+ uint64_t unused2 : 7; /**< 45:51 */
+ uint64_t op_done : 1; /**< 52 = Command Complete */
+ uint64_t unused3 : 3; /**< 53:55 */
+ uint64_t addr_parity_err : 1; /**< 56 = ECC Address Register
+ Parity Error */
+ uint64_t unused4 : 7; /**< 57:63 */
+ };
+} 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(const ControlReg_t* i_ctrl,
+ StatusReg_t* o_stat)
+{
+ errorHndl_t l_err = NO_ERROR;
+
+ do {
+ uint64_t poll_time = 0;
+ uint64_t loop = 0;
+ do
+ {
+ xscom_read( ECCB_STAT_REG, &(o_stat->data64) );
+ LPC_TRACFCOMP( "writeLPC> Poll on ECCB Status, "
+ "poll_time=0x%.16x, stat=0x%.16x",
+ poll_time,
+ o_stat->data64 );
+ 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( ECCB_POLL_INCR_NS*(++loop) );
+ poll_time += ECCB_POLL_INCR_NS * loop;
+ } while ( poll_time < ECCB_POLL_TIME_NS );
+
+ /* Check for hw errors or timeout if no previous logs */
+ if( (l_err == NO_ERROR) &&
+ ((o_stat->data64 & ECCB_STAT_REG_ERROR_MASK)
+ || (!o_stat->op_done)) )
+ {
+ TRACFCOMP( "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;
+ uint32_t l_addr = 0;
+
+ 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 );
+
+ /* Execute command. */
+ ControlReg_t eccb_cmd;
+ eccb_cmd.data64 = ECCB_CTL_REG_DEFAULT;
+ eccb_cmd.data_len = i_size;
+ eccb_cmd.read_op = 1;
+ eccb_cmd.addr_len = sizeof(l_addr);
+ eccb_cmd.address = l_addr;
+ xscom_write( ECCB_CTL_REG, eccb_cmd.data64 );
+
+ /* Poll for completion */
+ StatusReg_t eccb_stat;
+ l_err = pollComplete( &eccb_cmd, &eccb_stat );
+ if( l_err ) { break; }
+
+ /* Copy data out to caller's buffer. */
+ if( i_size <= sizeof(uint32_t) )
+ {
+ uint32_t tmpbuf = eccb_stat.read_data;
+ memcpy( o_data, &tmpbuf, i_size );
+ }
+ else
+ {
+ TRACFCOMP( "readLPC> Unsupported buffer size : %d", i_size );
+ l_err = -1;
+ break;
+ }
+
+ } while(0);
+
+ LPC_TRACFCOMP( "readLPC> %08X[%d] = %08X", l_addr, i_size, *reinterpret_cast<uint32_t*>( o_data ) >> (8 * (4 - i_size)) );
+
+ return l_err;
+}
+
+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;
+
+ do {
+ /* Generate the full absolute LPC address */
+ l_addr = checkAddr( i_type, i_addr );
+
+ uint64_t eccb_data = 0;
+ /* Left-justify user data into data register. */
+ switch ( i_size )
+ {
+ case 1:
+ eccb_data = (uint64_t)
+ (*(const uint8_t*)(i_data)) << 56;
+ break;
+ case 2:
+ eccb_data = (uint64_t)
+ (*(const uint16_t*)( i_data ) ) << 48;
+ break;
+ case 4:
+ eccb_data = (uint64_t)
+ (*(const uint32_t*)( i_data ) ) << 32;
+ break;
+ default:
+ TRACFCOMP( "writeLPC> Unsupported buffer size : %d", i_size );
+ break;
+ }
+
+ /* Write data out */
+ TRACZCOMP("ECCB_DATA_REG=%.8X%.8X",(uint32_t)(eccb_data>>32),(uint32_t)eccb_data);
+ xscom_write( ECCB_DATA_REG, eccb_data );
+
+ /* Execute command. */
+ ControlReg_t eccb_cmd;
+ eccb_cmd.data64 = ECCB_CTL_REG_DEFAULT;
+ eccb_cmd.data_len = i_size;
+ eccb_cmd.read_op = 0;
+ eccb_cmd.addr_len = sizeof(l_addr);
+ eccb_cmd.address = l_addr;
+ xscom_write( ECCB_CTL_REG, eccb_cmd.data64 );
+ TRACZCOMP("ECCB_CTL_REG=%.8X%.8X",(uint32_t)(eccb_cmd.data64>>32),(uint32_t)eccb_cmd.data64);
+
+ /* Poll for completion */
+ StatusReg_t eccb_stat;
+ l_err = pollComplete( &eccb_cmd, &eccb_stat );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ return l_err;
+}
diff --git a/src/occ_405/firdata/lpc.h b/src/occ_405/firdata/lpc.h
new file mode 100644
index 0000000..11290cc
--- /dev/null
+++ b/src/occ_405/firdata/lpc.h
@@ -0,0 +1,51 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/lpc.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 _LPC_H
+#define _LPC_H
+
+#include <native.h>
+#include <errl.h>
+
+/**
+ * @enum LPC::TransType
+ * @brief LPC Transaction Types
+ */
+typedef enum {
+ LPC_TRANS_IO = 1, /* LPC IO Space */
+ LPC_TRANS_FW = 2, /* 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 );
+
+#endif
diff --git a/src/occ_405/firdata/native.c b/src/occ_405/firdata/native.c
new file mode 100644
index 0000000..10ec524
--- /dev/null
+++ b/src/occ_405/firdata/native.c
@@ -0,0 +1,76 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/native.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 <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_405/firdata/native.h b/src/occ_405/firdata/native.h
new file mode 100644
index 0000000..242c5e3
--- /dev/null
+++ b/src/occ_405/firdata/native.h
@@ -0,0 +1,99 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/native.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 */
+
+/* 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_trac_inf,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 */
+#define PAGE_SIZE PAGESIZE
+
+#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_405/firdata/nor_micron.c b/src/occ_405/firdata/nor_micron.c
new file mode 100644
index 0000000..3d0329a
--- /dev/null
+++ b/src/occ_405/firdata/nor_micron.c
@@ -0,0 +1,73 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/nor_micron.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 "norflash.h"
+#include "sfc_ast2400.h"
+#include <native.h>
+
+
+
+
+/**
+ * @brief Check flag status bit on Micron NOR chips
+ * Some versions of Micron parts require the Flag
+ * Status register be read after a write or erase operation,
+ * otherwise all future operations won't work..
+ */
+errorHndl_t micronFlagStatus( Sfc_t* i_sfc )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACDCOMP( g_trac_pnor, "micronFlagStatus>" ); */
+
+ do {
+ /*Read Micron 'flag status' register */
+ uint8_t flagstat = 0;
+ l_err = sendSpiCmd( i_sfc,
+ SPI_MICRON_FLAG_STAT,
+ NO_ADDRESS,
+ 0, NULL,
+ sizeof(flagstat), &flagstat );
+ if(l_err) { break; }
+
+ /*TRACDCOMP(g_trac_pnor, */
+ /* "micronFlagStatus> (0x%.2X)", */
+ /* flagstat); */
+
+ /* check for ready and no errors */
+ /* bit 0 = ready, bit 2=erase fail, bit 3=Program (Write) failure */
+ if( (flagstat & 0xB0) != 0x80)
+ {
+ /*TRACFCOMP(g_trac_pnor, "micronFlagStatus> Error or timeout from Micron Flag Status Register (0x%.2X)", flagstat); */
+ l_err = -1;
+ break;
+ }
+
+
+ }while(0);
+
+ return l_err;
+
+}
+
diff --git a/src/occ_405/firdata/norflash.h b/src/occ_405/firdata/norflash.h
new file mode 100644
index 0000000..d41c878
--- /dev/null
+++ b/src/occ_405/firdata/norflash.h
@@ -0,0 +1,154 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/norflash.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_NORFLASH_H
+#define __PNOR_NORFLASH_H
+
+#include <native.h>
+#include <sfc_ast2400.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_sfc SFC driver to operate on
+ *
+ * @return Error from operation
+ */
+errorHndl_t micronFlagStatus( Sfc_t* i_sfc );
+
+
+
+
+#endif
diff --git a/src/occ_405/firdata/pnorData_common.h b/src/occ_405/firdata/pnorData_common.h
new file mode 100644
index 0000000..d73f937
--- /dev/null
+++ b/src/occ_405/firdata/pnorData_common.h
@@ -0,0 +1,153 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/pnorData.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 __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>
+
+/** 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).
+ *
+ * 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 targets using the following rules:
+ * - For a PROC, skip this PROC and all associated EXs, and MCSs.
+ * - For an EX, skip this EX.
+ * - For an MCS, skip this MCS.
+ * - For a MEMB, skip this MEMB and all associated MBAs.
+ * - For an MBA, skip this MBA.
+ * - 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) */
+
+} PNOR_Version_t;
+
+/** PNOR data header information. */
+typedef struct __attribute__((packed))
+{
+ uint32_t header; /*/< Magic number to indicate valid data and version */
+
+ uint32_t trgts : 8; /*/< Number of targets with register data */
+ uint32_t full : 1; /*/< 1 if PNOR data is full and data may be missing */
+ uint32_t reserved : 23;
+
+} PNOR_Data_t;
+
+/** @return An initialized PNOR_Data_t struct. */
+static inline PNOR_Data_t PNOR_getData()
+{
+ PNOR_Data_t d;
+ d.header = PNOR_FIR1;
+ d.trgts = 0;
+ d.full = 0;
+ d.reserved = 0;
+
+ 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 = 511, /* Should be plenty */
+
+} PNOR_Trgt_RegLimits_t;
+
+/** Information for each target with SCOM data. */
+typedef struct __attribute__((packed))
+{
+ uint32_t type : 3; /*/< Target type. See enum TrgtType_t */
+ uint32_t procPos : 3; /*/< The processor position (0-7) */
+ uint32_t unitPos : 4; /*/< Unit position relative to the processor (0-15) */
+ uint32_t regs : 9; /*/< Number of normal registers */
+ uint32_t idRegs : 4; /*/< Number of indirect-SCOM registers */
+ uint32_t scomErrs : 9; /*/< Number of SCOM errors detected */
+
+} PNOR_Trgt_t;
+
+/** @param i_type Target type. See enum TrgtType_t.
+ * @param i_procPos The processor position.
+ * @param i_procUnitPos Unit position relative to the processor.
+ * @return An initialized PNOR_Data_t struct.
+ */
+static inline PNOR_Trgt_t PNOR_getTrgt( uint32_t i_type, uint32_t i_procPos,
+ uint32_t i_procUnitPos )
+{
+ PNOR_Trgt_t t;
+ t.type = i_type;
+ t.procPos = i_procPos;
+ t.unitPos = i_procUnitPos;
+ t.regs = 0;
+ t.idRegs = 0;
+ t.scomErrs = 0;
+
+ return t;
+};
+
+/** Information for a normal register. */
+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. */
+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_405/firdata/pnor_util.c b/src/occ_405/firdata/pnor_util.c
new file mode 100644
index 0000000..bf32480
--- /dev/null
+++ b/src/occ_405/firdata/pnor_util.c
@@ -0,0 +1,236 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/pnor_util.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 */
+
+/* Interfaces to write into PNOR */
+
+#include <native.h>
+#include <sfc_ast2400.h>
+#include <ecc.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 SFC object */
+Sfc_t g_sfc;
+/* 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;
+ }
+
+ /* 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;
+ 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]), 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_sfc,
+ 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;
+
+ /* 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;
+
+ g_sfc.iv_mmioOffset = i_pnorInfo->mmioOffset;
+ g_sfc.iv_flashWorkarounds = i_pnorInfo->norWorkarounds;
+
+ /* 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_sfc);
+ if( l_err )
+ {
+ TRACFCOMP("hwInit failed");
+ /* hit an error, stop any writes from happening */
+ g_next_byte = 0xFFFFFFFF;
+ g_pnor_size = 0;
+ }
+
+ /* Future Improvement
+ Enable write mode once at the beginning to avoid extra
+ reg operations turning it on and off
+ l_err = enableWriteMode(g_sfc);
+ if( l_err )
+ {
+ 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;
+
+ /* Erase the section. */
+ for( idx = i_pnorInfo.pnorOffset;
+ idx < (i_pnorInfo.pnorOffset+i_pnorInfo.pnorSize);
+ idx += 4096 )
+ {
+ l_err = eraseFlash(&g_sfc,idx);
+ if( l_err )
+ {
+ TRACFCOMP("eraseFlash failed");
+ rc = FAIL;
+ break; /*nothing more to do here*/
+ }
+ }
+
+ 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_405/firdata/pnor_util.h b/src/occ_405/firdata/pnor_util.h
new file mode 100644
index 0000000..d8b5518
--- /dev/null
+++ b/src/occ_405/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_405/firdata/scom_trgt.c b/src/occ_405/firdata/scom_trgt.c
new file mode 100644
index 0000000..ec38122
--- /dev/null
+++ b/src/occ_405/firdata/scom_trgt.c
@@ -0,0 +1,135 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/scoms.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 <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 ( PROC == trgt.type ) trgt.procUnitPos = 0;
+
+ if ( MEMB == trgt.type || 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 PROC:
+ case EX:
+ case MCS:
+ p = i_trgt.procPos;
+ break;
+
+ case MEMB:
+ p = (i_trgt.procPos * MAX_MEMB_PER_PROC) + i_trgt.procUnitPos;
+ break;
+
+ case MBA:
+ p = (i_trgt.procPos * MAX_MEMB_PER_PROC) +
+ (i_trgt.procUnitPos / MAX_MBA_PER_MEMB);
+ break;
+
+ default: ;
+ }
+
+ return p;
+}
+
+/*------------------------------------------------------------------------------ */
+
+uint8_t SCOM_Trgt_getChipUnitPos( SCOM_Trgt_t i_trgt )
+{
+ uint32_t u = 0;
+
+ switch ( i_trgt.type )
+ {
+ case PROC:
+ case MEMB: u = 0; break;
+
+ case EX:
+ case MCS: u = i_trgt.procUnitPos; break;
+
+ case MBA: u = i_trgt.procUnitPos % MAX_MBA_PER_MEMB; break;
+
+ default: ;
+ }
+
+ return u;
+}
+
+/*------------------------------------------------------------------------------ */
+
+SCOM_Trgt_t SCOM_Trgt_getParentChip( SCOM_Trgt_t i_trgt )
+{
+ TrgtType_t t = MAX_TRGTS;
+ switch ( i_trgt.type )
+ {
+ case PROC:
+ case EX:
+ case MCS: t = PROC; break;
+
+ case MEMB:
+ case MBA: t = MEMB; break;
+
+ default: ;
+ }
+
+ uint8_t u = 0;
+ switch ( i_trgt.type )
+ {
+ case PROC:
+ case EX:
+ case MCS:
+ case MEMB: u = i_trgt.procUnitPos; break;
+
+ case MBA: u = i_trgt.procUnitPos / MAX_MBA_PER_MEMB; break;
+
+ default: ;
+ }
+
+ return SCOM_Trgt_getTrgt( t, i_trgt.procPos, u, i_trgt.fsiBaseAddr,
+ i_trgt.isMaster );
+}
+
diff --git a/src/occ_405/firdata/scom_trgt.h b/src/occ_405/firdata/scom_trgt.h
new file mode 100644
index 0000000..4ffe8b5
--- /dev/null
+++ b/src/occ_405/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_405/firdata/scom_util.c b/src/occ_405/firdata/scom_util.c
new file mode 100644
index 0000000..4f6a391
--- /dev/null
+++ b/src/occ_405/firdata/scom_util.c
@@ -0,0 +1,427 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/scom_util.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 */
+
+/* Support for SCOM operations */
+#include <scom_util.h>
+#include <fsi.h>
+#include <native.h>
+
+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;
+
+ TrgtType_t l_type = i_trgt.type;
+
+ *o_addr = i_addr;
+
+ /* No translation needed for non-unit scoms */
+ if( (l_type == PROC) || (l_type == MEMB) )
+ {
+ *o_addr = i_addr;
+ }
+ else /* it is a Unit */
+ {
+ uint8_t l_num = SCOM_Trgt_getChipUnitPos(i_trgt);
+
+ if( l_type == EX )
+ {
+ /*first byte is 0x10, second nibble of that byte is the EX number */
+ *o_addr |= (l_num << 24);
+ }
+ else if( l_type == MCS )
+ {
+ /*Non-DMI address */
+ if( (i_addr & MCS_MASK) == MCS_BASEADDR )
+ {
+ /* MC0 MCS0 = 0x02011800 MCS-0 range 0 */
+ /* MC0 MCS1 = 0x02011880 MCS-1 range 0 + remainder */
+ /* MC1 MCS0 = 0x02011900 MCS-2 range 1 */
+ /* MC1 MCS0 = 0x02011980 MCS-3 range 1 + remainder */
+ /* MC2 MCS0 = 0x02011C00 MCS-4 range 2 */
+ /* MC2 MCS1 = 0x02011C80 MCS-5 range 2 + remainder */
+ /* MC3 MCS0 = 0x02011D00 MCS-6 range 3 */
+ /* MC3 MCS1 = 0x02011D80 MCS-7 range 3 + remainder */
+ if( (l_num / 2) == 1) /*range 1 */
+ {
+ *o_addr |= 0x100;
+ }
+ else if( (l_num / 2) == 2) /*range 2 */
+ {
+ *o_addr |= 0x400;
+ }
+ else if( (l_num / 2) == 3) /*range 3 */
+ {
+ *o_addr |= 0x500;
+ }
+
+ /* Add 0x80 for the odd numbers */
+ if( l_num % 2)
+ {
+ *o_addr |= 0x80;
+ }
+ }
+ else if( (i_addr & MCS_MASK) == MCS_DMI_BASEADDR )
+ {
+ /* 0x00000000_02011A00 MCS 0-3 # MCS/DMI0 Direct SCOM */
+ /* 0x00000000_02011E00 MCS 4-7 # MCS/DMI4 Direct SCOM */
+ if( l_num > 3 )
+ {
+ *o_addr |= 0x400; /* A00->E00 */
+ }
+ }
+ else if( (i_addr & MCS_MASK) == IND_MCS_DMI_BASEADDR )
+ {
+ /* 0x80000060_02011A3F MCS 0 # DMI0 Indirect SCOM RX3 */
+ /* 0x80000040_02011A3F MCS 1 # DMI1 Indirect SCOM RX2 */
+ /* 0x80000000_02011A3F MCS 2 # DMI3 Indirect SCOM RX0 */
+ /* 0x80000020_02011A3F MCS 3 # DMI2 Indirect SCOM RX1 */
+
+ /* 0x80000060_02011E3F MCS 4 # DMI4 Indirect SCOM RX3 */
+ /* 0x80000040_02011E3F MCS 5 # DMI5 Indirect SCOM RX2 */
+ /* 0x80000000_02011E3F MCS 6 # DMI7 Indirect SCOM RX0 */
+ /* 0x80000020_02011E3F MCS 7 # DMI6 Indirect SCOM RX1 */
+
+ /* 0x80000460_02011A3F MCS 0 # DMI0 Indirect SCOM TX3 */
+ /* 0x80000440_02011A3F MCS 1 # DMI1 Indirect SCOM TX2 */
+ /* 0x80000400_02011A3F MCS 2 # DMI3 Indirect SCOM TX0 */
+ /* 0x80000420_02011A3F MCS 3 # DMI2 Indirect SCOM TX1 */
+
+ /* 0x80000460_02011E3F MCS 4 # DMI4 Indirect SCOM TX3 */
+ /* 0x80000440_02011E3F MCS 5 # DMI5 Indirect SCOM TX2 */
+ /* 0x80000400_02011E3F MCS 6 # DMI7 Indirect SCOM TX0 */
+ /* 0x80000420_02011E3F MCS 7 # DMI6 Indirect SCOM TX1 */
+
+ /* zero out the instance bits */
+ *o_addr &= 0xFFFFFF9FFFFFFFFF;
+ switch( l_num )
+ {
+ case(0):
+ case(4):
+ *o_addr |= 0x0000006000000000;
+ break;
+ case(1):
+ case(5):
+ *o_addr |= 0x0000004000000000;
+ break;
+ case(2):
+ case(6):
+ /*nothing to do */
+ break;
+ case(3):
+ case(7):
+ *o_addr |= 0x0000002000000000;
+ break;
+ default:
+ TRAC_ERR(FUNC"unsupported MCS unit position %d", l_num);
+ rc = FAIL;
+ }
+ if( l_num > 3 )
+ {
+ *o_addr |= 0x400; /* A00->E00 */
+ }
+ }
+ }
+ else if( l_type == MBA )
+ {
+ if( (i_addr & MBA_MASK) == MBA_BASEADDR )
+ {
+ /* 0x00000000_03010400 MBA 0 # MBA01 */
+ /* 0x00000000_03010C00 MBA 1 # MBA23 */
+ if( l_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_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_num == 1 )
+ {
+ /* 030114zz->030118zz */
+ *o_addr &= 0xFFFFFFFFFFFFFBFF;
+ *o_addr |= 0x0000000000000800;
+ }
+ }
+ }
+ else
+ {
+ TRAC_ERR( FUNC"unsupported unit type %d", l_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 rc = SUCCESS;
+
+ *o_val = 0;
+
+ /* SCOMs to the master chip are done via XSCOM. */
+ if ( i_chip.isMaster )
+ {
+ return xscom_read( i_addr, o_val );
+ }
+
+ /* 1) Sent the command to do the SCOM read. */
+ rc = putfsi( i_chip, COMMAND_REG, i_addr );
+ if ( SUCCESS != rc ) return rc;
+
+ /* 2) Check status next -- TODO */
+
+ /* 3) Read the two data registers. */
+ uint32_t data0, data1;
+
+ rc = getfsi( i_chip, DATA0_REG, &data0 );
+ if ( SUCCESS != rc ) return rc;
+
+ rc = getfsi( i_chip, DATA1_REG, &data1 );
+ if ( SUCCESS != rc ) return rc;
+
+ *o_val = ((uint64_t)data0 << 32) | (uint64_t)data1;
+
+ return 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 rc = SUCCESS;
+
+ /* SCOMs to the master chip are done via XSCOM. */
+ if ( i_chip.isMaster )
+ {
+ return xscom_write( i_addr, i_val );
+ }
+
+ /* 1) Write the two data registers. */
+ rc = putfsi( i_chip, DATA0_REG, i_val >> 32 );
+ if ( SUCCESS != rc ) return rc;
+
+ rc = putfsi( i_chip, DATA1_REG, (uint32_t)i_val );
+ if ( SUCCESS != rc ) return rc;
+
+ /* 2) Send the command to do the SCOM write. */
+ rc = putfsi( i_chip, COMMAND_REG, i_addr | 0x80000000 );
+ if ( SUCCESS != rc ) return rc;
+
+ /* 3) Check status next -- TODO */
+
+ return 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
+}
diff --git a/src/occ_405/firdata/scom_util.h b/src/occ_405/firdata/scom_util.h
new file mode 100644
index 0000000..039ac64
--- /dev/null
+++ b/src/occ_405/firdata/scom_util.h
@@ -0,0 +1,49 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/scom_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 */
+
+/* Interfaces to read SCOM registers */
+
+/*#include <stdint.h> */
+#include <native.h>
+#include <scom_trgt.h>
+
+#define SCOMFAIL 0xDEADBEEF
+
+/** @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 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 );
+
diff --git a/src/occ_405/firdata/sfc_ast2400.c b/src/occ_405/firdata/sfc_ast2400.c
new file mode 100644
index 0000000..fbdb0b3
--- /dev/null
+++ b/src/occ_405/firdata/sfc_ast2400.c
@@ -0,0 +1,728 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/sfc_ast2400.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 */
+
+/*****************************************************************************/
+/* I n c l u d e s */
+/*****************************************************************************/
+#include <native.h>
+#include <norflash.h>
+/*#include <string.h> */
+#include <sfc_ast2400.h>
+#include <lpc.h>
+extern int TRACE_LPC;
+int TRACE_SFC = 0;
+
+/*****************************************************************************/
+/* C o n s t a n t s */
+/*****************************************************************************/
+
+
+
+
+/*****************************************************************************/
+/* G l o b a l s */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* M e t h o d s */
+/*****************************************************************************/
+
+/**
+ * @brief Read data from the flash
+ */
+errorHndl_t readFlash( Sfc_t* i_sfc,
+ uint32_t i_addr,
+ size_t i_size,
+ void* o_data )
+{
+ /*TRACDCOMP( ENTER_MRK"readFlash> i_addr=0x%.8x, i_size=0x%.8x", i_addr, i_size ); */
+ errorHndl_t l_err = 0;
+
+ do{
+ uint32_t* word_ptr = (uint32_t*)(o_data);
+ uint32_t word_size = (ALIGN_4(i_size))/4;
+ uint32_t words_read = 0;
+ for( words_read = 0;
+ words_read < word_size;
+ words_read ++ )
+ {
+ /*Read directly from MMIO space */
+ uint32_t lpc_addr = i_sfc->iv_mmioOffset | (i_addr + words_read*4);
+ size_t reg_size = sizeof(uint32_t);
+ l_err = lpc_read( LPC_TRANS_FW,
+ lpc_addr,
+ (uint8_t*)&(word_ptr[words_read]),
+ reg_size );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+ }while(0);
+
+ /*TRACDCOMP( EXIT_MRK"readFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+
+/**
+ * @brief Write data into flash
+ */
+errorHndl_t writeFlash( Sfc_t* i_sfc,
+ uint32_t i_addr,
+ size_t i_size,
+ void* i_data )
+{
+ TRACFCOMP( "writeFlash> i_addr=0x%.8x, i_size=0x%.8x", i_addr, i_size );
+ errorHndl_t l_err = 0;
+ size_t l_bytes_left = i_size;
+ size_t l_bytes_to_write = 0;
+ uint32_t l_addr_to_write = i_addr;
+ uint8_t* l_dataptr = (uint8_t*)(i_data);
+
+ do {
+ /* Enable write mode */
+ l_err = enableWriteMode(i_sfc);
+ if( l_err ) { break; }
+
+ /* Page Program (PP) command only supports 256 bytes at a time */
+ if( l_bytes_left <= PAGE_PROGRAM_BYTES )
+ {
+ l_bytes_to_write = l_bytes_left;
+ l_bytes_left = 0;
+ }
+ else
+ {
+ l_bytes_to_write = PAGE_PROGRAM_BYTES;
+ l_bytes_left -= PAGE_PROGRAM_BYTES;
+ }
+
+ /* Send in the Page Program command with the data to write */
+ uint8_t opcode = SPI_JEDEC_PAGE_PROGRAM;
+ l_err = sendSpiCmd( i_sfc, opcode, l_addr_to_write,
+ l_bytes_to_write,
+ l_dataptr,
+ 0, NULL );
+ if( l_err ) { break; }
+
+ /* Move to the next chunk */
+ l_addr_to_write += l_bytes_to_write;
+ l_dataptr += l_bytes_to_write;
+
+ /* Wait for idle */
+ l_err = pollOpComplete(i_sfc);
+ if( l_err ) { break; }
+
+ /*check for special Micron Flag Status reg */
+ if(i_sfc->iv_flashWorkarounds & HWWK_MICRON_WRT_ERASE)
+ {
+ l_err = micronFlagStatus(i_sfc);
+ if(l_err) { break; }
+ }
+
+ } while(l_bytes_left);
+
+ /*TRACDCOMP( EXIT_MRK"writeFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Erase a block of flash
+ */
+errorHndl_t eraseFlash( Sfc_t* i_sfc,
+ uint32_t i_addr )
+{
+ TRACFCOMP(">>eraseFlash> Block 0x%.8X", i_addr );
+ errorHndl_t l_err = 0;
+
+ do {
+ // Enable write mode
+ l_err = enableWriteMode(i_sfc);
+ if( l_err ) { break; }
+
+ // Send erase command
+ uint8_t opcode = SPI_JEDEC_SECTOR_ERASE;
+ l_err = sendSpiCmd( i_sfc, opcode, i_addr, 0, 0, 0, NULL );
+ if( l_err ) { break; }
+
+ // Wait for idle
+ l_err = pollOpComplete(i_sfc);
+ if( l_err ) { break; }
+
+ //check for special Micron Flag Status reg
+ if(i_sfc->iv_flashWorkarounds & HWWK_MICRON_WRT_ERASE)
+ {
+ l_err = micronFlagStatus(i_sfc);
+ if(l_err) { break; }
+ }
+ } while(0);
+
+ return l_err;
+}
+
+
+/**
+ * @brief Initialize and configure the SFC hardware
+ */
+errorHndl_t hwInit( Sfc_t* i_sfc )
+{
+ TRACFCOMP( ENTER_MRK"hwInit>" );
+ errorHndl_t l_err = NO_ERROR;
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ /*** Initialize the LPC2AHB logic */
+
+ /* Send SuperIO password - send A5 twice */
+ uint8_t data = 0xA5;
+ l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_2E,
+ &data, reg_size );
+ if( l_err ) { break; }
+
+ l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_2E,
+ &data, reg_size );
+ if( l_err ) { break; }
+
+
+ /* Select logical device D (iLPC2AHB) */
+ l_err = writeRegSIO( i_sfc, 0x07, 0x0D );
+ if( l_err ) { break; }
+
+
+ /* Enable iLPC->AHB */
+ l_err = writeRegSIO( i_sfc, 0x30, 0x01 );
+ if( l_err ) { break; }
+
+
+ /*** Setup the SPI Controller */
+
+ /* Enable writing to the controller */
+ SpiControlReg04_t ctlreg;
+ l_err = readRegSPIC( i_sfc, CTLREG_04, &ctlreg.data32 );
+ if( l_err ) { break; }
+ TRACFCOMP("dc99> First read of CTLREG_04=%.8X", ctlreg.data32);
+ ctlreg.cmdMode = 2;/*0b10; //10:Normal Write (CMD + Address + Write data) */
+ l_err = writeRegSPIC( i_sfc, CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+
+ SpiConfigReg00_t confreg;
+ l_err = readRegSPIC( i_sfc, CONFREG_00, &confreg.data32 );
+ if( l_err ) { break; }
+ confreg.inactiveX2mode = 1; /*Enable CE# Inactive pulse width X2 mode */
+ confreg.enableWrite = 1; /*Enable flash memory write */
+ l_err = writeRegSPIC( i_sfc, CONFREG_00, confreg.data32 );
+ if( l_err ) { break; }
+
+
+ /*
+ * Setup control reg and for our use, switching
+ * to 1-bit mode, clearing user mode if set, etc...
+ *
+ * Also configure SPI clock to something safe
+ * like HCLK/8 (24Mhz)
+ */
+ ctlreg.fourByteMode = 1;
+ ctlreg.ioMode = 0;/*0b00; //single bit or controlled by bit[3] */
+ ctlreg.pulseWidth = 0x0; /*0000: 16T (1T = 1 HCLK clock) */
+ ctlreg.cmdData = 0x00;
+ ctlreg.spiClkFreq = 0x4; /*HCLK/8 */
+ ctlreg.dummyCycleRead1 = 0; /*no dummy cycles */
+ ctlreg.dummyCycleRead2 = 0;/*0b00; //no dummy cycles */
+ ctlreg.cmdMode = 0;/*0b00; //00:Normal Read (03h + Address + Read data) */
+ i_sfc->iv_ctlRegDefault = ctlreg; /* Default setup is regular read mode */
+
+ /* Configure for read */
+ l_err = writeRegSPIC( i_sfc, CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+
+ /* Setup flash-specific settings here, if there are any */
+
+ } while(0);
+
+ TRACFCOMP( "hwInit> err=%.8X", l_err );
+ return l_err;
+}
+
+/**
+ * @brief Send a SPI command
+ */
+errorHndl_t sendSpiCmd( Sfc_t* i_sfc,
+ uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData )
+{
+ errorHndl_t l_err = NO_ERROR;
+ size_t opsize = 0;
+ if(TRACE_SFC){
+ TRACFCOMP( ENTER_MRK"sendSpiCmd> i_opCode=%.2X, i_address=%.8X, i_writeCnt=0x%X, i_writeData=%p", i_opCode, i_address, i_writeCnt, i_writeData );
+ TRACFCOMP( " , i_readCnt=0x%X, o_readData=%p", i_readCnt, o_readData );
+ }
+
+ do {
+ /*Do a read of flash address zero to workaround */
+ /* a micron bug with extended reads */
+ if( (HWWK_MICRON_EXT_READ & i_sfc->iv_flashWorkarounds)
+ && (i_readCnt > 4) )
+ {
+ uint32_t ignored = 0;
+ l_err = readFlash( i_sfc, 0, 1, &ignored );
+ if(l_err) { break; }
+ }
+
+ /* Put controller into command mode (instead of read mode) */
+ l_err = commandMode( i_sfc, true );
+ if( l_err ) { break; }
+
+ /* Write command to the beginning of the flash space */
+ opsize = sizeof(i_opCode);
+ l_err = lpc_write( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ &i_opCode,
+ opsize ); /*just send opcode */
+ if( l_err ) { break; }
+
+ /* Send address if there is one */
+ if( i_address != NO_ADDRESS )
+ {
+ /* Write address to the beginning of the flash space */
+ opsize = sizeof(i_address);
+ l_err = lpc_write( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ (uint8_t*)&i_address,
+ opsize ); /*only supporting 4-byte addresses */
+ if( l_err ) { break; }
+ }
+
+ /* Send in the rest of the write data */
+ if( i_writeCnt && i_writeData )
+ {
+ size_t bytes_left = i_writeCnt;
+ uint8_t* curptr = (uint8_t*)(i_writeData);
+ while( bytes_left )
+ {
+ /* Write the last partial word if there is one */
+ if( bytes_left < 4 )
+ {
+ opsize = bytes_left;
+ l_err = lpc_write( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ curptr,
+ opsize );
+ break;
+ }
+
+ /* Write data into the beginning of the flash space, */
+ /* in command mode this doesn't write the flash */
+ /* but instead is a pass-through to the area we */
+ /* really want to write */
+ opsize = sizeof(uint32_t);
+ l_err = lpc_write( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ curptr,
+ opsize );
+ if( l_err ) { break; }
+
+ curptr += 4;
+ bytes_left -= 4;
+ }
+ if( l_err ) { break; }
+ }
+
+ /* Read back the results */
+ if( i_readCnt && o_readData )
+ {
+ size_t bytes_left = i_readCnt;
+ uint8_t* curptr = o_readData;
+ while( bytes_left )
+ {
+ /* Grab the last partial word if there is one */
+ if( bytes_left < 4 )
+ {
+ opsize = bytes_left;
+ l_err = lpc_read( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ curptr,
+ opsize );
+ break;
+ }
+
+ /* Read data from the beginning of the flash space, */
+ /* in command mode this doesn't read the flash */
+ /* but instead is a pass-through to the data we */
+ /* really want */
+ opsize = sizeof(uint32_t);
+ l_err = lpc_read( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ curptr,
+ opsize );
+ if( l_err ) { break; }
+
+ curptr += 4;
+ bytes_left -= 4;
+ }
+ if( l_err ) { break; }
+ }
+ } while(0);
+
+
+ /* No matter what, put the logic back into read mode */
+ int tmp_err = commandMode( i_sfc, false );
+ if( tmp_err )
+ {
+ if( !l_err )
+ {
+ l_err = tmp_err;
+ }
+ }
+
+ /*TRACDCOMP( EXIT_MRK"sendSpiCmd> o_readData=%.2X, err=%.8X", o_readData == NULL ? 0 : o_readData[0], ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Enter/exit command mode
+ */
+errorHndl_t commandMode( Sfc_t* i_sfc,
+ bool i_enter )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACDCOMP( ENTER_MRK"commandMode(%d)", i_enter ); */
+
+ /*
+ * There is only a limited addressable window within LPC space. The AST
+ * has its control register space at too far of a distance from the read
+ * space for them both to fit in a single window. Rather than moving the
+ * window around we will use the iLPC2AHB backdoor inside the SuperIO
+ * controller to do both register accesses and to write into the flash.
+ *
+ * High level flow to write into control space:
+ * Stop active control (SPI04 Control Reg)
+ * Enable command mode (SPI04 Control Reg)
+ * Write actual command into flash base addr (0x0E000000)
+ */
+
+ do {
+ SpiControlReg04_t ctlreg = i_sfc->iv_ctlRegDefault;
+
+ /* Switch to user mode, CE# dropped */
+ ctlreg.stopActiveCtl = 1;
+ ctlreg.cmdMode = 3;/*0b11; //User Mode (Read/Write Data) */
+ l_err = writeRegSPIC( i_sfc, CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+
+ if( i_enter ) /*ast_sf_start_cmd */
+ {
+ /* user mode, CE# active */
+ ctlreg.stopActiveCtl = 0;
+ l_err = writeRegSPIC( i_sfc, CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+ }
+ else /*ast_sf_end_cmd */
+ {
+ /* Switch back to read mode */
+ l_err = writeRegSPIC( i_sfc, CTLREG_04, i_sfc->iv_ctlRegDefault.data32 );
+ if( l_err ) { break; }
+ }
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"commandMode> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Enable write mode
+ */
+errorHndl_t enableWriteMode( Sfc_t* i_sfc )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACDCOMP( ENTER_MRK"enableWriteMode>" ); */
+
+ /* Some flashes need it to be hammered */
+ NorStatusReg_t status;
+// status.data8 = 0x55;
+ size_t i = 0;
+ for( i = 0; i < 10; i++ )
+ {
+ /* Send the command to enable writes */
+ uint8_t opcode = SPI_JEDEC_WRITE_ENABLE;
+ l_err = sendSpiCmd( i_sfc, opcode, NO_ADDRESS, 0, NULL, 0, NULL );
+ if( l_err ) { break; }
+
+ /* Check to see if it worked */
+ opcode = SPI_JEDEC_READ_STATUS;
+ l_err = sendSpiCmd( i_sfc, opcode, NO_ADDRESS, 0, NULL, 1, &(status.data8) );
+ if( l_err ) { break; }
+ TRACDCOMP( "SPI_JEDEC_READ_STATUS=%.2X", status.data8 );
+
+ if( status.writeEnable )
+ {
+ break;
+ }
+ }
+
+ if( !l_err && !status.writeEnable )
+ {
+ TRACFCOMP( "Could not enable writes" );
+ l_err = -1;
+ }
+
+ /*TRACDCOMP( EXIT_MRK"enableWriteMode> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Write a single byte into the SIO
+ */
+errorHndl_t writeRegSIO( Sfc_t* i_sfc,
+ uint8_t i_regAddr,
+ uint8_t i_data )
+{ /*lpc_sio_outb */
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACFCOMP( "writeRegSIO> i_regAddr=0x%.2X, i_data=0x%.2X", i_regAddr, i_data );*/
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ /* AST2400 integrates a Super I/O module with */
+ /* LPC protocol (I/O cycle 0x2E/0x2F) */
+
+ /* Write out the register address */
+ l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_2E,
+ &i_regAddr,
+ reg_size );
+ if( l_err ) { break; }
+
+ /* Write out the register data */
+ l_err = lpc_write( LPC_TRANS_IO, SIO_DATA_2F,
+ &i_data,
+ reg_size );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"writeRegSIO> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Read a single byte from the SIO
+ */
+errorHndl_t readRegSIO( Sfc_t* i_sfc,
+ uint8_t i_regAddr,
+ uint8_t* o_data )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACDCOMP( ENTER_MRK"readRegSIO> i_regAddr=0x%.2X", i_regAddr ); */
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ /* AST2400 integrates a Super I/O module with */
+ /* LPC protocol (I/O cycle 0x2E/0x2F) */
+
+ /* Write out the register address */
+ l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_2E,
+ &i_regAddr,
+ reg_size );
+ if( l_err ) { break; }
+
+ /* Read in the register data */
+ l_err = lpc_read( LPC_TRANS_IO, SIO_DATA_2F,
+ o_data,
+ reg_size );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"readRegSIO> o_data=0x%.2X, err-%.8X", *o_data, ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Prepare the iLPC2AHB address regs
+ */
+errorHndl_t setupAddrLPC2AHB( Sfc_t* i_sfc,
+ uint32_t i_addr )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACDCOMP( ENTER_MRK"setupAddrLPC2AHB> i_addr=0x%X", i_addr ); */
+
+ do {
+ /* Select logical device D (iLPC2AHB) */
+ l_err = writeRegSIO( i_sfc, 0x07, 0x0D );
+ if( l_err ) { break; }
+
+ /* Push 4 address bytes into SIO regs 0xF0-0xF3 */
+ size_t i;
+ for( i=sizeof(i_addr); i>0; i-- )
+ {
+ l_err = writeRegSIO( i_sfc, 0xF3-(i-1), /*F0,F1,F2,F3 */
+ (uint8_t)(i_addr >> ((i-1)*8)) );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+
+ /* Configure 4 byte length */
+ l_err = writeRegSIO( i_sfc, 0xF8, 0x02 );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"setupAddrLPC2AHB> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Write SPI Controller Register
+ */
+errorHndl_t writeRegSPIC( Sfc_t* i_sfc,
+ SpicReg_t i_reg,
+ uint32_t i_data )
+{
+ errorHndl_t l_err = NO_ERROR;
+ //TRACFCOMP( "writeRegSPIC> i_reg=0x%.2X, i_data=0x%.8X", i_reg, i_data );
+
+ do {
+ /* Compute the full LPC address */
+ uint32_t lpc_addr = i_reg | SPIC_BASE_ADDR_AHB;
+
+ /* Setup the logic for the write */
+ l_err = setupAddrLPC2AHB( i_sfc, lpc_addr );
+ if( l_err ) { break; }
+
+ /* Push 4 data bytes into SIO regs 0xF4-0xF7 */
+ uint8_t* ptr8 = (uint8_t*)(&i_data);
+ size_t i;
+ for( i=0; i<sizeof(i_data); i++ )
+ {
+ l_err = writeRegSIO( i_sfc, 0xF4+i, /*F4,F5,F6,F7 */
+ ptr8[i] );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+
+ /* Trigger the write operation by writing the magic 0xCF value */
+ l_err = writeRegSIO( i_sfc, 0xFE, 0xCF );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"writeRegSPIC> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Read SPI Controller Register
+ */
+errorHndl_t readRegSPIC( Sfc_t* i_sfc,
+ SpicReg_t i_reg,
+ uint32_t* o_data )
+{
+ //TRACFCOMP( "readRegSPIC> i_reg=0x%.2X", i_reg );
+ errorHndl_t l_err = NO_ERROR;
+
+ do {
+ /* Compute the full LPC address */
+ uint32_t lpc_addr = i_reg | SPIC_BASE_ADDR_AHB;
+
+ /* Setup the logic for the write */
+ l_err = setupAddrLPC2AHB( i_sfc, lpc_addr );
+ if( l_err ) { break; }
+
+ /* Trigger the write operation by reading the magic register */
+ uint8_t ignored = 0;
+ l_err = readRegSIO( i_sfc, 0xFE, &ignored );
+ if( l_err ) { break; }
+
+ /* Read 4 data bytes into SIO regs 0xF4-0xF7 */
+ uint8_t* ptr8 = (uint8_t*)(o_data);
+ size_t i;
+ for( i=0; i<sizeof(*o_data); i++ )
+ {
+ l_err = readRegSIO( i_sfc, 0xF4+i, /*F4,F5,F6,F7 */
+ &(ptr8[i]) );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"readRegSPIC> o_data=0x%.8X, l_err=%.8X", *o_data, ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Poll for completion of SPI operation
+ */
+errorHndl_t pollOpComplete( Sfc_t* i_sfc )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /* TRACDCOMP( "pollOpComplete>" ); */
+int trace_lpc=TRACE_LPC; TRACE_LPC=0;
+int trace_sfc=TRACE_SFC; TRACE_SFC=0;
+
+ do {
+ /* Send RDSR command until write-in-progress clears */
+ NorStatusReg_t status;
+ uint64_t poll_time = 0;
+ uint64_t loop = 0;
+ while( poll_time < MAX_WRITE_TIME_NS )
+ {
+ uint8_t opcode = SPI_JEDEC_READ_STATUS;
+ l_err = sendSpiCmd( i_sfc, opcode,
+ NO_ADDRESS,
+ 0, NULL,
+ 1, &(status.data8) );
+ if( l_err ) { break; }
+
+ /* check if any op is still going */
+ if( !status.writeInProgress )
+ {
+ 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 */
+ ++loop;
+ sleep( 100*loop );
+ poll_time += 100*loop;
+ }
+ if( l_err ) { break; }
+
+ /*TRACDCOMP(g_trac_pnor,"pollOpComplete> command took %d ns", poll_time); */
+
+ /* No status regs to check so just look for timeout */
+ if( status.writeInProgress )
+ {
+ TRACFCOMP( "pollOpComplete> Timeout during write or erase" );
+ l_err = -1;
+ break;
+ }
+ } while(0);
+
+TRACE_LPC=trace_lpc;
+TRACE_SFC=trace_sfc;
+ /*TRACDCOMP( EXIT_MRK"pollOpComplete> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
diff --git a/src/occ_405/firdata/sfc_ast2400.h b/src/occ_405/firdata/sfc_ast2400.h
new file mode 100644
index 0000000..30a9052
--- /dev/null
+++ b/src/occ_405/firdata/sfc_ast2400.h
@@ -0,0 +1,298 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/sfc_ast2400.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_SFCAST2400_H
+#define __PNOR_SFCAST2400_H
+
+#include <native.h>
+#include <homerData_common.h>
+
+/** @file sfc_ast2400.H
+ * @brief Provides the logic to access and configure the
+ * AST2400 BMC in order to access the PNOR
+ */
+
+/**
+ * @brief SPI04 Control Register
+ */
+typedef union
+{
+ uint32_t data32;
+ struct
+ { /*Little-endian bit positions*/
+ uint32_t rsvd : 2; /*31:30*/
+ uint32_t ioMode : 2; /*29:28*/
+ uint32_t pulseWidth : 4; /*27:24*/
+ uint32_t cmdData : 8; /*23:16*/
+ uint32_t dummyCycleCmd : 1; /*15*/
+ uint32_t dummyCycleRead1 : 1; /*14*/
+ uint32_t fourByteMode : 1; /*13*/
+ uint32_t disableCmdMerge : 1; /*12*/
+ uint32_t spiClkFreq : 4; /*11:8*/
+ uint32_t dummyCycleRead2 : 2; /*7:6*/
+ uint32_t lsbFirst : 1; /*5*/
+ uint32_t useClkMode3 : 1; /*4*/
+ uint32_t dualInputMode : 1; /*3*/
+ uint32_t stopActiveCtl : 1; /*2*/
+ uint32_t cmdMode : 2; /*1:0*/
+ };
+} SpiControlReg04_t;
+
+
+/**
+ * @brief Structure to hold information about the SFC
+ */
+typedef struct
+{
+ /**
+ * @brief Default value of SPI04 (saves a read)
+ */
+ SpiControlReg04_t iv_ctlRegDefault;
+
+ /**
+ * @brief Hardware workarounds
+ */
+ uint32_t iv_flashWorkarounds;
+
+ /**
+ * @brief LPC address that marks the beginning of flash
+ */
+ uint32_t iv_mmioOffset;
+} Sfc_t;
+
+
+/**
+ * @brief Initialize the SFC Hardware
+ * @param[in] Pointer to Sfc struct
+ *
+ * @return void
+ */
+errorHndl_t hwInit(Sfc_t* i_sfc);
+
+/**
+ * @brief Read data from the PNOR flash
+ *
+ * @param[in] Pointer to Sfc 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(Sfc_t* i_sfc,
+ uint32_t i_addr,
+ size_t i_size,
+ void* o_data);
+
+/**
+ * @brief Write data to the PNOR flash
+ *
+ * @param[in] Pointer to Sfc 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(Sfc_t* i_sfc,
+ uint32_t i_addr,
+ size_t i_size,
+ void* i_data);
+
+/**
+ * @brief Erase a block of flash
+ */
+errorHndl_t eraseFlash( Sfc_t* i_sfc,
+ uint32_t i_addr );
+
+/** @brief Constant for sendSpiCmd parameter */
+static const uint32_t NO_ADDRESS = UINT32_MAX;
+
+
+/**
+ * @brief Send a SPI command
+ *
+ * @param[in] Pointer to Sfc struct
+ * @parm[in] i_opCode: command to send into controller first
+ * @parm[in] i_address: address for those commands that need it
+ * @parm[in] i_writeCnt: number of bytes to write to device
+ * @parm[in] i_writeData: write data buffer
+ * @parm[in] i_readCnt: number of bytes to read from device
+ * @parm[out] o_readData: read data buffer
+ *
+ * @return Error from operation
+ */
+errorHndl_t sendSpiCmd( Sfc_t* i_sfc,
+ uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData );
+
+/**
+ * @brief List of registers in the SPI Controller logic
+ */
+typedef enum
+{
+ CONFREG_00 = 0x00,
+ CTLREG_04 = 0x04,
+ MISCCTLREG_10 = 0x10,
+ READTIMEREG_14 = 0x14
+} SpicReg_t;
+
+/**
+ * @brief Write a SPI Controller register
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_reg: Register to write
+ * @param[in] i_data: Data to write
+ *
+ * @return Error from operation
+ */
+errorHndl_t writeRegSPIC( Sfc_t* i_sfc,
+ SpicReg_t i_reg,
+ uint32_t i_data );
+
+/**
+ * @brief Write a SPI Controller register
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_reg: Register to write
+ * @param[in] o_data: Data that was read
+ *
+ * @return Error from operation
+ */
+errorHndl_t readRegSPIC( Sfc_t* i_sfc,
+ SpicReg_t i_reg,
+ uint32_t* o_data );
+
+/**
+ * @brief Write a single byte into a SIO register
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_reg: Register to write
+ * @param[in] i_data: Data to write
+ *
+ * @return Error from operation
+ */
+errorHndl_t writeRegSIO( Sfc_t* i_sfc,
+ uint8_t i_regAddr,
+ uint8_t i_data );
+
+/**
+ * @brief Read a single byte from a SIO register
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_reg: Register to read
+ * @param[in] o_data: Data that was read
+ *
+ * @return Error from operation
+ */
+errorHndl_t readRegSIO( Sfc_t* i_sfc,
+ uint8_t i_regAddr,
+ uint8_t* o_data );
+
+/**
+ * @brief Enable write mode
+ *
+ * @param[in] Pointer to Sfc struct
+ * @return Error from operation
+ */
+errorHndl_t enableWriteMode( Sfc_t* i_sfc );
+
+/**
+ * @brief Enter/exit command mode
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_enter: true=enter cmd mode, false=exit cmd mode
+ *
+ * @return Error from operation
+ */
+errorHndl_t commandMode( Sfc_t* i_sfc,
+ bool i_enter );
+
+/**
+ * @brief Poll for completion of SPI operation
+ *
+ * @param[in] Pointer to Sfc struct
+ * @return Error from operation
+ */
+errorHndl_t pollOpComplete( Sfc_t* i_sfc );
+
+/**
+ * @brief Prepare the iLPC2AHB address regs
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_addr: LPC address to access
+ *
+ * @return Error from operation
+ */
+errorHndl_t setupAddrLPC2AHB( Sfc_t* i_sfc,
+ uint32_t i_addr );
+
+
+/**
+ * @brief SPI0 Configuration Register
+ */
+typedef union
+{
+ uint32_t data32;
+ struct
+ { /*Little-endian bit positions*/
+ uint32_t rsvd : 30; /*31:2*/
+ uint32_t inactiveX2mode : 1; /*1*/
+ uint32_t enableWrite : 1; /*0*/
+ };
+} SpiConfigReg00_t;
+
+/** @brief General Constants */
+enum
+{
+ LPC_TOP_OF_FLASH_OFFSET = 0x0FFFFFFF,
+
+ /**< Offset to SPI Controller Register Space */
+ LPC_SFC_CTLR_BASE = 0x1E789000,
+
+ /**< AHB address of SPI Flash controller */
+ SPIC_BASE_ADDR_AHB = 0x1E630000,
+
+ /**< AHB address of flash */
+ FLASH_BASE_ADDR_AHB = 0x30000000,
+
+ /**< AHB address of LPC registers */
+ LPC_CTLR_BASE_ADDR_AHB = 0x1E789000,
+
+ /**< Maximum time to wait for a write/erase */
+ MAX_WRITE_TIME_NS = NS_PER_SEC,
+
+ /**< SuperIO Address Cycle */
+ SIO_ADDR_2E = 0x2E,
+
+ /**< SuperIO Data Cycle */
+ SIO_DATA_2F = 0x2F,
+};
+
+
+#endif
OpenPOWER on IntegriCloud