summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib/spd
diff options
context:
space:
mode:
authorBrian Silver <bsilver@us.ibm.com>2015-12-28 11:26:59 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2016-04-01 21:20:07 -0400
commit2dbce731a9de46f7f30df1eaa88b0b35a7797bc6 (patch)
treef5756a02b9bc91d33589dedd18117e9190951cff /src/import/chips/p9/procedures/hwp/memory/lib/spd
parent3ab41df3a6aabf47bcae6bf5b50dca05616929d6 (diff)
downloadtalos-hostboot-2dbce731a9de46f7f30df1eaa88b0b35a7797bc6.tar.gz
talos-hostboot-2dbce731a9de46f7f30df1eaa88b0b35a7797bc6.zip
Initial commit of memory subsystem
Change-Id: Ia6375304adaa7e04dfa642e144341d7a5776673a Original-Change-Id: I6b63d2c4eec5d77585c91d905a464962a6153a0a Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/22978 Tested-by: Jenkins Server Reviewed-by: Craig C. Hamilton <cchamilt@us.ibm.com> Reviewed-by: Brian Silver <bsilver@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/22759 Tested-by: FSP CI Jenkins Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory/lib/spd')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C3548
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H424
2 files changed, 3972 insertions, 0 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C
new file mode 100644
index 000000000..d215773a0
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C
@@ -0,0 +1,3548 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file spd_decoder.C
+/// @brief SPD decoder definitions
+///
+// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#include <fapi2.H>
+#include "../mss.H"
+#include "../utils/conversions.H"
+#include "spd_decoder.H"
+
+using fapi2::TARGET_TYPE_MCBIST;
+using fapi2::TARGET_TYPE_MCA;
+using fapi2::TARGET_TYPE_MCS;
+using fapi2::TARGET_TYPE_DIMM;
+
+
+namespace mss
+{
+namespace spd
+{
+
+// Note: IBM's implementation of std::maps are not thread safe
+
+// =========================================================
+// Byte 0 maps
+// Item JC-45-2220.01x
+// Page 14
+// DDR4 SPD Document Release 3
+// Byte 0 (0x000): Number of Bytes Used / Number of Bytes in SPD Device
+
+static const uint16_t bytes_used_map[] =
+{
+ // Shifting index by 1 first since first key value is undefined
+ // Key values < 1 and > 3 aren't supported or reserved
+
+ // Undefined
+ 128,
+ 256,
+ 384,
+ 512,
+ //...
+ // All other bits reserved
+};
+
+static const uint16_t bytes_total_map[] =
+{
+ // Shifting index by 1 first since first key value is undefined
+ // Key values < 1 and > 2 aren't supported or reserved
+
+ // Undefined
+ 256,
+ 512,
+ //...
+ // All other bits reserved
+};
+
+// =========================================================
+// Byte 2 maps
+// Item JC-45-2220.01x
+// Page 16
+// DDR4 SPD Document Release 3
+// Byte 2 (0x002): Key Byte / DRAM Device Type
+
+static const uint8_t dram_gen_map[] =
+{
+ // Initial and ending index values are not supported or reserved
+ // Shifting index by 11 since initial dram gen types aren't supported (by IBM)
+ // Key values < 12 and > 13 are not supported or reserved
+
+ // Reserved
+ // Fast page mode is not supported
+ // EDO is not supported
+ // Pipelined Nibbleis not supported
+ // SDRAM
+ // ROM is not supported
+ // DDR SGRAM is not supported
+ // DDR SDRAM is not supported
+ // DDR2 SDRAM is not supported
+ // DDR2 SDRAM FB-DIMM is not supported
+ // DDR2 SDRAM FB-DIMM PROBE is not supported
+ fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR3,
+ fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4,
+ //...
+ // All other bits reserved
+};
+
+// =========================================================
+// Byte 3 maps
+// Item JC-45-2220.01x
+// Page 17
+// DDR4 SPD Document Release 3
+// Byte 3 (0x003): Key Byte / Module Type
+
+static const uint8_t base_module_type_map[] =
+{
+
+ // Initial and ending index values are not supported or reserved
+ // Index shifted by 1 since first module type isn't supported (by IBM)
+ // Key values < 1 and > 4 are not supported or reserved
+
+ // Extending DIMM not supported
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_RDIMM,
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_UDIMM,
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_SO_DIMM,
+ fapi2::ENUM_ATTR_SPD_MODULE_TYPE_LRDIMM,
+ // Mini-RDIMM not supported
+ // Mini-UDIMM not supported
+ // Reserved
+ // 72b-SO-RDIMM not supported
+ // 72b-SO-UDIMM not supported
+ // Reserved
+ // Reserved
+ // 16b-SO-DIMM
+ // 32b-SO-DIMM
+ // Reserved
+ // Reserved
+};
+
+// =========================================================
+// Byte 4 maps
+// Item JC-45-2220.01x
+// Page 18
+// DDR4 SPD Document Release 3
+// Byte 4 (0x004): SDRAM Density and Banks
+
+static const uint8_t sdram_capacity_map[] =
+{
+ // Initial and ending index values are not supported or reserved
+ // Index shifted by 2 since first module type isn't supported (by IBM)
+ // Key values < 2 and > 9 are not supported or reserved
+
+ // 256 Mbs is not supported
+ // 512 Mbs is not supported
+ // // Units (Gigabits)
+ 1, // Gb
+ 2, // Gb
+ 4, // Gb
+ 8, // Gb
+ 16, // Gb
+ 32, // Gb
+ 12, // Gb
+ 24, // Gb
+ //...
+ //All others reserved
+};
+
+static const uint8_t sdram_banks_map[] =
+{
+ // Key values > 1 are not supported or reserved
+
+ 4, // banks address bits (2 address bits)
+ 8, // banks address bits (3 address bits)
+ //...
+ // All others Reserved
+};
+
+static const uint8_t sdram_bankgroups_map[] =
+{
+ // Key values > 2 are not supported or reserved
+
+ 0, // No bank groups (0 bank group bits)
+ 2, // 2 bank groups (1 bank group bit)
+ 4, // 4 bank groups (2 bank group bits)
+ //Reserved
+};
+
+// =========================================================
+// Byte 5 maps
+// Item JC-45-2220.01x
+// Page 18
+// DDR4 SPD Document Release 3
+// Byte 5 (0x005): SDRAM Addressing
+
+static const uint8_t column_address_map[] =
+{
+ 9, // Column address bits 000
+ 10, // Column address bits 001
+ 11, // Column address bits 010
+ 12, // Column address bits 011
+ // All others reserved
+};
+
+static const uint8_t row_address_map[] =
+{
+ 12, // Row address bits 000
+ 13, // Row address bits 001
+ 14, // Row address bits 010
+ 15, // Row address bits 011
+ 16, // Row address bits 100
+ 17, // Row address bits 101
+ 18, // Row address bits 110
+ // All others reserved
+};
+
+// =========================================================
+// Byte 6 maps
+// Item JC-45-2220.01x
+// Page 19
+// DDR4 SPD Document Release 3
+// Byte 6 (0x006): Primary SDRAM Package Type
+
+static const uint8_t die_count_map[] =
+{
+ 1, // 000 = Single die
+ 2, // 001 = 2 die
+ 3, // 010 = 3 die
+ 4, // 011 = 4 die
+ 5, // 100 = 5 die
+ 6, // 101 = 6 die
+ 7, // 110 = 7 die
+ 8, // 111 = 8 die
+};
+
+static const uint8_t package_type_map[] =
+{
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_SDP,
+ uint8_t(~0),
+ uint8_t(~0),
+ uint8_t(~0),
+ uint8_t(~0),
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_DDP_QDP,
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_3DS,
+};
+
+// =========================================================
+// Byte 7 maps
+// Item JC-45-2220.01x
+// Page 20
+// DDR4 SPD Document Release 3
+// Byte 7 (0x007): SDRAM Optional Features
+
+uint16_t static const MAC_map[] =
+{
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_UNTESTED, // Untested MAC
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_700K, // 700K
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_600K, // 600K
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_500K, // 500K
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_400K, // 400K
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_300K, // 300K
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_200K, // 200K
+ uint16_t(~0), // Reserved
+ fapi2::ENUM_ATTR_EFF_DRAM_MAC_UNLIMITED,// Unlimited MAC
+ // All others reserved
+};
+
+uint16_t static const tMAW_map[] =
+{
+ 8192,
+ 4096,
+ 2048,
+};
+
+// =========================================================
+// Byte 9 maps
+// Item JC-45-2220.01x
+// Page 21
+// DDR4 SPD Document Release 3
+// Byte 9 (0x009): Other SDRAM Optional Features
+static const uint8_t ppr_map[]
+{
+ fapi2::ENUM_ATTR_EFF_DRAM_PPR_NOT_SUPPORTED,
+ fapi2::ENUM_ATTR_EFF_DRAM_PPR_SUPPORTED,
+ //...
+ // Reserved
+};
+
+static const uint8_t soft_ppr_map[]
+{
+ fapi2::ENUM_ATTR_EFF_DRAM_SOFT_PPR_NOT_SUPPORTED,
+ fapi2::ENUM_ATTR_EFF_DRAM_SOFT_PPR_SUPPORTED,
+};
+
+// =========================================================
+// Byte 6 maps
+// Item JC-45-2220.01x
+// Page 19
+// DDR4 SPD Document Release 3
+// Byte 6 (0x006): Primary SDRAM Package Type
+
+static const uint8_t sec_die_count_map[] =
+{
+ 1, // 000 = Single die
+ 2, // 001 = 2 die
+ 3, // 010 = 3 die
+ 4, // 011 = 4 die
+ 5, // 100 = 5 die
+ 6, // 101 = 6 die
+ 7, // 110 = 7 die
+ 8, // 111 = 8 die
+};
+
+static const uint8_t sec_package_type_map[] =
+{
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_SDP,
+ uint8_t(~0),
+ uint8_t(~0),
+ uint8_t(~0),
+ uint8_t(~0),
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_DDP_QDP,
+ fapi2::ENUM_ATTR_EFF_STACK_TYPE_3DS,
+};
+
+// =========================================================
+// Byte 12 maps
+// Item JC-45-2220.01x
+// Page 23
+// DDR4 SPD Document Release 3
+// Byte 12 (0x00C): Module Organization
+static const uint8_t device_type_map[] =
+{
+ // // Units
+ 4, // bits
+ 8, // bits
+ 16, // bits
+ 32, // bits
+ // All others reserved
+};
+
+static const uint8_t num_pkgs_ranks_per_dimm_map[] =
+{
+ // // Units
+ 1, // package rank
+ 2, // package ranks
+ 3, // package ranks
+ 4, // package ranks
+ 5, // package ranks
+ 6, // package ranks
+ 7, // package ranks
+ 8 // package ranks
+ // All others reserved
+};
+
+// =========================================================
+// Byte 12 maps
+// Item JC-45-2220.01x
+// Page 23
+// DDR4 SPD Document Release 3
+// Byte 13 (0x00D): Module Memory Bus Width
+static const uint8_t prim_bus_width_map[] =
+{
+ // // Units
+ 8, // bits
+ 16, // bits
+ 32, // bits
+ 64, // bits
+ // All others reserved
+};
+
+static const uint8_t bus_width_ext_map[] =
+{
+ // // Units
+ 0, // bits
+ 8, // bits
+ // All others reserved
+};
+
+// =========================================================
+// Byte 17 maps
+// Item JC-45-2220.01x
+// Page 29
+// DDR4 SPD Document Release 3
+// Byte 17 (0x011): Timebases
+
+// Created a maps of a single value in case mapping expands to more values
+static const uint8_t medium_timebase_map[] =
+{
+ // // Units
+ 125, // ps
+ // All others reserved
+};
+
+static const uint8_t fine_timebase_map[] =
+{
+ // // Units
+ 1, // ps
+ // All others reserved
+};
+
+
+// =========================================================
+// Function implementations
+// =========================================================
+namespace check
+{
+///
+/// @brief Checks that stack type conforms to JEDEC table
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Consumed in (Byte 7) sdram_package_type(...)
+/// Item JC-45-2220.01x
+/// Page 20 (Terminology table)
+/// DDR4 SPD Document Release 3
+bool stack_type(const uint8_t i_stack_type, const uint8_t i_die_count)
+{
+ const size_t STACK_SDP = 0;
+ const size_t STACK_DDP_QDP = 5;
+ const size_t STACK_3DS = 6;
+
+ const size_t SINGLE_DIE_PACKAGE = 1;
+ const size_t DUAL_DIE_PACKAGE = 2;
+ const size_t QUAD_DIE_PACKAGE = 4;
+
+ const size_t TWO_SDRAM_DIE = 2;
+ const size_t EIGHT_SDRAM_DIE = 8;
+
+ // Use const or enums
+ switch(i_stack_type)
+ {
+ case STACK_SDP:
+ //SDP has single die
+ return i_die_count == SINGLE_DIE_PACKAGE;
+ break;
+
+ case STACK_DDP_QDP:
+ //DDP has 2 die, QDP has 4 die
+ return (i_die_count == DUAL_DIE_PACKAGE) || (i_die_count == QUAD_DIE_PACKAGE);
+ break;
+
+ case STACK_3DS:
+ //3DS has 2 - 8 dies
+ return (i_die_count >= TWO_SDRAM_DIE) && (i_die_count <= EIGHT_SDRAM_DIE);
+ break;
+
+ default:
+ return false; // Doesn't meet JEDEC spec
+ }
+}// stack_type()
+
+} // check namespace
+
+///
+/// @brief Calculates timing value
+/// @param[in] const int64_t& i_spd_timing_mtb,
+/// const int64_t& i_spd_timing_ftb,
+/// const int64_t& multiplier_mtb,
+/// const int64_t& multiplier_ftb
+/// @return int64_t, (timing value)
+inline int64_t calc_timing(const int64_t& i_spd_timing_mtb,
+ const int64_t& i_spd_timing_ftb,
+ const int64_t& multiplier_mtb,
+ const int64_t& multiplier_ftb)
+{
+ int64_t timing_val = i_spd_timing_mtb * multiplier_mtb;
+ int64_t offset = (i_spd_timing_ftb * multiplier_ftb);
+ int64_t remainder_val = timing_val % multiplier_mtb;
+
+ if( remainder_val == 0)
+ {
+ // If the timing value can be expressed as an integer number
+ // of MTB units, return that
+ return timing_val;
+ }
+ else
+ {
+ // Else round up and incorporate correction factor
+ return (++timing_val) + offset;
+ }
+}
+
+///
+/// @brief Decodes SPD number of bytes
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// size_t i_read_spd_size
+/// @return fapi2::ReturnCode
+/// @note Decodes SPD Byte 0
+///
+fapi2::ReturnCode decoder::number_of_bytes(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data,
+ const size_t i_read_spd_size)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 0;
+
+ // SPD Bytes used mapping limits
+ const size_t BYTES_USED_MAP_OFFSET = 1;
+ const size_t BYTES_USED_MIN_VALID_KEY = 1; // All previous keys are not supported or reserved
+ const size_t BYTES_USED_MAX_VALID_KEY = 4; // The rest are not supported or reserved
+
+ // Total SPD bytes mapping limits
+ const size_t BYTES_TOTAL_MAP_OFFSET = 1;
+ const size_t BYTES_TOTAL_MIN_VALID_KEY = 1; // All previous keys are not supported or reserved
+ const size_t BYTES_TOTAL_MAX_VALID_KEY = 2; // The rest are not supported or reserved
+
+ // Byte variables used for decoding
+ uint8_t l_spd_bytes_used = 0;
+ uint8_t l_spd_bytes_total = 0;
+ uint8_t l_reserved = 0;
+ uint16_t l_total_bytes_map_val = 0;
+ uint16_t l_used_bytes_map_val = 0;
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte 0: 0x%llX.",
+ mss::c_str(i_target_dimm),
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding 1st nibble, bits 3~0 (SPD Bytes Used)
+ l_spd_buffer.extractToRight<BYTES_USED_START, BYTES_USED_LEN>(l_spd_bytes_used);
+
+ // Check to assure SPD Bytes Used (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_spd_bytes_used >= BYTES_USED_MIN_VALID_KEY) &&
+ (l_spd_bytes_used <= BYTES_USED_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_spd_bytes_used,
+ "Failed check on Used SPD bytes") );
+
+ // Decoding bits 6~4 (SPD Bytes Total)
+ l_spd_buffer.extractToRight<BYTES_TOTAL_START, BYTES_TOTAL_LEN>(l_spd_bytes_total);
+
+ // Check to assure SPD Bytes Total (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_spd_bytes_total >= BYTES_TOTAL_MIN_VALID_KEY) &&
+ (l_spd_bytes_total <= BYTES_TOTAL_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_spd_bytes_total,
+ "Failed check on total SPD bytes" ) );
+
+ // Decoding bit 7 (Reserved bit)
+ l_spd_buffer.extractToRight<BYTES_RESERVED_START, BYTES_RESERVED_LEN>(l_reserved);
+
+ // Hold map values in temp variables
+ l_used_bytes_map_val = bytes_used_map[l_spd_bytes_used - BYTES_USED_MAP_OFFSET];
+ l_total_bytes_map_val = bytes_total_map[l_spd_bytes_total - BYTES_TOTAL_MAP_OFFSET];
+
+ // Size of input SPD read should match size it claims to be based on the SPD spec
+ // "Used SPD bytes" wasn't used since manufacturers may not use all available bytes
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_total_bytes_map_val == i_read_spd_size,
+ BYTE_INDEX,
+ l_total_bytes_map_val,
+ "Failed SPD size check") );
+
+ FAPI_INF("%s. Bytes Used: %d, Total Bytes: %d, Reserved : %d",
+ mss::c_str(i_target_dimm),
+ l_used_bytes_map_val,
+ l_total_bytes_map_val,
+ l_reserved);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decodes SPD Revision
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @param[in, out] uint8_t io_revision_num
+/// @return fapi2::ReturnCode
+/// @note Decodes SPD Byte 1
+///
+fapi2::ReturnCode decoder::revision(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 1;
+ const size_t UNDEFINED = 0xFF; // per JEDEC spec
+
+ // Byte variables used for decoding
+ uint8_t l_revision_num = 0;
+
+ // Verify SPD revision is not undefined. Value is defined by the JEDEC spec
+ l_revision_num = i_spd_data[BYTE_INDEX];
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_revision_num != UNDEFINED),
+ BYTE_INDEX,
+ l_revision_num,
+ "Failed check on SPD revision") );
+ // Print decoded info
+ FAPI_INF("%s. SPD data at Byte %d: 0x%llX, Revision number : %d",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX],
+ l_revision_num);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decodes DRAM Device Type
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Decodes SPD Byte 2
+///
+fapi2::ReturnCode decoder::dram_device_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 2;
+
+ // dram generation mapping limits
+ const size_t MIN_VALID_KEY = 12; // All previous keys are not supported or reserved
+ const size_t MAX_VALID_KEY = 13; // The rest are not supported or reserved
+ const size_t MAP_OFFSET = 11; // SPD DRAM device type map has an index offset of 11 (simplifies array)
+ // //since initial map values are not supported or reserved (ignored for now)
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_device_type = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_device_gen[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Check to assure SPD DRAM device type (map) wont be at invalid values
+ l_device_type = i_spd_data[BYTE_INDEX];
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_device_type >= MIN_VALID_KEY) &&
+ (l_device_type <= MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_device_type,
+ "Unsupported/reserved key value retried from SPD") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(eff_dram_gen(l_target_mcs, &l_device_gen[0][0]));
+
+ // Update attribute to decoded byte values
+ l_device_gen[PORT_NUM][DIMM_NUM] = dram_gen_map[l_device_type - MAP_OFFSET];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_GEN, l_target_mcs, l_device_gen));
+
+ // Print decoded info
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX. Device type : %d",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX],
+ l_device_gen[PORT_NUM][DIMM_NUM]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+
+}
+
+///
+/// @brief Decodes SPD module type
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Decodes SPD Byte 3
+///
+fapi2::ReturnCode decoder::module_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 3;
+
+ // Base module mapping limits // since first index is not supported
+ const size_t BASE_MODULE_MAP_OFFSET = 1; // base_module_type_map has an index offset of 1
+ const size_t MIN_VALID_KEY = 1; // All previous keys are not supported or reserved
+ const size_t MAX_VALID_KEY = 4; // The rest are not supported or reserved
+
+ // Hybrid Media limit
+ const size_t MAX_HYBRID_MEDIA_KEY = 1; // All other key values reserved
+
+ // Hybrid
+ const size_t MAX_HYBRID_KEY = 1; // Nothing else exits afterwards
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_base_module_type = 0;
+ uint8_t l_hybrid_media = 0;
+ uint8_t l_hybrid = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_module_type[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace in the front assists w/ debug
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 3~0
+ l_spd_buffer.extractToRight<BASE_MODULE_START, BASE_MODULE_LEN>(l_base_module_type);
+
+ // Check to assure SPD DRAM base module type (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_base_module_type >= MIN_VALID_KEY) &&
+ (l_base_module_type <= MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_base_module_type,
+ "Failed check for SPD DRAM base module type") );
+
+ // Decoding bits 6~4
+ l_spd_buffer.extractToRight<HYBRID_MEDIA_START, HYBRID_MEDIA_LEN>(l_hybrid_media);
+
+ // Check to assure SPD DRAM hybrid media is valid
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_hybrid_media <= MAX_HYBRID_MEDIA_KEY,
+ BYTE_INDEX,
+ l_hybrid_media,
+ "Failed check for SPD DRAM hybrid media") );
+
+ // Decoding bit 7
+ l_spd_buffer.extractToRight<HYBRID_START, HYBRID_LEN>(l_hybrid);
+
+
+ // Check to assure SPD DRAM hybrid media is valid
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_hybrid_media <= MAX_HYBRID_KEY,
+ BYTE_INDEX,
+ l_hybrid,
+ "Failed check for SPD DRAM hybrid media") );
+ // Retrive entire MCS level attribute
+ FAPI_TRY(spd_module_type(l_target_mcs, &l_module_type[0][0]));
+
+ // Update attribute to decoded byte values
+ l_module_type[PORT_NUM][DIMM_NUM] = base_module_type_map[l_base_module_type - BASE_MODULE_MAP_OFFSET];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_TYPE, l_target_mcs, l_module_type));
+
+ FAPI_INF("%s. Base Module Type: %d, Hybrid Media: %d, Hybrid: %d",
+ c_str(i_target_dimm),
+ l_module_type[PORT_NUM][DIMM_NUM],
+ l_hybrid_media,
+ l_hybrid);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode SDRAM density
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 4
+///
+fapi2::ReturnCode decoder::sdram_density(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 4;
+
+ // DRAM capacity mapping limits
+ const size_t CAPACITY_MAP_OFFSET = 1; // base_module_type_map has an index offset of 1
+ const size_t CAPACITY_MIN_VALID_KEY = 2; // All previous keys are not supported or reserved
+ const size_t CAPACITY_MAX_VALID_KEY = 9; // The rest are not supported or reserved
+
+ // DRAM banks mapping limits
+ const size_t BANKS_MAX_VALID_KEY = 1; // The rest are not supported or reserved
+
+ // DRAM bank groups mapping limits
+ const size_t BANK_GRP_MAX_VALID_KEY = 2; // The rest are not supported or reserved
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_sdram_capacity = 0;
+ uint8_t l_sdram_banks = 0;
+ uint8_t l_sdram_bank_group = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_capacities[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_banks[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_bank_groups[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace in the front assists w/ debug
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 3~0
+ l_spd_buffer.extractToRight<SDRAM_CAPACITY_START, SDRAM_CAPACITY_LEN>(l_sdram_capacity);
+
+ // Check to assure SPD DRAM capacity (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sdram_capacity >= CAPACITY_MIN_VALID_KEY) &&
+ (l_sdram_capacity <= CAPACITY_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_sdram_capacity,
+ "Failed check for SPD DRAM capacity") );
+ // Decoding bits 5~4
+ l_spd_buffer.extractToRight<SDRAM_BANKS_START, SDRAM_BANKS_LEN>(l_sdram_banks);
+
+ // Check to assure SPD DRAM banks (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sdram_banks <= BANKS_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_sdram_banks,
+ "Failed check for SPD DRAM banks") );
+
+ // Decoding bits 7~6
+ l_spd_buffer.extractToRight<BANK_GROUP_START, BANK_GROUP_LEN>(l_sdram_bank_group);
+
+ // Check to assure SPD DRAM banks groups (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sdram_bank_group <= BANK_GRP_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_sdram_bank_group,
+ "Failed check for SPD DRAM bank groups") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_density(l_target_mcs, &l_capacities[0][0]) );
+ FAPI_TRY( eff_dram_banks(l_target_mcs, &l_banks[0][0]) );
+ FAPI_TRY( eff_dram_bank_groups(l_target_mcs, &l_bank_groups[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_capacities[PORT_NUM][DIMM_NUM] = sdram_capacity_map[l_sdram_capacity - CAPACITY_MAP_OFFSET];
+ l_banks[PORT_NUM][DIMM_NUM] = sdram_banks_map[l_sdram_banks];
+ l_bank_groups[PORT_NUM][DIMM_NUM] = sdram_bankgroups_map[l_sdram_bank_group];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_DENSITY, l_target_mcs, l_capacities));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_BANKS, l_target_mcs, l_banks));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_BANK_GROUPS, l_target_mcs, l_bank_groups));
+
+ FAPI_INF("%s. SDRAM capacity: %d, banks: %d, bank groups: %d",
+ c_str(i_target_dimm),
+ sdram_capacity_map[l_sdram_capacity],
+ sdram_banks_map[l_sdram_banks],
+ sdram_bankgroups_map[l_sdram_bank_group]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode SDRAM addressing
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 5
+///
+fapi2::ReturnCode decoder::sdram_addressing(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 5;
+ // DRAM column address mapping limits
+ const size_t COLUMN_MAX_VALID_KEY = 3; // The rest are not supported or reserved
+ // DRAM row address mapping limits
+ const size_t ROW_MAX_VALID_KEY = 6; // The rest are not supported or reserved
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_column_addr = 0;
+ uint8_t l_row_addr = 0;
+ uint8_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_columns[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_rows[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace in the front assists w/ debug
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 2~0 (Column Address bits)
+ l_spd_buffer.extractToRight<COL_ADDRESS_START, COL_ADDRESS_LEN>(l_column_addr);
+
+ // Check to assure SPD DRAM Column Address bits (map) wont be indexed at invalid values
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_column_addr <= COLUMN_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_column_addr,
+ "Failed check for SPD DRAM bank groups") );
+
+ // Decoding bits 3~0 (Row address bits)
+ l_spd_buffer.extractToRight<ROW_ADDRESS_START, ROW_ADDRESS_LEN>(l_row_addr);
+
+ // Check to assure SPD DRAM Row address bits (map) wont be at invalid values
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_row_addr <= ROW_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_row_addr,
+ "Failed check for SPD DRAM bank groups") );
+
+ // Decoding bits 7~6
+ l_spd_buffer.extractToRight<ADDRESS_RESERVED_START, ADDRESS_RESERVED_LEN>(l_reserved);
+
+ // Check to assure SPD reserved bits are 0 as defined in JEDEC SPD spec
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_reserved == 0),
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for SPD DRAM bank groups") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_cols(l_target_mcs, &l_columns[0][0]) );
+ FAPI_TRY( eff_dram_rows(l_target_mcs, &l_rows[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_columns[PORT_NUM][DIMM_NUM] = column_address_map[l_column_addr];
+ l_rows[PORT_NUM][DIMM_NUM] = row_address_map[l_row_addr];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_COLS, l_target_mcs, l_columns));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_ROWS, l_target_mcs, l_rows));
+
+ FAPI_INF("%s. Columns: %d, Rows: %d",
+ c_str(i_target_dimm),
+ l_columns[PORT_NUM][DIMM_NUM],
+ l_rows[PORT_NUM][DIMM_NUM]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
+/// @brief Decode SDRAM Package Type
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 6
+///
+fapi2::ReturnCode decoder::primary_package_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 6;
+ const size_t INVALID_VALUE = 0x11; //per JEDEC spec
+ const size_t RESERVED = 0;
+
+ // DRAM die count mapping limits
+ const size_t DIE_COUNT_MAX_VALID_KEY = 7; // Nothing greater doesn't exist
+ const size_t INVALID_PACKAGE_TYPE = ~0;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_prim_signal_loading = 0;
+ uint8_t l_reserved = 0;
+ uint8_t l_prim_die_count = 0;
+ uint8_t l_prim_package_type = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_stack_type = 0;
+ uint8_t l_sdram_package_type[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_sdram_die_count[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 1~0 (Signal loading)
+ l_spd_buffer.extractToRight<PRIM_PRIM_SIGNAL_LOAD_START, PRIM_PRIM_SIGNAL_LOAD_LEN>(l_prim_signal_loading);
+
+ // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_prim_signal_loading != INVALID_VALUE),
+ BYTE_INDEX,
+ l_prim_signal_loading,
+ "Failed check for SPD DRAM signal loading") );
+ // Decoding bits 3~2 (Reserved)
+ l_spd_buffer.extractToRight<PACKAGE_RESERVE_START, PACKAGE_RESERVE_LEN>(l_reserved);
+
+ // Check to assure SPD reserved bits are 0 as defined in JEDEC SPD spec
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ (l_reserved == RESERVED),
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for SPD DRAM reserved bits");
+
+ // Decoding bits 6~4 (Die Count)
+ l_spd_buffer.extractToRight<PRIM_DIE_COUNT_START, PRIM_DIE_COUNT_LEN>(l_prim_die_count);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_prim_die_count <= DIE_COUNT_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_prim_die_count,
+ "Failed check for SPD DRAM die count") );
+ // Decoding bit 7
+ l_spd_buffer.extractToRight<PRIM_PACKAGE_TYPE_START, PRIM_PACKAGE_TYPE_LEN>(l_prim_package_type);
+
+ // Manipulating and combining l_prim_package_type and l_prim_signal_loading to produce the following
+ // table for indexing the package_type_map[].
+ // 0000 0000 = SDP (monolithic device)
+ // 0000 0101 = DDP/QDP (non-monolithic device)
+ // 0000 0110 = 3DS (non-monolithic device)
+ // What this essentially does is remove reserved bits.
+ // This was done to avoid having large gaps (of 0's) in the package_type_map (sparsed array)
+ // since we can't use std::map due to thread saftey issues
+ l_stack_type = (l_prim_package_type >> 5) | l_prim_signal_loading;
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ check::stack_type(l_stack_type, die_count_map[l_prim_die_count]) &&
+ (package_type_map[l_stack_type] != INVALID_PACKAGE_TYPE),
+ BYTE_INDEX,
+ package_type_map[l_stack_type],
+ "Failed check for SPD DRAM stack type") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_stack_type(l_target_mcs, &l_sdram_package_type[0][0]) );
+ FAPI_TRY( eff_prim_die_count(l_target_mcs, &l_sdram_die_count[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_sdram_die_count[PORT_NUM][DIMM_NUM] = die_count_map[l_prim_die_count];
+ l_sdram_package_type[PORT_NUM][DIMM_NUM] = package_type_map[l_stack_type];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_STACK_TYPE, l_target_mcs, l_sdram_package_type));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_PRIM_DIE_COUNT, l_target_mcs, l_sdram_die_count));
+
+ FAPI_INF("%s. Signal loading: %d, Die count: %d, Stack type: %d",
+ c_str(i_target_dimm),
+ l_prim_signal_loading,
+ die_count_map[l_prim_die_count],
+ l_sdram_package_type[PORT_NUM][DIMM_NUM]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+//TODO
+// Need to complete this function, map need tREF1 calculations
+
+///
+/// @brief Decode SDRAM Optional Features
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 7
+///
+fapi2::ReturnCode decoder::sdram_optional_features(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 7;
+ const size_t RESERVED = 0;
+
+ // MAC mapping limits
+ const size_t MAC_RESERVED = 7; //per JEDEC spec
+ const size_t MAC_MAX_VALID_KEY = 8;
+
+ // TMAW mappint limits
+ const size_t TMAW_MAX_VALID_KEY = 2;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint16_t l_MAC = 0; // Maximum Active Count
+ uint16_t l_tMAW = 0; // Maximum Active Window
+ uint8_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ uint16_t l_mac[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint16_t l_tmaw[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 3~0 (MAC)
+ l_spd_buffer.extractToRight<MAC_START, MAC_LEN>(l_MAC);
+ // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_MAC <= MAC_MAX_VALID_KEY) &&
+ l_MAC != MAC_RESERVED,
+ BYTE_INDEX,
+ l_MAC,
+ "Failed check for Maximum Active Count (MAC)") );
+
+ // Decoding bits 5~4 (tMAW)
+ l_spd_buffer.extractToRight<TMAW_START, TMAW_LEN>(l_tMAW);
+
+ // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tMAW <= TMAW_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_tMAW,
+ "Failed check for Maximum Active Window (tMAW)") );
+
+ // Decoding bits 7~6 (Reserved)
+ l_spd_buffer.extractToRight<OPT_FEAT_RESERVED_START, OPT_FEAT_RESERVED_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ (l_reserved == RESERVED),
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for Reserved bits") ;
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(eff_dram_mac(l_target_mcs, &l_mac[0][0]));
+ FAPI_TRY(eff_dram_tmaw(l_target_mcs, &l_tmaw[0][0]));
+
+ // Update attribute to decoded byte values
+ l_mac[PORT_NUM][DIMM_NUM] = MAC_map[l_MAC];
+ l_tmaw[PORT_NUM][DIMM_NUM] = tMAW_map[l_tMAW];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_MAC, l_target_mcs, l_mac));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TMAW, l_target_mcs, l_tmaw));
+
+ // Print decoded info
+ FAPI_INF("%s. MAC: %d, tMAW: %d",
+ c_str(i_target_dimm),
+ l_tmaw[PORT_NUM][DIMM_NUM],
+ l_mac[PORT_NUM][DIMM_NUM]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}// decode_sdram_optional_features()
+
+///
+/// @brief Decode SDRAM Thermal and Refresh Options
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 8, currently reserved
+///
+fapi2::ReturnCode decoder::thermal_and_refresh_options(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 8;
+ const size_t RESERVED_BYTE = 0; // per JEDEC spec
+
+ // Byte variable
+ uint8_t l_reserved = i_spd_data[BYTE_INDEX];
+
+ // Check to assure SPD reserved byte is 0 per JEDEC spec
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_reserved == RESERVED_BYTE),
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for SPD DRAM reserved byte") );
+
+ // Print decoded info
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}// decode_thermal_and_refresh_options()
+
+
+///
+/// @brief Decode Other SDRAM Optional Features
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 9
+///
+fapi2::ReturnCode decoder::other_optional_features(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 9;
+ const size_t RESERVED = 0;
+
+ // Soft PPR mapping limits
+ const size_t SOFT_PPR_MAX_VALID_KEY = 2; // Nothing greater doesn't exist
+
+ // PPR mapping limits
+ const size_t PPR_MAX_VALID_KEY = 2; // Nothing greater doesn't exist
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_reserved = 0;
+ uint8_t l_soft_ppr = 0;// Soft Post Package Repair
+ uint8_t l_ppr = 0; // Post Package Repair
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_soft_PPRs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_PPRs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 4~0
+ l_spd_buffer.extractToRight<PPR_RESERVED_START, PPR_RESERVED_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ (l_reserved == RESERVED),
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for reserved bits");
+
+ // Decoding bit 5
+ l_spd_buffer.extractToRight<SOFT_PPR_START, SOFT_PPR_LEN>(l_soft_ppr);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_soft_ppr < SOFT_PPR_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_soft_ppr,
+ "Failed check for SOFT PPR") );
+
+ // Decoding bits 7~6
+ l_spd_buffer.extractToRight<PPR_START, PPR_LEN>(l_ppr);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_ppr < PPR_MAX_VALID_KEY),
+ BYTE_INDEX,
+ l_ppr,
+ "Failed check for PPR") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(eff_dram_soft_ppr(l_target_mcs, &l_soft_PPRs[0][0]));
+ FAPI_TRY(eff_dram_ppr(l_target_mcs, &l_PPRs[0][0]));
+
+ // Update attribute to decoded byte values
+ l_soft_PPRs[PORT_NUM][DIMM_NUM] = soft_ppr_map[l_soft_ppr];
+ l_PPRs[PORT_NUM][DIMM_NUM] = ppr_map[l_ppr];
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_SOFT_PPR, l_target_mcs, l_soft_PPRs));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_PPR, l_target_mcs, l_PPRs));
+
+ // Printed decoded info
+ FAPI_INF("%s. Soft PPR: %d, PPR: %d, Reserved: %d",
+ c_str(i_target_dimm),
+ l_soft_PPRs[PORT_NUM][DIMM_NUM],
+ l_PPRs[PORT_NUM][DIMM_NUM],
+ l_reserved);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Secondary SDRAM Package Type
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 10
+///
+fapi2::ReturnCode decoder::secondary_package_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 10;
+ const size_t SUPPORTED_VALUE = 0;
+
+ // Byte variables used for decoding
+ uint8_t l_sec_signal_loading = 0;
+ uint8_t l_density_ratio = 0;
+ uint8_t l_sec_die_count = 0;
+ uint8_t l_sec_package_type = 0;
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Currently we do not support asymmetrical assembly of multiple SDRAM package types
+ // According to the JEDEC spec, for modules with symmetrical assembly (which we do support),
+ // this byte must be coded as 0x00. Additional checks were added to isolate any corrupt data failure
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 1~0 (Signal loading)
+ l_spd_buffer.extractToRight<SEC_SIGNAL_LOAD_START, SEC_SIGNAL_LOAD_LEN>(l_sec_signal_loading);
+
+ // Check to assure SPD DRAM signal loading conforms to JEDEC SPEC
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sec_signal_loading == SUPPORTED_VALUE),
+ BYTE_INDEX,
+ l_sec_signal_loading,
+ "Failed check for SPD DRAM signal loading") );
+
+ // Decoding bits 3~2 (Density Ratio)
+ l_spd_buffer.extractToRight<DENSITY_RATIO_START, DENSITY_RATIO_LEN>(l_density_ratio);
+
+ // Check to assure SPD density ratio bits are 0 to assure symmetical package
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_density_ratio == SUPPORTED_VALUE),
+ BYTE_INDEX,
+ l_density_ratio,
+ "Failed check for SPD DRAM density ratio") );
+
+ // Decoding bits 6~4 (Die Count)
+ l_spd_buffer.extractToRight<SEC_DIE_COUNT_START, SEC_DIE_COUNT_LEN>(l_sec_die_count);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sec_die_count == SUPPORTED_VALUE),
+ BYTE_INDEX,
+ l_sec_die_count,
+ "Failed check for SPD DRAM secondary die count") );
+
+ // Decoding bit 7
+ l_spd_buffer.extractToRight<SEC_PACKAGE_TYPE_START, SEC_PACKAGE_TYPE_LEN>(l_sec_package_type);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_sec_package_type == SUPPORTED_VALUE),
+ BYTE_INDEX,
+ l_sec_package_type,
+ "Failed check for SPD DRAM secondary package type") );
+
+ // Printed decoded info
+ FAPI_INF("Signal Loading: %d, DRAM Density Ratio: %d, Die Count: %d, SDRAM Package Type: %d",
+ l_sec_signal_loading,
+ l_density_ratio,
+ l_sec_die_count,
+ l_sec_package_type);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Module Nominal Voltage, VDD
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 11
+///
+fapi2::ReturnCode decoder::module_nominal_voltage(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 11;
+ const size_t RESERVED = 0; // per JEDEC sepc
+ const size_t SUPPORTED = 1; // per JEDEC sepc
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_operable = 0;
+ uint8_t l_endurant = 0;
+ uint8_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ uint64_t l_operable_attrs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding bits 0 (Operable)
+ l_spd_buffer.extractToRight<OPERABLE_START, OPERABLE_LEN>(l_operable);
+
+ // DDR4 only supports 1.2 V, if not OPERABLE at this voltage than fail IPL
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_operable == SUPPORTED,
+ BYTE_INDEX,
+ l_operable,
+ "Failed check for OPERABLE module nominal voltage") );
+ // Decoding bits 1 (Endurant)
+ l_spd_buffer.extractToRight<ENDURANT_START, ENDURANT_LEN>(l_endurant);
+
+ // OPERABLE at 1.2V implies ENDURANT at 1.2V
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_endurant == SUPPORTED,
+ BYTE_INDEX,
+ l_endurant,
+ "Failed check for ENDURABLE module nominal voltage") );
+
+ // Decoding bits 7~2 (Reserved)
+ l_spd_buffer.extractToRight<NOM_VOLT_START, NOM_VOLT_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for module nominal voltage RESERVED bits");
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(spd_module_nominal_voltage(l_target_mcs, &l_operable_attrs[0][0]));
+
+ // Update attribute to decoded byte values
+ l_operable_attrs[PORT_NUM][DIMM_NUM] = l_operable;
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_NOMINAL_VOLTAGE, l_target_mcs, l_operable_attrs) );
+
+ // Printed decoded info
+ FAPI_INF( "%s Operable: %d, Endurant: %d, Reserved: %d",
+ c_str(i_target_dimm),
+ l_operable,
+ l_endurant,
+ l_reserved );
+
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Module Organization
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 12
+///
+fapi2::ReturnCode decoder::module_organization(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 12;
+ const size_t RESERVED = 0;
+
+ // SDRAM device width mapping limits
+ const size_t MAX_DEV_WIDTH_VALID_KEY = 3; // All others reserved
+
+ // Number of package ranks per DIMM mapping limits
+ const size_t MAX_PKG_RANKS_VALID_KEY = 7; // max supported packages
+
+ // Rank mix limits
+ const size_t SYMMETRICAL = 0; // asymmetical not supported
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_device_width = 0;
+ uint8_t l_num_pkgs_ranks = 0;
+ uint8_t l_rank_mix = 0;
+ uint8_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_sdram_device_widths[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_num_pkg_ranks_per_dimm[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ uint8_t l_rank_mixes[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding Bits 2~0
+ l_spd_buffer.extractToRight<SDRAM_WIDTH_START, SDRAM_WIDTH_LEN>(l_device_width);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_device_width <= MAX_DEV_WIDTH_VALID_KEY,
+ BYTE_INDEX,
+ l_device_width,
+ "Failed check for SDRAM device width") );
+ // Decoding Bits 5~3
+ l_spd_buffer.extractToRight<PACKAGE_RANKS_START, PACKAGE_RANKS_LEN>(l_num_pkgs_ranks);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_num_pkgs_ranks <= MAX_PKG_RANKS_VALID_KEY,
+ BYTE_INDEX,
+ l_num_pkgs_ranks,
+ "Failed check for number of packages per DIMM") );
+ // Decoding Bit 6
+ l_spd_buffer.extractToRight<RANK_MIX_START, RANK_MIX_LEN>(l_rank_mix);
+
+ // We only support symmetrical rank mix
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_rank_mix == SYMMETRICAL,
+ BYTE_INDEX,
+ l_rank_mix,
+ "Failed check for number of packages per DIMM") );
+ // Decoding Bit 7
+ l_spd_buffer.extractToRight<MODULE_ORG_RESERVED_START, MODULE_ORG_RESERVED_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for number of packages per DIMM");
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(eff_dram_width(l_target_mcs, &l_sdram_device_widths[0][0]));
+ FAPI_TRY(eff_num_packages_per_rank(l_target_mcs, &l_num_pkg_ranks_per_dimm[0][0]));
+ FAPI_TRY(eff_dram_rank_mix(l_target_mcs, &l_rank_mixes[0][0]));
+
+ // Update attribute to decoded byte values
+ l_sdram_device_widths[PORT_NUM][DIMM_NUM] = device_type_map[l_device_width];
+ l_num_pkg_ranks_per_dimm[PORT_NUM][DIMM_NUM] = num_pkgs_ranks_per_dimm_map[l_num_pkgs_ranks];
+ l_rank_mixes[PORT_NUM][DIMM_NUM] = l_rank_mix;
+
+ // Update MCS level attribute
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_WIDTH, l_target_mcs, l_sdram_device_widths) );
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_NUM_PACKAGES_PER_RANK, l_target_mcs, l_num_pkg_ranks_per_dimm) );
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_RANK_MIX, l_target_mcs, l_rank_mixes) );
+
+ // Printed decoded info
+ FAPI_INF( "%s. Device Width: %d, Number of rank packages per DIMM: %d, Rank Mix: %d",
+ c_str(i_target_dimm),
+ l_sdram_device_widths[PORT_NUM][DIMM_NUM],
+ l_num_pkg_ranks_per_dimm[PORT_NUM][DIMM_NUM],
+ l_rank_mixes[PORT_NUM][DIMM_NUM] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+//TODO
+// Returning correct stuff (bits) ?? Or am I supposed to calc "Module DRAM Capacity" pg 27
+
+///
+/// @brief Decode Module Memory Bus Width
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 13
+///
+fapi2::ReturnCode decoder::module_memory_bus_width(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 13;
+ const size_t RESERVED = 0;
+
+ // Primary bus width mapping limits
+ const size_t MAX_PRIM_BUS_WIDTH_KEY = 3; // All others reserved
+
+ // Bus width extention mapping limits
+ const size_t MAX_VALID_BUS_WIDTH_EXT_KEY = 1; // All others reserved
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint8_t l_bus_width = 0;
+ uint8_t l_bus_width_ext = 0;
+ uint8_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_module_bus_widths[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding Bits 2~0
+ l_spd_buffer.extractToRight<BUS_WIDTH_START, BUS_WIDTH_LEN>(l_bus_width);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_bus_width <= MAX_PRIM_BUS_WIDTH_KEY,
+ BYTE_INDEX,
+ l_bus_width,
+ "Failed check on primary bus width") );
+ // Decoding Bits 4~3
+ l_spd_buffer.extractToRight<BUS_EXT_WIDTH_START, BUS_EXT_WIDTH_LEN>(l_bus_width_ext);
+
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_bus_width_ext <= MAX_VALID_BUS_WIDTH_EXT_KEY,
+ BYTE_INDEX,
+ l_bus_width_ext,
+ "Failed check for bus width extension") );
+ // Decoding bits Bits 7~5
+ l_spd_buffer.extractToRight<BUS_WIDTH_RESERVED_START, BUS_WIDTH_RESERVED_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for bus width reserved bits");
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_module_bus_width(l_target_mcs, &l_module_bus_widths[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_module_bus_widths[PORT_NUM][DIMM_NUM] = prim_bus_width_map[l_bus_width] + bus_width_ext_map[l_bus_width_ext];
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_MODULE_BUS_WIDTH, l_target_mcs, l_module_bus_widths);
+
+ // Printed decoded info
+ FAPI_INF( "%s Module Memory Bus Width (in bits): %d, Primary bus width: %d, Bus width extension: %d",
+ c_str(i_target_dimm),
+ l_module_bus_widths[PORT_NUM][DIMM_NUM],
+ prim_bus_width_map[l_bus_width],
+ bus_width_ext_map[l_bus_width_ext] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
+/// @brief Decode Module Thermal Sensor
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 14, no attribute found for this
+///
+fapi2::ReturnCode decoder::module_thermal_sensor(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 14;
+ const size_t VALID_VALUE = 1;
+ const size_t RESERVED = 0;
+
+ // Byte variables used for decoding
+ uint8_t l_reserved = 0;
+ uint8_t l_thermal_sensor = 0;
+
+ // Attribute variables used to set decoded vals
+ uint8_t l_therm_sensors[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding Bits 6~0
+ l_spd_buffer.extractToRight<THERM_SENSOR_RESERV_START, THERM_SENSOR_RESERV_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for thermal sensor reserved bits");
+ // Decoding bits Bit 7
+ l_spd_buffer.extractToRight<THERM_SENSOR_START, THERM_SENSOR_LEN>(l_thermal_sensor);
+
+ // Length is a single bit (0 or 1), anything larger means corrupt data
+ FAPI_TRY( mss::check::spd::valid_value_fail(i_target_dimm,
+ l_thermal_sensor <= VALID_VALUE,
+ BYTE_INDEX,
+ l_thermal_sensor,
+ "Failed check for thermal sensor") );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( spd_module_thermal_sensor(l_target_mcs, &l_therm_sensors[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_therm_sensors[PORT_NUM][DIMM_NUM] = l_thermal_sensor;
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET(fapi2::ATTR_SPD_MODULE_THERMAL_SENSOR, l_target_mcs, l_therm_sensors);
+
+ // Printed decoded info
+ FAPI_INF("%s. Thermal sensor: %d, Reserved: %d",
+ c_str(i_target_dimm),
+ l_thermal_sensor,
+ l_reserved );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Extended Module Type
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 15, no attribute for this byte
+///
+fapi2::ReturnCode decoder::extended_module_type(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 15;
+ const size_t RESERVED = 0;
+
+ // Byte variables used for decoding
+ uint8_t l_ext_module_type = 0;
+ uint8_t l_reserved = 0;
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // Decoding Bits 3~0
+ l_spd_buffer.extractToRight<EXT_MOD_TYPE_START, EXT_MOD_TYPE_LEN>(l_ext_module_type);
+
+ // According to JEDEC spec this value should be coded as 0000 which is the value as the reserved bits
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ l_ext_module_type == RESERVED,
+ BYTE_INDEX,
+ l_ext_module_type,
+ "Failed check for extended base module type") );
+ // Decoding Bit 7~4
+ l_spd_buffer.extractToRight<EXT_MOD_TYPE_RESERV_START, EXT_MOD_TYPE_RESERV_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for extended module type reserved bits");
+
+ // Printed decoded info
+ FAPI_INF("%s. Extended Base Module Type: %d, Reserved: %d",
+ c_str(i_target_dimm),
+ l_ext_module_type,
+ l_reserved );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Timebases
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 17
+///
+fapi2::ReturnCode decoder::timebases(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 17;
+ const size_t RESERVED = 0;
+
+ // Medium timebase mapping limits
+ const int64_t MAX_VALID_MTB_KEY = 1; // All others reserved
+
+ // Fine timebase mapping limits
+ const int64_t MAX_VALID_FTB_KEY = 1; // All others reserved
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ int64_t l_fine_timebase = 0;
+ int64_t l_medium_timebase = 0;
+ int64_t l_reserved = 0;
+
+ // Attribute variables used to set decoded vals
+ int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Buffer used for bit manipulation
+ fapi2::buffer<uint8_t> l_spd_buffer(i_spd_data[BYTE_INDEX]);
+
+ // TODO - update ENUMS to take account to int64_t
+ // Decoding Bits 1~0
+ l_spd_buffer.extractToRight<FINE_TIMEBASE_START, FINE_TIMEBASE_LEN>(l_fine_timebase);
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ l_fine_timebase < MAX_VALID_FTB_KEY,
+ BYTE_INDEX,
+ l_fine_timebase,
+ "Failed check for fine timebase") );
+ // Decoding Bits 3~2
+ l_spd_buffer.extractToRight<MED_TIMEBASE_START, MED_TIMEBASE_LEN>(l_medium_timebase);
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ l_medium_timebase < MAX_VALID_MTB_KEY,
+ BYTE_INDEX,
+ l_medium_timebase,
+ "Failed check for medium timebase") );
+ // Decoding bits Bits 7~4
+ l_spd_buffer.extractToRight<TIMEBASE_RESERV_START, TIMEBASE_RESERV_LEN>(l_reserved);
+
+ mss::check::spd::valid_value_warn(i_target_dimm,
+ l_reserved == RESERVED,
+ BYTE_INDEX,
+ l_reserved,
+ "Failed check for timebases reserved bits");
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) );
+ FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_FTBs[PORT_NUM][DIMM_NUM] = fine_timebase_map[l_fine_timebase];
+ l_MTBs[PORT_NUM][DIMM_NUM] = medium_timebase_map[l_medium_timebase];
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_SPD_FINE_TIMEBASE, l_target_mcs, l_FTBs );
+ FAPI_ATTR_SET( fapi2::ATTR_SPD_MEDIUM_TIMEBASE, l_target_mcs, l_MTBs );
+
+ // Printed decoded info
+ FAPI_INF( "%s. Fine Timebase: %d, Medium Timebase: %d",
+ c_str(i_target_dimm),
+ l_FTBs[PORT_NUM][DIMM_NUM],
+ l_MTBs[PORT_NUM][DIMM_NUM] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode SDRAM Minimum Cycle Time
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 18 & Byte 125
+/// This byte depends on the fine & medium timebase values
+/// obtained from Byte 17
+///
+fapi2::ReturnCode decoder::min_cycle_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MTB = 18; // min cycle medium timebase (mtb)
+ const size_t BYTE_INDEX_FTB = 125; // min cycle fine timebase (ftb)
+
+ const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC
+
+ const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ int64_t l_tCKmin_mtb = 0;
+ int64_t l_tCKmin_ftb = 0;
+
+ // Attribute variables
+ int64_t l_min_cycle_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_MTB,
+ i_spd_data[BYTE_INDEX_MTB]);
+
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_FTB,
+ i_spd_data[BYTE_INDEX_FTB]);
+
+ // Retrieve SDRAM Maximum Cycle Time
+ l_tCKmin_mtb = i_spd_data[BYTE_INDEX_MTB];
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tCKmin_mtb <= MAX_CYCLE_TIME_MTB) &&
+ (l_tCKmin_mtb >= MIN_CYCLE_TIME_MTB),
+ BYTE_INDEX_MTB,
+ l_tCKmin_mtb,
+ "Failed check for tCKmin (min cycle time) in MTB units") );
+
+ // Retrieve Fine Offset for SDRAM Minimum Cycle Time
+ // casted int8_t undoes 2's complement on the uint8_t spd data
+ l_tCKmin_ftb = int8_t(i_spd_data[BYTE_INDEX_FTB]);
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tCKmin_ftb <= MAX_CYCLE_TIME_FTB) &&
+ (l_tCKmin_ftb >= MIN_CYCLE_TIME_FTB),
+ BYTE_INDEX_FTB,
+ l_tCKmin_ftb,
+ "Failed check for tCKmin (min cycle time) in FTB units") );
+
+
+ // Retrieving medium timebase (MTB) multiplier used for timing calculation
+ FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) );
+ FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( spd_timing_tckmin(l_target_mcs, &l_min_cycle_times[0][0]) );
+
+ // Update attribute to decoded byte values
+ // Calculating minimum cycle time in picosconds
+ l_min_cycle_times[PORT_NUM][DIMM_NUM] = calc_timing(l_tCKmin_mtb,
+ l_tCKmin_ftb,
+ l_MTBs[PORT_NUM][DIMM_NUM],
+ l_FTBs[PORT_NUM][DIMM_NUM]);
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_TIMING_TCKMIN, l_target_mcs, l_min_cycle_times );
+
+ // Printed decoded info
+ FAPI_INF("%s. tCKmin (min cycle time): %d (ps)",
+ c_str(i_target_dimm),
+ l_min_cycle_times[PORT_NUM][DIMM_NUM] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode SDRAM Maximum Cycle Time
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 19 and 124
+///
+fapi2::ReturnCode decoder::max_cycle_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MTB = 19; // min cycle medium timebase (mtb)
+ const size_t BYTE_INDEX_FTB = 124; // min cycle fine timebase (ftb)
+
+ const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC
+
+ const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ int64_t l_tCKmax_mtb = 0;
+ int64_t l_tCKmax_ftb = 0;
+
+ // Attribute variable
+ int64_t l_max_cycle_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_MTB,
+ i_spd_data[BYTE_INDEX_MTB]);
+
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_FTB,
+ i_spd_data[BYTE_INDEX_FTB]);
+
+ // Retrieve SDRAM Maximum Cycle Time
+ l_tCKmax_mtb = i_spd_data[BYTE_INDEX_MTB];
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tCKmax_mtb <= MAX_CYCLE_TIME_MTB) &&
+ (l_tCKmax_mtb >= MIN_CYCLE_TIME_MTB),
+ BYTE_INDEX_MTB,
+ l_tCKmax_mtb,
+ "Failed check for tCKmin (min cycle time) in MTB units") );
+
+ // Retrieve Fine Offset for SDRAM Maximum Cycle Time
+ // casted int8_t undoes 2's complement on the uint8_t spd data
+ l_tCKmax_ftb = int8_t(i_spd_data[BYTE_INDEX_FTB]);
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tCKmax_ftb <= MAX_CYCLE_TIME_FTB) &&
+ (l_tCKmax_ftb >= MIN_CYCLE_TIME_FTB),
+ BYTE_INDEX_FTB,
+ l_tCKmax_ftb,
+ "Failed check for tCKmin (min cycle time) in FTB units") );
+
+ // Retrieving medium timebase (MTB) multiplier used for timing calculation
+ FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) );
+ FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(spd_timing_tckmax(l_target_mcs, &l_max_cycle_times[0][0]))
+
+ // Update attribute to decoded byte values
+ l_max_cycle_times[PORT_NUM][DIMM_NUM] = calc_timing(l_tCKmax_mtb,
+ l_tCKmax_ftb,
+ l_MTBs[PORT_NUM][DIMM_NUM],
+ l_FTBs[PORT_NUM][DIMM_NUM]);
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_TIMING_TCKMAX, l_target_mcs, l_max_cycle_times );
+
+ // Printed decoded info
+ FAPI_INF("%s. tCKmax (max cycle time): %d (ps)",
+ c_str(i_target_dimm),
+ l_max_cycle_times[PORT_NUM][DIMM_NUM] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Minimum CAS Latency Time
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 24 & 123
+///
+fapi2::ReturnCode decoder::min_cas_latency_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MTB = 24; // min cycle medium timebase (mtb)
+ const size_t BYTE_INDEX_FTB = 123; // min cycle fine timebase (ftb)
+
+ const int64_t MIN_CYCLE_TIME_MTB = 1; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_MTB = 255; // from JEDEC
+
+ const int64_t MIN_CYCLE_TIME_FTB = -128; // from JEDEC
+ const int64_t MAX_CYCLE_TIME_FTB = 127; // from JEDEC
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ int64_t l_tAAmin_mtb = 0;
+ int64_t l_tAAmin_ftb = 0;
+
+ // Attribute variable
+ int64_t l_min_cas_latency_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_MTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+ int64_t l_FTBs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_MTB,
+ i_spd_data[BYTE_INDEX_MTB]);
+
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX_FTB,
+ i_spd_data[BYTE_INDEX_FTB]);
+
+ // Retrieve SDRAM Minimum CAS Latency Time
+ l_tAAmin_mtb = i_spd_data[BYTE_INDEX_MTB];
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tAAmin_mtb <= MAX_CYCLE_TIME_MTB) &&
+ (l_tAAmin_mtb >= MIN_CYCLE_TIME_MTB),
+ BYTE_INDEX_MTB,
+ l_tAAmin_mtb,
+ "Failed check for min CAS latency time (tAAmin) in MTB units") );
+
+ // Retrieve Fine Offset for Minimum CAS Latency Time
+ // casted int8_t undoes 2's complement on the uint8_t spd data
+ l_tAAmin_ftb = int8_t(i_spd_data[BYTE_INDEX_FTB]);
+
+ FAPI_TRY(mss::check::spd::valid_value_fail(i_target_dimm,
+ (l_tAAmin_ftb <= MAX_CYCLE_TIME_FTB) &&
+ (l_tAAmin_ftb >= MIN_CYCLE_TIME_FTB),
+ BYTE_INDEX_FTB,
+ l_tAAmin_ftb,
+ "Failed check for min CAS latency time (tAAmin) in FTB units") );
+
+ // Retrieving medium timebase (MTB) multiplier used for timing calculation
+ FAPI_TRY( spd_medium_timebase(l_target_mcs, &l_MTBs[0][0]) );
+ FAPI_TRY( spd_fine_timebase(l_target_mcs, &l_FTBs[0][0]) );
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY(spd_timing_taamin(l_target_mcs, &l_min_cas_latency_times[0][0]))
+
+ // Update attribute to decoded byte values
+ l_min_cas_latency_times[PORT_NUM][DIMM_NUM] = calc_timing(l_tAAmin_mtb,
+ l_tAAmin_ftb,
+ l_MTBs[PORT_NUM][DIMM_NUM],
+ l_FTBs[PORT_NUM][DIMM_NUM]);
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_TIMING_TAAMIN, l_target_mcs, l_min_cas_latency_times );
+
+ // Printed decoded info
+ FAPI_INF("%s. tAAmin (min cycle time): %d (ps)",
+ c_str(i_target_dimm),
+ l_min_cas_latency_times[PORT_NUM][DIMM_NUM] );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+#if 0
+
+///
+/// @brief Decode CAS Latencies Supported
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 20-23
+///
+fapi2::ReturnCode decoder::supported_cas_latencies(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t FIRST_BYTE = 20;
+ const size_t SEC_BYTE = 21;
+ const size_t THIRD_BYTE = 22;
+ const size_t FORTH_BYTE = 23;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding
+ uint64_t l_supported_cas_lat = 0;
+
+ // Attribute variables used to set decoded vals
+ uint64_t l_supported_CLs[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_first_byte_buff(i_spd_data[FIRST_BYTE]);
+ fapi2::buffer<uint8_t> l_second_byte_buff(i_spd_data[SEC_BYTE]);
+ fapi2::buffer<uint8_t> l_third_byte_buff(i_spd_data[THIRD_BYTE]);
+ fapi2::buffer<uint8_t> l_forth_byte_buff(i_spd_data[FORTH_BYTE]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Combine Bytes 20 - 23 to create bitmap
+ l_first_byte_buff.extractToRight<CAS_BYTE_1_START, CAS_BYTE_1_LEN>(l_supported_cas_lat).
+ l_second_byte_buff.extractToRight<CAS_BYTE_2_START, CAS_BYTE_2_LEN>(l_supported_cas_lat).
+ l_third_byte_buff.extractToRight<CAS_BYTE_3_START, CAS_BYTE_3_LEN>(l_supported_cas_lat).
+ l_forth_byte_buff.extractToRight<CAS_BYTE_4_START, CAS_BYTE_4_LEN>(l_supported_cas_lat);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( cas_latencies_supported(l_target_mcs, &l_supported_CLs[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_supported_CLs[PORT_NUM][DIMM_NUM] = l_supported_cas_lat;
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_SPD_CAS_LATENCIES_SUPPORTED, l_target_mcs, l_supported_CLs );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+
+///
+/// @brief Decode Minimum RAS to CAS Delay Time
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 25
+///
+fapi2::ReturnCode decoder::min_ras_to_cas_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 25;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (rcd = ras to cas delay)
+ int64_t l_min_rcd_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trcd(l_target_mcs, &l_min_rcd_times[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_rcd_times[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRCD, l_target_mcs, l_min_rcd_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Minimum Row Precharge Delay Time
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte 26
+///
+fapi2::ReturnCode decoder::min_row_precharge_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 26;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (rp = row to precharge)
+ int64_t l_min_rp_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trp(l_target_mcs, &l_min_rp_times[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_rp_times[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRP, l_target_mcs, l_min_rp_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Decode Minimum Active to Precharge Delay Time (tRASmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 27 Bits 3~0 along with Byte 28 Bits 7~0
+///
+fapi2::ReturnCode decoder::min_activate_to_precharge_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSB = 27; // MSN = most significant byte
+ const size_t BYTE_INDEX_LSB = 28; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (tRAS = Active to Precharge Delay Time)
+ int64_t l_tRASmin = 0;
+
+ // Attribute variable
+ int64_t l_min_ras_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSB]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.extractToRight<TRASMIN_MSN_START, TRASMIN_MSN_LEN>(l_tRASmin);
+ l_buffer_lower_byte.extractToRight<TRASMIN_LSB_START, TRASMIN_LSB_LEN>(l_tRASmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_tras(l_target_mcs, &l_min_ras_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds)
+ l_min_ras_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRASmin);
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRAS, l_target_mcs, l_min_ras_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Active to Active/Refresh Delay Time (tRCmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte Byte 27 Bits 7~4 along with Byte 29 Bits 7~0
+///
+fapi2::ReturnCode
+decoder::min_activate_to_activate_refresh_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSN = 27; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 28; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (RC = Activate to Activate/Refresh Delay)
+ uint16_t l_tRCmin = 0;
+
+ // Attribute variable
+ uint16_t l_min_rc_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.extractToRight<TRCMIN_MSN_START, TRCMIN_MSN_LEN>(l_tRCmin);
+ l_buffer_lower_byte.extractToRight<TRCMIN_LSB_START, TRCMIN_LSB_LEN>(l_tRCmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rc_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_rc_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRCmin);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRC, l_target_mcs, l_min_rc_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Refresh Recovery Delay Time 1 (tRFC1min)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte Byte 30 (LSB) along with Byte 31 (MSB)
+///
+fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_1(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSB = 31; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 30; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (RFC1 = Minimum Refresh Recovery Delay Time)
+ uint32_t l_tRFC1min = 0;
+
+ // Attribute variable
+ uint32_t l_min_rfc1_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]);
+ fapi2::buffer<uint8_t> l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_MSB.extractToRight<, >();
+ l_buffer_LSB.extractToRight<, >();
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc1_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_rfc1_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRFC1min);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRFC1, l_target_mcs, l_min_rfc1_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Refresh Recovery Delay Time 2 (tRFC2min)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte Byte 32 (LSB) along with Byte 33 (MSB)
+///
+fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_2(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSB = 33; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 32; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (RFC1 = Minimum Refresh Recovery Delay 2)
+ uint32_t l_tRFC2min = 0;
+
+ // Attribute variable
+ uint32_t l_min_rfc2_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]);
+ fapi2::buffer<uint8_t> l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_MSB.extractToRight<, >();
+ l_buffer_LSB.extractToRight<, >();
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc2_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_rfc1_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRFC2min);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRFC2, l_target_mcs, l_min_rfc2_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Refresh Recovery Delay Time 4 (tRFC4min)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note SPD Byte Byte 34 (LSB) along with Byte 5 (MSB)
+///
+fapi2::ReturnCode decoder::min_refresh_recovery_delay_time_4(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSB = 35; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 34; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (RFC4 = Minimum Refresh Recovery Delay 4)
+ uint32_t l_tRFC4min = 0;
+
+ // Attribute variable
+ uint32_t l_min_rfc4_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_MSB(i_spd_data[BYTE_INDEX_MSB]);
+ fapi2::buffer<uint8_t> l_buffer_LSB(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_MSB.extractToRight<, >();
+ l_buffer_LSB.extractToRight<, >();
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_rfc4_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_rfc1_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tRFC4min);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRFC2, l_target_mcs, l_min_rfc4_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Four Activate Window Delay Time (t FAW min)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 36 Bits 3 ~ 0 along with Byte 37 Bits 7 ~ 0
+///
+fapi2::ReturnCode decoder::min_four_activate_window_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSN = 36; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 37; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (FAW = Four Activate Window Delay)
+ uint16_t l_tFAW = 0;
+
+ // Attribute variable
+ uint16_t l_min_faw_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.extractToRight<TRCMIN_MSN_START, TRCMIN_MSN_LEN>(l_tFAW);
+ l_buffer_lower_byte.extractToRight<TRCMIN_LSB_START, TRCMIN_LSB_LEN>(l_tFAW);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trc(l_target_mcs, &l_min_faw_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_faw_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tFAW);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRC, l_target_mcs, l_min_faw_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Activate to Activate Delay Time (tRRD_Smin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 38
+///
+fapi2::ReturnCode
+decoder::min_act_to_act_delay_time_diff_bank_group(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 38;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (rrd_s = Activate to Activate Delay)
+ int64_t l_min_tRRD_S[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_tRRD_S[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_tRRD_S[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRRD_S, l_target_mcs, l_min_tRRD_S );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Activate to Activate Delay Time (tRRD_Lmin), samebank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 39
+///
+fapi2::ReturnCode
+decoder::min_act_to_act_delay_time_same_bank_group(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 39;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (rrd_s = Activate to Activate Delay)
+ int64_t l_min_tRRD_S[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_tRRD_S[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_tRRD_S[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TRRD_L, l_target_mcs, l_min_tRRD_S );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum CAS to CAS Delay Time (tCCD_Lmin), same bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 40
+///
+fapi2::ReturnCode decoder::min_cas_to_cas_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 40;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TCCD_L, l_target_mcs, l_min_tCCD_L );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Write Recovery Time (tWRmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 41 Bits 3~0, Byte 42 Bits 7~0
+///
+fapi2::ReturnCode decoder::min_write_recovery_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSN = 41; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 42; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (FAW = Four Activate Window Delay)
+ uint16_t l_tWRmin = 0;
+
+ // Attribute variable
+ int64_t l_min_wr_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.insert<, >(l_tWRmin);
+ l_buffer_lower_byte.insert<, >(l_tWRmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_twr(l_target_mcs, &l_min_wr_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_wr_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRmin);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWR, l_target_mcs, l_min_wr_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Write to Read Time (tWTR_Smin), different bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 43 Bits 3~0, Byte 44 Bits 7~0
+///
+fapi2::ReturnCode decoder::min_write_to_read_time_diff_bank_group(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSN = 43; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 44; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (WRT = Write to Read Time)
+ int64_t l_tWRTmin = 0;
+
+ // Attribute variable
+ int64_t l_min_wrt_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.insert<, >(l_tWRTmin);
+ l_buffer_lower_byte.insert<, >(l_tWRTmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_twrt(l_target_mcs, &l_min_wrt_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_wrt_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRTmin);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWRT, l_target_mcs, l_min_wrt_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Minimum Write to Read Time (tWTR_Lmin), same bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 43 Bits 7~4, Byte 45 Bits 7~0
+///
+fapi2::ReturnCode
+decoder::min_write_to_read_time_same_bank_group(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSN = 43; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 45; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (WRT = Write to Read Time)
+ int64_t l_tWRTmin = 0;
+
+ // Attribute variable
+ int64_t l_min_wrt_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.insert<, >(l_tWRTmin);
+ l_buffer_lower_byte.insert<, >(l_tWRTmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_twrt(l_target_mcs, &l_min_wrt_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_wrt_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRTmin);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWRT, l_target_mcs, l_min_wrt_times );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Connector to SDRAM Bit Mapping
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Bytes 60~77
+///
+fapi2::ReturnCode decoder::connector_to_sdram_bit_mapping(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+// Retrive entire MCS level attribute
+// Update attribute to decoded byte values
+// Update MCS level attribute
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for Minimum CAS to CAS Delay Time (tCCD_Lmin), same bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 117
+///
+fapi2::ReturnCode decoder::offset_for_min_cas_to_cas_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 117;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+// Retrive entire MCS level attribute
+// Update attribute to decoded byte values
+// Update MCS level attribute
+
+fapi_try_exit:
+return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for Minimum Activate to Activate Delay Time(tRRD_Lmin), same bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 118
+///
+fapi2::ReturnCode
+decoder::offset_min_act_to_act_delay_time_diff_bank_gp(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 118;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+
+}
+
+///
+/// @brief Fine Offset for Minimum Activate to Activate Delay Time (tRRD_Smin), different bank group
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 119
+///
+fapi2::ReturnCode
+decoder::offset_min_act_to_act_delay_time_same_bank_gp(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 119;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for Minimum Active to Active/Refresh Delay Time (tRCmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 120
+///
+fapi2::ReturnCode
+decoder::offset_for_min_act_to_act_refresh_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 120;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+
+// Retrive entire MCS level attribute
+// Update attribute to decoded byte values
+// Update MCS level attribute
+
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for Minimum Row Precharge Delay Time (tRPmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 121
+///
+fapi2::ReturnCode
+decoder::offset_for_min_row_precharge_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 121;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+
+///
+/// @brief Fine Offset for Minimum RAS to CAS Delay Time (tRCDmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 122
+///
+fapi2::ReturnCode decoder::offset_for_min_ras_to_cas_delay_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 122;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for Minimum CAS Latency Time (tAAmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 123
+///
+fapi2::ReturnCode decoder::offset_for_min_cas_latency_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 123;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for SDRAM Maximum Cycle Time (tCKAVGmax)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 124
+///
+fapi2::ReturnCode decoder::offset_for_max_cycle_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 124;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fine Offset for SDRAM Minimum Cycle Time (tCKAVGmin)
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 125
+///
+fapi2::ReturnCode decoder::offset_for_min_cycle_time(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX = 125;
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Attribute variable (CCD_L = Minimum CAS to CAS Delay Time, same bank group)
+ int64_t l_min_offset_tCCD_L[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_trrd(l_target_mcs, &l_min_offset_tCCD_L[0][0]) );
+
+ // Update attribute to decoded byte values
+ l_min_offset_tCCD_L[PORT_NUM][DIMM_NUM] = ns_to_ps( int64_t(i_spd_data[BYTE_INDEX]) );
+
+ // Update MCS level attribute
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_OFFSET_DRAM_TCCD_L, l_target_mcs, l_min_offset_tCCD_L );
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Cyclical Redundancy Code (CRC) for Base Configuration Section
+/// @param[in] const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+/// uint8_t* i_spd_data
+/// @return fapi2::ReturnCode
+/// @note Byte 126 (LSB) along with Byte 127 (MSB)
+///
+fapi2::ReturnCode decoder::crc_for_base_config_section(const fapi2::Target<TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data)
+{
+ // Immutable constants
+ const size_t BYTE_INDEX_MSB = 127; // MSN = most significant nibble
+ const size_t BYTE_INDEX_LSB = 126; // LSB = least significant byte
+
+ // Targets
+ const auto l_target_mcs = find_target<TARGET_TYPE_MCS>(i_target_dimm);
+ const auto l_target_port = find_target<TARGET_TYPE_MCA>(i_target_dimm);
+
+ // Current index
+ const auto PORT_NUM = index(l_target_port);
+ const auto DIMM_NUM = index(i_target_dimm);
+
+ // Byte variables used for decoding (WRT = Write to Read Time)
+ int64_t l_tWRTmin = 0;
+
+ // Attribute variable
+ int64_t l_min_wrt_times[PORTS_PER_MCS][MAX_DIMM_PER_PORT] = {0};
+
+ // TODO - update ENUMS to take account to int64_t
+
+ // Buffers used for bit manipulation
+ fapi2::buffer<uint8_t> l_buffer_upper_nibble(i_spd_data[BYTE_INDEX_MSN]);
+ fapi2::buffer<uint8_t> l_buffer_lower_byte(i_spd_data[BYTE_INDEX_LSB]);
+
+ // Trace print in the front assists w/ debug
+ FAPI_INF("%s SPD data at Byte %d: 0x%llX",
+ c_str(i_target_dimm),
+ BYTE_INDEX,
+ i_spd_data[BYTE_INDEX]);
+
+ // Combining bits to create timing value
+ l_buffer_upper_nibble.insert<, >(l_tWRTmin);
+ l_buffer_lower_byte.insert<, >(l_tWRTmin);
+
+ // Retrive entire MCS level attribute
+ FAPI_TRY( eff_dram_twrt(l_target_mcs, &l_min_wrt_times[0][0]) );
+
+ // Update attribute to decoded byte values (returning picoseconds, currently nanoseconds)
+ l_min_wrt_times[PORT_NUM][DIMM_NUM] = ns_to_ps(l_tWRTmin);
+
+ // Update MCS level attribute (returning picoseconds, currently nanoseconds)
+ FAPI_ATTR_SET( fapi2::ATTR_EFF_DRAM_TWRT, l_target_mcs, l_min_wrt_times );
+
+ // Printed decoded info
+ FAPI_INF("%s",
+ c_str(i_target_dimm);
+ fapi_try_exit:
+ return fapi2::current_err;
+}
+#endif
+
+}//spd namespace
+}// mss namespace
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H
new file mode 100644
index 000000000..c86dc8816
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H
@@ -0,0 +1,424 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/hwp/memory/lib/spd/spd_decoder.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file spd_decoder.H
+/// @brief SPD decoder declarations
+///
+// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_SPD_DECODER_H_
+#define _MSS_SPD_DECODER_H_
+
+#include <fapi2.H>
+#include <cstdint>
+
+namespace mss
+{
+namespace spd
+{
+
+
+enum constants : uint64_t
+{
+ // Byte 0
+ BYTES_USED_START = 4,
+ BYTES_USED_LEN = 4,
+
+ BYTES_TOTAL_START = 1,
+ BYTES_TOTAL_LEN = 3,
+
+ BYTES_RESERVED_START = 0,
+ BYTES_RESERVED_LEN = 1,
+
+ // Byte 1 & 2 not used now
+
+ // Byte 3
+ BASE_MODULE_START = 4,
+ BASE_MODULE_LEN = 4,
+
+ HYBRID_MEDIA_START = 1,
+ HYBRID_MEDIA_LEN = 3,
+
+ HYBRID_START = 0,
+ HYBRID_LEN = 1,
+
+ // Byte 4
+ SDRAM_CAPACITY_START = 4,
+ SDRAM_CAPACITY_LEN = 4,
+
+ SDRAM_BANKS_START = 2,
+ SDRAM_BANKS_LEN = 2,
+
+ BANK_GROUP_START = 0,
+ BANK_GROUP_LEN = 2,
+
+ // Byte 5
+ COL_ADDRESS_START = 5,
+ COL_ADDRESS_LEN = 3,
+
+ ROW_ADDRESS_START = 2,
+ ROW_ADDRESS_LEN = 3,
+
+ ADDRESS_RESERVED_START = 0,
+ ADDRESS_RESERVED_LEN = 2,
+
+ // Byte 6
+ PRIM_PRIM_SIGNAL_LOAD_START = 5,
+ PRIM_PRIM_SIGNAL_LOAD_LEN = 2,
+
+ PACKAGE_RESERVE_START = 4,
+ PACKAGE_RESERVE_LEN = 2,
+
+ PRIM_DIE_COUNT_START = 1,
+ PRIM_DIE_COUNT_LEN = 3,
+
+ PRIM_PACKAGE_TYPE_START = 0,
+ PRIM_PACKAGE_TYPE_LEN = 1,
+
+ // Byte 7
+ MAC_START = 4,
+ MAC_LEN = 4,
+
+ TMAW_START = 2,
+ TMAW_LEN = 2,
+
+ OPT_FEAT_RESERVED_START = 0,
+ OPT_FEAT_RESERVED_LEN = 2,
+
+ // Byte 8 reserved
+
+ // Byte 9
+ PPR_RESERVED_START = 3,
+ PPR_RESERVED_LEN = 5,
+
+ SOFT_PPR_START = 2,
+ SOFT_PPR_LEN = 1,
+
+ PPR_START = 0,
+ PPR_LEN = 2,
+
+ // Byte 10
+ SEC_SIGNAL_LOAD_START = 5,
+ SEC_SIGNAL_LOAD_LEN = 2,
+
+ DENSITY_RATIO_START = 4,
+ DENSITY_RATIO_LEN = 2,
+
+ SEC_DIE_COUNT_START = 1,
+ SEC_DIE_COUNT_LEN = 3,
+
+ SEC_PACKAGE_TYPE_START = 0,
+ SEC_PACKAGE_TYPE_LEN = 1,
+
+ // Byte 11
+ OPERABLE_START = 7,
+ OPERABLE_LEN = 1,
+
+ ENDURANT_START = 6,
+ ENDURANT_LEN = 1,
+
+ NOM_VOLT_START = 0,
+ NOM_VOLT_LEN = 6,
+
+ // Byte 12
+ SDRAM_WIDTH_START = 5,
+ SDRAM_WIDTH_LEN = 3,
+
+ PACKAGE_RANKS_START = 2,
+ PACKAGE_RANKS_LEN = 3,
+
+ RANK_MIX_START = 1,
+ RANK_MIX_LEN = 1,
+
+ MODULE_ORG_RESERVED_START = 0,
+ MODULE_ORG_RESERVED_LEN = 1,
+
+ // Byte 13
+ BUS_WIDTH_START = 6,
+ BUS_WIDTH_LEN = 2,
+
+ BUS_EXT_WIDTH_START = 3,
+ BUS_EXT_WIDTH_LEN = 2,
+
+ BUS_WIDTH_RESERVED_START = 0,
+ BUS_WIDTH_RESERVED_LEN = 3,
+
+ // Byte 14
+ THERM_SENSOR_RESERV_START = 1,
+ THERM_SENSOR_RESERV_LEN = 7,
+
+ THERM_SENSOR_START = 0,
+ THERM_SENSOR_LEN = 1,
+
+ // Byte 15
+ EXT_MOD_TYPE_START = 5,
+ EXT_MOD_TYPE_LEN = 3,
+
+ EXT_MOD_TYPE_RESERV_START = 0,
+ EXT_MOD_TYPE_RESERV_LEN = 4,
+
+ // Byte 16 - reserved
+
+ // Byte 17
+ FINE_TIMEBASE_START = 6,
+ FINE_TIMEBASE_LEN = 2,
+
+ MED_TIMEBASE_START = 4,
+ MED_TIMEBASE_LEN = 2,
+
+ TIMEBASE_RESERV_START = 0,
+ TIMEBASE_RESERV_LEN = 4,
+
+ // Byte 18 - bits not decoded
+ // Byte 19 - bits not decoded
+
+ // Byte 20-23
+ CAS_BYTE_1_START = 55,
+ CAS_BYTE_1_LEN = 8,
+ CAS_BYTE_2_START = 47,
+ CAS_BYTE_2_LEN = 8,
+ CAS_BYTE_3_START = 39,
+ CAS_BYTE_3_LEN = 8,
+ CAS_BYTE_4_START = 31,
+ CAS_BYTE_4_LEN = 8,
+
+ // Byte 24 - bits not decoded
+ // Byte 25 - bits not decoded
+ // Byte 26 - bits not decoded
+
+ // Byte 27
+ TRCMIN_MSN_START = 0, // MSN = most significant nibble
+ TRCMIN_MSN_LEN = 4,
+
+ TRASMIN_MSN_START = 4, // MSN = most significant nibble
+ TRASMIN_MSN_LEN = 4,
+
+ // Byte 28
+ TRASMIN_LSB_START = 4, // LSB = least significant byte
+ TRASMIN_LSB_LEN = 8,
+
+ // Byte 29
+ TRCMIN_LSB_START = 4, // LSB = least significant byte
+ TRCMIN_LSB_LEN = 8,
+
+ // Byte 30
+ // TRFC1MIN_LSB_START
+ // TRFC1MIN_LSB_LEN
+
+ // Byte 31
+// TRFC1MIN_MSB_START
+// TRFC1MIN_MSB_LEN
+
+ // Bytes 46 - 59 - reserved
+
+ // Bytes 60 - 77 - Connector to SDRAM Bit Mapping ??
+
+ // Bytes 78 - 116 - reserved
+
+ // Bytes 117 - 125 : bits not decoded
+
+ // Bytes 128 ~ 191 Module-Specific Section ??
+
+ // Bytes 192 ~ 255 Hybrid Memory Architecture Specific Parameters ??
+
+ // Bytes 256 ~ 319 Extended Function Parameter Block ??
+
+ // Bytes 320 ~ 383 Module Supplier’s Data ??
+};
+
+
+class decoder
+{
+
+ public:
+ // Constructor
+ decoder() = default;
+ // Deconstructor
+ virtual ~decoder() = default;
+
+ // Methods
+ virtual fapi2::ReturnCode number_of_bytes(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data,
+ const size_t i_read_spd_size);
+
+ virtual fapi2::ReturnCode revision(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode dram_device_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode module_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode sdram_density(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode sdram_addressing(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode primary_package_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode sdram_optional_features(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode thermal_and_refresh_options(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode other_optional_features(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode secondary_package_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode module_nominal_voltage(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode module_organization(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode module_memory_bus_width(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode module_thermal_sensor(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode extended_module_type(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode timebases(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode max_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_cas_latency_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ // Note: Yet to be implemented methods
+#if 0
+
+ virtual fapi2::ReturnCode supported_cas_latencies(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+
+ virtual fapi2::ReturnCode min_ras_to_cas_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_row_precharge_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode upper_nibble_tRAS_tRC(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_activate_to_activate_refresh_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_activate_to_precharge_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_refresh_recovery_delay_time_1(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_refresh_recovery_delay_time_2(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_refresh_recovery_delay_time_4(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_four_activate_window_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_act_to_act_delay_time_diff_bank_group(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_act_to_act_delay_time_same_bank_group(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_cas_to_cas_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_write_recovery_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_write_to_read_time_diff_bank_group(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode min_write_recovery_time_same_bank_group(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode connector_to_sdram_bit_mapping(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_cas_to_cas_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_min_act_to_act_delay_time_diff_bank_gp(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_min_act_to_act_delay_time_same_bank_gp(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_act_to_act_refresh_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_row_precharge_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_ras_to_cas_delay_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_cas_latency_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_min_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode offset_for_max_cycle_time(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+
+ virtual fapi2::ReturnCode crc_for_base_config_section(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target_dimm,
+ const uint8_t* i_spd_data);
+#endif
+};
+
+}// spd
+}// mss
+
+#endif //_MSS_SPD_DECODER_H_
OpenPOWER on IntegriCloud