From c7cf0b2d56200537be4227b246fa5c4754cc7306 Mon Sep 17 00:00:00 2001 From: Stephen Glancy Date: Tue, 11 Oct 2016 20:54:09 -0500 Subject: Fixed CL and timing bugs, unit test augmentations Fix 3DS timing params for SLR and DLR and add unit tests. Fix CL setting for non-configured ports and add unit CL tests Fixed SPD timing errors, CL, MR, and ddr_phy UT bugs Change-Id: Icc7efcc6f5a01ceee168a10ca8236cb656ba013c Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/31066 Tested-by: Jenkins Server Tested-by: Hostboot CI Reviewed-by: Louis Stermole Reviewed-by: JACOB L. HARVEY Reviewed-by: STEPHEN GLANCY Reviewed-by: Matt K. Light Reviewed-by: Christian R. Geddes Reviewed-by: Brian R. Silver Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/31484 Tested-by: FSP CI Jenkins --- .../p9/procedures/hwp/memory/lib/dimm/ddr4/mrs00.C | 3 +- .../hwp/memory/lib/eff_config/eff_config.C | 653 ++++++++------ .../hwp/memory/lib/eff_config/eff_config.H | 56 +- .../procedures/hwp/memory/lib/eff_config/timing.C | 14 +- .../procedures/hwp/memory/lib/eff_config/timing.H | 952 +++++++++++++++++++-- .../procedures/hwp/memory/lib/freq/cas_latency.C | 441 +++++----- .../procedures/hwp/memory/lib/freq/cas_latency.H | 170 ++-- .../p9/procedures/hwp/memory/lib/freq/cycle_time.H | 38 - .../hwp/memory/lib/mss_attribute_accessors.H | 151 +++- .../chips/p9/procedures/hwp/memory/lib/phy/seq.C | 22 +- .../hwp/memory/lib/spd/common/spd_decoder.C | 25 +- .../p9/procedures/hwp/memory/p9_mss_eff_config.C | 10 +- .../chips/p9/procedures/hwp/memory/p9_mss_freq.C | 31 +- .../chips/p9/procedures/hwp/memory/p9_mss_freq.H | 39 +- .../xml/attribute_info/memory_mcs_attributes.xml | 45 +- .../fapi2/xml/attribute_info/hb_temp_defaults.xml | 4 +- 16 files changed, 1883 insertions(+), 771 deletions(-) (limited to 'src/import') diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs00.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs00.C index 71a51e7bb..9f2aafc01 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs00.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs00.C @@ -122,7 +122,7 @@ fapi2::ReturnCode mrs00(const fapi2::Target& i_target, constexpr uint8_t wr_map[WR_COUNT] = { // 10 12 14 16 18 20 22 24 26 - 0b0000, 0, 0b0001, 0, 0b0001, 0, 0b0011, 0, 0b0100, 0, 0b0101, 0, 0b0111, 0, 0b0110, 0, 0b1000 + 0b0000, 0, 0b0001, 0, 0b0010, 0, 0b0011, 0, 0b0100, 0, 0b0101, 0, 0b0111, 0, 0b0110, 0, 0b1000 }; // Map from the CAS Latency attribute to the bits in the MRS @@ -241,4 +241,3 @@ fapi2::ReturnCode (*mrs00_data::decode)(const ccs::instruction_t #include #include +#include using fapi2::TARGET_TYPE_MCA; using fapi2::TARGET_TYPE_MCS; @@ -387,31 +388,26 @@ fapi_try_exit: /// @param[in] i_target FAPI2 target /// @return fapi2::FAPI2_RC_SUCCESS if okay /// -fapi2::ReturnCode eff_config::refresh_interval_time(const fapi2::Target& i_target) +fapi2::ReturnCode eff_config::dram_trefi(const fapi2::Target& i_target) { - uint8_t l_temp_refresh_range = 0; - uint8_t l_refresh_mode = 0; - int64_t l_trefi_in_ps = 0; - - FAPI_TRY( mss::mrw_temp_refresh_range(l_temp_refresh_range), "Failed mrw_temp_refresh_range()" ); - FAPI_TRY( mss::mrw_fine_refresh_mode(l_refresh_mode), "Failed mrw_fine_refresh_mode()" ); + uint64_t l_trefi_in_ps = 0; // Calculates appropriate tREFI based on fine refresh mode - switch(l_refresh_mode) + switch(iv_refresh_mode) { case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL: FAPI_TRY( calc_trefi( mss::refresh_rate::REF1X, - l_temp_refresh_range, + iv_temp_refresh_range, l_trefi_in_ps), - "Failed to calculate tREF1 in refresh_interval_time for target %s", mss::c_str(i_target) ); + "Failed to calculate tREF1 for target %s", mss::c_str(i_target) ); break; case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_2X: case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_2X: FAPI_TRY( calc_trefi( mss::refresh_rate::REF2X, - l_temp_refresh_range, + iv_temp_refresh_range, l_trefi_in_ps), "Failed to calculate tREF2 for target %s", mss::c_str(i_target) ); break; @@ -420,7 +416,7 @@ fapi2::ReturnCode eff_config::refresh_interval_time(const fapi2::Target(i_target) ); std::vector l_mcs_attrs_trefi(PORTS_PER_MCS, 0); - uint16_t l_trefi_in_nck = 0; + uint64_t l_trefi_in_nck = 0; // Retrieve MCS attribute data FAPI_TRY( eff_dram_trefi(l_mcs, l_mcs_attrs_trefi.data()) ); // Calculate nck - // iv_tCK-in_ps will always be positive - FAPI_TRY( calc_nck(l_trefi_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_trefi_in_nck), + FAPI_TRY( spd::calc_nck(l_trefi_in_ps, static_cast(iv_tCK_in_ps), INVERSE_DDR4_CORRECTION_FACTOR, + l_trefi_in_nck), "Error in calculating tREFI for target %s, with value of l_trefi_in_ps: %d", mss::c_str(i_target), l_trefi_in_ps); - FAPI_INF("Calculated tREFI (ps): %d, tREFI (nck): %d", l_trefi_in_ps, l_trefi_in_nck); + FAPI_INF("tCK (ps): %d, tREFI (ps): %d, tREFI (nck): %d", + iv_tCK_in_ps, l_trefi_in_ps, l_trefi_in_nck); // Update MCS attribute l_mcs_attrs_trefi[l_port_num] = l_trefi_in_nck; @@ -476,17 +473,13 @@ fapi_try_exit: /// @param[in] i_target FAPI2 target /// @return fapi2::FAPI2_RC_SUCCESS if okay /// -fapi2::ReturnCode eff_config::refresh_cycle_time(const fapi2::Target& i_target) +fapi2::ReturnCode eff_config::dram_trfc(const fapi2::Target& i_target) { - uint8_t l_refresh_mode = 0; int64_t l_trfc_mtb = 0; int64_t l_trfc_in_ps = 0; - FAPI_TRY ( mss::mrw_fine_refresh_mode(l_refresh_mode), - "Failed to get MRW attribute for fine refresh mode" ); - // Selects appropriate tRFC based on fine refresh mode - switch(l_refresh_mode) + switch(iv_refresh_mode) { case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL: FAPI_TRY( iv_pDecoder->min_refresh_recovery_delay_time_1(i_target, l_trfc_mtb), @@ -511,11 +504,10 @@ fapi2::ReturnCode eff_config::refresh_cycle_time(const fapi2::Targetmedium_timebase(i_target, l_mtb) ); FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); - l_trfc_in_ps = calc_timing_from_timebase(l_trfc_mtb, l_mtb, l_trfc_ftb, l_ftb); + FAPI_INF( "medium timebase (ps): %ld, fine timebase (ps): %ld, tRFC (MTB): %ld, tRFC(FTB): %ld", + l_mtb, l_ftb, l_trfc_mtb, l_trfc_ftb ); + + l_trfc_in_ps = spd::calc_timing_from_timebase(l_trfc_mtb, l_mtb, l_trfc_ftb, l_ftb); } { @@ -545,9 +540,11 @@ fapi2::ReturnCode eff_config::refresh_cycle_time(const fapi2::Target& i_target) +fapi2::ReturnCode eff_config::dram_trfc_dlr(const fapi2::Target& i_target) { const auto l_mcs = find_target(i_target); const auto l_port_num = index( find_target(i_target) ); - uint8_t l_refresh_mode = 0; uint8_t l_density = 0; uint64_t l_tCK_in_ps = 0; uint64_t l_trfc_dlr_in_ps = 0; @@ -582,21 +578,21 @@ fapi2::ReturnCode eff_config::refresh_cycle_time_dlr(const fapi2::Targetsdram_density(i_target, l_density), "Failed to get sdram density"); - FAPI_TRY ( mss::mrw_fine_refresh_mode(l_refresh_mode), "Failed to get MRW attribute for fine refresh mode" ); + FAPI_TRY ( mss::mrw_fine_refresh_mode(iv_refresh_mode), "Failed to get MRW attribute for fine refresh mode" ); FAPI_INF("Retrieved SDRAM density: %d, fine refresh mode: %d", - l_density, l_refresh_mode); + l_density, iv_refresh_mode); // Calculate refresh cycle time in ps - FAPI_TRY( calc_trfc_dlr(l_refresh_mode, l_density, l_trfc_dlr_in_ps), "Failed calc_trfc_dlr()" ); + FAPI_TRY( calc_trfc_dlr(iv_refresh_mode, l_density, l_trfc_dlr_in_ps), "Failed calc_trfc_dlr()" ); // Calculate clock period (tCK) from selected freq from mss_freq FAPI_TRY( clock_period(i_target, l_tCK_in_ps), "Failed to calculate clock period (tCK)"); // Calculate refresh cycle time in nck - FAPI_TRY( calc_nck(l_trfc_dlr_in_ps, l_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_trfc_dlr_in_nck)); + FAPI_TRY( spd::calc_nck(l_trfc_dlr_in_ps, l_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_trfc_dlr_in_nck)); - FAPI_INF("Calculated clock period (tCK): %d, tRFC_DLR (ps): %d, tRFC_DLR (nck): %d", + FAPI_INF("tCK (ps): %d, tRFC_DLR (ps): %d, tRFC_DLR (nck): %d", l_tCK_in_ps, l_trfc_dlr_in_ps, l_trfc_dlr_in_nck); // Retrieve MCS attribute data @@ -716,7 +712,7 @@ fapi2::ReturnCode eff_config::dram_dqs_time(const fapi2::Target& i_target) { - int64_t l_tccd_mtb = 0; - int64_t l_tccd_ftb = 0; int64_t l_tccd_in_ps = 0; - //Get the tCCD timing values - FAPI_TRY( iv_pDecoder->min_tccd_l(i_target, l_tccd_mtb), "failed to get min_tccd_l" ); - FAPI_TRY( iv_pDecoder->fine_offset_min_tccd_l(i_target, l_tccd_ftb) ); + // Get the tCCD_L timing values + // tCCD_L is speed bin independent and is + // the same for all bins within a speed grade. + // It is safe to read this from SPD because the correct nck + // value will be calulated based on our dimm speed. - //Calculate tccd in ps + // TODO: RTC 163150 Clean up eff_config timing boilerplate { int64_t l_ftb = 0; int64_t l_mtb = 0; - - FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb) ); - FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); - - l_tccd_in_ps = calc_timing_from_timebase(l_tccd_mtb, l_mtb, l_tccd_ftb, l_ftb); + int64_t l_tccd_mtb = 0; + int64_t l_tccd_ftb = 0; + + FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb), + "Failed medium_timebase() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb), + "Failed fine_timebase() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->min_tccd_l(i_target, l_tccd_mtb), + "Failed min_tccd_l() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->fine_offset_min_tccd_l(i_target, l_tccd_ftb), + "Failed fine_offset_min_tccd_l() for %s", mss::c_str(i_target) ); + + FAPI_INF("medium timebase (ps): %ld, fine timebase (ps): %ld, tCCD_L (MTB): %ld, tCCD_L(FTB): %ld", + l_mtb, l_ftb, l_tccd_mtb, l_tccd_ftb ); + + l_tccd_in_ps = spd::calc_timing_from_timebase(l_tccd_mtb, l_mtb, l_tccd_ftb, l_ftb); } - { // Calculate refresh cycle time in nCK & set attribute const auto l_mcs = find_target(i_target); @@ -768,9 +774,11 @@ fapi2::ReturnCode eff_config::dram_tccd_l(const fapi2::Target& "Failed to retrieve tCCD attribute" ); // Calculate nck - FAPI_TRY ( calc_nck(l_tccd_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_tccd_in_nck), + FAPI_TRY ( spd::calc_nck(l_tccd_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_tccd_in_nck), "Error in calculating tccd for target %s, with value of l_tccd_in_ps: %d", mss::c_str(i_target), l_tccd_in_ps); - FAPI_INF("Calculated tCCD (ps): %d, tCCD (nck): %d", l_tccd_in_ps, l_tccd_in_nck); + + FAPI_INF("tCK (ps): %d, tCCD_L (ps): %d, tCCD_L (nck): %d", + iv_tCK_in_ps, l_tccd_in_ps, l_tccd_in_nck); // Update MCS attribute l_mcs_attrs_tccd[l_port_num] = l_tccd_in_nck; @@ -808,7 +816,7 @@ fapi2::ReturnCode eff_config::dimm_rc00(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc00[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc00; - FAPI_INF("%s: RC00 settting: %d", c_str(i_target), l_attrs_dimm_rc00[l_port_num][l_dimm_num] ); + FAPI_INF("%s: RC00 settting: %d", mss::c_str(i_target), l_attrs_dimm_rc00[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC00, l_mcs, l_attrs_dimm_rc00) ); fapi_try_exit: @@ -837,7 +845,7 @@ fapi2::ReturnCode eff_config::dimm_rc01(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc01[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc01; - FAPI_INF("%s: RC01 settting: %d", c_str(i_target), l_attrs_dimm_rc01[l_port_num][l_dimm_num] ); + FAPI_INF("%s: RC01 settting: %d", mss::c_str(i_target), l_attrs_dimm_rc01[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC01, l_mcs, l_attrs_dimm_rc01) ); fapi_try_exit: @@ -866,7 +874,7 @@ fapi2::ReturnCode eff_config::dimm_rc02(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc02[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc02; - FAPI_INF("%s: RC02 settting: %d", c_str(i_target), l_attrs_dimm_rc02[l_port_num][l_dimm_num] ); + FAPI_INF("%s: RC02 settting: %d", mss::c_str(i_target), l_attrs_dimm_rc02[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC02, l_mcs, l_attrs_dimm_rc02) ); fapi_try_exit: @@ -898,7 +906,7 @@ fapi2::ReturnCode eff_config::dimm_rc03(const fapi2::Target& i FAPI_TRY( iv_pDecoder->iv_module_decoder->ca_signal_output_driver(l_ca_output_drive) ); FAPI_INF( "%s: Retrieved register output drive, for CA: %d, CS: %d", - c_str(i_target), l_ca_output_drive, l_cs_output_drive ); + mss::c_str(i_target), l_ca_output_drive, l_cs_output_drive ); // Lets construct encoding byte for RCD setting { @@ -916,7 +924,7 @@ fapi2::ReturnCode eff_config::dimm_rc03(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc03[l_port_num][l_dimm_num] = l_buffer; - FAPI_INF("%s: RC03 settting: %d", c_str(i_target), l_attrs_dimm_rc03[l_port_num][l_dimm_num] ); + FAPI_INF("%s: RC03 settting: %d", mss::c_str(i_target), l_attrs_dimm_rc03[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC03, l_mcs, l_attrs_dimm_rc03) ); fapi_try_exit: @@ -948,7 +956,7 @@ fapi2::ReturnCode eff_config::dimm_rc04(const fapi2::Target& i FAPI_TRY( iv_pDecoder->iv_module_decoder->cke_signal_output_driver(l_cke_output_drive) ); FAPI_INF( "%s: Retrieved signal driver output, for CKE: %d, ODT: %d", - c_str(i_target), l_cke_output_drive, l_odt_output_drive ); + mss::c_str(i_target), l_cke_output_drive, l_odt_output_drive ); // Lets construct encoding byte for RCD setting { @@ -967,7 +975,7 @@ fapi2::ReturnCode eff_config::dimm_rc04(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc04[l_port_num][l_dimm_num] = l_buffer; - FAPI_INF("%s: RC04 setting: %d", c_str(i_target), l_attrs_dimm_rc04[l_port_num][l_dimm_num] ); + FAPI_INF("%s: RC04 setting: %d", mss::c_str(i_target), l_attrs_dimm_rc04[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC04, l_mcs, l_attrs_dimm_rc04) ); fapi_try_exit: @@ -999,7 +1007,7 @@ fapi2::ReturnCode eff_config::dimm_rc05(const fapi2::Target& i FAPI_TRY( iv_pDecoder->iv_module_decoder->b_side_clk_output_driver(l_b_side_output_drive) ); FAPI_INF( "%s: Retrieved register output drive for clock, b-side (Y0,Y2): %d, a-side (Y1,Y3): %d", - c_str(i_target), l_b_side_output_drive, l_a_side_output_drive ); + mss::c_str(i_target), l_b_side_output_drive, l_a_side_output_drive ); { // Buffer insert constants for ODT and CKE output drive @@ -1018,7 +1026,7 @@ fapi2::ReturnCode eff_config::dimm_rc05(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc05[l_port_num][l_dimm_num] = l_buffer; - FAPI_INF( "%s: RC05 setting: %d", c_str(i_target), l_attrs_dimm_rc05[l_port_num][l_dimm_num] ) + FAPI_INF( "%s: RC05 setting: %d", mss::c_str(i_target), l_attrs_dimm_rc05[l_port_num][l_dimm_num] ) FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC05, l_mcs, l_attrs_dimm_rc05) ); fapi_try_exit: @@ -1047,7 +1055,7 @@ fapi2::ReturnCode eff_config::dimm_rc06_07(const fapi2::Target // Update MCS attribute l_attrs_dimm_rc06_07[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc06_07; - FAPI_INF( "%s: RC06_07 setting: %d", c_str(i_target), l_attrs_dimm_rc06_07[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC06_07 setting: %d", mss::c_str(i_target), l_attrs_dimm_rc06_07[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC06_07, l_mcs, l_attrs_dimm_rc06_07) ); fapi_try_exit: @@ -1076,7 +1084,7 @@ fapi2::ReturnCode eff_config::dimm_rc08(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc08[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc08; - FAPI_INF( "%s: RC08 setting: %d", c_str(i_target), l_attrs_dimm_rc08[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC08 setting: %d", mss::c_str(i_target), l_attrs_dimm_rc08[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC08, l_mcs, l_attrs_dimm_rc08) ); fapi_try_exit: @@ -1107,7 +1115,7 @@ fapi2::ReturnCode eff_config::dimm_rc09(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc09[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc09; - FAPI_INF( "%s: RC09 setting: %d", c_str(i_target), l_attrs_dimm_rc09[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC09 setting: %d", mss::c_str(i_target), l_attrs_dimm_rc09[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC09, l_mcs, l_attrs_dimm_rc09) ); fapi_try_exit: @@ -1162,7 +1170,7 @@ fapi2::ReturnCode eff_config::dimm_rc10(const fapi2::Target& i break; } - FAPI_INF( "%s: RC10 setting: %d", c_str(i_target), l_attrs_dimm_rc10[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC10 setting: %d", mss::c_str(i_target), l_attrs_dimm_rc10[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC10, l_mcs, l_attrs_dimm_rc10) ); fapi_try_exit: @@ -1191,7 +1199,7 @@ fapi2::ReturnCode eff_config::dimm_rc11(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc11[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc0b; - FAPI_INF( "%s: RC11 setting: %d", c_str(i_target), l_attrs_dimm_rc11[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC11 setting: %d", mss::c_str(i_target), l_attrs_dimm_rc11[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC11, l_mcs, l_attrs_dimm_rc11) ); fapi_try_exit: @@ -1220,7 +1228,7 @@ fapi2::ReturnCode eff_config::dimm_rc12(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc12[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc0c; - FAPI_INF( "%s: R12 setting: %d", c_str(i_target), l_attrs_dimm_rc12[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: R12 setting: %d", mss::c_str(i_target), l_attrs_dimm_rc12[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC12, l_mcs, l_attrs_dimm_rc12) ); fapi_try_exit: @@ -1285,7 +1293,7 @@ fapi2::ReturnCode eff_config::dimm_rc13(const fapi2::Target& i FAPI_TRY( spd::base_module_type(i_target, iv_pDecoder->iv_spd_data, l_dimm_type) ); l_attrs_dimm_rc13[l_port_num][l_dimm_num] = l_buffer; - FAPI_INF( "%s: RC13 setting: %d", c_str(i_target), l_attrs_dimm_rc13[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC13 setting: %d", mss::c_str(i_target), l_attrs_dimm_rc13[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC13, l_mcs, l_attrs_dimm_rc13) ); fapi_try_exit: @@ -1314,7 +1322,7 @@ fapi2::ReturnCode eff_config::dimm_rc14(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc14[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc0e; - FAPI_INF( "%s: RC14 setting: 0x%0x", c_str(i_target), l_attrs_dimm_rc14[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC14 setting: 0x%0x", mss::c_str(i_target), l_attrs_dimm_rc14[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC14, l_mcs, l_attrs_dimm_rc14) ); fapi_try_exit: @@ -1343,7 +1351,7 @@ fapi2::ReturnCode eff_config::dimm_rc15(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc15[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc0f; - FAPI_INF( "%s: RC15 setting: %d", c_str(i_target), l_attrs_dimm_rc15[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC15 setting: %d", mss::c_str(i_target), l_attrs_dimm_rc15[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC15, l_mcs, l_attrs_dimm_rc15) ); fapi_try_exit: @@ -1372,7 +1380,7 @@ fapi2::ReturnCode eff_config::dimm_rc1x(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc_1x[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc1x; - FAPI_INF( "%s: RC1X setting: %d", c_str(i_target), l_attrs_dimm_rc_1x[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC1X setting: %d", mss::c_str(i_target), l_attrs_dimm_rc_1x[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC_1x, l_mcs, l_attrs_dimm_rc_1x) ); fapi_try_exit: @@ -1401,7 +1409,7 @@ fapi2::ReturnCode eff_config::dimm_rc2x(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc_2x[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc2x; - FAPI_INF( "%s: RC2X setting: %d", c_str(i_target), l_attrs_dimm_rc_2x[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC2X setting: %d", mss::c_str(i_target), l_attrs_dimm_rc_2x[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC_2x, l_mcs, l_attrs_dimm_rc_2x) ); fapi_try_exit: @@ -1456,7 +1464,7 @@ fapi2::ReturnCode eff_config::dimm_rc3x(const fapi2::Target& i break; } - FAPI_INF( "%s: RC3X setting: %d", c_str(i_target), l_attrs_dimm_rc_3x[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC3X setting: %d", mss::c_str(i_target), l_attrs_dimm_rc_3x[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC_3x, l_mcs, l_attrs_dimm_rc_3x) ); @@ -1486,7 +1494,7 @@ fapi2::ReturnCode eff_config::dimm_rc4x(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc_4x[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc4x; - FAPI_INF( "%s: RC4X setting: %d", c_str(i_target), l_attrs_dimm_rc_4x[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC4X setting: %d", mss::c_str(i_target), l_attrs_dimm_rc_4x[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC_4x, l_mcs, l_attrs_dimm_rc_4x) ); fapi_try_exit: @@ -1515,7 +1523,7 @@ fapi2::ReturnCode eff_config::dimm_rc5x(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc_5x[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc5x; - FAPI_INF( "%s: RC5X setting: %d", c_str(i_target), l_attrs_dimm_rc_5x[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC5X setting: %d", mss::c_str(i_target), l_attrs_dimm_rc_5x[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC_5x, l_mcs, l_attrs_dimm_rc_5x) ); fapi_try_exit: @@ -1544,7 +1552,7 @@ fapi2::ReturnCode eff_config::dimm_rc6x(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc_6x[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc6x; - FAPI_INF( "%s: RC6X setting: %d", c_str(i_target), l_attrs_dimm_rc_6x[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC6X setting: %d", mss::c_str(i_target), l_attrs_dimm_rc_6x[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC_6x, l_mcs, l_attrs_dimm_rc_6x) ); fapi_try_exit: @@ -1631,7 +1639,7 @@ fapi2::ReturnCode eff_config::dimm_rc8x(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc_8x[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc8x; - FAPI_INF( "%s: RC8X setting: %d", c_str(i_target), l_attrs_dimm_rc_8x[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC8X setting: %d", mss::c_str(i_target), l_attrs_dimm_rc_8x[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC_8x, l_mcs, l_attrs_dimm_rc_8x) ); fapi_try_exit: @@ -1660,7 +1668,7 @@ fapi2::ReturnCode eff_config::dimm_rc9x(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc_9x[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rc9x; - FAPI_INF( "%s: RC9X setting: %d", c_str(i_target), l_attrs_dimm_rc_9x[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RC9X setting: %d", mss::c_str(i_target), l_attrs_dimm_rc_9x[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC_9x, l_mcs, l_attrs_dimm_rc_9x) ); fapi_try_exit: @@ -1689,7 +1697,7 @@ fapi2::ReturnCode eff_config::dimm_rcax(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc_ax[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rcax; - FAPI_INF( "%s: RCAX setting: %d", c_str(i_target), l_attrs_dimm_rc_ax[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RCAX setting: %d", mss::c_str(i_target), l_attrs_dimm_rc_ax[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC_Ax, l_mcs, l_attrs_dimm_rc_ax) ); fapi_try_exit: @@ -1718,7 +1726,7 @@ fapi2::ReturnCode eff_config::dimm_rcbx(const fapi2::Target& i // Update MCS attribute l_attrs_dimm_rc_bx[l_port_num][l_dimm_num] = iv_pDecoder->iv_raw_card.iv_rcbx; - FAPI_INF( "%s: RCBX setting: %d", c_str(i_target), l_attrs_dimm_rc_bx[l_port_num][l_dimm_num] ); + FAPI_INF( "%s: RCBX setting: %d", mss::c_str(i_target), l_attrs_dimm_rc_bx[l_port_num][l_dimm_num] ); FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_DDR4_RC_Bx, l_mcs, l_attrs_dimm_rc_bx) ); fapi_try_exit: @@ -1736,31 +1744,41 @@ fapi2::ReturnCode eff_config::dram_twr(const fapi2::Target& i_ const auto l_port_num = index(find_target(i_target)); int64_t l_twr_in_ps = 0; - // Calculate twr (in ps) + // Get the tWR timing values + // tWR is speed bin independent and is + // the same for all bins within a speed grade. + // It is safe to read this from SPD because the correct nck + // value will be calulated based on our dimm speed. { constexpr int64_t l_twr_ftb = 0; int64_t l_twr_mtb = 0; int64_t l_ftb = 0; int64_t l_mtb = 0; - FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb) ); - FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); - FAPI_TRY( iv_pDecoder->min_write_recovery_time(i_target, l_twr_mtb) ); - FAPI_INF("Values for write_recovery (twr) in MTB units: medium timebase: %ld, fine timebase: %ld, and min write: %ld", - l_mtb, l_ftb, l_twr_mtb); - l_twr_in_ps = calc_timing_from_timebase(l_twr_mtb, l_mtb, l_twr_ftb, l_ftb); + FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb), + "Failed medium_timebase() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb), + "Failed fine_timebase() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->min_write_recovery_time(i_target, l_twr_mtb), + "Failed min_write_recovery_time() for %s", mss::c_str(i_target) ); + + FAPI_INF("medium timebase (ps): %ld, fine timebase (ps): %ld, tWR (MTB): %ld, tWR(FTB): %ld", + l_mtb, l_ftb, l_twr_mtb, l_twr_ftb); + + // Calculate twr (in ps) + l_twr_in_ps = spd::calc_timing_from_timebase(l_twr_mtb, l_mtb, l_twr_ftb, l_ftb); } { std::vector l_attrs_dram_twr(PORTS_PER_MCS, 0); uint8_t l_twr_in_nck = 0; - FAPI_INF("iv tck is %d", iv_tCK_in_ps); // Calculate tNCK - FAPI_TRY( calc_nck(l_twr_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_twr_in_nck), + FAPI_TRY( spd::calc_nck(l_twr_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_twr_in_nck), "Error in calculating l_twr_in_nck for target %s, with value of l_twr_in_ps: %d", mss::c_str(i_target), l_twr_in_ps); - FAPI_INF("Calculated tWR (ps): %d, tWR (nck): %d for target: %s", l_twr_in_ps, l_twr_in_nck, mss::c_str(i_target)); + FAPI_INF( "tCK (ps): %d, tWR (ps): %d, tWR (nck): %d for target: %s", + iv_tCK_in_ps, l_twr_in_ps, l_twr_in_nck, mss::c_str(i_target) ); // Get & update MCS attribute FAPI_TRY( eff_dram_twr(l_mcs, l_attrs_dram_twr.data()) ); @@ -1885,7 +1903,7 @@ fapi2::ReturnCode eff_config::dram_cwl(const fapi2::Target& i_ .set_VALUE(l_preamble) .set_DIMM_TARGET(i_target), "Target %s VPD_MT_PREAMBLE is invalid (not 1 or 0), value is %d", - c_str(i_target), + mss::c_str(i_target), l_preamble ); FAPI_TRY( mss::freq(l_mcbist, l_freq) ); @@ -1942,7 +1960,7 @@ fapi2::ReturnCode eff_config::dram_lpasr(const fapi2::Target& FAPI_TRY( eff_dram_lpasr(l_mcs, l_attrs_lpasr.data()) ); - l_attrs_lpasr[l_port_num] = fapi2::ENUM_ATTR_EFF_DRAM_LPASR_ASR; + l_attrs_lpasr[l_port_num] = fapi2::ENUM_ATTR_EFF_DRAM_LPASR_MANUAL_EXTENDED; FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_LPASR, l_mcs, @@ -2262,7 +2280,7 @@ fapi2::ReturnCode eff_config::crc_error_clear(const fapi2::Target& i_ int64_t l_ftb = 0; int64_t l_mtb = 0; - FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb) ); - FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); - FAPI_TRY( iv_pDecoder->min_row_precharge_delay_time(i_target, l_trp_mtb) ); - FAPI_TRY( iv_pDecoder->fine_offset_min_trp(i_target, l_trp_ftb) ); + FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb), + "Failed medium_timebase() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb), + "Failed fine_timebase() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->min_row_precharge_delay_time(i_target, l_trp_mtb), + "Failed min_row_precharge_delay_time() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->fine_offset_min_trp(i_target, l_trp_ftb), + "Failed fine_offset_min_trp() for %s", mss::c_str(i_target) ); + + FAPI_INF("medium timebase (ps): %ld, fine timebase (ps): %ld, tRP (MTB): %ld, tRP(FTB): %ld", + l_mtb, l_ftb, l_trp_mtb, l_trp_ftb); - l_trp_in_ps = calc_timing_from_timebase(l_trp_mtb, l_mtb, l_trp_ftb, l_ftb); + l_trp_in_ps = spd::calc_timing_from_timebase(l_trp_mtb, l_mtb, l_trp_ftb, l_ftb); + } + + // SPD spec gives us the minimum... compute our worstcase (maximum) from JEDEC + { + // Declaring as int64_t to fix std::max compile + const int64_t l_trp = mss::ps_to_cycles(i_target, mss::trtp()); + l_trp_in_ps = std::max( l_trp_in_ps , l_trp ); } { @@ -3077,10 +3109,11 @@ fapi2::ReturnCode eff_config::dram_trp(const fapi2::Target& i_ uint8_t l_trp_in_nck = 0; // Calculate nck - FAPI_TRY( calc_nck(l_trp_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_trp_in_nck), + FAPI_TRY( spd::calc_nck(l_trp_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_trp_in_nck), "Error in calculating dram_tRP nck for target %s, with value of l_trp_in_ps: %d", mss::c_str(i_target), l_trp_in_ps); - FAPI_INF("Calculated trp (ps): %d, trp (nck): %d for target: %s", l_trp_in_ps, l_trp_in_nck, mss::c_str(i_target)); + FAPI_INF( "tCK (ps): %d, tRP (ps): %d, tRP (nck): %d for target: %s", + iv_tCK_in_ps, l_trp_in_ps, l_trp_in_nck, mss::c_str(i_target) ); // Get & update MCS attribute FAPI_TRY( eff_dram_trp(l_mcs, l_attrs_dram_trp.data()) ); @@ -3107,31 +3140,43 @@ fapi2::ReturnCode eff_config::dram_trcd(const fapi2::Target& i const auto l_port_num = index(find_target(i_target)); int64_t l_trcd_in_ps = 0; - // Calculate trcd (in ps) + // Calculate tRCD (in ps) + // Get the tRCD timing values + // tRCD is speed bin dependent and has a unique + // value for each speed bin so it is safe to + // read from SPD because the correct nck + // value will be calulated based on our dimm speed. { int64_t l_trcd_mtb = 0; int64_t l_trcd_ftb = 0; int64_t l_ftb = 0; int64_t l_mtb = 0; - FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb) ); - FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); - FAPI_TRY( iv_pDecoder->min_ras_to_cas_delay_time(i_target, l_trcd_mtb) ); - FAPI_TRY( iv_pDecoder->fine_offset_min_trcd(i_target, l_trcd_ftb) ); - FAPI_INF( "trcd values are: min_trcd %d, fine offset is %d", l_trcd_mtb, l_trcd_ftb); - l_trcd_in_ps = calc_timing_from_timebase(l_trcd_mtb, l_mtb, l_trcd_ftb, l_ftb); - } + FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb), + "Failed medium_timebase() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb), + "Failed fine_timebase() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->min_ras_to_cas_delay_time(i_target, l_trcd_mtb), + "Failed min_ras_to_cas_delay_time() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->fine_offset_min_trcd(i_target, l_trcd_ftb), + "Failed fine_offset_min_trcd() for %s", mss::c_str(i_target) ); + FAPI_INF("medium timebase MTB (ps): %ld, fine timebase FTB (ps): %ld, tRCD (MTB): %ld, tRCD (FTB): %ld", + l_mtb, l_ftb, l_trcd_mtb, l_trcd_ftb); + + l_trcd_in_ps = spd::calc_timing_from_timebase(l_trcd_mtb, l_mtb, l_trcd_ftb, l_ftb); + } { std::vector l_attrs_dram_trcd(PORTS_PER_MCS, 0); uint8_t l_trcd_in_nck = 0; // Calculate nck - FAPI_TRY( calc_nck(l_trcd_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_trcd_in_nck), + FAPI_TRY( spd::calc_nck(l_trcd_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_trcd_in_nck), "Error in calculating trcd for target %s, with value of l_trcd_in_ps: %d", mss::c_str(i_target), l_trcd_in_ps); - FAPI_INF("Calculated trcd (ps): %d, trcd (nck): %d for target: %s", l_trcd_in_ps, l_trcd_in_nck, mss::c_str(i_target)); + FAPI_INF("tCK (ps): %d, tRCD (ps): %d, tRCD (nck): %d for target: %s", + iv_tCK_in_ps, l_trcd_in_ps, l_trcd_in_nck, mss::c_str(i_target)); // Get & update MCS attribute FAPI_TRY( eff_dram_trcd(l_mcs, l_attrs_dram_trcd.data()) ); @@ -3147,6 +3192,65 @@ fapi_try_exit: return fapi2::current_err; } +/// +/// @brief Determines & sets effective config for tRC +/// @param[in] i_target FAPI2 target +/// @return fapi2::FAPI2_RC_SUCCESS if okay +/// +fapi2::ReturnCode eff_config::dram_trc(const fapi2::Target& i_target) +{ + const auto l_mcs = find_target(i_target); + const auto l_port_num = index(find_target(i_target)); + int64_t l_trc_in_ps = 0; + + // Calculate trc (in ps) + { + int64_t l_trc_mtb = 0; + int64_t l_trc_ftb = 0; + int64_t l_ftb = 0; + int64_t l_mtb = 0; + + FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb), + "Failed medium_timebase() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb), + "Failed fine_timebase() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->min_active_to_active_refresh_delay_time(i_target, l_trc_mtb), + "Failed min_active_to_active_refresh_delay_time() for %s", mss::c_str(i_target) ); + FAPI_TRY( iv_pDecoder->fine_offset_min_trc(i_target, l_trc_ftb), + "Failed fine_offset_min_trc() for %s", mss::c_str(i_target) ); + + FAPI_INF("medium timebase MTB (ps): %ld, fine timebase FTB (ps): %ld, tRCmin (MTB): %ld, tRCmin(FTB): %ld", + l_mtb, l_ftb, l_trc_mtb, l_trc_ftb); + + l_trc_in_ps = spd::calc_timing_from_timebase(l_trc_mtb, l_mtb, l_trc_ftb, l_ftb); + } + + { + std::vector l_attrs_dram_trc(PORTS_PER_MCS, 0); + uint8_t l_trc_in_nck = 0; + + // Calculate nck + FAPI_TRY( spd::calc_nck(l_trc_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_trc_in_nck), + "Error in calculating trc for target %s, with value of l_trc_in_ps: %d", + mss::c_str(i_target), l_trc_in_ps ); + + FAPI_INF( "tCK (ps): %d, tRC (ps): %d, tRC (nck): %d for target: %s", + iv_tCK_in_ps, l_trc_in_ps, l_trc_in_nck, mss::c_str(i_target) ); + + // Get & update MCS attribute + FAPI_TRY( eff_dram_trc(l_mcs, l_attrs_dram_trc.data()) ); + + l_attrs_dram_trc[l_port_num] = l_trc_in_nck; + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TRC, + l_mcs, + UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_trc, PORTS_PER_MCS)), + "Failed setting attribute for DRAM_TRC"); + } + +fapi_try_exit: + return fapi2::current_err; +} + /// /// @brief Determines & sets effective config for tWTR_L /// @param[in] i_target FAPI2 target @@ -3169,7 +3273,10 @@ fapi2::ReturnCode eff_config::dram_twtr_l(const fapi2::Target& FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); FAPI_TRY( iv_pDecoder->min_twtr_l(i_target, l_twtr_l_mtb) ); - l_twtr_l_in_ps = calc_timing_from_timebase(l_twtr_l_mtb, l_mtb, l_twtr_l_ftb, l_ftb); + FAPI_INF("medium timebase (ps): %ld, fine timebase (ps): %ld, tWTR_S (MTB): %ld, tWTR_S (FTB): %ld", + l_mtb, l_ftb, l_twtr_l_mtb, l_twtr_l_ftb ); + + l_twtr_l_in_ps = spd::calc_timing_from_timebase(l_twtr_l_mtb, l_mtb, l_twtr_l_ftb, l_ftb); } @@ -3177,12 +3284,12 @@ fapi2::ReturnCode eff_config::dram_twtr_l(const fapi2::Target& std::vector l_attrs_dram_twtr_l(PORTS_PER_MCS, 0); int8_t l_twtr_l_in_nck = 0; - // Calculate tNCK - FAPI_TRY( calc_nck(l_twtr_l_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_twtr_l_in_nck), - "Error in calculating twtr_l for target %s, with value of l_twtr_in_ps: %d", mss::c_str(i_target), l_twtr_l_in_ps ); + // Calculate nck + FAPI_TRY( spd::calc_nck(l_twtr_l_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_twtr_l_in_nck), + "Error in calculating tWTR_L for target %s, with value of l_twtr_in_ps: %d", mss::c_str(i_target), l_twtr_l_in_ps ); - FAPI_INF("Calculated twtr_l (ps): %d, twtr_l (nck): %d for target: %s", l_twtr_l_in_ps, l_twtr_l_in_nck, - mss::c_str(i_target)); + FAPI_INF( "tCK (ps): %d, tWTR_L (ps): %d, tWTR_L (nck): %d for target: %s", + iv_tCK_in_ps, l_twtr_l_in_ps, l_twtr_l_in_nck, mss::c_str(i_target) ); // Get & update MCS attribute FAPI_TRY( eff_dram_twtr_l(l_mcs, l_attrs_dram_twtr_l.data()) ); @@ -3220,7 +3327,10 @@ fapi2::ReturnCode eff_config::dram_twtr_s(const fapi2::Target& FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); FAPI_TRY( iv_pDecoder->min_twtr_s(i_target, l_twtr_s_mtb) ); - l_twtr_s_in_ps = calc_timing_from_timebase(l_twtr_s_mtb, l_mtb, l_twtr_s_ftb, l_ftb); + FAPI_INF("medium timebase (ps): %ld, fine timebase (ps): %ld, tWTR_S (MTB): %ld, tWTR_S (FTB): %ld", + l_mtb, l_ftb, l_twtr_s_mtb, l_twtr_s_ftb ); + + l_twtr_s_in_ps = spd::calc_timing_from_timebase(l_twtr_s_mtb, l_mtb, l_twtr_s_ftb, l_ftb); } { @@ -3228,11 +3338,11 @@ fapi2::ReturnCode eff_config::dram_twtr_s(const fapi2::Target& uint8_t l_twtr_s_in_nck = 0; // Calculate nck - FAPI_TRY( calc_nck(l_twtr_s_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_twtr_s_in_nck), - "Error in calculating l_twtr_s for target %s, with value of l_twtr_in_ps: %d", mss::c_str(i_target), l_twtr_s_in_ps); + FAPI_TRY( spd::calc_nck(l_twtr_s_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_twtr_s_in_nck), + "Error in calculating tWTR_S for target %s, with value of l_twtr_in_ps: %d", mss::c_str(i_target), l_twtr_s_in_ps); - FAPI_INF("Calculated twtr_s (ps): %d, twtr_s (nck): %d for target: %s", l_twtr_s_in_ps, l_twtr_s_in_nck, - mss::c_str(i_target)); + FAPI_INF("tCK (ps): %d, tWTR_S (ps): %d, tWTR_S (nck): %d for target: %s", + iv_tCK_in_ps, l_twtr_s_in_ps, l_twtr_s_in_nck, mss::c_str(i_target) ); // Get & update MCS attribute FAPI_TRY( eff_dram_twtr_s(l_mcs, l_attrs_dram_twtr_s.data()) ); @@ -3257,42 +3367,44 @@ fapi2::ReturnCode eff_config::dram_trrd_s(const fapi2::Target& { const auto l_mcs = find_target(i_target); const auto l_port_num = index(find_target(i_target)); - int64_t l_trrd_s_in_ps = 0; - // Calculate trrd_s (in ps) - { - int64_t l_trrd_s_mtb = 0; - int64_t l_trrd_s_ftb = 0; - int64_t l_ftb = 0; - int64_t l_mtb = 0; + std::vector l_attrs_dram_trrd_s(PORTS_PER_MCS, 0); + uint64_t l_trrd_s_in_nck = 0; + uint8_t l_stack_type = 0; + uint8_t l_dram_width = 0; - FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb) ); - FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); - FAPI_TRY( iv_pDecoder->min_trrd_s(i_target, l_trrd_s_mtb) ); - FAPI_TRY( iv_pDecoder->fine_offset_min_trrd_s(i_target, l_trrd_s_ftb) ); + FAPI_TRY( iv_pDecoder->prim_sdram_signal_loading(i_target, l_stack_type) ); + FAPI_TRY( iv_pDecoder->device_width(i_target, l_dram_width), + "Failed to access device_width()"); - l_trrd_s_in_ps = calc_timing_from_timebase(l_trrd_s_mtb, l_mtb, l_trrd_s_ftb, l_ftb); - } + // From the SPD Spec: + // At some frequencies, a minimum number of clocks may be required resulting + // in a larger tRRD_Smin value than indicated in the SPD. + // tRRD_S (3DS) is speed bin independent. + // So we won't read this from SPD and choose the correct value based on mss_freq + if( l_stack_type == fapi2::ENUM_ATTR_EFF_PRIM_STACK_TYPE_3DS) { - std::vector l_attrs_dram_trrd_s(PORTS_PER_MCS, 0); - uint8_t l_trrd_s_in_nck = 0; + FAPI_TRY( trrd_s_slr(i_target, l_trrd_s_in_nck) ); + } + else + { + // Non-3DS + FAPI_TRY( mss::trrd_s(i_target, l_dram_width, l_trrd_s_in_nck) ); + } - // Calculate nck - FAPI_TRY( calc_nck(l_trrd_s_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_trrd_s_in_nck), - "Error in calculating trrd_s for target %s, with value of l_twtr_in_ps: %d", mss::c_str(i_target), l_trrd_s_in_ps); + FAPI_INF("SDRAM width: %d, tRRD_S (nck): %d for target: %s", + l_dram_width, l_trrd_s_in_nck, mss::c_str(i_target)); - FAPI_INF("Calculated trrd_s (ps): %d, trrd_s (nck): %d for target: %s", l_trrd_s_in_ps, l_trrd_s_in_nck, - mss::c_str(i_target)); - // Get & update MCS attribute - FAPI_TRY( eff_dram_trrd_s(l_mcs, l_attrs_dram_trrd_s.data()) ); + // Get & update MCS attribute + FAPI_TRY( eff_dram_trrd_s(l_mcs, l_attrs_dram_trrd_s.data()) ); - l_attrs_dram_trrd_s[l_port_num] = l_trrd_s_in_nck; - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TRRD_S, - l_mcs, - UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_trrd_s, PORTS_PER_MCS)), - "Failed setting attribute for DRAM_TRRD_S"); - } + l_attrs_dram_trrd_s[l_port_num] = l_trrd_s_in_nck; + + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TRRD_S, + l_mcs, + UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_trrd_s, PORTS_PER_MCS)), + "Failed setting attribute for DRAM_TRRD_S"); fapi_try_exit: return fapi2::current_err; @@ -3307,43 +3419,72 @@ fapi2::ReturnCode eff_config::dram_trrd_l(const fapi2::Target& { const auto l_mcs = find_target(i_target); const auto l_port_num = index(find_target(i_target)); - int64_t l_trrd_l_in_ps = 0; - // Calculate trrd_l (in ps) - { - int64_t l_trrd_l_mtb = 0; - int64_t l_trrd_l_ftb = 0; - int64_t l_ftb = 0; - int64_t l_mtb = 0; + std::vector l_attrs_dram_trrd_l(PORTS_PER_MCS, 0); + uint64_t l_trrd_l_in_nck = 0; + uint8_t l_stack_type = 0; + uint8_t l_dram_width = 0; - FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb) ); - FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); - FAPI_TRY( iv_pDecoder->min_trrd_l(i_target, l_trrd_l_mtb) ); - FAPI_TRY( iv_pDecoder->fine_offset_min_trrd_l(i_target, l_trrd_l_ftb) ); + FAPI_TRY( iv_pDecoder->prim_sdram_signal_loading(i_target, l_stack_type), + "Failed prim_sdram_signal_loading()" ); + FAPI_TRY( iv_pDecoder->device_width(i_target, l_dram_width), + "Failed to access device_width()"); - l_trrd_l_in_ps = calc_timing_from_timebase(l_trrd_l_mtb, l_mtb, l_trrd_l_ftb, l_ftb); - } + // From the SPD Spec: + // At some frequencies, a minimum number of clocks may be required resulting + // in a larger tRRD_Smin value than indicated in the SPD. + // tRRD_S (3DS) is speed bin independent. + // So we won't read this from SPD and choose the correct value based on mss_freq + if( l_stack_type == fapi2::ENUM_ATTR_EFF_PRIM_STACK_TYPE_3DS) + { + FAPI_TRY( trrd_l_slr(i_target, l_trrd_l_in_nck) ); + } + else { - std::vector l_attrs_dram_trrd_l(PORTS_PER_MCS, 0); - uint8_t l_trrd_l_in_nck = 0; + FAPI_TRY( mss::trrd_l(i_target, l_dram_width, l_trrd_l_in_nck), "Failed trrd_l()" ); + } - // Calculate nck - FAPI_TRY( calc_nck(l_trrd_l_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_trrd_l_in_nck), - "Error in calculating trrd_l for target %s, with value of l_twtr_in_ps: %d", mss::c_str(i_target), l_trrd_l_in_ps); + FAPI_INF("SDRAM width: %d, tRRD_L (nck): %d for target: %s", + l_dram_width, l_trrd_l_in_nck, mss::c_str(i_target)); - FAPI_INF("Calculated trrd_l (ps): %d, trrd_l (nck): %d for target: %s", l_trrd_l_in_ps, l_trrd_l_in_nck, - mss::c_str(i_target)); + // Get & update MCS attribute + FAPI_TRY( eff_dram_trrd_l(l_mcs, l_attrs_dram_trrd_l.data()) ); - // Get & update MCS attribute - FAPI_TRY( eff_dram_trrd_l(l_mcs, l_attrs_dram_trrd_l.data()) ); + l_attrs_dram_trrd_l[l_port_num] = l_trrd_l_in_nck; + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TRRD_L, + l_mcs, + UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_trrd_l, PORTS_PER_MCS)), + "Failed setting attribute for DRAM_TRRD_L"); - l_attrs_dram_trrd_l[l_port_num] = l_trrd_l_in_nck; - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TRRD_L, - l_mcs, - UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_trrd_l, PORTS_PER_MCS)), - "Failed setting attribute for DRAM_TRRD_L"); - } +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Determines & sets effective config for tRRD_dlr +/// @param[in] i_target FAPI2 target +/// @return fapi2::FAPI2_RC_SUCCESS if okay +/// +fapi2::ReturnCode eff_config::dram_trrd_dlr(const fapi2::Target& i_target) +{ + const auto l_mcs = find_target(i_target); + const auto l_port_num = index(find_target(i_target)); + + std::vector l_attrs_dram_trrd_dlr(PORTS_PER_MCS, 0); + constexpr uint64_t l_trrd_dlr_in_nck = trrd_dlr(); + + FAPI_INF("tRRD_dlr (nck): %d for target: %s", l_trrd_dlr_in_nck, mss::c_str(i_target)); + + // Get & update MCS attribute + FAPI_TRY( eff_dram_trrd_dlr(l_mcs, l_attrs_dram_trrd_dlr.data()) ); + + l_attrs_dram_trrd_dlr[l_port_num] = l_trrd_dlr_in_nck; + + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TRRD_DLR, + l_mcs, + UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_trrd_dlr, PORTS_PER_MCS)), + "Failed setting attribute for DRAM_TRRD_DLR"); fapi_try_exit: return fapi2::current_err; @@ -3358,90 +3499,114 @@ fapi2::ReturnCode eff_config::dram_tfaw(const fapi2::Target& i { const auto l_mcs = find_target(i_target); const auto l_port_num = index(find_target(i_target)); - int64_t l_tfaw_in_ps = 0; - // Calculate tfaw (in ps) - { - constexpr int64_t l_tfaw_ftb = 0; - int64_t l_tfaw_mtb = 0; - int64_t l_ftb = 0; - int64_t l_mtb = 0; + std::vector l_attrs_dram_tfaw(PORTS_PER_MCS, 0); + uint64_t l_tfaw_in_nck = 0; + uint8_t l_stack_type = 0; + uint8_t l_dram_width = 0; - FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb) ); - FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); - FAPI_TRY( iv_pDecoder->min_tfaw(i_target, l_tfaw_mtb) ); + FAPI_TRY( iv_pDecoder->prim_sdram_signal_loading(i_target, l_stack_type), + "Failed prim_sdram_signal_loading()"); + FAPI_TRY( iv_pDecoder->device_width(i_target, l_dram_width), + "Failed device_width()"); - l_tfaw_in_ps = calc_timing_from_timebase(l_tfaw_mtb, l_mtb, l_tfaw_ftb, l_ftb); + if( l_stack_type == fapi2::ENUM_ATTR_EFF_PRIM_STACK_TYPE_3DS) + { + FAPI_TRY( tfaw_slr(i_target, l_dram_width, l_tfaw_in_nck), "Failed tfaw_slr()"); } - + else { - std::vector l_attrs_dram_tfaw(PORTS_PER_MCS, 0); - uint8_t l_tfaw_in_nck = 0; + FAPI_TRY( mss::tfaw(i_target, l_dram_width, l_tfaw_in_nck), "Failed tfaw()" ); + } - // Calculate nck - FAPI_TRY ( calc_nck(l_tfaw_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_tfaw_in_nck), - "Error in calculating tfaw_l for target %s, with value of l_twtr_in_ps: %d", mss::c_str(i_target), l_tfaw_in_ps ); + FAPI_INF("SDRAM width: %d, tFAW (nck): %d for target: %s", + l_dram_width, l_tfaw_in_nck, mss::c_str(i_target)); - FAPI_INF("Calculated tFAW (ps): %d, tFAW (nck): %d for target: %s", l_tfaw_in_ps, l_tfaw_in_nck, mss::c_str(i_target)); + // Get & update MCS attribute + FAPI_TRY( eff_dram_tfaw(l_mcs, l_attrs_dram_tfaw.data()) ); - // Get & update MCS attribute - FAPI_TRY( eff_dram_tfaw(l_mcs, l_attrs_dram_tfaw.data()) ); + l_attrs_dram_tfaw[l_port_num] = l_tfaw_in_nck; - l_attrs_dram_tfaw[l_port_num] = l_tfaw_in_nck; - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TFAW, - l_mcs, - UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_tfaw, PORTS_PER_MCS)), - "Failed setting attribute for DRAM_TFAW"); - } + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TFAW, + l_mcs, + UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_tfaw, PORTS_PER_MCS)), + "Failed setting attribute for DRAM_TFAW"); fapi_try_exit: return fapi2::current_err; } /// -/// @brief Determines & sets effective config for tRAS +/// @brief Determines & sets effective config for tFAW_DLR /// @param[in] i_target FAPI2 target /// @return fapi2::FAPI2_RC_SUCCESS if okay /// -fapi2::ReturnCode eff_config::dram_tras(const fapi2::Target& i_target) +fapi2::ReturnCode eff_config::dram_tfaw_dlr(const fapi2::Target& i_target) { const auto l_mcs = find_target(i_target); const auto l_port_num = index(find_target(i_target)); - int64_t l_tras_in_ps = 0; - // Calculate tras (in ps) - { - constexpr int64_t l_tras_ftb = 0; - int64_t l_tras_mtb = 0; - int64_t l_ftb = 0; - int64_t l_mtb = 0; + std::vector l_attrs_dram_tfaw_dlr(PORTS_PER_MCS, 0); + constexpr uint64_t l_tfaw_dlr_in_nck = tfaw_dlr(); - FAPI_TRY( iv_pDecoder->medium_timebase(i_target, l_mtb) ); - FAPI_TRY( iv_pDecoder->fine_timebase(i_target, l_ftb) ); - FAPI_TRY( iv_pDecoder->min_active_to_precharge_delay_time(i_target, l_tras_mtb) ); + FAPI_INF("tFAW_dlr (nck): %d for target: %s", l_tfaw_dlr_in_nck, mss::c_str(i_target)); - l_tras_in_ps = calc_timing_from_timebase(l_tras_mtb, l_mtb, l_tras_ftb, l_ftb); - } + // Get & update MCS attribute + FAPI_TRY( eff_dram_tfaw_dlr(l_mcs, l_attrs_dram_tfaw_dlr.data()) ); - { - std::vector l_attrs_dram_tras(PORTS_PER_MCS, 0); - int8_t l_tras_in_nck = 0; + l_attrs_dram_tfaw_dlr[l_port_num] = l_tfaw_dlr_in_nck; - // Calculate nck - FAPI_TRY( calc_nck(l_tras_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_tras_in_nck), - "Error in calculating tras_l for target %s, with value of l_twtr_in_ps: %d", mss::c_str(i_target), l_tras_in_ps); + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TFAW_DLR, + l_mcs, + UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_tfaw_dlr, PORTS_PER_MCS)), + "Failed setting attribute for DRAM_TFAW_DLR"); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Determines & sets effective config for tRAS +/// @param[in] i_target FAPI2 target +/// @return fapi2::FAPI2_RC_SUCCESS if okay +/// +fapi2::ReturnCode eff_config::dram_tras(const fapi2::Target& i_target) +{ + const auto l_mcs = find_target(i_target); + const auto l_port_num = index(find_target(i_target)); - FAPI_INF("Calculated tRAS (ps): %d, tRAS (nck): %d for target: %s", l_tras_in_ps, l_tras_in_nck, mss::c_str(i_target)); + // tRAS is bin independent so we don't read this from SPD + // which will give the best timing value for the dimm + // (like 2400 MT/s) which may be different than the system + // speed (if we were being limited by VPD or MRW restrictions) + const uint64_t l_tras_in_ps = mss::tras(i_target); - // Get & update MCS attribute - FAPI_TRY( eff_dram_tras(l_mcs, l_attrs_dram_tras.data()) ); + // Calculate nck + std::vector l_attrs_dram_tras(PORTS_PER_MCS, 0); + uint8_t l_tras_in_nck = 0; + + // Cast needed for calculations to be done on the same integral type + // as required by template deduction. We have iv_tCK_in_ps as a signed + // integer because we have other timing values that calculations do + // addition with negative integers. + FAPI_TRY( spd::calc_nck(l_tras_in_ps, + static_cast(iv_tCK_in_ps), + INVERSE_DDR4_CORRECTION_FACTOR, + l_tras_in_nck), + "Error in calculating tras_l for target %s, with value of l_twtr_in_ps: %d", + mss::c_str(i_target), l_tras_in_ps); + + FAPI_INF("tCK (ps): %d, tRAS (ps): %d, tRAS (nck): %d for target: %s", + iv_tCK_in_ps, l_tras_in_ps, l_tras_in_nck, mss::c_str(i_target)); - l_attrs_dram_tras[l_port_num] = l_tras_in_nck; - FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TRAS, - l_mcs, - UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_tras, PORTS_PER_MCS)), - "Failed setting attribute for tRAS"); - } + // Get & update MCS attribute + FAPI_TRY( eff_dram_tras(l_mcs, l_attrs_dram_tras.data()) ); + + l_attrs_dram_tras[l_port_num] = l_tras_in_nck; + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TRAS, + l_mcs, + UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_tras, PORTS_PER_MCS)), + "Failed setting attribute for tRAS"); fapi_try_exit: return fapi2::current_err; @@ -3460,22 +3625,24 @@ fapi2::ReturnCode eff_config::dram_trtp(const fapi2::Target& i // Values from proposed DDR4 Full spec update(79-4A) // Item No. 1716.78C // Page 241 & 246 - constexpr int64_t l_max_trtp_in_ps = 7500; - constexpr int64_t l_min_trtp_in_nck = 4; + int64_t constexpr l_max_trtp_in_ps = trtp(); std::vector l_attrs_dram_trtp(PORTS_PER_MCS, 0); - int64_t l_calc_trtp_in_nck = 0; + uint8_t l_calc_trtp_in_nck = 0; // Calculate nck - FAPI_TRY( calc_nck(l_max_trtp_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_calc_trtp_in_nck), - "Error in calculating trtp for target %s, with value of l_twtr_in_ps: %d", mss::c_str(i_target), l_max_trtp_in_ps); + FAPI_TRY( spd::calc_nck(l_max_trtp_in_ps, iv_tCK_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_calc_trtp_in_nck), + "Error in calculating trtp for target %s, with value of l_twtr_in_ps: %d", + mss::c_str(i_target), l_max_trtp_in_ps); - FAPI_INF("Calculated trtp (nck): %d", l_calc_trtp_in_nck); + FAPI_INF("tCK (ps): %d, tRTP (ps): %d, tRTP (nck): %d", + iv_tCK_in_ps, l_max_trtp_in_ps, l_calc_trtp_in_nck); // Get & update MCS attribute FAPI_TRY( eff_dram_trtp(l_mcs, l_attrs_dram_trtp.data()) ); - l_attrs_dram_trtp[l_port_num] = uint8_t( std::max(l_min_trtp_in_nck, l_calc_trtp_in_nck) ); + l_attrs_dram_trtp[l_port_num] = l_calc_trtp_in_nck; + FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_TRTP, l_mcs, UINT8_VECTOR_TO_1D_ARRAY(l_attrs_dram_trtp, PORTS_PER_MCS)), @@ -3505,7 +3672,7 @@ fapi2::ReturnCode eff_config::decode_vpd(const fapi2::Target& i // We need to set up all VPD info before calling getVPD, the API assumes this // For MR we need to tell the VPDInfo the frequency (err ... mt/s - why is this mhz?) FAPI_TRY( mss::freq(find_target(i_target), l_vpd_info.iv_freq_mhz) ); - FAPI_INF("%s. VPD info - dimm data rate: %d MT/s", c_str(i_target), l_vpd_info.iv_freq_mhz); + FAPI_INF("%s. VPD info - dimm data rate: %d MT/s", mss::c_str(i_target), l_vpd_info.iv_freq_mhz); // Make sure to create 0 filled blobs for all the possible blobs, not just for the // chiplets which are configured. This prevents the decoder from accessing nullptrs @@ -3542,7 +3709,7 @@ fapi2::ReturnCode eff_config::decode_vpd(const fapi2::Target& i l_vpd_info.iv_rank_count_dimm_1 = l_rank_count_dimm[1]; FAPI_INF("%s. VPD info - rank count for dimm_0: %d, dimm_1: %d", - c_str(i_target), l_vpd_info.iv_rank_count_dimm_0, l_vpd_info.iv_rank_count_dimm_1); + mss::c_str(i_target), l_vpd_info.iv_rank_count_dimm_0, l_vpd_info.iv_rank_count_dimm_1); // Get the MCS blob for this specific rank combination *only if* we have DIMM. Remember, // Cronus can give us functional MCA which have no DIMM - and we'd puke getting the VPD. diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.H b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.H index e3613c20b..a85ed96d3 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/eff_config.H @@ -56,20 +56,24 @@ namespace mss /// class eff_config { - private: - - int64_t iv_tCK_in_ps; - public: //TK - Make this constructor take this as param - AAM std::shared_ptr iv_pDecoder; + int64_t iv_tCK_in_ps; + + // Assists testing with write ability on these MRW + // settings that are normally NOT writable + // using attribute accessors + // Could create getters & setters... + uint8_t iv_refresh_mode; + uint8_t iv_temp_refresh_range; //TODO: RTC 159777: Change eff_config class to use iv's for mcs, port and dimm position /// /// @brief Constructor - /// @param[in] i_target, the fapi2::Target which we're configuring (DIMM) - /// @param[out] o_rc, a return code which determines the success of the constructor + /// @param[in] i_target the fapi2::Target which we're configuring (DIMM) + /// @param[out] o_rc a return code which determines the success of the constructor /// eff_config( const fapi2::Target& i_target, fapi2::ReturnCode& o_rc ) { @@ -84,12 +88,15 @@ class eff_config /// /// @brief Constructor /// @param[in] i_target the fapi2::Target which we're configuring (MCS) - /// @param[out] o_rc, a return code which determines the success of the constructor + /// @param[out] o_rc a return code which determines the success of the constructor /// eff_config( const fapi2::Target& i_target, fapi2::ReturnCode& o_rc ) { FAPI_TRY( clock_period(i_target, iv_tCK_in_ps), "Failed to calculate clock period (tCK)" ); - FAPI_INF("Calculated clock period (tCK): %d on DIMM %s", iv_tCK_in_ps, mss::c_str(i_target)); + FAPI_TRY( mss::mrw_temp_refresh_range(iv_temp_refresh_range), "Failed mrw_temp_refresh_range()" ); + FAPI_TRY( mss::mrw_fine_refresh_mode(iv_refresh_mode), "Failed mrw_fine_refresh_mode()" ); + + FAPI_INF( "Calculated clock period - tCK (ps): %d for %s", iv_tCK_in_ps, mss::c_str(i_target) ); fapi_try_exit: o_rc = fapi2::current_err; @@ -147,21 +154,21 @@ class eff_config /// @param[in] i_target FAPI2 target /// @return fapi2::FAPI2_RC_SUCCESS if okay /// - fapi2::ReturnCode refresh_interval_time(const fapi2::Target& i_target); + fapi2::ReturnCode dram_trefi(const fapi2::Target& i_target); /// /// @brief Determines & sets effective config for refresh cycle time (tRFC) /// @param[in] i_target FAPI2 target /// @return fapi2::FAPI2_RC_SUCCESS if okay /// - fapi2::ReturnCode refresh_cycle_time(const fapi2::Target& i_target); + fapi2::ReturnCode dram_trfc(const fapi2::Target& i_target); /// /// @brief Determines & sets effective config for refresh cycle time (logical ranks) (tRFC_DLR) /// @param[in] i_target FAPI2 target /// @return fapi2::FAPI2_RC_SUCCESS if okay /// - fapi2::ReturnCode refresh_cycle_time_dlr(const fapi2::Target& i_target); + fapi2::ReturnCode dram_trfc_dlr(const fapi2::Target& i_target); /// /// @brief Determines & sets effective config for dram density @@ -704,6 +711,13 @@ class eff_config /// fapi2::ReturnCode dram_trcd(const fapi2::Target& i_target); + /// + /// @brief Determines & sets effective config for tRC + /// @param[in] i_target FAPI2 target + /// @return fapi2::FAPI2_RC_SUCCESS if okay + /// + fapi2::ReturnCode dram_trc(const fapi2::Target& i_target); + /// /// @brief Determines & sets effective config for tWTR_L /// @param[in] i_target FAPI2 target @@ -719,26 +733,40 @@ class eff_config fapi2::ReturnCode dram_twtr_s(const fapi2::Target& i_target); /// - /// @brief Determines & sets effective config for tRRD_S + /// @brief Determines & sets effective config for tRRD_S (tRRD_S_slr) /// @param[in] i_target FAPI2 target /// @return fapi2::FAPI2_RC_SUCCESS if okay /// fapi2::ReturnCode dram_trrd_s(const fapi2::Target& i_target); /// - /// @brief Determines & sets effective config for tRRD_L + /// @brief Determines & sets effective config for tRRD_L (or tRRD_L_slr) /// @param[in] i_target FAPI2 target /// @return fapi2::FAPI2_RC_SUCCESS if okay /// fapi2::ReturnCode dram_trrd_l(const fapi2::Target& i_target); /// - /// @brief Determines & sets effective config for tfaw + /// @brief Determines & sets effective config for tRRD_DLR + /// @param[in] i_target FAPI2 target + /// @return fapi2::FAPI2_RC_SUCCESS if okay + /// + fapi2::ReturnCode dram_trrd_dlr(const fapi2::Target& i_target); + + /// + /// @brief Determines & sets effective config for tFAW (or tFAW_slr) /// @param[in] i_target FAPI2 target /// @return fapi2::FAPI2_RC_SUCCESS if okay /// fapi2::ReturnCode dram_tfaw(const fapi2::Target& i_target); + /// + /// @brief Determines & sets effective config for tFAW_DLR + /// @param[in] i_target FAPI2 target + /// @return fapi2::FAPI2_RC_SUCCESS if okay + /// + fapi2::ReturnCode dram_tfaw_dlr(const fapi2::Target& i_target); + /// /// @brief Determines & sets effective config for tRAS /// @param[in] i_target FAPI2 target diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C index e87a0457e..82ef939d1 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C @@ -30,6 +30,12 @@ namespace mss { +enum temp_mode : uint8_t +{ + NORMAL = 1, + EXTENDED = 2, +}; + // Proposed DDR4 Full spec update(79-4B) // Item No. 1716.78C // pg.46 @@ -81,9 +87,9 @@ static const std::vector > TRFC_DLR4 = /// fapi2::ReturnCode calc_trefi( const refresh_rate i_mode, const uint8_t i_temp_refresh_range, - int64_t& o_timing ) + uint64_t& o_timing ) { - int64_t l_multiplier = 0; + uint64_t l_multiplier = 0; switch(i_temp_refresh_range) { @@ -104,8 +110,8 @@ fapi2::ReturnCode calc_trefi( const refresh_rate i_mode, break; } - const int64_t l_quotient = TREFI_BASE / ( int64_t(i_mode) * l_multiplier ); - const int64_t l_remainder = TREFI_BASE % ( int64_t(i_mode) * l_multiplier ); + const uint64_t l_quotient = TREFI_BASE / ( int64_t(i_mode) * l_multiplier ); + const uint64_t l_remainder = TREFI_BASE % ( int64_t(i_mode) * l_multiplier ); o_timing = l_quotient + (l_remainder == 0 ? 0 : 1); FAPI_INF( "tREFI: %d, quotient: %d, remainder: %d, tREFI_base: %d", diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H index 6dfb94227..9180aaa9c 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H @@ -43,7 +43,7 @@ namespace mss { -enum GUARD_BAND : uint16_t +enum guard_band : uint16_t { // Used for caclulating spd timing values - from JEDEC rounding algorithm // Correction factor is 1% (for DDR3) or 2.5% (for DDR4) @@ -61,11 +61,8 @@ enum class refresh_rate : uint8_t REF4X = 4, }; -enum temp_mode : uint8_t +namespace spd { - NORMAL = 1, - EXTENDED = 2, -}; /// /// @brief Calculates timing value @@ -88,50 +85,142 @@ inline int64_t calc_timing_from_timebase(const int64_t i_timing_mtb, } /// -/// @brief Returns clock cycles -/// @tparam T input -/// @tparam OT output -/// @param[in] timing_in_ps timing parameter in ps -/// @param[in] tck_in_ps clock period in ps -/// @param[in] inverse_corr_factor inverse correction factor (defined by JEDEC) +/// @brief Helper to compute JEDEC's SPD rounding algorithm +/// to convert ps to nCK +/// @tparam T input type +/// @tparam OT output type +/// @param[in] i_timing_in_ps timing parameter in ps +/// @param[in] i_tck_in_ps clock period in ps +/// @param[in] i_inverse_corr_factor inverse correction factor (defined by JEDEC) /// @param[out] o_value_nck the end calculation in nck -/// @return the clock cycles of timing parameter (provided in ps) +/// @return true if overflow didn't occur, false otherwise /// @note DDR4 SPD Contents Rounding Algorithm /// @note Item 2220.46 /// template -inline fapi2::ReturnCode calc_nck(const T& i_timing_in_ps, - const T& i_tck_in_ps, - GUARD_BAND i_inverse_corr_factor, - OT& o_val_nck) +static inline bool jedec_spd_rounding_alg(const T& i_timing_in_ps, + const T& i_tck_in_ps, + const guard_band i_inverse_corr_factor, + OT& o_val_nck) { // Preliminary nCK calculation, scaled by 1000 per JDEC algorithm - T l_temp_nck = (i_timing_in_ps * 1000) / (i_tck_in_ps == 0 ? 1 : i_tck_in_ps); + T l_temp_nck = (i_timing_in_ps * CONVERT_PS_IN_A_NS) / (i_tck_in_ps == 0 ? 1 : i_tck_in_ps); l_temp_nck += i_inverse_corr_factor; - l_temp_nck = l_temp_nck / 1000; + l_temp_nck = l_temp_nck / CONVERT_PS_IN_A_NS; - //Check for overflow. + // Check for overflow + // static_cast needed for HB compiler that complains about + // comparision of two different integral types o_val_nck = l_temp_nck; - FAPI_ASSERT(o_val_nck == l_temp_nck, - fapi2::MSS_INVALID_CAST_CALC_NCK(). - set_TIMING_PS(i_timing_in_ps). - set_NCK_NS(i_tck_in_ps). - set_CORRECTION_FACTOR(i_inverse_corr_factor), - "Bad cast for calc_nck. Output is: %d, after cast is %d", l_temp_nck, l_temp_nck); - return fapi2::FAPI2_RC_SUCCESS; + FAPI_DBG("Input timing (ps) %d, tCK (ps) %d, temp output %d, output (nCK) %d", + i_timing_in_ps, i_tck_in_ps, l_temp_nck, o_val_nck); + + return (static_cast(o_val_nck) == l_temp_nck); +} + +/// +/// @brief Returns clock cycles based on input application period +/// @tparam T input type +/// @tparam OT output type +/// @param[in] i_timing_in_ps timing parameter in ps +/// @param[in] i_tck_in_ps clock period in ps +/// @param[in] i_inverse_corr_factor inverse correction factor (defined by JEDEC) +/// @param[out] o_value_nck the end calculation in nck +/// @return FAPI2_RC_SUCCESS iff okay +/// @note DDR4 SPD Contents Rounding Algorithm +/// @note Item 2220.46 +/// +template +inline fapi2::ReturnCode calc_nck(const T& i_timing_in_ps, + const T& i_tck_in_ps, + const guard_band i_inverse_corr_factor, + OT& o_val_nck) +{ + FAPI_ASSERT( jedec_spd_rounding_alg(i_timing_in_ps, + i_tck_in_ps, + i_inverse_corr_factor, + o_val_nck), + fapi2::MSS_INVALID_CAST_CALC_NCK(). + set_TIMING_PS(i_timing_in_ps). + set_NCK_NS(i_tck_in_ps). + set_CORRECTION_FACTOR(i_inverse_corr_factor), + "Overflow occured. Returned data is %d", o_val_nck); fapi_try_exit: return fapi2::current_err; } +/// +/// @brief Returns clock cycles form picoseconds based on speed bin +/// Uses SPD rounding algorithm for DDR4 +/// @tparam T the target type from which to get the mt/s +/// @tparam OT the output type, derrived from the parameters +/// @param[in] i_target target for the frequency attribute +/// @param[in] timing_in_ps timing parameter in ps +/// @return the clock cycles of timing parameter (provided in ps) +/// @note Uses DDR4 SPD Contents Rounding Algorithm +/// @note Item 2220.46 +/// +template +inline OT ps_to_nck( const fapi2::Target& i_target, const OT& i_timing_in_ps) +{ + uint64_t l_freq = 0; + OT l_tck_in_ps = 0; + OT l_temp_nck = 0; + + FAPI_TRY( mss::freq( find_target(i_target), l_freq) ); + + // No time if MT/s is 0 (well, infinite really but shut up) + if (l_freq == 0) + { + return 0; + } + + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "Failed freq() accessor" ); + FAPI_TRY( calc_nck(i_timing_in_ps, l_tck_in_ps, INVERSE_DDR4_CORRECTION_FACTOR, l_temp_nck), + "Failed calc_nck()" ); + + return l_temp_nck; + +fapi_try_exit: + // We simply can't work if we can't get the frequency or + // if we get an unsupported value that can't be converted to a valid tCK (clock period) + // ...so this should be ok + FAPI_ERR("Can't get MSS_FREQ, obtained an invalid MSS_FREQ (%d), or overflow occurred - stopping", l_freq); + fapi2::Assert(false); + + // Keeps compiler happy + return 0; +} + +/// +/// @brief Returns clock cycles from nanoseconds +/// Uses SPD rounding algorithm for DDR4 +/// @tparam T the target type from which to get the mt/s +/// @tparam OT the output type, derrived from the parameters +/// @param[in] timing_in_ps timing parameter in ps +/// @param[out] o_value_nck the end calculation in nck +/// @return the clock cycles of timing parameter (provided in ps) +/// @note Uses DDR4 SPD Contents Rounding Algorithm +/// @note Item 2220.46 +/// +template +inline OT ns_to_nck( const fapi2::Target& i_target, const OT& i_timing_in_ns) +{ + return ps_to_nck(i_target, i_timing_in_ns * CONVERT_PS_IN_A_NS); +} + +}// spd + /// /// @brief Returns application clock period (tCK) based on dimm transfer rate /// @tparam T the fapi2 target /// @tparam OT output type /// @param[in] i_target FAPI2 target /// @param[out] o_tCK_in_ps application period in ps -/// @return fapi2::FAPI2_RC_SUCCESS if okay +/// @return fapi2::FAPI2_RC_SUCCESS iff okay /// template inline fapi2::ReturnCode clock_period(const fapi2::Target& i_target, @@ -155,7 +244,7 @@ fapi_try_exit: /// fapi2::ReturnCode calc_trefi( const refresh_rate i_mode, const uint8_t i_temp_refresh_range, - int64_t& o_timing ); + uint64_t& o_timing ); /// /// @brief Calculates Minimum Refresh Recovery Delay Time (different logical rank) @@ -317,37 +406,6 @@ fapi_try_exit: return 0; } -/// -/// @brief Refresh cycle time -/// @param[in] i_target the DIMM target used to get clocks (needed to know the stack type) -/// @param[out] o_trfc the trfc *in clocks* -/// @return FAPI2_RC_SUCCESS iff ok -/// -inline fapi2::ReturnCode trfc( const fapi2::Target& i_target, uint16_t& o_trfc ) -{ - // Pull down the 3DS attribute. If we have a stack we need to use - // tRFC_DLR if not we pull down TRFC and use that. - uint8_t l_stack = 0; - - FAPI_TRY( mss::eff_prim_stack_type(i_target, l_stack) ); - - if (l_stack == fapi2::ENUM_ATTR_EFF_PRIM_STACK_TYPE_3DS) - { - uint8_t l_value = 0; - FAPI_TRY( mss::eff_dram_trfc_dlr(i_target, l_value) ); - o_trfc = l_value; - } - else - { - FAPI_TRY( mss::eff_dram_trfc(i_target, o_trfc) ); - } - - return fapi2::FAPI2_RC_SUCCESS; - -fapi_try_exit: - return fapi2::current_err; -} - /// /// @brief Direct ODT turn on Latency /// @param[in] i_target the DIMM target used to get attributes @@ -465,5 +523,781 @@ fapi_try_exit: return fapi2::current_err; } +/// +/// @brief tRTP *in ps* +/// @return constexpr value of RTP = 7500 ps +/// +constexpr uint64_t trtp() +{ + // Per JEDEC spec, defaults to 7500 ps for all frequencies. + // (technically max of 7.5 ns or 4 nclk, which is always 7.5ns for DDR4) + return 7500; +} + +/// +/// @brief Return the minimum allowable tRAS in picoseconds +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @return value in picoseconds +/// +template< fapi2::TargetType T > +inline uint64_t tras(const fapi2::Target& i_target) +{ + uint64_t l_freq = 0; + uint64_t l_tras = 0; + + // Frequency is used to determine tRAS + FAPI_TRY( freq(mss::find_target(i_target), l_freq) ); + + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + l_tras = 34000; + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + l_tras = 33000; + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + l_tras = 32000; + break; + + default: + FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), l_freq); + } + + return l_tras; + +fapi_try_exit: + + // We simply can't work if we can't get the frequency or + // if we get an unsupported value that can't be converted to a valid tCK (clock period) + // ...so this should be ok + FAPI_ERR("Can't get MSS_FREQ or obtained an invalid MSS_FREQ (%d) - stopping", l_freq); + fapi2::Assert(false); + + // Keeps compiler happy + return 0; +} + +/// +/// @brief Helper function to find tFAW based speed (MT/s) for 1/2 KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode tfaw_half_kb_page_helper(const fapi2::Target& i_target, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability. + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(l_freq) + { + // static_cast is needed for template deduction of std::max API + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + o_output = std::max( 16, spd::ns_to_nck(i_target, 17) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + o_output = std::max( 16, spd::ns_to_nck(i_target, 15) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + o_output = std::max( 16, spd::ns_to_nck(i_target, 13) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + o_output = std::max( 16, spd::ns_to_nck(i_target, 12) ); + break; + + default: + FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), l_freq); + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tFAW based speed (MT/s) for 1KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode tfaw_1kb_page_helper(const fapi2::Target& i_target, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability (and ease of debug?). + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + o_output = std::max( 20, spd::ns_to_nck(i_target, 23) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + o_output = std::max( 20, spd::ns_to_nck(i_target, 21) ); + break; + + default: + FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), l_freq); + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tFAW based speed (MT/s) for 2KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode tfaw_2kb_page_helper(const fapi2::Target& i_target, + uint64_t& o_output) +{ + + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability. + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + o_output = std::max( 28, spd::ns_to_nck(i_target, 30) ); + break; + + default: + FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), l_freq); + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Return the minimum allowable tFAW in nck +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_dram_width the page size +/// @param[out] o_tFAW timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +// +template< fapi2::TargetType T > +fapi2::ReturnCode tfaw( const fapi2::Target& i_target, + const uint8_t i_dram_width, + uint64_t& o_tFAW ) +{ + switch(i_dram_width) + { + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4: + FAPI_TRY( tfaw_half_kb_page_helper(i_target, o_tFAW) ); + break; + + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8: + FAPI_TRY( tfaw_1kb_page_helper(i_target, o_tFAW) ); + break; + + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16: + FAPI_TRY( tfaw_2kb_page_helper(i_target, o_tFAW) ); + break; + + default: + FAPI_ERR("%s Recieved an invalid page size: %lu", mss::c_str(i_target), i_dram_width); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tFAW_slr_x4 based on speed (MT/s) +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for 3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode tfaw_slr_x4_helper(const fapi2::Target& i_target, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability. + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + o_output = spd::ns_to_nck(i_target, 17); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + o_output = spd::ns_to_nck(i_target, 15); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + o_output = spd::ns_to_nck(i_target, 13); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + FAPI_ERR("2666 MT/s is TBD from the DDR3 3DS spec"); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + + default: + FAPI_ERR( "%s: Invalid frequency received (%d)", c_str(i_target), l_freq ); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tFAW_slr_x8 based on speed (MT/s) +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for 3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode tfaw_slr_x8_helper(const fapi2::Target& i_target, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + FAPI_INF("Fetching timing value for %d MT/s"); + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability. + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + o_output = spd::ns_to_nck(i_target, 23); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + o_output = spd::ns_to_nck(i_target, 21); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + FAPI_ERR("2666 MT/s is TBD from the DDR3 3DS spec"); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + + default: + FAPI_ERR( "%s: Invalid frequency received (%d)", c_str(i_target), l_freq ); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Return the minimum allowable tFAW in nck +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_page_size the page size +/// @param[out] o_tFAW timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +// +template< fapi2::TargetType T > +fapi2::ReturnCode tfaw_slr( const fapi2::Target& i_target, + const uint8_t i_dram_width, + uint64_t& o_tFAW ) +{ + if( i_dram_width == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4 ) + { + FAPI_TRY( tfaw_slr_x4_helper(i_target, o_tFAW) ); + } + else + { + FAPI_TRY( tfaw_slr_x8_helper(i_target, o_tFAW) ); + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief tFAW_dlr *in nck* +/// @return 16nck +/// @note From DDR4 3DS Spec +/// 12.2 Timing Parameters by Speed Grade +/// +constexpr uint64_t tfaw_dlr() +{ + return 16; +} + +/// +/// @brief tRRD_dlr *in nck* +/// @return 4nck +/// @note From DDR4 3DS Spec +/// 12.2 Timing Parameters by Speed Grade +/// +constexpr uint64_t trrd_dlr() +{ + return 4; +} + +/// +/// @brief Find tRRD_S_slr in nck +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for 3DS DIMM +/// +template< fapi2::TargetType T > +fapi2::ReturnCode trrd_s_slr(const fapi2::Target& i_target, + uint64_t& o_output) +{ + + // Values derived from DDR4 3DS Spec + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability. + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + o_output = std::max( 4, spd::ps_to_nck(i_target, 4200) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + o_output = std::max( 4, spd::ps_to_nck(i_target, 3700) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + o_output = std::max( 4, spd::ps_to_nck(i_target, 3300) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + FAPI_ERR("2666 MT/s is TBD from the DDR3 3DS spec"); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + + default: + FAPI_ERR( "%s: Invalid frequency received (%d)", c_str(i_target), l_freq ); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Find tRRD_L_slr in nck +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for 3DS DIMM +/// +template< fapi2::TargetType T > +fapi2::ReturnCode trrd_l_slr(const fapi2::Target& i_target, + uint64_t& o_output) +{ + + // Values derived from DDR4 3DS Spec + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability. + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + o_output = std::max( 4, spd::ps_to_nck(i_target, 5300) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + o_output = std::max( 4, spd::ps_to_nck(i_target, 4900) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + FAPI_ERR("2666 MT/s is TBD from the DDR4 SPD spec"); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + + default: + FAPI_ERR( "%s: Invalid frequency received (%d)", c_str(i_target), l_freq ); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tRRD_L based speed (MT/s) for 1KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode trrd_l_half_and_1kb_page_helper(const fapi2::Target& i_target, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability (and ease of debug?). + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + // From the spec: Max(4nCK,5.3ns) + o_output = std::max( 4, spd::ps_to_nck(i_target, 5300) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + // Max(4nCK,4.9ns) + o_output = std::max( 4, spd::ps_to_nck(i_target, 4900) ); + break; + + default: + FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), l_freq); + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tRRD_L based speed (MT/s) for 2KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode trrd_l_2kb_page_helper(const fapi2::Target& i_target, + uint64_t& o_output) +{ + + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability (and ease of debug?). + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + o_output = std::max( 4, spd::ps_to_nck(i_target, 6400) ); + break; + + default: + FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), l_freq); + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Return the minimum allowable tRRD_L in nck +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_dram_width the page size +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +fapi2::ReturnCode trrd_l( const fapi2::Target& i_target, + const uint8_t i_dram_width, + uint64_t& o_tRRD_L ) +{ + switch(i_dram_width) + { + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4: + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8: + FAPI_TRY( trrd_l_half_and_1kb_page_helper(i_target, o_tRRD_L) ); + break; + + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16: + FAPI_TRY( trrd_l_2kb_page_helper(i_target, o_tRRD_L) ); + break; + + default: + FAPI_ERR("%s Recieved an invalid page size: %lu", mss::c_str(i_target), i_dram_width); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tRRD_S based speed (MT/s) for 1KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode trrd_s_half_and_1kb_page_helper(const fapi2::Target& i_target, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability (and ease of debug?). + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + o_output = std::max( 4, spd::ns_to_nck(i_target, 4200) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + o_output = std::max( 4, spd::ns_to_nck(i_target, 3700) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + o_output = std::max( 4, spd::ns_to_nck(i_target, 3300) ); + break; + + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + o_output = std::max( 4, spd::ns_to_nck(i_target, 3000) ); + break; + + default: + FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), l_freq); + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tRRD_S based speed (MT/s) for 2KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode trrd_s_2kb_page_helper(const fapi2::Target& i_target, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + uint64_t l_freq = 0; + FAPI_TRY( freq(find_target(i_target), l_freq), + "Failed to invoke freq accessor" ); + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability (and ease of debug?). + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(l_freq) + { + case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: + case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: + o_output = std::max( 4, spd::ps_to_nck(i_target, 5300) ); + break; + + default: + FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), l_freq); + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Return the minimum allowable tRRD_S in nck +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_dram_width the page size +/// @param[out] o_tRRD_S timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +fapi2::ReturnCode trrd_s( const fapi2::Target& i_target, + const uint8_t i_dram_width, + uint64_t& o_tRRD_S ) +{ + switch(i_dram_width) + { + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4: + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8: + FAPI_TRY( trrd_s_half_and_1kb_page_helper(i_target, o_tRRD_S) ); + break; + + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16: + FAPI_TRY( trrd_s_2kb_page_helper(i_target, o_tRRD_S) ); + break; + + default: + FAPI_ERR("%s Recieved an invalid page size: %lu", mss::c_str(i_target), i_dram_width); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + } // mss #endif diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C index 07e4ca4d2..c275c1e0d 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -66,17 +67,19 @@ namespace mss /// @param[in] i_caches decoder caches /// cas_latency::cas_latency(const fapi2::Target& i_target, - const std::map >& i_caches): + const std::map >& i_caches, + fapi2::ReturnCode& o_rc): iv_dimm_list_empty(false), + iv_target(i_target), iv_largest_taamin(0), iv_proposed_tck(0), - iv_common_CL(UINT64_MAX) // Masks out supported CLs + iv_common_cl(UINT64_MAX) // Masks out supported CLs { - const auto l_dimm_list = find_targets(i_target); + const auto l_dimm_list = find_targets(iv_target); if(l_dimm_list.empty()) { - FAPI_INF("cas latency ctor seeing no DIMM on %s", mss::c_str(i_target)); + FAPI_INF("cas latency ctor seeing no DIMM on %s", mss::c_str(iv_target)); iv_dimm_list_empty = true; return; } @@ -86,105 +89,169 @@ cas_latency::cas_latency(const fapi2::Target& i_target, const auto l_dimm_pos = pos(l_dimm); // Find decoder factory for this dimm position + // Can't be const auto because HB needs to implement + // something - AAM auto l_it = i_caches.find(l_dimm_pos); FAPI_TRY( check::spd::invalid_cache(l_dimm, l_it != i_caches.end(), l_dimm_pos), - "Failed to get valid cache"); + "%s. Failed to get valid cache", mss::c_str(iv_target) ); { // Retrive timing values from the SPD - uint64_t l_tAAmin_in_ps = 0; - uint64_t l_tCKmax_in_ps = 0; - uint64_t l_tCKmin_in_ps = 0; + uint64_t l_taa_min_in_ps = 0; + uint64_t l_tckmax_in_ps = 0; + uint64_t l_tck_min_in_ps = 0; - FAPI_TRY( get_taamin(l_dimm, l_it->second, l_tAAmin_in_ps), - "Failed to get tAAmin"); - FAPI_TRY( get_tckmax(l_dimm, l_it->second, l_tCKmax_in_ps), - "Failed to get tCKmax" ); - FAPI_TRY( get_tckmin(l_dimm, l_it->second, l_tCKmin_in_ps), - "Failed to get tCKmin"); + FAPI_TRY( get_taamin(l_dimm, l_it->second, l_taa_min_in_ps), + "%s. Failed to get tAAmin", mss::c_str(iv_target) ); + FAPI_TRY( get_tckmax(l_dimm, l_it->second, l_tckmax_in_ps), + "%s. Failed to get tCKmax", mss::c_str(iv_target) ); + FAPI_TRY( get_tckmin(l_dimm, l_it->second, l_tck_min_in_ps), + "%s. Failed to get tCKmin", mss::c_str(iv_target) ); // Determine largest tAAmin value - iv_largest_taamin = std::max(iv_largest_taamin, l_tAAmin_in_ps); + iv_largest_taamin = std::max(iv_largest_taamin, l_taa_min_in_ps); // Determine a proposed tCK value that is greater than or equal tCKmin // But less than tCKmax - iv_proposed_tck = std::max(iv_proposed_tck, l_tCKmin_in_ps); - iv_proposed_tck = std::min(iv_proposed_tck, l_tCKmax_in_ps); + iv_proposed_tck = std::max(iv_proposed_tck, l_tck_min_in_ps); + iv_proposed_tck = std::min(iv_proposed_tck, l_tckmax_in_ps); + } + + // Collecting stack type + // If I have at least one 3DS DIMM connected I have + // to use 3DS tAAmax of 21.5 ps versus 18 ps for non-3DS DDR4 + if( iv_is_3ds != loading::IS_3DS) + { + uint8_t l_stack_type = 0; + FAPI_TRY( l_it->second->prim_sdram_signal_loading(l_dimm, l_stack_type) ); + + // Is there a more algorithmic efficient approach? - AAM + iv_is_3ds = (l_stack_type == fapi2::ENUM_ATTR_EFF_PRIM_STACK_TYPE_3DS) ? + loading::IS_3DS : loading::NOT_3DS; } { // Retrieve dimm supported cas latencies from SPD - uint64_t l_dimm_supported_CL = 0; + uint64_t l_dimm_supported_cl = 0; FAPI_TRY( l_it->second->supported_cas_latencies(l_dimm, - l_dimm_supported_CL), - "Failed to get supported CAS latency"); + l_dimm_supported_cl), + "%s. Failed to get supported CAS latency", mss::c_str(iv_target) ); - // ANDing bitmap from all modules creates a bitmap w/a common CL - iv_common_CL &= l_dimm_supported_CL; + // Bitwise ANDING the bitmap from all modules creates a bitmap w/a common CL + iv_common_cl &= l_dimm_supported_cl; } }// dimm + // Limit tCK from the max supported dimm speed in the system + // So that this is taken into account when calculating CL + { + // Defaulting to non-zero speed + uint64_t l_freq_override = fapi2::ENUM_ATTR_MSS_FREQ_MT2666; + uint64_t l_tck_override_in_ps = 0; + + FAPI_TRY( select_supported_freq(iv_target, l_freq_override), + "%s. Failed select_supported_freq()", mss::c_str(iv_target) ); + FAPI_TRY( freq_to_ps(l_freq_override, l_tck_override_in_ps), + "%s. Failed freq_to_ps()", mss::c_str(iv_target) ); + + FAPI_INF("%s. Selected supported dimm speed %d MT/s (Clock period %d in ps)", + mss::c_str(iv_target), l_freq_override, l_tck_override_in_ps); + + iv_proposed_tck = std::max( l_tck_override_in_ps, iv_proposed_tck ); + FAPI_INF("%s. Initial proposed tCK in ps: %d", mss::c_str(iv_target), iv_proposed_tck); + } + // Why didn't I encapsulate common CL operations and checking in a function // like the timing params? Well, I want to check the "final" common CL and - // the creation of common CLs (ANDing bits) is dimm level operation - FAPI_ASSERT(iv_common_CL != 0, + // the creation of common CLs (bitwise ANDING) is at the dimm level operation + FAPI_ASSERT(iv_common_cl != 0, fapi2::MSS_NO_COMMON_SUPPORTED_CL(). - set_CL_SUPPORTED(iv_common_CL). - set_MCS_TARGET(i_target), - "No common CAS latencies (CL bitmap = 0)"); + set_CL_SUPPORTED(iv_common_cl). + set_MCS_TARGET(iv_target), + "%s. No common CAS latencies (CL bitmap = 0)", + mss::c_str(iv_target) ); - FAPI_DBG("Supported CL bitmap 0x%llX", iv_common_CL); + FAPI_INF("%s. Supported CL bitmap 0x%llX", mss::c_str(iv_target), iv_common_cl); - // If we reach here al instance vars should have successfully initialized + // If we reach here all member vars should have successfully initialized + o_rc = fapi2::FAPI2_RC_SUCCESS; return; // If we reach here something failed above. fapi_try_exit: - FAPI_ERR("Something went wrong retreiving dimm info"); + o_rc = fapi2::FAPI2_RC_FALSE; + FAPI_ERR("%s. Something went wrong retrieving DIMM info", mss::c_str(iv_target) ); }// ctor /// -/// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec. +/// @brief Constructor that allows the user to set desired data in lieu of SPD /// @param[in] i_target the controller target +/// @param[in] i_taa_min largest tAAmin we want to set in picoseconds +/// @param[in] i_tck_min proposed tCKmin in picoseconds +/// @param[in] i_common_cl_mask common CAS latency mask we want to force (bitmap) +/// @param[in] i_is_3ds boolean for whether this is a 3DS SDRAM, 3DS is true, false otherwise (default) +/// +cas_latency::cas_latency(const fapi2::Target& i_target, + const uint64_t i_taa_min, + const uint64_t i_tck_min, + const uint64_t i_common_cl_mask, + const loading i_is_3ds): + iv_dimm_list_empty(false), + iv_target(i_target), + iv_largest_taamin(i_taa_min), + iv_proposed_tck(i_tck_min), + iv_common_cl(i_common_cl_mask), + iv_is_3ds(i_is_3ds) +{ + const auto l_dimm_list = find_targets(iv_target); + + if(l_dimm_list.empty()) + { + FAPI_INF("cas latency ctor seeing no DIMM on %s", mss::c_str(iv_target)); + iv_dimm_list_empty = true; + } +} + +/// +/// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec. /// @param[out] o_cas_latency selected CAS latency -/// @param[out] o_tCK cycle time corresponding to seleted CAS latency +/// @param[out] o_tck cycle time corresponding to selected CAS latency /// @return fapi2::FAPI2_RC_SUCCESS if ok /// -fapi2::ReturnCode cas_latency::find_CL(const fapi2::Target& i_target, - uint64_t& o_cas_latency, - uint64_t& o_tCK) +fapi2::ReturnCode cas_latency::find_cl(uint64_t& o_cas_latency, + uint64_t& o_tck) { uint64_t l_desired_cas_latency = 0; if(!iv_dimm_list_empty) { // Create a vector filled with common CLs from buffer - std::vector l_supported_CLs = create_common_cl_vector(iv_common_CL); + std::vector l_supported_cls = integral_bitmap_to_vector(iv_common_cl); //For a proposed tCK value between tCKmin(all) and tCKmax, determine the desired CAS Latency. - l_desired_cas_latency = calc_cas_latency(iv_largest_taamin, iv_proposed_tck); + FAPI_TRY( calc_cas_latency(iv_largest_taamin, iv_proposed_tck, l_desired_cas_latency), + "%s. Failed to calculate CAS latency", mss::c_str(iv_target) ); //Chose an actual CAS Latency (CLactual) that is greater than or equal to CLdesired //and is supported by all modules on the memory channel - FAPI_TRY( choose_actual_CL(l_supported_CLs, iv_largest_taamin, iv_proposed_tck, l_desired_cas_latency), - "Failed choose_actual_CL()"); + FAPI_TRY( is_cl_supported_in_common(l_supported_cls, l_desired_cas_latency), + "%s. Failed to find a common CAS latency supported among all modules", mss::c_str(iv_target) ); - // Once the calculation of CLactual is completed, the BIOS must also + // Once the calculation of CLactual is completed // verify that this CAS Latency value does not exceed tAAmax. - //If not, choose a lower CL value and repeat until a solution is found. - FAPI_TRY( validate_valid_CL(l_supported_CLs, iv_largest_taamin, iv_proposed_tck, l_desired_cas_latency), - "Failed validate_valid_CL()"); + FAPI_TRY( is_cl_exceeding_taa_max (l_desired_cas_latency, iv_proposed_tck), + "%s. Failed to find a CL value that doesn't exceed tAAmax", mss::c_str(iv_target) ); } // Update output values after all criteria is met // If the MCS has no dimm configured than both // l_desired_latency & iv_proposed_tck is 0 by initialization o_cas_latency = l_desired_cas_latency; - o_tCK = iv_proposed_tck; + o_tck = iv_proposed_tck; fapi_try_exit: return fapi2::current_err; @@ -207,27 +274,32 @@ fapi2::ReturnCode cas_latency::get_taamin(const fapi2::Target& int64_t l_fine_timebase = 0; // Retrieve timing parameters - FAPI_TRY( i_pDecoder->medium_timebase(i_target, l_medium_timebase) ); - FAPI_TRY( i_pDecoder->fine_timebase(i_target, l_fine_timebase) ); - FAPI_TRY( i_pDecoder->min_cas_latency_time(i_target, l_timing_mtb) ); - FAPI_TRY( i_pDecoder->fine_offset_min_taa(i_target, l_timing_ftb) ); + FAPI_TRY( i_pDecoder->medium_timebase(i_target, l_medium_timebase), + "%s. Failed medium_timebase()", mss::c_str(iv_target) ); + FAPI_TRY( i_pDecoder->fine_timebase(i_target, l_fine_timebase), + "%s. Failed fine_timebase()", mss::c_str(iv_target) ); + FAPI_TRY( i_pDecoder->min_cas_latency_time(i_target, l_timing_mtb), + "%s. Failed min_cas_latency_time()", mss::c_str(iv_target) ); + FAPI_TRY( i_pDecoder->fine_offset_min_taa(i_target, l_timing_ftb), + "%s. Failed fine_offset_min_taa()", mss::c_str(iv_target) ); // Calculate timing value - o_value = uint64_t(calc_timing_from_timebase(l_timing_mtb, - l_medium_timebase, - l_timing_ftb, - l_fine_timebase)); + o_value = spd::calc_timing_from_timebase(l_timing_mtb, + l_medium_timebase, + l_timing_ftb, + l_fine_timebase); // Sanity check FAPI_ASSERT(o_value > 0, fapi2::MSS_INVALID_TIMING_VALUE(). set_VALUE(o_value). set_DIMM_TARGET(i_target), - "tAAmin invalid (<= 0) : %d", + "%s. tAAmin invalid (<= 0) : %d", + mss::c_str(iv_target), o_value); - FAPI_DBG( "%s. tAAmin (ps): %d", - c_str(i_target), + FAPI_INF( "%s. tAAmin (ps): %d", + mss::c_str(iv_target), o_value); fapi_try_exit: @@ -252,34 +324,38 @@ fapi2::ReturnCode cas_latency::get_tckmin(const fapi2::Target& int64_t l_fine_timebase = 0; // Retrieve timing parameters - FAPI_TRY( i_pDecoder->medium_timebase(i_target, l_medium_timebase) ); - FAPI_TRY( i_pDecoder->fine_timebase(i_target, l_fine_timebase) ); - FAPI_TRY( i_pDecoder->min_cycle_time(i_target, l_timing_mtb) ); - FAPI_TRY( i_pDecoder->fine_offset_min_tck(i_target, l_timing_ftb) ); + FAPI_TRY( i_pDecoder->medium_timebase(i_target, l_medium_timebase), + "%s. Failed medium_timebase()", mss::c_str(iv_target) ); + FAPI_TRY( i_pDecoder->fine_timebase(i_target, l_fine_timebase), + "%s. Failed fine_timebase()", mss::c_str(iv_target) ); + FAPI_TRY( i_pDecoder->min_cycle_time(i_target, l_timing_mtb), + "%s. Failed min_cycle_time()", mss::c_str(iv_target) ); + FAPI_TRY( i_pDecoder->fine_offset_min_tck(i_target, l_timing_ftb), + "%s. Failed fine_offset_min_tck()", mss::c_str(iv_target) ); // Calculate timing value - o_value = uint64_t( calc_timing_from_timebase(l_timing_mtb, - l_medium_timebase, - l_timing_ftb, - l_fine_timebase) ); + o_value = spd::calc_timing_from_timebase(l_timing_mtb, + l_medium_timebase, + l_timing_ftb, + l_fine_timebase); // Sanity check FAPI_ASSERT(o_value > 0, fapi2::MSS_INVALID_TIMING_VALUE(). set_VALUE(o_value). set_DIMM_TARGET(i_target), - "tCKmin invalid (<= 0) : %d", + "%s. tCKmin invalid (<= 0) : %d", + mss::c_str(iv_target), o_value); - FAPI_DBG("%s. tCKmin (ps): %d", - c_str(i_target), + FAPI_INF("%s. tCKmin (ps): %d", + mss::c_str(iv_target), o_value ); fapi_try_exit: return fapi2::current_err; } - /// /// @brief Retrieves SDRAM Maximum Cycle Time (tCKmax) from SPD /// @param[in] i_target the dimm target @@ -297,27 +373,32 @@ fapi2::ReturnCode cas_latency::get_tckmax(const fapi2::Target& int64_t l_fine_timebase = 0; // Retrieve timing parameters - FAPI_TRY( i_pDecoder->medium_timebase(i_target, l_medium_timebase) ); - FAPI_TRY( i_pDecoder->fine_timebase(i_target, l_fine_timebase) ); - FAPI_TRY( i_pDecoder->max_cycle_time(i_target, l_timing_mtb) ); - FAPI_TRY( i_pDecoder->fine_offset_max_tck(i_target, l_timing_ftb) ); + FAPI_TRY( i_pDecoder->medium_timebase(i_target, l_medium_timebase), + "%s. Failed medium_timebase()", mss::c_str(iv_target) ); + FAPI_TRY( i_pDecoder->fine_timebase(i_target, l_fine_timebase), + "%s. Failed fine_timebase()", mss::c_str(iv_target) ); + FAPI_TRY( i_pDecoder->max_cycle_time(i_target, l_timing_mtb), + "%s. Failed max_cycle_time()", mss::c_str(iv_target) ); + FAPI_TRY( i_pDecoder->fine_offset_max_tck(i_target, l_timing_ftb), + "%s. Failed fine_offset_max_tck()", mss::c_str(iv_target) ); // Calculate timing value - o_value = uint64_t(calc_timing_from_timebase(l_timing_mtb, - l_medium_timebase, - l_timing_ftb, - l_fine_timebase) ); + o_value = spd::calc_timing_from_timebase(l_timing_mtb, + l_medium_timebase, + l_timing_ftb, + l_fine_timebase); // Sanity check FAPI_ASSERT(o_value > 0, fapi2::MSS_INVALID_TIMING_VALUE(). set_VALUE(o_value). set_DIMM_TARGET(i_target), - "tCKmax invalid (<= 0) : %d", + "%s. tCKmax invalid (<= 0) : %d", + mss::c_str(iv_target), o_value); - FAPI_DBG( "%s. tCKmax (ps): %d", - c_str(i_target), + FAPI_INF( "%s. tCKmax (ps): %d", + mss::c_str(iv_target), o_value); fapi_try_exit: @@ -326,231 +407,133 @@ fapi_try_exit: /// /// @brief Gets max CAS latency (CL) for the appropriate High/Low Range -/// @param[in] i_supported_CL +/// @param[in] i_supported_cl /// @return the maximum supported CL /// @note Depends on bit 7 of byte 23 from the DDR4 SPD /// -inline uint64_t cas_latency::get_max_CL(const fapi2::buffer i_supported_CL) const +inline uint64_t cas_latency::get_max_cl(const fapi2::buffer i_supported_cl) const { - constexpr uint64_t CAS_LAT_RANGE_BIT = 31; - // If the last of Byte 23 of the SPD is 1, this selects CL values // in the High CL range (23 to 52) // If the last bit of Byte 23 of the SPD is 0, this selects CL values // in the Low CL range (7 to 36) //Assuming bitmap is right aligned - return i_supported_CL.getBit() ? HIGH_RANGE_MAX_CL_DDR4 : LOW_RANGE_MAX_CL_DDR4; + return i_supported_cl.getBit() ? HIGH_RANGE_MAX_CL_DDR4 : LOW_RANGE_MAX_CL_DDR4; } /// /// @brief Gets min CAS latency (CL) for the appropriate High/Low Range -/// @param[in] i_supported_CL +/// @param[in] i_supported_cl /// @return the minimum supported CL /// @note Depends on bit 7 of byte 23 from the DDR4 SPD /// -inline uint64_t cas_latency::get_min_CL(const fapi2::buffer& i_supported_CL) const +inline uint64_t cas_latency::get_min_cl(const fapi2::buffer& i_supported_cl) const { // If the last of Byte 23 of the SPD is 1, this selects CL values // in the High CL range (23 to 52) // If the last bit of Byte 23 of the SPD is 0, this selects CL values // in the Low CL range (7 to 36) - constexpr uint64_t CAS_LAT_RANGE_BIT = 31; - - return i_supported_CL.getBit() ? HIGH_RANGE_MIN_CL_DDR4 : LOW_RANGE_MIN_CL_DDR4; + return i_supported_cl.getBit() ? HIGH_RANGE_MIN_CL_DDR4 : LOW_RANGE_MIN_CL_DDR4; } /// /// @brief Calculates CAS latency time from tCK and tAA -/// @param[in] i_tAA cas latency time -/// @param[in] i_tCK min cycle time -/// @return o_cas_latency calculated CAS latency +/// @param[in] i_taa cas latency time +/// @param[in] i_tck min cycle time +/// @param[out] o_cas_latency calculated CAS latency +/// @return FAPI2_RC_SUCCESS iff okay /// -inline uint64_t cas_latency::calc_cas_latency(const uint64_t i_tAA, const uint64_t i_tCK) const +inline fapi2::ReturnCode cas_latency::calc_cas_latency(const uint64_t i_taa, + const uint64_t i_tck, + uint64_t& o_cas_latency) const { - uint64_t l_quotient = i_tAA / i_tCK; - uint64_t l_remainder = i_tAA % i_tCK; - uint64_t o_cas_latency = l_quotient + (l_remainder == 0 ? 0 : 1); + FAPI_TRY( spd::calc_nck(i_taa, i_tck, INVERSE_DDR4_CORRECTION_FACTOR, o_cas_latency) ); - FAPI_DBG("Calculated CL = tAA / tCK : %d / %d = %d", - i_tAA, - i_tCK, + FAPI_INF("%s. tAA (ps): %d, tCK (ps): %d, CL (nck): %d", + mss::c_str(iv_target), + i_taa, + i_tck, o_cas_latency); - return o_cas_latency; +fapi_try_exit: + return fapi2::current_err; } /// /// @brief Helper function to create a vector of supported CAS latencies from a bitmap -/// @param[in] i_common_CL common CAS latency bitmap +/// @param[in] i_common_cl common CAS latency bitmap /// @return vector of supported CAS latencies /// -std::vector cas_latency::create_common_cl_vector(const uint64_t i_common_CL) const +std::vector cas_latency::integral_bitmap_to_vector(const uint64_t i_common_cl) const { std::vector l_vector; - fapi2::buffer l_CL_mask(i_common_CL); + fapi2::buffer l_cl_mask(i_common_cl); - uint64_t min_CL = get_min_CL(l_CL_mask); - uint64_t max_CL = get_max_CL(l_CL_mask); + uint64_t min_cl = get_min_cl(l_cl_mask); + uint64_t max_cl = get_max_cl(l_cl_mask); - FAPI_DBG("min CL %lu", min_CL); - FAPI_DBG("max CL %lu", max_CL); + FAPI_INF("%s. min CL %lu", mss::c_str(iv_target), min_cl); + FAPI_INF("%s. max CL %lu", mss::c_str(iv_target), max_cl); - for(uint64_t cas_latency = min_CL; cas_latency <= max_CL; ++cas_latency) + for(uint64_t l_cas_latency = min_cl; l_cas_latency <= max_cl; ++l_cas_latency) { // 64 bit is buffer length - indexed at 0 - 63 constexpr uint64_t l_buffer_length = 64 - 1; - uint64_t l_bit_pos = l_buffer_length - (cas_latency - min_CL); + uint64_t l_bit_pos = l_buffer_length - (l_cas_latency - min_cl); // Traversing through buffer one bit at a time // 0 means unsupported CAS latency // 1 means supported CAS latency // We are pushing supported CAS latencies into a vector for direct use - if( l_CL_mask.getBit(l_bit_pos) ) + if( l_cl_mask.getBit(l_bit_pos) ) { - l_vector.push_back(cas_latency); + // I want don't this to print all the time, DBG is fine + FAPI_DBG( "%s. Supported CL (%d) from common CL mask", + mss::c_str(iv_target), l_cas_latency ); + + l_vector.push_back(l_cas_latency); } } return l_vector; } - /// /// @brief Determines if a requested CAS latency (CL) is supported in the bin of common CLs -/// @param[in] i_common_CLs vector of common CAS latencies +/// @param[in] i_common_cls vector of common CAS latencies /// @param[in] i_cas_latency CAS latency we are comparing against -/// @return true if CAS latency is supported +/// @return FAPI2_RC_SUCCESS iff ok /// -inline bool cas_latency::is_CL_supported_in_common(const std::vector& i_common_CLs, +inline fapi2::ReturnCode cas_latency::is_cl_supported_in_common(const std::vector& i_common_cls, const uint64_t i_cas_latency) const { - return std::binary_search(i_common_CLs.begin(), i_common_CLs.end(), i_cas_latency); + return std::binary_search(i_common_cls.begin(), i_common_cls.end(), i_cas_latency) == true ? + fapi2::FAPI2_RC_SUCCESS : fapi2::FAPI2_RC_FALSE; } /// /// @brief Checks that CAS latency doesn't exceed largest CAS latency time /// @param[in] i_cas_latency cas latency -/// @param[in] i_tCK cycle time -/// @return bool true if CAS latency exceeds the largest CAS latency time -/// false otherwise -/// -inline bool cas_latency::is_CL_exceeding_tAAmax(const uint64_t i_cas_latency, - const uint64_t i_tCK) const -{ - // JEDEC spec requirement - return (i_cas_latency * i_tCK > TAA_MAX_DDR4); -} - - -/// -/// @brief Helper function to determines next lowest CAS latency (CL) -/// @param[in] i_common_CLs vector of common CAS latencies -/// @param[in] i_desired_cas_latency current CAS latency -/// @return the next lowest CL -/// -inline uint64_t cas_latency::next_lowest_CL(const std::vector& i_common_CLs, - const uint64_t i_desired_cas_latency) -{ - auto iterator = std::lower_bound(i_common_CLs.begin(), i_common_CLs.end(), i_desired_cas_latency); - return *(--iterator); -} - -/// -/// @brief Checks that CAS latency (CL) is supported among all dimms -/// and if it isn't we try to find a CL that is. -/// @param[in] i_common_CLs vector of common CAS latencies -/// @param[in] i_tAA CAS latency time -/// @param[in,out] io_tCK cycle time that corresponds to cas latency -/// @param[in,out] io_desired_cas_lat cas latency supported for all dimms -/// @return fapi2::FAPI2_RC_SUCCESS if we find a valid CL also common among all dimms -/// -fapi2::ReturnCode cas_latency::choose_actual_CL (const std::vector& i_common_CLs, - const uint64_t i_tAA, - uint64_t& io_tCK, - uint64_t& io_desired_cas_lat) -{ - if( i_common_CLs.empty() ) - { - FAPI_ERR("Common CAS latency vector is empty!"); - return fapi2::FAPI2_RC_INVALID_PARAMETER; - } - - //check if the desired CL is supported in the common CAS latency bin - bool l_is_CL_supported = is_CL_supported_in_common(i_common_CLs, io_desired_cas_lat); - - while( !l_is_CL_supported ) - { - // If CL is not supported... - // Choose a higher tCKproposed value and recalculate CL - // Check recalculated CL is supported in common CL - // Repeat until a solution is found - FAPI_TRY( select_higher_tck(io_tCK), "Failed select_higher_tck()"); - FAPI_DBG("Next higher tCK: %d", io_tCK); - - io_desired_cas_lat = calc_cas_latency(i_tAA, io_tCK); - l_is_CL_supported = is_CL_supported_in_common(i_common_CLs, io_desired_cas_lat); - } - - // If we reach here everything is okay - return fapi2::FAPI2_RC_SUCCESS; - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Checks that CAS latency (CL) doesn't exceed max CAS latency time (tAAmax) -/// and if it does it tries to find a valid CL that doesn't exceed tAAmax. -/// @param[in] i_common_CLs vector of common CAS latencies -/// @param[in] i_tAA CAS latency time -/// @param[in,out] io_tCK cycle time that corresponds to cas latency -/// @param[in,out] io_desired_cas_lat cas latency supported for all dimms -/// @return fapi2::FAPI2_RC_SUCCESS if CL doesn't exceed tAAmax +/// @param[in] i_tck cycle time +/// @return FAPI2_RC_SUCCESS iff ok /// -fapi2::ReturnCode cas_latency::validate_valid_CL (const std::vector& i_common_CLs, - const uint64_t i_tAA, - uint64_t& io_tCK, - uint64_t& io_desired_cas_lat) +inline fapi2::ReturnCode cas_latency::is_cl_exceeding_taa_max(const uint64_t i_cas_latency, + const uint64_t i_tck) const { - if( i_common_CLs.empty() ) - { - FAPI_ERR("Common CAS latency vector is empty!"); - return fapi2::FAPI2_RC_INVALID_PARAMETER; - } + // JEDEC SPD spec requirement + const size_t l_taa_max = (iv_is_3ds == loading::NOT_3DS) ? TAA_MAX_DDR4 : TAA_MAX_DDR4_3DS; - // Check that selected CL is less than tAAmax - bool l_is_CL_violating_spec = is_CL_exceeding_tAAmax (io_desired_cas_lat, io_tCK); + FAPI_INF("%s. CL (%d) * tCK (%d) = %d > %d", + mss::c_str(iv_target), + i_cas_latency, + i_tck, + i_cas_latency * i_tck, + l_taa_max); - while(l_is_CL_violating_spec) - { - // If it is not.... - // Decrement CL to next lowest supported CL - // And try again - io_desired_cas_lat = next_lowest_CL(i_common_CLs, io_desired_cas_lat); - FAPI_DBG("Next lowest CAS latency %d", io_desired_cas_lat); - - FAPI_TRY( choose_actual_CL(i_common_CLs, i_tAA, io_tCK, io_desired_cas_lat), - "Failed choose_actual_CL()"); - - l_is_CL_violating_spec = is_CL_exceeding_tAAmax (io_desired_cas_lat, io_tCK); - } - - //If we reach this point that we are not violationg tAAmax spec anymore - return fapi2::FAPI2_RC_SUCCESS; - -fapi_try_exit: - // Since a fail here could mean a fail due to choose_actual_cl and - // due to violation of taamax specification, this error will help - // distinguish error reason - FAPI_ASSERT(false, - fapi2::MSS_EXCEED_TAA_MAX_NO_CL(). - set_CL(io_desired_cas_lat), - "Exceeded tAAmax"); - - return fapi2::current_err; + return (i_cas_latency * i_tck) > l_taa_max ? fapi2::FAPI2_RC_FALSE : fapi2::FAPI2_RC_SUCCESS; } }// mss diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H index b52c6b16c..d1c11510c 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H @@ -50,23 +50,16 @@ namespace mss { -enum constants : std::uint64_t + +// I choose enumerations over boolean because I feel +// it makes the interface clearer than could be depicted +// by 'true' and 'false' alone. +enum class loading : size_t { - // From JEDEC Standard No. 79-4A - // Speed Bins pg. 164 - /// Time in picoseconds - TAA_MAX_DDR4 = 18000, - - // Low range CAS latency from SPD - LOW_RANGE_MIN_CL_DDR4 = 7, - LOW_RANGE_MAX_CL_DDR4 = 36, - - // High range CAS latency SPD - HIGH_RANGE_MIN_CL_DDR4 = 23, - HIGH_RANGE_MAX_CL_DDR4 = 52, + NOT_3DS, + IS_3DS, }; - /// /// @class decoder /// @brief CAS latency class that encapsulates JEDEC calculation algorithm @@ -89,23 +82,73 @@ class cas_latency /// @brief Class constructor that retrieves required SPD data held by internal state /// @param[in] i_target the controller target /// @param[in] i_caches decoder caches + /// @param[out] o_rc returns FAPI2_RC_SUCCESS if constructor initialzed successfully /// cas_latency(const fapi2::Target& i_target_mcs, - const std::map >& i_caches); + const std::map >& i_caches, + fapi2::ReturnCode& o_rc); + + /// @brief Constructor that allows the user to set desired data in lieu of SPD + /// @param[in] i_target the controller target + /// @param[in] i_taa_min largest tAAmin we want to set in picoseconds + /// @param[in] i_tck_min proposed tCKmin in picoseconds + /// @param[in] i_common_cl_mask common CAS latency mask we want to use (bitmap) + /// @param[in] i_is_3ds loading::IS_3DS if this is for 3DS, + /// loading::NOT_3DS otherwise (default) + /// + cas_latency(const fapi2::Target& i_target, + const uint64_t i_taa_min, + const uint64_t i_tck_min, + const uint64_t i_common_cl_mask, + const loading i_is_3ds = loading::NOT_3DS); - // Default destructor + /// + /// @brief Default destructor + /// ~cas_latency() = default; /// /// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec. - /// @param[in] i_target the controller target /// @param[out] o_cas_latency selected CAS latency - /// @param[out] o_tCK cycle time corresponding to seleted CAS latency + /// @param[out] o_tck cycle time corresponding to seleted CAS latency /// @return fapi2::FAPI2_RC_SUCCESS if ok /// - fapi2::ReturnCode find_CL(const fapi2::Target& i_target_mcs, - uint64_t& o_cas_latency, - uint64_t& o_tCK); + fapi2::ReturnCode find_cl(uint64_t& o_cas_latency, + uint64_t& o_tck); + + private: + + enum + { + // From JEDEC Standard No. 79-4A + // Speed Bins pg. 164 + /// Time in picoseconds + TAA_MAX_DDR4 = 18000, + + // From JEDEC Standard No. 79-4 3DS + // Speed Bins pg. 135 + /// Time in picoseconds + TAA_MAX_DDR4_3DS = 21500, + + // Low range CAS latency from SPD + LOW_RANGE_MIN_CL_DDR4 = 7, + LOW_RANGE_MAX_CL_DDR4 = 36, + + // High range CAS latency SPD + HIGH_RANGE_MIN_CL_DDR4 = 23, + HIGH_RANGE_MAX_CL_DDR4 = 52, + + CAS_LAT_RANGE_BIT = 31, + }; + + ///////////////////////// + // Private variables + ///////////////////////// + fapi2::Target iv_target; + uint64_t iv_largest_taamin;// cas latency time + uint64_t iv_proposed_tck;// cycle time + uint64_t iv_common_cl; // common cas latency + loading iv_is_3ds; /// /// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD @@ -141,99 +184,56 @@ class cas_latency /// /// @brief Gets max CAS latency (CL) for the appropriate High/Low Range - /// @param[in] i_supported_CL + /// @param[in] i_supported_cl /// @return the maximum supported CL /// @note Depends on bit 7 of byte 23 from the DDR4 SPD /// - inline uint64_t get_max_CL(const fapi2::buffer i_supported_CL) const; + inline uint64_t get_max_cl(const fapi2::buffer i_supported_cl) const; /// /// @brief Gets min CAS latency (CL) for the appropriate High/Low Range - /// @param[in] i_supported_CL + /// @param[in] i_supported_cl /// @return the minimum supported CL /// @note Depends on bit 7 of byte 23 from the DDR4 SPD /// - inline uint64_t get_min_CL(const fapi2::buffer& i_supported_CL) const; + inline uint64_t get_min_cl(const fapi2::buffer& i_supported_cl) const; /// /// @brief Calculates CAS latency time from tCK and tAA - /// @param[in] i_tAA cas latency time - /// @param[in] i_tCK min cycle time - /// @return o_cas_latency calculated CAS latency + /// @param[in] i_taa cas latency time + /// @param[in] i_tck min cycle time + /// @param[out] o_cas_latency calculated CAS latency + /// @return FAPI2_RC_SUCCESS iff okay /// - inline uint64_t calc_cas_latency(const uint64_t i_tAA, const uint64_t i_tCK) const; + inline fapi2::ReturnCode calc_cas_latency(const uint64_t i_taa, + const uint64_t i_tck, + uint64_t& o_cas_latency) const; /// /// @brief Helper function to create a vector of supported CAS latencies from a bitmap - /// @param[in] i_common_CL common CAS latency bitmap + /// @param[in] i_common_cl common CAS latency bitmap /// @return vector of supported CAS latencies /// - std::vector create_common_cl_vector(const uint64_t i_common_CL) const; + std::vector integral_bitmap_to_vector(const uint64_t i_bitmap) const; /// /// @brief Determines if a requested CAS latency (CL) is supported in the bin of common CLs - /// @param[in] i_common_CLs vector of common CAS latencies + /// @param[in] i_common_cls vector of common CAS latencies /// @param[in] i_cas_latency CAS latency we are comparing against - /// @return true if CAS latency is supported + /// @return fapi2::FAPI2_RC_SUCCESS if ok /// - inline bool is_CL_supported_in_common(const std::vector& i_common_CLs, - const uint64_t i_cas_latency) const; + inline fapi2::ReturnCode is_cl_supported_in_common(const std::vector& i_common_cls, + const uint64_t i_cas_latency) const; /// /// @brief Checks that CAS latency doesn't exceed largest CAS latency time /// @param[in] i_cas_latency cas latency - /// @param[in] i_tCK cycle time - /// @return bool true if CAS latency exceeds the largest CAS latency time - /// false otherwise - /// - inline bool is_CL_exceeding_tAAmax(const uint64_t i_cas_latency, - const uint64_t i_tCK) const; - - /// - /// @brief Helper function to determines next lowest CAS latency (CL) - /// @param[in] i_common_CLs vector of common CAS latencies - /// @param[in] i_desired_cas_latency current CAS latency - /// @return the next lowest CL - /// - inline uint64_t next_lowest_CL(const std::vector& i_common_CLs, - const uint64_t i_desired_cas_latency); - - /// - /// @brief Checks that CAS latency (CL) is supported among all dimms - /// and if it isn't we try to find a CL that is. - /// @param[in] i_common_CLs vector of common CAS latencies - /// @param[in] i_tAA CAS latency time - /// @param[in,out] io_tCK cycle time that corresponds to cas latency - /// @param[in,out] io_desired_cas_lat cas latency supported for all dimms - /// @return fapi2::FAPI2_RC_SUCCESS if we find a valid CL also common among all dimms - /// - fapi2::ReturnCode choose_actual_CL (const std::vector& i_common_CLs, - const uint64_t i_tAA, - uint64_t& io_tCK, - uint64_t& io_desired_cas_lat); - /// - /// @brief Checks that CAS latency (CL) doesn't exceed max CAS latency time (tAAmax) - /// and if it does it tries to find a valid CL that doesn't exceed tAAmax. - /// @param[in] i_common_CLs vector of common CAS latencies - /// @param[in] i_tAA CAS latency time - /// @param[in,out] io_tCK cycle time that corresponds to cas latency - /// @param[in,out] io_desired_cas_lat cas latency supported for all dimms - /// @return fapi2::FAPI2_RC_SUCCESS if CL doesn't exceed tAAmax + /// @param[in] i_tck cycle time + /// @return fapi2::FAPI2_RC_SUCCESS if ok /// - fapi2::ReturnCode validate_valid_CL (const std::vector& i_common_CLs, - const uint64_t i_tAA, - uint64_t& io_tCK, - uint64_t& io_desired_cas_lat); - - private: - - ///////////////////////// - // Private variables - ///////////////////////// - uint64_t iv_largest_taamin;// cas latency time - uint64_t iv_proposed_tck;// cycle time - uint64_t iv_common_CL; // common cas latency + inline fapi2::ReturnCode is_cl_exceeding_taa_max(const uint64_t i_cas_latency, + const uint64_t i_tck) const; };// cas_latency diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cycle_time.H b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cycle_time.H index 2352d14df..39ff8d401 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cycle_time.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cycle_time.H @@ -52,22 +52,6 @@ enum FREQ_MARGIN : std::uint64_t MAX_FREQ_MARGIN = 2799, }; -// Proposed DDR4 Full spec update(79-4A) -// Item No. 1716.78C -// Page 217 -// 10.1 Item No. 1716.78C -// Speed Bin Table Note -static const std::vector tckmin_avg_ddr4 -{ - - // Timing in picoseconds | Application bin speed - 750, // 2666 MT/s - 833, // 2400 MT/s - 937, // 2133 MT/s - 1071, // 1866 MT/s - /* 1250, // 1600 MT/s - don't think we support this one - AAM */ -}; - /// /// @brief Selects DIMM frequency to run based on supported system frequencies /// @tparam T the fapi2::TargetType for which the DIMM information exists. @@ -127,28 +111,6 @@ fapi_try_exit: return fapi2::current_err; } -/// -/// @brief Determines next highest min cycle time (tCK) -/// @param[in,out] io_tCK_in_ps min cycle time in ps -/// @return fapi2::FAPI2_RC_SUCCESS if ok -/// -inline fapi2::ReturnCode select_higher_tck(uint64_t& io_tCK) -{ - auto iterator = std::upper_bound(tckmin_avg_ddr4.begin(), - tckmin_avg_ddr4.end(), - io_tCK); - - // Did we find a greater than value? - FAPI_ASSERT(iterator != tckmin_avg_ddr4.end(), - fapi2::MSS_REACHED_HIGHEST_TCK(). - set_TCK(io_tCK), - "Reached highest valid tCK"); - -fapi_try_exit: - return fapi2::current_err; -} - - }// mss #endif diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors.H b/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors.H index 5d99d8caf..0a1b3c896 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mss_attribute_accessors.H @@ -15854,8 +15854,11 @@ fapi_try_exit: /// @param[out] ref to the value uint16_t /// @note Generated by gen_accessors.pl generateParameters (D) /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK -/// @note Average Refresh Interval (tREFI) in nck (number of clock cycles). creator: -/// mss_eff_config consumer: various firmware notes: +/// @note Average Refresh Interval (tREFI) in nck (number of clock cycles). This depends +/// on MRW attribute that selects fine refresh mode (x1, x2, x4). From DDR4 spec +/// (79-4A). For 3DS, the tREFI time to the same logical rank is defined as +/// tRFC_slr1, tRFC_slr2, or tRFC_slr4. creator: mss_eff_config consumer: various +/// firmware notes: /// none /// inline fapi2::ReturnCode eff_dram_trefi(const fapi2::Target& i_target, uint16_t& o_value) @@ -15878,8 +15881,11 @@ fapi_try_exit: /// @param[out] ref to the value uint16_t /// @note Generated by gen_accessors.pl generateParameters (D.1) /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK -/// @note Average Refresh Interval (tREFI) in nck (number of clock cycles). creator: -/// mss_eff_config consumer: various firmware notes: +/// @note Average Refresh Interval (tREFI) in nck (number of clock cycles). This depends +/// on MRW attribute that selects fine refresh mode (x1, x2, x4). From DDR4 spec +/// (79-4A). For 3DS, the tREFI time to the same logical rank is defined as +/// tRFC_slr1, tRFC_slr2, or tRFC_slr4. creator: mss_eff_config consumer: various +/// firmware notes: /// none /// inline fapi2::ReturnCode eff_dram_trefi(const fapi2::Target& i_target, uint16_t& o_value) @@ -15903,8 +15909,11 @@ fapi_try_exit: /// @param[out] uint16_t* memory to store the value /// @note Generated by gen_accessors.pl generateParameters (E) /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK -/// @note Average Refresh Interval (tREFI) in nck (number of clock cycles). creator: -/// mss_eff_config consumer: various firmware notes: +/// @note Average Refresh Interval (tREFI) in nck (number of clock cycles). This depends +/// on MRW attribute that selects fine refresh mode (x1, x2, x4). From DDR4 spec +/// (79-4A). For 3DS, the tREFI time to the same logical rank is defined as +/// tRFC_slr1, tRFC_slr2, or tRFC_slr4. creator: mss_eff_config consumer: various +/// firmware notes: /// none /// inline fapi2::ReturnCode eff_dram_trefi(const fapi2::Target& i_target, uint16_t* o_array) @@ -15933,8 +15942,9 @@ fapi_try_exit: /// @param[out] ref to the value uint8_t /// @note Generated by gen_accessors.pl generateParameters (D) /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK -/// @note Internal Read to Precharge Delay. Each memory channel will have a value. -/// creator: mss_eff_cnfg_timing consumer: various firmware notes: +/// @note Internal Read to Precharge Delay. From the DDR4 spec (79-4A). Each memory +/// channel will have a value. creator: mss_eff_cnfg_timing consumer: various +/// firmware notes: /// none /// inline fapi2::ReturnCode eff_dram_trtp(const fapi2::Target& i_target, uint8_t& o_value) @@ -15957,8 +15967,9 @@ fapi_try_exit: /// @param[out] ref to the value uint8_t /// @note Generated by gen_accessors.pl generateParameters (D.1) /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK -/// @note Internal Read to Precharge Delay. Each memory channel will have a value. -/// creator: mss_eff_cnfg_timing consumer: various firmware notes: +/// @note Internal Read to Precharge Delay. From the DDR4 spec (79-4A). Each memory +/// channel will have a value. creator: mss_eff_cnfg_timing consumer: various +/// firmware notes: /// none /// inline fapi2::ReturnCode eff_dram_trtp(const fapi2::Target& i_target, uint8_t& o_value) @@ -15982,8 +15993,9 @@ fapi_try_exit: /// @param[out] uint8_t* memory to store the value /// @note Generated by gen_accessors.pl generateParameters (E) /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK -/// @note Internal Read to Precharge Delay. Each memory channel will have a value. -/// creator: mss_eff_cnfg_timing consumer: various firmware notes: +/// @note Internal Read to Precharge Delay. From the DDR4 spec (79-4A). Each memory +/// channel will have a value. creator: mss_eff_cnfg_timing consumer: various +/// firmware notes: /// none /// inline fapi2::ReturnCode eff_dram_trtp(const fapi2::Target& i_target, uint8_t* o_array) @@ -16012,11 +16024,11 @@ fapi_try_exit: /// @param[out] ref to the value uint8_t /// @note Generated by gen_accessors.pl generateParameters (D) /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK -/// @note Minimum Refresh Recovery Delay Time in nck (number of clock cyles). Selected -/// tRFC value (tRFC_dl1, tRFC_dl2, or tRFC_dl4) depends on MRW attribute that -/// selects fine refresh mode (x1, x2, x4). For 3DS, The tRFC time to different -/// logical ranks are defined as tRFC_dlr creator: eff_config consumer: various -/// firmware notes: +/// @note Minimum Refresh Recovery Delay Time (different logical ranks) in nck (number of +/// clock cyles). Selected tRFC value (tRFC_dlr1, tRFC_dlr2, or tRFC_dlr4) depends +/// on MRW attribute that selects fine refresh mode (x1, x2, x4). For 3DS, The tRFC +/// time to different logical ranks are defined as tRFC_dlr creator: eff_config +/// consumer: various firmware notes: /// none /// inline fapi2::ReturnCode eff_dram_trfc_dlr(const fapi2::Target& i_target, uint8_t& o_value) @@ -16039,11 +16051,11 @@ fapi_try_exit: /// @param[out] ref to the value uint8_t /// @note Generated by gen_accessors.pl generateParameters (D.1) /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK -/// @note Minimum Refresh Recovery Delay Time in nck (number of clock cyles). Selected -/// tRFC value (tRFC_dl1, tRFC_dl2, or tRFC_dl4) depends on MRW attribute that -/// selects fine refresh mode (x1, x2, x4). For 3DS, The tRFC time to different -/// logical ranks are defined as tRFC_dlr creator: eff_config consumer: various -/// firmware notes: +/// @note Minimum Refresh Recovery Delay Time (different logical ranks) in nck (number of +/// clock cyles). Selected tRFC value (tRFC_dlr1, tRFC_dlr2, or tRFC_dlr4) depends +/// on MRW attribute that selects fine refresh mode (x1, x2, x4). For 3DS, The tRFC +/// time to different logical ranks are defined as tRFC_dlr creator: eff_config +/// consumer: various firmware notes: /// none /// inline fapi2::ReturnCode eff_dram_trfc_dlr(const fapi2::Target& i_target, uint8_t& o_value) @@ -16067,11 +16079,11 @@ fapi_try_exit: /// @param[out] uint8_t* memory to store the value /// @note Generated by gen_accessors.pl generateParameters (E) /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK -/// @note Minimum Refresh Recovery Delay Time in nck (number of clock cyles). Selected -/// tRFC value (tRFC_dl1, tRFC_dl2, or tRFC_dl4) depends on MRW attribute that -/// selects fine refresh mode (x1, x2, x4). For 3DS, The tRFC time to different -/// logical ranks are defined as tRFC_dlr creator: eff_config consumer: various -/// firmware notes: +/// @note Minimum Refresh Recovery Delay Time (different logical ranks) in nck (number of +/// clock cyles). Selected tRFC value (tRFC_dlr1, tRFC_dlr2, or tRFC_dlr4) depends +/// on MRW attribute that selects fine refresh mode (x1, x2, x4). For 3DS, The tRFC +/// time to different logical ranks are defined as tRFC_dlr creator: eff_config +/// consumer: various firmware notes: /// none /// inline fapi2::ReturnCode eff_dram_trfc_dlr(const fapi2::Target& i_target, uint8_t* o_array) @@ -16179,6 +16191,91 @@ fapi_try_exit: return fapi2::current_err; } +/// +/// @brief ATTR_EFF_DRAM_TRRD_DLR getter +/// @param[in] const ref to the fapi2::Target +/// @param[out] ref to the value uint8_t +/// @note Generated by gen_accessors.pl generateParameters (D) +/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK +/// @note Minimum Activate to Activate Delay Time (different logical ranks) in nck (number +/// of clock cycles). For 3DS, The tRRD_S time to a different logical rank is +/// defined as tRRD_dlr. Each memory channel will have a value. creator: eff_confg +/// consumer: various firmware notes: +/// none +/// +inline fapi2::ReturnCode eff_dram_trrd_dlr(const fapi2::Target& i_target, uint8_t& o_value) +{ + uint8_t l_value[2]; + + FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_DRAM_TRRD_DLR, i_target.getParent(), l_value) ); + o_value = l_value[mss::index(i_target)]; + return fapi2::current_err; + +fapi_try_exit: + FAPI_ERR("failed accessing ATTR_EFF_DRAM_TRRD_DLR: 0x%lx (target: %s)", + uint64_t(fapi2::current_err), mss::c_str(i_target)); + return fapi2::current_err; +} + +/// +/// @brief ATTR_EFF_DRAM_TRRD_DLR getter +/// @param[in] const ref to the fapi2::Target +/// @param[out] ref to the value uint8_t +/// @note Generated by gen_accessors.pl generateParameters (D.1) +/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK +/// @note Minimum Activate to Activate Delay Time (different logical ranks) in nck (number +/// of clock cycles). For 3DS, The tRRD_S time to a different logical rank is +/// defined as tRRD_dlr. Each memory channel will have a value. creator: eff_confg +/// consumer: various firmware notes: +/// none +/// +inline fapi2::ReturnCode eff_dram_trrd_dlr(const fapi2::Target& i_target, uint8_t& o_value) +{ + uint8_t l_value[2]; + auto l_mca = i_target.getParent(); + + FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_DRAM_TRRD_DLR, l_mca.getParent(), l_value) ); + o_value = l_value[mss::index(l_mca)]; + return fapi2::current_err; + +fapi_try_exit: + FAPI_ERR("failed accessing ATTR_EFF_DRAM_TRRD_DLR: 0x%lx (target: %s)", + uint64_t(fapi2::current_err), mss::c_str(i_target)); + return fapi2::current_err; +} + +/// +/// @brief ATTR_EFF_DRAM_TRRD_DLR getter +/// @param[in] const ref to the fapi2::Target +/// @param[out] uint8_t* memory to store the value +/// @note Generated by gen_accessors.pl generateParameters (E) +/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK +/// @note Minimum Activate to Activate Delay Time (different logical ranks) in nck (number +/// of clock cycles). For 3DS, The tRRD_S time to a different logical rank is +/// defined as tRRD_dlr. Each memory channel will have a value. creator: eff_confg +/// consumer: various firmware notes: +/// none +/// +inline fapi2::ReturnCode eff_dram_trrd_dlr(const fapi2::Target& i_target, uint8_t* o_array) +{ + if (o_array == nullptr) + { + FAPI_ERR("nullptr passed to attribute accessor %s", __func__); + return fapi2::FAPI2_RC_INVALID_PARAMETER; + } + + uint8_t l_value[2]; + + FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_DRAM_TRRD_DLR, i_target, l_value) ); + memcpy(o_array, &l_value, 2); + return fapi2::current_err; + +fapi_try_exit: + FAPI_ERR("failed accessing ATTR_EFF_DRAM_TRRD_DLR: 0x%lx (target: %s)", + uint64_t(fapi2::current_err), mss::c_str(i_target)); + return fapi2::current_err; +} + /// /// @brief ATTR_EFF_DRAM_TXS getter /// @param[in] const ref to the fapi2::Target diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.C index c7583f58c..61f6b5ee4 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.C @@ -116,13 +116,28 @@ fapi2::ReturnCode reset_timing0( const fapi2::Target& i_target l_data.insertFromRight( exp_helper(l_trp) ); // It's not really clear what to put here. We can have DIMM with different tRFC as they - // don't have to be the same (3DS v. SPD for example.) So we'll take the maximum trfc we + // don't have to be the same (3DS v. SDP for example.) So we'll take the maximum trfc we // find on the DIMM connected to this port. for (const auto& d : mss::find_targets(i_target)) { + // tRFC is for non-3DS, tRFC_slr for 3DS is to the same logical rank, + // and tRFC_dlr is to different logical ranks. Unclear which to use. uint16_t l_trfc = 0; - FAPI_TRY( mss::trfc(d, l_trfc) ); - l_trfc_max = std::max(l_trfc_max, l_trfc); + uint8_t l_trfc_dlr = 0; + + // tRFC (or tRFC_slr) will retrieve a value for 3DS or non-3DS + // tRFC_dlr is only set for 3DS (should be 0 otherwise) + // so we opt to take the more aggressive timing, + // means less chance of data being corrupted + FAPI_TRY( mss::eff_dram_trfc(d, l_trfc) ); + FAPI_TRY( mss::eff_dram_trfc_dlr(d, l_trfc_dlr) ); + + { + // cast needed for template deduction of std::max() + // HB doesn't support using std::min() with initializer lists + const uint16_t l_trfc_3ds_min = std::min(l_trfc, static_cast(l_trfc_dlr)); + l_trfc_max = std::min( l_trfc_3ds_min, l_trfc_max); + } } l_data.insertFromRight( exp_helper(l_trfc_max) ); @@ -194,4 +209,3 @@ fapi_try_exit: } // close namespace seq } // close namespace mss - diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/common/spd_decoder.C b/src/import/chips/p9/procedures/hwp/memory/lib/spd/common/spd_decoder.C index 1e71de864..864805541 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/spd/common/spd_decoder.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/common/spd_decoder.C @@ -1037,10 +1037,10 @@ fapi2::ReturnCode decoder::device_width(const fapi2::Target& i static const std::vector > DEVICE_WIDTH_MAP = { // {key byte, device width (bits)} - {0, 4}, - {1, 8}, - {2, 16}, - {3, 32}, + {0, fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4}, + {1, fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8}, + {2, fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16}, + {3, fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X32}, // All others reserved }; @@ -1544,28 +1544,28 @@ fapi2::ReturnCode decoder::supported_cas_latencies(const fapi2::Target(i_target, iv_spd_data); + FAPI_INF("MSN Field Bits value: %lu", tRASmin_MSN); constexpr size_t BYTE_INDEX_LSB = 28; uint8_t tRASmin_LSB = extract_spd_field< BYTE_INDEX_LSB, TRASMIN_LSB_START, TRASMIN_LSB_LEN >(i_target, iv_spd_data); + FAPI_INF("LSB Field Bits value: %lu", tRASmin_LSB); // Combining bits to create timing value (in a buffer) constexpr size_t MSN_START = 52; @@ -1831,9 +1833,11 @@ fapi2::ReturnCode decoder::min_active_to_active_refresh_delay_time(const fapi2:: { constexpr size_t BYTE_INDEX_MSN = 27; uint8_t tRCmin_MSN = extract_spd_field< BYTE_INDEX_MSN, TRCMIN_MSN_START, TRCMIN_MSN_LEN >(i_target, iv_spd_data); + FAPI_INF("MSN Field Bits value: %lu", tRCmin_MSN); constexpr size_t BYTE_INDEX_LSB = 29; uint8_t tRCmin_LSB = extract_spd_field< BYTE_INDEX_LSB, TRCMIN_LSB_START, TRCMIN_LSB_LEN >(i_target, iv_spd_data); + FAPI_INF("LSB Field Bits value: %lu", tRCmin_LSB); // Combining bits to create timing value (in a buffer) constexpr size_t MSN_START = 52; @@ -1842,7 +1846,6 @@ fapi2::ReturnCode decoder::min_active_to_active_refresh_delay_time(const fapi2:: constexpr size_t LSB_LEN = 8; fapi2::buffer l_buffer; - l_buffer.insertFromRight( tRCmin_MSN ) .insertFromRight( tRCmin_LSB ); @@ -2072,9 +2075,11 @@ fapi2::ReturnCode decoder::min_tfaw(const fapi2::Target& i_tar { constexpr size_t BYTE_INDEX_MSN = 36; uint8_t tFAWmin_MSN = extract_spd_field< BYTE_INDEX_MSN, TFAWMIN_MSN_START, TFAWMIN_MSN_LEN >(i_target, iv_spd_data); + FAPI_INF("MSN Field Bits value: %lu", tFAWmin_MSN); constexpr size_t BYTE_INDEX_LSB = 37; uint8_t tFAWmin_LSB = extract_spd_field< BYTE_INDEX_LSB, TFAWMIN_LSB_START, TFAWMIN_LSB_LEN >(i_target, iv_spd_data); + FAPI_INF("LSB Field Bits value: %lu", tFAWmin_LSB); // Combining bits to create timing value (in a buffer) constexpr size_t MSN_START = 52; @@ -2789,9 +2794,11 @@ fapi2::ReturnCode decoder::cyclical_redundancy_code(const fapi2::Target(i_target, iv_spd_data); + FAPI_INF("MSB Field Bits value: %lu", crc_MSB); constexpr size_t BYTE_INDEX_LSB = 126; uint8_t crc_LSB = extract_spd_field< BYTE_INDEX_LSB, CRC_LSB_START, CRC_LSB_LEN >(i_target, iv_spd_data); + FAPI_INF("LSB Field Bits value: %lu", crc_LSB); // Combining bits to create timing value (in a buffer) constexpr size_t MSN_START = 0; diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_eff_config.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_eff_config.C index 46a4dd765..8306dc750 100644 --- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_eff_config.C +++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_eff_config.C @@ -93,13 +93,12 @@ fapi2::ReturnCode p9_mss_eff_config( const fapi2::Target FAPI_TRY( l_eff_config.dram_width(l_dimm) ); FAPI_TRY( l_eff_config.dram_density(l_dimm) ); FAPI_TRY( l_eff_config.ranks_per_dimm(l_dimm) ); - // Master ranks done above FAPI_TRY( l_eff_config.primary_stack_type(l_dimm) ); FAPI_TRY( l_eff_config.dimm_size(l_dimm) ); FAPI_TRY( l_eff_config.hybrid_memory_type(l_dimm) ); - FAPI_TRY( l_eff_config.refresh_interval_time(l_dimm) ); - FAPI_TRY( l_eff_config.refresh_cycle_time(l_dimm) ); - FAPI_TRY( l_eff_config.refresh_cycle_time_dlr(l_dimm) ); + FAPI_TRY( l_eff_config.dram_trefi(l_dimm) ); + FAPI_TRY( l_eff_config.dram_trfc(l_dimm) ); + FAPI_TRY( l_eff_config.dram_trfc_dlr(l_dimm) ); FAPI_TRY( l_eff_config.rcd_mirror_mode(l_dimm) ); FAPI_TRY( l_eff_config.dram_bank_bits(l_dimm) ); FAPI_TRY( l_eff_config.dram_row_bits(l_dimm) ); @@ -168,11 +167,14 @@ fapi2::ReturnCode p9_mss_eff_config( const fapi2::Target FAPI_TRY( l_eff_config.memcal_interval(l_dimm) ); FAPI_TRY( l_eff_config.dram_trp(l_dimm) ); FAPI_TRY( l_eff_config.dram_trcd(l_dimm) ); + FAPI_TRY( l_eff_config.dram_trc(l_dimm) ); FAPI_TRY( l_eff_config.dram_twtr_l(l_dimm) ); FAPI_TRY( l_eff_config.dram_twtr_s(l_dimm) ); FAPI_TRY( l_eff_config.dram_trrd_s(l_dimm) ); FAPI_TRY( l_eff_config.dram_trrd_l(l_dimm) ); + FAPI_TRY( l_eff_config.dram_trrd_dlr(l_dimm) ); FAPI_TRY( l_eff_config.dram_tfaw(l_dimm) ); + FAPI_TRY( l_eff_config.dram_tfaw_dlr(l_dimm) ); FAPI_TRY( l_eff_config.dram_tras(l_dimm) ); FAPI_TRY( l_eff_config.dram_trtp(l_dimm) ); FAPI_TRY( l_eff_config.read_dbi(l_dimm) ); diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C index 953626b16..646885e34 100644 --- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C +++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C @@ -99,16 +99,19 @@ extern "C" // Get cached decoder std::map > l_factory_caches; FAPI_TRY( mss::spd::populate_decoder_caches(l_mcs, l_factory_caches), - "Failed to populate decoder cache"); + "%s. Failed to populate decoder cache", mss::c_str(i_target) ); { // instantiation of class that calculates CL algorithm - mss::cas_latency l_cas_latency(l_mcs, l_factory_caches); + fapi2::ReturnCode l_rc; + mss::cas_latency l_cas_latency(l_mcs, l_factory_caches, l_rc); + FAPI_TRY( l_rc, "%s. Failed to initialize cas_latency ctor", mss::c_str(i_target) ); if(l_cas_latency.iv_dimm_list_empty) { // Cannot fail out for an empty DIMM configuration, so default values are set - FAPI_INF("DIMM list is empty! Setting default values for CAS latency and DIMM speed."); + FAPI_INF("%s. DIMM list is empty! Setting default values for CAS latency and DIMM speed.", + mss::c_str(i_target) ); } else { @@ -121,33 +124,35 @@ extern "C" uint64_t l_tCKmin = 0; // Find CAS latency using JEDEC algorithm - l_cas_latency.find_CL(l_mcs, - l_desired_cas_latency[l_index], - l_tCKmin); + FAPI_TRY( l_cas_latency.find_cl(l_desired_cas_latency[l_index], + l_tCKmin) ); + + FAPI_INF("%s. Result from CL algorithm, CL (nck): %d, tCK (ps): %d", + mss::c_str(i_target), l_desired_cas_latency[l_index], l_tCKmin); // Find dimm transfer speed from selected tCK FAPI_TRY( mss::ps_to_freq(l_tCKmin, l_min_dimm_freq[l_index]), - "Failed ps_to_freq()"); + "%s. Failed ps_to_freq()", mss::c_str(i_target) ); - FAPI_INF("DIMM speed from selected tCK: %d (%s)", l_min_dimm_freq[l_index], mss::c_str(l_mcs)); + FAPI_INF("DIMM speed from selected tCK (ps): %d for %s", l_min_dimm_freq[l_index], mss::c_str(l_mcs)); FAPI_TRY(mss::select_supported_freq(l_mcs, l_min_dimm_freq[l_index]), - "Failed select_supported_freq() %s", mss::c_str(l_mcs)); + "Failed select_supported_freq() for %s", mss::c_str(l_mcs)); - FAPI_INF("Selected DIMM speed from supported speeds: %d", l_min_dimm_freq[l_index]); + FAPI_INF("%s. Selected DIMM speed from supported speeds: %d", + mss::c_str(i_target), l_min_dimm_freq[l_index]); }// end else } // close scope FAPI_TRY(mss::set_CL_attr(l_mcs, l_desired_cas_latency[l_index] ), - "Failed set_CL_attr()"); + "%s. Failed set_CL_attr()", mss::c_str(i_target) ); - FAPI_INF( "Final Chosen CL: %d (%s)", l_desired_cas_latency[l_index], mss::c_str(l_mcs)); } // close for each mcs FAPI_TRY(mss::set_freq_attrs(l_mcbist, l_min_dimm_freq), - "Failed set_freq_attrs()"); + "%s. Failed set_freq_attrs()", mss::c_str(i_target) ); fapi_try_exit: return fapi2::current_err; diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H index 4050b06c2..3f24856bf 100644 --- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H +++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H @@ -45,32 +45,6 @@ namespace mss { -/// -/// @brief Checks for frequency override and sets dimm frequency and timing values -/// @param[in] i_target mcbist fapi2 target -/// @param[out] o_tCK new cycle time if there is a freq override -/// @return FAPI2_RC_SUCCESS iff ok -/// -inline fapi2::ReturnCode check_for_freq_override(const fapi2::Target& i_target, - uint64_t& o_tCK) -{ - uint64_t l_freq_override = 0; - - FAPI_TRY(freq_override(i_target, l_freq_override), - "Failed to override frequency!"); - - // If there is no override, don't change anything - if ( l_freq_override != fapi2::ENUM_ATTR_MSS_FREQ_OVERRIDE_AUTO) - { - FAPI_TRY( mss::freq_to_ps(l_freq_override, o_tCK), "Failed freq_to_ps()"); - FAPI_DBG( "Override Frequency Detected: %d", l_freq_override); - } - -fapi_try_exit: - return fapi2::current_err; -} - - /// /// @brief Sets DRAM CAS latency attributes /// @param[in] i_target the controller target @@ -80,15 +54,20 @@ fapi_try_exit: inline fapi2::ReturnCode set_CL_attr(const fapi2::Target& i_target, uint64_t i_cas_latency) { - // Declaration of the vector correctly initializes it to the right size - // in the case the enum for PORTS_PER_MCS changes - std::vector l_cls_vect(PORTS_PER_MCS, uint8_t(i_cas_latency) ); + std::vector l_cls(PORTS_PER_MCS, 0); + + // Set configured ports + for( const auto& p : find_targets(i_target) ) + { + l_cls[mss::index(p)] = i_cas_latency; + FAPI_INF( "Final Chosen CL: %d for %s", i_cas_latency, mss::c_str(p)); + } // set CAS latency attribute // casts vector into the type FAPI_ATTR_SET is expecting by deduction FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_CL, i_target, - UINT8_VECTOR_TO_1D_ARRAY(l_cls_vect, PORTS_PER_MCS)) , + UINT8_VECTOR_TO_1D_ARRAY(l_cls, PORTS_PER_MCS)) , "Failed to set CAS latency attribute"); fapi_try_exit: diff --git a/src/import/chips/p9/procedures/xml/attribute_info/memory_mcs_attributes.xml b/src/import/chips/p9/procedures/xml/attribute_info/memory_mcs_attributes.xml index 8d5776543..b0353804e 100644 --- a/src/import/chips/p9/procedures/xml/attribute_info/memory_mcs_attributes.xml +++ b/src/import/chips/p9/procedures/xml/attribute_info/memory_mcs_attributes.xml @@ -2865,7 +2865,14 @@ ATTR_EFF_DRAM_TREFI TARGET_TYPE_MCS - Average Refresh Interval (tREFI) in nck (number of clock cycles). + Average Refresh Interval (tREFI) + in nck (number of clock cycles). + This depends on MRW attribute that selects fine refresh mode (x1, x2, x4). + From DDR4 spec (79-4A). + + For 3DS, the tREFI time to the same logical rank is defined as + tRFC_slr1, tRFC_slr2, or tRFC_slr4. + creator: mss_eff_config consumer: various firmware notes: none @@ -2881,14 +2888,14 @@ ATTR_EFF_DRAM_TRTP - TARGET_TYPE_MCS - Internal Read to Precharge Delay. - Each memory channel will have a value. - creator: mss_eff_cnfg_timing - consumer: various - firmware notes: none + Internal Read to Precharge Delay. + From the DDR4 spec (79-4A). + Each memory channel will have a value. + creator: mss_eff_cnfg_timing + consumer: various + firmware notes: none uint8 @@ -2901,9 +2908,9 @@ ATTR_EFF_DRAM_TRFC_DLR TARGET_TYPE_MCS - Minimum Refresh Recovery Delay Time + Minimum Refresh Recovery Delay Time (different logical ranks) in nck (number of clock cyles). - Selected tRFC value (tRFC_dl1, tRFC_dl2, or tRFC_dl4) + Selected tRFC value (tRFC_dlr1, tRFC_dlr2, or tRFC_dlr4) depends on MRW attribute that selects fine refresh mode (x1, x2, x4). For 3DS, The tRFC time to different logical ranks are defined as tRFC_dlr creator: eff_config @@ -2937,6 +2944,26 @@ eff_dram_tfaw_dlr + + ATTR_EFF_DRAM_TRRD_DLR + TARGET_TYPE_MCS + + Minimum Activate to Activate Delay Time (different logical ranks) + in nck (number of clock cycles). + For 3DS, The tRRD_S time to a different logical rank is defined as tRRD_dlr. + Each memory channel will have a value. + creator: eff_confg + consumer: various + firmware notes: none + + + uint8 + + 2 + nck + eff_dram_trrd_dlr + + ATTR_EFF_DRAM_TXS TARGET_TYPE_MCS diff --git a/src/import/hwpf/fapi2/xml/attribute_info/hb_temp_defaults.xml b/src/import/hwpf/fapi2/xml/attribute_info/hb_temp_defaults.xml index 79fe18a1d..6aee20e1b 100644 --- a/src/import/hwpf/fapi2/xml/attribute_info/hb_temp_defaults.xml +++ b/src/import/hwpf/fapi2/xml/attribute_info/hb_temp_defaults.xml @@ -212,7 +212,9 @@ ATTR_SYSTEM_RESCLK_ENABLE - + + ATTR_EFF_DRAM_TRRD_DLR + -- cgit v1.2.1